抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

众所周知,Mathematica中虽然使用下标形式非常方便,但如果对下标结构进行直接赋值,它将关联到内部符号Subscript上。这样,在我们大量清理符号定义的时候可能会漏掉一些定义。类似地,导数Derivative有同样的问题,比如对于

1
f'=df

使用

1
2
Clear[f]
Clear["`*"]

并不能清除f'的定义。

虽说将直接赋值改为用UpSet或者TagSet替代可以将赋值关联到符号f上而不是别的,比如下面的代码。

1
f/:f'=df

但每次多打一些东西总归是不方便,我们总会想找一个一劳永逸的办法。

官方文档中提到的对数量值的处理给了我启发。

在Wolfram语言中,数量值的处理与上值类似,当定义了f的数量值以后,Wolfram语言就象求值运算Nf的上值一样来输入这一定义.

下标的情况相对比较容易处理,类似an的结构在Wolfram语言中实质就是Subscript[a,n],我们只要把普通的赋值转化为TagSet即可,就如下面的代码所示

1
2
3
4
Subscript /: Set[Subscript[a_Symbol, rest__], val_] := 
TagSet[a, Subscript[a, rest], val]
Subscript /: SetDelayed[Subscript[a_Symbol, rest__], val_] :=
TagSetDelayed[a, Subscript[a, rest], val]

Derivative的情况相对要复杂一些,因为即使看上去非常简单的f'[x]在Wolfram语言内部也会表示为Derivative[1][f][x],我们认为的主要符号f在这个表达式中层次太深,无法直接将TagSet应用在上面,因此只能采取一些迂回的办法。

值得庆幸的是,Mathematica也支持纯函数式的导数,例如Sin'会得到Cos[#1]&。而在Derivative[1][f]结构中,f是可以通过TagSet赋予上值的。对于这种情况,采用和前面类似的方法就能解决。

1
2
3
4
Derivative /: Set[Derivative[ns__Integer][f_Symbol], val_] := 
TagSet[f, Derivative[ns][f], val]
Derivative /: SetDelayed[Derivative[ns__Integer][f_Symbol], val_] :=
TagSetDelayed[f, Derivative[ns][f], val]

而对于类似Derivative[1][f][x]的情况,虽然我们无法直接对其使用TagSet,但我们可以考虑将其转换为纯函数的情况。

动手前先分析,例如f'[x_]:=x我们希望将其转换为f':=Function[{x},x],为了达到这个目的,需要去掉原本赋值中的模式结构:_
我们知道,像x_的完整形式是Pattern[x,Blanck[]]。因此,提取x_x只要将其第一部分提取出来即可。综合一下可以写成如下的代码

1
2
3
4
5
6
Derivative /: 
Set[Derivative[ns__Integer][f_Symbol][args__Pattern], val_] :=
Set[Derivative[ns][f], Evaluate[First /@ {args}] \[Function] val]
Derivative /:
SetDelayed[Derivative[ns__Integer][f_Symbol][args__Pattern], val_] :=
Set[Derivative[ns][f], Evaluate[First /@ {args}] \[Function] val]

其中,Evaluate是为了解决FunctionHoldAll属性的。

除此之外,还有一点值得注意。像Derivative[1]Derivative[1,0]是不同的,Derivative的参数个数应该与被求导函数的参数个数匹配。
考虑了这个问题后,可以将上面的代码改成下面这样,以避免出现类似f'[x_,y_]:=df[x,y]错误形式。

1
2
3
4
5
6
7
8
9
10
Derivative /: 
Set[Derivative[ns__Integer][f_Symbol][x__Pattern], val_] :=
If[Length@{ns} == Length@{x},
Set[Derivative[ns][f],
Evaluate[First /@ {x}] \[Function] val], $Failed]
Derivative /:
SetDelayed[Derivative[ns__Integer][f_Symbol][x__Pattern], val_] :=
If[Length@{ns} == Length@{x},
Set[Derivative[ns][f],
Evaluate[First /@ {x}] \[Function] val], $Failed]

当然,这种方法不能应对类似f'[1]=0这样的单点导数赋值。但这种基于模式的单点导数定义本身也不是很合适的做法,比如

1
2
3
f'[1]=0;
f'[x_]:=x
D[f[x],x]

其结果是无法体现出f'[1]=0的。

因此对于一个函数的某阶导数,应该避免重载。如果有需要,也应该使用Piecewise之类的手段整合成一个函数。

评论