MathGroup Archive 2008

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Don't understand replacement rule for some functions

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

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", 
> * 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}

                  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}

                                           -1 + g[x]
                 2                        x
Integrate[(1 + x ) Sin[----------------------------------------------],
                         g[x]  1/2 x (1 + x )    1    g[x]
                        2     E               (------)     Gamma[g[x]]
                                               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]

GammaDistribution[b, -]

In[6]:= PDF[GammaDistribution[b, c/L], x]

         -1 + b
  (L x)/c  c b
E        (-)  Gamma[b]

In[7]:= Sin[PDF[GammaDistribution[b, c/L], x]]*L

               -1 + b
L Sin[----------------------]
        (L x)/c  c b
       E        (-)  Gamma[b]

In[8]:= Integrate[Sin[PDF[GammaDistribution[b, c/L], x]]*L, {x, 1, 10}]

                         -1 + b
Integrate[L Sin[----------------------], {x, 1, 10}]
                  (L x)/c  c b
                 E        (-)  Gamma[b]

In[9]:= % /. {b -> 1, c -> 2, L -> 3}

                  3                      3
-2 SinIntegral[-----] + 2 SinIntegral[------]
                   15                     3/2
                2 E                    2 E

- Jean-Marc

  • Prev by Date: Re: What "style"s are available in a notebook?
  • Next by Date: FYI, Tally is still broken.
  • Previous by thread: Re: Don't understand replacement rule for some functions
  • Next by thread: What "style"s are available in a notebook?