Wolfram mathematica 什么是;“增值”;什么时候使用它们?

Wolfram mathematica 什么是;“增值”;什么时候使用它们?,wolfram-mathematica,Wolfram Mathematica,对我来说,g/:f[g[x]]:=h[x]只是详细地等同于f[g[x]]:=h[x]。你能举一个你必须使用的例子吗?事实上,g/:f[g[x]]:=h[x]并不等同于f[g[x]]:=h[x]。后者将定义与f关联,而(/:)和(^=及其,^:=)将定义与g关联。这是一个关键的区别,可以用一个简单的例子来说明。假设你想要一组变量服从模5加法,即6+7模5=3。因此,我们希望任何带有头部的mod都能正常工作。起初,我们认为 a_mod + b_mod := mod@Mod[a + b, 5] 会有

对我来说,
g/:f[g[x]]:=h[x]
只是详细地等同于
f[g[x]]:=h[x]
。你能举一个你必须使用的例子吗?

事实上,
g/:f[g[x]]:=h[x]
并不等同于
f[g[x]]:=h[x]
。后者将定义与
f
关联,而(
/:
)和(
^=
及其,
^:=
)将定义与
g
关联。这是一个关键的区别,可以用一个简单的例子来说明。假设你想要一组变量服从模5加法,即6+7模5=3。因此,我们希望任何带有
头部的
mod
都能正常工作。起初,我们认为

a_mod + b_mod := mod@Mod[a + b, 5]
会有用的。但是,它会产生错误

SetDelayed::write : Tag Plus in a_mod + b_mod is Protected.
我们可以删除
Unprotect
Plus
,然后我们的定义就会起作用,但这可能会导致其他定义出现问题,并且随着
Plus
积累更多的定义,它会变慢。或者,我们可以通过
TagSet
将addition属性与
mod
对象本身相关联

mod /: mod[a_] + mod[b_] := mod @ Mod[a + b, 5]
UpSetDelayed

mod[a_] + mod[b_] ^:= mod @ Mod[a + b, 5]
从概念的角度来看,设置更为正确,因为
mod
具有不同的属性

有几个问题需要注意。首先,upvalue机制只能扫描一级深度,即
Plus[a_mod,b_mod]
可以,但
Exp[Plus[a_mod,b_mod]]
将抛出错误。这可能需要你用一种中间类型来创造。其次,从编码的角度来看,
UpSetDelayed
更容易编写,但偶尔会出现一些歧义,即
Head
是与之相关的upvalue
TagSet
通过显式命名适当的
Head
来处理这个问题,一般来说,我倾向于选择它而不是
under

Mathematica的一些操作符没有任何与之相关的行为,因此它们不受保护。对于这些运算符,可以根据需要定义函数。例如,我定义了

a_ \[CircleTimes] b_ := KroneckerProduct[a,b]
a_ \[CircleTimes] b_ \[CircleTimes] c__ := a \[CircleTimes] ( b \[CircleTimes] c )

为我经常使用的矩阵运算提供方便的速记符号

我上面的例子有点做作,但是有很多次
UpValues
都派上了用场。例如,我发现我需要一种符号形式来表示单位的复数根,它在乘法和幂运算中表现得很好

示例:一个简单而有用的示例是将
符号
标记为实数:

makeReal[a__Symbol] := (
     # /: Element[#, Reals] := True; 
     # /: Im[#] := 0; 
     # /: Re[#] := #;
     # /: Abs[#] := Sign[#] #;
     # /: Arg[#] := Piecewise[{{0, Sign[#] >= 0}, {Pi, Sign[#] < 0}}]
   ) & /@ List[a]
makeReal[a__符号]:=(
#/:元素[#,Reals]:=True;
#/:Im[#]:=0;
#/:Re[#]:=#;
#/:Abs[#]:=符号[#]\;
#/:Arg[#]:=分段[{0,符号[#]>=0},{Pi,符号[#]<0}]
)&/@List[a]

