Sympy's subs limitations
<p>I am working with some long equations but not really complex, and I wanted to use <strong>sympy</strong> to simplify and "factorize" them. But I have encountered a few problems. Here is a list of some minimal examples:</p>

<p><strong>Problem 1: symmetry</strong></p>

<pre><code>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)
</code></pre>

<p>The first line gives the expected result (ie. <code>a+1</code>) while in the second one there is no substitution.</p>

<p><strong>Problem 2: factorized expressions</strong></p>

<p>Some parts of the expression are factorized and when I expand the expression they get simplified, thus making the substitution impossible. For example</p>

<pre><code>(((x+1)**2-x).expand()).subs(x**2+2*x, y+1)
</code></pre>

<p>will give <code>x^2+x+1</code> and what I am looking for is <code>y+2-x</code>.</p>

<p><strong>Question</strong></p>

<p>Is there a way to solve these problems ? Or maybe I should use another symbolic mathematical tool ? Any suggestions are welcomed.</p>

<p>There is a major gotcha in SymPy, which is that, because of the way Python works, <code>number/number</code> gives a floating point (or does integer division if you use Python 2 and don't <code>from __future__ import division</code>). </p>

<p>In the first case and in your original expression, Python evaluates <code>1/12*b</code> from left to right. <code>1/12</code> is evaluated by Python to give <code>0.08333333333333333</code>, which is then multiplied by <code>b</code>. In the second case, <code>b*1</code> is evaluated as <code>b</code>. Then <code>b/12</code> is evaluated by SymPy (because <code>b</code> is a SymPy object), to give <code>Rational(1, 12)*b</code>. </p>

<p>Due to the inexact nature of floating point numbers, SymPy does not see the float <code>0.08333333333333333</code> as equal to the rational <code>1/12</code>. </p>

<p>There is some more discussion of this issue <a href="http://docs.sympy.org/latest/tutorial/gotchas.html" rel="nofollow">here</a>. As a workaround, you should avoid direct <code>integer/integer</code> without wrapping it somehow, so that SymPy can create a rational. The following will all create a rational:</p>

<pre><code>b/12
Rational(1, 12)*b
S(1)/12*b
</code></pre>

<hr>

<p>For <code>(((x+1)**2-x).expand()).subs(x**2+2*x, y+1)</code> the issue is that <code>x**2 + 2*x</code> does not appear exactly in the expression, which is <code>x**2 + x + 1</code>. SymPy generally only replaces things that it sees exactly. </p>

<p>It seems you don't mind adding and subtracting an <code>x</code> to make the replacement work. So I would suggest doing instead <code>(((x+1)**2-x).expand()).subs(x**2, y+1 - 2*x)</code>. By only substituting a single term (<code>x**2</code>), the substitution will always work, and the <code>2*x</code> will cancel out to leave whatever <code>x</code> term remains (in this case, <code>-x</code>). </p>

python sympy substitution symbolic-math