question about creating a 2d array of symbols

2,192 views
Skip to first unread message

Comer

unread,
Feb 5, 2012, 2:54:50 PM2/5/12
to sympy
I am working on a project which requires that I create a matrix of
symbols. For discussion purposes say the matrix is 3 x 3. The matrix
is to contain 9 unique symbols and my preferred format is the usual
matrix format:

a11, ..., a33 = symbols('a_11 ....a_33')

Now obviously I could easily just type in the above for all nine
symbols. However, what I want to see how to do is to create a 3 x 3
array as above but do it in a couple of for loops. I looked at the
symbols() function but it only seems to work with a linear sequence of
symbol names such as x0, x1, x2, .... xN. But I can not see how to do
the same for a 2d array of symbol names such as x00, x01, x02, ... .
It would be convenient in my project to be able to quickly create the
2d array of symbols directly by calling symbols(). It would save some
typing.

Can someone please let me know how best to do this?

Thanks.

Comer

Matthew Rocklin

unread,
Feb 5, 2012, 3:03:45 PM2/5/12
to sy...@googlegroups.com
In pull request 1015 you can do this with the following code
In [1]: A = MatrixSymbol('a', 3, 3)

In [2]: print A.as_explicit()
[a(0, 0), a(0, 1), a(0, 2)]
[a(1, 0), a(1, 1), a(1, 2)]
[a(2, 0), a(2, 1), a(2, 2)]

Each of these entries are a unique symbol (actually a function object).  You can also just ask for A[1,2] and get a(1, 2) without the as_explicit call and it'll generate it on the fly. 
In [3]: A[1,2]
Out[3]: a(1, 2)

Unfortunately this is not the same text as you're looking for. 

A simpler and probably better solution that works in master is to use a doubly nested list comprehension. I apologize for the horizontal coding. This is effectively just a doubly nested for loop written sideways. 
In [4]: [[Symbol('a_%d%d'%(i,j)) for j in range(3)] for i in range(3)]
Out[4]: [[a₀₀, a₀₁, a₀₂], [a₁₀, a₁₁, a₁₂], [a₂₀, a₂₁, a₂₂]]

-Matt


Comer

--
You received this message because you are subscribed to the Google Groups "sympy" group.
To post to this group, send email to sy...@googlegroups.com.
To unsubscribe from this group, send email to sympy+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sympy?hl=en.


miham

unread,
Feb 6, 2012, 12:58:47 PM2/6/12
to sympy
Try this:

>>> Matrix(3, 3, lambda i,j: Symbol('a_%d%d' % (i,j)))

miham

unread,
Feb 6, 2012, 12:59:50 PM2/6/12
to sympy
In case you can't find it in the previous post, here it is again:

Chris Smith

unread,
Feb 6, 2012, 4:06:27 PM2/6/12
to sy...@googlegroups.com
On Mon, Feb 6, 2012 at 11:44 PM, miham <tlor...@gmail.com> wrote:
> In case you can't find it in the previous post, here it is again:
>
> Matrix(3, 3, lambda i,j: Symbol('a_%d%d' % (i,j)))

Very nice!

Ondřej Čertík

unread,
Feb 7, 2012, 4:06:43 AM2/7/12
to sy...@googlegroups.com
On Sun, Feb 5, 2012 at 11:54 AM, Comer <comer....@gmail.com> wrote:

I think you are looking for the symarray() function in sympy:


Type: function
Base Class: <type 'function'>
String Form:<function symarray at 0x2aa3488>
Namespace: Interactive
File: /home/ondrej/repos/sympy/sympy/matrices/matrices.py
Definition: symarray(prefix, shape)
Docstring:
Create a numpy ndarray of symbols (as an object array).

The created symbols are named `prefix_i1_i2_`... You should thus provide a
non-empty prefix if you want your symbols to be unique for different output
arrays, as Sympy symbols with identical names are the same object.

Parameters
----------

prefix : string
A prefix prepended to the name of every symbol.

shape : int or tuple
Shape of the created array. If an int, the array is one-dimensional; for
more than one dimension the shape must be a tuple.

Examples
--------
These doctests require numpy.

>>> from sympy import symarray
>>> symarray('', 3) #doctest: +SKIP
[_0, _1, _2]

If you want multiple symarrays to contain distinct symbols, you *must*
provide unique prefixes:

>>> a = symarray('', 3) #doctest: +SKIP

