bloqade-circuit 0.7.12__py3-none-any.whl → 0.8.0__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/__init__.py +8 -4
- bloqade/analysis/address/analysis.py +119 -29
- bloqade/analysis/address/impls.py +290 -87
- bloqade/analysis/address/lattice.py +209 -24
- bloqade/analysis/fidelity/analysis.py +2 -2
- bloqade/analysis/measure_id/impls.py +3 -27
- bloqade/cirq_utils/__init__.py +3 -1
- bloqade/cirq_utils/emit/__init__.py +3 -0
- bloqade/cirq_utils/emit/base.py +243 -0
- bloqade/cirq_utils/emit/gate.py +104 -0
- bloqade/cirq_utils/emit/noise.py +90 -0
- bloqade/cirq_utils/emit/qubit.py +35 -0
- bloqade/cirq_utils/lowering.py +664 -0
- bloqade/native/__init__.py +0 -1
- bloqade/native/_prelude.py +3 -3
- bloqade/native/dialects/gate/__init__.py +2 -0
- bloqade/native/dialects/gate/_dialect.py +3 -0
- bloqade/native/dialects/{gates → gate}/_interface.py +5 -5
- bloqade/native/dialects/{gates → gate}/stmts.py +5 -5
- bloqade/native/stdlib/broadcast.py +19 -19
- bloqade/native/stdlib/simple.py +14 -13
- bloqade/native/upstream/__init__.py +5 -0
- bloqade/native/upstream/squin2native.py +136 -0
- bloqade/pyqrack/__init__.py +1 -2
- bloqade/pyqrack/device.py +6 -17
- bloqade/pyqrack/native.py +17 -17
- bloqade/pyqrack/reg.py +1 -6
- bloqade/pyqrack/squin/gate/__init__.py +1 -0
- bloqade/pyqrack/squin/gate/gate.py +136 -0
- bloqade/pyqrack/squin/noise/native.py +120 -54
- bloqade/pyqrack/squin/qubit.py +25 -41
- bloqade/pyqrack/target.py +2 -2
- bloqade/qasm2/dialects/core/address.py +21 -12
- bloqade/qasm2/dialects/noise/fidelity.py +2 -6
- bloqade/qasm2/dialects/noise/model.py +2 -1
- bloqade/qasm2/passes/parallel.py +3 -1
- bloqade/qasm2/rewrite/__init__.py +0 -1
- bloqade/qasm2/rewrite/noise/heuristic_noise.py +7 -17
- bloqade/qasm2/rewrite/parallel_to_glob.py +28 -15
- bloqade/qasm2/rewrite/parallel_to_uop.py +2 -8
- bloqade/qubit/__init__.py +12 -0
- bloqade/qubit/_dialect.py +3 -0
- bloqade/qubit/_interface.py +49 -0
- bloqade/qubit/_prelude.py +45 -0
- bloqade/qubit/analysis/__init__.py +1 -0
- bloqade/qubit/analysis/address_impl.py +40 -0
- bloqade/qubit/stdlib/__init__.py +2 -0
- bloqade/qubit/stdlib/_new.py +34 -0
- bloqade/qubit/stdlib/broadcast.py +62 -0
- bloqade/qubit/stdlib/simple.py +59 -0
- bloqade/qubit/stmts.py +60 -0
- bloqade/rewrite/passes/aggressive_unroll.py +2 -1
- bloqade/squin/__init__.py +44 -17
- bloqade/squin/analysis/__init__.py +0 -1
- bloqade/squin/analysis/schedule.py +2 -2
- bloqade/squin/gate/__init__.py +2 -0
- bloqade/squin/gate/_dialect.py +3 -0
- bloqade/squin/gate/_interface.py +98 -0
- bloqade/squin/gate/stmts.py +119 -0
- bloqade/squin/groups.py +4 -21
- bloqade/squin/noise/__init__.py +1 -9
- bloqade/squin/noise/_dialect.py +1 -1
- bloqade/squin/noise/_interface.py +45 -0
- bloqade/squin/noise/stmts.py +65 -29
- bloqade/squin/rewrite/U3_to_clifford.py +70 -51
- bloqade/squin/rewrite/__init__.py +0 -2
- bloqade/squin/rewrite/remove_dangling_qubits.py +2 -2
- bloqade/squin/rewrite/wrap_analysis.py +4 -35
- bloqade/squin/stdlib/broadcast/__init__.py +34 -0
- bloqade/squin/stdlib/broadcast/_qubit.py +4 -0
- bloqade/squin/stdlib/broadcast/gate.py +260 -0
- bloqade/squin/stdlib/broadcast/noise.py +144 -0
- bloqade/squin/stdlib/simple/__init__.py +33 -0
- bloqade/squin/stdlib/simple/gate.py +242 -0
- bloqade/squin/stdlib/simple/noise.py +126 -0
- bloqade/stim/__init__.py +1 -0
- bloqade/stim/_wrappers.py +6 -0
- bloqade/stim/dialects/noise/emit.py +6 -1
- bloqade/stim/dialects/noise/stmts.py +5 -3
- bloqade/stim/emit/stim_str.py +2 -0
- bloqade/stim/parse/lowering.py +12 -17
- bloqade/stim/passes/__init__.py +0 -1
- bloqade/stim/passes/flatten.py +26 -0
- bloqade/stim/passes/simplify_ifs.py +6 -1
- bloqade/stim/passes/squin_to_stim.py +4 -70
- bloqade/stim/rewrite/__init__.py +0 -4
- bloqade/stim/rewrite/ifs_to_stim.py +23 -29
- bloqade/stim/rewrite/qubit_to_stim.py +90 -41
- bloqade/stim/rewrite/squin_measure.py +9 -18
- bloqade/stim/rewrite/squin_noise.py +132 -108
- bloqade/stim/rewrite/util.py +5 -204
- bloqade/types.py +10 -0
- {bloqade_circuit-0.7.12.dist-info → bloqade_circuit-0.8.0.dist-info}/METADATA +2 -2
- {bloqade_circuit-0.7.12.dist-info → bloqade_circuit-0.8.0.dist-info}/RECORD +96 -100
- bloqade/native/dialects/gates/__init__.py +0 -3
- bloqade/native/dialects/gates/_dialect.py +0 -3
- bloqade/pyqrack/squin/op.py +0 -180
- bloqade/pyqrack/squin/runtime.py +0 -543
- bloqade/pyqrack/squin/wire.py +0 -51
- bloqade/squin/_typeinfer.py +0 -20
- bloqade/squin/analysis/address_impl.py +0 -71
- bloqade/squin/analysis/nsites/__init__.py +0 -9
- bloqade/squin/analysis/nsites/analysis.py +0 -50
- bloqade/squin/analysis/nsites/impls.py +0 -99
- bloqade/squin/analysis/nsites/lattice.py +0 -49
- bloqade/squin/cirq/__init__.py +0 -306
- bloqade/squin/cirq/emit/emit_circuit.py +0 -129
- bloqade/squin/cirq/emit/noise.py +0 -49
- bloqade/squin/cirq/emit/op.py +0 -176
- bloqade/squin/cirq/emit/qubit.py +0 -58
- bloqade/squin/cirq/emit/runtime.py +0 -242
- bloqade/squin/cirq/lowering.py +0 -439
- bloqade/squin/lowering.py +0 -80
- bloqade/squin/noise/_wrapper.py +0 -36
- bloqade/squin/noise/rewrite.py +0 -129
- bloqade/squin/op/__init__.py +0 -41
- bloqade/squin/op/_dialect.py +0 -3
- bloqade/squin/op/_wrapper.py +0 -121
- bloqade/squin/op/number.py +0 -5
- bloqade/squin/op/rewrite.py +0 -46
- bloqade/squin/op/stdlib.py +0 -62
- bloqade/squin/op/stmts.py +0 -300
- bloqade/squin/op/traits.py +0 -43
- bloqade/squin/op/types.py +0 -128
- bloqade/squin/parallel.py +0 -200
- bloqade/squin/qubit.py +0 -194
- bloqade/squin/rewrite/canonicalize.py +0 -60
- bloqade/squin/rewrite/desugar.py +0 -102
- bloqade/squin/stdlib/channel.py +0 -86
- bloqade/squin/stdlib/gate.py +0 -201
- bloqade/squin/types.py +0 -8
- bloqade/squin/wire.py +0 -201
- bloqade/stim/rewrite/wire_identity_elimination.py +0 -24
- bloqade/stim/rewrite/wire_to_stim.py +0 -57
- {bloqade_circuit-0.7.12.dist-info → bloqade_circuit-0.8.0.dist-info}/WHEEL +0 -0
- {bloqade_circuit-0.7.12.dist-info → bloqade_circuit-0.8.0.dist-info}/licenses/LICENSE +0 -0
bloqade/squin/noise/__init__.py
CHANGED
|
@@ -1,10 +1,2 @@
|
|
|
1
|
-
from . import stmts as stmts
|
|
1
|
+
from . import stmts as stmts, _interface as _interface
|
|
2
2
|
from ._dialect import dialect as dialect
|
|
3
|
-
from ._wrapper import (
|
|
4
|
-
depolarize as depolarize,
|
|
5
|
-
qubit_loss as qubit_loss,
|
|
6
|
-
depolarize2 as depolarize2,
|
|
7
|
-
pauli_error as pauli_error,
|
|
8
|
-
two_qubit_pauli_channel as two_qubit_pauli_channel,
|
|
9
|
-
single_qubit_pauli_channel as single_qubit_pauli_channel,
|
|
10
|
-
)
|
bloqade/squin/noise/_dialect.py
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from typing import Any, Literal, TypeVar
|
|
2
|
+
|
|
3
|
+
from kirin.dialects import ilist
|
|
4
|
+
from kirin.lowering import wraps
|
|
5
|
+
|
|
6
|
+
from bloqade.types import Qubit
|
|
7
|
+
|
|
8
|
+
from . import stmts
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@wraps(stmts.Depolarize)
|
|
12
|
+
def depolarize(p: float, qubits: ilist.IList[Qubit, Any]) -> None: ...
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
N = TypeVar("N", bound=int)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@wraps(stmts.Depolarize2)
|
|
19
|
+
def depolarize2(
|
|
20
|
+
p: float, controls: ilist.IList[Qubit, N], targets: ilist.IList[Qubit, N]
|
|
21
|
+
) -> None: ...
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@wraps(stmts.SingleQubitPauliChannel)
|
|
25
|
+
def single_qubit_pauli_channel(
|
|
26
|
+
px: float, py: float, pz: float, qubits: ilist.IList[Qubit, Any]
|
|
27
|
+
) -> None: ...
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@wraps(stmts.TwoQubitPauliChannel)
|
|
31
|
+
def two_qubit_pauli_channel(
|
|
32
|
+
probabilities: ilist.IList[float, Literal[15]],
|
|
33
|
+
controls: ilist.IList[Qubit, N],
|
|
34
|
+
targets: ilist.IList[Qubit, N],
|
|
35
|
+
) -> None: ...
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@wraps(stmts.QubitLoss)
|
|
39
|
+
def qubit_loss(p: float, qubits: ilist.IList[Qubit, Any]) -> None: ...
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@wraps(stmts.CorrelatedQubitLoss)
|
|
43
|
+
def correlated_qubit_loss(
|
|
44
|
+
p: float, qubits: ilist.IList[ilist.IList[Qubit, N], Any]
|
|
45
|
+
) -> None: ...
|
bloqade/squin/noise/stmts.py
CHANGED
|
@@ -2,74 +2,110 @@ from kirin import ir, types, lowering
|
|
|
2
2
|
from kirin.decl import info, statement
|
|
3
3
|
from kirin.dialects import ilist
|
|
4
4
|
|
|
5
|
+
from bloqade.types import QubitType
|
|
6
|
+
|
|
5
7
|
from ._dialect import dialect
|
|
6
|
-
from ..op.types import OpType, NumOperators, MultiQubitPauliOpType
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
@statement
|
|
10
11
|
class NoiseChannel(ir.Statement):
|
|
11
|
-
traits = frozenset({
|
|
12
|
-
result: ir.ResultValue = info.result(OpType)
|
|
12
|
+
traits = frozenset({lowering.FromPythonCall()})
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
@statement
|
|
16
|
-
class
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
@statement
|
|
16
|
+
class SingleQubitNoiseChannel(NoiseChannel):
|
|
17
|
+
# NOTE: we are not adding e.g. qubits here, since inheriting then will
|
|
18
|
+
# change the order of the wrapper arguments
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@statement
|
|
23
|
+
class TwoQubitNoiseChannel(NoiseChannel):
|
|
24
|
+
pass
|
|
19
25
|
|
|
20
26
|
|
|
21
27
|
@statement(dialect=dialect)
|
|
22
|
-
class
|
|
28
|
+
class SingleQubitPauliChannel(SingleQubitNoiseChannel):
|
|
23
29
|
"""
|
|
24
|
-
|
|
30
|
+
This will apply one of the randomly chosen Pauli operators according to the
|
|
31
|
+
given probabilities (p_x, p_y, p_z).
|
|
25
32
|
"""
|
|
26
33
|
|
|
27
|
-
|
|
34
|
+
px: ir.SSAValue = info.argument(types.Float)
|
|
35
|
+
py: ir.SSAValue = info.argument(types.Float)
|
|
36
|
+
pz: ir.SSAValue = info.argument(types.Float)
|
|
37
|
+
qubits: ir.SSAValue = info.argument(ilist.IListType[QubitType, types.Any])
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
N = types.TypeVar("N", bound=types.Int)
|
|
28
41
|
|
|
29
42
|
|
|
30
43
|
@statement(dialect=dialect)
|
|
31
|
-
class
|
|
44
|
+
class TwoQubitPauliChannel(TwoQubitNoiseChannel):
|
|
32
45
|
"""
|
|
33
|
-
Apply correlated depolarize error to two qubits
|
|
34
|
-
|
|
35
46
|
This will apply one of the randomly chosen Pauli products:
|
|
36
47
|
|
|
37
48
|
{IX, IY, IZ, XI, XX, XY, XZ, YI, YX, YY, YZ, ZI, ZX, ZY, ZZ}
|
|
49
|
+
|
|
50
|
+
but the choice is weighed with the given probability.
|
|
51
|
+
|
|
52
|
+
NOTE: the given parameters are ordered as given in the list above!
|
|
38
53
|
"""
|
|
39
54
|
|
|
40
|
-
|
|
55
|
+
probabilities: ir.SSAValue = info.argument(
|
|
56
|
+
ilist.IListType[QubitType, types.Literal(15)]
|
|
57
|
+
)
|
|
58
|
+
controls: ir.SSAValue = info.argument(ilist.IListType[QubitType, N])
|
|
59
|
+
targets: ir.SSAValue = info.argument(ilist.IListType[QubitType, N])
|
|
41
60
|
|
|
42
61
|
|
|
43
62
|
@statement(dialect=dialect)
|
|
44
|
-
class
|
|
45
|
-
|
|
63
|
+
class Depolarize(SingleQubitNoiseChannel):
|
|
64
|
+
"""
|
|
65
|
+
Apply depolarize error to single qubit.
|
|
66
|
+
|
|
67
|
+
This randomly picks one of the three Pauli operators to apply. Each Pauli
|
|
68
|
+
operator has the probability `p / 3` to be selected. No operator is applied
|
|
69
|
+
with the probability `1 - p`.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
p: ir.SSAValue = info.argument(types.Float)
|
|
73
|
+
qubits: ir.SSAValue = info.argument(ilist.IListType[QubitType, types.Any])
|
|
46
74
|
|
|
47
75
|
|
|
48
76
|
@statement(dialect=dialect)
|
|
49
|
-
class
|
|
77
|
+
class Depolarize2(TwoQubitNoiseChannel):
|
|
50
78
|
"""
|
|
51
|
-
|
|
79
|
+
Apply correlated depolarize error to two qubits
|
|
52
80
|
|
|
53
|
-
|
|
81
|
+
This will apply one of the randomly chosen Pauli products each with probability `p / 15`:
|
|
54
82
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
NOTE: the given parameters are ordered as given in the list above!
|
|
83
|
+
`{IX, IY, IZ, XI, XX, XY, XZ, YI, YX, YY, YZ, ZI, ZX, ZY, ZZ}`
|
|
58
84
|
"""
|
|
59
85
|
|
|
60
|
-
|
|
86
|
+
p: ir.SSAValue = info.argument(types.Float)
|
|
87
|
+
controls: ir.SSAValue = info.argument(ilist.IListType[QubitType, N])
|
|
88
|
+
targets: ir.SSAValue = info.argument(ilist.IListType[QubitType, N])
|
|
61
89
|
|
|
62
90
|
|
|
63
91
|
@statement(dialect=dialect)
|
|
64
|
-
class QubitLoss(
|
|
92
|
+
class QubitLoss(SingleQubitNoiseChannel):
|
|
93
|
+
"""
|
|
94
|
+
Apply an atom loss with channel.
|
|
95
|
+
"""
|
|
96
|
+
|
|
65
97
|
# NOTE: qubit loss error (not supported by Stim)
|
|
66
98
|
p: ir.SSAValue = info.argument(types.Float)
|
|
99
|
+
qubits: ir.SSAValue = info.argument(ilist.IListType[QubitType, types.Any])
|
|
67
100
|
|
|
68
101
|
|
|
69
102
|
@statement(dialect=dialect)
|
|
70
|
-
class
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
103
|
+
class CorrelatedQubitLoss(NoiseChannel):
|
|
104
|
+
"""
|
|
105
|
+
Apply a correlated atom loss channel.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
p: ir.SSAValue = info.argument(types.Float)
|
|
109
|
+
qubits: ir.SSAValue = info.argument(
|
|
110
|
+
ilist.IListType[ilist.IListType[QubitType, N], types.Any]
|
|
74
111
|
)
|
|
75
|
-
result: ir.ResultValue = info.result(OpType)
|
|
@@ -1,47 +1,56 @@
|
|
|
1
1
|
# create rewrite rule name SquinMeasureToStim using kirin
|
|
2
2
|
import math
|
|
3
|
-
from typing import List, Tuple, Callable
|
|
4
3
|
|
|
5
4
|
import numpy as np
|
|
6
5
|
from kirin import ir
|
|
7
6
|
from kirin.dialects import py
|
|
8
7
|
from kirin.rewrite.abc import RewriteRule, RewriteResult
|
|
9
8
|
|
|
10
|
-
from bloqade.squin import
|
|
9
|
+
from bloqade.squin import gate
|
|
11
10
|
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
# Placeholder type, swap in an actual S statement with adjoint=True
|
|
13
|
+
# during the rewrite method
|
|
14
|
+
class Sdag(ir.Statement):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SqrtXdag(ir.Statement):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SqrtYdag(ir.Statement):
|
|
23
|
+
pass
|
|
15
24
|
|
|
16
25
|
|
|
17
26
|
# (theta, phi, lam)
|
|
18
27
|
U3_HALF_PI_ANGLE_TO_GATES: dict[
|
|
19
|
-
tuple[int, int, int],
|
|
28
|
+
tuple[int, int, int], list[type[ir.Statement]] | list[None]
|
|
20
29
|
] = {
|
|
21
|
-
(0, 0, 0):
|
|
22
|
-
(0, 0, 1):
|
|
23
|
-
(0, 0, 2):
|
|
24
|
-
(0, 0, 3):
|
|
25
|
-
(1, 0, 0):
|
|
26
|
-
(1, 0, 1):
|
|
27
|
-
(1, 0, 2):
|
|
28
|
-
(1, 0, 3):
|
|
29
|
-
(1, 1, 0):
|
|
30
|
-
(1, 1, 1):
|
|
31
|
-
(1, 1, 2):
|
|
32
|
-
(1, 1, 3):
|
|
33
|
-
(1, 2, 0):
|
|
34
|
-
(1, 2, 1):
|
|
35
|
-
(1, 2, 2):
|
|
36
|
-
(1, 2, 3):
|
|
37
|
-
(1, 3, 0):
|
|
38
|
-
(1, 3, 1):
|
|
39
|
-
(1, 3, 2):
|
|
40
|
-
(1, 3, 3):
|
|
41
|
-
(2, 0, 0):
|
|
42
|
-
(2, 0, 1):
|
|
43
|
-
(2, 0, 2):
|
|
44
|
-
(2, 0, 3):
|
|
30
|
+
(0, 0, 0): [None],
|
|
31
|
+
(0, 0, 1): [gate.stmts.S],
|
|
32
|
+
(0, 0, 2): [gate.stmts.Z],
|
|
33
|
+
(0, 0, 3): [Sdag],
|
|
34
|
+
(1, 0, 0): [gate.stmts.SqrtY],
|
|
35
|
+
(1, 0, 1): [gate.stmts.S, gate.stmts.SqrtY],
|
|
36
|
+
(1, 0, 2): [gate.stmts.H],
|
|
37
|
+
(1, 0, 3): [Sdag, gate.stmts.SqrtY],
|
|
38
|
+
(1, 1, 0): [gate.stmts.S, SqrtXdag],
|
|
39
|
+
(1, 1, 1): [gate.stmts.Z, SqrtXdag],
|
|
40
|
+
(1, 1, 2): [Sdag, SqrtXdag],
|
|
41
|
+
(1, 1, 3): [SqrtXdag],
|
|
42
|
+
(1, 2, 0): [gate.stmts.Z, SqrtYdag],
|
|
43
|
+
(1, 2, 1): [Sdag, SqrtYdag],
|
|
44
|
+
(1, 2, 2): [SqrtYdag],
|
|
45
|
+
(1, 2, 3): [gate.stmts.S, SqrtYdag],
|
|
46
|
+
(1, 3, 0): [Sdag, gate.stmts.SqrtX],
|
|
47
|
+
(1, 3, 1): [gate.stmts.SqrtX],
|
|
48
|
+
(1, 3, 2): [gate.stmts.S, gate.stmts.SqrtX],
|
|
49
|
+
(1, 3, 3): [gate.stmts.Z, gate.stmts.SqrtX],
|
|
50
|
+
(2, 0, 0): [gate.stmts.Y],
|
|
51
|
+
(2, 0, 1): [gate.stmts.S, gate.stmts.Y],
|
|
52
|
+
(2, 0, 2): [gate.stmts.X],
|
|
53
|
+
(2, 0, 3): [Sdag, gate.stmts.Y],
|
|
45
54
|
}
|
|
46
55
|
|
|
47
56
|
|
|
@@ -61,8 +70,8 @@ class SquinU3ToClifford(RewriteRule):
|
|
|
61
70
|
"""
|
|
62
71
|
|
|
63
72
|
def rewrite_Statement(self, node: ir.Statement) -> RewriteResult:
|
|
64
|
-
if isinstance(node,
|
|
65
|
-
return self.
|
|
73
|
+
if isinstance(node, gate.stmts.U3):
|
|
74
|
+
return self.rewrite_U3(node)
|
|
66
75
|
else:
|
|
67
76
|
return RewriteResult()
|
|
68
77
|
|
|
@@ -87,35 +96,39 @@ class SquinU3ToClifford(RewriteRule):
|
|
|
87
96
|
else:
|
|
88
97
|
return round((angle / math.tau) % 1 * 4) % 4
|
|
89
98
|
|
|
90
|
-
def
|
|
91
|
-
self, node: qubit.Apply | qubit.Broadcast
|
|
92
|
-
) -> RewriteResult:
|
|
99
|
+
def rewrite_U3(self, node: gate.stmts.U3) -> RewriteResult:
|
|
93
100
|
"""
|
|
94
101
|
Rewrite Apply and Broadcast nodes to their clifford equivalent statements.
|
|
95
102
|
"""
|
|
96
|
-
if not isinstance(node.operator.owner, op.stmts.U3):
|
|
97
|
-
return RewriteResult()
|
|
98
103
|
|
|
99
|
-
gates = self.decompose_U3_gates(node
|
|
104
|
+
gates = self.decompose_U3_gates(node)
|
|
100
105
|
|
|
101
106
|
if len(gates) == 0:
|
|
102
107
|
return RewriteResult()
|
|
103
108
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
# Get rid of the U3 gate altogether if it's identity
|
|
110
|
+
if len(gates) == 1 and gates[0] is None:
|
|
111
|
+
node.delete()
|
|
112
|
+
return RewriteResult(has_done_something=True)
|
|
113
|
+
|
|
114
|
+
for gate_stmt in gates:
|
|
115
|
+
if gate_stmt is Sdag:
|
|
116
|
+
new_stmt = gate.stmts.S(adjoint=True, qubits=node.qubits)
|
|
117
|
+
elif gate_stmt is SqrtXdag:
|
|
118
|
+
new_stmt = gate.stmts.SqrtX(adjoint=True, qubits=node.qubits)
|
|
119
|
+
elif gate_stmt is SqrtYdag:
|
|
120
|
+
new_stmt = gate.stmts.SqrtY(adjoint=True, qubits=node.qubits)
|
|
121
|
+
else:
|
|
122
|
+
new_stmt = gate_stmt(qubits=node.qubits)
|
|
123
|
+
new_stmt.insert_before(node)
|
|
112
124
|
|
|
113
125
|
node.delete()
|
|
114
126
|
|
|
115
|
-
# rewrite U3 to clifford gates
|
|
116
127
|
return RewriteResult(has_done_something=True)
|
|
117
128
|
|
|
118
|
-
def decompose_U3_gates(
|
|
129
|
+
def decompose_U3_gates(
|
|
130
|
+
self, node: gate.stmts.U3
|
|
131
|
+
) -> list[type[ir.Statement]] | list[None]:
|
|
119
132
|
"""
|
|
120
133
|
Rewrite U3 statements to clifford gates if possible.
|
|
121
134
|
"""
|
|
@@ -124,7 +137,13 @@ class SquinU3ToClifford(RewriteRule):
|
|
|
124
137
|
lam = self.get_constant(node.lam)
|
|
125
138
|
|
|
126
139
|
if theta is None or phi is None or lam is None:
|
|
127
|
-
return
|
|
140
|
+
return []
|
|
141
|
+
|
|
142
|
+
# Angles will be in units of turns, we convert to radians
|
|
143
|
+
# to allow for the old logic to work
|
|
144
|
+
theta = theta * math.tau
|
|
145
|
+
phi = phi * math.tau
|
|
146
|
+
lam = lam * math.tau
|
|
128
147
|
|
|
129
148
|
# For U3(2*pi*n, phi, lam) = U3(0, 0, lam + phi) which is a Z rotation.
|
|
130
149
|
if np.isclose(np.mod(theta, math.tau), 0):
|
|
@@ -139,13 +158,13 @@ class SquinU3ToClifford(RewriteRule):
|
|
|
139
158
|
lam_half_pi: int | None = self.resolve_angle(lam)
|
|
140
159
|
|
|
141
160
|
if theta_half_pi is None or phi_half_pi is None or lam_half_pi is None:
|
|
142
|
-
return
|
|
161
|
+
return []
|
|
143
162
|
|
|
144
163
|
angles_key = (theta_half_pi, phi_half_pi, lam_half_pi)
|
|
145
164
|
if angles_key not in U3_HALF_PI_ANGLE_TO_GATES:
|
|
146
165
|
angles_key = equivalent_u3_para(*angles_key)
|
|
147
166
|
if angles_key not in U3_HALF_PI_ANGLE_TO_GATES:
|
|
148
|
-
return
|
|
167
|
+
return []
|
|
149
168
|
|
|
150
169
|
gates_stmts = U3_HALF_PI_ANGLE_TO_GATES.get(angles_key)
|
|
151
170
|
|
|
@@ -154,4 +173,4 @@ class SquinU3ToClifford(RewriteRule):
|
|
|
154
173
|
gates_stmts is not None
|
|
155
174
|
), "internal error, U3 gates not found for angles: {}".format(angles_key)
|
|
156
175
|
|
|
157
|
-
return gates_stmts
|
|
176
|
+
return gates_stmts
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
from kirin import ir
|
|
2
2
|
from kirin.rewrite.abc import RewriteRule, RewriteResult
|
|
3
3
|
|
|
4
|
-
from bloqade
|
|
4
|
+
from bloqade import qubit
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class RemoveDeadRegister(RewriteRule):
|
|
8
8
|
|
|
9
9
|
def rewrite_Statement(self, node: ir.Statement) -> RewriteResult:
|
|
10
10
|
|
|
11
|
-
if not isinstance(node, qubit.New):
|
|
11
|
+
if not isinstance(node, qubit.stmts.New):
|
|
12
12
|
return RewriteResult()
|
|
13
13
|
|
|
14
14
|
if bool(node.result.uses):
|
|
@@ -5,12 +5,11 @@ from kirin import ir
|
|
|
5
5
|
from kirin.rewrite.abc import RewriteRule, RewriteResult
|
|
6
6
|
from kirin.print.printer import Printer
|
|
7
7
|
|
|
8
|
-
from bloqade
|
|
8
|
+
from bloqade import qubit
|
|
9
9
|
from bloqade.analysis.address import Address
|
|
10
|
-
from bloqade.squin.analysis.nsites import Sites
|
|
11
10
|
|
|
12
11
|
|
|
13
|
-
@
|
|
12
|
+
@qubit.dialect.register
|
|
14
13
|
@dataclass
|
|
15
14
|
class AddressAttribute(ir.Attribute):
|
|
16
15
|
|
|
@@ -25,21 +24,6 @@ class AddressAttribute(ir.Attribute):
|
|
|
25
24
|
printer.print(self.address)
|
|
26
25
|
|
|
27
26
|
|
|
28
|
-
@op.dialect.register
|
|
29
|
-
@dataclass
|
|
30
|
-
class SitesAttribute(ir.Attribute):
|
|
31
|
-
|
|
32
|
-
name = "Sites"
|
|
33
|
-
sites: Sites
|
|
34
|
-
|
|
35
|
-
def __hash__(self) -> int:
|
|
36
|
-
return hash(self.sites)
|
|
37
|
-
|
|
38
|
-
def print_impl(self, printer: Printer) -> None:
|
|
39
|
-
# Can return to implementing this later
|
|
40
|
-
printer.print(self.sites)
|
|
41
|
-
|
|
42
|
-
|
|
43
27
|
@dataclass
|
|
44
28
|
class WrapAnalysis(RewriteRule):
|
|
45
29
|
|
|
@@ -61,7 +45,8 @@ class WrapAddressAnalysis(WrapAnalysis):
|
|
|
61
45
|
address_analysis: dict[ir.SSAValue, Address]
|
|
62
46
|
|
|
63
47
|
def wrap(self, value: ir.SSAValue) -> bool:
|
|
64
|
-
address_analysis_result
|
|
48
|
+
if (address_analysis_result := self.address_analysis.get(value)) is None:
|
|
49
|
+
return False
|
|
65
50
|
|
|
66
51
|
if value.hints.get("address") is not None:
|
|
67
52
|
return False
|
|
@@ -69,19 +54,3 @@ class WrapAddressAnalysis(WrapAnalysis):
|
|
|
69
54
|
value.hints["address"] = AddressAttribute(address_analysis_result)
|
|
70
55
|
|
|
71
56
|
return True
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
@dataclass
|
|
75
|
-
class WrapOpSiteAnalysis(WrapAnalysis):
|
|
76
|
-
|
|
77
|
-
op_site_analysis: dict[ir.SSAValue, Sites]
|
|
78
|
-
|
|
79
|
-
def wrap(self, value: ir.SSAValue) -> bool:
|
|
80
|
-
op_site_analysis_result = self.op_site_analysis[value]
|
|
81
|
-
|
|
82
|
-
if value.hints.get("sites") is not None:
|
|
83
|
-
return False
|
|
84
|
-
|
|
85
|
-
value.hints["sites"] = SitesAttribute(op_site_analysis_result)
|
|
86
|
-
|
|
87
|
-
return True
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from .gate import (
|
|
2
|
+
h as h,
|
|
3
|
+
s as s,
|
|
4
|
+
t as t,
|
|
5
|
+
x as x,
|
|
6
|
+
y as y,
|
|
7
|
+
z as z,
|
|
8
|
+
cx as cx,
|
|
9
|
+
cy as cy,
|
|
10
|
+
cz as cz,
|
|
11
|
+
rx as rx,
|
|
12
|
+
ry as ry,
|
|
13
|
+
rz as rz,
|
|
14
|
+
u3 as u3,
|
|
15
|
+
s_adj as s_adj,
|
|
16
|
+
shift as shift,
|
|
17
|
+
t_adj as t_adj,
|
|
18
|
+
sqrt_x as sqrt_x,
|
|
19
|
+
sqrt_y as sqrt_y,
|
|
20
|
+
sqrt_z as sqrt_z,
|
|
21
|
+
sqrt_x_adj as sqrt_x_adj,
|
|
22
|
+
sqrt_y_adj as sqrt_y_adj,
|
|
23
|
+
sqrt_z_adj as sqrt_z_adj,
|
|
24
|
+
)
|
|
25
|
+
from .noise import (
|
|
26
|
+
bit_flip as bit_flip,
|
|
27
|
+
depolarize as depolarize,
|
|
28
|
+
qubit_loss as qubit_loss,
|
|
29
|
+
depolarize2 as depolarize2,
|
|
30
|
+
correlated_qubit_loss as correlated_qubit_loss,
|
|
31
|
+
two_qubit_pauli_channel as two_qubit_pauli_channel,
|
|
32
|
+
single_qubit_pauli_channel as single_qubit_pauli_channel,
|
|
33
|
+
)
|
|
34
|
+
from ._qubit import reset as reset, measure as measure
|