bloqade-circuit 0.1.0__tar.gz → 0.2.0__tar.gz

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 (271) hide show
  1. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/.github/workflows/ci.yml +1 -1
  2. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/.github/workflows/release.yml +1 -1
  3. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/PKG-INFO +8 -2
  4. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/pyproject.toml +10 -2
  5. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/analysis/address/impls.py +5 -9
  6. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/analysis/address/lattice.py +1 -1
  7. bloqade_circuit-0.2.0/src/bloqade/analysis/fidelity/__init__.py +1 -0
  8. bloqade_circuit-0.2.0/src/bloqade/analysis/fidelity/analysis.py +69 -0
  9. bloqade_circuit-0.2.0/src/bloqade/device.py +130 -0
  10. bloqade_circuit-0.2.0/src/bloqade/noise/__init__.py +2 -0
  11. bloqade_circuit-0.2.0/src/bloqade/noise/fidelity.py +51 -0
  12. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/noise/native/model.py +1 -2
  13. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/noise/native/rewrite.py +5 -5
  14. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/noise/native/stmts.py +40 -11
  15. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/pyqrack/__init__.py +8 -2
  16. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/pyqrack/base.py +24 -3
  17. bloqade_circuit-0.2.0/src/bloqade/pyqrack/device.py +166 -0
  18. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/pyqrack/noise/native.py +1 -2
  19. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/pyqrack/qasm2/core.py +31 -15
  20. bloqade_circuit-0.2.0/src/bloqade/pyqrack/qasm2/glob.py +28 -0
  21. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/pyqrack/qasm2/uop.py +9 -1
  22. bloqade_circuit-0.2.0/src/bloqade/pyqrack/reg.py +77 -0
  23. bloqade_circuit-0.2.0/src/bloqade/pyqrack/squin/op.py +154 -0
  24. bloqade_circuit-0.2.0/src/bloqade/pyqrack/squin/qubit.py +85 -0
  25. bloqade_circuit-0.2.0/src/bloqade/pyqrack/squin/runtime.py +515 -0
  26. bloqade_circuit-0.2.0/src/bloqade/pyqrack/squin/wire.py +69 -0
  27. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/pyqrack/target.py +9 -2
  28. bloqade_circuit-0.2.0/src/bloqade/pyqrack/task.py +30 -0
  29. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/_wrappers.py +11 -1
  30. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/core/stmts.py +15 -4
  31. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/expr/_emit.py +9 -8
  32. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/emit/base.py +4 -2
  33. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/emit/gate.py +0 -14
  34. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/emit/main.py +19 -15
  35. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/emit/target.py +2 -6
  36. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/glob.py +1 -1
  37. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/parse/lowering.py +124 -1
  38. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/passes/glob.py +3 -3
  39. bloqade_circuit-0.2.0/src/bloqade/qasm2/passes/lift_qubits.py +26 -0
  40. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/passes/noise.py +6 -14
  41. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/passes/parallel.py +3 -3
  42. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/passes/py2qasm.py +1 -2
  43. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/passes/qasm2py.py +1 -2
  44. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/rewrite/desugar.py +6 -6
  45. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/rewrite/glob.py +9 -9
  46. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/rewrite/heuristic_noise.py +30 -38
  47. bloqade_circuit-0.2.0/src/bloqade/qasm2/rewrite/insert_qubits.py +34 -0
  48. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/rewrite/native_gates.py +54 -55
  49. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/rewrite/parallel_to_uop.py +9 -9
  50. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/rewrite/uop_to_parallel.py +20 -22
  51. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/types.py +3 -6
  52. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qbraid/schema.py +10 -12
  53. bloqade_circuit-0.2.0/src/bloqade/squin/__init__.py +2 -0
  54. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/squin/analysis/nsites/analysis.py +4 -6
  55. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/squin/analysis/nsites/impls.py +2 -6
  56. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/squin/analysis/schedule.py +1 -1
  57. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/squin/groups.py +15 -7
  58. bloqade_circuit-0.2.0/src/bloqade/squin/noise/__init__.py +27 -0
  59. bloqade_circuit-0.2.0/src/bloqade/squin/noise/_dialect.py +3 -0
  60. bloqade_circuit-0.2.0/src/bloqade/squin/noise/stmts.py +59 -0
  61. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/squin/op/__init__.py +35 -5
  62. bloqade_circuit-0.2.0/src/bloqade/squin/op/number.py +5 -0
  63. bloqade_circuit-0.2.0/src/bloqade/squin/op/rewrite.py +46 -0
  64. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/squin/op/stmts.py +23 -2
  65. bloqade_circuit-0.2.0/src/bloqade/squin/op/types.py +24 -0
  66. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/squin/qubit.py +79 -11
  67. bloqade_circuit-0.2.0/src/bloqade/squin/rewrite/measure_desugar.py +33 -0
  68. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/squin/wire.py +31 -2
  69. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/emit/stim.py +1 -1
  70. bloqade_circuit-0.2.0/src/bloqade/task.py +94 -0
  71. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/visual/animation/base.py +25 -15
  72. bloqade_circuit-0.2.0/test/analysis/address/test_lattice.py +17 -0
  73. bloqade_circuit-0.2.0/test/analysis/fidelity/test_fidelity.py +246 -0
  74. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/pyqrack/runtime/noise/native/test_loss.py +9 -9
  75. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/pyqrack/runtime/noise/native/test_pauli.py +20 -8
  76. bloqade_circuit-0.2.0/test/pyqrack/runtime/test_dyn_memory.py +36 -0
  77. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/pyqrack/runtime/test_qrack.py +6 -5
  78. bloqade_circuit-0.2.0/test/pyqrack/test_squin.py +514 -0
  79. bloqade_circuit-0.2.0/test/pyqrack/test_target.py +173 -0
  80. bloqade_circuit-0.2.0/test/qasm2/emit/test_qasm2.py +26 -0
  81. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/passes/test_heuristic_noise.py +5 -7
  82. bloqade_circuit-0.2.0/test/qasm2/test_lowering.py +82 -0
  83. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/test_native.py +37 -1
  84. bloqade_circuit-0.2.0/test/squin/test_constprop.py +110 -0
  85. bloqade_circuit-0.2.0/test/squin/test_measure_sugar.py +36 -0
  86. bloqade_circuit-0.2.0/test/squin/test_mult_rewrite.py +166 -0
  87. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/stim/dialects/stim/emit/base.py +1 -1
  88. bloqade_circuit-0.2.0/test/stim/wrapper/__init__.py +0 -0
  89. bloqade_circuit-0.2.0/test/visual/__init__.py +0 -0
  90. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/uv.lock +23 -5
  91. bloqade_circuit-0.1.0/src/bloqade/noise/__init__.py +0 -1
  92. bloqade_circuit-0.1.0/src/bloqade/pyqrack/reg.py +0 -109
  93. bloqade_circuit-0.1.0/src/bloqade/squin/__init__.py +0 -2
  94. bloqade_circuit-0.1.0/src/bloqade/squin/op/complex.py +0 -6
  95. bloqade_circuit-0.1.0/src/bloqade/squin/op/types.py +0 -10
  96. bloqade_circuit-0.1.0/test/pyqrack/runtime/test_dyn_memory.py +0 -32
  97. bloqade_circuit-0.1.0/test/pyqrack/test_target.py +0 -40
  98. bloqade_circuit-0.1.0/test/qasm2/emit/test_qasm2.py +0 -27
  99. bloqade_circuit-0.1.0/test/qasm2/test_lowering.py +0 -22
  100. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/.github/dependabot.yml +0 -0
  101. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/.github/workflows/isort.yml +0 -0
  102. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/.github/workflows/lint.yml +0 -0
  103. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/.gitignore +0 -0
  104. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/.pre-commit-config.yaml +0 -0
  105. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/LICENSE +0 -0
  106. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/README.md +0 -0
  107. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/_typos.toml +0 -0
  108. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/justfile +0 -0
  109. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/analysis/__init__.py +0 -0
  110. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/analysis/address/__init__.py +0 -0
  111. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/analysis/address/analysis.py +0 -0
  112. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/noise/native/__init__.py +0 -0
  113. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/noise/native/_dialect.py +0 -0
  114. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/noise/native/_wrappers.py +0 -0
  115. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/pyqrack/noise/__init__.py +0 -0
  116. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/pyqrack/qasm2/__init__.py +0 -0
  117. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/pyqrack/qasm2/parallel.py +0 -0
  118. {bloqade_circuit-0.1.0/src/bloqade/squin/analysis → bloqade_circuit-0.2.0/src/bloqade/pyqrack/squin}/__init__.py +0 -0
  119. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/__init__.py +0 -0
  120. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/__init__.py +0 -0
  121. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/core/__init__.py +0 -0
  122. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/core/_dialect.py +0 -0
  123. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/core/_emit.py +0 -0
  124. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/core/_typeinfer.py +0 -0
  125. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/core/address.py +0 -0
  126. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/expr/__init__.py +0 -0
  127. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/expr/_dialect.py +0 -0
  128. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/expr/_from_python.py +0 -0
  129. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/expr/_interp.py +0 -0
  130. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/expr/stmts.py +0 -0
  131. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/glob.py +0 -0
  132. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/indexing.py +0 -0
  133. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/inline.py +0 -0
  134. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/noise.py +0 -0
  135. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/parallel.py +0 -0
  136. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/uop/__init__.py +0 -0
  137. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/uop/_dialect.py +0 -0
  138. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/uop/_emit.py +0 -0
  139. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/uop/schedule.py +0 -0
  140. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/dialects/uop/stmts.py +0 -0
  141. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/emit/__init__.py +0 -0
  142. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/groups.py +0 -0
  143. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/parallel.py +0 -0
  144. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/parse/__init__.py +0 -0
  145. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/parse/ast.py +0 -0
  146. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/parse/build.py +0 -0
  147. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/parse/parser.py +0 -0
  148. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/parse/print.py +0 -0
  149. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/parse/qasm2.lark +0 -0
  150. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/parse/visitor.py +0 -0
  151. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/parse/visitor.pyi +0 -0
  152. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/passes/__init__.py +0 -0
  153. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/passes/fold.py +0 -0
  154. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/rewrite/__init__.py +0 -0
  155. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qasm2/rewrite/register.py +0 -0
  156. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qbraid/__init__.py +0 -0
  157. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qbraid/lowering.py +0 -0
  158. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qbraid/simulation_result.py +0 -0
  159. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/qbraid/target.py +0 -0
  160. {bloqade_circuit-0.1.0/src/bloqade/visual/animation → bloqade_circuit-0.2.0/src/bloqade/squin/analysis}/__init__.py +0 -0
  161. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/squin/analysis/nsites/__init__.py +0 -0
  162. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/squin/analysis/nsites/lattice.py +0 -0
  163. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/squin/op/_dialect.py +0 -0
  164. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/squin/op/traits.py +0 -0
  165. {bloqade_circuit-0.1.0/src/bloqade/visual/animation/runtime → bloqade_circuit-0.2.0/src/bloqade/squin/rewrite}/__init__.py +0 -0
  166. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/__init__.py +0 -0
  167. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/_wrappers.py +0 -0
  168. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/__init__.py +0 -0
  169. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/aux/__init__.py +0 -0
  170. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/aux/_dialect.py +0 -0
  171. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/aux/emit.py +0 -0
  172. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/aux/interp.py +0 -0
  173. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/aux/lowering.py +0 -0
  174. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/aux/stmts/__init__.py +0 -0
  175. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/aux/stmts/annotate.py +0 -0
  176. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/aux/stmts/const.py +0 -0
  177. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/aux/types.py +0 -0
  178. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/collapse/__init__.py +0 -0
  179. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/collapse/_dialect.py +0 -0
  180. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/collapse/emit.py +0 -0
  181. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/collapse/stmts/__init__.py +0 -0
  182. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/collapse/stmts/measure.py +0 -0
  183. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/collapse/stmts/pp_measure.py +0 -0
  184. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/collapse/stmts/reset.py +0 -0
  185. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/gate/__init__.py +0 -0
  186. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/gate/_dialect.py +0 -0
  187. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/gate/emit.py +0 -0
  188. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/gate/stmts/__init__.py +0 -0
  189. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/gate/stmts/base.py +0 -0
  190. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/gate/stmts/clifford_1q.py +0 -0
  191. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/gate/stmts/clifford_2q.py +0 -0
  192. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/gate/stmts/control_2q.py +0 -0
  193. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/gate/stmts/pp.py +0 -0
  194. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/noise/__init__.py +0 -0
  195. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/noise/_dialect.py +0 -0
  196. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/noise/emit.py +0 -0
  197. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/dialects/noise/stmts.py +0 -0
  198. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/emit/__init__.py +0 -0
  199. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/stim/groups.py +0 -0
  200. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/test_utils.py +0 -0
  201. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/types.py +0 -0
  202. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/visual/__init__.py +0 -0
  203. {bloqade_circuit-0.1.0/test → bloqade_circuit-0.2.0/src/bloqade/visual/animation}/__init__.py +0 -0
  204. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/visual/animation/animate.py +0 -0
  205. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/visual/animation/gate_event.py +0 -0
  206. {bloqade_circuit-0.1.0/test/pyqrack → bloqade_circuit-0.2.0/src/bloqade/visual/animation/runtime}/__init__.py +0 -0
  207. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/visual/animation/runtime/aod.py +0 -0
  208. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/visual/animation/runtime/atoms.py +0 -0
  209. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/visual/animation/runtime/ppoly.py +0 -0
  210. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/visual/animation/runtime/qpustate.py +0 -0
  211. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/src/bloqade/visual/animation/runtime/utils.py +0 -0
  212. {bloqade_circuit-0.1.0/test/pyqrack/runtime → bloqade_circuit-0.2.0/test}/__init__.py +0 -0
  213. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/analysis/address/test_analysis.py +0 -0
  214. {bloqade_circuit-0.1.0/test/pyqrack/runtime/noise → bloqade_circuit-0.2.0/test/pyqrack}/__init__.py +0 -0
  215. {bloqade_circuit-0.1.0/test/qasm2 → bloqade_circuit-0.2.0/test/pyqrack/runtime}/__init__.py +0 -0
  216. {bloqade_circuit-0.1.0/test/qasm2/parse → bloqade_circuit-0.2.0/test/pyqrack/runtime/noise}/__init__.py +0 -0
  217. {bloqade_circuit-0.1.0/test/qasm2/passes → bloqade_circuit-0.2.0/test/qasm2}/__init__.py +0 -0
  218. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/analysis/test_dag.py +0 -0
  219. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/emit/test_extended.py +0 -0
  220. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/emit/test_qasm2_emit.py +0 -0
  221. {bloqade_circuit-0.1.0/test/qbraid → bloqade_circuit-0.2.0/test/qasm2/parse}/__init__.py +0 -0
  222. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/README.md +0 -0
  223. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/global.qasm +0 -0
  224. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/iqft1.qasm +0 -0
  225. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/main.qasm +0 -0
  226. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/noise.qasm +0 -0
  227. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/para.qasm +0 -0
  228. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/process_tomo.qasm +0 -0
  229. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/qelib1.inc +0 -0
  230. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/qft.qasm +0 -0
  231. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/qft2.qasm +0 -0
  232. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/rb.qasm +0 -0
  233. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/rep_code.qasm +0 -0
  234. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/ripple_carry_adder.qasm +0 -0
  235. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/programs/tele.qasm +0 -0
  236. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/test_ast.py +0 -0
  237. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/parse/test_roundtrip.py +0 -0
  238. {bloqade_circuit-0.1.0/test/sample → bloqade_circuit-0.2.0/test/qasm2/passes}/__init__.py +0 -0
  239. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/passes/test_global_to_parallel.py +0 -0
  240. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/passes/test_global_to_uop.py +0 -0
  241. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/passes/test_parallel_to_uop.py +0 -0
  242. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/passes/test_qasm2py.py +0 -0
  243. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/passes/test_uop_to_parallel.py +0 -0
  244. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/test_count.py +0 -0
  245. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/test_inline.py +0 -0
  246. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qasm2/test_two2one.py +0 -0
  247. {bloqade_circuit-0.1.0/test/stim → bloqade_circuit-0.2.0/test/qbraid}/__init__.py +0 -0
  248. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qbraid/test_clean_circuit.py +0 -0
  249. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qbraid/test_lowering.py +0 -0
  250. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/qbraid/test_target.py +0 -0
  251. {bloqade_circuit-0.1.0/test/stim/dialects → bloqade_circuit-0.2.0/test/sample}/__init__.py +0 -0
  252. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/sample/test_noise_model.py +0 -0
  253. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/squin/analysis/test_nsites_analysis.py +0 -0
  254. {bloqade_circuit-0.1.0/test/stim/dialects → bloqade_circuit-0.2.0/test}/stim/__init__.py +0 -0
  255. {bloqade_circuit-0.1.0/test/stim/dialects/stim/emit → bloqade_circuit-0.2.0/test/stim/dialects}/__init__.py +0 -0
  256. {bloqade_circuit-0.1.0/test/stim/wrapper → bloqade_circuit-0.2.0/test/stim/dialects/stim}/__init__.py +0 -0
  257. {bloqade_circuit-0.1.0/test/visual → bloqade_circuit-0.2.0/test/stim/dialects/stim/emit}/__init__.py +0 -0
  258. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/stim/dialects/stim/emit/test_stim_1q.py +0 -0
  259. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/stim/dialects/stim/emit/test_stim_ctrl.py +0 -0
  260. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/stim/dialects/stim/emit/test_stim_detector.py +0 -0
  261. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/stim/dialects/stim/emit/test_stim_meas.py +0 -0
  262. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/stim/dialects/stim/emit/test_stim_noise.py +0 -0
  263. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/stim/dialects/stim/emit/test_stim_obs_inc.py +0 -0
  264. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/stim/dialects/stim/emit/test_stim_ppmeas.py +0 -0
  265. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/stim/dialects/stim/emit/test_stim_spp.py +0 -0
  266. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/stim/dialects/stim/test_stim_circuits.py +0 -0
  267. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/stim/dialects/stim/test_stim_const.py +0 -0
  268. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/stim/wrapper/test_wrapper.py +0 -0
  269. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/test_serialization.py +0 -0
  270. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/test_zone_model.py +0 -0
  271. {bloqade_circuit-0.1.0 → bloqade_circuit-0.2.0}/test/visual/test_utils.py +0 -0