>>> b = symarray('', 3) #doctest: +SKIP
>>> a[0] is b[0] #doctest: +SKIP
True
>>> a = symarray('a', 3) #doctest: +SKIP
>>> b = symarray('b', 3) #doctest: +SKIP
>>> a[0] is b[0] #doctest: +SKIP
False

Creating symarrays with a prefix:

>>> symarray('a', 3) #doctest: +SKIP
[a_0, a_1, a_2]

For more than one dimension, the shape must be given as a tuple:

>>> symarray('a', (2, 3)) #doctest: +SKIP
[[a_0_0, a_0_1, a_0_2],
[a_1_0, a_1_1, a_1_2]]
>>> symarray('a', (2, 3, 2)) #doctest: +SKIP
[[[a_0_0_0, a_0_0_1],
[a_0_1_0, a_0_1_1],
[a_0_2_0, a_0_2_1]],
<BLANKLINE>
[[a_1_0_0, a_1_0_1],
[a_1_1_0, a_1_1_1],
[a_1_2_0, a_1_2_1]]]

Ondrej

Comer

unread,
Feb 7, 2012, 4:02:09 PM2/7/12
to sympy
Matt,

Thanks for the suggestions. Way 2 is more what I want to do(but not
quite) right now, but having the capability to do it via way 1 will be
welcomed!

Comer

On Feb 5, 3:03 pm, Matthew Rocklin <mrock...@gmail.com> wrote:
> In pull request 1015 <https://github.com/sympy/sympy/pull/1015> you can do
> this with the following code
> In [1]: A = MatrixSymbol('a', 3, 3)
>
> In [2]: print A.as_explicit()
> [a(0, 0), a(0, 1), a(0, 2)]
> [a(1, 0), a(1, 1), a(1, 2)]
> [a(2, 0), a(2, 1), a(2, 2)]
>
> Each of these entries are a unique symbol (actually a function object).
>  You can also just ask for A[1,2] and get a(1, 2) without the as_explicit
> call and it'll generate it on the fly.
> In [3]: A[1,2]
> Out[3]: a(1, 2)
>
> Unfortunately this is not the same text as you're looking for.
>
> A simpler and probably better solution that works in master is to use a
> doubly nested list comprehension. I apologize for the horizontal coding.
> This is effectively just a doubly nested for loop written sideways.
> In [4]: [[Symbol('a_%d%d'%(i,j)) for j in range(3)] for i in range(3)]
> Out[4]: [[a₀₀, a₀₁, a₀₂], [a₁₀, a₁₁, a₁₂], [a₂₀, a₂₁, a₂₂]]
>
> -Matt
>

Comer

unread,
Feb 7, 2012, 4:08:14 PM2/7/12
to sympy
Miham,

Thanks for the suggestion. It is rather elegant. However, I really
want to be able to assign a more convenient label to the created
symbols. That is, I want to assign

a11 -> a_11, a12 -> a_12, etc as the new symbols are defined. In a
loop would be nice, but I can not seem to get the syntax right. Here
is what I want:

for i in range(1,3):
for j in range(1,3):
aij = Symbol('a_%d%d' % (i,j))



and have an array of labels aij with i and j ranging over the
range(1,3).

Thanks for the neat suggestion.

Comer

Comer

unread,
Feb 7, 2012, 4:11:19 PM2/7/12
to sympy
Hi Ondrej,

Your suggestion is very useful. I am now defining a matrix array with
element notation a_ij and label aij whereas your suggestion seems to
result in a_i_j and no more convenient to type label such as my
desired aij. How to do this?

Comer

On Feb 7, 4:06 am, Ondřej Čertík <ondrej.cer...@gmail.com> wrote:

Ondřej Čertík

unread,
Feb 7, 2012, 7:31:27 PM2/7/12
to sy...@googlegroups.com
On Tue, Feb 7, 2012 at 1:11 PM, Comer <comer....@gmail.com> wrote:
> Hi Ondrej,
>
> Your suggestion is very useful.  I am now defining a matrix array with
> element notation a_ij and label aij whereas your suggestion seems to
> result in a_i_j and no more convenient to type label such as my
> desired aij.  How to do this?

The best is to improve the function symarray():

https://github.com/sympy/sympy/blob/master/sympy/matrices/matrices.py#L4377

You can see that the implementation is only 4 lines. You can add a few options
to it, controlling this underscore behavior.

Ondrej

Chris Smith

