MathGroup Archive 1993

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

Search the Archive

Re: Hold/Evaluate in Integrate

  • To: mathgroup at yoda.physics.unc.edu
  • Subject: Re: Hold/Evaluate in Integrate
  • From: villegas
  • Date: Sat, 11 Dec 1993 22:27:57 -0600

Daryl (dreece at cad.gatech.edu) asked:


>     Can anyone tell me why
>
> Hold[Integrate[Evaluate[x+x], x]]
>
> returns
>
> Hold[Integrate[Evaluate[x+x],x]]
>
> not Hold[Integrate[2x, x]]?
>
> I want to force evaluation of the arguments to Integrate
> but not evaluate the integral.


   An 'Evaluate' is effectual only if it is the outer wrapper of an
argument of a function.  In your case, the 'Evaluate' is inside
of an Integrate, so the Hold does not see it.  Here is another
example to illustrate when 'Evaluate' takes effect and when not:


In[12]:= Hold[Evaluate[Sin[Pi]], Sin[Evaluate[Pi]] ]

Out[12]= Hold[0, Sin[Evaluate[Pi]]]


   'Evaluate' is a flag caught by the evaluator during the
preliminaries of evaluating an expression. The standard
evaluation procedure, as outlined in Appendix A.4 of the
Mathematica book (p. 729), is to take an expression

h[e1, e2, ..., en]

and do some preliminary work on it before sending it as a whole to
the evaluator.  First it evaluates the head h, then the elements
ei in turn.  As you know, some functions such as Hold carry a
hold attribute (there are three:  HoldFirst, HoldRest, and HoldAll)
which tells the evaluator to leave some or all of the arguments
alone.  If A is a function carrying the attribute HoldAll, then

   H[e1, e2, ..., en]

will be passed on to the evaluator after evaluating only H, not the
ei's.  If R is a function carrying the attribute HoldRest, then

   R[e1, e2, ..., en]

will be passed on to the evaluator after evaluating R (the head is
always evaluated) and the first argument e1, but e2 through en will
be left as they are.

Since you sometimes want to override the hold on just one or a few
of the arguments, there's a mechanism for flagging selected arguments
to dictate that they should be pre-evaluated even though all the
other arguments are left as they are.  An argument is flagged by
wrapping it in the symbol 'Evaluate'.  If an argument ei doesn't
have head 'Evaluate', as e2 does in

   H[e1, Evaluate[e2], ..., en]

then ei will be left alone.  The evaluator will not delve into ei to
see if there are some 'Evaluate' wrappers on subexpressions inside
ei.


   Regardless, we can make up our own flag and write a function to
recognize it and deal with it when it is wrapped around deeply
nested elements.  Let's choose $Evaluate as our flag, since its
name is similiar to the built-in flag we are used to, and it's not
taken (at least not in 2.2).  Our function can make use of the
pattern matcher to search through an expression and locate all
subexpressions that have head '$Evaluate'.  For each $Evaluate
subexpression, we can just extract the contents, evaluate
them, and put them back where they were, but without the
'$Evaluate' which was merely a flag.  To replace a subexpression
with something else, we use the ReplacePart function:


In[14]:= ?? ReplacePart
ReplacePart[expr, new, n] yields an expression in which the nth part of
   expr is replaced by new. ReplacePart[expr, new, {i, j, ...}] replaces
   the part at position {i, j, ...}. ReplacePart[expr, new, {{i1, j1,
   ...}, {i2, j2, ...}, ...}] replaces parts at several positions by
   new.

Attributes[ReplacePart] = {Protected}


Here's a simple application of it to replace a held expression with its
evaluation:


In[15]:= heldexpr = Hold[Cos[Pi/2], Sin[Pi/2]]

                  Pi       Pi
Out[15]= Hold[Cos[--], Sin[--]]
                  2        2

In[16]:= ReplacePart[heldexpr, Sin[Pi/2], 2]

                  Pi
Out[16]= Hold[Cos[--], 1]
                  2


To apply this to an expression which we expect to have some $Evaluate
flags on subexpressions, we first use Position to find out where the
$Evaluate's are:


In[17]:= Clear[a, b]                                          


In[18]:= flaggedexpr = Hold[ $Evaluate[2 - 7], {$Evaluate[a = 3], b = 7} ]

Out[18]= Hold[$Evaluate[2 - 7], {$Evaluate[a = 3], b = 7}]

In[19]:= evalPositions = Position[flaggedexpr, _$Evaluate]

Out[19]= {{1}, {2, 1}}


Once we have a list of places to evaluate and replace, we use ReplacePart
to do it cumulatively:


In[20]:= ReplacePart[flaggedexpr, Part[flaggedexpr, 1], {1}]

Out[20]= Hold[$Evaluate[-5], {$Evaluate[a = 3], b = 7}]

In[21]:= ReplacePart[%, Part[%, 2, 1], {2, 1}]

Out[21]= Hold[$Evaluate[-5], {$Evaluate[3], b = 7}]


