Message Boards Message Boards

0
|
5506 Views
|
13 Replies
|
5 Total Likes
View groups...
Share
Share this post:

Can one shield expressions against replacement?

Posted 5 years ago

In an extended expression I would like to shield certain parts of it against replacement. Some identical matching parts would be replaced by a rule applying to the larger expression but certain ones could be shielded and not replaced.

13 Replies
Anonymous User
Anonymous User
Posted 5 years ago

Can you embed a marker in the first "A" like "keepA" and remove it ("keep") after the Graphics evaluates? (perhaps first disabling the association so it doesn't apply on any following evaluation)?

There is an efficient way to read an expr without causing evaluation: it is Extract[].

You'd like to evaluate your Graphics only one time if you can help it (save the evaluated one). Mathematica graphics can end up being re-evaluated many many times unless used carefully. One way this happens is by (use) of Options or in the making of Options.

I'm unsure if I can add anything more to help, I think I would need a full example so that I knew my answer would help your situation by testing it first. For example i might conject that using mm's character code would escape replacement until displayed - but i'm unsure it makes sense to try without an example. Association seems to understand only "Key" which (if i understand) cannot be an expression, where Rule can be an expression. Rule can inspect the larger (pairs of) expressions and could filter repeated "A" in any manner you wish - given the expression containing both.

POSTED BY: Anonymous User
Posted 5 years ago

Another approach. This will shield arguments to Hold from replacement attempts, on any level:

replaceAllNotHeld[expr_, reprules_] := Module[
    {allPos, heldPos, repPos},
    allPos = Position[expr, _];
    heldPos = Position[expr, Hold] /. 0 -> __;
    repPos = Intersection @@ (DeleteCases[allPos, #] & /@ heldPos);
    MapAt[Replace[#, reprules] &, expr, repPos]
  ]

Example:

In[2]:= testExpr1 = {Hold@"A", "B", {Hold@"C", "D", Text[Hold@"E", "F"]}}    
Out[2]= {Hold["A"], "B", {Hold["C"], "D", Text[Hold["E"], "F"]}}

In[3]:= replaceAllNotHeld[testExpr1, x_String :> LetterNumber@x] // ReleaseHold  
Out[3]= {"A", 2, {"C", 4, Text["E", 6]}}
POSTED BY: Hans Milton

Variation:

assoc = Association["A" -> GrassmannPointExpression];
{Point["A"], Text["A", "A"]} /.
 {Text[txt_, pos_] :> Text[txt, pos /. assoc],
  "A" -> GrassmannPointExpression}
POSTED BY: Gianluca Gorni

Gianluca,

The problem with that approach is that the Text statements are generally embedded in a larger set of Graphics primitives that will have many substitutions from assoc. So the first argument will still be subject to replacement. Otherwise the assoc replacement would have to be seeded in at many individual places and the whole purpose of simplified transformation with a single use of assoc would be negated.

How about this:

assoc = Association["A" -> GrassmannPointExpression];
Text["A", "A"] /. Text[txt_, pos_] :> Text[txt, pos /. assoc]
POSTED BY: Gianluca Gorni

Hi David,

glad that you like my approach!

I was never aware of that particular usage of a Module

Well, this idea of course is not mine, I found it years ago in a contribution made by @Leonid Shifrin (if I remember correctly), so in this respect all credits should go to him! But it is a nice way to give "memory" to a function i.e. mimic static variables.

@Neil Singer: I like your solution - and I have the impression that it is more robust. Thanks for sharing!

Regards -- Henrik

POSTED BY: Henrik Schachner

Henrik has a nice solution. Here is an alternative. You can make your own replacement function that will control the order of replacements so you can do what you want. map a function into your expression and replace the new function, f[] depending on the argument.

doReplacements[expr_, value_, replacement_] := 
 Module[{f}, 
  Map[f, expr, Infinity] //. f[holdReplacement[f[value]]] -> value //. 
    f[value] -> replacement //. f[arg_] -> arg]

Now you can do something like:

doReplacements[{holdReplacement["A"], "A", holdReplacement["A"], 
  holdReplacement["B"], "B", holdReplacement["C"], "C"}, "A", "junk"]

to get

(* {"A", "junk", "A", holdReplacement["B"], "B", 
 holdReplacement["C"], "C"} *)

You can expand this concept to handle the association instead of a single replacement. I am not sure if there is any improvement using this approach but it is another way to do this.

FYI: holdReplacement cannot be defined -- or you can change it to some other symbol

Regards,

Neil

POSTED BY: Neil Singer

Hi Henrik,

That is a very impressive solution! It appears to work, I was never aware of that particular usage of a Module. Because the routines are defined within a Module they have access to a Module variable like repRules. And the routines can be used outside the Module.

Kudos

Hi David,

not that I like my approach very much (it rather looks like a syntactic joke to me), but how about this: With

Module[{local},
 holdReplacement[s_] := (local = s; "Dummy123");
 releaseHoldReplacement := "Dummy123" -> local;
 ]

you can write

Text[holdReplacement["A"], "A"] /. assoc /. releaseHoldReplacement
(* Out:  Text["A",GrassmannPointExpression]  *)

Is this helpful in any way? Regards -- Henrik

EDIT:

OK - here comes an "improvement":

assoc = Association["A" -> aExpression, "B" -> bExpression, "C" -> cExpression];

Module[{repRules = {}},
 holdReplacement[s_] := With[{dummy = Unique[]}, AppendTo[repRules, dummy -> s]; dummy];
 releaseHoldReplacement := With[{r = repRules}, repRules = {}; r];
 ]

then this works:

Text[holdReplacement["A"], "A", holdReplacement["B"], "B", 
   holdReplacement["C"], "C"] /. assoc /. releaseHoldReplacement
(* Out:  Text["A",aExpression,"B",bExpression,"C",cExpression]  *)
POSTED BY: Henrik Schachner

Thanks Hans,

That doesn't quite work because the expression I'm doing the replacement on is actually an extended List of graphics directives so replacements are needed at various levels. I would like to have just one replace command.

I think what I have to do is make certain that none of the Keys in the Association are the same as labels I want in a diagram..

Posted 5 years ago

David, using Replace instead of ReplaceAll, in combination with Hold, seems to work:

assoc=Association["A"->{1,2}] 
Replace[Text[Hold@"A","A"],assoc,1]//ReleaseHold
POSTED BY: Hans Milton

Neil,

I have an Association that has a number of rules that represent points or lines or structures in a geometric diagram, or derivation or proof. The right hand sides are symbolic vector expressions with symbolic basis vectors. I use Strings as Keys because I want to be free to use the Keys in expressions using contextual names and then substitute with the Association to do the calculation. I use Associations because I can gather all the data together for one topic. Here I use just one rule.

assoc = Association["A" -> GrassmannPointExpression]

There's also a command that will convert the GrassmannPointExpression to a Mathematica List that is applied after the Association.

But in the following, which might be used in Graphics, the first "A" is intended to be text and not substituted, and the second "A" will be converted to a position. I would like to shield the first "A" and then un-shield it after the assoc substitution.

Text["A", "A"] /. assoc

I would like something like the following. HoldAll does not stop replacement.

Text[HoldReplacement["A"], "A"] /. assoc // ReleaseHold

David,

Can you give an example? How do you want to designate which parts are shielded? Would you put a function around the term? Would it be by position?

Regards

POSTED BY: Neil Singer
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract