2016-09-05 4 views
1

Я работаю с длинными уравнениями, но не очень сложный, и я хотел использовать sympy, чтобы упростить и «разложить» их. Но я столкнулся с несколькими проблемами. Вот список некоторых минимальных примеров:Ограничения на подписку Sympy

Задача 1: симметрия

from sympy import * 
from __future__ import division 
a = symbols('a') 
b = symbols('b') 
expr = 1/12*b + 1 
expr.subs(1/12*b, a) 
expr.subs(b*1/12, a) 

Первая строка дает ожидаемый результат (т.е. a+1.), А во втором нет никакой замены.

Проблема 2: факторизованная выражения

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

(((x+1)**2-x).expand()).subs(x**2+2*x, y+1) 

x^2+x+1 даст и то, что я ищу это y+2-x.

Вопрос

Есть ли способ, чтобы решить эти проблемы? Или, может быть, я должен использовать другой символический математический инструмент? Любые предложения приветствуются.

ответ

4

Существует большой глюк в SymPy, которая является то, что из-за работ на Python пути, number/number дает плавающей точкой (или же целочисленное деление, если вы используете Python 2 и не from __future__ import division).

В первом случае и в вашем исходном выражении Python оценивает 1/12*b слева направо. 1/12 оценивается Python, чтобы дать 0.08333333333333333, который затем умножается на b. Во втором случае b*1 оценивается как b. Затем b/12 оценивается по SymPy (потому что b является объектом SymPy), чтобы дать Rational(1, 12)*b.

Из-за неточного характера чисел с плавающей запятой SymPy не видит поплавок 0.08333333333333333 как равный рациональному 1/12.

Есть еще несколько обсуждений по этому вопросу here. В качестве обходного пути вам следует избегать прямого integer/integer, не оборачивая его каким-либо образом, чтобы SymPy мог создать рациональное. Ниже будет все создать рациональную:

b/12 
Rational(1, 12)*b 
S(1)/12*b 

Для (((x+1)**2-x).expand()).subs(x**2+2*x, y+1) Вопрос заключается в том, что x**2 + 2*x не появляется именно в выражении, которое x**2 + x + 1. SymPy обычно заменяет только то, что он видит.

Кажется, вы не против добавления и вычитания x, чтобы выполнить замену. Поэтому я бы предложил вместо этого сделать (((x+1)**2-x).expand()).subs(x**2, y+1 - 2*x). Подставляя только один термин (x**2), замена всегда будет работать, и будет отменять, чтобы оставить все остальное (-x).

1

Вот возможное решение ваших проблем:

from sympy import * 

a = symbols('a') 
b = symbols('b') 
expr = 1/12 * b + 1 
print(expr.subs((1/12) * b, a)) 
print(expr.subs(b * (1/12), a)) 

x = symbols('x') 
y = symbols('y') 
expr = ((x + 1)**2 - x).expand() 
print(expr.subs(x**2 + x, y - x + 1)) 
+0

Для первой проблемы я думаю, что существует 'от __future__ import division ', с этим дополнением я пробовал и работает. Однако я не понимаю, почему. Для второй проблемы это действительно не решает мою проблему. То, что я здесь приводил, - это минимальные примеры, но на самом деле уравнения действительно длинны. Я не могу «обмануть» результаты. И я определенно не могу изменить значение, которое нужно заменить ... Спасибо, что ответили! – lasofivec

+0

Для второго вопроса, может быть, мой вопрос: «Можно ли расширять без упрощения»? – lasofivec

1

Что касается задачи 1, отметим, что 1/12*b и b*1/12 являются не то же самое в SymPy. Первый - это плавающее число, mutliplied символом, тогда как второе является точным символическим выражением (вы можете проверить его простым заявлением печати). Так как expr содержит 1/12*b, неудивительно, что второй subs не работает.

Что касается проблемы 2, то правило subs, которое вы предоставляете, неоднозначно. В частности, правило подстановки означает, что уравнение x**2+2*x==y+1. Однако это уравнение имеет множество интерпретаций, например,

x**2 == y + 1 - 2*x (это один вы считаете),

x**2 + x == y + 1 - x,

x == (y + 1 - x**2)/2,

По этой причине я считаю SymPy, отказываясь выполнять подстановка на самом деле является правильным подходом.

Если это первая интерпретация, которую вы хотите, лучше явно указать ее в правиле subs, т.е.,

(((x+1)**2-x).expand()).subs(x**2, -2*x + y + 1) 

-x + y + 2

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