bloqade-circuit 0.1.0__py3-none-any.whl → 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of bloqade-circuit might be problematic. Click here for more details.

Files changed (74) hide show
  1. bloqade/analysis/address/impls.py +5 -9
  2. bloqade/analysis/address/lattice.py +1 -1
  3. bloqade/analysis/fidelity/__init__.py +1 -0
  4. bloqade/analysis/fidelity/analysis.py +69 -0
  5. bloqade/device.py +130 -0
  6. bloqade/noise/__init__.py +2 -1
  7. bloqade/noise/fidelity.py +51 -0
  8. bloqade/noise/native/model.py +1 -2
  9. bloqade/noise/native/rewrite.py +5 -5
  10. bloqade/noise/native/stmts.py +40 -11
  11. bloqade/pyqrack/__init__.py +8 -2
  12. bloqade/pyqrack/base.py +24 -3
  13. bloqade/pyqrack/device.py +166 -0
  14. bloqade/pyqrack/noise/native.py +1 -2
  15. bloqade/pyqrack/qasm2/core.py +31 -15
  16. bloqade/pyqrack/qasm2/glob.py +28 -0
  17. bloqade/pyqrack/qasm2/uop.py +9 -1
  18. bloqade/pyqrack/reg.py +17 -49
  19. bloqade/pyqrack/squin/__init__.py +0 -0
  20. bloqade/pyqrack/squin/op.py +154 -0
  21. bloqade/pyqrack/squin/qubit.py +85 -0
  22. bloqade/pyqrack/squin/runtime.py +515 -0
  23. bloqade/pyqrack/squin/wire.py +69 -0
  24. bloqade/pyqrack/target.py +9 -2
  25. bloqade/pyqrack/task.py +30 -0
  26. bloqade/qasm2/_wrappers.py +11 -1
  27. bloqade/qasm2/dialects/core/stmts.py +15 -4
  28. bloqade/qasm2/dialects/expr/_emit.py +9 -8
  29. bloqade/qasm2/emit/base.py +4 -2
  30. bloqade/qasm2/emit/gate.py +0 -14
  31. bloqade/qasm2/emit/main.py +19 -15
  32. bloqade/qasm2/emit/target.py +2 -6
  33. bloqade/qasm2/glob.py +1 -1
  34. bloqade/qasm2/parse/lowering.py +124 -1
  35. bloqade/qasm2/passes/glob.py +3 -3
  36. bloqade/qasm2/passes/lift_qubits.py +26 -0
  37. bloqade/qasm2/passes/noise.py +6 -14
  38. bloqade/qasm2/passes/parallel.py +3 -3
  39. bloqade/qasm2/passes/py2qasm.py +1 -2
  40. bloqade/qasm2/passes/qasm2py.py +1 -2
  41. bloqade/qasm2/rewrite/desugar.py +6 -6
  42. bloqade/qasm2/rewrite/glob.py +9 -9
  43. bloqade/qasm2/rewrite/heuristic_noise.py +30 -38
  44. bloqade/qasm2/rewrite/insert_qubits.py +34 -0
  45. bloqade/qasm2/rewrite/native_gates.py +54 -55
  46. bloqade/qasm2/rewrite/parallel_to_uop.py +9 -9
  47. bloqade/qasm2/rewrite/uop_to_parallel.py +20 -22
  48. bloqade/qasm2/types.py +3 -6
  49. bloqade/qbraid/schema.py +10 -12
  50. bloqade/squin/__init__.py +1 -1
  51. bloqade/squin/analysis/nsites/analysis.py +4 -6
  52. bloqade/squin/analysis/nsites/impls.py +2 -6
  53. bloqade/squin/analysis/schedule.py +1 -1
  54. bloqade/squin/groups.py +15 -7
  55. bloqade/squin/noise/__init__.py +27 -0
  56. bloqade/squin/noise/_dialect.py +3 -0
  57. bloqade/squin/noise/stmts.py +59 -0
  58. bloqade/squin/op/__init__.py +35 -5
  59. bloqade/squin/op/number.py +5 -0
  60. bloqade/squin/op/rewrite.py +46 -0
  61. bloqade/squin/op/stmts.py +23 -2
  62. bloqade/squin/op/types.py +14 -0
  63. bloqade/squin/qubit.py +79 -11
  64. bloqade/squin/rewrite/__init__.py +0 -0
  65. bloqade/squin/rewrite/measure_desugar.py +33 -0
  66. bloqade/squin/wire.py +31 -2
  67. bloqade/stim/emit/stim.py +1 -1
  68. bloqade/task.py +94 -0
  69. bloqade/visual/animation/base.py +25 -15
  70. {bloqade_circuit-0.1.0.dist-info → bloqade_circuit-0.2.1.dist-info}/METADATA +8 -2
  71. {bloqade_circuit-0.1.0.dist-info → bloqade_circuit-0.2.1.dist-info}/RECORD +73 -52
  72. bloqade/squin/op/complex.py +0 -6
  73. {bloqade_circuit-0.1.0.dist-info → bloqade_circuit-0.2.1.dist-info}/WHEEL +0 -0
  74. {bloqade_circuit-0.1.0.dist-info → bloqade_circuit-0.2.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,9 +1,12 @@
1
+ from typing import Any
2
+
1
3
  from kirin import interp
4
+ from kirin.interp import InterpreterError
5
+ from kirin.dialects import ilist
2
6
 
3
7
  from bloqade.pyqrack.reg import (
4
8
  CBitRef,
5
9
  CRegister,
6
- PyQrackReg,
7
10
  QubitState,
8
11
  Measurement,
9
12
  PyQrackQubit,
@@ -14,20 +17,18 @@ from bloqade.qasm2.dialects import core
14
17
 
15
18
  @core.dialect.register(key="pyqrack")
16
19
  class PyQrackMethods(interp.MethodTable):
17
-
18
20
  @interp.impl(core.QRegNew)
19
21
  def qreg_new(
20
22
  self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: core.QRegNew
21
23
  ):
22
24
  n_qubits: int = frame.get(stmt.n_qubits)
23
- return (
24
- PyQrackReg(
25
- size=n_qubits,
26
- sim_reg=interp.memory.sim_reg,
27
- addrs=interp.memory.allocate(n_qubits),
28
- qubit_state=[QubitState.Active] * n_qubits,
29
- ),
25
+ qreg = ilist.IList(
26
+ [
27
+ PyQrackQubit(i, interp.memory.sim_reg, QubitState.Active)
28
+ for i in interp.memory.allocate(n_qubits=n_qubits)
29
+ ]
30
30
  )
31
+ return (qreg,)
31
32
 
32
33
  @interp.impl(core.CRegNew)
33
34
  def creg_new(
@@ -40,7 +41,9 @@ class PyQrackMethods(interp.MethodTable):
40
41
  def qreg_get(
41
42
  self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: core.QRegGet
42
43
  ):
43
- return (PyQrackQubit(ref=frame.get(stmt.reg), pos=frame.get(stmt.idx)),)
44
+ reg = frame.get(stmt.reg)
45
+ i = frame.get(stmt.idx)
46
+ return (reg[i],)
44
47
 
45
48
  @interp.impl(core.CRegGet)
46
49
  def creg_get(
@@ -52,12 +55,25 @@ class PyQrackMethods(interp.MethodTable):
52
55
  def measure(
53
56
  self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: core.Measure
54
57
  ):
55
- qarg: PyQrackQubit = frame.get(stmt.qarg)
56
- carg: CBitRef = frame.get(stmt.carg)
57
- if qarg.is_active():
58
- carg.set_value(Measurement(qarg.sim_reg.m(qarg.addr)))
58
+ qarg: PyQrackQubit | ilist.IList[PyQrackQubit, Any] = frame.get(stmt.qarg)
59
+ carg: CBitRef | CRegister = frame.get(stmt.carg)
60
+
61
+ if isinstance(qarg, PyQrackQubit) and isinstance(carg, CBitRef):
62
+ if qarg.is_active():
63
+ carg.set_value(Measurement(qarg.sim_reg.m(qarg.addr)))
64
+ else:
65
+ carg.set_value(interp.loss_m_result)
66
+ elif isinstance(qarg, ilist.IList) and isinstance(carg, CRegister):
67
+ for i, qubit in enumerate(qarg):
68
+ cbit = CBitRef(carg, i)
69
+ if qubit.is_active():
70
+ cbit.set_value(Measurement(qubit.sim_reg.m(qubit.addr)))
71
+ else:
72
+ cbit.set_value(interp.loss_m_result)
59
73
  else:
60
- carg.set_value(interp.loss_m_result)
74
+ raise InterpreterError(
75
+ f"Expected measure call on either a single qubit and classical bit, or two registers, but got the types {type(qarg)} and {type(carg)}"
76
+ )
61
77
 
62
78
  return ()
63
79
 
@@ -0,0 +1,28 @@
1
+ from typing import Any
2
+
3
+ from kirin import interp
4
+ from kirin.dialects import ilist
5
+
6
+ from bloqade.pyqrack.reg import PyQrackQubit
7
+ from bloqade.pyqrack.base import PyQrackInterpreter
8
+ from bloqade.qasm2.dialects import glob
9
+
10
+
11
+ @glob.dialect.register(key="pyqrack")
12
+ class PyQrackMethods(interp.MethodTable):
13
+ @interp.impl(glob.UGate)
14
+ def ugate(self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: glob.UGate):
15
+ registers: ilist.IList[ilist.IList[PyQrackQubit, Any], Any] = frame.get(
16
+ stmt.registers
17
+ )
18
+ theta, phi, lam = (
19
+ frame.get(stmt.theta),
20
+ frame.get(stmt.phi),
21
+ frame.get(stmt.lam),
22
+ )
23
+
24
+ for qreg in registers:
25
+ for qarg in qreg:
26
+ if qarg.is_active():
27
+ interp.memory.sim_reg.u(qarg.addr, theta, phi, lam)
28
+ return ()
@@ -2,6 +2,7 @@ import math
2
2
 
3
3
  from kirin import interp
4
4
 
5
+ from pyqrack.pauli import Pauli
5
6
  from bloqade.pyqrack.reg import PyQrackQubit
6
7
  from bloqade.qasm2.dialects import uop
7
8
 
@@ -26,7 +27,14 @@ class PyQrackMethods(interp.MethodTable):
26
27
  "tdg": "adjt",
27
28
  }
28
29
 
29
- AXIS_MAP = {"rx": 1, "ry": 2, "rz": 3, "crx": 1, "cry": 2, "crz": 3}
30
+ AXIS_MAP = {
31
+ "rx": Pauli.PauliX,
32
+ "ry": Pauli.PauliY,
33
+ "rz": Pauli.PauliZ,
34
+ "crx": Pauli.PauliX,
35
+ "cry": Pauli.PauliY,
36
+ "crz": Pauli.PauliZ,
37
+ }
30
38
 
31
39
  @interp.impl(uop.Barrier)
32
40
  def barrier(
bloqade/pyqrack/reg.py CHANGED
@@ -1,8 +1,8 @@
1
1
  import enum
2
- from typing import TYPE_CHECKING, List
2
+ from typing import TYPE_CHECKING
3
3
  from dataclasses import dataclass
4
4
 
5
- from bloqade.qasm2.types import QReg, Qubit
5
+ from bloqade.qasm2.types import Qubit
6
6
 
7
7
  if TYPE_CHECKING:
8
8
  from pyqrack import QrackSimulator
@@ -33,7 +33,7 @@ class CBitRef:
33
33
  pos: int
34
34
  """The position of this bit in the classical register."""
35
35
 
36
- def set_value(self, value: bool):
36
+ def set_value(self, value: Measurement):
37
37
  self.ref[self.pos] = value
38
38
 
39
39
  def get_value(self):
@@ -45,55 +45,18 @@ class QubitState(enum.Enum):
45
45
  Lost = enum.auto()
46
46
 
47
47
 
48
- @dataclass(frozen=True)
49
- class PyQrackReg(QReg):
50
- """Simulation runtime value of a quantum register."""
51
-
52
- size: int
53
- """The number of qubits in this register."""
54
-
55
- sim_reg: "QrackSimulator"
56
- """The register of the simulator."""
57
-
58
- addrs: tuple[int, ...]
59
- """The global addresses of the qubits in this register."""
60
-
61
- qubit_state: List[QubitState]
62
- """The state of each qubit in this register."""
63
-
64
- def drop(self, pos: int):
65
- """Drop the qubit at the given position in-place.
66
-
67
- Args
68
- pos (int): The position of the qubit to drop.
69
-
70
- """
71
- assert self.qubit_state[pos] is QubitState.Active, "Qubit already lost"
72
- self.qubit_state[pos] = QubitState.Lost
73
-
74
- def __getitem__(self, pos: int):
75
- return PyQrackQubit(self, pos)
76
-
77
-
78
- @dataclass(frozen=True)
48
+ @dataclass
79
49
  class PyQrackQubit(Qubit):
80
50
  """The runtime representation of a qubit reference."""
81
51
 
82
- ref: PyQrackReg
83
- """The quantum register that is holding this qubit."""
84
-
85
- pos: int
86
- """The position of this qubit in the quantum register."""
52
+ addr: int
53
+ """The address of this qubit in the quantum register."""
87
54
 
88
- @property
89
- def sim_reg(self):
90
- """The register of the simulator."""
91
- return self.ref.sim_reg
55
+ sim_reg: "QrackSimulator"
56
+ """The register of the simulator."""
92
57
 
93
- @property
94
- def addr(self) -> int:
95
- """The global address of the qubit."""
96
- return self.ref.addrs[self.pos]
58
+ state: QubitState
59
+ """The state of the qubit (active/lost)"""
97
60
 
98
61
  def is_active(self) -> bool:
99
62
  """Check if the qubit is active.
@@ -102,8 +65,13 @@ class PyQrackQubit(Qubit):
102
65
  True if the qubit is active, False otherwise.
103
66
 
104
67
  """
105
- return self.ref.qubit_state[self.pos] is QubitState.Active
68
+ return self.state is QubitState.Active
106
69
 
107
70
  def drop(self):
108
71
  """Drop the qubit in-place."""
109
- self.ref.drop(self.pos)
72
+ self.state = QubitState.Lost
73
+
74
+
75
+ @dataclass
76
+ class PyQrackWire:
77
+ qubit: PyQrackQubit
File without changes
@@ -0,0 +1,154 @@
1
+ from kirin import interp
2
+
3
+ from bloqade.squin import op
4
+ from bloqade.pyqrack.base import PyQrackInterpreter
5
+
6
+ from .runtime import (
7
+ SnRuntime,
8
+ SpRuntime,
9
+ U3Runtime,
10
+ RotRuntime,
11
+ KronRuntime,
12
+ MultRuntime,
13
+ ScaleRuntime,
14
+ AdjointRuntime,
15
+ ControlRuntime,
16
+ PhaseOpRuntime,
17
+ IdentityRuntime,
18
+ OperatorRuntime,
19
+ ProjectorRuntime,
20
+ OperatorRuntimeABC,
21
+ PauliStringRuntime,
22
+ )
23
+
24
+
25
+ @op.dialect.register(key="pyqrack")
26
+ class PyQrackMethods(interp.MethodTable):
27
+
28
+ @interp.impl(op.stmts.Kron)
29
+ def kron(
30
+ self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: op.stmts.Kron
31
+ ) -> tuple[OperatorRuntimeABC]:
32
+ lhs = frame.get(stmt.lhs)
33
+ rhs = frame.get(stmt.rhs)
34
+ return (KronRuntime(lhs, rhs),)
35
+
36
+ @interp.impl(op.stmts.Mult)
37
+ def mult(
38
+ self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: op.stmts.Mult
39
+ ) -> tuple[OperatorRuntimeABC]:
40
+ lhs = frame.get(stmt.lhs)
41
+ rhs = frame.get(stmt.rhs)
42
+ return (MultRuntime(lhs, rhs),)
43
+
44
+ @interp.impl(op.stmts.Adjoint)
45
+ def adjoint(
46
+ self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: op.stmts.Adjoint
47
+ ) -> tuple[OperatorRuntimeABC]:
48
+ op = frame.get(stmt.op)
49
+ return (AdjointRuntime(op),)
50
+
51
+ @interp.impl(op.stmts.Scale)
52
+ def scale(
53
+ self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: op.stmts.Scale
54
+ ) -> tuple[OperatorRuntimeABC]:
55
+ op = frame.get(stmt.op)
56
+ factor = frame.get(stmt.factor)
57
+ return (ScaleRuntime(op, factor),)
58
+
59
+ @interp.impl(op.stmts.Control)
60
+ def control(
61
+ self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: op.stmts.Control
62
+ ) -> tuple[OperatorRuntimeABC]:
63
+ op = frame.get(stmt.op)
64
+ n_controls = stmt.n_controls
65
+ rt = ControlRuntime(
66
+ op=op,
67
+ n_controls=n_controls,
68
+ )
69
+ return (rt,)
70
+
71
+ @interp.impl(op.stmts.Rot)
72
+ def rot(
73
+ self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: op.stmts.Rot
74
+ ) -> tuple[OperatorRuntimeABC]:
75
+ axis = frame.get(stmt.axis)
76
+ angle = frame.get(stmt.angle)
77
+ return (RotRuntime(axis, angle),)
78
+
79
+ @interp.impl(op.stmts.Identity)
80
+ def identity(
81
+ self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: op.stmts.Identity
82
+ ) -> tuple[OperatorRuntimeABC]:
83
+ return (IdentityRuntime(sites=stmt.sites),)
84
+
85
+ @interp.impl(op.stmts.PhaseOp)
86
+ @interp.impl(op.stmts.ShiftOp)
87
+ def phaseop(
88
+ self,
89
+ interp: PyQrackInterpreter,
90
+ frame: interp.Frame,
91
+ stmt: op.stmts.PhaseOp | op.stmts.ShiftOp,
92
+ ) -> tuple[OperatorRuntimeABC]:
93
+ theta = frame.get(stmt.theta)
94
+ global_ = isinstance(stmt, op.stmts.PhaseOp)
95
+ return (PhaseOpRuntime(theta, global_=global_),)
96
+
97
+ @interp.impl(op.stmts.X)
98
+ @interp.impl(op.stmts.Y)
99
+ @interp.impl(op.stmts.Z)
100
+ @interp.impl(op.stmts.H)
101
+ @interp.impl(op.stmts.S)
102
+ @interp.impl(op.stmts.T)
103
+ def operator(
104
+ self,
105
+ interp: PyQrackInterpreter,
106
+ frame: interp.Frame,
107
+ stmt: (
108
+ op.stmts.X | op.stmts.Y | op.stmts.Z | op.stmts.H | op.stmts.S | op.stmts.T
109
+ ),
110
+ ) -> tuple[OperatorRuntimeABC]:
111
+ return (OperatorRuntime(method_name=stmt.name.lower()),)
112
+
113
+ @interp.impl(op.stmts.P0)
114
+ @interp.impl(op.stmts.P1)
115
+ def projector(
116
+ self,
117
+ interp: PyQrackInterpreter,
118
+ frame: interp.Frame,
119
+ stmt: op.stmts.P0 | op.stmts.P1,
120
+ ) -> tuple[OperatorRuntimeABC]:
121
+ state = isinstance(stmt, op.stmts.P1)
122
+ return (ProjectorRuntime(to_state=state),)
123
+
124
+ @interp.impl(op.stmts.Sp)
125
+ def sp(
126
+ self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: op.stmts.Sp
127
+ ) -> tuple[OperatorRuntimeABC]:
128
+ return (SpRuntime(),)
129
+
130
+ @interp.impl(op.stmts.Sn)
131
+ def sn(
132
+ self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: op.stmts.Sn
133
+ ) -> tuple[OperatorRuntimeABC]:
134
+ return (SnRuntime(),)
135
+
136
+ @interp.impl(op.stmts.U3)
137
+ def u3(
138
+ self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: op.stmts.U3
139
+ ) -> tuple[OperatorRuntimeABC]:
140
+ theta = frame.get(stmt.theta)
141
+ phi = frame.get(stmt.phi)
142
+ lam = frame.get(stmt.lam)
143
+ return (U3Runtime(theta, phi, lam),)
144
+
145
+ @interp.impl(op.stmts.PauliString)
146
+ def clifford_string(
147
+ self,
148
+ interp: PyQrackInterpreter,
149
+ frame: interp.Frame,
150
+ stmt: op.stmts.PauliString,
151
+ ) -> tuple[OperatorRuntimeABC]:
152
+ string = stmt.string
153
+ ops = [OperatorRuntime(method_name=name.lower()) for name in stmt.string]
154
+ return (PauliStringRuntime(string, ops),)
@@ -0,0 +1,85 @@
1
+ from typing import Any
2
+
3
+ from kirin import interp
4
+ from kirin.dialects import ilist
5
+
6
+ from bloqade.squin import qubit
7
+ from bloqade.pyqrack.reg import QubitState, PyQrackQubit
8
+ from bloqade.pyqrack.base import PyQrackInterpreter
9
+
10
+ from .runtime import OperatorRuntimeABC
11
+
12
+
13
+ @qubit.dialect.register(key="pyqrack")
14
+ class PyQrackMethods(interp.MethodTable):
15
+ @interp.impl(qubit.New)
16
+ def new(self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: qubit.New):
17
+ n_qubits: int = frame.get(stmt.n_qubits)
18
+ qreg = ilist.IList(
19
+ [
20
+ PyQrackQubit(i, interp.memory.sim_reg, QubitState.Active)
21
+ for i in interp.memory.allocate(n_qubits=n_qubits)
22
+ ]
23
+ )
24
+ return (qreg,)
25
+
26
+ @interp.impl(qubit.Apply)
27
+ def apply(self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: qubit.Apply):
28
+ qubits: ilist.IList[PyQrackQubit, Any] = frame.get(stmt.qubits)
29
+ operator: OperatorRuntimeABC = frame.get(stmt.operator)
30
+ operator.apply(*qubits)
31
+
32
+ @interp.impl(qubit.Broadcast)
33
+ def broadcast(
34
+ self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: qubit.Broadcast
35
+ ):
36
+ operator: OperatorRuntimeABC = frame.get(stmt.operator)
37
+ qubits: ilist.IList[PyQrackQubit, Any] = frame.get(stmt.qubits)
38
+ operator.broadcast_apply(qubits)
39
+
40
+ def _measure_qubit(self, qbit: PyQrackQubit):
41
+ if qbit.is_active():
42
+ return bool(qbit.sim_reg.m(qbit.addr))
43
+
44
+ @interp.impl(qubit.MeasureQubitList)
45
+ def measure_qubit_list(
46
+ self,
47
+ interp: PyQrackInterpreter,
48
+ frame: interp.Frame,
49
+ stmt: qubit.MeasureQubitList,
50
+ ):
51
+ qubits: ilist.IList[PyQrackQubit, Any] = frame.get(stmt.qubits)
52
+ result = ilist.IList([self._measure_qubit(qbit) for qbit in qubits])
53
+ return (result,)
54
+
55
+ @interp.impl(qubit.MeasureQubit)
56
+ def measure_qubit(
57
+ self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: qubit.MeasureQubit
58
+ ):
59
+ qbit: PyQrackQubit = frame.get(stmt.qubit)
60
+ result = self._measure_qubit(qbit)
61
+ return (result,)
62
+
63
+ @interp.impl(qubit.MeasureAndReset)
64
+ def measure_and_reset(
65
+ self,
66
+ interp: PyQrackInterpreter,
67
+ frame: interp.Frame,
68
+ stmt: qubit.MeasureAndReset,
69
+ ):
70
+ qubits: ilist.IList[PyQrackQubit, Any] = frame.get(stmt.qubits)
71
+ result = []
72
+ for qbit in qubits:
73
+ if qbit.is_active():
74
+ result.append(qbit.sim_reg.m(qbit.addr))
75
+ else:
76
+ result.append(None)
77
+ qbit.sim_reg.force_m(qbit.addr, 0)
78
+
79
+ return (ilist.IList(result),)
80
+
81
+ @interp.impl(qubit.Reset)
82
+ def reset(self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: qubit.Reset):
83
+ qubits: ilist.IList[PyQrackQubit, Any] = frame.get(stmt.qubits)
84
+ for qbit in qubits:
85
+ qbit.sim_reg.force_m(qbit.addr, 0)