如果我不想使用mma的Erfc或Erf函数,我想定义自己的
myErf[x_] := Integrate[Exp[-y^2/2], {y, -Infinity, x}];
然后我希望mma用myErf [x]代替积分的任何evalulation,例如:
Integrate[Exp[-y^2+y/2], {y, x, Infinity}]
怎么做?或者一般来说,如何让mma使用我想要使用的函数来评估表达式,而不是使用自己的内置函数?有没有办法做到这一点?
非常感谢。
答案 0 :(得分:3)
我在评论中的意思是天真的
Unprotect[Integrate];
Integrate[Exp[-y_^2], {y_, -\[Infinity], x_}] := myErf[x]
尝试拦截某些Integrate
评估不起作用。
实际上它确实有效
In[]:= Integrate[Exp[-y^2],{y,-Infinity,z}]
Out[]= myErf[z]
(这将教会我在午夜回答SO问题)。
所以,也许您不需要下面给出的myIntegrate
函数。
无论如何......评论中给出的两个备选方案是:
1)您可以使用类似
之类的内容编写自己的Erf
集成商
In[1]:= myErf[x_?NumericQ]:=NIntegrate[Exp[-y^2],{y,-\[Infinity],x}]
(* sames as Erf up to constant and scaling *)
In[2]:= Clear[myIntegrate]
myIntegrate[a_. Exp[b_. y_^2], {y_, -\[Infinity], x_}] /; FreeQ[{a, b}, y] := ConditionalExpression[myErf[x], b < 0]
myIntegrate[a_. Exp[b_. y_^2], {y_, xx_, x_}] := myIntegrate[a Exp[b y^2], {y, -\[Infinity], x}] - myIntegrate[a Exp[b y^2], {y, -\[Infinity], xx}]
myIntegrate[a_ + b_, lims__] := myIntegrate[a, lims] + myIntegrate[b, lims] (* assuming this is ok *)
myIntegrate[expr_, lims__] := Integrate[expr, lims]
In[8]:= myIntegrate[a Exp[x]+b Exp[-b x^2],{x,2y,z}]
Out[8]= ConditionalExpression[a (-E^(2 y)+E^z) - myErf[2 y] + myErf[z], b > 0]
最后,剩余的积分将传递给Integrate
。但是你必须更聪明地进行模式匹配(可能包括中间步骤中的一些转换),以便捕获所有类似函数的Erf
。
<强> 2)强>
您覆盖Erf
- 类型函数,以便它们永远不会使用内置例程进行评估:
In[9]:= Clear[myErf];
Unprotect[Erf,Erfc,Erfi];
In[10]:= Erf[x__] := myErf[x]
Erfc[x__]:= myErfc[x]
Erfi[x__]:= myErfi[x]
In[13]:= {Erf[1], Erfc[2], Erfi[\[Pi]], Integrate[E^-x^2,x]}
Out[13]= {myErf[1], myErfc[2], myErfi[\[Pi]], 1/2 Sqrt[Pi] myErf[x]}
显然,您可以为myErf
函数选择自己的约定。
修改强>
最简单,也许是最安全/最软的方法(感谢Leonid)做你想要的只是Block[{Erf=...},...]
并让Mathematica集成商完成所有的工作。
例如,您myErf
被指定为
In[1]:= myErf[x] == Integrate[Exp[-y^2/2], {y, -Infinity, x}]
Out[1]= myErf[x]==Sqrt[Pi/2] (1+Erf[x/Sqrt[2]])
所以要解决原帖中的积分,
In[2]:= Block[{Erf = (Sqrt[2/Pi]*myErf[Sqrt[2] #] - 1 &)},
Integrate[Exp[-y^2 + y/2], {y, x, Infinity}]]
Out[2]= (E^(1/16)(Sqrt[\[Pi]] (-1 + 4 x + Sqrt[(-1 + 4 x)^2]) +
Sqrt[2] (1 - 4 x) myErf[Sqrt[2] Sqrt[(-(1/4) + x)^2]])
)/(2 Sqrt[(1 - 4 x)^2])
编辑2:
也许你只需要能够翻译myErf
表达式。
这意味着它不会是自动的,但它会灵活。尝试
In[1]:= toMyErf=(FunctionExpand[#]/.Erf:>(Sqrt[2/Pi]*myErf[Sqrt[2] #]-1&)&);
fromMyErf=(#/.myErf:>(Sqrt[Pi/2] (1+Erf[#/Sqrt[2]])&)&);
In[3]:= Integrate[Exp[-y^2+y/2],{y,x,Infinity}]//toMyErf
Out[3]= 1/2 E^(1/16) Sqrt[\[Pi]] (2-Sqrt[2/\[Pi]] myErf[Sqrt[2] (-(1/4)+x)])
In[4]:= D[x*myErf[x+x^2],x]//fromMyErf//toMyErf
Out[4]= E^(-(1/2) (x+x^2)^2) x (1+2 x)+myErf[x+x^2]
请注意,FunctionExpand
命令可以将Erfc[x]
重写为1-Erf[x]
。您可能希望稍微更好地实现该部分。
答案 1 :(得分:3)
更柔和的方法是使用UpValues
:
ClearAll[withMyErf];
SetAttributes[withMyErf, HoldAll];
withMyErf[code_] :=
Block[{Exp},
Exp /: Integrate[Exp[(a : _ : 1)*x_^2], {x_, t0_, t_}] :=
ConditionalExpression[(Sqrt[Pi]*(myErf[Sqrt[-a]*t] - myErf[Sqrt[-a]*t0]))/(2*Sqrt[-a]),
Re[a] < 0];
code]
示例:
In[4]:= withMyErf[Integrate[Exp[-3*x^2], {x, -Infinity, t}]]
Out[4]= 1/2 Sqrt[\[Pi]/3] (myErf[Sqrt[3] t] - myErf[-\[Infinity]])
在我们的自定义“动态范围构造”之外,一切都将照常工作。将代码放在您希望在其中发生的位置。并且,Integrate
没有任何变化,这可能是危险的。我们所冒的全部风险是Exp不会评估,但我认为大多数符号转换规则都是本地规则。
编辑:
回答一般问题,如果你想改变Mathematica评估事物的标准方式,你有几个选择。在之前的答案中已经提到了其中一些,我只是想在更抽象的层面上对它们进行总结。给定表达式f[g[something]]
,通常可以:
重新定义g
的DownValues - 如果您希望将g
重写为其他内容,这将有效
在f
“看到”它之前,但仅当f
不将其参数保持在g[something]
的位置时
代表
针对UpValue
或类似情况,为g
添加f[g[_]]
。这将适用于你
想要以一种柔和的方式改变f
的行为,也就是说,只在与形式相匹配的参数上改变
UpValue
定义(在这种情况下为f[g[_]]
)。为此,g
不应该有
DownValues
匹配g[something]
(因此不会评估),或f
应该保留它
论点。这是f
是系统函数并且g
是用户定义的典型用例,因为
这是改变系统功能行为的最软方式 - 请注意f
行为不同,规则附加到g
。
将DownValue
添加到f
。这是一种“艰难”的方式。如果f
持有其参数,或者如果。{
g [something]本身不会评估别的东西,或者你必须暂时添加
保持 - 属性为f
,这更具侵入性。如果f
是系统函数,那么这个
方法是最后的手段。如果f
是非平凡的或经常使用的,那么尤其要避免这种情况
重要的内置功能,因为很难预见到这种后果的所有后果
修改,而许多系统功能在顶层使用其他系统功能。
编写自己的词法范围构造,它将以未评估的形式分析代码 做适当的替换,然后才允许代码进行评估。这需要你 可以访问您的代码(也就是说,代码必须以您想要的形式存在 开始),这是一个严格的限制,所以实际上在大多数情况下排除了这个选项。
还有一个Block
技巧,它允许您通过将这些重新定义动态地本地化为您希望它们应用的代码块来“本地化损坏”。在某些情况下,我发现它是不可或缺的,因为它允许非本地控制评估过程的方法,这些方法不容易被其他语言结构复制。