Добавление функций
Итак, если у вас есть две функции 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
Рассмотрим:
In[1]:= Through[(f + g)[1]]
Out[1]= f[1] + g[1]
Чтобы уточнить, вы можете определить h
следующим образом:
h = Through[ (f + g)[#] ] &;
Если у вас ограниченное количество функций и операндов, то UpSet
в соответствии с рекомендациями yoda, безусловно, синтаксически чище. Однако Through
является более общим. Без каких-либо новых определений с участием Times
или h
можно легко сделать:
i = Through[ (h * f * g)[#] ] &
i[7]
43218
Ответ 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 (а также от Леонида и Вербеи) для более UpValues
и когда использовать их
Ответ 3
Я напишу полный код для Gram-Schmidt и пример добавления функции и т.д., так как у меня был этот код, написанный около 4 лет назад. Однако не проверял широко. Теперь я не изменил ни одной строки, поэтому отказ от ответственности (в то время я был намного хуже на mma). Тем не менее, здесь представлена реализация процедуры Gram-Schmidt, которая представляет собой слегка обобщенную версию кода, который я обсуждал здесь здесь:
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]];
Вышеуказанные функции параметризуются тремя функциями, реализующими сложение, умножение на число и произведение точек в данном векторном пространстве. Примером для иллюстрации будет найти полиномы Hermite
ортонормирующими одночленами. Это возможные реализации для трех функций, которые нам нужны:
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) &}
Это действительно правильно нормированные полиномы Эрмита, как легко проверить. Нормализация встроенного 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
оптимизируются, и эти оптимизации могут не учитывать учетные данные пользователя. Тем не менее, это соображение может не повлиять на какое-либо конкретное приложение, поэтому этот вариант по-прежнему является допустимым, если не рискованным, выбором дизайна.