From e5c0abfe92337f2c92cb3e23c9e2633db5cf24f6 Mon Sep 17 00:00:00 2001 From: peachnuts Date: Thu, 30 Nov 2023 14:33:11 -0800 Subject: [PATCH 1/9] add reset operation --- bqskit/ir/gates/__init__.py | 4 +++- bqskit/ir/gates/reset.py | 26 ++++++++++++++++++++++++++ bqskit/ir/lang/qasm2/visitor.py | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 bqskit/ir/gates/reset.py diff --git a/bqskit/ir/gates/__init__.py b/bqskit/ir/gates/__init__.py index b6a2c7956..56c963f5a 100644 --- a/bqskit/ir/gates/__init__.py +++ b/bqskit/ir/gates/__init__.py @@ -112,6 +112,7 @@ CircuitGate MeasurementPlaceholder + Reset BarrierPlaceholder .. rubric:: Gate Base Classes @@ -141,6 +142,7 @@ from bqskit.ir.gates.constantgate import ConstantGate from bqskit.ir.gates.generalgate import GeneralGate from bqskit.ir.gates.measure import MeasurementPlaceholder +from bqskit.ir.gates.reset import Reset from bqskit.ir.gates.parameterized import * # noqa from bqskit.ir.gates.parameterized import __all__ as parameterized_all from bqskit.ir.gates.qubitgate import QubitGate @@ -150,7 +152,7 @@ __all__ = composed_all + constant_all + parameterized_all __all__ += ['ComposedGate', 'ConstantGate'] __all__ += ['QubitGate', 'QutritGate', 'QuditGate'] -__all__ += ['CircuitGate', 'MeasurementPlaceholder', 'BarrierPlaceholder'] +__all__ += ['CircuitGate', 'MeasurementPlaceholder', 'Reset', 'BarrierPlaceholder'] __all__ += ['GeneralGate'] # TODO: Implement the rest of the gates in: diff --git a/bqskit/ir/gates/reset.py b/bqskit/ir/gates/reset.py new file mode 100644 index 000000000..ce70e0c11 --- /dev/null +++ b/bqskit/ir/gates/reset.py @@ -0,0 +1,26 @@ +"""This module implements the Reset class.""" +from __future__ import annotations + +from bqskit.ir.gates.constantgate import ConstantGate +from bqskit.ir.gates.qubitgate import QubitGate +from bqskit.qis.unitary.unitary import RealVector +from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix + +class Reset(QubitGate, ConstantGate): + """ + Construct a Reset. + + Args: + reset (int): the index of the qubit that has reset. + """ + + def __init__(self): + self._num_qudits = 1 + self._qasm_name = 'reset' + + def get_unitary(self, params: RealVector = []) -> UnitaryMatrix: + raise RuntimeError( + 'Cannot compute unitary for a reset.', + ) + + diff --git a/bqskit/ir/lang/qasm2/visitor.py b/bqskit/ir/lang/qasm2/visitor.py index 4f7c289ba..8ff6fecc7 100644 --- a/bqskit/ir/lang/qasm2/visitor.py +++ b/bqskit/ir/lang/qasm2/visitor.py @@ -50,6 +50,7 @@ from bqskit.ir.gates.constant.z import ZGate from bqskit.ir.gates.constant.zz import ZZGate from bqskit.ir.gates.measure import MeasurementPlaceholder +from bqskit.ir.gates.reset import Reset from bqskit.ir.gates.parameterized.ccp import CCPGate from bqskit.ir.gates.parameterized.cp import CPGate from bqskit.ir.gates.parameterized.crx import CRXGate @@ -261,6 +262,9 @@ def fill_gate_defs(self) -> None: self.gate_defs['rccx'] = GateDef('rccx', 0, 3, RCCXGate()) self.gate_defs['rc3x'] = GateDef('rc3x', 0, 4, RC3XGate()) + # reset + self.gate_defs['reset'] = GateDef('reset', 0, 1, Reset()) + def qreg(self, tree: lark.Tree) -> None: """Qubit register node visitor.""" reg_name = tree.children[0] @@ -651,8 +655,33 @@ def measure(self, tree: lark.Tree) -> None: ) def reset(self, tree: lark.Tree) -> None: - """Reset statement node visitor.""" - raise LangException('BQSKit currently does not support resets.') + """reset node visitor.""" + params = [] + qlist = tree.children[-1] + location = CircuitLocation(self.convert_qubit_ids_to_indices(qlist)) + # Parse gate object + gate_name = tree.data + if gate_name in self.gate_defs: + gate_def: GateDef | CustomGateDef = self.gate_defs[gate_name] + elif gate_name in self.custom_gate_defs: + gate_def = self.custom_gate_defs[gate_name] + else: + raise LangException('Unrecognized gate: %s.' % gate_name) + + if len(params) != gate_def.num_params: + raise LangException( + 'Expected %d params got %d params for gate %s.' + % (gate_def.num_params, len(params), gate_name), + ) + + if len(location) != gate_def.num_vars: + raise LangException( + 'Gate acts on %d qubits, got %d qubit variables.' + % (gate_def.num_vars, len(location)), + ) + + # Build operation and add to circuit + self.op_list.append(gate_def.build_op(location, params)) def convert_qubit_ids_to_indices(self, qlist: lark.Tree) -> list[int]: if qlist.data == 'anylist': From 2d4053b2f2222e9cb14ea801d628c2ad25339cea Mon Sep 17 00:00:00 2001 From: peachnuts Date: Mon, 4 Dec 2023 11:41:47 -0800 Subject: [PATCH 2/9] add support for mid-circuit measurement --- bqskit/ir/lang/qasm2/visitor.py | 48 ++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/bqskit/ir/lang/qasm2/visitor.py b/bqskit/ir/lang/qasm2/visitor.py index 8ff6fecc7..05e0441cf 100644 --- a/bqskit/ir/lang/qasm2/visitor.py +++ b/bqskit/ir/lang/qasm2/visitor.py @@ -181,12 +181,6 @@ def get_circuit(self) -> Circuit: circuit = Circuit(num_qubits) circuit.extend(self.op_list) - # Add measurements - if len(self.measurements) > 0: - cregs = cast(List[Tuple[str, int]], self.classical_regs) - mph = MeasurementPlaceholder(cregs, self.measurements) - circuit.append_gate(mph, list(self.measurements.keys())) - return circuit def fill_gate_defs(self) -> None: @@ -301,13 +295,6 @@ def gate(self, tree: lark.Tree) -> None: qlist = tree.children[-1] location = CircuitLocation(self.convert_qubit_ids_to_indices(qlist)) - if any(q in self.measurements for q in location): - raise LangException( - 'BQSKit currently does not support mid-circuit measurements.' - ' Unable to apply a gate on the same qubit where a measurement' - ' has been previously made.', - ) - # Parse gate object gate_name = str(tree.children[0]) if gate_name in self.gate_defs: @@ -654,11 +641,46 @@ def measure(self, tree: lark.Tree) -> None: 'measured to a single classical bit.', ) + + for key, item in enumerate(self.measurements.items()): + cregs = cast(List[Tuple[str, int]], self.classical_regs) + mph = MeasurementPlaceholder(cregs, {key: item}) + self.gate_defs['measure'] = GateDef('measure', 0, 1, mph) + + params = [] + qlist = tree.children[0] + location = CircuitLocation(self.convert_qubit_ids_to_indices(qlist)) + + # Parse gate object + gate_name = tree.data + if gate_name in self.gate_defs: + gate_def: GateDef | CustomGateDef = self.gate_defs[gate_name] + elif gate_name in self.custom_gate_defs: + gate_def = self.custom_gate_defs[gate_name] + else: + raise LangException('Unrecognized gate: %s.' % gate_name) + + if len(params) != gate_def.num_params: + raise LangException( + 'Expected %d params got %d params for gate %s.' + % (gate_def.num_params, len(params), gate_name), + ) + + if len(location) != gate_def.num_vars: + raise LangException( + 'Gate acts on %d qubits, got %d qubit variables.' + % (gate_def.num_vars, len(location)), + ) + + # Build operation and add to circuit + self.op_list.append(gate_def.build_op(location, params)) + def reset(self, tree: lark.Tree) -> None: """reset node visitor.""" params = [] qlist = tree.children[-1] location = CircuitLocation(self.convert_qubit_ids_to_indices(qlist)) + # Parse gate object gate_name = tree.data if gate_name in self.gate_defs: From dcc2bbbc9fef1cc43b6991b585bf0a1efc30132e Mon Sep 17 00:00:00 2001 From: peachnuts Date: Mon, 4 Dec 2023 14:39:14 -0800 Subject: [PATCH 3/9] add MMR partition support --- bqskit/passes/partitioning/quick.py | 101 ++++++++++++++++++++++++++- bqskit/passes/partitioning/single.py | 5 +- 2 files changed, 101 insertions(+), 5 deletions(-) diff --git a/bqskit/passes/partitioning/quick.py b/bqskit/passes/partitioning/quick.py index 4c9d2e0e4..b5322c1ec 100644 --- a/bqskit/passes/partitioning/quick.py +++ b/bqskit/passes/partitioning/quick.py @@ -13,6 +13,8 @@ from bqskit.ir.location import CircuitLocation from bqskit.ir.point import CircuitPoint from bqskit.utils.typing import is_integer +from bqskit.ir.gates import MeasurementPlaceholder +from bqskit.ir.gates import Reset _logger = logging.getLogger(__name__) @@ -112,12 +114,12 @@ def process_pending_bins() -> None: loc = list(sorted(bin.qudits)) # Merge previously placed blocks if possible - merging = not isinstance(bin, BarrierBin) + merging = not isinstance(bin, (BarrierBin, MeasurementBin, ResetBin)) while merging: merging = False for p in partitioned_circuit.rear: op = partitioned_circuit[p] - if isinstance(op.gate, BarrierPlaceholder): + if isinstance(op.gate, (BarrierPlaceholder, MeasurementPlaceholder, Reset)): # Don't merge through barriers continue qudits = list(op.location) @@ -152,7 +154,7 @@ def process_pending_bins() -> None: partitioned_circuit.append_circuit( subc, loc, - not isinstance(bin, BarrierBin), + not isinstance(bin, (BarrierBin, MeasurementBin, ResetBin)), True, ) for qudit in bin.qudits: @@ -191,6 +193,32 @@ def process_pending_bins() -> None: pending_bins.append(BarrierBin(point, location, circuit)) continue + # Measurement close all overlapping bins + if isinstance(op.gate, MeasurementPlaceholder): + for bin in overlapping_bins: + if close_bin_qudits(bin, location, cycle): + num_closed += 1 + else: + extended = [q for q in location if q not in bin.qudits] + bin.blocked_qudits.update(extended) + + # Track the measurement to restore it in partitioned circuit + pending_bins.append(MeasurementBin(point, location, circuit)) + continue + + # Reset close all overlapping bins + if isinstance(op.gate, Reset): + for bin in overlapping_bins: + if close_bin_qudits(bin, location, cycle): + num_closed += 1 + else: + extended = [q for q in location if q not in bin.qudits] + bin.blocked_qudits.update(extended) + + # Track the reset to restore it in partitioned circuit + pending_bins.append(ResetBin(point, location, circuit)) + continue + # Get all the currently active bins that can have op added to them admissible_bins = [ bin for bin in overlapping_bins @@ -378,3 +406,70 @@ def __init__( # Close the bin for q in location: self.active_qudits.remove(q) + + +class MeasurementBin(Bin): + """A special bin made to mark and preserve measurement location.""" + + def __init__( + self, + point: CircuitPoint, + location: CircuitLocation, + circuit: Circuit, + ) -> None: + """Initialize a MeasurementBin with the point and location of a measurement.""" + super().__init__() + + # Add the measurement + self.add_op(point, location) + + # Barriar bins fill the volume to the next gates + + nexts = circuit.next(point) + ends: dict[int, int | None] = {q: None for q in location} + for p in nexts: + loc = circuit[p].location + for q in loc: + if q in ends and ( + ends[q] is None or ends[q] >= p.cycle): # type: ignore # noqa # short-circuit safety for >= + ends[q] = p.cycle - 1 + + self.ends = ends + + # Close the bin + for q in location: + self.active_qudits.remove(q) + + +class ResetBin(Bin): + """A special bin made to mark and preserve reset location.""" + + def __init__( + self, + point: CircuitPoint, + location: CircuitLocation, + circuit: Circuit, + ) -> None: + """Initialize a reset with the point and location of a reset.""" + super().__init__() + + # Add the reset + self.add_op(point, location) + + # Barriar bins fill the volume to the next gates + + nexts = circuit.next(point) + ends: dict[int, int | None] = {q: None for q in location} + for p in nexts: + loc = circuit[p].location + for q in loc: + if q in ends and ( + ends[q] is None or ends[q] >= p.cycle): # type: ignore # noqa # short-circuit safety for >= + ends[q] = p.cycle - 1 + + self.ends = ends + + # Close the bin + for q in location: + self.active_qudits.remove(q) + diff --git a/bqskit/passes/partitioning/single.py b/bqskit/passes/partitioning/single.py index ce9a431e2..814df3dc4 100644 --- a/bqskit/passes/partitioning/single.py +++ b/bqskit/passes/partitioning/single.py @@ -6,7 +6,8 @@ from bqskit.ir.circuit import Circuit from bqskit.ir.gates.barrier import BarrierPlaceholder from bqskit.ir.region import CircuitRegion - +from bqskit.ir.gates import MeasurementPlaceholder +from bqskit.ir.gates import Reset class GroupSingleQuditGatePass(BasePass): """ @@ -31,7 +32,7 @@ async def run(self, circuit: Circuit, data: PassData) -> None: op = circuit[c, q] if ( op.num_qudits == 1 - and not isinstance(op.gate, BarrierPlaceholder) + and not isinstance(op.gate, (BarrierPlaceholder, MeasurementPlaceholder, Reset)) ): if region_start is None: region_start = c From 4ef7e767717dbce8b33c5501cf175968471441b2 Mon Sep 17 00:00:00 2001 From: peachnuts Date: Mon, 11 Dec 2023 16:28:36 -0800 Subject: [PATCH 4/9] change test --- tests/ir/lang/test_qasm_decode.py | 13 +++++++++++++ tests/ir/lang/test_qasm_encode.py | 14 ++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/tests/ir/lang/test_qasm_decode.py b/tests/ir/lang/test_qasm_decode.py index c912705b6..f6e40e005 100644 --- a/tests/ir/lang/test_qasm_decode.py +++ b/tests/ir/lang/test_qasm_decode.py @@ -11,6 +11,7 @@ from bqskit.ir.gates.circuitgate import CircuitGate from bqskit.ir.gates.constant.cx import CNOTGate from bqskit.ir.gates.measure import MeasurementPlaceholder +from bqskit.ir.gates.reset import Reset from bqskit.ir.gates.parameterized.u1 import U1Gate from bqskit.ir.gates.parameterized.u1q import U1qGate from bqskit.ir.gates.parameterized.u2 import U2Gate @@ -296,6 +297,18 @@ def test_include_simple(self) -> None: assert circuit.get_unitary().get_distance_from(gate_unitary) < 1e-7 +class TestReset: + def test_reset_single(self) -> None: + input = """ + OPENQASM 2.0; + qreg q[1]; + reset q[0]; + """ + circuit = OPENQASM2Language().decode(input) + expected = Reset() + assert circuit[0, 0].gate == expected + + class TestMeasure: def test_measure_single_bit(self) -> None: input = """ diff --git a/tests/ir/lang/test_qasm_encode.py b/tests/ir/lang/test_qasm_encode.py index 182540f39..1a1bb5ed2 100644 --- a/tests/ir/lang/test_qasm_encode.py +++ b/tests/ir/lang/test_qasm_encode.py @@ -3,6 +3,7 @@ from bqskit.ir.circuit import Circuit from bqskit.ir.gates import CNOTGate from bqskit.ir.gates import U3Gate +from bqskit.ir.gates import Reset from bqskit.ir.lang.qasm2 import OPENQASM2Language @@ -41,3 +42,16 @@ def test_nested_circuitgate(self) -> None: qasm = OPENQASM2Language().encode(circuit) parsed_circuit = OPENQASM2Language().decode(qasm) assert parsed_circuit.get_unitary().get_distance_from(in_utry) < 1e-7 + + def test_reset(self) -> None: + circuit = Circuit(1) + circuit.append_gate(Reset(), 0) + qasm = OPENQASM2Language().encode(circuit) + + expected = """ + OPENQASM 2.0; + qreg q[1]; + reset q[0]; + """ + assert qasm == expected + From b52d53b1e0471a69cff036916b8d86c286badb4d Mon Sep 17 00:00:00 2001 From: peachnuts Date: Mon, 11 Dec 2023 17:15:10 -0800 Subject: [PATCH 5/9] fix errors --- tests/ir/lang/test_qasm_encode.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ir/lang/test_qasm_encode.py b/tests/ir/lang/test_qasm_encode.py index 1a1bb5ed2..a621f5209 100644 --- a/tests/ir/lang/test_qasm_encode.py +++ b/tests/ir/lang/test_qasm_encode.py @@ -50,8 +50,8 @@ def test_reset(self) -> None: expected = """ OPENQASM 2.0; + include "qelib1.inc"; qreg q[1]; reset q[0]; """ - assert qasm == expected - + assert qasm.strip() == expected.strip() From 7b791227f0b16e5c17f5611aff35a14ad182b82b Mon Sep 17 00:00:00 2001 From: peachnuts Date: Fri, 15 Dec 2023 15:22:12 -0800 Subject: [PATCH 6/9] add support for reset register --- bqskit/ir/gates/reset.py | 20 +++++++++++--------- bqskit/ir/lang/qasm2/visitor.py | 31 ++++++++++++++++++++++--------- tests/ir/lang/test_qasm_decode.py | 13 ++++++++++++- tests/ir/lang/test_qasm_encode.py | 14 +++++++------- 4 files changed, 52 insertions(+), 26 deletions(-) diff --git a/bqskit/ir/gates/reset.py b/bqskit/ir/gates/reset.py index ce70e0c11..8a4a93833 100644 --- a/bqskit/ir/gates/reset.py +++ b/bqskit/ir/gates/reset.py @@ -1,22 +1,24 @@ """This module implements the Reset class.""" from __future__ import annotations -from bqskit.ir.gates.constantgate import ConstantGate -from bqskit.ir.gates.qubitgate import QubitGate +from bqskit.ir.gate import Gate from bqskit.qis.unitary.unitary import RealVector from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix -class Reset(QubitGate, ConstantGate): - """ - Construct a Reset. +class Reset(Gate): + """Pseudogate to initialize the qudit to |0>.""" - Args: - reset (int): the index of the qubit that has reset. - """ + def __init__(self, radix: int = 2) -> None: + """ + Construct a Reset. - def __init__(self): + Args: + radix (int): the dimension of the qudit. (Default: 2) + """ self._num_qudits = 1 self._qasm_name = 'reset' + self._radixes = tuple([radix]) + self._num_params = 0 def get_unitary(self, params: RealVector = []) -> UnitaryMatrix: raise RuntimeError( diff --git a/bqskit/ir/lang/qasm2/visitor.py b/bqskit/ir/lang/qasm2/visitor.py index 8ff6fecc7..a55ac9829 100644 --- a/bqskit/ir/lang/qasm2/visitor.py +++ b/bqskit/ir/lang/qasm2/visitor.py @@ -658,8 +658,6 @@ def reset(self, tree: lark.Tree) -> None: """reset node visitor.""" params = [] qlist = tree.children[-1] - location = CircuitLocation(self.convert_qubit_ids_to_indices(qlist)) - # Parse gate object gate_name = tree.data if gate_name in self.gate_defs: gate_def: GateDef | CustomGateDef = self.gate_defs[gate_name] @@ -674,14 +672,29 @@ def reset(self, tree: lark.Tree) -> None: % (gate_def.num_params, len(params), gate_name), ) - if len(location) != gate_def.num_vars: - raise LangException( - 'Gate acts on %d qubits, got %d qubit variables.' - % (gate_def.num_vars, len(location)), - ) + if len(qlist.children) == 2: + location = CircuitLocation(self.convert_qubit_ids_to_indices(qlist)) + # Parse gate object + if len(location) != gate_def.num_vars: + raise LangException( + 'Gate acts on %d qubits, got %d qubit variables.' + % (gate_def.num_vars, len(location)), + ) + + # Build operation and add to circuit + self.op_list.append(gate_def.build_op(location, params)) + else: + locations = [CircuitLocation(i) for i in range(self.qubit_regs[0][1])] + for location in locations: + if len(location) != gate_def.num_vars: + raise LangException( + 'Gate acts on %d qubits, got %d qubit variables.' + % (gate_def.num_vars, len(location)), + ) + + # Build operation and add to circuit + self.op_list.append(gate_def.build_op(location, params)) - # Build operation and add to circuit - self.op_list.append(gate_def.build_op(location, params)) def convert_qubit_ids_to_indices(self, qlist: lark.Tree) -> list[int]: if qlist.data == 'anylist': diff --git a/tests/ir/lang/test_qasm_decode.py b/tests/ir/lang/test_qasm_decode.py index f6e40e005..7227ea1bc 100644 --- a/tests/ir/lang/test_qasm_decode.py +++ b/tests/ir/lang/test_qasm_decode.py @@ -298,7 +298,7 @@ def test_include_simple(self) -> None: class TestReset: - def test_reset_single(self) -> None: + def test_reset_single_qubit(self) -> None: input = """ OPENQASM 2.0; qreg q[1]; @@ -308,6 +308,17 @@ def test_reset_single(self) -> None: expected = Reset() assert circuit[0, 0].gate == expected + def test_reset_register(self) -> None: + input = """ + OPENQASM 2.0; + qreg q[2]; + reset q; + """ + circuit = OPENQASM2Language().decode(input) + expected = Reset() + assert circuit[0, 0].gate == expected + assert circuit[0, 1].gate == expected + class TestMeasure: def test_measure_single_bit(self) -> None: diff --git a/tests/ir/lang/test_qasm_encode.py b/tests/ir/lang/test_qasm_encode.py index a621f5209..061a035c5 100644 --- a/tests/ir/lang/test_qasm_encode.py +++ b/tests/ir/lang/test_qasm_encode.py @@ -47,11 +47,11 @@ def test_reset(self) -> None: circuit = Circuit(1) circuit.append_gate(Reset(), 0) qasm = OPENQASM2Language().encode(circuit) + expected = ( + 'OPENQASM 2.0;\n' + 'include "qelib1.inc";\n' + 'qreg q[1];\n' + 'reset q[0];\n' + ) + assert qasm == expected - expected = """ - OPENQASM 2.0; - include "qelib1.inc"; - qreg q[1]; - reset q[0]; - """ - assert qasm.strip() == expected.strip() From d965dc71ecf79a0e7ea517624916085a59e63a73 Mon Sep 17 00:00:00 2001 From: peachnuts Date: Wed, 17 Jan 2024 23:26:30 -0800 Subject: [PATCH 7/9] fix reset test bug --- bqskit/ir/gates/reset.py | 4 ++-- bqskit/ir/lang/qasm2/visitor.py | 2 +- tests/ir/lang/test_qasm_encode.py | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bqskit/ir/gates/reset.py b/bqskit/ir/gates/reset.py index 8a4a93833..e72049003 100644 --- a/bqskit/ir/gates/reset.py +++ b/bqskit/ir/gates/reset.py @@ -1,11 +1,11 @@ """This module implements the Reset class.""" from __future__ import annotations -from bqskit.ir.gate import Gate +from bqskit.ir.gates.constantgate import ConstantGate from bqskit.qis.unitary.unitary import RealVector from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix -class Reset(Gate): +class Reset(ConstantGate): """Pseudogate to initialize the qudit to |0>.""" def __init__(self, radix: int = 2) -> None: diff --git a/bqskit/ir/lang/qasm2/visitor.py b/bqskit/ir/lang/qasm2/visitor.py index a55ac9829..3f89310c6 100644 --- a/bqskit/ir/lang/qasm2/visitor.py +++ b/bqskit/ir/lang/qasm2/visitor.py @@ -656,7 +656,7 @@ def measure(self, tree: lark.Tree) -> None: def reset(self, tree: lark.Tree) -> None: """reset node visitor.""" - params = [] + params: list[float] = [] qlist = tree.children[-1] gate_name = tree.data if gate_name in self.gate_defs: diff --git a/tests/ir/lang/test_qasm_encode.py b/tests/ir/lang/test_qasm_encode.py index 061a035c5..3ba60775d 100644 --- a/tests/ir/lang/test_qasm_encode.py +++ b/tests/ir/lang/test_qasm_encode.py @@ -2,8 +2,8 @@ from bqskit.ir.circuit import Circuit from bqskit.ir.gates import CNOTGate -from bqskit.ir.gates import U3Gate from bqskit.ir.gates import Reset +from bqskit.ir.gates import U3Gate from bqskit.ir.lang.qasm2 import OPENQASM2Language @@ -46,6 +46,7 @@ def test_nested_circuitgate(self) -> None: def test_reset(self) -> None: circuit = Circuit(1) circuit.append_gate(Reset(), 0) + qasm = OPENQASM2Language().encode(circuit) expected = ( 'OPENQASM 2.0;\n' From 26e9464405eb79890ab4f875fb5e5d9a3e2922a8 Mon Sep 17 00:00:00 2001 From: peachnuts Date: Thu, 18 Jan 2024 01:14:25 -0800 Subject: [PATCH 8/9] debug measure --- bqskit/ir/lang/qasm2/visitor.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/bqskit/ir/lang/qasm2/visitor.py b/bqskit/ir/lang/qasm2/visitor.py index cb4531a49..cc175a38b 100644 --- a/bqskit/ir/lang/qasm2/visitor.py +++ b/bqskit/ir/lang/qasm2/visitor.py @@ -586,6 +586,7 @@ def measure(self, tree: lark.Tree) -> None: class_childs = tree.children[1].children qubit_reg_name = str(qubit_childs[0]) class_reg_name = str(class_childs[0]) + cregs = cast(List[Tuple[str, int]], self.classical_regs) if not any(r.name == qubit_reg_name for r in self.qubit_regs): raise LangException( f'Measuring undefined qubit register: {qubit_reg_name}', @@ -596,7 +597,7 @@ def measure(self, tree: lark.Tree) -> None: f'Measuring undefined classical register: {class_reg_name}', ) - if len(qubit_childs) == 1 and len(class_childs) == 1: + if len(qubit_childs) == 1 and len(class_childs) == 1: # for measure all for name, size in self.qubit_regs: if qubit_reg_name == name: qubit_size = size @@ -620,6 +621,13 @@ def measure(self, tree: lark.Tree) -> None: for i in range(qubit_size): self.measurements[outer_idx + i] = (class_reg_name, i) + # for key, item in enumerate(self.measurements.items()): + # + # mph = MeasurementPlaceholder(cregs, {key: item[1]}) + mph = MeasurementPlaceholder(cregs, self.measurements) + self.gate_defs['measure'] = GateDef('measure', 0, qubit_size, mph) + + elif len(qubit_childs) == 2 and len(class_childs) == 2: qubit_index = int(qubit_childs[1]) class_index = int(class_childs[1]) @@ -633,6 +641,9 @@ def measure(self, tree: lark.Tree) -> None: outer_idx += size self.measurements[qubit_index] = (class_reg_name, class_index) + mph = MeasurementPlaceholder(cregs, self.measurements) + self.gate_defs['measure'] = GateDef('measure', 0, 1, mph) + else: raise LangException( @@ -641,11 +652,10 @@ def measure(self, tree: lark.Tree) -> None: 'measured to a single classical bit.', ) - - for key, item in enumerate(self.measurements.items()): - cregs = cast(List[Tuple[str, int]], self.classical_regs) - mph = MeasurementPlaceholder(cregs, {key: item}) - self.gate_defs['measure'] = GateDef('measure', 0, 1, mph) + # for key, item in enumerate(self.measurements.items()): + # cregs = cast(List[Tuple[str, int]], self.classical_regs) + # mph = MeasurementPlaceholder(cregs, {key: item[1]}) + # self.gate_defs['measure'] = GateDef('measure', 0, 1, mph) params = [] qlist = tree.children[0] From 76bdfc3ac998105f6ae7a650e03a3f60b5214af0 Mon Sep 17 00:00:00 2001 From: peachnuts Date: Thu, 18 Jan 2024 09:06:49 -0800 Subject: [PATCH 9/9] change quick partition --- bqskit/ir/lang/qasm2/visitor.py | 11 +-- bqskit/passes/partitioning/quick.py | 103 ++-------------------------- 2 files changed, 5 insertions(+), 109 deletions(-) diff --git a/bqskit/ir/lang/qasm2/visitor.py b/bqskit/ir/lang/qasm2/visitor.py index cc175a38b..23a51c083 100644 --- a/bqskit/ir/lang/qasm2/visitor.py +++ b/bqskit/ir/lang/qasm2/visitor.py @@ -620,10 +620,6 @@ def measure(self, tree: lark.Tree) -> None: for i in range(qubit_size): self.measurements[outer_idx + i] = (class_reg_name, i) - - # for key, item in enumerate(self.measurements.items()): - # - # mph = MeasurementPlaceholder(cregs, {key: item[1]}) mph = MeasurementPlaceholder(cregs, self.measurements) self.gate_defs['measure'] = GateDef('measure', 0, qubit_size, mph) @@ -652,12 +648,7 @@ def measure(self, tree: lark.Tree) -> None: 'measured to a single classical bit.', ) - # for key, item in enumerate(self.measurements.items()): - # cregs = cast(List[Tuple[str, int]], self.classical_regs) - # mph = MeasurementPlaceholder(cregs, {key: item[1]}) - # self.gate_defs['measure'] = GateDef('measure', 0, 1, mph) - - params = [] + params: list[float] = [] qlist = tree.children[0] location = CircuitLocation(self.convert_qubit_ids_to_indices(qlist)) diff --git a/bqskit/passes/partitioning/quick.py b/bqskit/passes/partitioning/quick.py index b5322c1ec..d010c6def 100644 --- a/bqskit/passes/partitioning/quick.py +++ b/bqskit/passes/partitioning/quick.py @@ -13,8 +13,6 @@ from bqskit.ir.location import CircuitLocation from bqskit.ir.point import CircuitPoint from bqskit.utils.typing import is_integer -from bqskit.ir.gates import MeasurementPlaceholder -from bqskit.ir.gates import Reset _logger = logging.getLogger(__name__) @@ -114,12 +112,12 @@ def process_pending_bins() -> None: loc = list(sorted(bin.qudits)) # Merge previously placed blocks if possible - merging = not isinstance(bin, (BarrierBin, MeasurementBin, ResetBin)) + merging = not isinstance(bin, BarrierBin) while merging: merging = False for p in partitioned_circuit.rear: op = partitioned_circuit[p] - if isinstance(op.gate, (BarrierPlaceholder, MeasurementPlaceholder, Reset)): + if isinstance(op.gate, BarrierPlaceholder): # Don't merge through barriers continue qudits = list(op.location) @@ -154,7 +152,7 @@ def process_pending_bins() -> None: partitioned_circuit.append_circuit( subc, loc, - not isinstance(bin, (BarrierBin, MeasurementBin, ResetBin)), + not isinstance(bin, BarrierBin), True, ) for qudit in bin.qudits: @@ -193,32 +191,6 @@ def process_pending_bins() -> None: pending_bins.append(BarrierBin(point, location, circuit)) continue - # Measurement close all overlapping bins - if isinstance(op.gate, MeasurementPlaceholder): - for bin in overlapping_bins: - if close_bin_qudits(bin, location, cycle): - num_closed += 1 - else: - extended = [q for q in location if q not in bin.qudits] - bin.blocked_qudits.update(extended) - - # Track the measurement to restore it in partitioned circuit - pending_bins.append(MeasurementBin(point, location, circuit)) - continue - - # Reset close all overlapping bins - if isinstance(op.gate, Reset): - for bin in overlapping_bins: - if close_bin_qudits(bin, location, cycle): - num_closed += 1 - else: - extended = [q for q in location if q not in bin.qudits] - bin.blocked_qudits.update(extended) - - # Track the reset to restore it in partitioned circuit - pending_bins.append(ResetBin(point, location, circuit)) - continue - # Get all the currently active bins that can have op added to them admissible_bins = [ bin for bin in overlapping_bins @@ -405,71 +377,4 @@ def __init__( # Close the bin for q in location: - self.active_qudits.remove(q) - - -class MeasurementBin(Bin): - """A special bin made to mark and preserve measurement location.""" - - def __init__( - self, - point: CircuitPoint, - location: CircuitLocation, - circuit: Circuit, - ) -> None: - """Initialize a MeasurementBin with the point and location of a measurement.""" - super().__init__() - - # Add the measurement - self.add_op(point, location) - - # Barriar bins fill the volume to the next gates - - nexts = circuit.next(point) - ends: dict[int, int | None] = {q: None for q in location} - for p in nexts: - loc = circuit[p].location - for q in loc: - if q in ends and ( - ends[q] is None or ends[q] >= p.cycle): # type: ignore # noqa # short-circuit safety for >= - ends[q] = p.cycle - 1 - - self.ends = ends - - # Close the bin - for q in location: - self.active_qudits.remove(q) - - -class ResetBin(Bin): - """A special bin made to mark and preserve reset location.""" - - def __init__( - self, - point: CircuitPoint, - location: CircuitLocation, - circuit: Circuit, - ) -> None: - """Initialize a reset with the point and location of a reset.""" - super().__init__() - - # Add the reset - self.add_op(point, location) - - # Barriar bins fill the volume to the next gates - - nexts = circuit.next(point) - ends: dict[int, int | None] = {q: None for q in location} - for p in nexts: - loc = circuit[p].location - for q in loc: - if q in ends and ( - ends[q] is None or ends[q] >= p.cycle): # type: ignore # noqa # short-circuit safety for >= - ends[q] = p.cycle - 1 - - self.ends = ends - - # Close the bin - for q in location: - self.active_qudits.remove(q) - + self.active_qudits.remove(q) \ No newline at end of file