2016-05-30 2 views
2

Рассмотрим следующее выражение в Python/SymPy:SymPy: Использование диких символов в качестве входных данных для функции

from sympy.abc import x, y 
expression = 3*x**2*y**1 + x**2*y**3 

Теперь я хочу, чтобы заменить x**n*y**m на max(n,m) помощью сопоставления с образцом:

from sympy import Wild 
n = Wild('n') 
m = Wild('m') 
expression = expression.replace(x**n*y**m,max(n,m)) 

Однако, Я получаю TypeError:

Traceback (most recent call last): 
    File "wild.py", line 15, in <module> 
    expression = expression.replace(x**n*y**m,max(n,m)) 
    File "/usr/lib/python3/dist-packages/sympy/core/relational.py", line 103, in __nonzero__ 
    raise TypeError("cannot determine truth value of\n%s" % self) 
TypeError: cannot determine truth value of 
    m_ > n_ 

The Pro очевидно, что при сопоставлении выражения sympy не преобразует значение символа Wild в согласованное значение перед пересылкой его в функцию max. Есть ли способ сделать эту работу?

Обратите внимание, что это простой пример более общей проблемы, которую я имею, поэтому обходной путь, который не обобщает хорошо, не очень полезен. Я особенно надеюсь, что существует решение, использующее выражение.

Update: По предложению Сандвичевых и замены max(n,m) от (m+n+abs(m-n))/2 работ, однако, функции я использую в моей реальной программе гораздо сложнее. Что касается проблемы упоминаемого бутерброда, что replace выполняет замены, начиная с нижней частью дерева выражений: если я использую exact=True и определить f = sympy.Function('f') затем следующие работы (за исключением, что я буду иметь дело с некоторыми случаями отдельно):

expression = expression.replace(x**n*y**m,f(n,m),exact=True) 

Это все еще, однако, не работает для max(n,m).

+0

Замена 'макс (т, п)' с математически эквивалентным '(т + п + абс (м-н))/2' помогает с ошибкой вы запускали в. Но есть большая проблема, так как 'replace' выполняет подстановки, начинающиеся в нижней части дерева выражений. Итак, 'x ** 2 * y ** 3' будет заменено на 1, потому что это' x * x * y * y * y', где каждый из пяти членов заменяется на 1. –

+0

@soup 'x * * 2 * y ** 3' представляется как 'Mul (Pow (x, 2), Pow (y, 3))', а не 'Mul (x, x, y, y, y)'. На самом деле единственным способом представления последнего является явное его создание с помощью 'evaluation = False'. – asmeurer

ответ

1

max является встроенной функцией Python, которая пытается сразу оценить, поэтому ошибки (она не может определить, какой из n и m больше, если они символичны).Вам, вероятно, нужна функция SymPy Max, которая работает символически. my_func, который вы определили в своем ответе, фактически является базовой реализацией Max.

In [14]: expression = expression.replace(x**n*y**m, Max(n,m)) 

In [15]: expression 
Out[15]: 4 

Кажется, это не работает (ответ 4 неверно). Проблема в том, что он соответствует x**2 как x**2*y**0. Поскольку математическое значение функции замены зависит от формы выражения, это проблематично, так как SymPy пытается быть умным. Вы действительно можете сделать n, а m не соответствует 0 с Wild('n', exclude=[x, 0]), но тогда есть проблема, что он не соответствует x**2*y как x**2*y**1.

Поэтому я рекомендую преобразовать ваше выражение в полином и точно выполнить замену. Надеемся, что это обобщающее хорошо, что вы на самом деле делает

In [18]: Poly(expression, x, y) 
Out[18]: Poly(x**2*y**3 + 3*x**2*y, x, y, domain='ZZ') 

In [19]: Poly(expression, x, y).terms() 
Out[19]: [((2, 3), 1), ((2, 1), 3)] 

In [20]: sum(max(pows)*coeff for pows, coeff in Poly(expression, x, y).terms()) 
Out[20]: 9 
+0

Спасибо, однако этот ответ проблематичен на нескольких уровнях: в первую очередь он дает неверный ответ: как легко проверить вручную, результат должен быть не 4, а вместо этого должен быть 9. Эта ошибка исходит из того, что выражение заменяется на '3 * Max (1,0)^2 * Max (0,1)^2 + Max (1,0)^2 * Max (0,2)^3', что легко увидеть, используя фиктивная функция. Однако использование флага 'exact = True' немного лучше, но в этом случае выражение' 3 * x ** 2 * y ** 1' выражения не попадает. Наконец, как я уже говорил, я хочу иметь возможность использовать более сложные функции, чем 'max' ... – kalix

+0

... (продолжение) Решение всех этих вопросов приводит к моему ответу. Я мог бы знать, как улучшить свой ответ, чтобы улучшить время выполнения, если я найду время, я буду исследовать это. – kalix

+0

@kalix я вижу. Реальная проблема заключается в том, что 'x ** n * y ** m -> Max (n, m)' не определено в математическом смысле. Я обновил ответ с помощью более прямого решения, используя 'Poly'. – asmeurer

0

Хорошо, я нашел решение, очень примечательно, хотя это может иметь отношение к тому факту, что я мало знаю о написании функций, которые прекрасно взаимодействуют с sympy.

Сначала я импортировать все соответствующие:

import sympy 
from sympy.abc import x, y, a, b,z 
from sympy import Wild 
from sympy import Function 

Тогда я определяю свою собственную функцию, которая будет возвращать максимум, вот возвращение макс (х, у) может быть заменена более сложной функции:

class my_func(Function): 
    @classmethod 
    def eval(cls, x, y): 
    if x.is_Number and y.is_Number: 
     return max(x,y) 

выражение Я хочу изменить это:

3*x**2*y**1 + x**2*y**3 

определяет НКА обходимо дикие символы и SymPy функция, которая используется временно, чтобы сделать замену без оценки:

n = Wild('n') 
m = Wild('m') 
k = Wild('k') 
f = Function('f') 
expression = expression.replace(x,f(1,0),exact=True) 
expression = expression.replace(y,f(0,1),exact=True) 
expression = expression.replace(f(1,0)**n,f(n,0),exact=True) 
expression = expression.replace(f(0,1)**n,f(0,n),exact=True) 
expression = expression.replace(k*f(0,m)*f(n,0),k*f(n,m),exact=True) 

Этих замен перехватывать все случаи, которые приходят в моей проблеме. На последнем этапе я заменяю f на my_func, который выполняет оценку.

expression = expression.replace(f(n,m),my_func(n,m)) 

Может быть кто-нибудь найдет более хорошее решение ....

Смежные вопросы