bloqade-circuit 0.3.0__py3-none-any.whl → 0.4.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.
Files changed (69) hide show
  1. bloqade/analysis/address/impls.py +3 -16
  2. bloqade/pyqrack/__init__.py +1 -1
  3. bloqade/pyqrack/noise/native.py +8 -8
  4. bloqade/pyqrack/squin/noise/__init__.py +1 -0
  5. bloqade/pyqrack/squin/noise/native.py +72 -0
  6. bloqade/pyqrack/squin/op.py +7 -0
  7. bloqade/pyqrack/squin/qubit.py +0 -29
  8. bloqade/pyqrack/squin/runtime.py +18 -0
  9. bloqade/pyqrack/squin/wire.py +0 -36
  10. bloqade/{noise/native → qasm2/dialects/noise}/__init__.py +1 -7
  11. bloqade/qasm2/dialects/noise/_dialect.py +3 -0
  12. bloqade/{noise → qasm2/dialects/noise}/fidelity.py +2 -2
  13. bloqade/qasm2/dialects/noise/model.py +278 -0
  14. bloqade/qasm2/emit/impls/__init__.py +1 -1
  15. bloqade/qasm2/emit/impls/{noise_native.py → noise.py} +11 -11
  16. bloqade/qasm2/emit/main.py +2 -4
  17. bloqade/qasm2/emit/target.py +3 -3
  18. bloqade/qasm2/groups.py +0 -2
  19. bloqade/{noise/native/_wrappers.py → qasm2/noise.py} +9 -5
  20. bloqade/qasm2/passes/glob.py +12 -8
  21. bloqade/qasm2/passes/noise.py +5 -14
  22. bloqade/qasm2/rewrite/__init__.py +2 -0
  23. bloqade/qasm2/rewrite/noise/__init__.py +0 -0
  24. bloqade/qasm2/rewrite/{heuristic_noise.py → noise/heuristic_noise.py} +31 -53
  25. bloqade/{noise/native/rewrite.py → qasm2/rewrite/noise/remove_noise.py} +2 -2
  26. bloqade/qbraid/lowering.py +8 -8
  27. bloqade/squin/__init__.py +16 -1
  28. bloqade/squin/analysis/nsites/impls.py +0 -9
  29. bloqade/squin/cirq/__init__.py +89 -0
  30. bloqade/squin/cirq/lowering.py +303 -0
  31. bloqade/squin/groups.py +7 -7
  32. bloqade/squin/lowering.py +27 -0
  33. bloqade/squin/noise/__init__.py +3 -1
  34. bloqade/squin/noise/_wrapper.py +7 -3
  35. bloqade/squin/noise/rewrite.py +111 -0
  36. bloqade/squin/noise/stmts.py +21 -16
  37. bloqade/squin/op/__init__.py +1 -0
  38. bloqade/squin/op/_wrapper.py +4 -0
  39. bloqade/squin/op/stmts.py +10 -11
  40. bloqade/squin/op/types.py +2 -0
  41. bloqade/squin/qubit.py +32 -37
  42. bloqade/squin/rewrite/desugar.py +65 -0
  43. bloqade/squin/rewrite/qubit_to_stim.py +0 -23
  44. bloqade/squin/rewrite/squin_measure.py +2 -27
  45. bloqade/squin/rewrite/stim_rewrite_util.py +3 -8
  46. bloqade/squin/rewrite/wire_to_stim.py +0 -21
  47. bloqade/squin/wire.py +4 -9
  48. bloqade/stim/__init__.py +2 -1
  49. bloqade/stim/_wrappers.py +4 -0
  50. bloqade/stim/dialects/auxiliary/__init__.py +1 -0
  51. bloqade/stim/dialects/auxiliary/emit.py +17 -2
  52. bloqade/stim/dialects/auxiliary/stmts/__init__.py +1 -0
  53. bloqade/stim/dialects/auxiliary/stmts/annotate.py +8 -0
  54. bloqade/stim/dialects/collapse/emit_str.py +3 -1
  55. bloqade/stim/dialects/gate/emit.py +9 -2
  56. bloqade/stim/dialects/noise/emit.py +32 -1
  57. bloqade/stim/dialects/noise/stmts.py +29 -0
  58. bloqade/stim/parse/__init__.py +1 -0
  59. bloqade/stim/parse/lowering.py +686 -0
  60. {bloqade_circuit-0.3.0.dist-info → bloqade_circuit-0.4.1.dist-info}/METADATA +3 -1
  61. {bloqade_circuit-0.3.0.dist-info → bloqade_circuit-0.4.1.dist-info}/RECORD +64 -57
  62. bloqade/noise/__init__.py +0 -2
  63. bloqade/noise/native/_dialect.py +0 -3
  64. bloqade/noise/native/model.py +0 -346
  65. bloqade/qasm2/dialects/noise.py +0 -48
  66. bloqade/squin/rewrite/measure_desugar.py +0 -33
  67. /bloqade/{noise/native → qasm2/dialects/noise}/stmts.py +0 -0
  68. {bloqade_circuit-0.3.0.dist-info → bloqade_circuit-0.4.1.dist-info}/WHEEL +0 -0
  69. {bloqade_circuit-0.3.0.dist-info → bloqade_circuit-0.4.1.dist-info}/licenses/LICENSE +0 -0