unread,
Feb 8, 2012, 1:02:22 AM2/8/12
to sy...@googlegroups.com
Perhaps a `separator`="_" keyword could be added.

Comer

unread,
Feb 10, 2012, 1:32:27 PM2/10/12
to sympy


On Feb 8, 1:02 am, Chris Smith <smi...@gmail.com> wrote:
> Perhaps a `separator`="_" keyword could be added.

Chris, thanks. I have experimented a bit and have some results and
some questions which remain. Here goes.

I have written a little modification to symarray called csymarray. I
list it below and then comment.

def csymarray(prefix,sep,nx,ny):
from sympy import Symbol
from sympy import symbols
import numpy as np
shape = (nx,ny)
arr = np.empty(shape,dtype=object)
for j in range(ny):
for i in range(nx):
arr[i][j] = Symbol('%s%s%s%s' %
(prefix,sep,str(i),str(j)))
return arr

I decided that I would try to do the simplest thing first. This meant
that I would do what I need, namely to define an array of symbols.
While there may be better ways to do the above, this seems to work.
Well, maybe not.. I used it in a little test code listed as follows:

from sympy import Symbol
from sympy import symbols
import numpy as np
import comer as gcd #comer.py is where the function csymarray is
defined
ZS =gcd.csymarray('Z','_',3,3)
print 'ZS **********************************'
print ZS
print '**********************************'
print ZS[1][2]
print '**********************************'

Z_10 = Z_01


The function works I think as the output shows. There is a problem in
that I want to create a 3x3 array---actually I want a matrix. But the
last line of the file returns an error. Here is the output. While in
isympy:

In [1]: run testcsymarray
ZS **********************************
[[Z_00 Z_01 Z_02]
[Z_10 Z_11 Z_12]
[Z_20 Z_21 Z_22]]
**********************************
Z_12
**********************************
---------------------------------------------------------------------------
NameError Traceback (most recent call
last)
/Users/comerduncan/ipython/IPython/utils/py3compat.pyc in
execfile(fname, *where)
173 else:
174 filename = fname
--> 175 __builtin__.execfile(filename, *where)

/Users/comerduncan/comeripython/notebooks/testcsymarray.py in
<module>()
10 print ZS[1][2]
11 print '**********************************'
---> 12 Z_10 = Z_01

NameError: name 'Z_01' is not defined

So, it seems that ZS is defined and has length 3. So it is three
'vectors'. But the individual components are not defined? Who ordered
that? I want to create the 3x3 matrix and then create a new symmetric
matrix from ZS ( the 'S' in the name ZS is for using the Symbol()
rather than symbols()).

I have tried creating the matrix zmat = Matrix(ZS) but can not address
the matrix elements. I have tried Matrix(3,3,ZS) but get an error
that the length must be equal to rows*cols.

How come the csymarray function creates ZS from objects presumably of
type Symbol but isympy never gets that message. The original empty
thing is a numpy beast.

Thanks for help and suggestions.

Comer

Matthew Rocklin

unread,
Feb 10, 2012, 1:59:58 PM2/10/12
to sy...@googlegroups.com
It sounds like you want to actually create the variables a_00 = Symbol('a_00'),  a_01 = ... in the active namespace. 

In a previous e-mail you wrote that you wanted something like the following 
for i in range(1,3):
    for j in range(1,3):
         aij = Symbol('a_%d%d' % (i,j))

Unfortunately this repeatedly redefines a single variable named "aij" rather than "a00", "a01", ....
Usually injecting a lot of variable names into an python session requires some hackery. Forunately, SymPy has such a piece of hackery in the var function

Try this code snippet and see if it does what you want

for i in range(3):
    for j in range(3):
         var('a_%d%d' % (i,j))

This will inject all of the names a_00, a_01, a_02, etc... into the ipython session so that you can use them directly. 

Of course, I may have misunderstood what you were asking for. 

If you're looking for a matrix of these symbols then I would suggest using Miham's solution. 





Chris Smith

unread,
Feb 10, 2012, 2:23:57 PM2/10/12
to sy...@googlegroups.com
> So, it seems that ZS is defined and has length 3. So it is three
> 'vectors'. But the individual components are not defined? Who ordered
> that? I want to create the 3x3 matrix and then create a new symmetric
> matrix from ZS  ( the 'S' in the name ZS is for using the Symbol()
> rather than symbols()).

Yes, this is the 'gotcha' about symbols: the objects exist but aren't assigned
to any python variables. When you do Symbol('x') this doesn't create a python
variable x, only a sympy Symbol object.