@@ -21,7 +21,7 @@ jobs:
21
21
  steps:
22
22
  - uses: actions/checkout@v4
23
23
  - name: Install uv
24
- uses: astral-sh/setup-uv@v5
24
+ uses: astral-sh/setup-uv@v6
25
25
  with:
26
26
  # Install a specific version of uv.
27
27
  version: "0.5.1"
@@ -10,7 +10,7 @@ jobs:
10
10
  steps:
11
11
  - uses: actions/checkout@v4
12
12
  - name: Install uv
13
- uses: astral-sh/setup-uv@v5
13
+ uses: astral-sh/setup-uv@v6
14
14
  with:
15
15
  # Install a specific version of uv.
16
16
  version: "0.5.5"
@@ -1,19 +1,25 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bloqade-circuit
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: The software development toolkit for neutral atom arrays.
5
5
  Author-email: Roger-luo <rluo@quera.com>, kaihsin <khwu@quera.com>, weinbe58 <pweinberg@quera.com>, johnzl-777 <jlong@quera.com>
6
6
  License-File: LICENSE
7
7
  Requires-Python: >=3.10
8
- Requires-Dist: kirin-toolchain~=0.16.0
8
+ Requires-Dist: kirin-toolchain~=0.17.0
9
9
  Requires-Dist: numpy>=1.22.0
10
10
  Requires-Dist: pandas>=2.2.3
11
11
  Requires-Dist: pydantic<2.11.0,>=1.3.0
12
+ Requires-Dist: pyqrack-cpu>=1.38.2; sys_platform != 'darwin'
13
+ Requires-Dist: pyqrack>=1.38.2; sys_platform == 'darwin'
12
14
  Requires-Dist: rich>=13.9.4
13
15
  Requires-Dist: scipy>=1.13.1
14
16
  Provides-Extra: cirq
15
17
  Requires-Dist: cirq-core>=1.4.1; extra == 'cirq'
16
18
  Requires-Dist: cirq-core[contrib]>=1.4.1; extra == 'cirq'
19
+ Provides-Extra: pyqrack-cuda
20
+ Requires-Dist: pyqrack-cuda>=1.38.2; extra == 'pyqrack-cuda'
21
+ Provides-Extra: pyqrack-opencl
22
+ Requires-Dist: pyqrack>=1.38.2; (sys_platform != 'darwin') and extra == 'pyqrack-opencl'
17
23
  Provides-Extra: qasm2
18
24
  Requires-Dist: lark>=1.2.2; extra == 'qasm2'
19
25
  Provides-Extra: qbraid
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bloqade-circuit"
3
- version = "0.1.0"
3
+ version = "0.2.0"
4
4
  description = "The software development toolkit for neutral atom arrays."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -13,10 +13,12 @@ requires-python = ">=3.10"
