13

I know that sympy in python can set assumptions on variables, such as x is positive, negative, real, complex, etc. I was wondering if sympy can set assumptions on variables relative to other variables. For example, if I have variables x and y, can I set sympy to assume that x > y in its solutions. Or, alternatively, if I have two variables, a and B, can I set sympy to assume that a + 2B < 1? These sorts of assumptions would possibly help sympy simplify complicated solutions to solve() and eigenvectors.

I've looked all over and haven't found information pertaining to setting these kinds of assumptions in sympy.

I ask because I'm attempting to find the eigenvectors of a particular matrix

a,b = symbols('a,b', nonnegative=False)
M = Matrix([ [1-a-2*b, a, b, b], 
             [a, 1-a-2*b, b, b],
             [b, b, 1-a-2*b, a],
             [b, b, a, 1-a-2*b] ])

Sympy finds the eigenvalues correctly

M.eigenvals()

which I've confirmed via MATLAB and WolframAlpha, which all give the same results. However, the eigenvectors are a mess

M.eigenvects()

MATLAB and WolframAlpha both return eigenvectors of [1,1,1,1] [-1,-1,1,1] [0,0,-1,1] [-1,1,0,0], which are the correct eigenvectors. I haven't even tried to simplify sympy's results because they're incredibly long and complex. I suspect it has to do with assumptions on the variables, like specifying that a+2b < 1, but I'm not sure.

Nate
  • 1,888
  • 3
  • 18
  • 26

2 Answers2

13

I was wondering whether to post this as a comment but it is too long:

Short answer: not in a usable way.

The assumption system of SymPy is kind of a mess right now (version 0.7.2, latest as of May 2013). There is a possibility that it will get better this summer due to a prospective GSoC project, but this is not certain yet.

There are actually two assumption systems within SymPy. The old one, which adds the assumptions to the Symbols themselves (hence causes problems with rebuilding of expression trees) and is called in the constructor (e.g. Symbol(..., positive=True)), and there is the new one, which is based around global variables for the global assumptions and context managers (with assume(...):) for local ones.

Many of the functions within SymPy do check the old assumptions (for instance Abs will check whether the keyword argument positive was set), but there still can be misses. The new assumption system can be more powerful but is almost unused at the moment (except in very recent submodules).

In the old assumption system what you want is not possible. In the new one it is possible, but probably not implemented yet and not used in any parts of SymPy.

So you have two options: help us with the assumption systems or help us with the matrix module. Both can use some more love.

Krastanov
  • 6,479
  • 3
  • 29
  • 42
  • 1
    Hello, you seem to know a lot about the assumption system. Where can I learn more practical tips about the current state of the assumption system in late 2016? Sympy is now at version 1 and there seems to still be two assumption systems because there is the assumptions module and the symbol constructor assumptions. The documentation doesn't explain why there are still two systems or give guidance to know when to use one or the other. – Shaun Dec 02 '16 at 19:14
  • @Shaun, the best place to ask for updated instructions would be the sympy mailing list. – Krastanov Dec 04 '16 at 04:57
5

The assumptions are not coming into play here. That usually only matters if you have square roots, because sqrt(x**2) = x only if x >= 0.

All you need to do for this is simplify the result. Matrix.eigenvects has a simplify flag, but it apparently doesn't simplify the results. I'll open an issue for that. In the meanwhile, you can do so manually. Note that Matrix.simplify acts in-place (if you don't like that, you can use Matrix.applyfunc(simplify)

>>> A = M.eigenvects()
>>> A[0][2][0].simplify()
>>> A[1][2][0].simplify()
>>> pprint(A)
⎡⎛1, 1, ⎡⎡1⎤⎤⎞, ⎛-4⋅b + 1, 1, ⎡⎡-1⎤⎤⎞, ⎛-2⋅a - 2⋅b + 1, 2, ⎡⎡-1⎤, ⎡0 ⎤⎤⎞⎤
⎢⎜      ⎢⎢ ⎥⎥⎟  ⎜             ⎢⎢  ⎥⎥⎟  ⎜                   ⎢⎢  ⎥  ⎢  ⎥⎥⎟⎥
⎢⎜      ⎢⎢1⎥⎥⎟  ⎜             ⎢⎢-1⎥⎥⎟  ⎜                   ⎢⎢1 ⎥  ⎢0 ⎥⎥⎟⎥
⎢⎜      ⎢⎢ ⎥⎥⎟  ⎜             ⎢⎢  ⎥⎥⎟  ⎜                   ⎢⎢  ⎥  ⎢  ⎥⎥⎟⎥
⎢⎜      ⎢⎢1⎥⎥⎟  ⎜             ⎢⎢1 ⎥⎥⎟  ⎜                   ⎢⎢0 ⎥  ⎢-1⎥⎥⎟⎥
⎢⎜      ⎢⎢ ⎥⎥⎟  ⎜             ⎢⎢  ⎥⎥⎟  ⎜                   ⎢⎢  ⎥  ⎢  ⎥⎥⎟⎥
⎣⎝      ⎣⎣1⎦⎦⎠  ⎝             ⎣⎣1 ⎦⎦⎠  ⎝                   ⎣⎣0 ⎦  ⎣1 ⎦⎦⎠⎦
asmeurer
  • 86,894
  • 26
  • 169
  • 240
  • Ah. Thanks! This solves actually solves a number of issues I was having. I have run into issues with eigenvectors containing square roots, like sqrt( (K-a)**2 ). It would be nice to be able to specify an assumption that K > a so this simplifies as positive. Based on the post above, it appears this isn't possible yet. – Nate May 08 '13 at 19:51
  • 1
    You can do it to some degree with the new assumptions. Try `refine(expr, Q.positive(K - a))`. – asmeurer May 09 '13 at 00:07
  • I tried this. If I do refine( sqrt((K-a)**2), Q.positive(K-a) ), I get |K-a| when it should be K-a since K-a is defined as positive. It's the same result I get if I assume that both K and a are positive, using K,a = symbols('K, a', positive=True); sqrt((K-a)**2). – Nate May 09 '13 at 01:50
  • Ah, it seems that was a bug that has since been fixed in the git version of SymPy. – asmeurer May 09 '13 at 02:16