Skip to content

Commit 6020870

Browse files
authored
Implement pyqrack interpreter method for qasm2 glob.u gate (#152)
* Reorder UGate arguments to match wrapper function arg order The wrapper was already in use in a bunch of places with this order, but using named arguments so it never errored. Still this should be consistent and I stuck with the order of the wrapper as it is already used. * Make PyQrackReg iterable by throwing IndexError in getitem method * Implement pyqrack interpreter method for glob.u gate * Fix pyright issue in core & reg * Fix order of glob.u decorator yet again (to match original UGate class args) * Move new method to separate method table * Add TODO to clean up PyQrackReg
1 parent 0253a76 commit 6020870

File tree

7 files changed

+107
-6
lines changed

7 files changed

+107
-6
lines changed

src/bloqade/pyqrack/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@
1414

1515
# NOTE: The following import is for registering the method tables
1616
from .noise import native as native
17-
from .qasm2 import uop as uop, core as core, parallel as parallel
17+
from .qasm2 import uop as uop, core as core, glob as glob, parallel as parallel
1818
from .target import PyQrack as PyQrack

src/bloqade/pyqrack/qasm2/core.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
@core.dialect.register(key="pyqrack")
1616
class PyQrackMethods(interp.MethodTable):
17-
1817
@interp.impl(core.QRegNew)
1918
def qreg_new(
2019
self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: core.QRegNew

src/bloqade/pyqrack/qasm2/glob.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from typing import Any
2+
3+
from kirin import interp
4+
from kirin.dialects import ilist
5+
6+
from bloqade.pyqrack.reg import PyQrackReg
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[PyQrackReg, Any] = frame.get(stmt.registers)
16+
theta, phi, lam = (
17+
frame.get(stmt.theta),
18+
frame.get(stmt.phi),
19+
frame.get(stmt.lam),
20+
)
21+
22+
for qreg in registers:
23+
for qarg in qreg:
24+
if qarg.is_active():
25+
interp.memory.sim_reg.u(qarg.addr, theta, phi, lam)
26+
return ()

src/bloqade/pyqrack/reg.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class CBitRef:
3333
pos: int
3434
"""The position of this bit in the classical register."""
3535

36-
def set_value(self, value: bool):
36+
def set_value(self, value: Measurement):
3737
self.ref[self.pos] = value
3838

3939
def get_value(self):
@@ -46,7 +46,7 @@ class QubitState(enum.Enum):
4646

4747

4848
@dataclass(frozen=True)
49-
class PyQrackReg(QReg):
49+
class PyQrackReg(QReg): # TODO: clean up implementation with list base class
5050
"""Simulation runtime value of a quantum register."""
5151

5252
size: int
@@ -72,6 +72,8 @@ def drop(self, pos: int):
7272
self.qubit_state[pos] = QubitState.Lost
7373

7474
def __getitem__(self, pos: int):
75+
if not 0 <= pos < self.size:
76+
raise IndexError("Qubit index out of bounds of register.")
7577
return PyQrackQubit(self, pos)
7678

7779

src/bloqade/qasm2/glob.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
@wraps(glob.UGate)
1313
def u(
14-
theta: float, phi: float, lam: float, registers: ilist.IList[QReg, Any] | list
14+
registers: ilist.IList[QReg, Any] | list, theta: float, phi: float, lam: float
1515
) -> None:
1616
"""Apply a U gate to all qubits in the input registers.
1717

test/pyqrack/test_target.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,77 @@ def ghz():
3838
assert math.isclose(out[0].real, val, abs_tol=abs_tol)
3939
assert math.isclose(out[-1].real, val, abs_tol=abs_tol)
4040
assert all(math.isclose(ele.real, 0.0, abs_tol=abs_tol) for ele in out[1:-1])
41+
42+
43+
def test_target_glob():
44+
@qasm2.extended
45+
def global_h():
46+
q = qasm2.qreg(3)
47+
48+
# rotate around Y by pi/2, i.e. perform a hadamard
49+
qasm2.glob.u([q], math.pi / 2.0, 0, 0)
50+
51+
return q
52+
53+
target = PyQrack(3)
54+
q = target.run(global_h)
55+
56+
assert isinstance(q, reg.PyQrackReg)
57+
58+
out = q.sim_reg.out_ket()
59+
60+
# remove global phase introduced by pyqrack
61+
phase = out[0] / abs(out[0])
62+
out = [ele / phase for ele in out]
63+
64+
for element in out:
65+
assert math.isclose(element.real, 1 / math.sqrt(8), abs_tol=2.2e-7)
66+
assert math.isclose(element.imag, 0, abs_tol=2.2e-7)
67+
68+
@qasm2.extended
69+
def multiple_registers():
70+
q1 = qasm2.qreg(2)
71+
q2 = qasm2.qreg(2)
72+
q3 = qasm2.qreg(2)
73+
74+
# hadamard on first register
75+
qasm2.glob.u(
76+
[q1],
77+
math.pi / 2.0,
78+
0,
79+
0,
80+
)
81+
82+
# apply hadamard to the other two
83+
qasm2.glob.u(
84+
[q2, q3],
85+
math.pi / 2.0,
86+
0,
87+
0,
88+
)
89+
90+
# rotate all of them back down
91+
qasm2.glob.u(
92+
[q1, q2, q3],
93+
-math.pi / 2.0,
94+
0,
95+
0,
96+
)
97+
98+
return q1
99+
100+
target = PyQrack(6)
101+
q1 = target.run(multiple_registers)
102+
103+
assert isinstance(q1, reg.PyQrackReg)
104+
105+
out = q1.sim_reg.out_ket()
106+
107+
assert out[0] == 1
108+
for i in range(1, len(out)):
109+
assert out[i] == 0
110+
111+
assert True
112+
113+
114+
test_target_glob()

test/qasm2/passes/test_heuristic_noise.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ def test_global_noise():
265265
def test_method():
266266
q0 = qasm2.qreg(1)
267267
q1 = qasm2.qreg(1)
268-
glob.UGate([q0, q1], 0.1, 0.2, 0.3)
268+
qasm2.glob.u([q0, q1], 0.1, 0.2, 0.3)
269269

270270
px = 0.01
271271
py = 0.01

0 commit comments

Comments
 (0)