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.
- bloqade/analysis/address/impls.py +5 -9
- bloqade/analysis/address/lattice.py +1 -1
- bloqade/analysis/fidelity/__init__.py +1 -0
- bloqade/analysis/fidelity/analysis.py +69 -0
- bloqade/device.py +130 -0
- bloqade/noise/__init__.py +2 -1
- bloqade/noise/fidelity.py +51 -0
- bloqade/noise/native/model.py +1 -2
- bloqade/noise/native/rewrite.py +5 -5
- bloqade/noise/native/stmts.py +40 -11
- bloqade/pyqrack/__init__.py +8 -2
- bloqade/pyqrack/base.py +24 -3
- bloqade/pyqrack/device.py +166 -0
- bloqade/pyqrack/noise/native.py +1 -2
- bloqade/pyqrack/qasm2/core.py +31 -15
- bloqade/pyqrack/qasm2/glob.py +28 -0
- bloqade/pyqrack/qasm2/uop.py +9 -1
- bloqade/pyqrack/reg.py +17 -49
- bloqade/pyqrack/squin/__init__.py +0 -0
- bloqade/pyqrack/squin/op.py +154 -0
- bloqade/pyqrack/squin/qubit.py +85 -0
- bloqade/pyqrack/squin/runtime.py +515 -0
- bloqade/pyqrack/squin/wire.py +69 -0
- bloqade/pyqrack/target.py +9 -2
- bloqade/pyqrack/task.py +30 -0
- bloqade/qasm2/_wrappers.py +11 -1
- bloqade/qasm2/dialects/core/stmts.py +15 -4
- bloqade/qasm2/dialects/expr/_emit.py +9 -8
- bloqade/qasm2/emit/base.py +4 -2
- bloqade/qasm2/emit/gate.py +0 -14
- bloqade/qasm2/emit/main.py +19 -15
- bloqade/qasm2/emit/target.py +2 -6
- bloqade/qasm2/glob.py +1 -1
- bloqade/qasm2/parse/lowering.py +124 -1
- bloqade/qasm2/passes/glob.py +3 -3
- bloqade/qasm2/passes/lift_qubits.py +26 -0
- bloqade/qasm2/passes/noise.py +6 -14
- bloqade/qasm2/passes/parallel.py +3 -3
- bloqade/qasm2/passes/py2qasm.py +1 -2
- bloqade/qasm2/passes/qasm2py.py +1 -2
- bloqade/qasm2/rewrite/desugar.py +6 -6
- bloqade/qasm2/rewrite/glob.py +9 -9
- bloqade/qasm2/rewrite/heuristic_noise.py +30 -38
- bloqade/qasm2/rewrite/insert_qubits.py +34 -0
- bloqade/qasm2/rewrite/native_gates.py +54 -55
- bloqade/qasm2/rewrite/parallel_to_uop.py +9 -9
- bloqade/qasm2/rewrite/uop_to_parallel.py +20 -22
- bloqade/qasm2/types.py +3 -6
- bloqade/qbraid/schema.py +10 -12
- bloqade/squin/__init__.py +1 -1
- bloqade/squin/analysis/nsites/analysis.py +4 -6
- bloqade/squin/analysis/nsites/impls.py +2 -6
- bloqade/squin/analysis/schedule.py +1 -1
- bloqade/squin/groups.py +15 -7
- bloqade/squin/noise/__init__.py +27 -0
- bloqade/squin/noise/_dialect.py +3 -0
- bloqade/squin/noise/stmts.py +59 -0
- bloqade/squin/op/__init__.py +35 -5
- bloqade/squin/op/number.py +5 -0
- bloqade/squin/op/rewrite.py +46 -0
- bloqade/squin/op/stmts.py +23 -2
- bloqade/squin/op/types.py +14 -0
- bloqade/squin/qubit.py +79 -11
- bloqade/squin/rewrite/__init__.py +0 -0
- bloqade/squin/rewrite/measure_desugar.py +33 -0
- bloqade/squin/wire.py +31 -2
- bloqade/stim/emit/stim.py +1 -1
- bloqade/task.py +94 -0
- bloqade/visual/animation/base.py +25 -15
- {bloqade_circuit-0.1.0.dist-info → bloqade_circuit-0.2.1.dist-info}/METADATA +8 -2
- {bloqade_circuit-0.1.0.dist-info → bloqade_circuit-0.2.1.dist-info}/RECORD +73 -52
- bloqade/squin/op/complex.py +0 -6
- {bloqade_circuit-0.1.0.dist-info → bloqade_circuit-0.2.1.dist-info}/WHEEL +0 -0
- {bloqade_circuit-0.1.0.dist-info → bloqade_circuit-0.2.1.dist-info}/licenses/LICENSE +0 -0
bloqade/pyqrack/qasm2/core.py
CHANGED
|
@@ -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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
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
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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 ()
|
bloqade/pyqrack/qasm2/uop.py
CHANGED
|
@@ -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 = {
|
|
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
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
|
|
5
|
-
from bloqade.qasm2.types import
|
|
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:
|
|
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
|
|
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
|
-
|
|
83
|
-
"""The
|
|
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
|
-
|
|
89
|
-
|
|
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
|
-
|
|
94
|
-
|
|
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.
|
|
68
|
+
return self.state is QubitState.Active
|
|
106
69
|
|
|
107
70
|
def drop(self):
|
|
108
71
|
"""Drop the qubit in-place."""
|
|
109
|
-
self.
|
|
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)
|