Ask Your Question
1

Keys of a dictionary

asked 2017-12-10 14:43:41 +0100

Xenia gravatar image

updated 2017-12-10 14:44:02 +0100

Hello guys, I have a piece of code to get a dictionary of preimages of a function. These look like this:

{[0.0]: [[0 0 0 0 0]], [1.27]: [[0 0 0 0 1]], [2.63]: [[1 1 1 0 0]], ..... , [5.619999999999999]: [[1 0 1 1 1]]}

if I look for preimages.keys(), I get the following:

[[0.0], [1.27], [2.63], ....... , [5.619999999999999]]

But when I try to get a particular preimage like preimages[1.27] I get an error

KeyError: 1.27000000000000

even though it is in a dictionary. Or if I try

preimages [[1.27]]

I get another error

TypeError: unhashable type: 'list'

Could someone please help to solve this ploblem ?

edit retag flag offensive close merge delete

Comments

Please provide your code with a correct Sage/Python syntax, [[0 0 0 0 0]] is meaningless, also, it is not possible to have a list as a key for a dictionary since it is unhashable, so having a dictionary whose definition starts with {[0.0]: is meaningless too. As is, there is no hope we can reproduce anything.

tmonteil gravatar imagetmonteil ( 2017-12-10 14:57:54 +0100 )edit
1

Please give code producing a simple dictionary (with two keys) so that the values do not lead to errors - note that [0 0 0 0 0] immediately gives an error.

Why are the keys (displayed) above lists (and how did this dictionary come into sage)? Why not simple elements? Or tuples if we really need one element tuples? For instance:

sage: dic = {(0.0): [[0, 0, 0, 0, 0]], (1.27): [[0, 0, 0, 0, 1]], (2.63): [[1, 1, 1, 0, 0]], (5.619999999999999): [[1, 0, 1, 1, 1]]}
sage: dic[ (0.0) ]
[[0, 0, 0, 0, 0]]

Why do we use approximate values in the (tuples)? This may be a good reason to "miss the key", for instance the last one, if the precision does not match or if after computation an other value is delivered "not the expected one".

dan_fulea gravatar imagedan_fulea ( 2017-12-10 15:02:34 +0100 )edit

The code looks like this:

import itertools
W = itertools.product([0,1], repeat = n)
preimages = {}
for w in W:
     w = vector(w)
     w = w.row()
     v = w.transpose()
     u = w * K * v
     u.set_immutable()
     if u in preimages:
          preimages[u].append(w)
     else:
          preimages[u] = [w]

The problem is most likely because I have set u immutable, but I need to get preimages for my function u = w * K * v

Xenia gravatar imageXenia ( 2017-12-10 15:19:05 +0100 )edit

if I change the last part of my code to:

...
u = w * K * v
for u in results:
     preimages[u] = [w]

(results are defines before as list or tuple of all u) the problem with keys seems to be solved, but I do not get appropriate vectors as preimages, instead I get (1, 1, 1, 1, 1) for all u

Xenia gravatar imageXenia ( 2017-12-10 16:13:39 +0100 )edit

the best I can get, but the problem remains the same:

v = w.transpose()
for u in results:
     u = w * K * v
     u.set_immutable()
     preimages[u] = vector(w)
Xenia gravatar imageXenia ( 2017-12-10 17:06:26 +0100 )edit

2 Answers

Sort by ยป oldest newest most voted
1

answered 2017-12-10 19:59:26 +0100

dan_fulea gravatar image

The question creates a very complicated dictionary, so complicated that even the keys are not easily accessible.

In the following code, i will also define a matrix K, and an n for my taste, in the same time using exact objects.

n = 3
K = matrix( ZZ, 3, 3, [ 1,2,1,2,1,2,1,2,1 ] )

import itertools
W = itertools.product( [0,1], repeat = n )
preimages = {}

for w in W:
     w = vector(w)
     w = w.row()
     v = w.transpose()
     u = w * K * v
     u.set_immutable()
     if u in preimages:
          preimages[u].append(w)
     else:
          preimages[u] = [w]

keys = preimages.keys()
for key in keys:
    print key, type(key), preimages[ key ]

# trying to get the value for the MATRIX [6], which is ("convinced" to be) a key...
m = matrix( ZZ, 1, 1, [6,] )
m.set_immutable()
print "preimages of [6,] is:", preimages[ m ]

This gives:

[0] <type 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'> [[0 0 0]]
[1] <type 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'> [[0 0 1], [0 1 0], [1 0 0]]
[13] <type 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'> [[1 1 1]]
[6] <type 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'> [[0 1 1], [1 1 0]]
[4] <type 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'> [[1 0 1]]
preimages of [6,] is: [[0 1 1], [1 1 0]]

Note:

There are many other better ways to build versions of the above preimages dictionary. For instance:

n = 3
K = matrix( ZZ, 3, 3, [ 1,2,1,2,1,2,1,2,1 ] )

V = [ vector( c )
      for c in cartesian_product( [ [ ZZ(0), ZZ(1) ] for _ in range(n) ] ) ]

def f( v ):
    return ( v.row() * K * v.column() )[0,0]

f_values = list( set( [ f(v) for v in V ] ) )
preimages = dict( [ ( val, [ v for v in V if f(v) == val ] )
                    for val in f_values ] )

The generated dictionary is:

sage: import pprint
sage: pprint.pprint( preimages )
{0: [(0, 0, 0)],
 1: [(0, 0, 1), (0, 1, 0), (1, 0, 0)],
 4: [(1, 0, 1)],
 6: [(0, 1, 1), (1, 1, 0)],
 13: [(1, 1, 1)]}
edit flag offensive delete link more

Comments

Thanks a lot for your answer and help, but it seems that the problem remained the same. Keys of a dictionary are matrices and I cannot get specific preimage. For example for your last example if I type preimage[4] it still gives me a KeyError

If I work with real number instead of integers ZZ, it does not work either

m = matrix( ZZ, 1, 1, [6,] )
m.set_immutable()
Xenia gravatar imageXenia ( 2017-12-11 13:31:41 +0100 )edit
1

Please mention what is really needed for the further application:

  • Do we really need 1x1 matrices as keys? If not, than the solution is to replace the two lines in the initial post, u = w * K * v, and u.set_immutable() with the one line u = (w * K * v)[0,0] - then the key is a "number".

  • Do we really need floating, inaccurate numbers? If yes, than the caller / user function of the dictionary has to take care, since there is a good danger to miss the key. The post of slelievre is relevant for this aspect. Better use strings or explicitly truncated values of the numbers. (The keys will be detected, by there are no longer accurate in the further usage.)

    • Why do we need in fact this dictionary, designed this way?
dan_fulea gravatar imagedan_fulea ( 2017-12-11 15:10:54 +0100 )edit

Thank you, it works better now. I think the problem was because of the keys being matrices. Why do we need this dictionary? I need to find minimal values of my function and then find the corresponding vectors for those minimal values. Initially I thought, it could be easy to just define a dictionary like this and find corresponding vectors this way.

Xenia gravatar imageXenia ( 2017-12-11 19:36:46 +0100 )edit
0

answered 2017-12-10 18:25:08 +0100

slelievre gravatar image

This is because many different "floating-point" numbers display as 1.27.

See my answer to this other Sage question for an explanation of a related phenomenon: https://ask.sagemath.org/question/40024/why-is-ab-false/.

One workaround might be to use a string representation of these numbers as keys to your dictionary:

  • use str(f(x)) instead of f(x) as a key when building your dictionary
  • then use preimages['1.27'] to get the preimages of 1.27
edit flag offensive delete link more

Comments

It's worth noting in this case that the OP's dict keys are not even decimal numbers of some kind, but rather 1x1 immutable matrices thereof. Their mistake seems to be, most likely, ignoring this fact and copying just the numeric value and/or copying the repr of the 1x1 matrix (which happens to be the same as the repr of a one element Python list). Depending on the context they may or may not prefer to use a simpler type for the dict keys. But if not then they have to be aware that merely copying the text representation of an object is not necessarily the same as the object itself for the purposes of keying into a dictionary.

Iguananaut gravatar imageIguananaut ( 2017-12-11 16:29:14 +0100 )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

1 follower

Stats

Asked: 2017-12-10 14:43:41 +0100

Seen: 2,607 times

Last updated: Dec 10 '17