13
13
  dependencies = [
14
14
  "numpy>=1.22.0",
15
15
  "scipy>=1.13.1",
16
- "kirin-toolchain~=0.16.0",
16
+ "kirin-toolchain~=0.17.0",
17
17
  "rich>=13.9.4",
18
18
  "pydantic>=1.3.0,<2.11.0",
19
19
  "pandas>=2.2.3",
20
+ "pyqrack>=1.38.2 ; sys_platform == 'darwin'",
21
+ "pyqrack-cpu>=1.38.2 ; sys_platform != 'darwin'",
20
22
  ]
21
23
 
22
24
  [project.optional-dependencies]
@@ -36,6 +38,12 @@ cirq = [
36
38
  "cirq-core>=1.4.1",
37
39
  "cirq-core[contrib]>=1.4.1",
38
40
  ]
41
+ pyqrack-opencl = [
42
+ "pyqrack>=1.38.2 ; sys_platform != 'darwin'",
43
+ ]
44
+ pyqrack-cuda = [
45
+ "pyqrack-cuda>=1.38.2",
46
+ ]
39
47
 
40
48
  [build-system]
41
49
  requires = ["hatchling"]
@@ -192,7 +192,10 @@ class SquinWireMethodTable(interp.MethodTable):
192
192
 
193
193
  origin_qubit = frame.get(stmt.qubit)
