From 0e7b03d9c9ac54720089c3c4c52b26eb8cd8f85d Mon Sep 17 00:00:00 2001 From: "Davide Gessa (dakk)" Date: Sun, 16 Jun 2024 15:12:53 +0200 Subject: [PATCH] improve bernstein vazirani testing --- docs/source/example_simon.ipynb | 1 + qlasskit/algorithms/__init__.py | 2 +- qlasskit/algorithms/bernsteinvazirani.py | 23 +++++--- test/algo/test_bernstein_vazirani.py | 70 ++++++++++-------------- test/test_tools.py | 2 +- 5 files changed, 48 insertions(+), 50 deletions(-) diff --git a/docs/source/example_simon.ipynb b/docs/source/example_simon.ipynb index 9e38bb1f..c80d77d3 100644 --- a/docs/source/example_simon.ipynb +++ b/docs/source/example_simon.ipynb @@ -24,6 +24,7 @@ "source": [ "from qlasskit import qlassf, Qint\n", "\n", + "\n", "@qlassf\n", "def f(a: Qint[4]) -> Qint[4]:\n", " return (a >> 3) + 1" diff --git a/qlasskit/algorithms/__init__.py b/qlasskit/algorithms/__init__.py index 6df7ba1e..f6d0dddc 100644 --- a/qlasskit/algorithms/__init__.py +++ b/qlasskit/algorithms/__init__.py @@ -21,4 +21,4 @@ from .grover import Grover # noqa: F401, E402 from .simon import Simon # noqa: F401, E402 from .deutschjozsa import DeutschJozsa # noqa: F401, E402 -from .bernsteinvazirani import BernsteinVazirani +from .bernsteinvazirani import BernsteinVazirani, secret_oracle # noqa: F401, E402 diff --git a/qlasskit/algorithms/bernsteinvazirani.py b/qlasskit/algorithms/bernsteinvazirani.py index 51b3c436..23e76058 100644 --- a/qlasskit/algorithms/bernsteinvazirani.py +++ b/qlasskit/algorithms/bernsteinvazirani.py @@ -16,10 +16,21 @@ from ..qcircuit import QCircuit from ..qlassfun import QlassF -from ..types import Qtype, interpret_as_qtype, format_outcome +from ..types import Qtype, interpret_as_qtype from .qalgorithm import QAlgorithm +def secret_oracle(isize, secret): + """Create an oracle embedding a secret for Bernstein-Vazirani""" + f = f"def oracle(x: Qint[{isize}]) -> bool:\n" + f += f" s=Qint{isize}({secret})\n" + f += " return (" + f += "^".join(f"(x[{i}]&s[{i}])" for i in range(isize)) + f += ")" + + return QlassF.from_function(f) + + class BernsteinVazirani(QAlgorithm): def __init__( self, @@ -62,12 +73,10 @@ def output_qubits(self) -> List[int]: """Returns the list of output qubits""" len_a = len(self.f.args[0]) return list(range(len_a)) - - # @override def decode_output( - self, istr: Union[str, int, List, dict] - ) -> Union[Tuple[str, int], Qtype, str]: - format_outcome(istr, len(self.f.args[0]) - 1) - return istr[-len(self.f.args[0]):][::-1] + self, istr: Union[str, int, List[bool]] + ) -> Union[Tuple[str, int], Qtype, str]: + return interpret_as_qtype(istr, self.f.args[0].ttype, len(self.f.args[0])) + # return istr[-len(self.f.args[0]) :][::-1] diff --git a/test/algo/test_bernstein_vazirani.py b/test/algo/test_bernstein_vazirani.py index cc9033a4..21ff4372 100644 --- a/test/algo/test_bernstein_vazirani.py +++ b/test/algo/test_bernstein_vazirani.py @@ -14,56 +14,44 @@ import unittest -from parameterized import parameterized_class +from parameterized import parameterized, parameterized_class -from qlasskit import qlassf -from qlasskit.algorithms import BernsteinVazirani +from qlasskit import QlassF +from qlasskit.algorithms import BernsteinVazirani, secret_oracle from ..utils import ENABLED_COMPILERS, qiskit_measure_and_count @parameterized_class(("compiler"), ENABLED_COMPILERS) class TestAlgoBernsteinVazirani(unittest.TestCase): - - - def test_1_bernstein_vazirani(self): - f = """ -def oracle(x: Qint[4]) -> bool: - s=Qint4(14) - return ((x[0]&s[0])^(x[1]&s[1])^(x[2]&s[2])^(x[3]&s[3])) -""" - qf = qlassf(f, compiler=self.compiler) - algo = BernsteinVazirani(qf) - - qc_algo = algo.circuit().export("circuit", "qiskit") - counts = qiskit_measure_and_count(qc_algo, shots=1024) - counts_readable = algo.decode_counts(counts) - self.assertEqual(counts_readable["0111"],1024) - - def test_2_bernstein_vazirani(self): - f = """ -def oracle(x: Qint[4]) -> bool: - s=Qint4(12) - return ((x[0]&s[0])^(x[1]&s[1])^(x[2]&s[2])^(x[3]&s[3])) -""" - qf = qlassf(f, compiler=self.compiler) - algo = BernsteinVazirani(qf) + def test_secret_oracle(self): + isize = 4 + secret = 12 + + f = f"def oracle(x: Qint[{isize}]) -> bool:\n" + f += f" s=Qint{isize}({secret})\n" + f += " return (" + f += "^".join(f"(x[{i}]&s[{i}])" for i in range(isize)) + f += ")" + + qf = QlassF.from_function(f) + qf2 = secret_oracle(isize, secret) + self.assertEqual(qf.export("qasm"), qf2.export("qasm")) + + @parameterized.expand( + [ + (4, 14), + (4, 12), + (4, 15), + (8, 122), + ] + ) + def test_bernstein_vazirani_secret(self, isize, secret): + algo = BernsteinVazirani(secret_oracle(isize, secret)) qc_algo = algo.circuit().export("circuit", "qiskit") counts = qiskit_measure_and_count(qc_algo, shots=1024) counts_readable = algo.decode_counts(counts) - self.assertEqual(counts_readable["0011"],1024) - - def test_3_bernstein_vazirani(self): - f = """ -def oracle(x: Qint[4]) -> bool: - s=Qint4(15) - return ((x[0]&s[0])^(x[1]&s[1])^(x[2]&s[2])^(x[3]&s[3])) -""" - qf = qlassf(f, compiler=self.compiler) - algo = BernsteinVazirani(qf) - qc_algo = algo.circuit().export("circuit", "qiskit") - counts = qiskit_measure_and_count(qc_algo, shots=1024) - counts_readable = algo.decode_counts(counts) - self.assertEqual(counts_readable["1111"],1024) + self.assertTrue(secret in counts_readable) + self.assertEqual(counts_readable[secret], 1024) diff --git a/test/test_tools.py b/test/test_tools.py index a59c75c5..9b03ecfd 100644 --- a/test/test_tools.py +++ b/test/test_tools.py @@ -20,13 +20,13 @@ import sympy from sympy.logic.boolalg import And, Not, Or, is_cnf, is_dnf, is_nnf + # from sympy.logic.boolalg import to_anf from sympy.logic.utilities.dimacs import load import qlasskit from qlasskit.qcircuit import exporter_qasm from qlasskit.qlassfun import qlassf - from qlasskit.tools import utils dummy_script = """