MathGroup Archive 2004

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

Search the Archive

Re: Re: Re: Mathematica language issues

  • To: mathgroup at smc.vnet.net
  • Subject: [mg53112] Re: [mg53050] Re: Re: Mathematica language issues
  • From: "Fred Simons" <f.h.simons at tue.nl>
  • Date: Fri, 24 Dec 2004 05:58:58 -0500 (EST)
  • Sender: owner-wri-mathgroup at wolfram.com

So far I could resist the temptation to participate in this discussion.
However, in his mail Maxim Rytin presents some examples of which he thinks
the result is unpredictable.

Maybe there is some interest in how I predict the results of simple commands
in which Unevaluated occurs. Of course these examples are of no practical
interest. Unevaluated is meant to pass unevaluated arguments to a function
body and as such it works perfectly. No one in practice is interested in
(1+1)*Unevaluated[2+2].

The basic principle has been clearly explained by Andrzej Kozlowsky. Suppose 
we have a function f that we call with one or more Unevaluated arguments. 
The first step in the evaluation procedure is that arguments are evaluated 
as far as allowed and attributes such as Orderless and Flat are applied. In 
this step Unevaluated is unwrapped from the argument, but Mathematica has 
labeled the arguments which come from Unevaluated. If now no rules for f can 
be applied, Mathematica returns the result so far, with Unevaluated wrapped 
again around the labeled arguments. If a rule for f can be applied, the 
administration of arguments that come from Unevaluated is completely 
skipped.

Here are three illustrative examples. Try to predict the result!

In[1] :=
ClearAll[f]
Attributes[f]={Orderless};

f[b, Unevaluated[a]] // Trace

Out[3]=
{f[b,a],f[a,b],f[Unevaluated[a],b]}

In[4]:=
ClearAll[f]
Attributes[f]={Orderless};
f[x__]:= {x}[[1]];
f[b, Unevaluated[a]] // Trace

Out[7]=
{f[b,a],f[a,b],{a,b}[[1]],a}

In[8]:=
ClearAll[f]
Attributes[f]={Orderless, Flat};
f[b, Unevaluated[f[a,c]]] // Trace

Out[10]=
{f[b,f[a,c]],f[b,a,c],f[a,b,c],f[Unevaluated[a],b,Unevaluated[c]]}

The second example equals the first example, but now a rule for f is applied
so the result is a instead of Unevaluated[a]. The third example demonstrates
the labeling: the arguments a and c come from an Unevaluated argument in the
function call. Since no rule for f is applied, they are wrapped with
Unevaluated in the result, which is rather different from the original
command.

With respect to the functions Plus and Times the results seem to different.
When we consider e.g. Times[Unevaluated[z], 2], we expect that in the first
step of the evaluation due to the attribute Orderless of Times we arrive at
Times[2, z] with z labeled as coming from an Unevaluated argument. Since no
rules for Times can be applied, we expect the result to be 2*Unevaluated[z].
But the result is 2*z.

In order to understand what is going on here, we must have a closer look at
the functions Plus and Times. I first formulate my assumption (only WRI and
maybe a few others  know if I am right!) and then I will explain and
demonstrate it by some examples. Finally, using this hypothesis I will
explain Maxim's counterexamples.

Hypothesis: When Mathematica has to evaluate an expression with head Plus or
Times, then immediately after the evaluation of the head, so before the use
of the attributes, Mathematica calls a function that adds or multiplies all
numerical arguments. If there are no other arguments, this result is the
outcome of the evaluation. Otherwise Plus or Times is called with this
numerical result as first argument followed by the remaining arguments.

To illustrate the hypothesis we slightly modify the function Plus (the same
can be done with Times) so that Mathematica tells us when and how Plus is
called during the evaluation. Moreover, and that can be dangerous, we remove
the attribute Orderless of Plus.

In[13]:=
Unprotect[Plus];
Attributes[Plus]= Complement[Attributes[Plus], {Orderless}];
Plus[x___] /; (Print["Plus"[x]];False) := 12

In[16]:=
3 + c - 5 + b - a + 6

From In[16]:=
Plus[4,c,b,-a]

Out[16]=
4+c+b-a

