25

I`m creating a script in Python Sympy library and trying to access the result returned by solveset() and linsolve() functions. My problem is that the object returned by these functions is of type finiteset and I want to select some results automaticaly to re-enter it in other equations. Any body could help me?

An example: I create a list of equations with two unknown variables:

>>> a1, a2 = symbols('a1, a2')
>>> eq2_1 = Eq(-3*a1/10 - 3*a2/20 + 1/12)
>>> eq2_2 = Eq(-3*a1/20 - 13*a2/105 + 1/20)
>>> lista = [eq2_1,eq2_2]
>>> str(lista)
[-3*a1/10 - 3*a2/20 + 1/12, -3*a1/20 - 13*a2/105 + 1/20]

Then a solve it with the linsolve() method.

>>> a = linsolve(lista,a1,a2)
>>> a
{(71/369, 7/41)} 

The result is correct, but I'm unable to get these results in to a variable.

O tried dics, lists, tuples, indexing commands, but always return the error. "Finiteset objects has no attribute 'command'"

Mike
  • 15,696
  • 10
  • 49
  • 75

6 Answers6

17

I found the sympy library way in this link http://docs.sympy.org/latest/tutorial/manipulation.html

Use .args atribute in the function or result object. If I have a function:

>>>func = Eq(u(x),−x+sin(x)) 
>>>func
u(x) = -x + sin(x)
>>>func.args[0] 
u(x)
>>>func.args[1]
-x+sin(x)

The same applies for a result that is a finite set type.

7

A slightly more general solution is to simply convert the FiniteSet into a standard python list

>>> a=list(linsolve(lista,a1,a2))
>>> a
[(71/369, 7/41)]

Then you can extract elements using standard indexing — in this case a[0]. But then if you get multiple solutions, you can just pull out the one you want.

Mike
  • 15,696
  • 10
  • 49
  • 75
4

You can use iter to get an iterator based on the set, and then next to return one element of that set (if you only need one element).

Example:

from sympy import *
var('x y')
sol = linsolve([x+y-2, 2*x-3*y], x, y)
(x0, y0) = next(iter(sol))

Now x0 is 6/5 and y0 is 4/5.

4

Weird. There's no description anywhere how to use the results of linsolve.

Even the specs only test the result set as a whole, without checking the elements separately.

Sequence unpacking

If you know that the system of equation admits at least one solution, you can use sequence unpacking with a trailing comma before the assignment :

>>> from sympy import linsolve, symbols, solve, Rational
>>> a1, a2 = symbols('a1 a2')
>>> equations = [-3*a1/10 - 3*a2/20 + Rational(1, 12), -3*a1/20 - 13*a2/105 + Rational(1, 20)]
>>> equations
[-3*a1/10 - 3*a2/20 + 1/12, -3*a1/20 - 13*a2/105 + 1/20]
>>> linsolve(equations, a1, a2)
{(71/369, 7/41)}
>>> solution, = linsolve(equations, a1, a2)
>>> solution
(71/369, 7/41)

This syntax will also work if there is an infinity of solution:

>>> solution, = linsolve([a1, a1], a1, a2)
>>> solution
(0, a2)

But it will fail if there are no solution:

>>> solution, = linsolve([a1 - 1, a1 - 2], a1, a2)
ValueError: not enough values to unpack (expected 1, got 0)

which might be the desired behaviour.

Iterate over the solutions:

Another possibility is to simply iterate over the solutions:

>>> for solution in linsolve(equations, a1, a2):
...     print(solution)
... 
(71/369, 7/41)

Nothing happens if there's no solution:

>>> for solution in linsolve([a1 - 1, a1 - 2], a1, a2):
...     print(solution)
... 

solve instead of linsolve

You could also use solve instead of linsolve, even though it's not recommended by the project because it can output different types:

>>> solve(equations, a1, a2)
{a1: 71/369, a2: 7/41}
>>> solve([a1 - 1, a1 - 2], a1, a2)
[]
Eric Duminil
  • 48,038
  • 8
  • 56
  • 100
1

You can use tuple in combination with argument unpacking:

var('x y z')
eqs = [ x + y + z - 1, x + y + 2*z - 3 ]
sol = linsolve( eqs, x, y, z )
(x0, y0, z0) = tuple(*sol)

Now you can check the solution with:

eqs[0].subs( [(x, x0), (y, y0), (z, z0)] )
eqs[1].subs( [(x, x0), (y, y0), (z, z0)] )
Stilunke
  • 11
  • 2
1

FiniteSet has an args() method that returns a tuple.

https://github.com/sympy/sympy/issues/19689

Ilya
  • 162
  • 9