增加功能

时间:2011-10-25 22:32:47

标签: wolfram-mathematica

一般来说,如果你有两个函数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'。

4 个答案:

答案 0 :(得分:12)

考虑:

In[1]:= Through[(f + g)[1]]

Out[1]= f[1] + g[1]

详细说明,您可以像这样定义h

h = Through[ (f + g)[#] ] &;

如果您的函数和操作数有限,那么yoda推荐的UpSet肯定在语法上更清晰。但是,Through更为通用。如果没有涉及Timesh的任何新定义,可以轻松完成:

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的调用进行了优化,这些优化可能不会考虑用户定义。但是,这种考虑可能不会影响任何特定的应用程序,因此该选项仍然是有效的,如果有风险的设计选择。