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
- References:
- selfdefined operators
- From: Roland Koppenberger <roland@koppenberger.com>
- Re: selfdefined operators
- From: Hartmut Wolf <hwolf@debis.com>
- selfdefined operators