194
194
 
195
- return (AddressWire(origin_qubit=origin_qubit),)
195
+ if isinstance(origin_qubit, AddressQubit):
196
+ return (AddressWire(origin_qubit=origin_qubit),)
197
+ else:
198
+ return (Address.top(),)
196
199
 
197
200
  @interp.impl(squin.wire.Apply)
198
201
  def apply(
@@ -201,14 +204,7 @@ class SquinWireMethodTable(interp.MethodTable):
201
204
  frame: ForwardFrame[Address],
202
205
  stmt: squin.wire.Apply,
203
206
  ):
204
-
205
- origin_qubits = tuple(
206
- [frame.get(input_elem).origin_qubit for input_elem in stmt.inputs]
207
- )
208
- new_address_wires = tuple(
209
- [AddressWire(origin_qubit=origin_qubit) for origin_qubit in origin_qubits]
210
- )
211
- return new_address_wires
207
+ return frame.get_values(stmt.inputs)
212
208
 
213
209
 
214
210
  @squin.qubit.dialect.register(key="qubit.address")
@@ -81,5 +81,5 @@ class AddressWire(Address):
81
81
 
82
82
  def is_subseteq(self, other: Address) -> bool:
83
83
  if isinstance(other, AddressWire):
84
- return self.origin_qubit == self.origin_qubit
84
+ return self.origin_qubit == other.origin_qubit
85
85
  return False
