Skip to content

Commit 1f472bd

Browse files
committed
simon algorithm
1 parent 97622bf commit 1f472bd

File tree

7 files changed

+121
-10
lines changed

7 files changed

+121
-10
lines changed

TODO.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
- [x] Qmatrix
108108
- [x] Hash function preimage attack notebook
109109
- [x] Move all examples to doc
110+
- [x] Simon periodicity
110111
- [ ] Improve documentation
111112
- [ ] First stable release
112113

@@ -133,6 +134,10 @@
133134
- [ ] Builtin function: map
134135
- [ ] First beta release
135136

137+
### Algorithms
138+
139+
- [ ] Deutsch-Jozsa
140+
136141
### Language support
137142

138143
- [ ] Datatype: Dict

docs/source/example_grover_hash.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"cell_type": "markdown",
3333
"metadata": {},
3434
"source": [
35-
"Thanks to the fact that qlasskit function are standard python functions, we can call the `original_f` to perform some kind of analysis on the hash function. Since the input space is tiny (it is a toy hash function), we can detect if the hash function it's uniform (if it maps equally to the output space)."
35+
"Thanks to the fact that qlasskit function are standard python functions, we can call the `original_f` to perform some kind of analysis on the hash function. Since the input space is tiny (it is a toy hash function), we can detect if the hash function is uniform (if it maps equally to the output space)."
3636
]
3737
},
3838
{

qlasskit/algorithms/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@
1919
ConstantOracleException,
2020
)
2121
from .grover import Grover # noqa: F401, E402
22+
from .simon import Simon # noqa: F401, E402

qlasskit/algorithms/simon.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright 2023 Davide Gessa
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from typing import List, Tuple, Union
16+
17+
from ..qcircuit import QCircuit
18+
from ..qlassfun import QlassF
19+
from ..types import Qtype, interpret_as_qtype
20+
from .qalgorithm import QAlgorithm
21+
22+
23+
class Simon(QAlgorithm):
24+
def __init__(
25+
self,
26+
f: QlassF,
27+
):
28+
"""
29+
Args:
30+
f (QlassF): our f(x)
31+
"""
32+
if len(f.args) != 1:
33+
raise Exception("f should receive exactly one parameter")
34+
35+
self.f: QlassF = f
36+
self.search_space_size = len(f.args[0])
37+
self._qcircuit = QCircuit(self.f.num_qubits)
38+
39+
# State preparation
40+
self._qcircuit.barrier(label="s")
41+
for i in range(self.search_space_size):
42+
self._qcircuit.h(i)
43+
44+
# Prepare and add the f
45+
self._qcircuit += self.f.circuit()
46+
47+
# State preparation out
48+
self._qcircuit.barrier(label="s")
49+
for i in range(self.search_space_size):
50+
self._qcircuit.h(i)
51+
52+
# @override
53+
@property
54+
def output_qubits(self) -> List[int]:
55+
"""Returns the list of output qubits"""
56+
len_a = len(self.f.args[0])
57+
return list(range(len_a))
58+
59+
# @override
60+
def decode_output(
61+
self, istr: Union[str, int, List[bool]]
62+
) -> Union[bool, Tuple, Qtype]:
63+
return interpret_as_qtype(istr, self.f.args[0].ttype, len(self.f.args[0]))

qlasskit/qcircuit/qcircuitwrapper.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ def encode_input(self, *qvals):
6363
def decode_output(self, istr):
6464
raise Exception("Abstract")
6565

66-
def decode_counts(self, counts: Dict[str, int], discard_lower: Optional[int] = None) -> Dict[Any, int]:
66+
def decode_counts(
67+
self, counts: Dict[str, int], discard_lower: Optional[int] = None
68+
) -> Dict[Any, int]:
6769
"""Decode data from a circuit counts dict"""
6870
outcomes = [(self.decode_output(e), c) for (e, c) in counts.items()]
6971
int_counts: Dict[Any, int] = {}
@@ -72,10 +74,12 @@ def decode_counts(self, counts: Dict[str, int], discard_lower: Optional[int] = N
7274
int_counts[e] += c
7375
else:
7476
int_counts[e] = c
75-
77+
7678
if discard_lower:
77-
int_counts = dict(filter(lambda el: el[1] >= discard_lower, int_counts.items()))
78-
79+
int_counts = dict(
80+
filter(lambda el: el[1] >= discard_lower, int_counts.items())
81+
)
82+
7983
return int_counts
8084

8185
def circuit(self):

qlasskit/types/__init__.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,17 @@ def interpret_as_qtype(
103103
out: Union[str, int, List[bool]], qtype, out_len: Optional[int] = None
104104
) -> Any:
105105
out = list(reversed(format_outcome(out, out_len)))
106-
106+
107107
def _getsize(x):
108108
if hasattr(x, "BIT_SIZE"):
109-
return x.BIT_SIZE
109+
return x.BIT_SIZE
110110
elif len(get_args(x)) > 0:
111111
size = 0
112112
for x in get_args(x):
113-
size += _getsize(x)
114-
return size
113+
size += _getsize(x)
114+
return size
115115
else:
116116
return 1
117-
118117

119118
def _interpret(out, qtype, out_len):
120119
if hasattr(qtype, "from_bool"):

test/test_algo_simon.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2023 Davide Gessa
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import unittest
16+
17+
from qlasskit import Qint2, Qint4, qlassf
18+
from qlasskit.algorithms import Simon
19+
20+
from .utils import qiskit_measure_and_count
21+
22+
23+
class TestAlgoSimon(unittest.TestCase):
24+
def test_simon(self):
25+
f = """
26+
def hash(k: Qint4) -> Qint4:
27+
return k >> 3
28+
"""
29+
qf = qlassf(f, compiler="tweedledum")
30+
algo = Simon(qf)
31+
32+
qc = algo.circuit().export("circuit", "qiskit")
33+
counts = qiskit_measure_and_count(qc, shots=1024)
34+
counts_readable = algo.decode_counts(counts)
35+
36+
for x in [0, 8]:
37+
self.assertEqual(x in counts_readable, True)
38+
self.assertEqual(counts_readable[x] > 480, True)
39+
self.assertEqual(algo.output_qubits, [0, 1, 2, 3])

0 commit comments

Comments
 (0)