Разверните функцию из произвольного числа аргументов, если она линейна в каждом аргументе - PullRequest
0 голосов
/ 16 мая 2018

Есть ли способ написать правило замены для функции f с произвольным числом аргументов, которое делает ее линейной по всем аргументам? Пример, когда f имеет три аргумента:

  1. f (x1 + x4, x2, x3) = f (x4, x2, x3) + f (x1, x2, x3)
  2. f (x1, x2 + x4, x3) = f (x1, x2, x3) + f (x1, x4, x3)
  3. f (x1, x2, x3 + x4) = f (x1, x2, x3) + f (x1, x2, x4)

Использование «Wild» работает частично:

from sympy import *
f=Function('f')
var("x1:5")
a=Wild("a")
b=Wild("b")
A=Wild('A', exclude=[0])
B=Wild('B', exclude=[0])
expr=f(x1,x2+x4,x3);
print("This one works")
print expr , '->' , expr.replace(f(a,Add(A,B),b),f(a,A,b)+f(a,B,b))
# f(x1, x2 + x4, x3) -> f(x1, x2, x3) + f(x1, x4, x3)
print("This one doesn't on the last entry")
expr=f(x1,x2,x3+x4);
print f(x1,x2,x3+x4) , '->' , expr.replace(f(a,Add(A,B),b),f(a,A,b)+f(a,B,b))
# f(x1, x2, x3 + x4) -> f(x1, x2, x3 + x4)

Я знаю, что мог бы различными способами перебирать аргументы функции, изменяя замену, но я надеялся, что функциональность уже встроена в "Wild" или "replace". Например, Mathematica имеет «подстановочные знаки», такие как «a ___, b ___, A ___, B___», которые означают, что «a___» может быть пустой последовательностью, или одним аргументом, или последовательностью нескольких аргументов. Например, в Mathematica,

expr /. f[a__,A_Plus,b__] :> f[a,A[[1]],b]+f[a,A[[2;;]],b]

правильно упростит как тестовые случаи, так и f с любым количеством аргументов.

Есть ли что-то похожее, или это близко к симпати?

В качестве альтернативы, возможно ли это сделать при распаковке аргумента в рекурсивном определении, начиная с чего-то вроде def f(*args):?

1 Ответ

0 голосов
/ 16 мая 2018

Вместо сопоставления Wild, я бы обнаружил, какие аргументы f являются Add, и расширил бы аргументы, используя itertools.product

import itertools
term_groups = [term.args if term.func is Add else (term,) for term in expr.args]
expanded = Add(*[expr.func(*args) for args in itertools.product(*term_groups)])

Например, если expr равно f(x1+x2+x4, x2+x4, x3*x1), то term_groups равно [(x1, x2, x4), (x2, x4), (x1*x3,)], где последний аргумент дает кортеж из 1 элемента, поскольку это не Add. И expanded является

f(x1, x2, x1*x3) + f(x1, x4, x1*x3) + f(x2, x2, x1*x3) + f(x2, x4, x1*x3) + f(x4, x2, x1*x3) + f(x4, x4, x1*x3)
...