diff --git a/TODO.md b/TODO.md index 0a7e5002..8a44fa1f 100644 --- a/TODO.md +++ b/TODO.md @@ -50,8 +50,10 @@ - [x] Extensible type system - [x] Builtin functions: max(), min(), len() - [x] Function call (to builtin) +- [x] Int arithmetic: + +- [ ] Int: shift right / left +- [ ] Int: subtraction - [ ] Publish doc -- [ ] Int arithmetic: + ## Month 2: diff --git a/qlasskit/ast2ast.py b/qlasskit/ast2ast.py index 6853b8fd..e34b0add 100644 --- a/qlasskit/ast2ast.py +++ b/qlasskit/ast2ast.py @@ -72,7 +72,7 @@ def visit_Call(self, node): else: args = node.args - op = ast.Gt() if node.func.id == "max" else ast.Lt() + op = ast.Gt() if node.func.id == "max" else ast.LtE() def iterif(arg_l): if len(arg_l) == 1: diff --git a/qlasskit/ast2logic/__init__.py b/qlasskit/ast2logic/__init__.py index 7915a41e..284d1aa7 100644 --- a/qlasskit/ast2logic/__init__.py +++ b/qlasskit/ast2logic/__init__.py @@ -15,7 +15,7 @@ from .env import Env, Binding # noqa: F401, E402 from .utils import flatten # noqa: F401, E402 -from .typing import Args, BoolExpList # noqa: F401, E402 +from .typing import Args, Arg, BoolExpList # noqa: F401, E402 from .t_arguments import translate_argument, translate_arguments # noqa: F401, E402 from .t_expression import translate_expression, decompose_to_symbols # noqa: F401, E402 from .t_statement import translate_statement # noqa: F401, E402 diff --git a/qlasskit/compiler/poccompiler2.py b/qlasskit/compiler/poccompiler2.py index 0177c423..a5f83f87 100644 --- a/qlasskit/compiler/poccompiler2.py +++ b/qlasskit/compiler/poccompiler2.py @@ -123,12 +123,27 @@ def compile_expr(self, qc: QCircuit, expr: Boolean) -> int: elif isinstance(expr, Xor): erets = list(map(lambda e: self.compile_expr(qc, e), expr.args)) + last = erets.pop() qc.barrier("xor") - [qc.mark_ancilla(eret) for eret in erets[:-1]] - qc.mcx(erets[0:-1], erets[-1]) - return erets[-1] + if last in qc.ancilla_lst: + fa = last + self.expqmap.update_exp_for_qubit(last, expr) + else: + fa = qc.get_free_ancilla() + + qc.cx(last, fa) + qc.mark_ancilla(last) + self.expqmap[expr] = fa + + for x in erets: + qc.cx(x, fa) + + [qc.mark_ancilla(eret) for eret in erets] + self.garbage_collect(qc) + + return fa elif isinstance(expr, BooleanFalse): return qc.get_free_ancilla() diff --git a/test/test_qlassf_bool.py b/test/test_qlassf_bool.py index 8c931a3f..51774868 100644 --- a/test/test_qlassf_bool.py +++ b/test/test_qlassf_bool.py @@ -183,7 +183,7 @@ def test_assign3(self): + "\th = (not a) and b and (not c)\n" + "\treturn g if d and e else h" ) - qf = qlassf(f, to_compile=False) + qf = qlassf(f, to_compile=COMPILATION_ENABLED) self.assertEqual(len(qf.expressions), 5) self.assertEqual(qf.expressions[-1][1], ITE(d & e, g, h)) compute_and_compare_results(self, qf) diff --git a/test/test_qlassf_int.py b/test/test_qlassf_int.py index d0b3e92e..b6542385 100644 --- a/test/test_qlassf_int.py +++ b/test/test_qlassf_int.py @@ -293,8 +293,9 @@ def test_composed_comparators(self): # return a + b +# TODO: parameterize class TestQlassfIntAdd(unittest.TestCase): - def test_add2(self): + def test_add_tuple(self): f = "def test(a: Tuple[Qint2, Qint2]) -> Qint2: return a[0] + a[1]" qf = qlassf(f, to_compile=COMPILATION_ENABLED) compute_and_compare_results(self, qf) @@ -313,3 +314,13 @@ def test_add_const2(self): f = "def test() -> Qint4: return Qint4(3) + 3" qf = qlassf(f, to_compile=COMPILATION_ENABLED) compute_and_compare_results(self, qf) + + def test_add_const3(self): + f = "def test(a: Qint2, b: Qint2) -> Qint4: return Qint4(3) + a if a == 3 else Qint4(1) + b" + qf = qlassf(f, to_compile=COMPILATION_ENABLED) + compute_and_compare_results(self, qf) + + def test_add_const4(self): + f = "def test(a: Qint2) -> Qint2: return a + 2" + qf = qlassf(f, to_compile=COMPILATION_ENABLED) + compute_and_compare_results(self, qf) diff --git a/test/utils.py b/test/utils.py index d6520bf5..7f4875c0 100644 --- a/test/utils.py +++ b/test/utils.py @@ -54,15 +54,13 @@ def compute_result_of_qcircuit(cls, qf, truth_line): gate = qf.gate() qc = QuantumCircuit(gate.num_qubits) - # circ_qi = circ.export("circuit", "qiskit") - # print(circ_qi.draw("text")) - # print(qf.expressions) - # Prepare inputs [qc.initialize(1 if truth_line[i] else 0, i) for i in range(qf.input_size)] qc.append(gate, list(range(qf.num_qubits))) + # print(qc.decompose().draw("text")) + # Measure counts = qiskit_measure_and_count(qc) @@ -111,7 +109,7 @@ def res_to_str(res): return "".join([res_to_str(x) for x in res]) elif type(res) == int: qc = const_to_qtype(res) - qi = qc[0].from_bool(qc[1]) + qi = qf.returns.ttype.from_bool(qc[1]) return qi.to_bin() else: return res.to_bin() @@ -145,6 +143,11 @@ def compute_and_compare_results(cls, qf): if len(truth_table) > MAX_Q_SIM and COMPILATION_ENABLED: qc_truth = [random.choice(truth_table) for x in range(MAX_Q_SIM)] + elif COMPILATION_ENABLED: + qc_truth = truth_table + + # circ_qi = qf.circuit().export("circuit", "qiskit") + # print(circ_qi.draw("text")) for truth_line in truth_table: # Extract str of truthtable and result @@ -152,11 +155,11 @@ def compute_and_compare_results(cls, qf): map(lambda x: "1" if x else "0", truth_line[-qf.ret_size :]) ) + # Calculate and compare the originalf result + res_original = compute_result_of_originalf(cls, qf, truth_line) + cls.assertEqual(truth_str, res_original) + # Calculate and compare the gate result if qc_truth and truth_line in qc_truth and COMPILATION_ENABLED: res_qc = compute_result_of_qcircuit(cls, qf, truth_line) cls.assertEqual(truth_str, res_qc) - - # Calculate and compare the originalf result - res_original = compute_result_of_originalf(cls, qf, truth_line) - cls.assertEqual(truth_str, res_original)