diff --git a/tket2-py/src/circuit.rs b/tket2-py/src/circuit.rs index faa8463f..2f9167db 100644 --- a/tket2-py/src/circuit.rs +++ b/tket2-py/src/circuit.rs @@ -10,6 +10,37 @@ use tket2::passes::CircuitChunks; use tket2::rewrite::CircuitRewrite; use tket_json_rs::circuit_json::SerialCircuit; +/// The module definition +pub fn module(py: Python) -> PyResult<&PyModule> { + let m = PyModule::new(py, "_circuit")?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + + m.add_function(wrap_pyfunction!(validate_hugr, m)?)?; + m.add_function(wrap_pyfunction!(to_hugr_dot, m)?)?; + m.add_function(wrap_pyfunction!(to_hugr, m)?)?; + m.add_function(wrap_pyfunction!(chunks, m)?)?; + + m.add("HugrError", py.get_type::())?; + m.add("BuildError", py.get_type::())?; + m.add( + "ValidationError", + py.get_type::(), + )?; + m.add( + "HUGRSerializationError", + py.get_type::(), + )?; + m.add( + "OpConvertError", + py.get_type::(), + )?; + + Ok(m) +} + /// Apply a fallible function expecting a hugr on a pytket circuit. pub fn try_with_hugr(circ: Py, f: F) -> PyResult where @@ -79,33 +110,3 @@ impl T2Circuit { rw.apply(&mut self.0).expect("Apply error."); } } -/// circuit module -pub fn add_circuit_module(py: Python, parent: &PyModule) -> PyResult<()> { - let m = PyModule::new(py, "circuit")?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - - m.add_function(wrap_pyfunction!(validate_hugr, m)?)?; - m.add_function(wrap_pyfunction!(to_hugr_dot, m)?)?; - m.add_function(wrap_pyfunction!(to_hugr, m)?)?; - m.add_function(wrap_pyfunction!(chunks, m)?)?; - - m.add("HugrError", py.get_type::())?; - m.add("BuildError", py.get_type::())?; - m.add( - "ValidationError", - py.get_type::(), - )?; - m.add( - "HUGRSerializationError", - py.get_type::(), - )?; - m.add( - "OpConvertError", - py.get_type::(), - )?; - - parent.add_submodule(m) -} diff --git a/tket2-py/src/lib.rs b/tket2-py/src/lib.rs index 315eaae5..2245220f 100644 --- a/tket2-py/src/lib.rs +++ b/tket2-py/src/lib.rs @@ -3,94 +3,32 @@ mod circuit; mod optimiser; -mod pass; +mod passes; +mod pattern; -use circuit::{add_circuit_module, to_hugr, T2Circuit}; -use optimiser::add_optimiser_module; -use pass::add_pass_module; - -use hugr::Hugr; use pyo3::prelude::*; -use tket2::portmatching::pyo3::PyPatternMatch; -use tket2::portmatching::{CircuitPattern, PatternMatcher}; -use tket2::rewrite::CircuitRewrite; - -#[derive(Clone)] -#[pyclass] -/// A rewrite rule defined by a left hand side and right hand side of an equation. -pub struct Rule(pub [Hugr; 2]); - -#[pymethods] -impl Rule { - #[new] - fn new_rule(l: PyObject, r: PyObject) -> PyResult { - let l = to_hugr(l)?; - let r = to_hugr(r)?; - - Ok(Rule([l, r])) - } -} -#[pyclass] -struct RuleMatcher { - matcher: PatternMatcher, - rights: Vec, -} - -#[pymethods] -impl RuleMatcher { - #[new] - pub fn from_rules(rules: Vec) -> PyResult { - let (lefts, rights): (Vec<_>, Vec<_>) = - rules.into_iter().map(|Rule([l, r])| (l, r)).unzip(); - let patterns: Result, _> = - lefts.iter().map(CircuitPattern::try_from_circuit).collect(); - let matcher = PatternMatcher::from_patterns(patterns?); - - Ok(Self { matcher, rights }) - } - - pub fn find_match(&self, target: &T2Circuit) -> PyResult> { - let h = &target.0; - let p_match = self.matcher.find_matches_iter(h).next(); - if let Some(m) = p_match { - let py_match = PyPatternMatch::try_from_rust(m, h, &self.matcher)?; - let r = self.rights.get(py_match.pattern_id).unwrap().clone(); - let rw = py_match.to_rewrite(h, r)?; - Ok(Some(rw)) - } else { - Ok(None) - } - } -} /// The Python bindings to TKET2. #[pymodule] #[pyo3(name = "tket2")] fn tket2_py(py: Python, m: &PyModule) -> PyResult<()> { - add_circuit_module(py, m)?; - add_pattern_module(py, m)?; - add_pass_module(py, m)?; - add_optimiser_module(py, m)?; + add_submodule(py, m, circuit::module(py)?)?; + add_submodule(py, m, optimiser::module(py)?)?; + add_submodule(py, m, passes::module(py)?)?; + add_submodule(py, m, pattern::module(py)?)?; Ok(()) } -/// portmatching module -fn add_pattern_module(py: Python, parent: &PyModule) -> PyResult<()> { - let m = PyModule::new(py, "pattern")?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - - m.add( - "InvalidPatternError", - py.get_type::(), - )?; - m.add( - "InvalidReplacementError", - py.get_type::(), - )?; - - parent.add_submodule(m) +fn add_submodule(py: Python, parent: &PyModule, submodule: &PyModule) -> PyResult<()> { + parent.add_submodule(submodule)?; + + // Add submodule to sys.modules. + // This is required to be able to do `from parent.submodule import ...`. + // + // See [https://github.com/PyO3/pyo3/issues/759] + let parent_name = parent.name()?; + let submodule_name = submodule.name()?; + let modules = py.import("sys")?.getattr("modules")?; + modules.set_item(format!("{parent_name}.{submodule_name}"), submodule)?; + Ok(()) } diff --git a/tket2-py/src/optimiser.rs b/tket2-py/src/optimiser.rs index af31ec52..3f1b4bfd 100644 --- a/tket2-py/src/optimiser.rs +++ b/tket2-py/src/optimiser.rs @@ -9,12 +9,11 @@ use tket2::optimiser::{DefaultTasoOptimiser, TasoLogger}; use crate::circuit::update_hugr; -/// The circuit optimisation module. -pub fn add_optimiser_module(py: Python, parent: &PyModule) -> PyResult<()> { - let m = PyModule::new(py, "optimiser")?; +/// The module definition +pub fn module(py: Python) -> PyResult<&PyModule> { + let m = PyModule::new(py, "_optimiser")?; m.add_class::()?; - - parent.add_submodule(m) + Ok(m) } /// Wrapped [`DefaultTasoOptimiser`]. diff --git a/tket2-py/src/pass.rs b/tket2-py/src/passes.rs similarity index 95% rename from tket2-py/src/pass.rs rename to tket2-py/src/passes.rs index 7cbc00a6..bd3ce2fb 100644 --- a/tket2-py/src/pass.rs +++ b/tket2-py/src/passes.rs @@ -9,6 +9,21 @@ use crate::{ optimiser::PyTasoOptimiser, }; +/// The module definition +/// +/// This module is re-exported from the python module with the same name. +pub fn module(py: Python) -> PyResult<&PyModule> { + let m = PyModule::new(py, "_passes")?; + m.add_function(wrap_pyfunction!(greedy_depth_reduce, m)?)?; + m.add_function(wrap_pyfunction!(taso_optimise, m)?)?; + m.add_class::()?; + m.add( + "PullForwardError", + py.get_type::(), + )?; + Ok(m) +} + #[pyfunction] fn greedy_depth_reduce(py_c: PyObject) -> PyResult<(PyObject, u32)> { try_with_hugr(py_c, |mut h| { @@ -119,16 +134,3 @@ fn taso_optimise( PyResult::Ok(circ) }) } - -pub(crate) fn add_pass_module(py: Python, parent: &PyModule) -> PyResult<()> { - let m = PyModule::new(py, "passes")?; - m.add_function(wrap_pyfunction!(greedy_depth_reduce, m)?)?; - m.add_function(wrap_pyfunction!(taso_optimise, m)?)?; - m.add_class::()?; - m.add( - "PullForwardError", - py.get_type::(), - )?; - parent.add_submodule(m)?; - Ok(()) -} diff --git a/tket2-py/src/pattern.rs b/tket2-py/src/pattern.rs new file mode 100644 index 00000000..52a2ed61 --- /dev/null +++ b/tket2-py/src/pattern.rs @@ -0,0 +1,78 @@ +//! + +use crate::circuit::{to_hugr, T2Circuit}; + +use hugr::Hugr; +use pyo3::prelude::*; +use tket2::portmatching::pyo3::PyPatternMatch; +use tket2::portmatching::{CircuitPattern, PatternMatcher}; +use tket2::rewrite::CircuitRewrite; + +/// The module definition +pub fn module(py: Python) -> PyResult<&PyModule> { + let m = PyModule::new(py, "_pattern")?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + + m.add( + "InvalidPatternError", + py.get_type::(), + )?; + m.add( + "InvalidReplacementError", + py.get_type::(), + )?; + + Ok(m) +} + +#[derive(Clone)] +#[pyclass] +/// A rewrite rule defined by a left hand side and right hand side of an equation. +pub struct Rule(pub [Hugr; 2]); + +#[pymethods] +impl Rule { + #[new] + fn new_rule(l: PyObject, r: PyObject) -> PyResult { + let l = to_hugr(l)?; + let r = to_hugr(r)?; + + Ok(Rule([l, r])) + } +} +#[pyclass] +struct RuleMatcher { + matcher: PatternMatcher, + rights: Vec, +} + +#[pymethods] +impl RuleMatcher { + #[new] + pub fn from_rules(rules: Vec) -> PyResult { + let (lefts, rights): (Vec<_>, Vec<_>) = + rules.into_iter().map(|Rule([l, r])| (l, r)).unzip(); + let patterns: Result, _> = + lefts.iter().map(CircuitPattern::try_from_circuit).collect(); + let matcher = PatternMatcher::from_patterns(patterns?); + + Ok(Self { matcher, rights }) + } + + pub fn find_match(&self, target: &T2Circuit) -> PyResult> { + let h = &target.0; + let p_match = self.matcher.find_matches_iter(h).next(); + if let Some(m) = p_match { + let py_match = PyPatternMatch::try_from_rust(m, h, &self.matcher)?; + let r = self.rights.get(py_match.pattern_id).unwrap().clone(); + let rw = py_match.to_rewrite(h, r)?; + Ok(Some(rw)) + } else { + Ok(None) + } + } +} diff --git a/tket2-py/test/test_bindings.py b/tket2-py/test/test_bindings.py index e06cf840..8c765346 100644 --- a/tket2-py/test/test_bindings.py +++ b/tket2-py/test/test_bindings.py @@ -1,17 +1,16 @@ from dataclasses import dataclass -from tket2 import passes, circuit, pattern - from pytket.circuit import Circuit -# TODO clean up after fixing module structure #169 -Rule, RuleMatcher = pattern.Rule, pattern.RuleMatcher -T2Circuit = circuit.T2Circuit +from tket2 import circuit +from tket2.passes import greedy_depth_reduce +from tket2.circuit import T2Circuit +from tket2.pattern import Rule, RuleMatcher @dataclass class DepthOptimisePass: def apply(self, circ: Circuit) -> Circuit: - (circ, n_moves) = passes.greedy_depth_reduce(circ) + (circ, n_moves) = greedy_depth_reduce(circ) return circ @@ -54,238 +53,18 @@ def test_cx_rule(): def test_multiple_rules(): - circuit = T2Circuit(Circuit(3).CX(0, 1).H(0).H(1).H(2).Z(0).H(0).H(1).H(2)) + circ = T2Circuit(Circuit(3).CX(0, 1).H(0).H(1).H(2).Z(0).H(0).H(1).H(2)) rule1 = Rule(Circuit(1).H(0).Z(0).H(0), Circuit(1).X(0)) rule2 = Rule(Circuit(1).H(0).H(0), Circuit(1)) matcher = RuleMatcher([rule1, rule2]) match_count = 0 - while match := matcher.find_match(circuit): + while match := matcher.find_match(circ): match_count += 1 - circuit.apply_match(match) + circ.apply_match(match) assert match_count == 3 - out = circuit.finish() + out = circ.finish() assert out == Circuit(3).CX(0, 1).X(0) - - -# from dataclasses import dataclass -# from typing import Callable, Iterable -# import time -# from functools import wraps - -# import pytest -# from tket2 import ( -# RsCircuit, -# WireType, -# RsOpType, -# Subgraph, -# CircuitRewrite, -# greedy_pattern_rewrite, -# remove_redundancies, -# Direction, -# greedy_iter_rewrite, -# Rational, -# Quaternion, -# Angle, -# check_soundness, -# CustomOp, -# Signature, -# decompose_custom_pass, -# count_pycustom, -# ) -# from tket2.custom_base import CustomOpBase - -# from pytket import Circuit, OpType, Qubit - - -# def simple_rs(op): -# c = RsCircuit() -# v = c.add_vertex_with_edges( -# op, -# [c.new_input(WireType.Qubit)], -# [c.new_output(WireType.Qubit)], -# ) -# check_soundness(c) -# return c - - -# def test_conversion(): -# c = Circuit(2).H(0).CX(0, 1) -# rc = RsCircuit.from_tket1(c) -# assert len(rc.to_tket1().get_commands()) == 2 - -# assert rc.dot_string() - - -# def test_apply_rewrite(): -# c = simple_rs(RsOpType.H) -# assert c.edge_endpoints(0) == (0, 2) -# assert c.edge_at_port(2, 0, Direction.Outgoing) == 1 -# c2 = simple_rs(RsOpType.Reset) - -# c.apply_rewrite(CircuitRewrite(Subgraph({2}, [0], [1]), c2, 0.0)) -# c.defrag() # needed for exact equality check -# print(c.dot_string()) -# print(c2.dot_string()) -# assert c == c2 -# assert c.remove_node(2) == RsOpType.Reset -# assert c.remove_node(2) == None - - -# @pytest.fixture() -# def cx_circ() -> RsCircuit: -# return RsCircuit.from_tket1(Circuit(2).CX(0, 1).CX(0, 1)) - - -# def _noop_circ() -> RsCircuit: -# c = Circuit(2) -# c.add_gate(OpType.noop, [0]) -# c.add_gate(OpType.noop, [1]) -# return RsCircuit.from_tket1(c) - - -# @pytest.fixture() -# def noop_circ() -> RsCircuit: -# return _noop_circ() - - -# def timed(f: Callable): -# @wraps(f) -# def wrapper(*args, **kwargs): -# start = time.time() -# out = f(*args, **kwargs) -# print(time.time() - start) -# return out - -# return wrapper - - -# def cx_pair_searcher(circ: RsCircuit) -> Iterable[CircuitRewrite]: -# for nid in circ.node_indices(): -# if circ.node_op(nid) != RsOpType.CX: -# continue -# sucs = circ.node_edges(nid, Direction.Outgoing) - -# if len(sucs) != 2: -# continue - -# _, target0 = circ.edge_endpoints(sucs[0]) -# _, target1 = circ.edge_endpoints(sucs[1]) -# if target0 != target1: -# # same node -# continue -# next_nid = target0 -# if circ.node_op(next_nid) != RsOpType.CX: -# continue - -# s0p = circ.port_of_edge(nid, sucs[0], Direction.Outgoing) -# t0p = circ.port_of_edge(next_nid, sucs[0], Direction.Incoming) - -# s1p = circ.port_of_edge(nid, sucs[1], Direction.Outgoing) -# t1p = circ.port_of_edge(next_nid, sucs[1], Direction.Incoming) -# # check ports match -# if s0p == t0p and s1p == t1p: -# in_edges = circ.node_edges(nid, Direction.Incoming) -# out_edges = circ.node_edges(next_nid, Direction.Outgoing) -# yield CircuitRewrite( -# Subgraph({nid, next_nid}, in_edges, out_edges), _noop_circ(), 0.0 -# ) - - -# def test_cx_rewriters(cx_circ, noop_circ): -# c = Circuit(2).H(0).CX(1, 0).CX(1, 0) -# rc = RsCircuit.from_tket1(c) -# assert rc.node_edges(3, Direction.Incoming) == [3, 4] -# assert rc.neighbours(4, Direction.Outgoing) == [1, 1] -# check_soundness(rc) -# # each one of these ways of applying this rewrite should take longer than -# # the one before - -# c1 = timed(greedy_pattern_rewrite)(rc, cx_circ, lambda x: noop_circ) - -# c2 = timed(greedy_pattern_rewrite)( -# rc, cx_circ, lambda x: noop_circ, lambda ni, op: op == cx_circ.node_op(ni) -# ) - -# c3 = timed(greedy_iter_rewrite)(rc, cx_pair_searcher) - -# correct = Circuit(2).H(0) -# correct.add_gate(OpType.noop, [1]) -# correct.add_gate(OpType.noop, [0]) -# for c in (c1, c2, c3): -# check_soundness(c) -# assert c.to_tket1().get_commands() == correct.get_commands() - - -# def test_equality(): -# bell_circ = lambda: RsCircuit.from_tket1(Circuit(2).H(0).CX(0, 1)) -# assert bell_circ() == bell_circ() -# assert bell_circ() != RsCircuit.from_tket1(Circuit(2).H(0)) - - -# def test_auto_convert(): -# c = Circuit(2).CX(0, 1).CX(0, 1).Rx(2, 1) -# c2 = remove_redundancies(c) -# correct = Circuit(2).Rx(2, 1) - -# assert c2 == correct - - -# def test_const(): -# rat = Rational(1, 2) -# quat = Quaternion([0.1, 0.2, 0.3, 0.4]) -# ang1 = Angle.rational(rat) -# ang2 = Angle.float(2.3) - -# c = RsCircuit() -# for const in (True, 2, 4.5, quat, ang1, ang2): -# v = c.add_const(const) -# assert c.get_const(v) == const - -# assert c.get_const(0) == c.get_const(1) == None -# pass - - -# @dataclass -# class CustomBridge(CustomOpBase): -# flip: bool - -# def signature(self) -> Signature: -# return Signature([WireType.Qubit] * 3, ([], [])) - -# def to_circuit(self) -> RsCircuit: -# c = RsCircuit() - -# for i in range(3): -# c.add_linear_unitid(Qubit("q", [i])) - -# if self.flip: -# c.append(RsOpType.CX, [1, 2]) -# c.append(RsOpType.CX, [0, 1]) -# c.append(RsOpType.CX, [1, 2]) -# c.append(RsOpType.CX, [0, 1]) -# else: -# c.append(RsOpType.CX, [0, 1]) -# c.append(RsOpType.CX, [1, 2]) -# c.append(RsOpType.CX, [0, 1]) -# c.append(RsOpType.CX, [1, 2]) -# return c - - -# @pytest.mark.parametrize("flip", (True, False)) -# def test_custom(flip): -# c = RsCircuit() -# for i in range(3): -# c.add_linear_unitid(Qubit("q", [i])) -# op = CustomOp(CustomBridge(flip)) -# c.append(op, [0, 1, 2]) -# assert count_pycustom(c) == 1 - -# c, success = decompose_custom_pass(c) -# check_soundness(c) -# assert success -# assert c.node_count() == 6 -# assert count_pycustom(c) == 0 diff --git a/tket2-py/test/test_optimiser.py b/tket2-py/test/test_optimiser.py index ed49e802..eeab2ce7 100644 --- a/tket2-py/test/test_optimiser.py +++ b/tket2-py/test/test_optimiser.py @@ -1,11 +1,11 @@ from pytket import Circuit -from tket2 import optimiser +from tket2.optimiser import TasoOptimiser def test_simple_optimiser(): """a simple circuit matching test""" c = Circuit(3).CX(0, 1).CX(0, 1).CX(1, 2) - opt = optimiser.TasoOptimiser.compile_eccs("test_files/cx_cx_eccs.json") + opt = TasoOptimiser.compile_eccs("test_files/cx_cx_eccs.json") # optimise for 1s cc = opt.optimise(c, 3) diff --git a/tket2-py/test/test_portmatching.py b/tket2-py/test/test_portmatching.py index d55cf9d4..36864066 100644 --- a/tket2-py/test/test_portmatching.py +++ b/tket2-py/test/test_portmatching.py @@ -1,24 +1,24 @@ from pytket import Circuit from pytket.qasm import circuit_from_qasm -from tket2 import pattern +from tket2.pattern import CircuitPattern, PatternMatcher def test_simple_matching(): """a simple circuit matching test""" c = Circuit(2).CX(0, 1).H(1).CX(0, 1) - p1 = pattern.CircuitPattern(Circuit(2).CX(0, 1).H(1)) - p2 = pattern.CircuitPattern(Circuit(2).H(0).CX(1, 0)) + p1 = CircuitPattern(Circuit(2).CX(0, 1).H(1)) + p2 = CircuitPattern(Circuit(2).H(0).CX(1, 0)) - matcher = pattern.PatternMatcher(iter([p1, p2])) + matcher = PatternMatcher(iter([p1, p2])) assert len(matcher.find_matches(c)) == 2 def test_non_convex_pattern(): """two-qubit circuits can't match three-qb ones""" - p1 = pattern.CircuitPattern(Circuit(3).CX(0, 1).CX(1, 2)) - matcher = pattern.PatternMatcher(iter([p1])) + p1 = CircuitPattern(Circuit(3).CX(0, 1).CX(1, 2)) + matcher = PatternMatcher(iter([p1])) c = Circuit(2).CX(0, 1).CX(1, 0) assert len(matcher.find_matches(c)) == 0 @@ -34,11 +34,11 @@ def test_larger_matching(): """a larger crafted circuit with matches WIP""" c = circuit_from_qasm("test_files/simple.qasm") - p1 = pattern.CircuitPattern(Circuit(2).CX(0, 1).H(1)) - p2 = pattern.CircuitPattern(Circuit(2).H(0).CX(1, 0)) - p3 = pattern.CircuitPattern(Circuit(2).CX(0, 1).CX(1, 0)) - p4 = pattern.CircuitPattern(Circuit(3).CX(0, 1).CX(1, 2)) + p1 = CircuitPattern(Circuit(2).CX(0, 1).H(1)) + p2 = CircuitPattern(Circuit(2).H(0).CX(1, 0)) + p3 = CircuitPattern(Circuit(2).CX(0, 1).CX(1, 0)) + p4 = CircuitPattern(Circuit(3).CX(0, 1).CX(1, 2)) - matcher = pattern.PatternMatcher(iter([p1, p2, p3, p4])) + matcher = PatternMatcher(iter([p1, p2, p3, p4])) assert len(matcher.find_matches(c)) == 6 diff --git a/tket2-py/tket2/__init__.py b/tket2-py/tket2/__init__.py index 8bed83d8..918ca898 100644 --- a/tket2-py/tket2/__init__.py +++ b/tket2-py/tket2/__init__.py @@ -1,5 +1,3 @@ -from .tket2 import * # noqa: F403,F405 +from . import passes, circuit, optimiser, pattern -__doc__ = tket2.__doc__ # noqa: F405 -if hasattr(tket2, "__all__"): # noqa: F405 - __all__ = tket2.__all__ # noqa: F405 +__all__ = [circuit, optimiser, passes, pattern] diff --git a/tket2-py/tket2/circuit.py b/tket2-py/tket2/circuit.py new file mode 100644 index 00000000..fd15c81e --- /dev/null +++ b/tket2-py/tket2/circuit.py @@ -0,0 +1,5 @@ +# Re-export native bindings +from .tket2._circuit import * # noqa: F403 +from .tket2 import _circuit + +__all__ = _circuit.__all__ diff --git a/tket2-py/tket2/custom_base.py b/tket2-py/tket2/custom_base.py deleted file mode 100644 index 3851edaf..00000000 --- a/tket2-py/tket2/custom_base.py +++ /dev/null @@ -1,12 +0,0 @@ -# from abc import ABC, abstractmethod -# from tket2 import RsCircuit, Signature - - -# class CustomOpBase(ABC): -# @abstractmethod -# def signature(self) -> Signature: -# ... - -# @abstractmethod -# def to_circuit(self) -> RsCircuit: -# ... diff --git a/tket2-py/tket2/optimiser.py b/tket2-py/tket2/optimiser.py new file mode 100644 index 00000000..e44d9371 --- /dev/null +++ b/tket2-py/tket2/optimiser.py @@ -0,0 +1,5 @@ +# Re-export native bindings +from .tket2._optimiser import * # noqa: F403 +from .tket2 import _optimiser + +__all__ = _optimiser.__all__ diff --git a/tket2-py/tket2/passes.py b/tket2-py/tket2/passes.py index b1cb76ed..34dc76cb 100644 --- a/tket2-py/tket2/passes.py +++ b/tket2-py/tket2/passes.py @@ -4,7 +4,17 @@ from pytket import Circuit from pytket.passes import CustomPass -from tket2 import passes, optimiser + +from tket2 import optimiser + +# Re-export native bindings +from .tket2._passes import * # noqa: F403 +from .tket2 import _passes + +__all__ = [ + "taso_pass", + *_passes.__all__, +] def taso_pass( @@ -28,7 +38,7 @@ def taso_pass( def apply(circuit: Circuit) -> Circuit: """Apply TASO optimisation to the circuit.""" - return passes.taso_optimise( + return _passes.taso_optimise( circuit, opt, max_threads, diff --git a/tket2-py/tket2/pattern.py b/tket2-py/tket2/pattern.py new file mode 100644 index 00000000..0dc0ea3f --- /dev/null +++ b/tket2-py/tket2/pattern.py @@ -0,0 +1,5 @@ +# Re-export native bindings +from .tket2._pattern import * # noqa: F403 +from .tket2 import _pattern + +__all__ = _pattern.__all__