In[17]:=
2-5+10

Out[17]=
7

In the first example we see from the printed message that the first time
Plus is called all numerical arguments are already added, the remaining
arguments are not sorted. In the second example we see that Plus is not
called at all.

That indeed Mathematica automatically calls another function when an
expression with head Plus or Times is met can be seen from the following
example, for which we start with a fresh kernel.

In[18]:=
Quit[]

In[1]:=
Block[{Plus},
Plus[a__]:= {a}[[1]];
{Plus[x,1], Plus[1+12], Plus[12,x,-12]}]

Out[1]=
{1,13,x}

Despite the fact that within the block we have a local variable Plus with a
very different definition of the outside function Plus, the pre-evaluation
mentioned in the hypothesis takes place! (I do not consider this as a bug in
scoping but as a feature of the system names Plus and Times).

So let us accept the hypothesis, let PrePlus and PreTimes be our names for
the functions mentioned in the hypothesis and let us consider some example's
of the type of Maxim's counterexamples.

1. Times[Unevaluated[z], 2]. PreTimes[Unevaluated[z], 2] applies a rule for
PreTimes, so the labeling of arguments from Unevaluated disappears and we
arrive at Times[2, z] with z not wrapped by Unevaluated.

2. 1 + 1 + Unevaluated[z]. PrePlus[1,1,Unevaluated[z]] applies a rule to
arrive at Plus[2, z], so z is not wrapped with Unevaluated.

3. 2 + Unevaluated[z].  PrePlus[2, Unevaluated[z]] has no rules to apply so
we arrive at Plus[2, z] with z still marked as coming from an Unevaluated
argument, so the result is Plus[2, Unevaluated[z]] (a different result from
the previous example!)

4. Unevaluated[2]/Sqrt[2]. PreTimes does not apply a rule, so we arrive at
Times[2, 1/Sqrt[2]] with the first argument still marked. Now Times applies
a rule and the result has no Unevaluated arguments.

5. Unevaluated[Sqrt[2] + Sqrt[2]]/Sqrt[2]. PreTimes does not apply a rule,
so we arrive at Times[1/Sqrt[2], Sqrt[2]+Sqrt[2]] with the second argument
labeled. Times has no rules for these arguments, so the outcome is
Unevaluated[Sqrt[2] + Sqrt[2]]/Sqrt[2].

6. Unevaluated[Sqrt[2]*(Sqrt[3] + 1)]*Csc[Pi/12]. PreTimes does not apply a
rule so due to the attribute Flat of Times we arrive at Times[Sqrt[2],
Sqrt[3] + 1, 1 + Sqrt[3], Sqrt[2]], where the first two arguments are
labeled. Mathematica 5.1 now returns Sqrt[2] Unevaluated[Sqrt[3] + 1] (1 +
Sqrt[3]) Unevaluated[Sqrt[2]].

That is correct, but it puzzles me. When I copy and paste this result in an
Input cell and evaluate, the result now becomes 2 (1 + Sqrt[3])^2 . That is
what I had  expected and which is Maxim's result. But when I ask for this
result without copying and pasting it does NOT evaluate to 2 (1+Sqrt[3])^2.
This is more an evaluation problem (bug?) in version 5.1 than that is has to
do with the basic properties of Unevaluated as discussed above.

7. Unevaluated[Sqrt[6]+Sqrt[2]]*Csc[Pi/12]. PreTimes does not apply a rule
so we arrive at Times[Sqrt[2], 1 + Sqrt[3], Sqrt[6] + Sqrt[2]] with the last
argument labeled. There are no rules for Times to be used, so Mathematica
returns Sqrt[2]*(1 + Sqrt[3]) Unevaluated[Sqrt[6] + Sqrt[2]].

Hence, despite the problem mentioned in example 6, my feeling is that there
is nothing mysterious and unpredictable in the behaviour of Unevaluated in
the examples discussed so far.

Fred Simons

Eindhoven University of Technology



  • Prev by Date: Re: Zero testing
  • Next by Date: Re: Zero testing
  • Previous by thread: Re: N[] does not work inside Replace[] ?
  • Next by thread: Re: Re: Re: Mathematica language issues