@@ -0,0 +1 @@
1
+ from .analysis import FidelityAnalysis as FidelityAnalysis
@@ -0,0 +1,69 @@
1
+ from typing import Any
2
+ from dataclasses import field
3
+
4
+ from kirin import ir
5
+ from kirin.lattice import EmptyLattice
6
+ from kirin.analysis import Forward
7
+ from kirin.interp.value import Successor
8
+ from kirin.analysis.forward import ForwardFrame
9
+
10
+ from ..address import AddressAnalysis
11
+
12
+
13
+ class FidelityAnalysis(Forward):
14
+ """
15
+ This analysis pass can be used to track the global addresses of qubits and wires.
16
+ """
17
+
18
+ keys = ["circuit.fidelity"]
19
+ lattice = EmptyLattice
20
+
21
+ """
22
+ The fidelity of the gate set described by the analysed program. It reduces whenever a noise channel is encountered.
23
+ """
24
+ gate_fidelity: float = 1.0
25
+
26
+ _current_gate_fidelity: float = field(init=False)
27
+
28
+ """
29
+ The probabilities that each of the atoms in the register survive the duration of the analysed program. The order of the list follows the order they are in the register.
30
+ """
31
+ atom_survival_probability: list[float] = field(init=False)
32
+
33
+ _current_atom_survival_probability: list[float] = field(init=False)
34
+
35
+ addr_frame: ForwardFrame = field(init=False)
36
+
37
+ def initialize(self):
38
+ super().initialize()
39
+ self._current_gate_fidelity = 1.0
40
+ self._current_atom_survival_probability = [
41
+ 1.0 for _ in range(len(self.atom_survival_probability))
42
+ ]
43
+ return self
44
+
45
+ def posthook_succ(self, frame: ForwardFrame, succ: Successor):
46
+ self.gate_fidelity *= self._current_gate_fidelity
47
+ for i, _current_survival in enumerate(self._current_atom_survival_probability):
48
+ self.atom_survival_probability[i] *= _current_survival
49
+
50
+ def eval_stmt_fallback(self, frame: ForwardFrame, stmt: ir.Statement):
51
+ # NOTE: default is to conserve fidelity, so do nothing here
52
+ return
53
+
54
+ def run_method(self, method: ir.Method, args: tuple[EmptyLattice, ...]):
55
+ return self.run_callable(method.code, (self.lattice.bottom(),) + args)
56
+
57
+ def run_analysis(
58
+ self, method: ir.Method, args: tuple | None = None, *, no_raise: bool = True
59
+ ) -> tuple[ForwardFrame, Any]:
60
+ self._run_address_analysis(method, no_raise=no_raise)
61
+ return super().run_analysis(method, args, no_raise=no_raise)
62
+
63
+ def _run_address_analysis(self, method: ir.Method, no_raise: bool):
64
+ addr_analysis = AddressAnalysis(self.dialects)
65
+ addr_frame, _ = addr_analysis.run_analysis(method=method, no_raise=no_raise)
66
+ self.addr_frame = addr_frame
67
+
68
+ # NOTE: make sure we have as many probabilities as we have addresses
69
+ self.atom_survival_probability = [1.0] * addr_analysis.qubit_count
@@ -0,0 +1,130 @@
1
+ import abc
2
+ from typing import Any, Generic, TypeVar, ParamSpec
3
+
4
+ from kirin import ir
5
+
6
+ from bloqade.task import (
7
+ BatchFuture,
8
+ AbstractTask,
9
+ AbstractRemoteTask,
10
+ AbstractSimulatorTask,
11
+ DeviceTaskExpectMixin,
12
+ )
13
+
14
+ Params = ParamSpec("Params")
15
+ RetType = TypeVar("RetType")
16
+ ObsType = TypeVar("ObsType")
17
+
18
+
19
+ TaskType = TypeVar("TaskType", bound=AbstractTask)
20
+
21
+
22
+ class AbstractDevice(abc.ABC, Generic[TaskType]):
23
+ """Abstract base class for devices. Defines the minimum interface for devices."""
24
+
25
+ @abc.abstractmethod
26
+ def task(
27
+ self,
28
+ kernel: ir.Method[Params, RetType],
29
+ args: tuple[Any, ...] = (),
30
+ kwargs: dict[str, Any] | None = None,
31
+ ) -> TaskType:
32
+ """Creates a remote task for the device."""
33
+
34
+
35
+ ExpectTaskType = TypeVar("ExpectTaskType", bound=DeviceTaskExpectMixin)
36
+
37
+
38
+ class ExpectationDeviceMixin(AbstractDevice[ExpectTaskType]):
39
+ def expect(
40
+ self,
41
+ kernel: ir.Method[Params, RetType],
42
+ observable: ir.Method[[RetType], ObsType],
43
+ args: tuple[Any, ...] = (),
44
+ kwargs: dict[str, Any] | None = None,
45
+ *,
46
+ shots: int = 1,
47
+ ) -> ObsType:
48
+ """Returns the expectation value of the given observable after running the task."""
49
+ return self.task(kernel, args, kwargs).expect(observable, shots)
50
+
51
+
52
+ RemoteTaskType = TypeVar("RemoteTaskType", bound=AbstractRemoteTask)
53
+
54
+
55
+ class AbstractRemoteDevice(AbstractDevice[RemoteTaskType]):
56
+ """Abstract base class for remote devices."""
57
+
58
+ def run(
59
+ self,
60
+ kernel: ir.Method[Params, RetType],
61
+ args: tuple[Any, ...] = (),
62
+ kwargs: dict[str, Any] | None = None,
63
+ *,
64
+ shots: int = 1,
65
+ timeout: float | None = None,
66
+ ) -> list[RetType]:
67
+ """Runs the kernel and returns the result.
68
+
69
+ Args:
70
+ kernel (ir.Method):
71
+ The kernel method to run.
72
+ args (tuple[Any, ...]):
73
+ Positional arguments to pass to the kernel method.
74
+ kwargs (dict[str, Any] | None):
75
+ Keyword arguments to pass to the kernel method.
76
+ shots (int):
77
+ The number of times to run the kernel method.
78
+ timeout (float | None):
79
+ Timeout in seconds for the asynchronous execution. If None, wait indefinitely.
80
+
81
+ Returns:
82
+ list[RetType]:
83
+ The result of the kernel method, if any.
84
+
85
+ """
86
+ return self.task(kernel, args, kwargs).run(shots=shots, timeout=timeout)
87
+
88
+ def run_async(
89
+ self,
90
+ kernel: ir.Method[Params, RetType],
91
+ args: tuple[Any, ...] = (),
92
+ kwargs: dict[str, Any] | None = None,
93
+ *,
94
+ shots: int = 1,
95
+ ) -> BatchFuture[RetType]:
96
+ """Runs the kernel asynchronously and returns a Future object.
97
+
98
+ Args:
99
+ kernel (ir.Method):
100
+ The kernel method to run.
101
+ args (tuple[Any, ...]):
102
+ Positional arguments to pass to the kernel method.
103
+ kwargs (dict[str, Any] | None):
104
+ Keyword arguments to pass to the kernel method.
105
+ shots (int):
106
+ The number of times to run the kernel method.
107
+
108
+ Returns:
109
+ Future[list[RetType]]:
110
+ The Future for all executions of the kernel method.
111
+
112
+
113
+ """
114
+ return self.task(kernel, args, kwargs).run_async(shots=shots)
115
+
116
+
117
+ SimulatorTaskType = TypeVar("SimulatorTaskType", bound=AbstractSimulatorTask)
118
+
119
+
120
+ class AbstractSimulatorDevice(AbstractDevice[SimulatorTaskType]):
121
+ """Abstract base class for simulator devices."""
122
+
123
+ def run(
124
+ self,
125
+ kernel: ir.Method[Params, RetType],
126
+ args: tuple[Any, ...] = (),
127
+ kwargs: dict[str, Any] | None = None,
128
+ ) -> RetType:
129
+ """Runs the kernel and returns the result."""
130
+ return self.task(kernel, args, kwargs).run()
@@ -0,0 +1,2 @@
1
+ # NOTE: just to register methods
2
+ from . import native as native, fidelity as fidelity
@@ -0,0 +1,51 @@
1
+ from kirin import interp
2
+ from kirin.lattice import EmptyLattice
3
+
4
+ from bloqade.analysis.fidelity import FidelityAnalysis
5
+
6
+ from .native import dialect as native
7
+ from .native.stmts import PauliChannel, CZPauliChannel, AtomLossChannel
8
+ from ..analysis.address import AddressQubit, AddressTuple
9
+
10
+
11
+ @native.register(key="circuit.fidelity")
12
+ class FidelityMethodTable(interp.MethodTable):
13
+
14
+ @interp.impl(PauliChannel)
15
+ @interp.impl(CZPauliChannel)
16
+ def pauli_channel(
17
+ self,
18
+ interp: FidelityAnalysis,
19
+ frame: interp.Frame[EmptyLattice],
20
+ stmt: PauliChannel | CZPauliChannel,
21
+ ):
22
+ probs = stmt.probabilities
23
+ try:
24
+ ps, ps_ctrl = probs
25
+ except ValueError:
26
+ (ps,) = probs
27
+ ps_ctrl = ()
28
+
29
+ p = sum(ps)
30
+ p_ctrl = sum(ps_ctrl)
31
+
32
+ # NOTE: fidelity is just the inverse probability of any noise to occur
33
+ fid = (1 - p) * (1 - p_ctrl)
34
+
35
+ interp._current_gate_fidelity *= fid
36
+
37
+ @interp.impl(AtomLossChannel)
38
+ def atom_loss(
39
+ self,
40
+ interp: FidelityAnalysis,
41
+ frame: interp.Frame[EmptyLattice],
42
+ stmt: AtomLossChannel,
43
+ ):
44
+ # NOTE: since AtomLossChannel acts on IList[Qubit], we know the assigned address is a tuple
45
+ addresses: AddressTuple = interp.addr_frame.get(stmt.qargs)
46
+
47
+ # NOTE: get the corresponding index and reduce survival probability accordingly
48
+ for qbit_address in addresses.data:
49
+ assert isinstance(qbit_address, AddressQubit)
50
+ index = qbit_address.data
51
+ interp._current_atom_survival_probability[index] *= 1 - stmt.prob
@@ -102,10 +102,9 @@ class MoveNoiseModelABC(abc.ABC):
102
102
  params: MoveNoiseParams = field(default_factory=MoveNoiseParams)
