diff --git a/pytket/binders/circuit/Circuit/add_op.cpp b/pytket/binders/circuit/Circuit/add_op.cpp index 7c9000d85e..07cccadb2a 100644 --- a/pytket/binders/circuit/Circuit/add_op.cpp +++ b/pytket/binders/circuit/Circuit/add_op.cpp @@ -513,6 +513,35 @@ void init_circuit_add_op(py::class_> &c) { ":param args: The bits to apply the expression to\n" ":return: the new :py:class:`Circuit`", py::arg("expr"), py::arg("args")) + .def( + "add_clexpr_from_logicexp", + [](Circuit *circ, const py::tket_custom::LogicExpression &exp, + const py::tket_custom::SequenceVec &output_bits, + const py::kwargs &kwargs) { + py::list outputs; + for (const auto &bit : output_bits) { + outputs.append(bit); + } + py::module clexpr = py::module::import("pytket.circuit.clexpr"); + py::object add_op = + clexpr.attr("_add_clexpr_to_circuit_from_logicexp"); + add_op(circ, exp, outputs, **kwargs); + return circ; + }, + "Append a :py:class:`ClExprOp` defined in terms of a logical " + "expression.\n\n" + "Example:\n" + ">>> c = Circuit()\n" + ">>> x_reg = c.add_c_register('x', 3)\n" + ">>> y_reg = c.add_c_register('y', 3)\n" + ">>> z_reg = c.add_c_register('z', 3)\n" + ">>> c.add_clexpr_from_logicexp(x_reg | y_reg, z_reg.to_list())\n" + ">>> [ClExpr x[0], x[1], x[2], y[0], y[1], y[2], z[0], z[1], z[2]; " + "]\n\n" + ":param exp: logical expression\n" + ":param output_bits: list of bits in output\n" + ":return: the updated circuit", + py::arg("exp"), py::arg("output_bits")) .def( "add_custom_gate", [](Circuit *circ, const composite_def_ptr_t &definition, diff --git a/pytket/docs/changelog.rst b/pytket/docs/changelog.rst index 0c5e383cf0..3495ec283d 100644 --- a/pytket/docs/changelog.rst +++ b/pytket/docs/changelog.rst @@ -20,6 +20,7 @@ Features: * Use `ClExprOp` by default when converting from QASM. * Extend `DecomposeClassicalExp` to handle `ClExprOp` as well as `ClassicalExpBox`. +* Add convenience method `Circuit.add_clecpr_from_logicexp()`. Deprecations: diff --git a/pytket/pytket/_tket/circuit.pyi b/pytket/pytket/_tket/circuit.pyi index f8c5649089..6105ee6703 100644 --- a/pytket/pytket/_tket/circuit.pyi +++ b/pytket/pytket/_tket/circuit.pyi @@ -1461,6 +1461,22 @@ class Circuit: :param args: The bits to apply the expression to :return: the new :py:class:`Circuit` """ + def add_clexpr_from_logicexp(self, exp: pytket.circuit.logic_exp.LogicExp, output_bits: typing.Sequence[pytket._tket.unit_id.Bit], **kwargs: Any) -> Circuit: + """ + Append a :py:class:`ClExprOp` defined in terms of a logical expression. + + Example: + >>> c = Circuit() + >>> x_reg = c.add_c_register('x', 3) + >>> y_reg = c.add_c_register('y', 3) + >>> z_reg = c.add_c_register('z', 3) + >>> c.add_clexpr_from_logicexp(x_reg | y_reg, z_reg.to_list()) + >>> [ClExpr x[0], x[1], x[2], y[0], y[1], y[2], z[0], z[1], z[2]; ] + + :param exp: logical expression + :param output_bits: list of bits in output + :return: the updated circuit + """ @typing.overload def add_conditional_barrier(self, barrier_qubits: typing.Sequence[int], barrier_bits: typing.Sequence[int], condition_bits: typing.Sequence[int], value: int, data: str = '') -> Circuit: """ diff --git a/pytket/pytket/circuit/clexpr.py b/pytket/pytket/circuit/clexpr.py index b12221cb37..62d7e4bfe1 100644 --- a/pytket/pytket/circuit/clexpr.py +++ b/pytket/pytket/circuit/clexpr.py @@ -13,6 +13,7 @@ # limitations under the License. from dataclasses import dataclass +from typing import Any from pytket.circuit import ( Bit, @@ -194,3 +195,10 @@ def check_register_alignments(circ: Circuit) -> bool: ): return False return True + + +def _add_clexpr_to_circuit_from_logicexp( + circ: Circuit, exp: LogicExp, output_bits: list[Bit], **kwargs: Any +) -> None: + wexpr, args = wired_clexpr_from_logic_exp(exp, output_bits) + circ.add_clexpr(wexpr, args, **kwargs) diff --git a/pytket/tests/clexpr_test.py b/pytket/tests/clexpr_test.py index 8171288e9e..a9e81bca21 100644 --- a/pytket/tests/clexpr_test.py +++ b/pytket/tests/clexpr_test.py @@ -235,3 +235,23 @@ def test_circbox() -> None: c2 = c1.copy() c2.flatten_registers() assert c1 == c2 + + +def test_add_logicexp_as_clexpr() -> None: + c = Circuit() + a_reg = c.add_c_register("a", 3) + b_reg = c.add_c_register("b", 3) + c_reg = c.add_c_register("c", 3) + c.add_clexpr_from_logicexp(a_reg | b_reg, c_reg.to_list()) + qasm = circuit_to_qasm_str(c, header="hqslib1") + assert ( + qasm + == """OPENQASM 2.0; +include "hqslib1.inc"; + +creg a[3]; +creg b[3]; +creg c[3]; +c = (a | b); +""" + )