collecting common factors in a matrix

374 views
Skip to first unread message

Riccardo Rossi

unread,
Nov 27, 2015, 2:24:23 PM11/27/15
to sympy
Dear list,

i am a newby to sympy, and i should say that i liked what i found, so ... first of all kudos to the developers.

as of now i can succesfully generate my finite element matrices using sympy, which saves me quite a lot of work.

the point is that now i would like to optimize a bit what i did, and i would like to collect some common factors between the entries of a matrix.

for example imagine that i have (pseudocode and just an example, no physics behind)

a,b = symbols('a b')

A = Matrix(2,1)
A[0] = a*(exp(a+b)+exp(b^2))
A[1] = b*(exp(a+b)+exp(b^2))

i would like a way to detect that the term
(exp(a+b)+exp(b^2))

is common to the different entries and eventually later on do something of the type

aux = (exp(a+b)+exp(b^2))
A[0] = a*aux
A[1] = b*aux

note that later on for me it would be still interesting to do something similar on SOME of the entries of the matrix

for example if i had

A = Matrix(3,1)
A[0] = a*(exp(a+b)+exp(b^2))
A[1] = b*(exp(a+b)+exp(b^2))
A[2] = a+b

i would still love to have


aux = (exp(a+b)+exp(b^2))
A[0] = a*aux
A[1] = b*aux
A[2] = a+b



thanks in advance for any suggestion.

cheers
Riccardo

Mateusz Paprocki

unread,
Nov 28, 2015, 5:07:20 AM11/28/15
to sympy
Hi,
you could use cse() (common subexpression elimination) for this, e.g.:

In [1]: from sympy import *

In [2]: var('a,b')
Out[2]: (a, b)

In [3]: aux = exp(a + b) + exp(b**2)

In [4]: Matrix([a*aux, b*aux, a + b])
Out[4]:
Matrix([
[a*(exp(b**2) + exp(a + b))],
[b*(exp(b**2) + exp(a + b))],
[ a + b]])

In [5]: replacements, (M,) = cse(_)

In [6]: M
Out[6]:
Matrix([
[a*x1],
[b*x1],
[ x0]])

In [7]: replacements
Out[7]: [(x0, a + b), (x1, exp(b**2) + exp(x0))]

In [8]: M.subs(list(reversed(replacements)))
Out[8]:
Matrix([
[a*(exp(b**2) + exp(a + b))],
[b*(exp(b**2) + exp(a + b))],
[ a + b]])

However, this may not be exactly what you want, because it eliminates
`a + b` as well.

Mateusz

>
>
> thanks in advance for any suggestion.
>
> cheers
> Riccardo
>
> --
> 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/a72b7481-c0c8-49a2-9a1f-3e88ae8f5f3d%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Riccardo Rossi

unread,
Nov 28, 2015, 2:08:52 PM11/28/15
to sympy
Dear Mateusz,

what you suggest is exactly what i was hoping for and could not find by googling

i'll definitely try that out :-)

Dzienkuje Bardzo! (hope spelling is correct and...that i guessed correctly your nationalty)

cheers
Riccardo

Thomas Hisch

unread,
Nov 29, 2015, 4:08:21 AM11/29/15
to sympy
Take a look at https://github.com/sympy/sympy/pull/7318. I remember that this PR didn't work for all matrices (I guess matices including expressions with sqrt(2)). If we find a better way to determine the common factor, I'll update the PR.

Riccardo Rossi

unread,
Nov 29, 2015, 5:44:18 AM11/29/15
to sympy
Dear Thomas,

the suggestion of Mateusz appears to work fine for my needs. I don't mind if some optimization opportunities are left out... the common factors are even too many for me as of now :-)

one more little question though:

after collecting the factors i have to do some C code generation for them, and i am doing some string magic to have a form i like
for my C++ FE program. Nothing too clever really, but i would need to have access somehow to the name of the symbol.

i thought at first that __str__() would do, but no

imagine i have a symbol

a = symbol('a')
a = sqrt(2)

i would like something that returns me "a"

while

a.__str__() will return sqrt(2)

is there a method to give this? (surely yes, but i can not find it in the documentation

cheers
Riccardo

Jason Moore

unread,
Nov 29, 2015, 8:34:55 PM11/29/15
to sy...@googlegroups.com
Ricardo,

I think you are confusing SymPy symbols with Python variables here. In the previous case you store the symbol 'a' in the python variable 'a' and then you overwrite the python variable 'a' by storing the square root of two, which makes it an expression. In general, you don't get to access Python variable names because the same Python object can be assigned to any number of variables. For example:

a = Symbol('a')
b = Symbol('a')
c = Symbol('a')
my_sym = Symbol('a')

All of the above Python variables (a, b, c, my_sym) store the exact same SymPy symbol object.

Check out this page for some more info: http://docs.sympy.org/dev/gotchas.html#variables

Jason

Riccardo Rossi

unread,
Dec 1, 2015, 9:52:56 AM12/1/15
to sympy
Dear Jason,

i think i explained myself badly

imagine i have


a = Symbol('a')
a = sqrt(2)+1

my_special_print(a) --> i would like to print something like "double a = sqrt(2) + 1"

the point is that in writing the "my_special_print" i need to know the name of the variable to be able to print my special output (i need to tell that i see "a" as "a"...)

cheers
Riccardo

Björn Dahlgren

unread,
Dec 1, 2015, 6:48:02 PM12/1/15
to sympy


On Tuesday, 1 December 2015 15:52:56 UTC+1, Riccardo Rossi wrote:
Dear Jason,

i think i explained myself badly

imagine i have

a = Symbol('a')
a = sqrt(2)+1


the second statement "overwrites" the first, that's just how Python (and any other programming language that comes to mind) works.
Maybe you want to do something like this?:

In [1]: a_symb = Symbol('a')

In [2]: a_expr = sqrt(2) + 1

In [3]: ccode(a_expr, assign_to=a_symb)
Out[3]: 'a = 1 + sqrt(2);'



Reply all
Reply to author
Forward
0 new messages