【问题标题】:Addition of Functions增加功能
【发布时间】:2011-10-25 22:32:47
【问题描述】:

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

【问题讨论】:

  • 谢谢,+1(顺便说一句,最好不要签署您的消息,因为这是多余的,因为您的身份会在每个问题或答案下方屏蔽它。)

标签: wolfram-mathematica


【解决方案1】:

考虑:

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

【讨论】:

  • 感谢Through 功能;我不知道!
  • 很好,谢谢。我正在写一个 gram-schmidt 函数;如果它适用于伪装成向量的通用对象,例如函数、列表等,那就太好了。我认为最好的办法可能是作为可选参数,“add”和“scale”,这样你就可以定义什么向量加法和缩放是,所以 gramm-schmidt 函数适用于一般对象。
  • @ yoda,请参阅之前的评论:我会有很长的函数列表,它们将是下一个向量在前一个正交归一化向量的跨度上的投影。
  • @nmaxwell,根据您对 Mathematica 的熟悉程度,您可能会发现以下信息:combine[{__funcs}, _operator] := Through[operator[funcs][#]] & -- 您可以像 h = combine[{f,g}, Plus] 一样使用它。
  • David Park 的 PushThrough 包用来回答类似问题:home.comcast.net/~djmpark/Mathematica.html
【解决方案2】:

另一种方法是使用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 以及何时使用它们的信息

【讨论】:

  • +1 -- 我没有建议 UpSet,因为我认为这个问题对于各种功能来说都是通用的,而不是专门针对 fg
  • 是的,你可能是对的......这是他最后的陈述,暗示他正在考虑重载运算符让我发布了一个指向它的答案。此外,我想不出任何其他方法,实际上在您回答后等待了大约 5-10 分钟,只是为了看看您是否会进行快速忍者编辑以包含 UpSet :D
【解决方案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)}

【讨论】:

    【解决方案4】:

    我建议为此目的定义一个内置 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 的调用会得到优化,这些优化可能不会考虑用户定义。但是,这种考虑可能不会影响任何特定的应用程序,因此该选项仍然是一个有效的(如果有风险的)设计选择。

    【讨论】:

    • 正如 OP 所说,函数加法是规范定义的,因此任何其他定义都是所有数学家所期望的偏差
    猜你喜欢
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 2016-09-15
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    相关资源
    最近更新 更多