# Mathematica rule substitution memory

First I present the specific programming question, and then I provide further background details.

Given an expression in Mathematica, say f=3x+7y, there are two common ways to substitute information for x and y. The first is to use the /. rule, so something like

 t=f/.{x->0,y->0};


would make the value of t equal to 0.

And the other is a more general substitution for x and y everywhere they appear, such as

 x=0; y=0;
t=f;


This also makes the value of t equal to 0. The difference in memory usage, however, becomes apparent with more complicated polynomials. I have uploaded a text file with a complicated polynomial to MediaFire : http://www.mediafire.com/?0ea3mhtqmc8c3r2 (it is about 4MB, and I'm not aware of a better way of sharing it). If you download it and then load it into Mathematica as I will demonstrate, you can see for yourself the significant memory loss:

Substitution Method

 In[1]:= << "/home/username/Downloads/p";
In[2]:= MaxMemoryUsed[]
Out[2]= 79833424
In[3]:= MemoryInUse[]
Out[3]= 76373112
In[4]:= t = p /. {x -> 0, y -> 0, z -> 0};
In[5]:= MaxMemoryUsed[]
Out[5]= 152124264
In[6]:= MemoryInUse[]
Out[6]= 112876080


General Assignment Method

 In[1]:= << "/home/username/Downloads/p";
In[2]:= MaxMemoryUsed[]
Out[2]= 79831632
In[3]:= MemoryInUse[]
Out[3]= 75415960
In[4]:= x = 0; y = 0; z = 0;
In[5]:= MaxMemoryUsed[]
Out[5]= 79831632
In[6]:= MemoryInUse[]
Out[6]= 75420744
In[7]:= t = p;
In[8]:= MaxMemoryUsed[]
Out[8]= 112888664
In[9]:= MemoryInUse[]
Out[9]= 112875336


As you can see, during the substitution operation there was about 40MB of additional memory used to perform the substitution. The substitution method also takes much longer than the general method. The difference in the two methods becomes much higher (several GB) as the complexity of the polynomial increases, and ends up maxing out the available RAM. The problem is that for my program I cannot set x, y, z equal to zero in general.

This seems to be an inefficiency with the way Mathematica performs substitutions. I would appreciate any suggestions for working around this problem.

Further Background

The reason I cannot simply employ the general method is that the next step requires that I take derivatives of the original polynomial with respect to the variables x, y, z. The process would ideally be iterated as follows:

Step 1: Given p, write the result of p/.{x->0,y->0,z->0} to a file.

Step 2: Take derivatives of p with respect to x, y, z.

Step 3: Perform some algebraic operations with the derivatives, creating the more complicated polynomials p1 and p2.

Step 4: Repeat the process on each of p1 and p2.

Since the process runs out of RAM when using the substitution rule, I have been working around this by performing several iterations of the process without writing the output of p/.{x->0,y->0,z->0} to a file, and then applying the "General Assignment Method" (setting x=0; y=0; z=0; and writing the evaluation of each polynomial to a file).

This is an unsatisfactory workaround, however, because it is impossible to know the proper number of iterations which will be required, and so it is possible that after performing all the iterations and writing the results to a file that I will need to run it again, this time performing more iterations. If the results could be written out to a file in the intermediate steps, I would be able to check them and determine if I should let the iteration continue or if I can stop it.

-

## migrated from stackoverflow.comMar 8 '12 at 17:28

This question came from our site for professional and enthusiast programmers.

It's worth noting that both the Clear and Block solutions do not work when the substitution involves an indexed variable, like "a[8]". –  process91 Mar 8 '12 at 17:56

While I am not able to explain why there is a difference between the two methods, I would like to suggest using

t = Block[{x=0, y=0}, p];


Block will set a value to x and y only temporarily, and avoids the use of Clear.

Some more things that can be useful for you:

1. When you start working, use \$HistoryLength = 0 to avoid remembering past results and wasting memory (note that Mathematica sometimes remembers full results even when the input was ended in a semicolon!)

2. Use Share[] occasionally. It seems that with your polynomial this will help a lot more than in other cases. After reading in the polynomial, it frees 60 MB for me immediately.

-
Thanks for the tip. Much cleaner than my solution. I had two separate questions about the Share[] command - do you know if you have to run it more than once if you have created new complicated expressions since you originally ran it? Also, do algorithms (say the GroebnerBasis algorithm) take more time when you have used the Share[] command because they have to, in a sense, reconstruct the information? –  process91 Mar 8 '12 at 2:53
@process91 As I understand, Share[] optimizes the way expressions are stored. Every time a new expression is created, there will be a chance that Share[] can reduce memory usage. According to the documentation, Share[] might improve performance. There is no need to reconstruct anything: the information is all there except duplicate parts of expressions are not stored twice. I do not have much practical experience with the performance effects of Share[] because I don't usually work with expressions where it has such a significant effect, like in your case. –  Szabolcs Mar 8 '12 at 5:43
Thanks for the tip! –  process91 Mar 8 '12 at 13:43

I have solved this problem, in a very simple way, as I will demonstrate here:

 In[1]:= f = 3 x + 7 y
Out[1]= 3 x + 7 y
In[2]:= x = 0;
In[3]:= t = f
Out[3]= 7 y
In[4]:= Clear[x];
In[5]:= t
Out[5]= 7 y
In[6]:= f
Out[6]= 3 x + 7 y


Now I only wonder why Mathematica's substitute command does not use this method for substitutions. I'm sure there are situations where more complicated substitution rules may fail with this approach, but in that case some heuristics should determine if this much faster and less RAM intense method would be applicable and, if so, apply it.

-
The method here is "dangerous" in that you cannot readily tell, without examining previous input, that the variable x has (at least temporarily) been given a value. Using ReplaceAll (/.)with Rule (->) immediately makes the substitution obvious. Moreover, a number of functions such as Solve and DSolve return results as rules rather than as values, hence the common need for ReplaceAll. –  murray Mar 8 '12 at 19:51
Bear in mind that Mathematica is a term-rewriting system and direct substitutions work because the input is evaluated as a program. Thus, you ask here for a heuristic that can efficiently and in general determine whether two different programs (the one evaluated directly, and the one obtained using ReplaceAll to perform substitutions and then evaluated) are equivalent. –  Oleksandr R. Mar 8 '12 at 20:15
@OleksandrR. I would think that simply checking if the substitutions requested were for constants would be adequate. Perhaps I'm overlooking something, but from what I can tell using Block[{x=c1,y=c2,...},f] where the c1,c2,... are constants will always yield the same result as f/.{x->c1,y->c2,...}, and will do so faster and with less RAM required. Thus a simple form of the heuristic I'm looking for would be to see if the substitutions were all constants and, if so, use the Block method. –  process91 Mar 17 '12 at 18:22