Finally, we purge the $Evaluate flag from the expression:


In[22]:= DeleteCases[%, $Evaluate, {0, -1}, Heads->True]

Out[22]= Hold[-5, {3, b = 7}]


The $Evaluate seems to have had the desired effect.  The assignment
'a = 3' should have been one side effect, and 'b = 7' should not be
a side effect:


In[23]:= {a, b}

Out[23]= {3, b}


Here is a session excerpt defining EvaluateTaggedParts and the auxiliary
function DestroyTag.  Both functions allow you to specify a flag with
the EvaluateTag option, in case you don't want to use '$Evaluate'.


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Mathematica 2.2 for NeXT
Copyright 1988-93 Wolfram Research, Inc.
 -- NeXT graphics initialized --

In[1]:= DestroyTag[expr_] :=     

          DeleteCases[expr, $Evaluate, {0, -1}, Heads->True]
       

In[2]:= DestroyTag[expr_, EvaluateTag -> flag_Symbol] :=
          DeleteCases[expr, flag, {0, -1}, Heads->True]
       

In[3]:= EvaluateTaggedParts[expr_] := DestroyTag @
          Fold[ReplacePart[#1, Part[#1, Sequence @@ #2], #2]&,
                expr, Position[expr, _$Evaluate] ]
               

In[4]:= EvaluateTaggedParts[expr_, EvaluateTag -> flag_Symbol] :=
          DestroyTag[#, EvaluateTag -> flag]&  @
          Fold[ReplacePart[#1, Part[#1, Sequence @@ #2], #2]&,
                expr, Position[expr, Blank[flag]] ]
                       

In[5]:= expr = Hold[$Evaluate[2 + 18, Exp[Pi/4 I]], a = 7, $Evaluate[b =  
9]]

                                   Pi I
Out[5]= Hold[$Evaluate[2 + 18, Exp[----]], a = 7, $Evaluate[b = 9]]
                                    4

In[6]:= EvaluateTaggedParts[ expr, EvaluateTag -> $Please ]

                                   Pi I
Out[6]= Hold[$Evaluate[2 + 18, Exp[----]], a = 7, $Evaluate[b = 9]]
                                    4

In[7]:= {a, b}

Out[7]= {a, b}

In[8]:= EvaluateTaggedParts[expr]

                  I/4 Pi
Out[8]= Hold[20, E      , a = 7, 9]

In[9]:= {a, b}

Out[9]= {a, 9}

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


   This implementation will work even if there are nested $Evaluate
expressions, because of the ordering Position puts on the list it
returns.  If Position finds occurrences that are nested, it lists
the more deeply nested first.  Therefore, the cumulative replacement
will work from the bottom up when there are nested chains.  If it
worked from the top down, then a larger expression that contained some
$Evaluate's originally might get replaced with something that no
longer contained $Evaluate's, or contained them at different positions.

An example to show the ordering Position actually returns:


In[29]:= Clear[a, b, c]

In[31]:= nested = Hold[$Evaluate[2 + 3, $Evaluate[$Evaluate[a] = 7], c =  
2],
           6 - 3]

Out[31]= Hold[$Evaluate[2 + 3, $Evaluate[$Evaluate[a] = 7], c = 2],

>    6 - 3]

In[32]:= Position[nested, _$Evaluate]

Out[32]= {{1, 2, 1, 1}, {1, 2}, {1}}



Here is a re-formulation to show what would happen if the ordering were
reversed.  The only change to the original function is the application
of Reverse to the output of Position in the last line of the function:



In[34]:= EvaluateTaggedPartsReversed[expr_] := DestroyTag @
           Fold[ReplacePart[#1, Part[#1, Sequence @@ #2], #2]&,
                expr, Reverse @ Position[expr, _$Evaluate] ]

In[35]:= EvaluateTaggedPartsReversed[ nested ]

Part::partd: Part specification
    Hold[$Evaluate[5, $Evaluate[7], 2], 6 + <<1>>][[1,2,1,1]]
     is longer than depth of object.

ReplacePart::part:
   Part {1, 2, 1, 1} of Hold[$Evaluate[5, $Evaluate[7], 2], 6 - 3]
     does not exist.

Part::partd: Part specification Hold[5, 7, 2, 6 - 3][[1,2,1,1]]
     is longer than depth of object.

ReplacePart::part:
   Part {1, 2, 1, 1} of Hold[5, 7, 2, 6 - 3] does not exist.

Out[35]= ReplacePart[Hold[5, 7, 2, 6 - 3],

>    Hold[5, 7, 2, 6 - 3][[1,2,1,1]], {1, 2, 1, 1}]



A total mess results, since the first replacement changed the expression
enough that future ones didn't make sense.


Robby Villegas
Technical Support
Wolfram Research






  • Prev by Date: Re: Mathematica on Sun + Mac???
  • Next by Date: problems with Splice["file.mf"]
  • Previous by thread: Re: Hold/Evaluate in Integrate
  • Next by thread: Public Domain Software on Solaris 2.X