This notebook is a brief sketch of how to use Simon's algorithm. We start by declaring all necessary imports.


In [ ]:
from collections import defaultdict

import numpy as np
from mock import patch

from grove.simon.simon import Simon, create_valid_2to1_bitmap

Simon's algorithm can be used to find the mask $m$ of a 2-to-1 periodic Boolean function defined by $$f(x) = f(x \oplus m)$$ where $\oplus$ is the bit-wise XOR operator. To create one we can define a mask as a string and call a utility to generate a map. To assert the correct result we check it against an expected map


In [ ]:
mask = '110'
bm = create_valid_2to1_bitmap(mask, random_seed=42)
expected_map = {
    '000': '001',
    '001': '101',
    '010': '000',
    '011': '111',
    '100': '000',
    '101': '111',
    '110': '001',
    '111': '101'
}
for k, v in bm.items():
    assert v == expected_map[k]

To understand what a 2-to-1 function is let us revert the map and collect all keys tha point to the same value. As the assertion shows all values have 2 distinct origins


In [ ]:
reverse_bitmap = defaultdict(list)
for k, v in bm.items():
    reverse_bitmap[v].append(k)

expected_reverse_bitmap = {
    '001': ['000', '110'],
    '101': ['001', '111'],
    '000': ['010', '100'],
    '111': ['011', '101']
}

for k, v in reverse_bitmap.items():
    assert sorted(v) == sorted(expected_reverse_bitmap[k])

To use Simon's algorithm on a Quantum Hardware we need to define the connection to the QVM or QPU. However we don't have a real connection in this notebook, so we just mock out the response. If you run this notebook, ensure to replace cxn with a pyQuil connection object.


In [ ]:
with patch("pyquil.api.QuantumComputer") as qc:
    # Need to mock multiple returns as an iterable
    qc.run.side_effect = [
        (np.asarray([0, 1, 1], dtype=int), ),
        (np.asarray([1, 1, 1], dtype=int), ),
        (np.asarray([1, 1, 1], dtype=int), ),
        (np.asarray([1, 0, 0], dtype=int), ),
    ]

Now let's run Simon's algorithm. We instantiate the Simon object and then call its find_mask mehtod with the connection object and the 2-to-1 function whose mask we wish to find. Finally we assert its correctness by checking with the mask we used to generate the function


In [ ]:
sa = Simon()
found_mask = sa.find_mask(qc, bm)
assert ''.join([str(b) for b in found_mask]) == mask, "Found mask is not expected mask"

If the assertion succeeded we know we found the mask and we got our result.