dense-evolution 8.2.3__tar.gz → 8.3.1__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.
Files changed (171) hide show
  1. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/PKG-INFO +14 -4
  2. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/README.md +11 -1
  3. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/__init__.py +18 -4
  4. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/circuits/__init__.py +10 -0
  5. dense_evolution-8.3.1/dense_evolution/circuits/arithmetic.py +241 -0
  6. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/circuits/parser.py +69 -6
  7. dense_evolution-8.3.1/dense_evolution/circuits/postselect.py +59 -0
  8. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/config.py +13 -0
  9. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/mitigation/__init__.py +4 -4
  10. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/mitigation/kl_divergence.py +3 -1
  11. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/mitigation/magic_entropy.py +3 -1
  12. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/mitigation/magic_entropy_shadows.py +5 -0
  13. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/mitigation/renyi.py +3 -1
  14. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/mitigation/stabilizer_renyi_entropy.py +3 -1
  15. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/mitigation/zne.py +123 -7
  16. dense_evolution-8.3.1/dense_evolution/native_hf/libcint_bridge.py +167 -0
  17. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/physics/__init__.py +5 -1
  18. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/physics/qec.py +359 -0
  19. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/qec.py +5 -2
  20. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution.egg-info/PKG-INFO +14 -4
  21. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution.egg-info/SOURCES.txt +2 -0
  22. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution.egg-info/requires.txt +2 -3
  23. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/pyproject.toml +5 -11
  24. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/hamiltonians.py +21 -4
  25. dense_evolution-8.2.3/dense_evolution/native_hf/libcint_bridge.py +0 -225
  26. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/autodiff.py +0 -0
  27. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/backends/__init__.py +0 -0
  28. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/backends/chunk/__init__.py +0 -0
  29. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/backends/chunk/_engine_imports.py +0 -0
  30. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/backends/chunk/circuit_chunker.py +0 -0
  31. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/backends/chunk/core.py +0 -0
  32. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/backends/chunk/disk_overflow.py +0 -0
  33. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/backends/chunk/geometry.py +0 -0
  34. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/backends/chunk/guard.py +0 -0
  35. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/backends/chunk/kernels.py +0 -0
  36. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/backends/mps.py +0 -0
  37. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/backends/statevector.py +0 -0
  38. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/chunk.py +0 -0
  39. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/circuits/compiler.py +0 -0
  40. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/circuits/diagram.py +0 -0
  41. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/circuits/gates.py +0 -0
  42. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/circuits/qft.py +0 -0
  43. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/circuits/random_circuit.py +0 -0
  44. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/circuits/registry.py +0 -0
  45. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/circuits/topology.py +0 -0
  46. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/circuits/trotter.py +0 -0
  47. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/circuits/uccsd.py +0 -0
  48. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/cli.py +0 -0
  49. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/compiler.py +0 -0
  50. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/drawing.py +0 -0
  51. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/entropy.py +0 -0
  52. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/fermions.py +0 -0
  53. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/gates.py +0 -0
  54. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/harrison_tb.py +0 -0
  55. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/healing.py +0 -0
  56. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/interop/__init__.py +0 -0
  57. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/interop/qiskit_pennylane.py +0 -0
  58. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/measurement.py +0 -0
  59. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/mitigation/healing.py +0 -0
  60. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/mps.py +0 -0
  61. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/native_hf/__init__.py +0 -0
  62. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/native_hf/assembly.py +0 -0
  63. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/native_hf/basis.py +0 -0
  64. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/native_hf/boys.py +0 -0
  65. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/native_hf/bridge.py +0 -0
  66. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/native_hf/cartesian.py +0 -0
  67. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/native_hf/coulomb.py +0 -0
  68. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/native_hf/differentiable.py +0 -0
  69. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/native_hf/gaussians.py +0 -0
  70. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/native_hf/kinetic.py +0 -0
  71. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/native_hf/overlap.py +0 -0
  72. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/native_hf/scf.py +0 -0
  73. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/__init__.py +0 -0
  74. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/coherent_attack.py +0 -0
  75. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/cosmic_ray.py +0 -0
  76. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/density_matrix_channels.py +0 -0
  77. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/differentiable.py +0 -0
  78. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/kraus/__init__.py +0 -0
  79. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/kraus/amplitude_damping.py +0 -0
  80. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/kraus/bitflip.py +0 -0
  81. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/kraus/combined.py +0 -0
  82. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/kraus/depolarizing.py +0 -0
  83. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/kraus/ideal.py +0 -0
  84. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/kraus/phaseflip.py +0 -0
  85. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/kraus_channels.py +0 -0
  86. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/oscillating.py +0 -0
  87. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/noise/pink.py +0 -0
  88. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/observables.py +0 -0
  89. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/parser.py +0 -0
  90. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/physics/entropy.py +0 -0
  91. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/physics/fermions.py +0 -0
  92. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/physics/observables.py +0 -0
  93. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/physics/spectral.py +0 -0
  94. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/physics/states.py +0 -0
  95. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/protocols/__init__.py +0 -0
  96. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/protocols/bb84.py +0 -0
  97. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/protocols/di_qkd_ghz.py +0 -0
  98. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/protocols/dicka_protocol2.py +0 -0
  99. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/qft.py +0 -0
  100. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/qmmm/__init__.py +0 -0
  101. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/qmmm/ase_bridge.py +0 -0
  102. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/qmmm/forces.py +0 -0
  103. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/qmmm/propagation.py +0 -0
  104. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/qmmm/region.py +0 -0
  105. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/random_circuit.py +0 -0
  106. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/registry.py +0 -0
  107. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/simulator.py +0 -0
  108. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/solvers/__init__.py +0 -0
  109. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/solvers/autodiff.py +0 -0
  110. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/solvers/harrison_tb.py +0 -0
  111. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/solvers/vhd_tb.py +0 -0
  112. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/states.py +0 -0
  113. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/topology.py +0 -0
  114. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/trotter.py +0 -0
  115. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/utils/__init__.py +0 -0
  116. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/utils/drawing.py +0 -0
  117. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/utils/mass_decomposition.py +0 -0
  118. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/utils/measurement.py +0 -0
  119. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution/vhd_tb.py +0 -0
  120. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution.egg-info/dependency_links.txt +0 -0
  121. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution.egg-info/entry_points.txt +0 -0
  122. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/dense_evolution.egg-info/top_level.txt +0 -0
  123. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/license.md +0 -0
  124. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/research/local_site/__init__.py +0 -0
  125. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/research/local_site/app/__init__.py +0 -0
  126. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/research/local_site/app/server.py +0 -0
  127. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/setup.cfg +0 -0
  128. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/__init__.py +0 -0
  129. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/_gate_tables.py +0 -0
  130. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/band_structure.py +0 -0
  131. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/circuit_builder_component.py +0 -0
  132. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/circuit_diagram.py +0 -0
  133. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/crypto_protocols.py +0 -0
  134. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/engine.py +0 -0
  135. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/graphical_builder.py +0 -0
  136. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/mass_decomposition_tool.py +0 -0
  137. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/mitigation.py +0 -0
  138. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/native_hf_diagnostics.py +0 -0
  139. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/noise_tools.py +0 -0
  140. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/qasm_library.py +0 -0
  141. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/qmmm.py +0 -0
  142. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/rag_tool.py +0 -0
  143. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/state_visuals.py +0 -0
  144. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/system_limits.py +0 -0
  145. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/vector_healing.py +0 -0
  146. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/visuals.py +0 -0
  147. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/vqe.py +0 -0
  148. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/dashboard/core/wormhole.py +0 -0
  149. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/ia_utils/__init__.py +0 -0
  150. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/ia_utils/adversarial_vector_attack.py +0 -0
  151. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/ia_utils/rag.py +0 -0
  152. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/ia_utils/vector_healing.py +0 -0
  153. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/__init__.py +0 -0
  154. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/client.py +0 -0
  155. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/config.py +0 -0
  156. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/models.py +0 -0
  157. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/molecules.py +0 -0
  158. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/server.py +0 -0
  159. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/tools/__init__.py +0 -0
  160. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/tools/chemistry_tools.py +0 -0
  161. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/tools/circuit_tools.py +0 -0
  162. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/tools/crypto_tools.py +0 -0
  163. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/tools/mitigation_tools.py +0 -0
  164. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/tools/noise_tools.py +0 -0
  165. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/tools/retrieval_tools.py +0 -0
  166. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/tools/system_tools.py +0 -0
  167. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/tools/wormhole_tools.py +0 -0
  168. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/utils/__init__.py +0 -0
  169. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/utils/cache.py +0 -0
  170. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/utils/images.py +0 -0
  171. {dense_evolution-8.2.3 → dense_evolution-8.3.1}/tools/mcp_server/utils/truncation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dense-evolution
