Convert from a system of linear equations to a matrix

1,548 views
Skip to first unread message

Aaron Meurer

unread,
Oct 10, 2013, 8:49:14 PM10/10/13
to sy...@googlegroups.com
Is there a function in SymPy that makes it easy to convert from a
system of linear equations in symbolic form to a Matrix? I'm asking
because solve_linear_system takes a Matrix as input.

Aaron Meurer

Cristóvão Duarte Sousa

unread,
Oct 11, 2013, 6:59:26 AM10/11/13
to sy...@googlegroups.com
Hi Aaron,

I've found Expr.as_coefficients_dict() method useful for that, although I had to workaround constant and single variable expressions.

Check the function lin_expr_coeffs (https://github.com/cdsousa/PyLMI-SDP/blob/master/lmi_sdp/lm.py#L27) of my PyLMI-SDP package,
to see how I used it.

Aaron Meurer

unread,
Oct 11, 2013, 1:20:33 PM10/11/13
to sy...@googlegroups.com
That's useful, we should put that in SymPy, though I personally think
it would be more useful if it just took a system and returned a
matrix.

Aaron Meurer
> --
> You received this message because you are subscribed to the Google Groups
> "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sympy+un...@googlegroups.com.
> To post to this group, send email to sy...@googlegroups.com.
> Visit this group at http://groups.google.com/group/sympy.
> For more options, visit https://groups.google.com/groups/opt_out.

Cristóvão Duarte Sousa

unread,
Oct 24, 2013, 5:18:33 AM10/24/13
to sy...@googlegroups.com
Hi Aaron,

Sorry for the late reply.
Yes, the lin_expr_coeffs function can be extended to accept a linear
equation system.
Feel free, anyone, to take it and make a PR. If I find some time I can
do it, but that will not happen soon...
> You received this message because you are subscribed to a topic in the Google Groups "sympy" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/sympy/Wqs1OhTBexg/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to sympy+un...@googlegroups.com.

Chris Smith

unread,
Nov 13, 2013, 10:30:04 PM11/13/13
to sy...@googlegroups.com
You can just pass the system to solve and let it call solve_linear_system, can't you?  Otherwise

>>> s
(x + 2*y == 4, y/2 == -2*c)
>>> sym = (x, y)
>>> m = []
>>> rhs = []
>>> for si in s:
...   if isinstance(si, Equality): si = si.lhs - si.rhs
...   i, d = si.as_independent(*sym)
...   m.append(d)
...   rhs.append(-i)
...
>>> Matrix(m).jacobian(sym)
Matrix([
[1,   2],
[0, 1/2]])
>>> Matrix(rhs)
Matrix([
[ 4],
[-2*c]])

(This doesn't check that the system is linear, but you could just check that it is symbol-free:

>>> Matrix(m).jacobian(sym).atoms(Symbol)
set([])

[There is no free_symbols attribute for it: AttributeError: MutableDenseMatrix has no attribute free_symbols.]

Chris Smith

unread,
Nov 13, 2013, 11:56:22 PM11/13/13
to sy...@googlegroups.com
I forgot that as_independent, without the as_Add=True flag will treat Muls differently. The following will be more robust:

def eqs2matrix(eqs, syms, augment=False):
    """
    >>> s
    [x + 2*y == 4, 2*c + y/2 == 0]
    >>> eqs2matrix(s, (x, c))
    (Matrix([
    [1, 0],
    [0, 2]]), Matrix([
    [-2*y + 4],
    [    -y/2]]))
    >>> eqs2matrix([2*c*(x+y)-4],(x, y))
    (Matrix([[2*c, 2*c]]), Matrix([[4]]))
    """
    s = Matrix([si.lhs - si.rhs if isinstance(si, Equality) else si for si in eqs])
    sym = syms
    j = s.jacobian(sym)
    rhs = -(s - j*Matrix(sym))
    rhs.simplify()
    if augment:
        j.col_insert(0, rhs)
    else:
        j = (j, rhs)
    return j

Andrei Berceanu

unread,
Jun 5, 2014, 5:22:52 PM6/5/14
to sy...@googlegroups.com
Was this implemented into sympy at any point? It could be the equivalent of Mathematica's CoefficientArrays function.

James Crist

unread,
Jun 7, 2014, 1:28:47 AM6/7/14
to sy...@googlegroups.com
I just answered this on gitter earlier today, but you can just take the jacobian of the system to get its matrix form. For example:

In [1]: from sympy import *

In [2]: a, b, c, d = symbols('a, b, c, d')

In [3]: x1, x2, x3, x4 = symbols('x1:5')

In [4]: x = Matrix([x1, x2, x3, x4])

In [5]: system = Matrix([a*x1 + b*x2 + c,
   ...: c*x1 + d*x3 + 2,
   ...: c*x3 + b*x4 + a])

In [6]: A = system.jacobian(x)

In [7]: B = A*x - system

In [8]: A
Out[8]:
Matrix([
[a, b, 0, 0],
[c, 0, d, 0],
[0, 0, c, b]])

In [9]: B
Out[9]:
Matrix([
[-c],
[-2],
[-a]])

In [10]: assert A*x - B == system

The functionality I'm adding for my GSoC for linearizing a system of equations will also be able to return these matrices in a convenient form. But it's not terribly difficult to solve for these arrangements using the current functionality.

Aaron Meurer

unread,
Jun 13, 2014, 7:45:48 PM6/13/14
to sy...@googlegroups.com
That's a clever trick. I should have thought of that.

Is there any reason you let system = A*x - B instead of A*x + B? The
latter seems more natural.

Aaron Meurer
> --
> You received this message because you are subscribed to the Google Groups
> "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sympy+un...@googlegroups.com.
> To post to this group, send email to sy...@googlegroups.com.
> Visit this group at http://groups.google.com/group/sympy.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/sympy/8fb2dae4-9f46-4c1b-b96f-83033278c27d%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.

James Crist

unread,
Jun 14, 2014, 7:29:21 PM6/14/14
to sy...@googlegroups.com
It's just the convention I'm most used to. Systems that can be expressed as A*x = B I usually solve for x, or if A isn't square, the least squares solution x. In both cases you need A and B in this form. I suppose Ax + B could seem more natural though.

Aaron Meurer

unread,
Jun 14, 2014, 7:44:21 PM6/14/14
to sy...@googlegroups.com
Oh, of course. B is on the rhs. This is probably more natural to me too.

Should we make a convenience function that does this? I think this use
of jacobian would be lost on most people.

Aaron Meurer
> https://groups.google.com/d/msgid/sympy/a9c5f7ba-1c2d-4673-a8d4-b1253c150054%40googlegroups.com.

James Crist

unread,
Jun 15, 2014, 11:26:09 AM6/15/14
to sy...@googlegroups.com
We certainly could. The question would then be what the scope of the method should be. Should it only handle systems that can be expressed as Ax = b? Or should it behave like `CoefficientArrays` mentioned above, and handle Ax + Bx^2 + Cx^3 + D = 0? Either way, I think it should error if the form can't be matched exactly (i.e. don't linearize, just express a linear, or polynomial, system as matrices).

Aaron Meurer

unread,
Jun 24, 2014, 1:01:56 PM6/24/14
to sy...@googlegroups.com
A multidimensional version of collect() would probably be the best abstraction.

Aaron Meurer
> https://groups.google.com/d/msgid/sympy/0b486c56-8a2b-48a5-a210-f49b6d39899f%40googlegroups.com.

Adam Leeper

unread,
Oct 7, 2015, 11:51:36 AM10/7/15
to sympy
Hi all-

Interested party just wondering if there is any update on this.

Cheers,
Adam

Jason Moore

unread,
Oct 7, 2015, 11:53:02 AM10/7/15
to sy...@googlegroups.com
We've just introduced a function called linsolve from the GSoC work this summer. It has the capability to do this.

AMiT Kumar

unread,
Oct 8, 2015, 9:46:10 AM10/8/15
to sympy
Yeah, It's linear_eq_to_matrix in sympy.solvers.solveset.

Example:

    >>> eqns = [x + 2*y + 3*z - 1, 3*x + y + z + 6, 2*x + 4*y + 9*z - 2]
   
>>> A, b = linear_eq_to_matrix(eqns, [x, y, z])
   
>>> A
   
Matrix([
   
[1, 2, 3],
   
[3, 1, 1],
   
[2, 4, 9]])
   
>>> b
   
Matrix([
   
[ 1],
   
[-6],
   
[ 2]])


AMiT Kumar

Adam Leeper

unread,
Oct 9, 2015, 12:58:41 PM10/9/15
to sympy
Yeah, It's linear_eq_to_matrix in sympy.solvers.solveset.

Looks like it's just sympy.solveset.linear_eq_to_matrix.

Thanks!
Adam 

Riku Kivelä

unread,
Oct 10, 2015, 2:50:37 PM10/10/15
to sympy
Stupid question: How do I import this thing?

I updated sympy using Anacondas command 
conda update sympy

and this installed me sympy
sympy.__version__
Out[14]: '0.7.6.1'

I cannot import or use linear_eq_to_matrix

sympy.solveset.linear_eq_to_matrix

AttributeError: 'module' object has no attribute 'solveset'

import sympy.solvers.solveset
ImportError: No module named 'sympy.solvers.solveset'

Then I went looking into Anacondas packages (Anaconda3\pkgs\sympy-0.7.6.1-py34_0\Lib\site-packages\sympy\solvers) and there is no such file as solveset.py. On the Github page this file exists under the same version (https://github.com/sympy/sympy/tree/master/sympy/solvers). I also tried downloading that solveset.py to the directory above and that did not help. Doing that is a horrible way of doing things?

Jason Moore

unread,
Oct 10, 2015, 2:53:19 PM10/10/15
to sy...@googlegroups.com
This is only available in the development version of SymPy. It will be in the next release.

You can install the development version if you want to run that. See: http://docs.sympy.org/0.7.6/install.html for info.

--
You received this message because you are subscribed to the Google Groups "sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sympy+un...@googlegroups.com.
To post to this group, send email to sy...@googlegroups.com.
Visit this group at http://groups.google.com/group/sympy.

RCU

unread,
Nov 13, 2015, 5:39:03 AM11/13/15
to sy...@googlegroups.com
Hello.
I was very happy to find this thread.

I'm using the eqs2matrix(eqs, syms, augment=False) function provided in this thread
earlier (see below), in order to take some equations I parsed and build a matrix I can
then provide to the function solve_linear_system(resEqs2Matrix, xdst, ydst) in order to
determine the unknowns xdst and ydst. (If interested see the script and input equations at
https://github.com/alexsusu/video-diff/tree/master/TransformationSpecAndCodeGen ).
The function eqs2matrix provided by Chris Smith works greatly on quite a few input
equation examples. Unfortunately, it is not able to work greatly (it does not do good
"simplification") with the following "system" of equations:
xsrc = (M11*xdst + M12*ydst + M13)/(M31*xdst + M32*ydst + M33)
ysrc = (M21*xdst + M22*ydst + M23)/(M31*xdst + M32*ydst + M33)

More exactly, I need to compute the xdst and ydst from M11..M33, xsrc and ysrc. But
the final result I obtain with the script is big and redundant. More exactly, eqs2matrix
does not take into consideration it could keep linear the expressions above if we multiply
with the respective denominators the equations. (If I do this manually, it is OK, but I
would like eqs2matrix to automatically do this "preprocessing" intelligently, since there
can be probably many non-trivial cases with denominators, etc).

I'd like to ask you if there is a better way to implement eqs2matrix to obtain
simplified results.

Thank you,
Alex


On 10/7/2015 6:25 PM, Adam Leeper wrote:
> Hi all-
>
> Interested party just wondering if there is any update on this.
>
> Cheers,
> Adam
>
> On Tuesday, June 24, 2014 at 10:01:56 AM UTC-7, Aaron Meurer wrote:
>
> A multidimensional version of collect() would probably be the best abstraction.
>
> Aaron Meurer
>
> <http://groups.google.com/group/sympy>.
> >> >> > To view this discussion on the web visit
> >> >> >
> >> >> >
> >> >> >
> https://groups.google.com/d/msgid/sympy/8fb2dae4-9f46-4c1b-b96f-83033278c27d%40googlegroups.com
> <https://groups.google.com/d/msgid/sympy/8fb2dae4-9f46-4c1b-b96f-83033278c27d%40googlegroups.com>.
>
> >> >> >
> >> >> > For more options, visit https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>.
> >> >
> >> > --
> >> > You received this message because you are subscribed to the Google
> >> > Groups
> >> > "sympy" group.
> >> > To unsubscribe from this group and stop receiving emails from it, send
> >> > an
> >> > email to sympy+un...@googlegroups.com.
> >> > To post to this group, send email to sy...@googlegroups.com.
> >> > Visit this group at http://groups.google.com/group/sympy
> <http://groups.google.com/group/sympy>.
> >> > To view this discussion on the web visit
> >> >
> >> >
> https://groups.google.com/d/msgid/sympy/a9c5f7ba-1c2d-4673-a8d4-b1253c150054%40googlegroups.com
> <https://groups.google.com/d/msgid/sympy/a9c5f7ba-1c2d-4673-a8d4-b1253c150054%40googlegroups.com>.
>
> >> >
> >> > For more options, visit https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>.
> >
> > --
> > You received this message because you are subscribed to the Google Groups
> > "sympy" group.
> > To unsubscribe from this group and stop receiving emails from it, send an
> > email to sympy+un...@googlegroups.com <javascript:>.
> > To post to this group, send email to sy...@googlegroups.com <javascript:>.
> > Visit this group at http://groups.google.com/group/sympy
> <http://groups.google.com/group/sympy>.
> > To view this discussion on the web visit
> >
> https://groups.google.com/d/msgid/sympy/0b486c56-8a2b-48a5-a210-f49b6d39899f%40googlegroups.com
> <https://groups.google.com/d/msgid/sympy/0b486c56-8a2b-48a5-a210-f49b6d39899f%40googlegroups.com>.
>
> >
> > For more options, visit https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>.
>
> --
> You received this message because you are subscribed to the Google Groups "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
> sympy+un...@googlegroups.com <mailto:sympy+un...@googlegroups.com>.
> To post to this group, send email to sy...@googlegroups.com <mailto:sy...@googlegroups.com>.
> Visit this group at http://groups.google.com/group/sympy.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/sympy/9b453937-0394-4efc-8d7f-dc1a6a46267e%40googlegroups.com
> <https://groups.google.com/d/msgid/sympy/9b453937-0394-4efc-8d7f-dc1a6a46267e%40googlegroups.com?utm_medium=email&utm_source=footer>.
Reply all
Reply to author
Forward
0 new messages