This is what UpValues are for

*To*: mathgroup at smc.vnet.net*Subject*: [mg19357] This is what UpValues are for*From*: "Ersek, Ted R" <ErsekTR at navair.navy.mil>*Date*: Fri, 20 Aug 1999 23:09:36 -0400*Sender*: owner-wri-mathgroup at wolfram.com

Last week I said I would provide a discussion of UpValues once I resolved some subtle details. Well I still haven't resolved the details, but I will tell you all that I know on the subject. Suppose you wanted to make it so the kernel would automatically use the simplification: Cosh[z]+Sinh[z]-->Exp[z] Below I show different ways of doing this. First we should Unprotect the symbols we will work with. --------------------------- In[1]:= Unprotect[Plus,Sinh,Cosh]; The line below will use the identity for Cosh[z]+Sinh[z] and associate the definition with Plus which is apparent when you evaluate (??Plus ). When the identity is associated with Plus the kernel will take more time to perform addition. Actually in Versions 3 and 4 Plus (Times as well) apply built-in rules before user defined rules. As far as I am aware all other kernel functions apply user defined rules first. So to put it more correctly (I hope); when the identity below is used the kernel will check to see if this identity can be used whenever an expression has the head Plus after using all built-in rules for Plus. For example the kernel will not try the identity below on (4+2/3), but it will try it on (4+x). ---------------------- In[2]:= Cosh[z_]+Sinh[z_]:=Exp[z]; ??Plus (* Plus information includes the identity above. *) The identity above was stored in DownValues[Plus]. We should clear out the DownValue from Plus before moving on. The output of (??Plus ) proves the identity was removed. In[4]:= DownValues[Plus]={}; ??Plus (* The identity was removed from Plus information. *) ----------------------- Instead we can associate the identity with (Sinh) using the code in the next line. The "Sinh/:" part of the code says to only associate the definition with Sinh. When done this way the use of this identity will have no impact on how fast the kernel evaluates expressions with the Head Plus or Cosh. But this will have an impact on how fast expressions with the Head Sinh evaluate. This is likely a better approach since (Sinh) is used much less often than addition. However, it isn't clear to me how much of an impact it would have on the evaluation of Sinh[_]. Anyway that is a very practical application of UpValues. The result of evaluating (??Sinh ), (??Cosh ), (??Plus ) will show the identity is associated with Sinh but not Cosh or Plus. In[6]:= Sinh/:Cosh[z_]+Sinh[z_]:=Exp[z]; ??Sinh (* Sinh information includes the identity above. *) In[8]:= ??Cosh (* Cosh information doesn't include the identity above. *) In[9]:= ??Plus (* Plus information doesn't include the identity above. *) The identity above was stored in UpValues[Sinh]. We should clear out the UpValue before moving on. The output of (??Sinh ) proves that it was removed. In[10]:= UpValues[Sinh]={}; ??Sinh (* Sinh information doesn't include the identity above. *) ------------------------ We could also use the next line to associate the identity with both (Sinh) and (Cosh), but not (Plus). This is clear from the result of evaluating (??Sinh ), (??Cosh ), (??Plus ). In this case the identity is stored in DownValues[Sinh] and DownValues[Cosh]. When this method is used both (Sinh) and (Cosh) will run slower. In[11]:= Cosh[z_]+Sinh[z_]^:=Exp[z]; ??Sinh (* Sinh information does include the identity above. *) In[12]:= ??Cosh (* Cosh information does include the identity above. *) In[13]:= ??Plus (* Plus information doesn't include the identity above. *) -------------------- Now suppose you wanted the kernel to automatically use the identity Sin[z]^2 + Cos[z]^2 -->1 Notice both (Sin[z]^2) and (Cos[z]^2) have the Head Power. You could give Plus a DownValue using: Sin[z_]^2 + Cos[z_]^2 :=1 Actually the next line also works just as well since (z) isn't used on the right side. Let me know if you want to know why it matters if (z) is used on the right side. Sin[z_]^2 + Cos[z_]^2 =1 Instead you could use an UpValue for Power using either of the next four lines. Sin[z_]^2 + Cos[z_]^2 ^:=1 Sin[z_]^2 + Cos[z_]^2 ^=1 Power/:Sin[z_]^2 + Cos[z_]^2 :=1 Power/:Sin[z_]^2 + Cos[z_]^2 =1 Let me know if you want me to elaborate on the differences between lhs^:=rhs lhs^=rhs f/:lhs:=rhs f/:lhs=rhs BUT Mathematica will not let you associate the definition above with (Sin) or (Cos). You might be tempted to use one of the following, but they will not work because (Sin) and (Cos) are too deep in the expression. Sin/:( Sin[z_]^2 +Cos[z_]^2 )=1 Cos/:( Sin[z_]^2 +Cos[z_]^2 )=1 Sin/:( Sin[z_]^2 +Cos[z_]^2 ):=1 Cos/:( Sin[z_]^2 +Cos[z_]^2 ):=1 When you evaluate something with the form f/:lhs^=rhs (f) must be a symbol, and lhs[[n,0]] must return (f) for some integer (n). The same thing goes for f/:lhs^:=rhs In the case where ( lhs = Sin[z_]^2+Cos[z_]^2 ) lhs[[1,1,0]]-->Cos lhs[[2,1,0]]-->Sin You see both Sin and Cos are in so deep that the identity can't be associated with either Sin or Cos. -------------------- When you use lhs^:=rhs An UpValue is given to every symbol that can be accessed using lhs[[n,0]] for any integer (n). For example when you use lhs^:=rhs with ( lhs=Cosh[z_]+Sinh[z_] ) lhs[[1,0]]-->Cosh lhs[[2,0]]-->Sinh so an UpValue is given to both Cosh, Sinh. --------------------- Before continuing you might want to evaluate the next line to put everything back to normal. In[13]:= DownValues[Plus]={}; UpValues[Cosh]={}; UpValues[Sinh]={}; Protect[Plus,Cosh,Sinh]; -------------------- Regards, Ted Ersek For Mathematica tips, tricks see http://www.dot.net.au/~elisha/ersek/Tricks.html

**Follow-Ups**:**Re: This is what UpValues are for***From:*"Wolf, Hartmut" <hwolf@debis.com>

**QUESTION (EigenVectors)**

**Re: circumference of an ellipse**

**Re: QUESTION (EigenVectors)**

**Re: This is what UpValues are for**