Re: Don't understand replacement rule for some functions

*To*: mathgroup at smc.vnet.net*Subject*: [mg89576] Re: Don't understand replacement rule for some functions*From*: Jean-Marc Gulliet <jeanmarc.gulliet at gmail.com>*Date*: Fri, 13 Jun 2008 06:11:35 -0400 (EDT)*Organization*: The Open University, Milton Keynes, UK*References*: <g2qhhr$8or$1@smc.vnet.net> <g2qtt3$cek$1@smc.vnet.net>

Jean-Marc Gulliet wrote: > Mac wrote: > >> Can somebody explain why the following replacement rule works >> >> In[15]:= f[x] /. x -> y >> >> Out[15]= f[y] >> >> and this one complains >> >> In[14]:= RandomReal[GammaDistribution[L, 1/L], 2] /. L -> 3 >> >> During evaluation of In[14]:= RandomReal::parpos: The parameter L in \ >> position 1 of GammaDistribution[L,1/L] should be positive >> >> >> Out[14]= {1.89311, 1.11748} >> >> I find it quite elegant to use replacements for complicated functions >> but I'm never quite sure whether the replacement is actually carried >> out because of such behavior. > > Before evaluating an expression, Mathematica does many things [1]. Among > these things, it evaluates the arguments of the the expression *before* > applying any transformation rules. Also, keep in mind that an expression > is also a tree, so this process is applied recursively at each layer (or > level) of the tree. Then, starting from the lowest level, the > sub-expressions are evaluated in turn and any associated transformation > rules at the same level is applied. > > So, the evaluation of an expression such as f[x]/.x->y (assuming f, x, > and y have no associated meaning) can be summarized as follows: > > The expression f[x]/.x->y is split in two parts: f[x] and x->y. > > Before applying the rule x->y, Mathematica evaluates the argument (i.e. > x) of f[x]. Since x is an atomic expression with no value attached to > it, it evaluates to itself, that is x. > > So, now we are left with f[x] to which the rule x->y is going to be > applied. Having done so, f[x] is transformed into f[y] and only now > Mathematica is going to evaluate this expression f[y]. Since f has no > definition attached to it, the result of the evaluation is f[y] itself. > > Wow, I hope I have not confused you insofar! > > Following the same procedure, this time with the second expression, > > RandomReal[GammaDistribution[L, 1/L], 2] /. L -> 3 > > we now understand that Mathematica attempts to evaluate first (there is > a mechanism to control this, see below *) the arguments provided to > RandomReal, that is 2, which evaluates to 2, and GammaDistribution[L, > 1/L] which evaluates to itself since GammaDistribution required numeric > arguments (as well as RandomReal, thus the warning message). > > Therefore, the result of this preprocessing, is the expression > > RandomReal[GammaDistribution[L, 1/L], 2] > > to which Mathematica is going to apply the rule L->3 that was put on > hold. Having applied the rule, the expression becomes > > RandomReal[GammaDistribution[3, 1/3], 2] > > expression which is now perfectly valid and RandomReal is going to be > evaluated, which yields the two random numbers you got after the warning > message. > > Consequently, as a rule of thumb, one should "attach" any transformation > rules as close as possible of the relevant function or part of the > expression. For instance, > > In[1]:= RandomReal[GammaDistribution[L, 1/L] /. L -> 3, 2] > > Out[1]= {0.382089, 0.471758} > > Or, one can use the With[] construct as in > > In[2]:= With[{L = 3}, RandomReal[GammaDistribution[L, 1/L], 2]] > > Out[2]= {1.22402, 0.395845} > > Well, I hope I have shed more light than obscurity on the process :-)] > > Best regards, > - Jean-Marc > > [1] "The Main Loop", > http://reference.wolfram.com/mathematica/tutorial/TheMainLoop.html > > * to see the attributes of a function, one can use Attributes[], and > SetAttributes[] to set some specific attributes, such as HoldFirst that > delays the evaluation of the first argument until the execution of the > body of the function. > Following a private communication with Malcolm, I released that I had forgotten to mention two (important) things in my reply. First, one way to prevent the too early evaluation of the arguments is to define a function that encapsulates the original expression. This approach is much more flexible than using the With[] construct. We must use, of course, SetDelayed, i.e. :=, rather than Set when defining this function to prevent its immediate evaluation. In[1]:= f[L_] := RandomReal[GammaDistribution[L, 1/L], 2] In[2]:= f[3] Out[2]= {1.90898, 0.163862} Second, the main evaluation loop can be thought as a mechanism for function composition, like in mathematics. Thus, every function accepts none, one, or several arguments and returns something. This something as a 'type', say, to simplify, symbolic or numeric, and so does each argument of a function. Now when composing functions, whatever is returned by the evaluation of an argument must match the expected 'type' of the argument. (This mechanism is exemplify by functional language such as Haskell.) So, evaluating an expression such as the following, In[3]:= Integrate[Sin[PDF[GammaDistribution[b, c/L], x]]*L, {x, 1, 10}] /. {b -> 1, c -> 2, L -> 3} Out[3]= 3 3 -2 SinIntegral[-----] + 2 SinIntegral[------] 15 3/2 2 E 2 E works as expected, without any tweaking. We can even use other functions and symbolic values within the list of replacement rules. For instance, In[4]:= Integrate[Sin[PDF[GammaDistribution[b, c/L], x]]*L, {x, 1, 10}] /. {b -> g[x], c -> 2, L -> x^2 + 1} Out[4]= -1 + g[x] 2 x Integrate[(1 + x ) Sin[----------------------------------------------], 2 g[x] 1/2 x (1 + x ) 1 g[x] 2 E (------) Gamma[g[x]] 2 1 + x {x, 1, 10}] Now we can see why the above works (with the list of replacement rules being given at the highest level), whereas the original expression must be written with the replacement rule close to the argument. RandomReal[GammaDistribution[L, 1/L] /. L -> 3, 2] The return 'type' of GammaDistribution[L, 1/L] is symbolic (the expression itself). However, RandomReal expects its arguments to be numeric (real indeed). So witting its first argument as GammaDistribution[L, 1/L] /. L -> 3 yields an expression of type numeric and RandomReal is now happy with that. On the other hand, if we follow the evaluation process of each parts of the integral, we can see that every function involved in the process can 'consume' symbolic arguments so the evaluation process runs smoothly from bottom to top, as we can see below. In[5]:= GammaDistribution[b, c/L] Out[5]= c GammaDistribution[b, -] L In[6]:= PDF[GammaDistribution[b, c/L], x] Out[6]= -1 + b x ---------------------- (L x)/c c b E (-) Gamma[b] L In[7]:= Sin[PDF[GammaDistribution[b, c/L], x]]*L Out[7]= -1 + b x L Sin[----------------------] (L x)/c c b E (-) Gamma[b] L In[8]:= Integrate[Sin[PDF[GammaDistribution[b, c/L], x]]*L, {x, 1, 10}] Out[8]= -1 + b x Integrate[L Sin[----------------------], {x, 1, 10}] (L x)/c c b E (-) Gamma[b] L In[9]:= % /. {b -> 1, c -> 2, L -> 3} Out[9]= 3 3 -2 SinIntegral[-----] + 2 SinIntegral[------] 15 3/2 2 E 2 E HTH, - Jean-Marc