3
- Version: 8.2.3
3
+ Version: 8.3.1
4
4
  Summary: High-performance quantum simulation toolkit -- Statevector/MPS engines with JIT compilation, noise modeling, VQE, QEC, quantum chemistry, and agent-native tooling
5
5
  Author-email: Salvatore Pennacchio <jtatopenn@libero.it>
6
6
  License: Business Source License 1.1
@@ -39,6 +39,8 @@ Requires-Dist: streamlit>=1.30.0; extra == "dashboard"
39
39
  Requires-Dist: qiskit>=1.0.0; extra == "dashboard"
40
40
  Requires-Dist: pylatexenc>=2.10; extra == "dashboard"
41
41
  Requires-Dist: plotly>=5.0.0; extra == "dashboard"
42
+ Requires-Dist: rdkit>=2023.9.1; extra == "dashboard"
43
+ Requires-Dist: basis_set_exchange>=0.9; extra == "dashboard"
42
44
  Provides-Extra: qiskit
43
45
  Requires-Dist: qiskit>=1.0.0; extra == "qiskit"
44
46
  Provides-Extra: pennylane
@@ -58,8 +60,6 @@ Provides-Extra: mcp
58
60
  Requires-Dist: mcp>=2.0.0; extra == "mcp"
59
61
  Requires-Dist: httpx>=0.27; extra == "mcp"
60
62
  Requires-Dist: pydantic>=2.0.0; extra == "mcp"
61
- Provides-Extra: libcint
62
- Requires-Dist: pyscf>=2.0.0; extra == "libcint"
63
63
  Provides-Extra: qmmm
64
64
  Requires-Dist: rdkit>=2023.9.1; extra == "qmmm"
65
65
  Provides-Extra: ase
@@ -108,6 +108,13 @@ Dynamic: license-file
108
108
  **A high-performance quantum simulation toolkit
109
109
  Statevector/MPS engines with compilation, noise, VQE, QEC, chemistry, and agent-native tooling.**
110
110
 
