Mathematica中的函数类型声明

4
我曾多次遇到这个问题,与Mathematica可以理解的函数输入数据类型有关。
似乎Mathematica可以理解以下类型的声明: _Integer, _List, _?MatrixQ, _?VectorQ
然而,例如_Real,_Complex声明会导致函数有时无法计算。任何想法为什么会这样?
这里的一般规则是什么?

不清楚正在询问什么。 请提供示例代码和/或进一步解释。 - Mr.Wizard
1
@ Mr. Wizard:我稍微编辑了一下,但我认为问题已经足够清楚了,下面提供的答案有助于解决我遇到的问题。例如,我不明白为什么在输入具有实数类型限制的整数时,它会返回false。无论如何,下面的答案确实帮助我找到了这个问题的根源,并且有用地扩展了我的知识... - Phil
3个回答

10

当你像这样做 f[x_]:=Sin[x],你所做的是定义一个模式替换规则。如果你改为说 f[x_smth]:=5(如果你尝试这两种情况,请在第二个示例之前执行Clear[f]),你实际上是在说:“无论你在哪里看到 f[x],检查 x 的头部是否为 smth,如果是,则将其替换为5”。例如,尝试一下:

Clear[f]
f[x_smth]:=5
f[5]
f[smth[5]]
因此,回答你的问题,规则是在f[x_hd]:=1;中,hd可以是任何东西,且与x的头部匹配。人们还可以有更复杂的定义,例如f[x_] := Sin[x] /; x > 12,它将匹配如果x>12(当然这可以变得任意复杂)。编辑:我忘了实部,你当然可以定义Clear[f];f[x_Real]=Sin[x],并且它适用于例如f[12.]。但是你必须记住,虽然Head[12.]Real,但Head[12]Integer,因此你的定义不会匹配。

6

快速提醒一下,因为没有人提到过。您可以模式匹配多个Head - 这比使用条件匹配的?/;更快。

f[x:(_Integer|_Real)] := True (* function definition goes here *)

对于作用于实数或整数参数的简单函数,它的运行时间约为类似定义的75%。

g[x_] /; Element[x, Reals] := True (* function definition goes here *)

如WReach所指出的那样,它的运行时间比g[x_?(Element[#, Reals]&)] := True快75%。

后者的优势在于它适用于符号常数如Pi - 虽然如果你想要一个纯数字函数,可以在前者中使用N来解决。


5
像这样匹配多个表达式是非常脆弱的。很容易忘记一个类型的表达式,就像你在这里忘记了 Rational 或者像 Sqrt[2] 一样(不仅仅是 Pi)。如果你需要检查表达式是否仅为数值型(而不是它是否有虚部),最好使用 x_?NumericQ - Szabolcs
@Szabolcs:我最初考虑使用Rational,因为我检查了一下它不包括复数有理数,然后我忘记把它包含进去了!是的...所有作用于RealsRationals的数字函数都会破坏头部检查。所以你是对的,NumericQ结合一个可选的检查来查看它是否在Reals中可能是最好/最健壮的选择。 - Simon

4
最有可能的问题是你用来测试函数的输入。例如,
f[x_Complex]:= Conjugate[x]
f[x + I y]
f[3 + I 4]

返回值

f[x + I y]
3 - I 4

第二个可以运行而第一个不能的原因,可以从它们的FullForm中看出。
x + I y // FullForm == Plus[x, Times[ Complex[0,1], y]]
3 + I 4 // FullForm == Complex[3,4]

在内部,Mathematica将3 + I 4转换为一个Complex对象,因为每个术语都是数值,但x + I y没有像xy一样被处理,因为它们是Symbols。同样地,如果我们定义

g[x_Real] := -x

并使用它们

g[ 5 ]  == g[ 5 ]
g[ 5. ] == -5.

关键在于数字5属于Integer类型,而不是Real类型的子集。但是通过添加小数点,它变成了Real类型。
正如acl所指出的,模式_Something表示匹配任何Head === Something的内容,_Real_Complex都对赋给这些头部的值有很严格的限制。

4
@RM,我认为这是由于模式匹配机制的工作方式造成的,它只查看表达式的“Head”。因此,当您键入55.时,您得到一个“Integer”表达式与一个“Real”表达式。然后,模式匹配器只看到头不匹配。如果要同时匹配两个,请使用_?NumericQ。在匹配模式时,如果内部修改表达式以使其不再匹配,您会经常遇到此问题。对我来说,最臭名昭著的是收集复合表达式的虚部... - rcollyer
6
RM头匹配和一般的模式匹配都没有数学有效性的概念——唯一关心的是表达式的结构形式。数学有效性需要显式地编程。例如,如果想要一个适用于数学意义下的任何实数的函数,则可以编写 f[x_ /; x \[Element] Reals] := ... - WReach
4
为了好玩,我尝试了一个微基准测试:对于两种变体,Timing [Do[f[10], {10000000}]]/; 的运行时间比?快75%。 我不会过分解读这个结果。 在Mathematica中,清晰易懂的表达通常比性能更重要。 我会直接写最清晰的形式。 个人偏好也很重要 - 我碰巧经常使用'/;'。 当性能非常重要时,人们可能会寻找不同的算法,或者在失败的情况下使用Compile或符号C之类的东西。 - WReach
@WReach:很有趣。我一直以为时间会相反。即应用于单个模式的纯函数形式比本地变量上的测试更快... - Simon
3
可能的原因是ConditionFullForm比带有FunctionPatternTestFullForm要简单得多:f[x_ /; x \[Element] Reals] // FullFormf[x_?(Element[#, Reals] &)] // FullForm。在没有Function的情况下,PatternTest略微更快:ClearAll[f]; f[x_?NumericQ] := x; Timing[Do[f[10], {20000000}]]ClearAll[f]; f[x_ /; NumericQ[x]] := x; Timing[Do[f[10], {20000000}]]。这证实了您的洞察力,即我们应该根据上下文写出最清晰的形式。 - Alexey Popkov
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接