Skip to main content

programming - How is LHS = RHS; ... ; LHS (nontrivially) different from ... ; RHS


I'm trying to understand how Mathematica thinks about the results of Set. Suppose we perform LHS = RHS. I'm focusing on when Mathematica considers LHS to be fully evaluated and when it decides to evaluate LHS again later.


Discussion and Examples


Suppose I do the following:


(* First example *)

ClearAll[ LHS, f, F ];
LHS = f[x]; (* f[x] *)
f[x_] := F[x]
LHS
(* F[x] *)

This is what I would have expected to happen -- LHS is re-evaluated at the end.


Now, the following works a bit differently:


(* Second example *)
ClearAll[LHS, f, F, changeQ];


changeQ[x_] := False
f[x_?changeQ] := F[x]

LHS = f[x];
changeQ[x] := True
LHS
(* f[x] *)

Apparently Mathematica decided not to re-evaluate LHS at the end, otherwise it would evaluate to F[x]. This is a case where LHS and f[x] evaluate to different quantities.



Interestingly enough, swapping the order of two lines in the above changes the outcome:


(* Third example *)
ClearAll[LHS, f, F, changeQ];

changeQ[x_] := False
LHS = f[x];

f[x_?changeQ] := F[x]
changeQ[x] := True
LHS

(* F[x] *)

Swapping the order made LHS re-evaluate at the end, just like in the first example.


This leads me to more formally pose and tentatively answer the question:


Question


Suppose, for some choice of initialCode and additionalCode, we perform


initialCode
LHS = f[x]; (* f[x] *)
additionalCode
LHS


Assuming that LHS originally evaluated to f[x],




  1. For what types of additionalCode (and possibly initialCode) does the final evaluation of LHS yield something different from evaluating f[x]?




  2. If LHS and f[x] evaluate to different values (as is the case at the end of the second example above), is it possible to somehow "force" LHS to evaluate in the same way as f[x]?





Tentative Answer to Question 1


(Based on evidence from above examples)



  • LHS will re-evaluate when additionalCode gives a down value to f (See 1st and 3rd examples above)

  • LHS will not re-evaluate in general. (See 2nd example above, where a down value was given to a different function, changedQ.)


Follow Up


Assuming the tentative answer is along the right track, I'm looking for two things:



  • How does Mathematica 'know' when to re-evaluate LHS? I'm particularly interested in the vocabulary used to describe the process.


  • Are there any other conditions under which LHS re-evaluates?

  • Is there a generic way to force LHS to re-evaluate? (This is similar to the second question above.)


Of course, I'd welcome any suggestions for good references on this.



Answer



Behavior you're describing is briefly mentioned in last paragraph of "Controlling Infinite Evaluation" tutorial and very similar example is shown in documentation of Update function.


It's related to how Mathematica optimizes evaluation, how it decides that expression has not changed since last evaluation and whether it needs to be re-evaluated.



For what types of additionalCode (and possibly initialCode) does the final evaluation of LHS yield something different from evaluating f[x]?




If evaluation of f[x], before evaluating additionalCode, depends on Condition or PatternTest and evaluation of additionalCode changes some symbols in such a way that results of said Condition or PatternTest changes. Then evaluation of LHS will give different result than evaluation of f[x] after additionalCode was evaluated.


I don't know details of internal optimizations and above answer is based on what I recall from my experience, it's not backed up by any definite reference nor by conclusive experiments with Mathematica.



If LHS and f[x] evaluate to different values (as is the case at the end of the second example above), is it possible to somehow "force" LHS to evaluate in the same way as f[x]?



Yes, evalute Update[f] after evaluation of additionalCode:


(* Second example *)
ClearAll[LHS, f, F, changeQ];

changeQ[x_] := False

f[x_?changeQ] := F[x]

LHS = f[x];
changeQ[x] := True

Update[f]

LHS
(* F[x] *)



How does Mathematica 'know' when to re-evaluate LHS? I'm particularly interested in the vocabulary used to describe the process.


Are there any other conditions under which LHS re-evaluates?



Daniel Lichtblau shed some light on this in answer to "Mathematica execution-time bug: symbol names" post.



Is there a generic way to force LHS to re-evaluate? (This is similar to the second question above.)



Yes, use Update function. If you know which symbols where affected, pass them to Update, otherwise call Update[] without arguments.





Comments

Popular posts from this blog

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...

list manipulation - Selecting multiple columns from a matrix?

Sample data: data = { {{2013, 1, 1}, 24.13, 167.67, 231.82}, {{2013, 1, 2}, 32.15, 170.92, 225.99}, {{2013, 1, 3}, 35.43, 172.68, 221.67}, {{2013, 1, 4}, 36.73, 173.05, 218.32}, {{2013, 1, 5}, 58.19, 165.96, 197.05}, {{2013, 1, 6}, 69.99, 163.50, 187.52}, {{2013, 1, 7}, 71.37, 154.21, 175.58}, {{2013, 1, 8}, 72.51, 149.66, 163.25}}; I want a DateListPlot with three graphs, so for a matrix formed by columns 1 and 2, one for columns 1 and 3, and 1 for columns 1 and 4. At the moment I'm using this code: data2 = Transpose[{data[[All, 1]], data[[All, 2]]}]; data3 = Transpose[{data[[All, 1]], data[[All, 3]]}]; data4 = Transpose[{data[[All, 1]], data[[All, 4]]}]; DateListPlot[{data2, data3, data4}, Joined -> True, Filling -> {3 -> {1}}] but I have a hunch that this can be done more efficiently. I don't like the Transpose s in particular. Any ideas? edit (for extra credit) What if I need to multiply the second column by 2, which in my solution is simp...

plotting - How to draw some 2D curves in a 3D plot?

I want to plot several 2D curves ( Sin[x] at y=0 , Cos[x] at y=1 ) in a 3D plot, what function should i use? f[x_, y_] := Piecewise[{{0, y 0}, {Sin[x], y == 0}}] g[x_, y_] := Piecewise[{{0, y 1}, {Cos[x], y == 1}}] Plot3D[{f[x, y], g[x, y]}, {x, 0, 10}, {y, 0, 10}] doesn't work. Any ideas? Answer ParametricPlot3D[{{Sin[u], 0, u}, {Cos[u], 1, u}}, {u, 0, 20}, BoxRatios -> 1, PlotRange -> {{-2, 2}, {-.5, 2}, {0, 20}}] === update - general thoughts === I've seen the comments to this question and a few other approaches to the waterfall (or wire) plot are given in this question: Plotting several functions . Also I cannot not mention one of my favorite Mathematica blogs - Archery with this post on the story of discovery of 1st pulsar and an its infamous graphics - code is given in the post: