bloqade-circuit 0.2.2__tar.gz → 0.3.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 (297) hide show
  1. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/PKG-INFO +3 -3
  2. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/pyproject.toml +3 -3
  3. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/analysis/address/impls.py +14 -0
  4. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/analysis/fidelity/analysis.py +27 -2
  5. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/noise/fidelity.py +3 -3
  6. bloqade_circuit-0.3.0/src/bloqade/noise/native/_dialect.py +3 -0
  7. bloqade_circuit-0.3.0/src/bloqade/noise/native/_wrappers.py +63 -0
  8. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/noise/native/stmts.py +1 -1
  9. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/device.py +109 -21
  10. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/qasm2/core.py +4 -1
  11. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/squin/qubit.py +16 -9
  12. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/squin/wire.py +22 -4
  13. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/task.py +13 -5
  14. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/__init__.py +1 -0
  15. bloqade_circuit-0.3.0/src/bloqade/qasm2/_qasm_loading.py +151 -0
  16. bloqade_circuit-0.3.0/src/bloqade/qasm2/dialects/core/__init__.py +11 -0
  17. bloqade_circuit-0.3.0/src/bloqade/qasm2/dialects/expr/__init__.py +20 -0
  18. bloqade_circuit-0.3.0/src/bloqade/qasm2/dialects/noise.py +48 -0
  19. bloqade_circuit-0.3.0/src/bloqade/qasm2/dialects/uop/__init__.py +40 -0
  20. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/uop/schedule.py +1 -1
  21. bloqade_circuit-0.3.0/src/bloqade/qasm2/emit/impls/__init__.py +1 -0
  22. bloqade_circuit-0.3.0/src/bloqade/qasm2/emit/impls/noise_native.py +89 -0
  23. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/emit/main.py +21 -0
  24. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/emit/target.py +20 -5
  25. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/groups.py +2 -0
  26. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/parse/__init__.py +7 -4
  27. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/parse/lowering.py +20 -130
  28. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/parse/qasm2.lark +1 -1
  29. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/passes/__init__.py +1 -0
  30. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/passes/fold.py +6 -0
  31. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/passes/noise.py +50 -2
  32. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/passes/parallel.py +9 -0
  33. bloqade_circuit-0.3.0/src/bloqade/qasm2/passes/unroll_if.py +25 -0
  34. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/rewrite/__init__.py +1 -0
  35. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/rewrite/desugar.py +3 -2
  36. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/rewrite/heuristic_noise.py +1 -9
  37. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/rewrite/native_gates.py +67 -4
  38. bloqade_circuit-0.3.0/src/bloqade/qasm2/rewrite/split_ifs.py +66 -0
  39. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/analysis/nsites/__init__.py +1 -0
  40. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/analysis/nsites/impls.py +25 -1
  41. bloqade_circuit-0.3.0/src/bloqade/squin/noise/__init__.py +8 -0
  42. bloqade_circuit-0.2.2/src/bloqade/squin/noise/__init__.py → bloqade_circuit-0.3.0/src/bloqade/squin/noise/_wrapper.py +7 -9
  43. bloqade_circuit-0.3.0/src/bloqade/squin/op/__init__.py +36 -0
  44. bloqade_circuit-0.3.0/src/bloqade/squin/op/_wrapper.py +101 -0
  45. bloqade_circuit-0.3.0/src/bloqade/squin/op/stdlib.py +62 -0
  46. bloqade_circuit-0.3.0/src/bloqade/squin/passes/__init__.py +1 -0
  47. bloqade_circuit-0.3.0/src/bloqade/squin/passes/stim.py +68 -0
  48. bloqade_circuit-0.3.0/src/bloqade/squin/rewrite/__init__.py +11 -0
  49. bloqade_circuit-0.3.0/src/bloqade/squin/rewrite/qubit_to_stim.py +84 -0
  50. bloqade_circuit-0.3.0/src/bloqade/squin/rewrite/squin_measure.py +98 -0
  51. bloqade_circuit-0.3.0/src/bloqade/squin/rewrite/stim_rewrite_util.py +158 -0
  52. bloqade_circuit-0.3.0/src/bloqade/squin/rewrite/wire_identity_elimination.py +24 -0
  53. bloqade_circuit-0.3.0/src/bloqade/squin/rewrite/wire_to_stim.py +73 -0
  54. bloqade_circuit-0.3.0/src/bloqade/squin/rewrite/wrap_analysis.py +72 -0
  55. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/wire.py +1 -13
  56. bloqade_circuit-0.3.0/src/bloqade/stim/__init__.py +40 -0
  57. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/_wrappers.py +14 -12
  58. bloqade_circuit-0.3.0/src/bloqade/stim/dialects/__init__.py +1 -0
  59. {bloqade_circuit-0.2.2/src/bloqade/stim/dialects/aux → bloqade_circuit-0.3.0/src/bloqade/stim/dialects/auxiliary}/__init__.py +12 -1
  60. {bloqade_circuit-0.2.2/src/bloqade/stim/dialects/aux → bloqade_circuit-0.3.0/src/bloqade/stim/dialects/auxiliary}/emit.py +1 -1
  61. bloqade_circuit-0.3.0/src/bloqade/stim/dialects/collapse/__init__.py +14 -0
  62. bloqade_circuit-0.2.2/src/bloqade/stim/dialects/collapse/emit.py → bloqade_circuit-0.3.0/src/bloqade/stim/dialects/collapse/emit_str.py +1 -1
  63. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/collapse/stmts/pp_measure.py +1 -1
  64. bloqade_circuit-0.3.0/src/bloqade/stim/dialects/gate/__init__.py +18 -0
  65. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/gate/emit.py +1 -1
  66. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/gate/stmts/base.py +1 -1
  67. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/gate/stmts/pp.py +1 -1
  68. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/noise/emit.py +1 -1
  69. bloqade_circuit-0.3.0/src/bloqade/stim/emit/__init__.py +1 -0
  70. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/groups.py +4 -2
  71. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/analysis/fidelity/test_fidelity.py +6 -8
  72. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/pyqrack/runtime/noise/native/test_loss.py +2 -4
  73. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/pyqrack/runtime/noise/native/test_pauli.py +4 -6
  74. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/pyqrack/test_target.py +28 -5
  75. bloqade_circuit-0.3.0/test/qasm2/emit/test_extended_noise.py +138 -0
  76. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/emit/test_qasm2_emit.py +73 -6
  77. bloqade_circuit-0.3.0/test/qasm2/parse/invalid_programs/invalid_if.qasm +9 -0
  78. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/main.qasm +0 -4
  79. bloqade_circuit-0.3.0/test/qasm2/parse/programs/valid_if.qasm +7 -0
  80. bloqade_circuit-0.3.0/test/qasm2/parse/test_roundtrip.py +28 -0
  81. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/passes/test_heuristic_noise.py +9 -4
  82. bloqade_circuit-0.3.0/test/qasm2/passes/test_unroll_if.py +105 -0
  83. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/test_lowering.py +8 -11
  84. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/test_native.py +24 -0
  85. bloqade_circuit-0.3.0/test/squin/stim/stim.py +547 -0
  86. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/squin/test_constprop.py +5 -6
  87. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/stim/dialects/stim/emit/test_stim_ctrl.py +4 -3
  88. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/stim/dialects/stim/emit/test_stim_detector.py +1 -1
  89. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/stim/dialects/stim/emit/test_stim_meas.py +2 -1
  90. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/stim/dialects/stim/emit/test_stim_noise.py +1 -1
  91. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/stim/dialects/stim/emit/test_stim_obs_inc.py +4 -1
  92. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/stim/dialects/stim/emit/test_stim_ppmeas.py +3 -3
  93. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/stim/dialects/stim/emit/test_stim_spp.py +3 -3
  94. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/stim/dialects/stim/test_stim_const.py +3 -2
  95. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/stim/wrapper/test_wrapper.py +32 -29
  96. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/uv.lock +5 -5
  97. bloqade_circuit-0.2.2/src/bloqade/noise/native/_dialect.py +0 -3
  98. bloqade_circuit-0.2.2/src/bloqade/noise/native/_wrappers.py +0 -34
  99. bloqade_circuit-0.2.2/src/bloqade/qasm2/dialects/core/__init__.py +0 -3
  100. bloqade_circuit-0.2.2/src/bloqade/qasm2/dialects/expr/__init__.py +0 -3
  101. bloqade_circuit-0.2.2/src/bloqade/qasm2/dialects/noise.py +0 -16
  102. bloqade_circuit-0.2.2/src/bloqade/qasm2/dialects/uop/__init__.py +0 -4
  103. bloqade_circuit-0.2.2/src/bloqade/squin/op/__init__.py +0 -162
  104. bloqade_circuit-0.2.2/src/bloqade/stim/__init__.py +0 -6
  105. bloqade_circuit-0.2.2/src/bloqade/stim/dialects/__init__.py +0 -5
  106. bloqade_circuit-0.2.2/src/bloqade/stim/dialects/collapse/__init__.py +0 -3
  107. bloqade_circuit-0.2.2/src/bloqade/stim/dialects/gate/__init__.py +0 -3
  108. bloqade_circuit-0.2.2/src/bloqade/stim/emit/__init__.py +0 -1
  109. bloqade_circuit-0.2.2/test/qasm2/parse/test_roundtrip.py +0 -30
  110. bloqade_circuit-0.2.2/test/visual/__init__.py +0 -0
  111. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/.github/dependabot.yml +0 -0
  112. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/.github/workflows/ci.yml +0 -0
  113. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/.github/workflows/isort.yml +0 -0
  114. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/.github/workflows/lint.yml +0 -0
  115. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/.github/workflows/release.yml +0 -0
  116. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/.gitignore +0 -0
  117. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/.pre-commit-config.yaml +0 -0
  118. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/LICENSE +0 -0
  119. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/README.md +0 -0
  120. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/_typos.toml +0 -0
  121. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/justfile +0 -0
  122. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/analysis/__init__.py +0 -0
  123. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/analysis/address/__init__.py +0 -0
  124. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/analysis/address/analysis.py +0 -0
  125. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/analysis/address/lattice.py +0 -0
  126. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/analysis/fidelity/__init__.py +0 -0
  127. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/device.py +0 -0
  128. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/noise/__init__.py +0 -0
  129. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/noise/native/__init__.py +0 -0
  130. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/noise/native/model.py +0 -0
  131. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/noise/native/rewrite.py +0 -0
  132. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/__init__.py +0 -0
  133. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/base.py +0 -0
  134. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/noise/__init__.py +0 -0
  135. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/noise/native.py +0 -0
  136. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/qasm2/__init__.py +0 -0
  137. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/qasm2/glob.py +0 -0
  138. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/qasm2/parallel.py +0 -0
  139. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/qasm2/uop.py +0 -0
  140. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/reg.py +0 -0
  141. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/squin/__init__.py +0 -0
  142. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/squin/op.py +0 -0
  143. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/squin/runtime.py +0 -0
  144. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/pyqrack/target.py +0 -0
  145. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/_wrappers.py +0 -0
  146. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/__init__.py +0 -0
  147. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/core/_dialect.py +0 -0
  148. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/core/_emit.py +0 -0
  149. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/core/_typeinfer.py +0 -0
  150. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/core/address.py +0 -0
  151. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/core/stmts.py +0 -0
  152. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/expr/_dialect.py +0 -0
  153. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/expr/_emit.py +0 -0
  154. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/expr/_from_python.py +0 -0
  155. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/expr/_interp.py +0 -0
  156. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/expr/stmts.py +0 -0
  157. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/glob.py +0 -0
  158. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/indexing.py +0 -0
  159. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/inline.py +0 -0
  160. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/parallel.py +0 -0
  161. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/uop/_dialect.py +0 -0
  162. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/uop/_emit.py +0 -0
  163. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/dialects/uop/stmts.py +0 -0
  164. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/emit/__init__.py +0 -0
  165. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/emit/base.py +0 -0
  166. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/emit/gate.py +0 -0
  167. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/glob.py +0 -0
  168. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/parallel.py +0 -0
  169. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/parse/ast.py +0 -0
  170. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/parse/build.py +0 -0
  171. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/parse/parser.py +0 -0
  172. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/parse/print.py +0 -0
  173. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/parse/visitor.py +0 -0
  174. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/parse/visitor.pyi +0 -0
  175. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/passes/glob.py +0 -0
  176. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/passes/lift_qubits.py +0 -0
  177. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/passes/py2qasm.py +0 -0
  178. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/passes/qasm2py.py +0 -0
  179. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/rewrite/glob.py +0 -0
  180. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/rewrite/insert_qubits.py +0 -0
  181. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/rewrite/parallel_to_uop.py +0 -0
  182. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/rewrite/register.py +0 -0
  183. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/rewrite/uop_to_parallel.py +0 -0
  184. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qasm2/types.py +0 -0
  185. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qbraid/__init__.py +0 -0
  186. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qbraid/lowering.py +0 -0
  187. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qbraid/schema.py +0 -0
  188. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qbraid/simulation_result.py +0 -0
  189. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/qbraid/target.py +0 -0
  190. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/__init__.py +0 -0
  191. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/analysis/__init__.py +0 -0
  192. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/analysis/nsites/analysis.py +0 -0
  193. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/analysis/nsites/lattice.py +0 -0
  194. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/analysis/schedule.py +0 -0
  195. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/groups.py +0 -0
  196. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/noise/_dialect.py +0 -0
  197. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/noise/stmts.py +0 -0
  198. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/op/_dialect.py +0 -0
  199. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/op/number.py +0 -0
  200. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/op/rewrite.py +0 -0
  201. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/op/stmts.py +0 -0
  202. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/op/traits.py +0 -0
  203. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/op/types.py +0 -0
  204. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/qubit.py +0 -0
  205. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/squin/rewrite/measure_desugar.py +0 -0
  206. {bloqade_circuit-0.2.2/src/bloqade/stim/dialects/aux → bloqade_circuit-0.3.0/src/bloqade/stim/dialects/auxiliary}/_dialect.py +0 -0
  207. {bloqade_circuit-0.2.2/src/bloqade/stim/dialects/aux → bloqade_circuit-0.3.0/src/bloqade/stim/dialects/auxiliary}/interp.py +0 -0
  208. {bloqade_circuit-0.2.2/src/bloqade/stim/dialects/aux → bloqade_circuit-0.3.0/src/bloqade/stim/dialects/auxiliary}/lowering.py +0 -0
  209. {bloqade_circuit-0.2.2/src/bloqade/stim/dialects/aux → bloqade_circuit-0.3.0/src/bloqade/stim/dialects/auxiliary}/stmts/__init__.py +0 -0
  210. {bloqade_circuit-0.2.2/src/bloqade/stim/dialects/aux → bloqade_circuit-0.3.0/src/bloqade/stim/dialects/auxiliary}/stmts/annotate.py +0 -0
  211. {bloqade_circuit-0.2.2/src/bloqade/stim/dialects/aux → bloqade_circuit-0.3.0/src/bloqade/stim/dialects/auxiliary}/stmts/const.py +0 -0
  212. {bloqade_circuit-0.2.2/src/bloqade/stim/dialects/aux → bloqade_circuit-0.3.0/src/bloqade/stim/dialects/auxiliary}/types.py +0 -0
  213. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/collapse/_dialect.py +0 -0
  214. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/collapse/stmts/__init__.py +0 -0
  215. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/collapse/stmts/measure.py +0 -0
  216. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/collapse/stmts/reset.py +0 -0
  217. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/gate/_dialect.py +0 -0
  218. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/gate/stmts/__init__.py +0 -0
  219. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/gate/stmts/clifford_1q.py +0 -0
  220. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/gate/stmts/clifford_2q.py +0 -0
  221. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/gate/stmts/control_2q.py +0 -0
  222. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/noise/__init__.py +0 -0
  223. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/noise/_dialect.py +0 -0
  224. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/stim/dialects/noise/stmts.py +0 -0
  225. /bloqade_circuit-0.2.2/src/bloqade/stim/emit/stim.py → /bloqade_circuit-0.3.0/src/bloqade/stim/emit/stim_str.py +0 -0
  226. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/task.py +0 -0
  227. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/test_utils.py +0 -0
  228. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/types.py +0 -0
  229. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/visual/__init__.py +0 -0
  230. {bloqade_circuit-0.2.2/src/bloqade/squin/rewrite → bloqade_circuit-0.3.0/src/bloqade/visual/animation}/__init__.py +0 -0
  231. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/visual/animation/animate.py +0 -0
  232. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/visual/animation/base.py +0 -0
  233. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/visual/animation/gate_event.py +0 -0
  234. {bloqade_circuit-0.2.2/src/bloqade/visual/animation → bloqade_circuit-0.3.0/src/bloqade/visual/animation/runtime}/__init__.py +0 -0
  235. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/visual/animation/runtime/aod.py +0 -0
  236. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/visual/animation/runtime/atoms.py +0 -0
  237. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/visual/animation/runtime/ppoly.py +0 -0
  238. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/visual/animation/runtime/qpustate.py +0 -0
  239. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/src/bloqade/visual/animation/runtime/utils.py +0 -0
  240. {bloqade_circuit-0.2.2/src/bloqade/visual/animation/runtime → bloqade_circuit-0.3.0/test}/__init__.py +0 -0
  241. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/analysis/address/test_analysis.py +0 -0
  242. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/analysis/address/test_lattice.py +0 -0
  243. {bloqade_circuit-0.2.2/test → bloqade_circuit-0.3.0/test/pyqrack}/__init__.py +0 -0
  244. {bloqade_circuit-0.2.2/test/pyqrack → bloqade_circuit-0.3.0/test/pyqrack/runtime}/__init__.py +0 -0
  245. {bloqade_circuit-0.2.2/test/pyqrack/runtime → bloqade_circuit-0.3.0/test/pyqrack/runtime/noise}/__init__.py +0 -0
  246. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/pyqrack/runtime/test_dyn_memory.py +0 -0
  247. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/pyqrack/runtime/test_qrack.py +0 -0
  248. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/pyqrack/test_squin.py +0 -0
  249. {bloqade_circuit-0.2.2/test/pyqrack/runtime/noise → bloqade_circuit-0.3.0/test/qasm2}/__init__.py +0 -0
  250. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/analysis/test_dag.py +0 -0
  251. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/emit/test_extended.py +0 -0
  252. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/emit/test_qasm2.py +0 -0
  253. {bloqade_circuit-0.2.2/test/qasm2 → bloqade_circuit-0.3.0/test/qasm2/parse}/__init__.py +0 -0
  254. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/README.md +0 -0
  255. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/global.qasm +0 -0
  256. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/iqft1.qasm +0 -0
  257. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/noise.qasm +0 -0
  258. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/para.qasm +0 -0
  259. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/process_tomo.qasm +0 -0
  260. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/qelib1.inc +0 -0
  261. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/qft.qasm +0 -0
  262. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/qft2.qasm +0 -0
  263. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/rb.qasm +0 -0
  264. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/rep_code.qasm +0 -0
  265. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/ripple_carry_adder.qasm +0 -0
  266. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/programs/tele.qasm +0 -0
  267. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/parse/test_ast.py +0 -0
  268. {bloqade_circuit-0.2.2/test/qasm2/parse → bloqade_circuit-0.3.0/test/qasm2/passes}/__init__.py +0 -0
  269. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/passes/test_global_to_parallel.py +0 -0
  270. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/passes/test_global_to_uop.py +0 -0
  271. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/passes/test_parallel_to_uop.py +0 -0
  272. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/passes/test_qasm2py.py +0 -0
  273. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/passes/test_uop_to_parallel.py +0 -0
  274. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/test_count.py +0 -0
  275. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/test_inline.py +0 -0
  276. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qasm2/test_two2one.py +0 -0
  277. {bloqade_circuit-0.2.2/test/qasm2/passes → bloqade_circuit-0.3.0/test/qbraid}/__init__.py +0 -0
  278. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qbraid/test_clean_circuit.py +0 -0
  279. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qbraid/test_lowering.py +0 -0
  280. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/qbraid/test_target.py +0 -0
  281. {bloqade_circuit-0.2.2/test/qbraid → bloqade_circuit-0.3.0/test/sample}/__init__.py +0 -0
  282. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/sample/test_noise_model.py +0 -0
  283. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/squin/analysis/test_nsites_analysis.py +0 -0
  284. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/squin/test_measure_sugar.py +0 -0
  285. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/squin/test_mult_rewrite.py +0 -0
  286. {bloqade_circuit-0.2.2/test/sample → bloqade_circuit-0.3.0/test/stim}/__init__.py +0 -0
  287. {bloqade_circuit-0.2.2/test/stim → bloqade_circuit-0.3.0/test/stim/dialects}/__init__.py +0 -0
  288. {bloqade_circuit-0.2.2/test/stim/dialects → bloqade_circuit-0.3.0/test/stim/dialects/stim}/__init__.py +0 -0
  289. {bloqade_circuit-0.2.2/test/stim/dialects/stim → bloqade_circuit-0.3.0/test/stim/dialects/stim/emit}/__init__.py +0 -0
  290. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/stim/dialects/stim/emit/base.py +0 -0
  291. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/stim/dialects/stim/emit/test_stim_1q.py +0 -0
  292. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/stim/dialects/stim/test_stim_circuits.py +0 -0
  293. {bloqade_circuit-0.2.2/test/stim/dialects/stim/emit → bloqade_circuit-0.3.0/test/stim/wrapper}/__init__.py +0 -0
  294. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/test_serialization.py +0 -0
  295. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/test_zone_model.py +0 -0
  296. {bloqade_circuit-0.2.2/test/stim/wrapper → bloqade_circuit-0.3.0/test/visual}/__init__.py +0 -0
  297. {bloqade_circuit-0.2.2 → bloqade_circuit-0.3.0}/test/visual/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bloqade-circuit
