Ask Your Question
1

Making a dictionary of matrices

asked 2017-12-19 19:24:10 +0200

Symbol 1 gravatar image

I am trying to make a dictionary of matrices. Ideally

MatDic={ 
    matrix(GF(2),2,[1,0,0,1]):'a',
    matrix(GF(2),2,[1,1,0,1]):'b'
    # etc
}

But Sage refuses to hash (mutable) matrices. I then tried

MatDic={ 
    matrix(GF(2),2,[1,0,0,1]).set_immutable():'a',
    matrix(GF(2),2,[1,1,0,1]).set_immutable():'b'
}
MatDic

which gives

{None: 'b'}

I also tried making a dictionary of tuples

MatDic={ 
    (1,0,0,1):'a',
    (1,1,0,1):'b'
}

which raises no errors; However

MatDic[tuple(matrix(GF(2),2,[1,0,0,1]))]

gives

TypeError: mutable vectors are unhashable

What is the best, if possible, way to make a dictionary and lookup matrices?

edit retag flag offensive close merge delete

Comments

Why do we need to force the situation in a place where python insists to have hashable objects (...the keys)? A good possibility is to use the information from the entries as a tuple instead, e.g.

F = GF(2)
dic = { (F(1), F(0), F(0), F(1)) : '1001' ,
        (F(1), F(1), F(0), F(1)) : '1101' , }

and the keys are easily transformed to matrices, for instance:

sage: for tup in dic:
....:     m = matrix( 2,2, tup )
....:     print tup, '->', dic[tup], 'with matrix\n', m
....:     
(1, 1, 0, 1) -> 1101 with matrix
[1 1]
[0 1]
(1, 0, 0, 1) -> 1001 with matrix
[1 0]
[0 1]

Here, for the last matrix:

sage: m.parent()
Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 2
dan_fulea gravatar imagedan_fulea ( 2017-12-20 00:23:29 +0200 )edit

@dan_fulea Well I expect the dictionary to record not only entries but also the width and height. If I come up with a method that turns a matrix into a hashable matrix then I am reinventing .set_immutable(). So maybe the real question is why don't sage/python automatically make a hashable copy and then hash it.

Symbol 1 gravatar imageSymbol 1 ( 2017-12-20 03:10:14 +0200 )edit

1 Answer

Sort by ยป oldest newest most voted
1

answered 2017-12-19 23:37:49 +0200

vdelecroix gravatar image

updated 2017-12-19 23:38:52 +0200

Dictionaries can only be built with hashable objects. You get the same trouble with

sage: {[1,2]: 0, [0]: 5}
Traceback (most recent call last):
...
TypeError: unhashable type: 'list'

Though, using lists as values is fine

sage: {1: [0,3], 'hello': [1,2]}
{1: [0, 3], 'hello': [1, 2]}

In order to use matrices or vectors as keys of a dictionary you need to set them immutable first.

sage: m1 = matrix(ZZ, 2, [1, 2, 3, 4])
sage: m2 = matrix(ZZ, 2, [1, 0, 1, 1])
sage: {m1: 0, m2: 1}
Traceback (most recent call last):
...
TypeError: unhashable type: 'list'
sage: m1.set_immutable()
sage: m2.set_immutable()
sage: {m1: 0, m2: 1}
{[1 0]
 [1 1]: 1,
 [1 2]
 [3 4]: 0}

Note that the method set_mutable does not return anything but modifies the matrix itself.

edit flag offensive delete link more

Comments

I guess my bottleneck is that I expect set_mutable to return the object itself (like sorted()). By the way what is the best way to lookup the type of methods?

Symbol 1 gravatar imageSymbol 1 ( 2017-12-20 03:14:36 +0200 )edit

There is no type for methods in Python. The only thing that you have access to is their documentation and code

sage: m = matrix()
sage: m.set_immutable?
Docstring:     
   Call this function to set the matrix as immutable.

   Matrices are always mutable by default, i.e., you can change their
   entries using "A[i,j] = x". However, mutable matrices aren't
   hashable, so can't be used as keys in dictionaries, etc. Also,
   often when implementing a class, you might compute a matrix
   associated to it, e.g., the matrix of a Hecke operator.

  ...

As a convention (for Sage and Python in general) a method or a function like sorted is expected to return an object while sort is expected to modify it.

vdelecroix gravatar imagevdelecroix ( 2017-12-20 09:46:13 +0200 )edit

I have sometimes found the need to create immutable matrices inline as well. A utility function like

def immutable(A):             
    B=copy(A)
    B.set_immutable()
    return B

does the trick. You could of course skip the "B=copy(A)". However, then your function has a side-effect of making its argument immutable as well, which might be unexpected.

I have considered if the "matrix" constructor would need a "immutable=True" optional parameter, but I think this would be less useful than you'd think:

sage: A=matrix(2,2,[1,2,3,4])
sage: B=immutable(A)
sage: (B*B).is_immutable()
False

It's convenient for things like:

sage: len({immutable(a*a) for a in MatrixSpace(GF(2),2,2)})
10

Do we need it in the global namespace?

nbruin gravatar imagenbruin ( 2017-12-22 23:01:56 +0200 )edit
1

@nbruin: note that for graphs there is G.copy(immutable=True) that I like.

vdelecroix gravatar imagevdelecroix ( 2017-12-24 16:52:59 +0200 )edit

It might be nice if set_immutable() returned self so that it could be used in the manner the OP attempted.

Iguananaut gravatar imageIguananaut ( 2018-01-05 16:16:37 +0200 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

Stats

Asked: 2017-12-19 19:24:10 +0200

Seen: 815 times

Last updated: Dec 19 '17