# Keys of a dictionary

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'


edit retag close merge delete

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.

( 2017-12-10 07:57:54 -0500 )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".

( 2017-12-10 08:02:34 -0500 )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

( 2017-12-10 08:19:05 -0500 )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

( 2017-12-10 09:13:39 -0500 )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)

( 2017-12-10 10:06:26 -0500 )edit

Sort by » oldest newest most voted

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)]}

more

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()

( 2017-12-11 06:31:41 -0500 )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?
( 2017-12-11 08:10:54 -0500 )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.

( 2017-12-11 12:36:46 -0500 )edit

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
more

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.

( 2017-12-11 09:29:14 -0500 )edit