3
- Version: 0.2.2
3
+ Version: 0.3.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
@@ -9,8 +9,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
+ Requires-Dist: pyqrack-cpu<1.41,>=1.38.2; sys_platform != 'darwin'
13
+ Requires-Dist: pyqrack<1.41,>=1.38.2; sys_platform == 'darwin'
14
14
  Requires-Dist: rich>=13.9.4
15
15
  Requires-Dist: scipy>=1.13.1
16
16
  Provides-Extra: cirq
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bloqade-circuit"
3
- version = "0.2.2"
3
+ version = "0.3.0"
4
4
  description = "The software development toolkit for neutral atom arrays."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -17,8 +17,8 @@ dependencies = [
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
+ "pyqrack>=1.38.2,<1.41; sys_platform == 'darwin'",
21
+ "pyqrack-cpu>=1.38.2,<1.41 ; sys_platform != 'darwin'",
22
22
  ]
23
23
 
24
24
  [project.optional-dependencies]
@@ -206,6 +206,20 @@ class SquinWireMethodTable(interp.MethodTable):
206
206
  ):
207
207
  return frame.get_values(stmt.inputs)
208
208
 
209
+ @interp.impl(squin.wire.MeasureAndReset)
210
+ def measure_and_reset(
211
+ self,
212
+ interp_: AddressAnalysis,
213
+ frame: ForwardFrame[Address],
214
+ stmt: squin.wire.MeasureAndReset,
215
+ ):
216
+
217
+ # take the address data from the incoming wire
218
+ # and propagate that forward to the new wire generated.
219
+ # The first entry can safely be NotQubit because
220
+ # it's an integer
221
+ return (NotQubit(), frame.get(stmt.wire))
222
+
209
223
 
210
224
  @squin.qubit.dialect.register(key="qubit.address")
211
225
  class SquinQubitMethodTable(interp.MethodTable):
@@ -13,22 +13,47 @@ from ..address import AddressAnalysis
13
13
  class FidelityAnalysis(Forward):
14
14
  """
15
15
  This analysis pass can be used to track the global addresses of qubits and wires.
16
+
17
+ ## Usage examples
18
+
19
+ ```
20
+ from bloqade import qasm2
21
+ from bloqade.noise import native
22
+ from bloqade.analysis.fidelity import FidelityAnalysis
23
+ from bloqade.qasm2.passes.noise import NoisePass
24
+
25
+ noise_main = qasm2.extended.add(native.dialect)
26
+
27
+ @noise_main
28
+ def main():
29
+ q = qasm2.qreg(2)
30
+ qasm2.x(q[0])
31
+ return q
32
+
33
+ NoisePass(main.dialects)(main)
34
+
35
+ fid_analysis = FidelityAnalysis(main.dialects)
36
+ fid_analysis.run_analysis(main, no_raise=False)
37
+
38
+ gate_fidelity = fid_analysis.gate_fidelity
39
+ atom_survival_probs = fid_analysis.atom_survival_probability
40
+ ```
16
41
  """
17
42
 
18
43
  keys = ["circuit.fidelity"]
19
44
  lattice = EmptyLattice
20
45
 
46
+ gate_fidelity: float = 1.0
21
47
  """
22
48
  The fidelity of the gate set described by the analysed program. It reduces whenever a noise channel is encountered.
23
49
  """
24
- gate_fidelity: float = 1.0
25
50
 
26
51
  _current_gate_fidelity: float = field(init=False)
27
52
 
53
+ atom_survival_probability: list[float] = field(init=False)
28
54
  """
29
55
  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
56
  """
31
- atom_survival_probability: list[float] = field(init=False)
32
57
 
33
58
  _current_atom_survival_probability: list[float] = field(init=False)
34
59
 
@@ -1,14 +1,14 @@
1
1
  from kirin import interp
2
2
  from kirin.lattice import EmptyLattice
3
3
 
4
+ from bloqade.analysis.address import AddressQubit, AddressTuple
4
5
  from bloqade.analysis.fidelity import FidelityAnalysis
5
6
 
6
- from .native import dialect as native
7
+ from .native import dialect
7
8
  from .native.stmts import PauliChannel, CZPauliChannel, AtomLossChannel
8
- from ..analysis.address import AddressQubit, AddressTuple
9
9
 
10
10
 
11
- @native.register(key="circuit.fidelity")
11
+ @dialect.register(key="circuit.fidelity")
12
12
  class FidelityMethodTable(interp.MethodTable):
13
13
 
14
14
  @interp.impl(PauliChannel)
@@ -0,0 +1,3 @@
1
+ from kirin import ir
2
+
3
+ dialect = ir.Dialect("noise.native")
@@ -0,0 +1,63 @@
1
+ from typing import Any
2
+
3
+ from kirin.dialects import ilist
4
+ from kirin.lowering import wraps
5
+
6
+ from bloqade.noise import native
7
+ from bloqade.qasm2.types import Qubit
8
+
9
+
10
+ @wraps(native.AtomLossChannel)
11
+ def atom_loss_channel(qargs: ilist.IList[Qubit, Any] | list, *, prob: float) -> None:
12
+ """Apply an atom loss channel to a list of qubits.
13
+
14
+ Args:
15
+ qargs (ilist.IList[Qubit, Any] | list): List of qubits to apply the noise to.
16
+ prob (float): The loss probability.
17
+ """
18
+ ...
19
+
20
+
21
+ @wraps(native.PauliChannel)
22
+ def pauli_channel(
23
+ qargs: ilist.IList[Qubit, Any] | list, *, px: float, py: float, pz: float
24
+ ) -> None:
25
+ """Apply a Pauli channel to a list of qubits.
26
+
27
+ Args:
28
+ qargs (ilist.IList[Qubit, Any] | list): List of qubits to apply the noise to.
29
+ px (float): Probability of X error.
30
+ py (float): Probability of Y error.
31
+ pz (float): Probability of Z error.
32
+ """
33
+
34
+
35
+ @wraps(native.CZPauliChannel)
36
+ def cz_pauli_channel(
37
+ ctrls: ilist.IList[Qubit, Any] | list,
38
+ qargs: ilist.IList[Qubit, Any] | list,
39
+ *,
40
+ px_ctrl: float,
41
+ py_ctrl: float,
42
+ pz_ctrl: float,
43
+ px_qarg: float,
44
+ py_qarg: float,
45
+ pz_qarg: float,
46
+ paired: bool,
47
+ ) -> None:
48
+ """Insert noise for a CZ gate with a Pauli channel on qubits.
49
+
50
+ Args:
51
+ ctrls: List of control qubits.
52
+ qarg2: List of target qubits.
53
+ px_ctrl: Probability of X error on control qubits.
54
+ py_ctrl: Probability of Y error on control qubits.
55
+ pz_ctrl: Probability of Z error on control qubits.
56
+ px_qarg: Probability of X error on target qubits.
57
+ py_qarg: Probability of Y error on target qubits.
58
+ pz_qarg: Probability of Z error on target qubits.
59
+ paired: If True, the noise is applied to both control and target qubits
60
+ are not lost otherwise skip this error. If False Apply the noise on
61
+ the whatever qubit is not lost.
62
+ """
63
+ ...
@@ -4,7 +4,7 @@ from kirin import ir, types, lowering
4
4
  from kirin.decl import info, statement
5
5
  from kirin.dialects import ilist
6
6
 
7
- from bloqade.qasm2.types import QubitType
7
+ from bloqade.types import QubitType
8
8
 
9
9
  from ._dialect import dialect
10
10
 
@@ -25,7 +25,11 @@ Params = ParamSpec("Params")
25
25
 
26
26
  @dataclass
27
27
  class PyQrackSimulatorBase(AbstractSimulatorDevice[PyQrackSimulatorTask]):
28
+ """PyQrack simulation device base class."""
29
+
28
30
  options: PyQrackOptions = field(default_factory=_default_pyqrack_args)
31
+ """options (PyQrackOptions): options passed into the pyqrack simulator."""
32
+
29
33
  loss_m_result: Measurement = field(default=Measurement.One, kw_only=True)
30
34
  rng_state: np.random.Generator = field(
31
35
  default_factory=np.random.default_rng, kw_only=True
@@ -60,9 +64,7 @@ class PyQrackSimulatorBase(AbstractSimulatorDevice[PyQrackSimulatorTask]):
60
64
  kwargs: dict[str, Any] | None = None,
61
65
  ) -> list[complex]:
62
66
  """Runs task and returns the state vector."""
63
- task = self.task(kernel, args, kwargs)
64
- task.run()
65
- return task.state.sim_reg.out_ket()
67
+ return self.task(kernel, args, kwargs).state_vector()
66
68
 
67
69
  @staticmethod
68
70
  def pauli_expectation(pauli: list[Pauli], qubits: list[PyQrackQubit]) -> float:
@@ -96,12 +98,48 @@ class PyQrackSimulatorBase(AbstractSimulatorDevice[PyQrackSimulatorTask]):
96
98
  if len(qubit_ids) != len(set(qubit_ids)):
97
99
  raise ValueError("Qubits must be unique.")
98
100
 
99
- return sim_reg.pauli_expectation(pauli, qubit_ids)
101
+ return sim_reg.pauli_expectation(qubit_ids, pauli)
100
102
 
101
103
 
102
104
  @dataclass
103
105
  class StackMemorySimulator(PyQrackSimulatorBase):
104
- """PyQrack simulator device with precalculated stack of qubits."""
106
+ """
107
+ PyQrack simulator device with preallocated stack of qubits.
108
+
109
+ This can be used to simulate kernels where the number of qubits is known
110
+ ahead of time.
111
+
112
+ ## Usage examples
113
+
114
+ ```
115
+ # Define a kernel
116
+ @qasm2.main
117
+ def main():
118
+ q = qasm2.qreg(2)
119
+ c = qasm2.creg(2)
120
+
121
+ qasm2.h(q[0])
122
+ qasm2.cx(q[0], q[1])
123
+
124
+ qasm2.measure(q, c)
125
+ return q
126
+
127
+ # Create the simulator object
128
+ sim = StackMemorySimulator(min_qubits=2)
129
+
130
+ # Execute the kernel
131
+ qubits = sim.run(main)
132
+ ```
133
+
134
+ You can also obtain other information from it, such as the state vector:
135
+
136
+ ```
137
+ ket = sim.state_vector(main)
138
+
139
+ from pyqrack.pauli import Pauli
140
+ expectation_vals = sim.pauli_expectation([Pauli.PauliX, Pauli.PauliI], qubits)
141
+ ```
142
+ """
105
143
 
106
144
  min_qubits: int = field(default=0, kw_only=True)
107
145
 
@@ -111,6 +149,20 @@ class StackMemorySimulator(PyQrackSimulatorBase):
111
149
  args: tuple[Any, ...] = (),
112
150
  kwargs: dict[str, Any] | None = None,
113
151
  ):
152
+ """
153
+ Args:
154
+ kernel (ir.Method):
155
+ The kernel method to run.
156
+ args (tuple[Any, ...]):
157
+ Positional arguments to pass to the kernel method.
158
+ kwargs (dict[str, Any] | None):
159
+ Keyword arguments to pass to the kernel method.
160
+
161
+ Returns:
162
+ PyQrackSimulatorTask:
163
+ The task object used to track execution.
164
+
165
+ """
114
166
  if kwargs is None:
115
167
  kwargs = {}
116
168
 
@@ -136,7 +188,44 @@ class StackMemorySimulator(PyQrackSimulatorBase):
136
188
 
137
189
  @dataclass
138
190
  class DynamicMemorySimulator(PyQrackSimulatorBase):
139
- """PyQrack simulator device with dynamic qubit allocation."""
191
+ """
192
+
193
+ PyQrack simulator device with dynamic qubit allocation.
194
+
195
+ This can be used to simulate kernels where the number of qubits is not known
196
+ ahead of time.
197
+
198
+ ## Usage examples
199
+
200
+ ```
201
+ # Define a kernel
202
+ @qasm2.main
203
+ def main():
204
+ q = qasm2.qreg(2)
205
+ c = qasm2.creg(2)
206
+
207
+ qasm2.h(q[0])
208
+ qasm2.cx(q[0], q[1])
209
+
210
+ qasm2.measure(q, c)
211
+ return q
212
+
213
+ # Create the simulator object
214
+ sim = DynamicMemorySimulator()
215
+
216
+ # Execute the kernel
217
+ qubits = sim.run(main)
218
+ ```
219
+
220
+ You can also obtain other information from it, such as the state vector:
221
+
222
+ ```
223
+ ket = sim.state_vector(main)
224
+
225
+ from pyqrack.pauli import Pauli
226
+ expectation_vals = sim.pauli_expectation([Pauli.PauliX, Pauli.PauliI], qubits)
227
+
228
+ """
140
229
 
141
230
  def task(
142
231
  self,
@@ -144,23 +233,22 @@ class DynamicMemorySimulator(PyQrackSimulatorBase):
144
233
  args: tuple[Any, ...] = (),
145
234
  kwargs: dict[str, Any] | None = None,
146
235
  ):
236
+ """
237
+ Args:
238
+ kernel (ir.Method):
239
+ The kernel method to run.
240
+ args (tuple[Any, ...]):
241
+ Positional arguments to pass to the kernel method.
242
+ kwargs (dict[str, Any] | None):
243
+ Keyword arguments to pass to the kernel method.
244
+
245
+ Returns:
246
+ PyQrackSimulatorTask:
247
+ The task object used to track execution.
248
+
249
+ """
147
250
  if kwargs is None:
148
251
  kwargs = {}
149
252
 
150
253
  memory = DynamicMemory(self.options.copy())
151
254
  return self.new_task(kernel, args, kwargs, memory)
152
-
153
-
154
- def test():
155
- from bloqade.qasm2 import extended
156
-
157
- @extended
158
- def main():
159
- return 1
160
-
161
- @extended
162
- def obs(result: int) -> int:
163
- return result
164
-
165
- res = DynamicMemorySimulator().task(main)
166
- return res.run()
@@ -80,7 +80,10 @@ class PyQrackMethods(interp.MethodTable):
80
80
  @interp.impl(core.Reset)
81
81
  def reset(self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: core.Reset):
82
82
  qarg: PyQrackQubit = frame.get(stmt.qarg)
83
- qarg.sim_reg.force_m(qarg.addr, 0)
83
+
84
+ if bool(qarg.sim_reg.m(qarg.addr)):
85
+ qarg.sim_reg.x(qarg.addr)
86
+
84
87
  return ()
85
88
 
86
89
  @interp.impl(core.CRegEq)
@@ -37,9 +37,11 @@ class PyQrackMethods(interp.MethodTable):
37
37
  qubits: ilist.IList[PyQrackQubit, Any] = frame.get(stmt.qubits)
38
38
  operator.broadcast_apply(qubits)
39
39
 
40
- def _measure_qubit(self, qbit: PyQrackQubit):
40
+ def _measure_qubit(self, qbit: PyQrackQubit, interp: PyQrackInterpreter):
41
41
  if qbit.is_active():
42
42
  return bool(qbit.sim_reg.m(qbit.addr))
43
+ else:
44
+ return interp.loss_m_result
43
45
 
44
46
  @interp.impl(qubit.MeasureQubitList)
45
47
  def measure_qubit_list(
@@ -49,7 +51,7 @@ class PyQrackMethods(interp.MethodTable):
49
51
  stmt: qubit.MeasureQubitList,
50
52
  ):
51
53
  qubits: ilist.IList[PyQrackQubit, Any] = frame.get(stmt.qubits)
52
- result = ilist.IList([self._measure_qubit(qbit) for qbit in qubits])
54
+ result = ilist.IList([self._measure_qubit(qbit, interp) for qbit in qubits])
53
55
  return (result,)
54
56
 
55
57
  @interp.impl(qubit.MeasureQubit)
@@ -57,7 +59,7 @@ class PyQrackMethods(interp.MethodTable):
57
59
  self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: qubit.MeasureQubit
58
60
  ):
59
61
  qbit: PyQrackQubit = frame.get(stmt.qubit)
60
- result = self._measure_qubit(qbit)
62
+ result = self._measure_qubit(qbit, interp)
61
63
  return (result,)
62
64
 
63
65
  @interp.impl(qubit.MeasureAndReset)
@@ -70,11 +72,12 @@ class PyQrackMethods(interp.MethodTable):
70
72
  qubits: ilist.IList[PyQrackQubit, Any] = frame.get(stmt.qubits)
71
73
  result = []
72
74
  for qbit in qubits:
73
- if qbit.is_active():
74
- result.append(qbit.sim_reg.m(qbit.addr))
75
- else:
76
- result.append(None)
77
- qbit.sim_reg.force_m(qbit.addr, 0)
75
+ qbit_result = self._measure_qubit(qbit, interp)
76
+
77
+ if qbit_result:
78
+ qbit.sim_reg.x(qbit.addr)
79
+
80
+ result.append(qbit_result)
78
81
 
79
82
  return (ilist.IList(result),)
80
83
 
@@ -82,4 +85,8 @@ class PyQrackMethods(interp.MethodTable):
82
85
  def reset(self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: qubit.Reset):
83
86
  qubits: ilist.IList[PyQrackQubit, Any] = frame.get(stmt.qubits)
84
87
  for qbit in qubits:
85
- qbit.sim_reg.force_m(qbit.addr, 0)
88
+ if not qbit.is_active():
89
+ continue
90
+
91
+ if bool(qbit.sim_reg.m(qbit.addr)):
92
+ qbit.sim_reg.x(qbit.addr)
@@ -43,7 +43,11 @@ class PyQrackMethods(interp.MethodTable):
43
43
  ):
44
44
  w: PyQrackWire = frame.get(stmt.wire)
45
45
  qbit = w.qubit
46
- res: int = qbit.sim_reg.m(qbit.addr)
46
+
47
+ if not qbit.is_active():
48
+ return (interp.loss_m_result,)
49
+
50
+ res: bool = bool(qbit.sim_reg.m(qbit.addr))
47
51
  return (res,)
48
52
 
49
53
  @interp.impl(wire.MeasureAndReset)
@@ -55,8 +59,16 @@ class PyQrackMethods(interp.MethodTable):
55
59
  ):
56
60
  w: PyQrackWire = frame.get(stmt.wire)
57
61
  qbit = w.qubit
58
- res: int = qbit.sim_reg.m(qbit.addr)
59
- qbit.sim_reg.force_m(qbit.addr, False)
62
+
63
+ if not qbit.is_active():
64
+ return (w, interp.loss_m_result)
65
+
66
+ res: bool = bool(qbit.sim_reg.m(qbit.addr))
67
+
68
+ if res:
69
+ qbit.sim_reg.x(qbit.addr)
70
+
71
+ # TODO: do we need to rewrap this here? The qbit changed in-place
60
72
  new_w = PyQrackWire(qbit)
61
73
  return (new_w, res)
62
74
 
@@ -64,6 +76,12 @@ class PyQrackMethods(interp.MethodTable):
64
76
  def reset(self, interp: PyQrackInterpreter, frame: interp.Frame, stmt: wire.Reset):
65
77
  w: PyQrackWire = frame.get(stmt.wire)
66
78
  qbit = w.qubit
67
- qbit.sim_reg.force_m(qbit.addr, False)
79
+
80
+ if not qbit.is_active():
81
+ return (w,)
82
+
83
+ if bool(qbit.sim_reg.m(qbit.addr)):
84
+ qbit.sim_reg.x(qbit.addr)
85
+
68
86
  new_w = PyQrackWire(qbit)
69
87
  return (new_w,)
@@ -1,4 +1,4 @@
1
- from typing import TypeVar, ParamSpec
1
+ from typing import TypeVar, ParamSpec, cast
2
2
  from dataclasses import dataclass
3
3
 
4
4
  from bloqade.task import AbstractSimulatorTask
@@ -19,12 +19,20 @@ class PyQrackSimulatorTask(AbstractSimulatorTask[Param, RetType, MemoryType]):
19
19
  pyqrack_interp: PyQrackInterpreter[MemoryType]
20
20
 
21
21
  def run(self) -> RetType:
22
- return self.pyqrack_interp.run(
23
- self.kernel,
24
- args=self.args,
25
- kwargs=self.kwargs,
22
+ return cast(
23
+ RetType,
24
+ self.pyqrack_interp.run(
25
+ self.kernel,
26
+ args=self.args,
27
+ kwargs=self.kwargs,
28
+ ),
26
29
  )
27
30
 
28
31
  @property
29
32
  def state(self) -> MemoryType:
30
33
  return self.pyqrack_interp.memory
34
+
35
+ def state_vector(self) -> list[complex]:
36
+ """Returns the state vector of the simulator."""
37
+ self.run()
38
+ return self.state.sim_reg.out_ket()
@@ -17,3 +17,4 @@ from .types import (
17
17
  )
18
18
  from .groups import gate as gate, main as main, extended as extended
19
19
  from ._wrappers import * # noqa: F403
20
+ from ._qasm_loading import loads as loads, loadfile as loadfile
@@ -0,0 +1,151 @@
1
+ import os
2
+ import logging
3
+ import pathlib
4
+ from typing import Any
5
+
6
+ from kirin import ir, lowering
7
+ from kirin.dialects import func
8
+
9
+ from . import parse
10
+ from .groups import main
11
+ from .parse.lowering import QASM2
12
+
13
+
14
+ def loads(
15
+ qasm: str,
16
+ *,
17
+ kernel_name: str = "main",
18
+ dialects: ir.DialectGroup | None = None,
19
+ returns: str | None = None,
20
+ globals: dict[str, Any] | None = None,
21
+ file: str | None = None,
22
+ lineno_offset: int = 0,
23
+ col_offset: int = 0,
24
+ compactify: bool = True,
25
+ ) -> ir.Method[[], None]:
26
+ """Loads a QASM2 string and returns the corresponding kernel object.
27
+
28
+ Args:
29
+ qasm (str): The QASM2 string to load.
30
+
31
+ Keyword Args:
32
+ kernel_name (str): The name of the kernel to load. Defaults to "main".
33
+ dialects (ir.DialectGroup | None): The dialects to use. Defaults to `qasm2.main`.
34
+ returns (str | None): The return type of the kernel. Defaults to None.
35
+ globals (dict[str, Any] | None): The global variables to use. Defaults to None.
36
+ file (str | None): The file name for error reporting. Defaults to None.
37
+ lineno_offset (int): The line number offset for error reporting. Defaults to 0.
38
+ col_offset (int): The column number offset for error reporting. Defaults to 0.
39
+ compactify (bool): Whether to compactify the output. Defaults to True.
40
+
41
+ Example:
42
+
43
+ ```python
44
+ from bloqade import qasm2
45
+ method = qasm2.loads('''
46
+ OPENQASM 2.0;
47
+ qreg q[2];
48
+ creg c[2];
49
+ h q[0];
50
+ cx q[0], q[1];
51
+ measure q[0] -> c[0];
52
+ ''')
53
+ ```
54
+ """
55
+ # TODO: add source info
56
+ stmt = parse.loads(qasm)
57
+ qasm2_lowering = QASM2(dialects or main)
58
+ frame = qasm2_lowering.get_frame(
59
+ stmt,
60
+ source=qasm,
61
+ file=file,
62
+ globals=globals,
63
+ lineno_offset=lineno_offset,
64
+ col_offset=col_offset,
65
+ compactify=compactify,
66
+ )
67
+
68
+ if returns is not None:
69
+ return_value = frame.get(returns)
70
+ if return_value is None:
71
+ raise lowering.BuildError(f"Cannot find return value {returns}")
72
+ else:
73
+ return_value = func.ConstantNone()
74
+ frame.push(return_value)
75
+
76
+ return_node = frame.push(func.Return(value_or_stmt=return_value))
77
+
78
+ body = frame.curr_region
79
+ code = func.Function(
80
+ sym_name=kernel_name,
81
+ signature=func.Signature((), return_node.value.type),
82
+ body=body,
83
+ )
84
+
85
+ return ir.Method(
86
+ mod=None,
87
+ py_func=None,
88
+ sym_name=kernel_name,
89
+ arg_names=[],
90
+ dialects=qasm2_lowering.dialects,
91
+ code=code,
92
+ )
93
+
94
+
95
+ def loadfile(
96
+ qasm_file: str | pathlib.Path,
97
+ *,
98
+ kernel_name: str = "main",
99
+ dialects: ir.DialectGroup | None = None,
100
+ returns: str | None = None,
101
+ globals: dict[str, Any] | None = None,
102
+ file: str | None = None,
103
+ lineno_offset: int = 0,
104
+ col_offset: int = 0,
105
+ compactify: bool = True,
106
+ ) -> ir.Method[[], None]:
107
+ """Loads a QASM2 file and returns the corresponding kernel object. See also `loads`.
108
+
109
+ Args:
110
+ qasm_file (str): The QASM2 file to load.
111
+
112
+ Keyword Args:
113
+ kernel_name (str): The name of the kernel to load. Defaults to "main".
114
+ dialects (ir.DialectGroup | None): The dialects to use. Defaults to `qasm2.main`.
115
+ returns (str | None): The return type of the kernel. Defaults to None.
116
+ globals (dict[str, Any] | None): The global variables to use. Defaults to None.
117
+ file (str | None): The file name for error reporting. Defaults to None.
118
+ lineno_offset (int): The line number offset for error reporting. Defaults to 0.
119
+ col_offset (int): The column number offset for error reporting. Defaults to 0.
120
+ compactify (bool): Whether to compactify the output. Defaults to True.
121
+ """
122
+ if isinstance(file, pathlib.Path):
123
+ qasm_file_: pathlib.Path = qasm_file # type: ignore
124
+ else:
125
+ qasm_file_ = pathlib.Path(*os.path.split(qasm_file))
126
+
127
+ if not qasm_file_.is_file():
128
+ raise FileNotFoundError(f"File {qasm_file_} does not exist")
129
+
130
+ if not qasm_file_.name.endswith(".qasm") or not qasm_file_.name.endswith(".qasm2"):
131
+ logging.warning(
132
+ f"File {qasm_file_} does not end with .qasm or .qasm2. "
133
+ "This may cause issues with loading the file."
134
+ )
135
+
136
+ kernel_name = file.name.replace(".qasm", "") if kernel_name is None else kernel_name
137
+
138
+ with qasm_file_.open("r") as f:
139
+ source = f.read()
140
+
141
+ return loads(
142
+ source,
143
+ kernel_name=kernel_name,
144
+ dialects=dialects,
145
+ returns=returns,
146
+ globals=globals,
147
+ file=file,
148
+ lineno_offset=lineno_offset,
149
+ col_offset=col_offset,
150
+ compactify=compactify,
151
+ )