As Matt (IIRC) said, you can use var to create this. Here are some steps showing
how else you might do this:

get the array and store in a

>>> csymarray('A_','',3,3)
array([[A_00, A_01, A_02],
[A_10, A_11, A_12],
[A_20, A_21, A_22]], dtype=object)
>>> a=_

get a string of the *objects* in it; flatten undoes the nesting:

>>> str(flatten(a))[1:-1]
'A_00, A_01, A_02, A_10, A_11, A_12, A_20, A_21, A_22'
>>> s=_

make a string to execute in the local environment

>>> "%s=symbols('%s')" % (s,s)
"A_00, A_01, A_02, A_10, A_11, A_12, A_20, A_21, A_22=symbols('A_00, A_01, A_02,
A_10, A_11, A_12, A_20, A_21, A_22')"

execute it and confirm that the python variables (which happen to have
the same sympy symbol name) have been created

>>> exec(_)
>>> A_00
A_00

or do it all at once with

>>> var(s)
(A_00, A_01, A_02, A_10, A_11, A_12, A_20, A_21, A_22)
>>> A_11
A_11


You don't need to do any of that to define and manipulate a Matrix, however:

>>> Matrix(a)
[A_00, A_01, A_02]
[A_10, A_11, A_12]
[A_20, A_21, A_22]

or the alternate instantiation which requires the flat list of elements

>>> Matrix(3, 3, flatten(a))
[A_00, A_01, A_02]
[A_10, A_11, A_12]
[A_20, A_21, A_22]
>>>

HTH,
/c

Comer

unread,
Feb 10, 2012, 2:25:06 PM2/10/12
to sympy
Hi Matt,

Thanks for the reply!

On Feb 10, 1:59 pm, Matthew Rocklin <mrock...@gmail.com> wrote:
> It sounds like you want to actually create the variables a_00 =
> Symbol('a_00'),  a_01 = ... in the active namespace.
>
> In a previous e-mail you wrote that you wanted something like the following
> for i in range(1,3):
>     for j in range(1,3):
>          aij = Symbol('a_%d%d' % (i,j))
>
> Unfortunately this repeatedly redefines a single variable named "aij"
> rather than "a00", "a01", ....
> Usually injecting a lot of variable names into an python session requires
> some hackery. Forunately, SymPy has such a piece of hackery in the var
> function
>
> Try this code snippet and see if it does what you want
>
> for i in range(3):
>     for j in range(3):
>          var('a_%d%d' % (i,j))
>
> This will inject all of the names a_00, a_01, a_02, etc... into the ipython
> session so that you can use them directly.
>
> Of course, I may have misunderstood what you were asking for.
>

In my most recent post I listed the function csymarray, which is a mod
of symarray to make an array of symbols with the notation I desire
(namely a_12, a_13, etc) as you suggest. I wanted to create a matrix
in one call with the elements symbols with the desired notataion a_12,
etc. I elected to mod symarray based on Ondrej's suggestion. However
the result is confusing to me in that 1. it is not a matrix but an
array (as advertised!) and making it into a matrix does not result in
a matrix of independently adressable symbols. Doing it the by-hand
way does result in a matrix of symbols, but I do it by hand, which
strikes me as pretty primitive. So I wanted to create a function which
would 1.create the symbols so that they are in the namespace and 2.
make that array into a matrix of a desired shape. I am mainly
interested in square matrices in my current project.

Also, I am a bit unsure of the difference between using symbols(),
Symbol(), and var(). They all seem to do similar things. Aaron
commented on today's sympy that one should not use var except in an
interactive session...

Thanks.

Comer

Comer

unread,
Feb 10, 2012, 2:30:06 PM2/10/12
to sympy
Hi Chris,

Thanks very much for your reply and its content. Between you and Matt
I think I see better what is going on.

Comer

Chris Smith

unread,
Feb 10, 2012, 2:37:09 PM2/10/12
to sy...@googlegroups.com
On Sat, Feb 11, 2012 at 1:15 AM, Comer <comer....@gmail.com> wrote:
> Hi Chris,
>
> Thanks very much for your reply and its content. Between you and Matt
> I think I see better what is going on.

I appreciated how helpful the python community was when I was learning
(Danny Yoo was the tutor-list monitor at the time and a *great* help
as were many others). Glad to be able to return in kind.

/c

Reply all
Reply to author
Forward
0 new messages