103
103
  """Parameters for calculating move noise."""
104
104
 
105
- @classmethod
106
105
  @abc.abstractmethod
107
106
  def parallel_cz_errors(
108
- cls, ctrls: List[int], qargs: List[int], rest: List[int]
107
+ self, ctrls: List[int], qargs: List[int], rest: List[int]
109
108
  ) -> Dict[Tuple[float, float, float, float], List[int]]:
110
109
  """Takes a set of ctrls and qargs and returns a noise model for all qubits."""
111
110
  pass
@@ -1,7 +1,7 @@
1
1
  from dataclasses import dataclass
2
2
 
3
3
  from kirin import ir
4
- from kirin.rewrite import abc, dce, walk, result, fixpoint
4
+ from kirin.rewrite import abc, dce, walk, fixpoint
5
5
  from kirin.passes.abc import Pass
6
6
 
7
7
  from .stmts import PauliChannel, CZPauliChannel, AtomLossChannel
@@ -9,19 +9,19 @@ from ._dialect import dialect
9
9
 
10
10
 
11
11
  class RemoveNoiseRewrite(abc.RewriteRule):
12
- def rewrite_Statement(self, node: ir.Statement) -> result.RewriteResult:
12
+ def rewrite_Statement(self, node: ir.Statement) -> abc.RewriteResult:
13
13
  if isinstance(node, (AtomLossChannel, PauliChannel, CZPauliChannel)):
14
14
  node.delete()
15
- return result.RewriteResult(has_done_something=True)
15
+ return abc.RewriteResult(has_done_something=True)
16
16
 
17
- return result.RewriteResult()
17
+ return abc.RewriteResult()
18
18
 
19
19
 
20
20
  @dataclass
21
21
  class RemoveNoisePass(Pass):
22
22
  name = "remove-noise"
23
23
 
24
- def unsafe_run(self, mt: ir.Method) -> result.RewriteResult:
24
+ def unsafe_run(self, mt: ir.Method) -> abc.RewriteResult:
25
25
  delete_walk = walk.Walk(RemoveNoiseRewrite())
26
26
  dce_walk = fixpoint.Fixpoint(walk.Walk(dce.DeadCodeElimination()))
27
27
 
@@ -1,3 +1,5 @@
1
+ from typing import Tuple
2
+
1
3
  from kirin import ir, types, lowering
2
4
  from kirin.decl import info, statement
3
5
  from kirin.dialects import ilist
@@ -7,25 +9,44 @@ from bloqade.qasm2.types import QubitType
7
9
  from ._dialect import dialect
8
10
 
9
11
 
10
- @statement(dialect=dialect)
11
- class PauliChannel(ir.Statement):
12
-
12
+ @statement
13
+ class NativeNoiseStmt(ir.Statement):
13
14
  traits = frozenset({lowering.FromPythonCall()})
14
15
 
16
+ @property
17
+ def probabilities(self) -> Tuple[Tuple[float, ...], ...]:
18
+ raise NotImplementedError(f"Override the method in {type(self).__name__}")
19
+
20
+ def check(self):
21
+ for probs in self.probabilities:
22
+ self.check_probability(sum(probs))
23
+ for p in probs:
24
+ self.check_probability(p)
25
+
26
+ def check_probability(self, p: float):
27
+ if not 0 <= p <= 1:
28
+ raise ValueError(
29
+ f"Invalid noise probability encountered in {type(self).__name__}: {p}"
30
+ )
31
+
32
+
33
+ @statement(dialect=dialect)
34
+ class PauliChannel(NativeNoiseStmt):
15
35
  px: float = info.attribute(types.Float)
16
36
  py: float = info.attribute(types.Float)
17
37
  pz: float = info.attribute(types.Float)
18
38
  qargs: ir.SSAValue = info.argument(ilist.IListType[QubitType])
19
39
 
40
+ @property
41
+ def probabilities(self) -> Tuple[Tuple[float, ...], ...]:
42
+ return ((self.px, self.py, self.pz),)
43
+
20
44
 
21
45
  NumQubits = types.TypeVar("NumQubits")
22
46
 
23
47
 
24
48
  @statement(dialect=dialect)