@@ -3,12 +3,12 @@ from typing import Any
3
3
  from kirin import interp
4
4
  from kirin.dialects import ilist
5
5
 
6
- from bloqade.noise import native
7
6
  from bloqade.qasm2.parse import ast
7
+ from bloqade.qasm2.dialects import noise
8
8
  from bloqade.qasm2.emit.gate import EmitQASM2Gate, EmitQASM2Frame
9
9
 
10
10
 
11
- @native.dialect.register(key="emit.qasm2.gate")
11
+ @noise.dialect.register(key="emit.qasm2.gate")
12
12
  class NativeNoise(interp.MethodTable):
13
13
 
14
14
  def _convert(self, node: ast.Bit | ast.Name) -> str:
@@ -17,12 +17,12 @@ class NativeNoise(interp.MethodTable):
17
17
  else:
18
18
  return f"{node.id}"
19
19
 
20
- @interp.impl(native.CZPauliChannel)
20
+ @interp.impl(noise.CZPauliChannel)
21
21
  def emit_czp(
22
22
  self,
23
23
  emit: EmitQASM2Gate,
24
24
  frame: EmitQASM2Frame,
25
- stmt: native.CZPauliChannel,
25
+ stmt: noise.CZPauliChannel,
26
26
  ):
27
27
  paired: bool = stmt.paired
28
28
  px_ctrl: float = stmt.px_ctrl
@@ -35,7 +35,7 @@ class NativeNoise(interp.MethodTable):
35
35
  qargs: ilist.IList[ast.Bit, Any] = frame.get(stmt.qargs)
36
36
  frame.body.append(
37
37
  ast.Comment(
38
- text=f"native.CZPauliChannel(paired={paired}, p_ctrl=[x:{px_ctrl}, y:{py_ctrl}, z:{pz_ctrl}], p_qarg[x:{px_qarg}, y:{py_qarg}, z:{pz_qarg}])"
38
+ text=f"noise.CZPauliChannel(paired={paired}, p_ctrl=[x:{px_ctrl}, y:{py_ctrl}, z:{pz_ctrl}], p_qarg[x:{px_qarg}, y:{py_qarg}, z:{pz_qarg}])"
39
39
  )
40
40
  )
41
41
  frame.body.append(
@@ -50,16 +50,16 @@ class NativeNoise(interp.MethodTable):
50
50
  )
51
51
  return ()
52
52
 
53
- @interp.impl(native.AtomLossChannel)
53
+ @interp.impl(noise.AtomLossChannel)
54
54
  def emit_loss(
55
55
  self,
56
56
  emit: EmitQASM2Gate,
57
57
  frame: EmitQASM2Frame,
58
- stmt: native.AtomLossChannel,
58
+ stmt: noise.AtomLossChannel,
59
59
  ):
60
60
  prob: float = stmt.prob
61
61
  qargs: ilist.IList[ast.Bit, Any] = frame.get(stmt.qargs)
