MathGroup Archive 2000

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

Search the Archive

Re: Re: selfdefined operators

  • To: mathgroup at smc.vnet.net
  • Subject: [mg23025] Re: [mg23006] Re: [mg22989] selfdefined operators
  • From: Hartmut Wolf <hwolf at debis.com>
  • Date: Tue, 11 Apr 2000 23:18:43 -0400 (EDT)
  • Organization: debis Systemhaus
  • References: <200004090545.BAA13108@smc.vnet.net> <200004100622.CAA02164@smc.vnet.net>
  • Sender: owner-wri-mathgroup at wolfram.com

A better solution, a disclaimer and further insights on associativity,
flatness and grouping (see below):

Hartmut Wolf schrieb:
> 
> Roland Koppenberger schrieb:
> >
> > I have defined the operator \[CirclePlus] in the following way:
> >
> > x_ \[CirclePlus] y_ := x y /(x + y)
> >
> > When type in
> >
> > 1 \[CirclePlus] 2
> >
> > I get 2/3 as the right result. But when I try to compute
> >
> > 1 \[CirclePlus] 2 \[CirclePlus] 3
> >
> > the result will not be computed. How can I specify the operator in a
> > general way?
> 
> Roland,
> 
> if you consult The Mathematica Book p. 1015 you'll find the operator
> CirclePlus to be defined as fully associative. If you respect that,
> you'll have no problems (in case you know how to define it for many
> arguments). Two suggestions; #1:
> 
> In[1]:= SetAttributes[CirclePlus, {Flat, OneIdentity}]
> In[2]:= CirclePlus[x__] := Times[x]/Plus[x]
> In[3]:= 1\[CirclePlus]2
> Out[3]= 2/3
> 
> In[4]:= 1\[CirclePlus]2\[CirclePlus]3
> Out[4]= 1
> 
> In[5]:= 1\[CirclePlus]2\[CirclePlus]3\[CirclePlus]4
> Out[5]= 12/5
> 
> or #2:
> 
> In[13]:= CirclePlus[x1_, x__] := Fold[(#1 #2/(#1 + #2) &), x1, {x}]
> In[14]:= 1\[CirclePlus]2
> Out[14]= 2/3
> 
> In[15]:= 1\[CirclePlus]2\[CirclePlus]3
> Out[15]= 6/11
> 
> In[16]:= 1\[CirclePlus]2\[CirclePlus]3\[CirclePlus]4
> Out[16]= 12/25
> 

Dear Roland,

Most of this is not neccessary. As I said, the cause of your problem was
that no associativity rule for CirclePlus is defined. If however you do 
#3:

In[1]:= SetAttributes[CirclePlus, {Flat, OneIdentity}]

In[2]:= CirclePlus[x_, y_] := x y/(x + y)

In[3]:= a\[CirclePlus]b
Out[3]= (a*b)/(a + b)

Setting these Attributes now implicitly defines an evaluation order for
CirclePlus:

In[4]:= a\[CirclePlus]b\[CirclePlus]c
Out[4]= (a*b*c)/((b + c)*(a + (b*c)/(b + c)))

In[5]:= (a\[CirclePlus]b)\[CirclePlus]c
Out[5]= (a*b*c)/((a + b)*((a*b)/(a + b) + c))

In[6]:= a\[CirclePlus](b\[CirclePlus]c)
Out[6]= (a*b*c)/((b + c)*(a + (b*c)/(b + c)))

No further definition is needed, neither my iterative one above (#2) nor
the recursive ones of Allan Hayes (right-associative) or David Park
(left-associative). 
This all is an implication of the attributes Flat, One-Identity for
predefined operators, quite different as for definitions.

The terms I used here "right-assoc.", "left-assoc." have nothing to do
with the mathematical notion of associativity, they only say something
about evaluation order.

Mathematically associativity is a property of functions of _two_
arguments, namely

     (a op b) op c  == a op (b op c)

This is nothing which can be defined (as contrary to evaluation order),
it has to be _proven_ ! So for your function we find:

In[7]:= Apart[%5] === Apart[%6]
Out[7]= True

it is associative, that property which normally allows to _extend_ the
meaning  of the operator to three or more arguments:

     a op b op c

However when executing a sequential program (and esp. for dealing with
side effects) as every programmer knows an evaluation order must be
defined. The conventions are different for the programming language and
for the meaning of the operator. Normally, not always, both orders are
present.

In your case Mathematica decided on the evaluation order as above. Now
the question, could you define otherwise? Yes, just add e.g. David's
definition

In[8]:= CirclePlus[x_, y_, z__] := CirclePlus[CirclePlus[x, y], z]

In[9]:=  a\[CirclePlus]b\[CirclePlus]c
Out[9]= (a*b*c)/((a + b)*((a*b)/(a + b) + c))

and the order of evaluation now is from left to right.


If instead of CirclePlus you had used CircleMinus (don't be afraid of
the "Minus", it's just a word),

In[10]:= CircleMinus[x_, y_] := x y/(x + y)

In[11]:= a\[CircleMinus]b\[CircleMinus]c
Out[11]= (a*b*c)/((a + b)*((a*b)/(a + b) + c))

you would not have got any problems in first place, since Mathematica
already has defined an evaluation order for this operator (left-assoc.
in this case).

I had not realized this in clarity when I gave my reply yesterday; so I
defined that annoying #1:

In[12]:= Clear[CirclePlus]
In[13]:= CirclePlus[x__] := Times[x]/Plus[x]

In[14]:= Apart[(a\[CirclePlus]b)\[CirclePlus]c] === 
  Apart[ a\[CirclePlus](b\[CirclePlus]c)]
Out[14]= True

but 

In[15]:= Apart[a\[CirclePlus]b\[CirclePlus]c] === 
  Apart[ a\[CirclePlus](b\[CirclePlus]c)]
Out[15]= False

now quickly to be forgotten, before rubbing your eyes!


A final remark on Flat, whereas

In[36]:= SetAttributes[f, Flat]
In[37]:= f[a, f[b, c]]
Out[37]= f[a, b, c]

f is flattened after evaluation of it's arguments, before transformation
rules are applied, for an operator with attributes

In[44]:= Attributes[CirclePlus]
Out[44]= {Flat, OneIdentity}

f is grouped (un-flattend so to speak) after evaluation of the
arguments, before the binary definition of the operator-function is
applied

In[45]:= Hold[a\[CirclePlus](b\[CirclePlus]c)] // FullForm
Out[45]//FullForm=
Hold[CirclePlus[a, CirclePlus[b, c]]]

In[48]:= CirclePlus[x_, y_] := x/y - y/x

In[49]:= a\[CirclePlus]b\[CirclePlus]c 
Out[49]= a/(b/c - c/b) - (b/c - c/b)/a


Kind regards, Hartmut


  • Prev by Date: Re: Re: Command to get a notebook's directory?
  • Next by Date: Re: InequalitySolve with algebraic numbers and Simplify
  • Previous by thread: Re: selfdefined operators
  • Next by thread: Re: selfdefined operators