111
+ <p align="center">
112
+ <img src="docs/assets/favicon.svg" width="32" alt=""><br>
113
+ <b>Download the Dense Evolution Dashboard (Streamlit)</b><br>
114
+ <a href="https://github.com/tatopenn-cell/Dense-Evolution/raw/main/tools/installer/install-dashboard.bat">Windows (.bat)</a> &middot;
115
+ <a href="https://github.com/tatopenn-cell/Dense-Evolution/raw/main/tools/installer/install-dashboard.sh">macOS / Linux (.sh)</a>
116
+ </p>
117
+
111
118
  [![CI](https://github.com/tatopenn-cell/Dense-Evolution/actions/workflows/ci.yml/badge.svg)](https://github.com/tatopenn-cell/Dense-Evolution/actions/workflows/ci.yml)
112
119
  [![Docs](https://img.shields.io/badge/docs-tatopenn--cell.github.io-00e5ff?style=flat-square)](https://tatopenn-cell.github.io/Dense-Evolution/)
113
120
  [![codecov](https://codecov.io/gh/tatopenn-cell/Dense-Evolution/branch/main/graph/badge.svg)](https://codecov.io/gh/tatopenn-cell/Dense-Evolution)
@@ -293,8 +300,11 @@ sim.run_chunk(circuit.to_tuples(), chunk_size_gates=500)
293
300
 
294
301
  - **JIT-fused statevector engine.** No Kronecker-product overhead — stride-sliced linear kernel fusion compiled through JAX XLA, real GPU/TPU dispatch with no code change. [Simulator](https://tatopenn-cell.github.io/Dense-Evolution/api/simulator/) · [MPS backend](https://tatopenn-cell.github.io/Dense-Evolution/api/mps/) for low-entanglement circuits at scale.
295
302
  - **Anti-OOM `Chunk` engine.** Circuits too large for one array, split dynamically and sized off the real compute device's own free memory — with disk-backed overflow past even that ceiling. [Chunk guide](https://tatopenn-cell.github.io/Dense-Evolution/api/chunk/).
296
- - **Real noise, real mitigation.** Stochastic Kraus channels, real-device noise imported from Qiskit backends, and Zero-Noise Extrapolation to correct for it. [Noise](https://tatopenn-cell.github.io/Dense-Evolution/api/noise/) · [Mitigation](https://tatopenn-cell.github.io/Dense-Evolution/api/mitigation/) · [what noise/mitigation/healing each mean](https://tatopenn-cell.github.io/Dense-Evolution/concepts/).
303
+ - **Real noise, real mitigation.** Stochastic Kraus channels, real-device noise imported from Qiskit backends, and Zero-Noise Extrapolation, with the shot budget split optimally across noise factors and a single-qubit Bloch-vector variant that always returns a valid state, to correct for it. [Noise](https://tatopenn-cell.github.io/Dense-Evolution/api/noise/) · [Mitigation](https://tatopenn-cell.github.io/Dense-Evolution/api/mitigation/) · [what noise/mitigation/healing each mean](https://tatopenn-cell.github.io/Dense-Evolution/concepts/).
297
304
  - **Differentiable VQE, from scratch.** `circuit_to_energy_fn` is the same JAX-differentiable engine real molecular VQE runs on — real Hartree-Fock Hamiltonians, UCCSD/hardware-efficient ansätze, Adam optimization. [Autodiff](https://tatopenn-cell.github.io/Dense-Evolution/api/autodiff/).
305
+ - **libcint integrals on Windows, macOS and Linux.** `pip install dense-evolution` ships libcint compiled for each system: the full two-electron tensor of ethanol in 6-31G* in 0.32 s. [native_hf](https://tatopenn-cell.github.io/Dense-Evolution/api/native_hf/).
306
+ - **Reversible arithmetic.** Register adders, subtraction, comparisons and modular arithmetic up to modular exponentiation, applied as exact basis permutations and checked against the Vedral, Cuccaro, Draper and Beauregard circuits. [Arithmetic](https://tatopenn-cell.github.io/Dense-Evolution/api/arithmetic/).
307
+ - **Postselection.** Keep the branch where a qubit is found in `|0>`, `|1>`, `|±>` or `|±i>`, with its probability. [Postselection](https://tatopenn-cell.github.io/Dense-Evolution/api/postselect/).
298
308
  - **OpenQASM 2.0/3.0, both directions.** A real parser, plus Qiskit/PennyLane interop bridges. [QASM Parser](https://tatopenn-cell.github.io/Dense-Evolution/api/parser/) · [Interop](https://tatopenn-cell.github.io/Dense-Evolution/api/interop/).
299
309
  - **Code-agnostic QEC decoding**, Majorana/Jordan-Wigner fermion mapping, from-scratch Hartree-Fock for elements outside PennyLane's own basis set, a traversable-wormhole-inspired teleportation protocol, and real QM/MM region partitioning (ring-safe BFS, Diffuse2Seg-derived relevance propagation) — see the [full API reference](https://tatopenn-cell.github.io/Dense-Evolution/api/) for all of it.
300
310
 
@@ -8,6 +8,13 @@
8
8
  **A high-performance quantum simulation toolkit
9
9
  Statevector/MPS engines with compilation, noise, VQE, QEC, chemistry, and agent-native tooling.**
10
10
 
11
+ <p align="center">
12
+ <img src="docs/assets/favicon.svg" width="32" alt=""><br>
13
+ <b>Download the Dense Evolution Dashboard (Streamlit)</b><br>
14
+ <a href="https://github.com/tatopenn-cell/Dense-Evolution/raw/main/tools/installer/install-dashboard.bat">Windows (.bat)</a> &middot;
15
+ <a href="https://github.com/tatopenn-cell/Dense-Evolution/raw/main/tools/installer/install-dashboard.sh">macOS / Linux (.sh)</a>
16
+ </p>
17
+
11
18
  [![CI](https://github.com/tatopenn-cell/Dense-Evolution/actions/workflows/ci.yml/badge.svg)](https://github.com/tatopenn-cell/Dense-Evolution/actions/workflows/ci.yml)
12
19
  [![Docs](https://img.shields.io/badge/docs-tatopenn--cell.github.io-00e5ff?style=flat-square)](https://tatopenn-cell.github.io/Dense-Evolution/)
13
20
  [![codecov](https://codecov.io/gh/tatopenn-cell/Dense-Evolution/branch/main/graph/badge.svg)](https://codecov.io/gh/tatopenn-cell/Dense-Evolution)
@@ -193,8 +200,11 @@ sim.run_chunk(circuit.to_tuples(), chunk_size_gates=500)
193
200
 
194
201
  - **JIT-fused statevector engine.** No Kronecker-product overhead — stride-sliced linear kernel fusion compiled through JAX XLA, real GPU/TPU dispatch with no code change. [Simulator](https://tatopenn-cell.github.io/Dense-Evolution/api/simulator/) · [MPS backend](https://tatopenn-cell.github.io/Dense-Evolution/api/mps/) for low-entanglement circuits at scale.
195
202
  - **Anti-OOM `Chunk` engine.** Circuits too large for one array, split dynamically and sized off the real compute device's own free memory — with disk-backed overflow past even that ceiling. [Chunk guide](https://tatopenn-cell.github.io/Dense-Evolution/api/chunk/).
196
- - **Real noise, real mitigation.** Stochastic Kraus channels, real-device noise imported from Qiskit backends, and Zero-Noise Extrapolation to correct for it. [Noise](https://tatopenn-cell.github.io/Dense-Evolution/api/noise/) · [Mitigation](https://tatopenn-cell.github.io/Dense-Evolution/api/mitigation/) · [what noise/mitigation/healing each mean](https://tatopenn-cell.github.io/Dense-Evolution/concepts/).
203
+ - **Real noise, real mitigation.** Stochastic Kraus channels, real-device noise imported from Qiskit backends, and Zero-Noise Extrapolation, with the shot budget split optimally across noise factors and a single-qubit Bloch-vector variant that always returns a valid state, to correct for it. [Noise](https://tatopenn-cell.github.io/Dense-Evolution/api/noise/) · [Mitigation](https://tatopenn-cell.github.io/Dense-Evolution/api/mitigation/) · [what noise/mitigation/healing each mean](https://tatopenn-cell.github.io/Dense-Evolution/concepts/).
197
204
  - **Differentiable VQE, from scratch.** `circuit_to_energy_fn` is the same JAX-differentiable engine real molecular VQE runs on — real Hartree-Fock Hamiltonians, UCCSD/hardware-efficient ansätze, Adam optimization. [Autodiff](https://tatopenn-cell.github.io/Dense-Evolution/api/autodiff/).
205
+ - **libcint integrals on Windows, macOS and Linux.** `pip install dense-evolution` ships libcint compiled for each system: the full two-electron tensor of ethanol in 6-31G* in 0.32 s. [native_hf](https://tatopenn-cell.github.io/Dense-Evolution/api/native_hf/).
206
+ - **Reversible arithmetic.** Register adders, subtraction, comparisons and modular arithmetic up to modular exponentiation, applied as exact basis permutations and checked against the Vedral, Cuccaro, Draper and Beauregard circuits. [Arithmetic](https://tatopenn-cell.github.io/Dense-Evolution/api/arithmetic/).
207
+ - **Postselection.** Keep the branch where a qubit is found in `|0>`, `|1>`, `|±>` or `|±i>`, with its probability. [Postselection](https://tatopenn-cell.github.io/Dense-Evolution/api/postselect/).
198
208
  - **OpenQASM 2.0/3.0, both directions.** A real parser, plus Qiskit/PennyLane interop bridges. [QASM Parser](https://tatopenn-cell.github.io/Dense-Evolution/api/parser/) · [Interop](https://tatopenn-cell.github.io/Dense-Evolution/api/interop/).
199
209
  - **Code-agnostic QEC decoding**, Majorana/Jordan-Wigner fermion mapping, from-scratch Hartree-Fock for elements outside PennyLane's own basis set, a traversable-wormhole-inspired teleportation protocol, and real QM/MM region partitioning (ring-safe BFS, Diffuse2Seg-derived relevance propagation) — see the [full API reference](https://tatopenn-cell.github.io/Dense-Evolution/api/) for all of it.
200
210
 
@@ -31,7 +31,7 @@ from .backends.mps import MPSSimulator
31
31
  from .mitigation.zne import (richardson_extrapolate, richardson_amplification_factor,
32
32
  zero_noise_extrapolation, polynomial_extrapolate,
33
33
  bounded_exponential_extrapolate,
34
- project_to_physical, uhlmann_fidelity, zne_density_matrix,
34
+ project_to_physical, bloch_zne, bloch_zne_jit, uhlmann_fidelity, zne_density_matrix,
35
35
  jsd_predictive_zne_density_matrix,
36
36
  coherence_predictive_zne_density_matrix,
37
37
  classically_augmented_zne_phaseflip,
@@ -45,6 +45,12 @@ from .physics.observables import (pauli_expectation, pauli_sum_expectation, paul
45
45
  from .physics.states import ghz_state
46
46
  from .utils.measurement import sample_counts, statevector_fidelity
47
47
  from .circuits.qft import qft
48
+ from .circuits.arithmetic import (
49
+ add_registers, subtract_registers, add_constant,
50
+ compare_registers, compare_constant,
51
+ add_registers_mod, add_constant_mod, multiply_add_mod, multiply_mod, power_mod,
52
+ )
53
+ from .circuits.postselect import postselect
48
54
  from .circuits.random_circuit import random_circuit
49
55
  from .utils.drawing import draw_circuit
50
56
  from .solvers.harrison_tb import (ELEMENTS as HARRISON_ELEMENTS, ETA as HARRISON_ETA,
@@ -58,9 +64,11 @@ from .circuits.trotter import (pauli_rotation_ops, trotter_evolve_ops, continuou
58
64
  from .circuits.uccsd import find_excitations, single_excitation_ops, double_excitation_ops
59
65
  from .physics.qec import (pauli_commutes, compute_syndrome, erasure_aware_decode, pymatching_decode,
60
66
  blind_minimum_weight_decode, decode_with_erasure_fallback,
61
- counts_in_intervals_dimension, nearest_coset_decode)
67
+ counts_in_intervals_dimension, nearest_coset_decode, erasure_ml_decode,
68
+ peeling_decode, union_find_decode, matching_erasure_decode,
69
+ estimate_edge_probabilities_from_detection_events)
62
70
 
63
- __version__ = "8.2.3"
71
+ __version__ = "8.3.1"
64
72
 
65
73
  __all__ = [
66
74
  "__version__",
@@ -73,6 +81,10 @@ __all__ = [
73
81
  "NoiseModel", "NoiseSpec", "QuantumHardwareRegistry",
74
82
  "GATES", "PARAMETRIC_GATES", "GATE_IDS",
75
83
  "entangling_layer", "qft",
84
+ "add_registers", "subtract_registers", "add_constant",
85
+ "compare_registers", "compare_constant",
86
+ "add_registers_mod", "add_constant_mod", "multiply_add_mod", "multiply_mod", "power_mod",
87
+ "postselect",
76
88
  "pauli_rotation_ops", "trotter_evolve_ops", "continuous_pulse_evolve",
77
89
  "continuous_dissipative_evolve",
78
90
  "find_excitations", "single_excitation_ops", "double_excitation_ops",
@@ -89,7 +101,7 @@ __all__ = [
89
101
  "richardson_extrapolate", "richardson_amplification_factor",
90
102
  "zero_noise_extrapolation", "polynomial_extrapolate",
91
103
  "bounded_exponential_extrapolate",
92
- "project_to_physical", "uhlmann_fidelity", "zne_density_matrix",
104
+ "project_to_physical", "bloch_zne", "bloch_zne_jit", "uhlmann_fidelity", "zne_density_matrix",
93
105
  "jsd_predictive_zne_density_matrix", "coherence_predictive_zne_density_matrix",
94
106
  "classically_augmented_zne_phaseflip",
95
107
  "global_depolarizing_channel", "amplitude_damping_channel", "phaseflip_channel_exact",
@@ -105,6 +117,8 @@ __all__ = [
105
117
  "majorana_pauli_terms", "total_parity_operator", "hubbard_hamiltonian_pauli_terms", "square_lattice_edges",
106
118
  "pauli_commutes", "compute_syndrome", "erasure_aware_decode", "pymatching_decode", "blind_minimum_weight_decode",
107
119
  "decode_with_erasure_fallback", "counts_in_intervals_dimension", "nearest_coset_decode",
120
+ "erasure_ml_decode", "peeling_decode", "union_find_decode", "matching_erasure_decode",
121
+ "estimate_edge_probabilities_from_detection_events",
108
122
  # Utils -- drawing, measurement, random circuits
109
123
  "draw_circuit", "plot_circuit", "sample_counts", "statevector_fidelity", "random_circuit",
110
124
  ]
@@ -5,6 +5,12 @@ from .compiler import QuantumTranspiler
5
5
  from .registry import HAS_JAX, NoiseModel, NoiseSpec, QuantumHardwareRegistry
6
6
  from .topology import entangling_layer, VALID_PATTERNS
7
7
  from .qft import qft
8
+ from .arithmetic import (
9
+ add_registers, subtract_registers, add_constant,
10
+ compare_registers, compare_constant,
11
+ add_registers_mod, add_constant_mod, multiply_add_mod, multiply_mod, power_mod,
12
+ )
13
+ from .postselect import postselect
8
14
  from .random_circuit import random_circuit
9
15
  from .trotter import pauli_rotation_ops, trotter_evolve_ops
10
16
 
@@ -15,6 +21,10 @@ __all__ = [
15
21
  "HAS_JAX", "NoiseModel", "NoiseSpec", "QuantumHardwareRegistry",
16
22
  "entangling_layer", "VALID_PATTERNS",
17
23
  "qft",
24
+ "add_registers", "subtract_registers", "add_constant",
25
+ "compare_registers", "compare_constant",
26
+ "add_registers_mod", "add_constant_mod", "multiply_add_mod", "multiply_mod", "power_mod",
27
+ "postselect",
18
28
  "random_circuit",
19
29
  "pauli_rotation_ops", "trotter_evolve_ops",
20
30
  ]
@@ -0,0 +1,241 @@
1
+ """
2
+ Reversible arithmetic on qubit registers, applied to a statevector.
3
+
4
+ Every operation here is a bijection f on computational basis states, so its
5
+ unitary is the permutation U|x> = |f(x)> (Vedral, Barenco, Ekert,
6
+ quant-ph/9511018, Sect. II, Eqs. 2-3). It is applied directly as an index
7
+ permutation of the statevector, which is exact and costs one gather over the
8
+ 2^n amplitudes. The gate-level circuits from the papers (Cuccaro et al.
9
+ quant-ph/0410184 ripple-carry adder, Draper quant-ph/0008033 transform
10
+ adder) are the references the tests compare against.
11
+
12
+ A register is a list of qubit indices, least significant bit first. Qubit 0
13
+ is the most significant bit of the statevector index, as everywhere in the
14
+ engine.
15
+ """
16
+ import numpy as np
17
+
18
+ from ..config import ensure_x64
19
+ from .registry import HAS_JAX
20
+
21
+ if HAS_JAX:
22
+ import jax.numpy as jnp
23
+ xp = jnp
24
+ else:
25
+ xp = np
26
+
27
+ __all__ = ['add_registers', 'subtract_registers', 'add_constant',
28
+ 'compare_registers', 'compare_constant',
29
+ 'add_registers_mod', 'add_constant_mod', 'multiply_add_mod',
30
+ 'multiply_mod', 'power_mod']
31
+
32
+ _COMPARISONS = {
33
+ '<': np.less, '>': np.greater, '<=': np.less_equal,
34
+ '>=': np.greater_equal, '==': np.equal, '!=': np.not_equal,
35
+ }
36
+
37
+
38
+ def _register_values(n_qubits, register):
39
+ idx = np.arange(2 ** n_qubits)
40
+ value = np.zeros_like(idx)
41
+ for k, q in enumerate(register):
42
+ value |= ((idx >> (n_qubits - 1 - q)) & 1) << k
43
+ return idx, value
44
+
45
+
46
+ def _with_register(n_qubits, idx, register, value):
47
+ out = idx.copy()
48
+ for k, q in enumerate(register):
49
+ shift = n_qubits - 1 - q
50
+ out = (out & ~(1 << shift)) | (((value >> k) & 1) << shift)
51
+ return out
52
+
53
+
54
+ def _check(n_qubits, *registers):
55
+ used = [q for r in registers for q in r]
56
+ if len(set(used)) != len(used):
57
+ raise ValueError("registers must not share qubits")
58
+ if any(q < 0 or q >= n_qubits for q in used):
59
+ raise ValueError(f"qubit index out of range for {n_qubits} qubits")
60
+ if any(len(r) == 0 for r in registers):
61
+ raise ValueError("registers must not be empty")
62
+
63
+
64
+ def _permute(sv, target):
65
+ if xp is np:
66
+ sv = np.asarray(sv)
67
+ out = np.zeros_like(sv)
68
+ out[target] = sv
69
+ return out
70
+ ensure_x64()
71
+ sv = xp.asarray(sv)
72
+ return xp.zeros_like(sv).at[target].set(sv)
73
+
74
+
75
+ def add_registers(sv, n_qubits, a, b):
76
+ """
77
+ |a, b> -> |a, (a + b) mod 2^len(b)>.
78
+
79
+ With len(b) = len(a) + 1 the sum never overflows (Vedral et al.,
80
+ Sect. III.A, Eq. 9); with len(b) = len(a) it is addition modulo 2^n
81
+ (Cuccaro et al., Sect. 4.1).
82
+ """
83
+ _check(n_qubits, a, b)
84
+ idx, va = _register_values(n_qubits, a)
85
+ _, vb = _register_values(n_qubits, b)
86
+ target = _with_register(n_qubits, idx, b, (va + vb) % (1 << len(b)))
87
+ return _permute(sv, target)
88
+
89
+
90
+ def subtract_registers(sv, n_qubits, a, b):
91
+ """
92
+ |a, b> -> |a, (b - a) mod 2^len(b)>, the inverse of add_registers.
93
+
94
+ If b < a the result is 2^len(b) - (a - b) and, with len(b) = len(a) + 1,
95
+ its most significant qubit is 1 (Vedral et al., Sect. III.A).
96
+ """
97
+ _check(n_qubits, a, b)
98
+ idx, va = _register_values(n_qubits, a)
99
+ _, vb = _register_values(n_qubits, b)
100
+ target = _with_register(n_qubits, idx, b, (vb - va) % (1 << len(b)))
101
+ return _permute(sv, target)
102
+
103
+
104
+ def add_constant(sv, n_qubits, b, c):
105
+ """
106
+ |b> -> |(b + c) mod 2^len(b)> for a classical integer c.
107
+
108
+ c = 1 is increment, c = -1 decrement. Same operation as Draper's
109
+ transform adder with classical addend (Sect. 5) and Beauregard's
110
+ phiADD(c) (quant-ph/0205095, Sect. 2.1).
111
+ """
112
+ _check(n_qubits, b)
113
+ idx, vb = _register_values(n_qubits, b)
114
+ target = _with_register(n_qubits, idx, b, (vb + int(c)) % (1 << len(b)))
115
+ return _permute(sv, target)
116
+
117
+
118
+ def _flip_if(n_qubits, idx, out, condition):
119
+ return idx ^ (condition.astype(idx.dtype) << (n_qubits - 1 - out))
120
+
121
+
122
+ def _comparison(op):
123
+ if op not in _COMPARISONS:
124
+ raise ValueError(f"op must be one of {sorted(_COMPARISONS)}, got {op!r}")
125
+ return _COMPARISONS[op]
126
+
127
+
128
+ def compare_registers(sv, n_qubits, a, b, out, op='<'):
129
+ """
130
+ |a, b, z> -> |a, b, z XOR [a op b]>, inputs unchanged.
131
+
132
+ op = '<' is the comparator of Cuccaro et al. (Sect. 4.3): the high bit of
133
+ a - b, which is 1 if and only if a < b. The other comparisons follow by
134
+ swapping the operands and negating the output qubit.
135
+ """
136
+ _check(n_qubits, a, b, [out])
137
+ idx, va = _register_values(n_qubits, a)
138
+ _, vb = _register_values(n_qubits, b)
139
+ return _permute(sv, _flip_if(n_qubits, idx, out, _comparison(op)(va, vb)))
140
+
141
+
142
+ def compare_constant(sv, n_qubits, b, c, out, op='<'):
143
+ """
144
+ |b, z> -> |b, z XOR [b op c]> for a classical integer c.
145
+
146
+ op = '<' is the most significant qubit after the reverse phiADD(c) of
147
+ Beauregard (quant-ph/0205095, Sect. 2.1, Fig. 4).
148
+ """
149
+ _check(n_qubits, b, [out])
150
+ idx, vb = _register_values(n_qubits, b)
151
+ return _permute(sv, _flip_if(n_qubits, idx, out, _comparison(op)(vb, int(c))))
152
+
153
+
154
+ def _active(n_qubits, idx, controls):
155
+ on = np.ones(idx.shape, dtype=bool)
156
+ for q in controls:
157
+ on &= ((idx >> (n_qubits - 1 - q)) & 1).astype(bool)
158
+ return on
159
+
160
+
161
+ def _check_modulus(N, *registers):
162
+ if N < 1 or any(N > (1 << len(r)) for r in registers):
163
+ raise ValueError(f"modulus N={N} must be >= 1 and fit in the register")
164
+
165
+
166
+ def add_registers_mod(sv, n_qubits, a, b, N):
167
+ """
168
+ |a, b> -> |a, (a + b) mod N> for 0 <= a, b < N (Vedral et al., Sect. III.B,
169
+ Eq. 10). Basis states with a >= N or b >= N are left unchanged, which
170
+ keeps the map a permutation.
171
+ """
172
+ _check(n_qubits, a, b)
173
+ _check_modulus(N, a, b)
174
+ idx, va = _register_values(n_qubits, a)
175
+ _, vb = _register_values(n_qubits, b)
176
+ ok = (va < N) & (vb < N)
177
+ return _permute(sv, _with_register(n_qubits, idx, b, np.where(ok, (va + vb) % N, vb)))
178
+
179
+
180
+ def add_constant_mod(sv, n_qubits, b, c, N, controls=()):
181
+ """
182
+ |b> -> |(b + c) mod N> for 0 <= b < N, applied only where every control
183
+ qubit is 1: the doubly controlled phiADD(c)MOD(N) of Beauregard
184
+ (quant-ph/0205095, Sect. 2.2, Fig. 5). Basis states with b >= N are left
185
+ unchanged.
186
+ """
187
+ _check(n_qubits, b, *([list(controls)] if controls else []))
188
+ _check_modulus(N, b)
189
+ idx, vb = _register_values(n_qubits, b)
190
+ ok = _active(n_qubits, idx, controls) & (vb < N)
191
+ return _permute(sv, _with_register(n_qubits, idx, b, np.where(ok, (vb + int(c)) % N, vb)))
192
+
193
+
194
+ def multiply_add_mod(sv, n_qubits, x, b, a, N, controls=()):
195
+ """
196
+ |x, b> -> |x, (b + a*x) mod N> for 0 <= b < N, applied only where every
197
+ control qubit is 1: CMULT(a)MOD(N) of Beauregard (Sect. 2.3, Fig. 6),
198
+ built in the paper from n controlled modular additions of 2^i*a mod N
199
+ (Vedral et al., Sect. III.C). Basis states with b >= N are left unchanged.
200
+ """
201
+ _check(n_qubits, x, b, *([list(controls)] if controls else []))
202
+ _check_modulus(N, b)
203
+ idx, vx = _register_values(n_qubits, x)
204
+ _, vb = _register_values(n_qubits, b)
205
+ ok = _active(n_qubits, idx, controls) & (vb < N)
206
+ new = (vb + (int(a) % N) * (vx % N)) % N
207
+ return _permute(sv, _with_register(n_qubits, idx, b, np.where(ok, new, vb)))
208
+
209
+
210
+ def multiply_mod(sv, n_qubits, x, a, N, controls=()):
211
+ """
212
+ |x> -> |a*x mod N> in place for 0 <= x < N and gcd(a, N) = 1, applied only
213
+ where every control qubit is 1 (Vedral et al., Sect. II, Eqs. 4-6;
214
+ Beauregard, Sect. 2.3, Fig. 7). With N = 2^len(x) and odd a this is plain
215
+ multiplication modulo 2^n. Basis states with x >= N are left unchanged.
216
+ """
217
+ _check(n_qubits, x, *([list(controls)] if controls else []))
218
+ _check_modulus(N, x)
219
+ if np.gcd(int(a), N) != 1:
220
+ raise ValueError(f"a={a} and N={N} must be coprime for an in-place multiplication")
221
+ idx, vx = _register_values(n_qubits, x)
222
+ ok = _active(n_qubits, idx, controls) & (vx < N)
223
+ return _permute(sv, _with_register(n_qubits, idx, x, np.where(ok, (int(a) * vx) % N, vx)))
224
+
225
+
226
+ def power_mod(sv, n_qubits, x, y, a, N):
227
+ """
228
+ |x, y> -> |x, y * a^x mod N> for 0 <= y < N and gcd(a, N) = 1. With y = 1
229
+ this is the modular exponentiation |x, 1> -> |x, a^x mod N> of Shor's
230
+ algorithm (Vedral et al., Eq. 1 and Sect. III.D). Basis states with
231
+ y >= N are left unchanged.
232
+ """
233
+ _check(n_qubits, x, y)
234
+ _check_modulus(N, y)
235
+ if np.gcd(int(a), N) != 1:
236
+ raise ValueError(f"a={a} and N={N} must be coprime")
237
+ idx, vx = _register_values(n_qubits, x)
238
+ _, vy = _register_values(n_qubits, y)
239
+ powers = np.array([pow(int(a), int(e), N) for e in range(1 << len(x))])
240
+ ok = vy < N
241
+ return _permute(sv, _with_register(n_qubits, idx, y, np.where(ok, (vy * powers[vx]) % N, vy)))
@@ -260,12 +260,9 @@ class QASMParser:
260
260
  - `for` loops with unresolvable bounds, and all `if`/`while`/`def`
261
261
  blocks (no static execution — would need runtime classical bit
262
262
  state), are simply removed, leaving the rest of the source intact.
263
- - `gate` definitions are removed too — their body uses the gate's
264
- own formal parameter names, not real qubit indices, so it can't
265
- be executed directly; a later call site referencing that gate
266
- name still falls through as an unrecognized gate (silent no-op,
267
- same as any other unknown gate name elsewhere in this codebase),
268
- but no longer corrupts the qubit/statement that follows it.
263
+ - `gate` definitions never reach this loop: parse() lifts them out
264
+ first with _extract_gate_definitions and expands every call site
265
+ into the definition's body (_expand_gate_call).
269
266
 
270
267
  Runs as a search/replace loop rather than recursion: after an outer
271
268
  block is unrolled, any inner (nested) blocks are duplicated as raw
@@ -303,6 +300,70 @@ class QASMParser:
303
300
  s = s[:m.start()] + replacement + s[close_brace + 1:]
304
301
  return s
305
302
 
303
+ _RE_GATE_DEF = re.compile(r'\bgate\s+([a-zA-Z_]\w*)\s*(?:\(([^)]*)\))?\s*([^{]*)\{')
304
+
305
+ def _extract_gate_definitions(self, s: str) -> Tuple[str, Dict]:
306
+ """
307
+ Remove every `gate NAME(params) args { body }` definition from the
308
+ source and return it with a table NAME -> (params, args, body).
309
+
310
+ OpenQASM 2.0 defines new gates as a body of earlier gates acting on
311
+ formal arguments; exporters such as qiskit.qasm2.dumps write
312
+ composite and arithmetic circuits this way (e.g. gate_MAJ inside
313
+ CDKMRippleCarryAdder), so call sites must be expanded, not dropped.
314
+ """
315
+ defs: Dict[str, Tuple[List[str], List[str], str]] = {}
316
+ while True:
317
+ m = self._RE_GATE_DEF.search(s)
318
+ if not m:
319
+ return s, defs
320
+ close = self._find_matching_brace(s, m.end() - 1)
321
+ if close is None:
322
+ return s, defs
323
+ params = [p.strip() for p in (m.group(2) or '').split(',') if p.strip()]
324
+ args = [a.strip() for a in m.group(3).split(',') if a.strip()]
325
+ defs[m.group(1).lower()] = (params, args, s[m.end():close])
326
+ s = s[:m.start()] + s[close + 1:]
327
+
328
+ def _expand_gate_call(self, instr: str, defs: Dict, depth: int = 0) -> List[str]:
329
+ """
330
+ Replace a call to a user-defined gate by its body, with formal
331
+ arguments and parameters substituted, recursively for nested
332
+ definitions. Anything else is returned unchanged.
333
+ """
334
+ instr = re.sub(r'\s+', ' ', instr).strip()
335
+ head = re.split(r'[\s(]', instr, 1)[0].lower()
336
+ if head not in defs:
337
+ return [instr]
338
+ if depth > 64:
339
+ raise ValueError(f"gate definitions nested too deeply at '{head}'")
340
+ params, args, body = defs[head]
341
+ rest = instr[len(head):].strip()
342
+ actual_params: List[str] = []
343
+ if rest.startswith('('):
344
+ depth_p, close = 0, -1
345
+ for i, ch in enumerate(rest):
346
+ depth_p += (ch == '(') - (ch == ')')
347
+ if depth_p == 0:
348
+ close = i
349
+ break
350
+ actual_params = [t.strip() for t in self._split_params(rest[1:close])]
351
+ rest = rest[close + 1:]
352
+ actual_args = [a.strip() for a in rest.split(',') if a.strip()]
353
+ if len(actual_args) != len(args) or len(actual_params) != len(params):
354
+ raise ValueError(f"gate '{head}' expects {len(params)} parameters and "
355
+ f"{len(args)} qubits, got '{instr}'")
356
+ table = dict(zip(args, actual_args))
357
+ table.update({p: f'({v})' for p, v in zip(params, actual_params)})
358
+ if table:
359
+ names = re.compile(r'\b(' + '|'.join(re.escape(k) for k in table) + r')\b')
360
+ body = names.sub(lambda mm: table[mm.group(1)], body)
361
+ out: List[str] = []
362
+ for st in body.split(';'):
363
+ if st.strip():
364
+ out.extend(self._expand_gate_call(st, defs, depth + 1))
365
+ return out
366
+
306
367
  def parse(self, qasm_str: str) -> QASMCircuit:
307
368
  """
308
369
  Parse an OpenQASM 2.0 or 3.0 string into a QASMCircuit.
@@ -337,10 +398,12 @@ class QASMParser:
337
398
  # Must run before the ';'-split below: brace-delimited blocks are
338
399
  # not single ';'-terminated statements, and left alone they corrupt
339
400
  # whatever real statement follows them on the same line.
401
+ cleaned, gate_defs = self._extract_gate_definitions(cleaned)
340
402
  cleaned = self._process_block_constructs(cleaned)
341
403
 
342
404
  # ── split into statements ─────────────────────────────────────
343
405
  statements = [s.strip() for s in cleaned.split(';') if s.strip()]
406
+ statements = [e for st in statements for e in self._expand_gate_call(st, gate_defs)]
344
407
 
345
408
  for instr in statements:
346
409
  # collapse internal whitespace runs to a single space
@@ -0,0 +1,59 @@
1
+ """
2
+ Postselection: keep only the branch of the state in which a qubit is found in a
3
+ chosen state, then renormalise.
4
+
5
+ This is the operation in the definition of PostBQP (Aaronson,
6
+ quant-ph/0412187, Definition 1): the computation is conditioned on a
7
+ measurement outcome that has nonzero probability. It is not unitary, so it is
8
+ applied to the statevector directly, as the projector |psi><psi| on the
9
+ qubit followed by renormalisation, and the success probability is returned
10
+ with the new state.
11
+ """
12
+ import numpy as np
13
+
14
+ from ..config import ensure_x64
15
+ from .registry import HAS_JAX
16
+
17
+ if HAS_JAX:
18
+ import jax.numpy as jnp
19
+ xp = jnp
20
+ else:
21
+ xp = np
22
+
23
+ __all__ = ['postselect', 'POSTSELECT_STATES']
24
+
25
+ _R = 1 / np.sqrt(2)
26
+ POSTSELECT_STATES = {
27
+ '0': np.array([1, 0], dtype=np.complex128),
28
+ '1': np.array([0, 1], dtype=np.complex128),
29
+ '+': np.array([_R, _R], dtype=np.complex128),
30
+ '-': np.array([_R, -_R], dtype=np.complex128),
31
+ '+i': np.array([_R, 1j * _R], dtype=np.complex128),
32
+ '-i': np.array([_R, -1j * _R], dtype=np.complex128),
33
+ }
34
+
35
+
36
+ def postselect(sv, n_qubits, qubit, state='1'):
37
+ """
38
+ Project `qubit` onto `state` and renormalise.
39
+
40
+ `state` is one of '0', '1', '+', '-', '+i', '-i'. Returns
41
+ `(new_sv, probability)`, where `probability` is the chance of that outcome
42
+ before postselection. Raises ValueError if the probability is zero, since
43
+ postselection is only defined for outcomes that can occur (Aaronson,
44
+ Definition 1, condition (i)).
45
+ """
46
+ if state not in POSTSELECT_STATES:
47
+ raise ValueError(f"state must be one of {list(POSTSELECT_STATES)}, got {state!r}")
48
+ if not 0 <= qubit < n_qubits:
49
+ raise ValueError(f"qubit index out of range for {n_qubits} qubits")
50
+ if HAS_JAX:
51
+ ensure_x64()
52
+ psi = xp.asarray(POSTSELECT_STATES[state])
53
+ t = xp.asarray(sv).reshape(2 ** qubit, 2, 2 ** (n_qubits - qubit - 1))
54
+ overlap = xp.einsum('j,ijk->ik', xp.conj(psi), t)
55
+ probability = float(xp.sum(xp.abs(overlap) ** 2))
56
+ if probability <= 1e-15:
57
+ raise ValueError(f"outcome {state!r} on qubit {qubit} has zero probability")
58
+ projected = xp.einsum('j,ik->ijk', psi, overlap).reshape(-1)
59
+ return projected / np.sqrt(probability), probability
@@ -19,6 +19,8 @@ QuantumHardwareRegistry.__init__, circuit_to_energy_fn); set_precision()
19
19
  is the public opt-out for a caller who wants to choose precision
20
20
  explicitly, before constructing anything, and have that choice stick.
21
21
  """
22
+ import functools
23
+
22
24
  import jax
23
25
 
24
26
  _explicit = False
@@ -47,3 +49,14 @@ def ensure_x64() -> None:
47
49
  precision -- never at import time."""
48
50
  if not _explicit:
49
51
  jax.config.update("jax_enable_x64", True)
52
+
53
+
54
+ def with_x64(fn):
55
+ """Wrap `fn` so ensure_x64() runs before every call -- for public entry
56
+ points that build JAX arrays from user input, which JAX would otherwise
57
+ silently truncate to complex64/float32 if nothing else enabled x64 first."""
58
+ @functools.wraps(fn)
59
+ def wrapper(*args, **kwargs):
60
+ ensure_x64()
61
+ return fn(*args, **kwargs)
62
+ return wrapper
@@ -8,10 +8,10 @@ snapshots (magic_entropy_shadows), a multi-qubit per-state magic monotone
8
8
  that module's own docstring for the distinction), and the classical
9
9
  Kullback-Leibler divergence over probability distributions (kl_divergence)."""
10
10
  from .zne import (
11
- richardson_extrapolate, richardson_amplification_factor,
11
+ richardson_extrapolate, richardson_amplification_factor, zne_shot_allocation,
12
12
  zero_noise_extrapolation, polynomial_extrapolate,
13
13
  bounded_exponential_extrapolate,
14
- project_to_physical, uhlmann_fidelity, zne_density_matrix,
14
+ project_to_physical, bloch_zne, bloch_zne_jit, uhlmann_fidelity, zne_density_matrix,
15
15
  jsd_predictive_zne_density_matrix,
16
16
  coherence_predictive_zne_density_matrix,
17
17
  classically_augmented_zne_phaseflip,
@@ -33,10 +33,10 @@ from .magic_entropy_shadows import (
33
33
  from .kl_divergence import kl_divergence, kl_divergence_jit
34
34
 
35
35
  __all__ = [
36
- "richardson_extrapolate", "richardson_amplification_factor",
36
+ "richardson_extrapolate", "richardson_amplification_factor", "zne_shot_allocation",
37
37
  "zero_noise_extrapolation", "polynomial_extrapolate",
38
38
  "bounded_exponential_extrapolate",
39
- "project_to_physical", "uhlmann_fidelity", "zne_density_matrix",
39
+ "project_to_physical", "bloch_zne", "bloch_zne_jit", "uhlmann_fidelity", "zne_density_matrix",
40
40
  "jsd_predictive_zne_density_matrix",
41
41
  "coherence_predictive_zne_density_matrix",
42
42
  "classically_augmented_zne_phaseflip",
@@ -41,6 +41,7 @@ Additive, not a replacement for the already-validated healing pipeline.
41
41
  """
42
42
  import jax
43
43
  import jax.numpy as jnp
44
+ from ..config import with_x64
44
45
 
45
46
  __all__ = ["kl_divergence", "kl_divergence_jit"]
46
47
 
@@ -69,6 +70,7 @@ def _kl_divergence_core(p: jnp.ndarray, q: jnp.ndarray) -> jnp.ndarray:
69
70
  return jnp.where(is_support_violation, jnp.inf, finite_result)
70
71
 
71
72
 
73
+ @with_x64
72
74
  def kl_divergence(p: jnp.ndarray, q: jnp.ndarray) -> float:
73
75
  """Classical Kullback-Leibler divergence D_KL(p||q), in bits.
74
76
 
@@ -88,6 +90,6 @@ def kl_divergence(p: jnp.ndarray, q: jnp.ndarray) -> float:
88
90
  return float(_kl_divergence_core(p, q))
89
91
 
90
92
 
91
- kl_divergence_jit = jax.jit(_kl_divergence_core)
93
+ kl_divergence_jit = with_x64(jax.jit(_kl_divergence_core))
92
94
  """`jax.jit`-compiled entry point for `kl_divergence`. `p`/`q` must already
93
95
  be `float64` arrays. Returns a jnp scalar, not a Python `float`."""