62
- frame.body.append(ast.Comment(text=f"native.Atomloss(p={prob})"))
62
+ frame.body.append(ast.Comment(text=f"noise.Atomloss(p={prob})"))
63
63
  frame.body.append(
64
64
  ast.Comment(
65
65
  text=f" -: qargs: {', '.join([self._convert(q) for q in qargs])}"
@@ -67,19 +67,19 @@ class NativeNoise(interp.MethodTable):
67
67
  )
68
68
  return ()
69
69
 
70
- @interp.impl(native.PauliChannel)
70
+ @interp.impl(noise.PauliChannel)
71
71
  def emit_pauli(
72
72
  self,
73
73
  emit: EmitQASM2Gate,
74
74
  frame: EmitQASM2Frame,
75
- stmt: native.PauliChannel,
75
+ stmt: noise.PauliChannel,
76
76
  ):
77
77
  px: float = stmt.px
78
78
  py: float = stmt.py
79
79
  pz: float = stmt.pz
80
80
  qargs: ilist.IList[ast.Bit, Any] = frame.get(stmt.qargs)
81
81
  frame.body.append(
82
- ast.Comment(text=f"native.PauliChannel(px={px}, py={py}, pz={pz})")
82
+ ast.Comment(text=f"noise.PauliChannel(px={px}, py={py}, pz={pz})")
83
83
  )
84
84
  frame.body.append(
85
85
  ast.Comment(
@@ -25,12 +25,10 @@ class Func(interp.MethodTable):
25
25
  def emit_func(
26
26
  self, emit: EmitQASM2Main, frame: EmitQASM2Frame, stmt: func.Function
27
27
  ):
28
- from bloqade.qasm2.dialects import glob, noise, parallel
28
+ from bloqade.qasm2.dialects import glob, parallel
29
29
 
30
30
  emit.run_ssacfg_region(frame, stmt.body, ())
31
- if emit.dialects.data.intersection(
32
- (parallel.dialect, glob.dialect, noise.dialect)
33
- ):
31
+ if emit.dialects.data.intersection((parallel.dialect, glob.dialect)):
34
32
  header = ast.Kirin([dialect.name for dialect in emit.dialects])
35
33
  else:
36
34
  header = ast.OPENQASM(ast.Version(2, 0))
@@ -57,7 +57,7 @@ class QASM2:
57
57
 
58
58
 
59
59
  """
60
- from bloqade import noise, qasm2
60
+ from bloqade import qasm2
61
61
 
62
62
  self.main_target = qasm2.main
63
63
  self.gate_target = qasm2.gate
@@ -77,8 +77,8 @@ class QASM2:
77
77
  self.gate_target = self.gate_target.add(qasm2.dialects.glob)
78
78
 
79
79
  if allow_noise:
80
- self.main_target = self.main_target.add(noise.native)
81
- self.gate_target = self.gate_target.add(noise.native)
80
+ self.main_target = self.main_target.add(qasm2.dialects.noise)
81
+ self.gate_target = self.gate_target.add(qasm2.dialects.noise)
82
82
 
83
83
  if allow_global or allow_parallel or allow_noise:
84
84
  self.main_target = self.main_target.add(ilist)
bloqade/qasm2/groups.py CHANGED
@@ -2,7 +2,6 @@ from kirin import ir, passes
2
2
  from kirin.prelude import structural_no_opt
3
3
  from kirin.dialects import scf, func, ilist, lowering
4
4
 
5
- from bloqade.noise import native
6
5
  from bloqade.qasm2.dialects import (
7
6
  uop,
8
7
  core,
@@ -91,7 +90,6 @@ def main(self):
91
90
  noise,
92
91
  parallel,
93
92
  core,
94
- native,
95
93
  ]
96
94
  )
97
95
  )
@@ -3,11 +3,15 @@ from typing import Any
3
3
  from kirin.dialects import ilist
4
4
  from kirin.lowering import wraps
5
5
 
6
- from bloqade.noise import native
7
- from bloqade.qasm2.types import Qubit
6
+ from .types import Qubit
7
+ from .dialects import noise
8
+ from .dialects.noise import (
9
+ TwoRowZoneModel as TwoRowZoneModel,
10
+ MoveNoiseModelABC as MoveNoiseModelABC,
11
+ )
8
12
 
9
13
 
10
- @wraps(native.AtomLossChannel)
14
+ @wraps(noise.AtomLossChannel)
11
15
  def atom_loss_channel(qargs: ilist.IList[Qubit, Any] | list, *, prob: float) -> None:
12
16
  """Apply an atom loss channel to a list of qubits.
13
17
 
@@ -18,7 +22,7 @@ def atom_loss_channel(qargs: ilist.IList[Qubit, Any] | list, *, prob: float) ->
18
22
  ...
19
23
 
20
24
 
21
- @wraps(native.PauliChannel)
25
+ @wraps(noise.PauliChannel)
22
26
  def pauli_channel(
23
27
  qargs: ilist.IList[Qubit, Any] | list, *, px: float, py: float, pz: float
24
28
  ) -> None:
@@ -32,7 +36,7 @@ def pauli_channel(
32
36
  """
33
37
 
34
38
 
35
- @wraps(native.CZPauliChannel)
39
+ @wraps(noise.CZPauliChannel)
36
40
  def cz_pauli_channel(
37
41
  ctrls: ilist.IList[Qubit, Any] | list,
38
42
  qargs: ilist.IList[Qubit, Any] | list,
@@ -58,13 +58,15 @@ class GlobalToUOP(Pass):
58
58
  rewriter = walk.Walk(self.generate_rule(mt))
59
59
  result = rewriter.rewrite(mt.code)
60
60
 
61
- result = walk.Walk(dce.DeadCodeElimination()).rewrite(mt.code)
62
- result = Fixpoint(walk.Walk(rule=cse.CommonSubexpressionElimination())).rewrite(
63
- mt.code
61
+ result = walk.Walk(dce.DeadCodeElimination()).rewrite(mt.code).join(result)
62
+ result = (
63
+ Fixpoint(walk.Walk(rule=cse.CommonSubexpressionElimination()))
64
+ .rewrite(mt.code)
65
+ .join(result)
64
66
  )
65
67
 
66
68
  # do fold again to get proper hint for inserted const
67
- result = Fold(mt.dialects)(mt)
69
+ result = Fold(mt.dialects)(mt).join(result)
68
70
  return result
69
71
 
70
72
 
@@ -110,10 +112,12 @@ class GlobalToParallel(Pass):
110
112
  rewriter = walk.Walk(self.generate_rule(mt))
111
113
  result = rewriter.rewrite(mt.code)
112
114
 
113
- result = walk.Walk(dce.DeadCodeElimination()).rewrite(mt.code)
114
- result = Fixpoint(walk.Walk(rule=cse.CommonSubexpressionElimination())).rewrite(
115
- mt.code
115
+ result = walk.Walk(dce.DeadCodeElimination()).rewrite(mt.code).join(result)
116
+ result = (
117
+ Fixpoint(walk.Walk(rule=cse.CommonSubexpressionElimination()))
118
+ .rewrite(mt.code)
119
+ .join(result)
116
120
  )
117
121
  # do fold again to get proper hint
118
- result = Fold(mt.dialects)(mt)
122
+ result = Fold(mt.dialects)(mt).join(result)
119
123
  return result
@@ -8,10 +8,10 @@ from kirin.rewrite import (
8
8
  DeadCodeElimination,
9
9
  )
10
10
 
11
- from bloqade.noise import native
11
+ from bloqade.qasm2 import noise
12
12
  from bloqade.analysis import address
13
+ from bloqade.qasm2.rewrite import NoiseRewriteRule
13
14
  from bloqade.qasm2.passes.lift_qubits import LiftQubits
14
- from bloqade.qasm2.rewrite.heuristic_noise import NoiseRewriteRule
15
15
 
16
16
 
17
17
  @dataclass
@@ -25,12 +25,9 @@ class NoisePass(Pass):
25
25
 
26
26
  ```
27
27
  from bloqade import qasm2
28
- from bloqade.noise import native
29
- from bloqade.qasm2.passes.noise import NoisePass
28
+ from bloqade.qasm2.passes import NoisePass
30
29
 
31
- noise_main = qasm2.extended.add(native.dialect)
32
-
33
- @noise_main
30
+ @qasm2.extended
34
31
  def main():
35
32
  q = qasm2.qreg(2)
36
33
  qasm2.h(q[0])
@@ -51,12 +48,7 @@ class NoisePass(Pass):
51
48
 
52
49
  """
53
50
 
54
- noise_model: native.MoveNoiseModelABC = field(
55
- default_factory=native.TwoRowZoneModel
56
- )
57
- gate_noise_params: native.GateNoiseParams = field(
58
- default_factory=native.GateNoiseParams
59
- )
51
+ noise_model: noise.MoveNoiseModelABC = field(default_factory=noise.TwoRowZoneModel)
60
52
  address_analysis: address.AddressAnalysis = field(init=False)
61
53
 
62
54
  def __post_init__(self):
@@ -89,7 +81,6 @@ class NoisePass(Pass):
89
81
  qubit_ssa_value=qubit_ssa_value,
90
82
  address_analysis=address_analysis,
91
83
  noise_model=self.noise_model,
92
- gate_noise_params=self.gate_noise_params,
93
84
  ),
94
85
  reverse=True,
95
86
  )
@@ -11,3 +11,5 @@ from .uop_to_parallel import (
11
11
  SimpleGreedyMergePolicy as SimpleGreedyMergePolicy,
12
12
  SimpleOptimalMergePolicy as SimpleOptimalMergePolicy,
13
13
  )
14
+ from .noise.remove_noise import RemoveNoisePass as RemoveNoisePass
15
+ from .noise.heuristic_noise import NoiseRewriteRule as NoiseRewriteRule
File without changes
@@ -5,9 +5,8 @@ from kirin import ir
5
5
  from kirin.rewrite import abc as rewrite_abc
6
6
  from kirin.dialects import ilist
7
7
 
8
- from bloqade.noise import native
9
8
  from bloqade.analysis import address
10
- from bloqade.qasm2.dialects import uop, glob, parallel
9
+ from bloqade.qasm2.dialects import uop, glob, noise, parallel
11
10
 
12
11
 
13
12
  @dataclass
@@ -19,12 +18,7 @@ class NoiseRewriteRule(rewrite_abc.RewriteRule):
19
18
 
20
19
  address_analysis: Dict[ir.SSAValue, address.Address]
21
20
  qubit_ssa_value: Dict[int, ir.SSAValue]
22
- gate_noise_params: native.GateNoiseParams = field(
23
- default_factory=native.GateNoiseParams
24
- )
25
- noise_model: native.MoveNoiseModelABC = field(
26
- default_factory=native.TwoRowZoneModel
27
- )
21
+ noise_model: noise.MoveNoiseModelABC = field(default_factory=noise.TwoRowZoneModel)
28
22
 
29
23
  def rewrite_Statement(self, node: ir.Statement) -> rewrite_abc.RewriteResult:
30
24
  if isinstance(node, uop.SingleQubitGate):
@@ -46,22 +40,18 @@ class NoiseRewriteRule(rewrite_abc.RewriteRule):
46
40
  qargs: ir.SSAValue,
47
41
  probs: Tuple[float, float, float, float],
48
42
  ):
49
- native.PauliChannel(qargs, px=probs[0], py=probs[1], pz=probs[2]).insert_before(
43
+ noise.PauliChannel(qargs, px=probs[0], py=probs[1], pz=probs[2]).insert_before(
50
44
  node
51
45
  )
52
- native.AtomLossChannel(qargs, prob=probs[3]).insert_before(node)
46
+ noise.AtomLossChannel(qargs, prob=probs[3]).insert_before(node)
53
47
 
54
48
  return rewrite_abc.RewriteResult(has_done_something=True)
55
49
 
56
50
  def rewrite_single_qubit_gate(self, node: uop.SingleQubitGate):
57
- probs = (
58
- self.gate_noise_params.local_px,
59
- self.gate_noise_params.local_py,
60
- self.gate_noise_params.local_pz,
61
- self.gate_noise_params.local_loss_prob,
62
- )
63
51
  (qargs := ilist.New(values=(node.qarg,))).insert_before(node)
64
- return self.insert_single_qubit_noise(node, qargs.result, probs)
52
+ return self.insert_single_qubit_noise(
53
+ node, qargs.result, self.noise_model.local_errors
54
+ )
65
55
 
66
56
  def rewrite_global_single_qubit_gate(self, node: glob.UGate):
67
57
  addrs = self.address_analysis[node.registers]
@@ -77,14 +67,10 @@ class NoiseRewriteRule(rewrite_abc.RewriteRule):
77
67
  for qid in addr.data:
78
68
  qargs.append(self.qubit_ssa_value[qid])
79
69
 
80
- probs = (
81
- self.gate_noise_params.global_px,
82
- self.gate_noise_params.global_py,
83
- self.gate_noise_params.global_pz,
84
- self.gate_noise_params.global_loss_prob,
85
- )
86
70
  (qargs := ilist.New(values=tuple(qargs))).insert_before(node)
87
- return self.insert_single_qubit_noise(node, qargs.result, probs)
71
+ return self.insert_single_qubit_noise(
72
+ node, qargs.result, self.noise_model.global_errors
73
+ )
88
74
 
89
75
  def rewrite_parallel_single_qubit_gate(self, node: parallel.RZ | parallel.UGate):
90
76
  addrs = self.address_analysis[node.qargs]
@@ -94,15 +80,11 @@ class NoiseRewriteRule(rewrite_abc.RewriteRule):
94
80
  if not all(isinstance(addr, address.AddressQubit) for addr in addrs.data):
95
81
  return rewrite_abc.RewriteResult()
96
82
 
97
- probs = (
98
- self.gate_noise_params.local_px,
99
- self.gate_noise_params.local_py,
100
- self.gate_noise_params.local_pz,
101
- self.gate_noise_params.local_loss_prob,
102
- )
103
83
  assert isinstance(node.qargs, ir.ResultValue)
104
84
  assert isinstance(node.qargs.stmt, ilist.New)
105
- return self.insert_single_qubit_noise(node, node.qargs, probs)
85
+ return self.insert_single_qubit_noise(
86
+ node, node.qargs, self.noise_model.local_errors
87
+ )
106
88
 
107
89
  def move_noise_stmts(
108
90
  self,
@@ -118,9 +100,9 @@ class NoiseRewriteRule(rewrite_abc.RewriteRule):
118
100
  nodes.append(
119
101
  qargs := ilist.New(tuple(self.qubit_ssa_value[q] for q in qubits))
120
102
  )
121
- nodes.append(native.AtomLossChannel(qargs.result, prob=probs[3]))
103
+ nodes.append(noise.AtomLossChannel(qargs.result, prob=probs[3]))
122
104
  nodes.append(
123
- native.PauliChannel(qargs.result, px=probs[0], py=probs[1], pz=probs[2])
105
+ noise.PauliChannel(qargs.result, px=probs[0], py=probs[1], pz=probs[2])
124
106
  )
125
107
 
126
108
  return nodes
@@ -131,34 +113,30 @@ class NoiseRewriteRule(rewrite_abc.RewriteRule):
131
113
  qargs: ir.SSAValue,
132
114
  ) -> list[ir.Statement]:
133
115
  return [
134
- native.CZPauliChannel(
116
+ noise.CZPauliChannel(
135
117
  ctrls,
136
118
  qargs,
137
- px_ctrl=self.gate_noise_params.cz_paired_gate_px,
138
- py_ctrl=self.gate_noise_params.cz_paired_gate_py,
139
- pz_ctrl=self.gate_noise_params.cz_paired_gate_pz,
140
- px_qarg=self.gate_noise_params.cz_paired_gate_px,
141
- py_qarg=self.gate_noise_params.cz_paired_gate_py,
142
- pz_qarg=self.gate_noise_params.cz_paired_gate_pz,
119
+ px_ctrl=self.noise_model.cz_paired_gate_px,
120
+ py_ctrl=self.noise_model.cz_paired_gate_py,
121
+ pz_ctrl=self.noise_model.cz_paired_gate_pz,
122
+ px_qarg=self.noise_model.cz_paired_gate_px,
123
+ py_qarg=self.noise_model.cz_paired_gate_py,
124
+ pz_qarg=self.noise_model.cz_paired_gate_pz,
143
125
  paired=True,
144
126
  ),
145
- native.CZPauliChannel(
127
+ noise.CZPauliChannel(
146
128
  ctrls,
147
129
  qargs,
148
- px_ctrl=self.gate_noise_params.cz_unpaired_gate_px,
149
- py_ctrl=self.gate_noise_params.cz_unpaired_gate_py,
150
- pz_ctrl=self.gate_noise_params.cz_unpaired_gate_pz,
151
- px_qarg=self.gate_noise_params.cz_unpaired_gate_px,
152
- py_qarg=self.gate_noise_params.cz_unpaired_gate_py,
153
- pz_qarg=self.gate_noise_params.cz_unpaired_gate_pz,
130
+ px_ctrl=self.noise_model.cz_unpaired_gate_px,
131
+ py_ctrl=self.noise_model.cz_unpaired_gate_py,
132
+ pz_ctrl=self.noise_model.cz_unpaired_gate_pz,
133
+ px_qarg=self.noise_model.cz_unpaired_gate_px,
134
+ py_qarg=self.noise_model.cz_unpaired_gate_py,
135
+ pz_qarg=self.noise_model.cz_unpaired_gate_pz,
154
136
  paired=False,
155
137
  ),
156
- native.AtomLossChannel(
157
- ctrls, prob=self.gate_noise_params.cz_gate_loss_prob
158
- ),
159
- native.AtomLossChannel(
160
- qargs, prob=self.gate_noise_params.cz_gate_loss_prob
161
- ),
138
+ noise.AtomLossChannel(ctrls, prob=self.noise_model.cz_gate_loss_prob),
139
+ noise.AtomLossChannel(qargs, prob=self.noise_model.cz_gate_loss_prob),
162
140
  ]
163
141
 
164
142
  def rewrite_cz_gate(self, node: uop.CZ):
@@ -4,8 +4,8 @@ from kirin import ir
4
4
  from kirin.rewrite import abc, dce, walk, fixpoint
5
5
  from kirin.passes.abc import Pass
6
6
 
7
- from .stmts import PauliChannel, CZPauliChannel, AtomLossChannel
8
- from ._dialect import dialect
7
+ from ...dialects.noise.stmts import PauliChannel, CZPauliChannel, AtomLossChannel
8
+ from ...dialects.noise._dialect import dialect
9
9
 
10
10
 
11
11
  class RemoveNoiseRewrite(abc.RewriteRule):
@@ -4,13 +4,13 @@ from dataclasses import field, dataclass
4
4
  from kirin import ir, types, passes
5
5
  from kirin.dialects import func, ilist
6
6
 
7
- from bloqade import noise, qasm2
7
+ from bloqade import qasm2
8
8
  from bloqade.qbraid import schema
9
- from bloqade.qasm2.dialects import glob, parallel
9
+ from bloqade.qasm2.dialects import glob, noise, parallel
10
10
 
11
11
 
12
12
  @ir.dialect_group(
13
- [func, qasm2.core, qasm2.uop, parallel, glob, qasm2.expr, noise.native, ilist]
13
+ [func, qasm2.core, qasm2.uop, parallel, glob, qasm2.expr, noise, ilist]
14
14
  )
15
15
  def qbraid_noise(
16
16
  self,
@@ -192,7 +192,7 @@ class Lowering:
192
192
  qargs := ilist.New(values=tuple(self.qubit_id_map[q] for q in qubits))
193
193
  )
194
194
  self.block_list.append(
195
- noise.native.PauliChannel(px=px, py=py, pz=pz, qargs=qargs.result)
195
+ noise.PauliChannel(px=px, py=py, pz=pz, qargs=qargs.result)
196
196
  )
197
197
 
198
198
  for (p_ctrl, p_qarg), qubits in paired_layers.items():
@@ -204,7 +204,7 @@ class Lowering:
204
204
  qargs := ilist.New(values=tuple(self.qubit_id_map[q] for q in qargs))
205
205
  )
206
206
  self.block_list.append(
207
- noise.native.CZPauliChannel(
207
+ noise.CZPauliChannel(
208
208
  paired=True,
209
209
  px_ctrl=p_ctrl[0],
210
210
  py_ctrl=p_ctrl[1],
@@ -226,7 +226,7 @@ class Lowering:
226
226
  qargs := ilist.New(values=tuple(self.qubit_id_map[q] for q in qargs))
227
227
  )
228
228
  self.block_list.append(
229
- noise.native.CZPauliChannel(
229
+ noise.CZPauliChannel(
230
230
  paired=False,
231
231
  px_ctrl=p_ctrl[0],
232
232
  py_ctrl=p_ctrl[1],
@@ -285,7 +285,7 @@ class Lowering:
285
285
  qargs := ilist.New(values=tuple(self.qubit_id_map[q] for q in qubits))
286
286
  )
287
287
  self.block_list.append(
288
- noise.native.PauliChannel(px=px, py=py, pz=pz, qargs=qargs.result)
288
+ noise.PauliChannel(px=px, py=py, pz=pz, qargs=qargs.result)
289
289
  )
290
290
 
291
291
  def lower_measurement(self, operation: schema.Measurement):
@@ -303,7 +303,7 @@ class Lowering:
303
303
  for survival_prob, qubits in layers.items():
304
304
  self.block_list.append(qargs := ilist.New(values=qubits))
305
305
  self.block_list.append(
306
- noise.native.AtomLossChannel(prob=survival_prob, qargs=qargs.result)
306
+ noise.AtomLossChannel(prob=survival_prob, qargs=qargs.result)
307
307
  )
308
308
 
309
309
  def lower_number(self, value: float | int) -> ir.SSAValue:
bloqade/squin/__init__.py CHANGED
@@ -1,2 +1,17 @@
1
- from . import op as op, wire as wire, noise as noise, qubit as qubit
1
+ from . import (
2
+ op as op,
3
+ wire as wire,
4
+ noise as noise,
5
+ qubit as qubit,
6
+ lowering as lowering,
7
+ )
2
8
  from .groups import wired as wired, kernel as kernel
9
+
10
+ try:
11
+ # NOTE: make sure optional cirq dependency is installed
12
+ import cirq as cirq_package # noqa: F401
13
+ except ImportError:
14
+ pass
15
+ else:
16
+ from . import cirq as cirq
17
+ from .cirq import load_circuit as load_circuit
@@ -23,15 +23,6 @@ class SquinWire(interp.MethodTable):
23
23
 
24
24
  return tuple(frame.get(input) for input in stmt.inputs)
25
25
 
26
- @interp.impl(wire.MeasureAndReset)
27
- def measure_and_reset(
28
- self, interp: NSitesAnalysis, frame: interp.Frame, stmt: wire.MeasureAndReset
29
- ):
30
-
31
- # MeasureAndReset produces both a new wire
32
- # and an integer which don't have any sites at all
33
- return (NoSites(), NoSites())
34
-
35
26
 
36
27
  @op.dialect.register(key="op.nsites")
37
28
  class SquinOp(interp.MethodTable):
@@ -0,0 +1,89 @@
1
+ from typing import Any
2
+
3
+ import cirq
4
+ from kirin import ir, types
5
+ from kirin.dialects import func
6
+
7
+ from . import lowering as lowering
8
+ from .. import kernel
9
+ from .lowering import Squin
10
+
11
+
12
+ def load_circuit(
13
+ circuit: cirq.Circuit,
14
+ kernel_name: str = "main",
15
+ dialects: ir.DialectGroup = kernel,
16
+ globals: dict[str, Any] | None = None,
17
+ file: str | None = None,
18
+ lineno_offset: int = 0,
19
+ col_offset: int = 0,
20
+ compactify: bool = True,
21
+ ):
22
+ """Converts a cirq.Circuit object into a squin kernel.
23
+
24
+ Args:
25
+ circuit (cirq.Circuit): The circuit to load.
26
+
27
+ Keyword Args:
28
+ kernel_name (str): The name of the kernel to load. Defaults to "main".
29
+ dialects (ir.DialectGroup | None): The dialects to use. Defaults to `squin.kernel`.
30
+ globals (dict[str, Any] | None): The global variables to use. Defaults to None.
31
+ file (str | None): The file name for error reporting. Defaults to None.
32
+ lineno_offset (int): The line number offset for error reporting. Defaults to 0.
33
+ col_offset (int): The column number offset for error reporting. Defaults to 0.
34
+ compactify (bool): Whether to compactify the output. Defaults to True.
35
+
36
+ Example:
37
+
38
+ ```python
39
+ # from cirq's "hello qubit" example
40
+ import cirq
41
+ from bloqade import squin
42
+
43
+ # Pick a qubit.
44
+ qubit = cirq.GridQubit(0, 0)
45
+
46
+ # Create a circuit.
47
+ circuit = cirq.Circuit(
48
+ cirq.X(qubit)**0.5, # Square root of NOT.
49
+ cirq.measure(qubit, key='m') # Measurement.
50
+ )
51
+
52
+ # load the circuit as squin
53
+ main = squin.load_circuit(circuit)
54
+
55
+ # print the resulting IR
56
+ main.print()
57
+ ```
58
+ """
59
+
60
+ target = Squin(dialects=dialects, circuit=circuit)
61
+ body = target.run(
62
+ circuit,
63
+ source=str(circuit), # TODO: proper source string
64
+ file=file,
65
+ globals=globals,
66
+ lineno_offset=lineno_offset,
67
+ col_offset=col_offset,
68
+ compactify=compactify,
69
+ )
70
+
71
+ # NOTE: no return value
72
+ return_value = func.ConstantNone()
73
+ body.blocks[0].stmts.append(return_value)
74
+ body.blocks[0].stmts.append(func.Return(value_or_stmt=return_value))
75
+
76
+ code = func.Function(
77
+ sym_name=kernel_name,
78
+ signature=func.Signature((), types.NoneType),
79
+ body=body,
80
+ )
81
+
82
+ return ir.Method(
83
+ mod=None,
84
+ py_func=None,
85
+ sym_name=kernel_name,
86
+ arg_names=[],
87
+ dialects=dialects,
88
+ code=code,
89
+ )