как сделать такую ​​замену в mathematica - PullRequest
1 голос
/ 05 февраля 2011

В случае, если я не хочу использовать функции mma Erfc или Erf, я хочу определить свои собственные

myErf[x_] := Integrate[Exp[-y^2/2], {y, -Infinity, x}];

И затем я хочу, чтобы mma заменила любое вычисление интеграла на myErf [x]Например:

Integrate[Exp[-y^2+y/2], {y, x, Infinity}]

Как это сделать?Или вообще, как попросить mma оценить выражение, используя функцию, которую я хотел бы использовать вместо ее встроенной функции?Есть ли способ сделать это?

Большое спасибо.

Ответы [ 2 ]

3 голосов
/ 05 февраля 2011

Более мягкий способ - использовать 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]] обычно вы можете:

  • Переопределить значения DownValues ​​для g - это будет работать, если вы хотите, чтобы 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 [что-то] само по себе не будет вычислять что-то другое, либо вам придется временно добавить атрибут Hold - к ​​f, что еще более навязчиво.Если f является системной функцией, то этот метод является последним средством.Особенно избегайте этого, если f является нетривиальной или часто используемой и важной встроенной функцией, поскольку трудно предвидеть все последствия таких изменений, в то время как многие системные функции используют другие системные функции на верхнем уровне.

  • Напишите свои собственные лексические ограничивающие конструкции, которые будут анализировать код в неоцененной форме и делать правильные замены, и только после этого позволять коду оценивать.Это потребует, чтобы у вас был доступ к вашему коду в одной части (то есть код должен существовать в той форме, которую вы хотите с самого начала), что является серьезным ограничением, поэтому на практике этот параметр исключается в большинстве случаев.

Существует также трюк Block, который позволяет вам "локализовать ущерб", делая такие переопределения динамически локальными для блока кода, к которому вы хотите их применить.В некоторых случаях я нахожу это необходимым, потому что это позволяет не локально контролировать процесс оценки, который нелегко воспроизвести с помощью других языковых конструкций.

3 голосов
/ 05 февраля 2011

В моем комментарии я имел в виду, что наивный

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.


Редактировать: Самый простой и, возможно, самый безопасный / самый мягкий способ (благодаря Леониду) делать то, что вы хотите, это просто 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].Возможно, вы захотите реализовать эту часть немного лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...