diff --git a/TODO.md b/TODO.md index a8de210d..b40b0bc6 100644 --- a/TODO.md +++ b/TODO.md @@ -71,6 +71,7 @@ ### Week 2: (30 Oct 23) +- [x] Tuple-tuple comparison - [ ] Groover algorithm tests ### Week 3: (6 Nov 23) diff --git a/examples/groover_hash_collision.py b/examples/groover_hash_collision.py index 0cc2dfcb..647c5c0f 100644 --- a/examples/groover_hash_collision.py +++ b/examples/groover_hash_collision.py @@ -41,6 +41,21 @@ def qiskit_simulate(qc): # return (k<<1) + 2 if inner(k) else 4 +# from typing import Tuple + +# @qlassf +# def hash(k: Qint8) -> Tuple[bool, bool]: +# return k[0] and k[1] and not k[2] and not k[3], k[4] and not k[5] and k[6] and not k[7] +# algo = Groover(hash, (True,True)) + + +# @qlassf +# def hash(k: Qint8) -> bool: +# return k[0] and k[1] and not k[2] and not k[3] and k[4] and not k[5] and k[6] and not k[7] + +# algo = Groover(hash, True) + + @qlassf def hash(k: Qint4) -> Qint4: return (k << 1) + 2 diff --git a/qlasskit/algorithms/groover.py b/qlasskit/algorithms/groover.py index 09cf2154..86d4ee36 100644 --- a/qlasskit/algorithms/groover.py +++ b/qlasskit/algorithms/groover.py @@ -99,14 +99,11 @@ def oracle_outer(v: {argt_name}) -> bool: for i in range(n_iterations): self.qc.barrier(label=f"g{i}") - # self.qc.barrier(label=f"orac_{i}") self.qc += oracle_qc.copy() - # self.qc.barrier(label=f"diff_{i}") + self.qc.barrier() self.qc += diffuser_qc.copy() - # self.qc.barrier(label="end") - def circuit(self) -> QCircuit: return self.qc diff --git a/qlasskit/ast2logic/t_expression.py b/qlasskit/ast2logic/t_expression.py index cba1dd17..5d2f02b5 100644 --- a/qlasskit/ast2logic/t_expression.py +++ b/qlasskit/ast2logic/t_expression.py @@ -178,6 +178,34 @@ def unfold(v_exps, op): # Check comparability if tleft[0] == bool and tcomp[0] == bool: op_type = Qbool + + # Compare tuples for equality / inequality + elif len(get_args(tleft[0])) > 0 and len(get_args(tcomp[0])) > 0: + arg_l = get_args(tleft[0]) + arg_r = get_args(tcomp[0]) + if arg_l != arg_r: + raise exceptions.TypeErrorException(tleft[0], tcomp[0]) + + if isinstance(expr.ops[0], ast.Eq): + op = Qbool.eq + elif isinstance(expr.ops[0], ast.NotEq): + op = Qbool.neq + else: + raise exceptions.OperationNotSupportedException(bool, expr.ops[0]) + + c = True + idx = 0 + for left, right in zip(arg_l, arg_r): + if left == bool: + c = And(c, op((bool, tleft[1][idx]), (bool, tcomp[1][idx]))[1]) + idx += 1 + else: + for si in range(left.BIT_SIZE): + c = And(c, op((bool, tleft[1][i]), (bool, tcomp[1][idx]))[1]) + idx += 1 + + return (bool, c) + elif issubclass(tleft[0], Qtype) and issubclass(tcomp[0], Qtype): # type: ignore if not tleft[0].comparable(tcomp[0]): # type: ignore raise exceptions.TypeErrorException(tcomp[0], tleft[0]) diff --git a/qlasskit/compiler/internalcompiler.py b/qlasskit/compiler/internalcompiler.py index 003fd348..34131502 100644 --- a/qlasskit/compiler/internalcompiler.py +++ b/qlasskit/compiler/internalcompiler.py @@ -71,8 +71,6 @@ def compile_expr( # noqa: C901 elif isinstance(expr, Not): eret = self.compile_expr(qc, expr.args[0]) - # qc.barrier("not") - if eret in qc.ancilla_lst: qc.x(eret) self.expqmap[expr] = eret @@ -92,7 +90,6 @@ def compile_expr( # noqa: C901 if dest is None: dest = qc.get_free_ancilla() - # qc.barrier("and") qc.mcx(erets, dest) [qc.mark_ancilla(eret) for eret in erets] @@ -104,8 +101,6 @@ def compile_expr( # noqa: C901 erets = list(map(lambda e: self.compile_expr(qc, e), expr.args)) last = erets.pop() - # qc.barrier("xor") - if last in qc.ancilla_lst: dest = last self.expqmap[expr] = last diff --git a/qlasskit/qcircuit/qcircuitenhanced.py b/qlasskit/qcircuit/qcircuitenhanced.py index 661c0c08..1aa98184 100644 --- a/qlasskit/qcircuit/qcircuitenhanced.py +++ b/qlasskit/qcircuit/qcircuitenhanced.py @@ -100,7 +100,7 @@ def uncompute_all(self, keep: List[Union[Symbol, int]] = []): # TODO: replace with + invert(keep) scopy = copy.deepcopy(self.gates) uncomputed = set() - # self.barrier(label="un_all") + for g, qbs, p in reversed(scopy): if ( isinstance(g, gates.NopGate) @@ -115,10 +115,6 @@ def uncompute_all(self, keep: List[Union[Symbol, int]] = []): self.append(g, qbs, p) - # Remove barrier if no uncomputed - # if len(uncomputed) == 0: - # self.gates.pop() - return uncomputed def uncompute(self, to_mark=[]): @@ -128,8 +124,6 @@ def uncompute(self, to_mark=[]): if len(self.marked_ancillas) == 0: return [] - # self.barrier(label="un") - uncomputed = set() new_gates_comp = [] @@ -145,8 +139,4 @@ def uncompute(self, to_mark=[]): self.marked_ancillas = self.marked_ancillas - uncomputed self.gates_computed = new_gates_comp[::-1] - # Remove barrier if no uncomputed - # if len(uncomputed) == 0: - # self.gates.pop() - return uncomputed diff --git a/test/test_qlassf_tuple.py b/test/test_qlassf_tuple.py index 58f858d5..e1209a73 100644 --- a/test/test_qlassf_tuple.py +++ b/test/test_qlassf_tuple.py @@ -132,3 +132,13 @@ def test_tuple_result(self): self.assertEqual(qf.expressions[1][0], Symbol("_ret.1")) self.assertEqual(qf.expressions[1][1], b) # compute_and_compare_results(self, qf) + + def test_tuple_compare(self): + f = "def test(a: Tuple[bool, bool], b: Tuple[bool, bool]) -> bool:\n\treturn a == b" + qf = qlassf(f, to_compile=COMPILATION_ENABLED) + compute_and_compare_results(self, qf) + + def test_tuple_int_compare(self): + f = "def test(a: Tuple[Qint2, Qint2], b: Tuple[Qint2, Qint2]) -> bool:\n\treturn a == b" + qf = qlassf(f, to_compile=COMPILATION_ENABLED) + compute_and_compare_results(self, qf)