一般来说,如果你有两个函数f,g:X - > Y,并且如果在Y上定义了一些二元运算+,则f + g具有规范定义作为函数x - > f(x)+ g(x)。
在Mathematica中实现此功能的最佳方法是什么?
f[x_] := x^2
g[x_] := 2*x
h = f + g;
h[1]
产量
(f + g)[1]
作为输出
当然,
H = Function[z, f[z] + g[z]];
H[1]
收益率'3'。
答案 0 :(得分:12)
考虑:
In[1]:= Through[(f + g)[1]]
Out[1]= f[1] + g[1]
详细说明,您可以像这样定义h
:
h = Through[ (f + g)[#] ] &;
如果您的函数和操作数有限,那么yoda推荐的UpSet
肯定在语法上更清晰。但是,Through
更为通用。如果没有涉及Times
或h
的任何新定义,可以轻松完成:
i = Through[ (h * f * g)[#] ] &
i[7]
43218
答案 1 :(得分:9)
执行您尝试执行的操作的另一种方法是使用UpSetDelayed
。
f[x_] := x^2;
g[x_] := 2*x;
f + g ^:= f[#] + g[#] &; (*define upvalues for the operation f+g*)
h[x_] = f + g;
h[z]
Out[1]= 2 z + z^2
另请参阅rcollyer的this very nice answer(以及Leonid和Verbeia的文章)了解UpValues
的更多内容以及何时使用它们
答案 2 :(得分:3)
我将为Gram - Schmidt提供一个完整的代码和一个函数添加等的例子,因为我碰巧有大约4年前编写的代码。虽然没有广泛测试。我现在没有更改它的一行,所以免责声明(我当时在mma上情况更糟)。也就是说,这是一个Gram-Schmidt程序实现,它是我讨论的代码here的略微概括版本:
oneStepOrtogonalizeGen[vec_, {}, _, _, _] := vec;
oneStepOrtogonalizeGen[vec_, vecmat_List, dotF_, plusF_, timesF_] :=
Fold[plusF[#1, timesF[-dotF[vec, #2]/dotF[#2, #2], #2]] &, vec, vecmat];
GSOrthogonalizeGen[startvecs_List, dotF_, plusF_, timesF_] :=
Fold[Append[#1,oneStepOrtogonalizeGen[#2, #1, dotF, plusF, timesF]] &, {}, startvecs];
normalizeGen[vec_, dotF_, timesF_] := timesF[1/Sqrt[dotF[vec, vec]], vec];
GSOrthoNormalizeGen[startvecs_List, dotF_, plusF_, timesF_] :=
Map[normalizeGen[#, dotF, timesF] &, GSOrthogonalizeGen[startvecs, dotF, plusF, timesF]];
上述函数由3个函数参数化,实现加法,乘以数,以及给定向量空间中的点积。要说明的例子是通过正交归一化单项式来找到Hermite
多项式。这些是我们需要的3种功能的可能实现:
hermiteDot[f_Function, g_Function] :=
Module[{x}, Integrate[f[x]*g[x]*Exp[-x^2], {x, -Infinity, Infinity}]];
SetAttributes[functionPlus, {Flat, Orderless, OneIdentity}];
functionPlus[f__Function] := With[{expr = Plus @@ Through[{f}[#]]}, expr &];
SetAttributes[functionTimes, {Flat, Orderless, OneIdentity}];
functionTimes[a___, f_Function] /; FreeQ[{a}, # | Function] :=
With[{expr = Times[a, f[#]]}, expr &];
这些功能可能有点天真,但它们会说明这个想法(是的,我也使用了Through
)。以下是一些说明其用途的示例:
In[114]:= hermiteDot[#^2 &, #^4 &]
Out[114]= (15 Sqrt[\[Pi]])/8
In[107]:= functionPlus[# &, #^2 &, Sin[#] &]
Out[107]= Sin[#1] + #1 + #1^2 &
In[111]:= functionTimes[z, #^2 &, x, 5]
Out[111]= 5 x z #1^2 &
现在,主要测试:
In[115]:=
results =
GSOrthoNormalizeGen[{1 &, # &, #^2 &, #^3 &, #^4 &}, hermiteDot,
functionPlus, functionTimes]
Out[115]= {1/\[Pi]^(1/4) &, (Sqrt[2] #1)/\[Pi]^(1/4) &, (
Sqrt[2] (-(1/2) + #1^2))/\[Pi]^(1/4) &, (2 (-((3 #1)/2) + #1^3))/(
Sqrt[3] \[Pi]^(1/4)) &, (Sqrt[2/3] (-(3/4) + #1^4 -
3 (-(1/2) + #1^2)))/\[Pi]^(1/4) &}
这些确实是正确归一化的Hermite多项式,因为很容易验证。内置HermiteH
的规范化是不同的。我们的结果归一化,因为可以将谐波振荡器的波函数归一化。根据变量获得多项式列表作为表达式是很简单的,比如x:
In[116]:= Through[results[x]]
Out[116]= {1/\[Pi]^(1/4),(Sqrt[2] x)/\[Pi]^(1/4),(Sqrt[2] (-(1/2)+x^2))/\[Pi]^(1/4),
(2 (-((3 x)/2)+x^3))/(Sqrt[3] \[Pi]^(1/4)),(Sqrt[2/3] (-(3/4)+x^4-3 (-(1/2)+x^2)))/\[Pi]^(1/4)}
答案 3 :(得分:2)
我建议为此目的定义除内置Plus
之外的运算符。 Mathematica提供了许多运算符,这些运算符在此类情况下保留用户定义。一个这样的运算符是CirclePlus
,它没有预先定义的含义,但是具有很好的紧凑表示(至少,它在笔记本中是紧凑的 - 在StackOverflow网页上不那么紧凑)。您可以定义CirclePlus
以执行功能添加:
(x_ \[CirclePlus] y_)[args___] := x[args] + y[args]
有了这个定义,你现在可以执行功能添加:
h = f \[CirclePlus] g;
h[x]
(* Out[3]= f[x]+g[x] *)
如果一个人喜欢生活在边缘,那么内置Plus
运算符可以使用相同的技术,前提是它首先不受保护:
Unprotect[Plus];
(x_ + y_)[args___] := x[args] + y[args]
Protect[Plus];
h = f + g;
h[x]
(* Out[7]= f[x]+g[x] *)
我通常建议不要改变内置函数的行为 - 特别是像Plus
那样基本的行为。原因是无法保证用户添加的Plus
定义将被其他内置函数或内核函数所遵循。在某些情况下,对Plus
的调用进行了优化,这些优化可能不会考虑用户定义。但是,这种考虑可能不会影响任何特定的应用程序,因此该选项仍然是有效的,如果有风险的设计选择。