25
- class CZPauliChannel(ir.Statement):
26
-
27
- traits = frozenset({lowering.FromPythonCall()})
28
-
49
+ class CZPauliChannel(NativeNoiseStmt):
29
50
  paired: bool = info.attribute(types.Bool)
30
51
  px_ctrl: float = info.attribute(types.Float)
31
52
  py_ctrl: float = info.attribute(types.Float)
@@ -36,11 +57,19 @@ class CZPauliChannel(ir.Statement):
36
57
  ctrls: ir.SSAValue = info.argument(ilist.IListType[QubitType, NumQubits])
37
58
  qargs: ir.SSAValue = info.argument(ilist.IListType[QubitType, NumQubits])
38
59
 
60
+ @property
61
+ def probabilities(self) -> Tuple[Tuple[float, ...], ...]:
62
+ return (
63
+ (self.px_ctrl, self.py_ctrl, self.pz_ctrl),
64
+ (self.px_qarg, self.py_qarg, self.pz_qarg),
65
+ )
39
66
 
40
- @statement(dialect=dialect)
41
- class AtomLossChannel(ir.Statement):
42
-
43
- traits = frozenset({lowering.FromPythonCall()})
44
67
 
68
+ @statement(dialect=dialect)
69
+ class AtomLossChannel(NativeNoiseStmt):
45
70
  prob: float = info.attribute(types.Float)
46
71
  qargs: ir.SSAValue = info.argument(ilist.IListType[QubitType])
72
+
73
+ @property
74
+ def probabilities(self) -> Tuple[Tuple[float, ...], ...]:
75
+ return ((self.prob,),)
@@ -1,9 +1,9 @@
1
1
  from .reg import (
2
2
  CBitRef as CBitRef,
3
3
  CRegister as CRegister,
4
- PyQrackReg as PyQrackReg,
5
4
  QubitState as QubitState,
6
5
  Measurement as Measurement,
6
+ PyQrackWire as PyQrackWire,
7
7
  PyQrackQubit as PyQrackQubit,
8
8
  )
9
9
  from .base import (
@@ -11,8 +11,14 @@ from .base import (
11
11
  DynamicMemory as DynamicMemory,
12
12
  PyQrackInterpreter as PyQrackInterpreter,
13
13
  )
14
+ from .task import PyQrackSimulatorTask as PyQrackSimulatorTask
14
15
 
15
16
  # NOTE: The following import is for registering the method tables
16
17
  from .noise import native as native
17
- from .qasm2 import uop as uop, core as core, parallel as parallel
18
+ from .qasm2 import uop as uop, core as core, glob as glob, parallel as parallel
19
+ from .squin import op as op, qubit as qubit
20
+ from .device import (
21
+ StackMemorySimulator as StackMemorySimulator,
22
+ DynamicMemorySimulator as DynamicMemorySimulator,
23
+ )
18
24
  from .target import PyQrack as PyQrack
@@ -26,13 +26,28 @@ class PyQrackOptions(typing.TypedDict):
26
26
  isOpenCL: bool
27
27
 
28
28
 
29
+ def _validate_pyqrack_options(options: PyQrackOptions) -> None:
30
+ if options["isBinaryDecisionTree"] and options["isStabilizerHybrid"]:
31
+ raise ValueError(
32
+ "Cannot use both isBinaryDecisionTree and isStabilizerHybrid at the same time."
33
+ )
34
+ elif options["isTensorNetwork"] and options["isBinaryDecisionTree"]:
35
+ raise ValueError(
36
+ "Cannot use both isTensorNetwork and isBinaryDecisionTree at the same time."
37
+ )
38
+ elif options["isTensorNetwork"] and options["isStabilizerHybrid"]:
39
+ raise ValueError(
40
+ "Cannot use both isTensorNetwork and isStabilizerHybrid at the same time."
41
+ )
42
+
43
+
29
44
  def _default_pyqrack_args() -> PyQrackOptions:
30
45
  return PyQrackOptions(
31
46
  qubitCount=-1,
32
47
  isTensorNetwork=False,
33
48
  isSchmidtDecomposeMulti=True,
34
49
  isSchmidtDecompose=True,
35
- isStabilizerHybrid=True,
50
+ isStabilizerHybrid=False,
36
51
  isBinaryDecisionTree=True,
37
52
  isPaged=True,
38
53
  isCpuGpuHybrid=True,
@@ -45,6 +60,9 @@ class MemoryABC(abc.ABC):
45
60
  pyqrack_options: PyQrackOptions = field(default_factory=_default_pyqrack_args)
46
61
  sim_reg: "QrackSimulator" = field(init=False)
47
62
 
63
+ def __post_init__(self):
64
+ _validate_pyqrack_options(self.pyqrack_options)
65
+
48
66
  @abc.abstractmethod
49
67
  def allocate(self, n_qubits: int) -> tuple[int, ...]:
50
68
  """Allocate `n_qubits` qubits and return their ids."""
@@ -115,10 +133,13 @@ class DynamicMemory(MemoryABC):
115
133
  return tuple(range(start, start + n_qubits))
116
134
 
117
135
 
136
+ MemoryType = typing.TypeVar("MemoryType", bound=MemoryABC)
137
+
138
+
118
139
  @dataclass
119
- class PyQrackInterpreter(Interpreter):
140
+ class PyQrackInterpreter(Interpreter, typing.Generic[MemoryType]):
120
141
  keys = ["pyqrack", "main"]
121
- memory: MemoryABC = field(kw_only=True)
142
+ memory: MemoryType = field(kw_only=True)
122
143
  rng_state: np.random.Generator = field(
123
144
  default_factory=np.random.default_rng, kw_only=True
124
145
  )