QuantumDictionary#

class QuantumDictionary(init_dict={}, return_type=None)[source]#

This class can be used for loading data relations into the quantum computer which are not based on a quantum algorithm.

As an inheritor of the Python dictionary it has all the functionality we are used to

>>> from qrisp import QuantumDictionary, QuantumVariable, multi_measurement
>>> qd = QuantumDictionary()
>>> qd[1] = 2
>>> qd[42] = (3,4)
>>> qd["hello"] = "hallo"
>>> qd["world"] = "welt"
>>> print(qd[42])
(3,4)

The key difference is that the QuantumDictionary can also recieve QuantumVariables as keys and return the corresponding values as an entangled QuantumVariable.

We demonstrate this by preparing a QuantumVariable which has the keys of qd as outcome labels:

>>> key_qv = QuantumVariable.custom([1, 42, "hello", "world"])
>>> key_qv[:] = {"hello" : 1, "world" : 1}
>>> print(key_qv)
{'hello': 0.5, 'world': 0.5}

We now load the data from the QuantumDictionary into the quantum algorithm by dereferencing qd with key_qv:

>>> value_qv = qd[key_qv]
>>> multi_measurement([key_qv, value_qv])
{('hello', 'hallo'): 0.5, ('world', 'welt'): 0.5}

We see that the states of key_qv are now entangled with the states of the values.

QuantumDictionaries can also load from tuples of QuantumVariables:

>>> qd[(1,2)] = 73
>>> qd[(0,2)] = 37
>>> qf1 = QuantumFloat(1)
>>> qf2 = QuantumFloat(2)
>>> h(qf1)
>>> qf2[:] = 2
>>> res = qd[(qf1, qf2)]
>>> multi_measurement([qf1, qf2, res])
{(0, 2, 37): 0.5, (1, 2, 73): 0.5}

Mathematically we have

\[U_{\text{qd}} \left( \sum_{x \in \text{labels}} a_x \ket{x} \right) \ket{0} = \sum_{x \in \text{labels}} a_x \ket{x} \ket{\text{qd}[x]}\]

Note that this quantum operation is realized through quantum logic synthesis, which scales rather badly compared to algorithmic generation of data relations. Therefore, performing as much logic on the quantum computer is preferable over performing the logic on the classical computer and inserting the results using QuantumDictionaries.

Specifying the return type

The returned QuantumVariable value_qv is (similar to key_qv) a CustomQuantumVariable:

>>> print(type(value_qv))
<class 'qrisp.misc.misc_functions.custom_qv.<locals>.CustomQuantumVariable'>

If we want to apply further processing this might not be helpfull since custom QuantumVariables lack many methods that are available in more specific quantum types. In this case we can supply the QuantumDictionary with a return type:

>>> from qrisp import QuantumFloat
>>> qtype = QuantumFloat(4, -2, signed = True)
>>> float_qd = QuantumDictionary(return_type = qtype)

We fill again with some example values

>>> float_qd["hello"] = 0.5
>>> float_qd["world"] = -1

And retrieve the value:

>>> value_qv = float_qd[key_qv]
>>> print(type(value_qv))
<class 'qrisp.qtypes.quantum_float.QuantumFloat'>

Since value_qv is a QuantumFloat now, we can use the established methods for arithmetic - for instance the inplace addition:

>>> value_qv += 1.5
>>> print(multi_measurement([key_qv, value_qv]))
{('hello', 2.0): 0.5, ('world', 0.5): 0.5}

Advanced usage

In some cases, (such as manual uncomputation) it is required to specify into which variable the QuantumDictionary should load. We do this with the load method:

>>> qf = qtype.duplicate()
>>> float_qd.load(key_qv, qf)
>>> print(qf)
{0.5: 0.5, -1.0: 0.5}

The load method furthermore allows to specify which logic synthesis algorithm should be used.

>>> qf2 = qtype.duplicate()
>>> float_qd.load(key_qv, qf2, synth_method = "gray")

Methods#

QuantumDictionary.load(key[, value_qv, ...])

Loads the values of the QuantumDictionary into a given QuantumVariable.