请注意,
TagSet
作为
元素[a,Reals]^:=True的使用将是不明确的。规则将附加到
a
Reals
?此外,如果我们想要一个正实数,我们可以设置
Arg[#]:=0
,这允许
Simplify
按预期运行,例如
Simplify[Sqrt[a^2]==a

Rcollyer已经给出了一个很好的答案,但下面是一个可以使用
UpValues
的示例:当您使用自己的
头定义一个特定的数据结构时,您想定义像算术这样的内置操作如何与该结构一起工作。我曾经为
timeSeries
数据结构这样做过,例如,加法将匹配第一列中的日期,并在第二列中添加相应的值对。如果您没有使用
UpValue

定义这样的操作,那么在第一列中添加带有日期的T*2向量将给出无意义的日期。除了@rcollyer的出色回答之外,我想强调关于
UpValue
的其他一些重要内容

系统和其他功能的软/本地重新定义 一个非常重要的方面是,它们允许您仅在某些符号上“柔和地”重载某些系统功能。@rcollyer指出了这一点的重要性,但强调得不够——这使得代码的效果成为局部的,并大大降低了代码可以全局交互并影响系统其他部分或其他用户定义代码的可能性,与
取消保护
系统符号并向其添加一些
下行值
时不同

除了安全性和局部性之外,如果使用类似于
yoursymble/:f_[\u yoursymble,rest_uu]:=…
的结构,这种重新定义也可能非常普遍。使用时应小心,但有时会给出非常简洁和简单的解决方案。例如,一个代码可以用于同时“重载”多个系统函数,从而为它们提供额外的非平凡功能

评价顺序 下一点是评估。您可能遇到的常见语句是“
UpValues
DownValues
之前应用”。必须澄清这一点:对于
f[g[args]]
而言,这意味着
g
UpValues
DownValues
之前应用
f
,前提是评估过程已经“向下”到最里面的部分,然后又回到“向上”。特别是,这并不意味着
g
UpValues
将在
g
DownValues
之前应用
UpValues
——如果
g[args]
可以在
f
内部进行计算,因为
g
具有适当的
DownValues
,它将(除非f具有
保持
属性之一),而
UpValues
的存在不会阻止这一点,因为(对于标准评估而言,
g[args]
的评估发生在

makeReal[a__Symbol] := (
     # /: Element[#, Reals] := True; 
     # /: Im[#] := 0; 
     # /: Re[#] := #;
     # /: Abs[#] := Sign[#] #;
     # /: Arg[#] := Piecewise[{{0, Sign[#] >= 0}, {Pi, Sign[#] < 0}}]
   ) & /@ List[a]
In[58]:= 
ClearAll[f, g];
f[x_] := x^2;
g /: f[g[x_]] := Sin[g[x]];
g[x_] := Cos[x];

In[62]:= f[g[y]]
Out[62]= Cos[y]^2
In[63]:= f[Unevaluated[g[y]]]

Out[63]= Sin[Cos[y]]
In[64]:= ClearAll[f,ff];
f[x_]:=Print["Evaluated"];
ff/:h_[ff[x_]]:=Print["Evaluated"];

In[67]:= Hold[f[1]]
Out[67]= Hold[f[1]]

In[68]:= Hold[ff[1]]
During evaluation of In[68]:= Evaluated
In[69]:= {HoldComplete[f[1]],HoldComplete[ff[1]]}
Out[69]= {HoldComplete[f[1]],HoldComplete[ff[1]]}
In[74]:= 
ClearAll[a,myType,myCustomCode,newValue];
myType/:Set[var_myType,rhs_]:=myCustomCode;
In[79]:= a = myType[1, 2, 3];
a = newValue;
a

Out[81]= newValue
ClearAll[a,myType,myCustomCode,newValue];
myType/:Set[var_,rhs_]/;MatchQ[var,_myType]:=myCustomCode;
TagSetDelayed::tagpos: Tag myType in (var_=rhs_)/;MatchQ[var,_myType]
  is too deep for an assigned rule to be found. >>
Clear[a,b];
Plus[a,b]^:=1;

?a
Global`a
a/:a+b:=1

?b
Global`b
b/:a+b:=1
ClearAll[a,b];
a/:Plus[a,b]:=1;

?a
Global`a
a/:a+b:=1

?b
Global`b