2

I have lots of matrices (as result of rotations, etc.), but I would be sure to store them only once. I thought about using a set :

print set([np.matrix([[0, 0],[0, 1],[1, 1],[2, 1]]), 
 np.matrix([[0, 0],[1, 0],[1, -1],[1, -2]])])

Unfortunately, I get :

TypeError: unhashable type: 'matrix'

It's sad because a set would be exactly the right data type to avoid repetitions, and be able to use union, intersection, etc.

How to work with sets of matrices in Python?

Basj
  • 41,386
  • 99
  • 383
  • 673
  • 1
    This might help http://stackoverflow.com/questions/1939228/constructing-a-python-set-from-a-numpy-matrix – Asish M. Jun 18 '16 at 14:00
  • What's your python version? and the Numpy? – Mazdak Jun 18 '16 at 14:02
  • @Basj It's works well in my machine with python2.7, It might be because of your numpy version, which in that case you better to convert your matrices as `tuple`. – Mazdak Jun 18 '16 at 14:04
  • Are they all small like your example, 4x2? How many? Be wary of conversion to/from tuples. It will slow down access. – hpaulj Jun 18 '16 at 15:41

1 Answers1

0
In [299]: m1
Out[299]: 
matrix([[0, 0],
        [0, 1],
        [1, 1],
        [2, 1]])

In [300]: m2
Out[300]: 
matrix([[ 0,  0],
        [ 1,  0],
        [ 1, -1],
        [ 1, -2]])

In [297]: set([tuple(m1.A1),tuple(m2.A1)])
Out[297]: {(0, 0, 0, 1, 1, 1, 2, 1), (0, 0, 1, 0, 1, -1, 1, -2)}

m1.A1 converts the matrix to a 1d array, which displays as a simple list. Wrap that in tuple makes an object that is hashable.

A set is like a dictionary with keys but no values. Both provide quick access (and in testing) by converting each key to a 'hash'. Part of why it requires a tuple, as opposed to a list is that it must be immutable. The hash would change if you changed one of the values of the matrix.

Without the A1 (or other ravel) it does not work - look at tuple(m1).

In [302]: set([tuple(m1),tuple(m2)])
...
TypeError: unhashable type: 'matrix'

In [303]: tuple(m1)
Out[303]: (matrix([[0, 0]]), matrix([[0, 1]]), matrix([[1, 1]]), matrix([[2, 1]]))

We could also convert the matrix to some string representation, and store that. Note that these conversions don't save you space, and all incur a conversion cost.

We may need to explore how these matrices are compared. What makes one different from another?

Equality of matching elements:

In [306]: m1==m2
Out[306]: 
matrix([[ True,  True],
        [False, False],
        [ True, False],
        [False, False]], dtype=bool)

In [307]: (m1==m2).all()
Out[307]: False

In [308]: (m1==m1).all()
Out[308]: True

Of course that requires that they all be the same shape.

If the shapes differ it can't do element by element comparisons, so it returns a boolean scalar.

In [309]: m1==m1.T
Out[309]: False

You could compare the object ids

In [314]: set([id(m1),id(m2),id(m2[:])])
Out[314]: {3029619684, 3036025828, 3036825892}

but it doesn't capture the equality of views (m2[:] has the same values, but is a different object).

Also if I change a value, e.g. m2[2,1]=1, it does not change the id, but would change the tuple(m2.A1) hash, and equality tests.

hpaulj
  • 221,503
  • 14
  • 230
  • 353