Message Boards Message Boards

GROUPS:

Can one shield expressions against replacement?

Posted 1 month ago
505 Views
|
13 Replies
|
5 Total Likes
|

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

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

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
Posted 1 month 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

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..

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]  *)

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,

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

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

How about this:

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

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.

Variation:

assoc = Association["A" -> GrassmannPointExpression];
{Point["A"], Text["A", "A"]} /.
 {Text[txt_, pos_] :> Text[txt, pos /. assoc],
  "A" -> GrassmannPointExpression}
Posted 1 month 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]}}

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.

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