dense-evolution 8.1.78__tar.gz → 8.1.80__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 (151) hide show
  1. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/PKG-INFO +5 -2
  2. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/README.md +1 -1
  3. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/__init__.py +1 -1
  4. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/backends/chunk/_engine_imports.py +21 -1
  5. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/backends/chunk/disk_overflow.py +35 -19
  6. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/backends/chunk/guard.py +25 -1
  7. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/backends/chunk/kernels.py +10 -87
  8. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/backends/mps.py +11 -3
  9. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/circuits/compiler.py +103 -113
  10. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/circuits/registry.py +19 -10
  11. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/interop/qiskit_pennylane.py +8 -1
  12. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/mitigation/healing.py +16 -9
  13. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/mitigation/magic_entropy.py +7 -1
  14. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/native_hf/assembly.py +116 -45
  15. dense_evolution-8.1.80/dense_evolution/native_hf/differentiable.py +53 -0
  16. dense_evolution-8.1.80/dense_evolution/native_hf/scf.py +327 -0
  17. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/kraus_channels.py +12 -0
  18. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/physics/__init__.py +3 -2
  19. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/physics/entropy.py +27 -1
  20. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/physics/observables.py +1 -1
  21. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/physics/qec.py +13 -5
  22. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/solvers/autodiff.py +1 -1
  23. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution.egg-info/PKG-INFO +5 -2
  24. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution.egg-info/SOURCES.txt +3 -0
  25. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution.egg-info/requires.txt +3 -0
  26. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/pyproject.toml +15 -3
  27. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/__init__.py +30 -10
  28. dense_evolution-8.1.80/tools/dashboard/core/_gate_tables.py +30 -0
  29. dense_evolution-8.1.80/tools/dashboard/core/band_structure.py +71 -0
  30. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/circuit_builder_component.py +5 -5
  31. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/circuit_diagram.py +22 -10
  32. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/engine.py +35 -3
  33. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/graphical_builder.py +9 -0
  34. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/hamiltonians.py +21 -12
  35. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/mitigation.py +20 -0
  36. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/noise_tools.py +10 -0
  37. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/qasm_library.py +5 -8
  38. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/qmmm.py +81 -33
  39. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/state_visuals.py +51 -3
  40. dense_evolution-8.1.80/tools/dashboard/core/visuals.py +158 -0
  41. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/vqe.py +80 -8
  42. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/wormhole.py +19 -33
  43. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/server.py +6 -2
  44. dense_evolution-8.1.78/dense_evolution/native_hf/scf.py +0 -240
  45. dense_evolution-8.1.78/tools/dashboard/core/visuals.py +0 -59
  46. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/autodiff.py +0 -0
  47. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/backends/__init__.py +0 -0
  48. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/backends/chunk/__init__.py +0 -0
  49. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/backends/chunk/circuit_chunker.py +0 -0
  50. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/backends/chunk/core.py +0 -0
  51. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/backends/chunk/geometry.py +0 -0
  52. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/backends/statevector.py +0 -0
  53. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/chunk.py +0 -0
  54. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/circuits/__init__.py +0 -0
  55. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/circuits/diagram.py +0 -0
  56. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/circuits/gates.py +0 -0
  57. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/circuits/parser.py +0 -0
  58. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/circuits/qft.py +0 -0
  59. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/circuits/random_circuit.py +0 -0
  60. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/circuits/topology.py +0 -0
  61. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/circuits/trotter.py +0 -0
  62. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/circuits/uccsd.py +0 -0
  63. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/cli.py +0 -0
  64. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/compiler.py +0 -0
  65. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/config.py +0 -0
  66. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/drawing.py +0 -0
  67. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/entropy.py +0 -0
  68. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/fermions.py +0 -0
  69. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/gates.py +0 -0
  70. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/harrison_tb.py +0 -0
  71. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/healing.py +0 -0
  72. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/interop/__init__.py +0 -0
  73. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/measurement.py +0 -0
  74. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/mitigation/__init__.py +0 -0
  75. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/mitigation/kl_divergence.py +0 -0
  76. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/mitigation/magic_entropy_shadows.py +0 -0
  77. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/mitigation/renyi.py +0 -0
  78. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/mitigation/stabilizer_renyi_entropy.py +0 -0
  79. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/mitigation/zne.py +0 -0
  80. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/mps.py +0 -0
  81. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/native_hf/__init__.py +0 -0
  82. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/native_hf/basis.py +0 -0
  83. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/native_hf/boys.py +0 -0
  84. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/native_hf/bridge.py +0 -0
  85. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/native_hf/cartesian.py +0 -0
  86. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/native_hf/coulomb.py +0 -0
  87. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/native_hf/gaussians.py +0 -0
  88. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/native_hf/kinetic.py +0 -0
  89. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/native_hf/libcint_bridge.py +0 -0
  90. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/native_hf/overlap.py +0 -0
  91. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/__init__.py +0 -0
  92. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/coherent_attack.py +0 -0
  93. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/cosmic_ray.py +0 -0
  94. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/density_matrix_channels.py +0 -0
  95. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/differentiable.py +0 -0
  96. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/kraus/__init__.py +0 -0
  97. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/kraus/amplitude_damping.py +0 -0
  98. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/kraus/bitflip.py +0 -0
  99. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/kraus/combined.py +0 -0
  100. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/kraus/depolarizing.py +0 -0
  101. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/kraus/ideal.py +0 -0
  102. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/kraus/phaseflip.py +0 -0
  103. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/noise/oscillating.py +0 -0
  104. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/observables.py +0 -0
  105. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/parser.py +0 -0
  106. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/physics/fermions.py +0 -0
  107. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/physics/states.py +0 -0
  108. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/qec.py +0 -0
  109. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/qft.py +0 -0
  110. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/random_circuit.py +0 -0
  111. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/registry.py +0 -0
  112. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/simulator.py +0 -0
  113. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/solvers/__init__.py +0 -0
  114. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/solvers/harrison_tb.py +0 -0
  115. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/solvers/vhd_tb.py +0 -0
  116. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/states.py +0 -0
  117. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/topology.py +0 -0
  118. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/trotter.py +0 -0
  119. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/utils/__init__.py +0 -0
  120. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/utils/drawing.py +0 -0
  121. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/utils/measurement.py +0 -0
  122. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution/vhd_tb.py +0 -0
  123. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution.egg-info/dependency_links.txt +0 -0
  124. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution.egg-info/entry_points.txt +0 -0
  125. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/dense_evolution.egg-info/top_level.txt +0 -0
  126. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/license.md +0 -0
  127. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/research/local_site/__init__.py +0 -0
  128. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/research/local_site/app/__init__.py +0 -0
  129. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/research/local_site/app/server.py +0 -0
  130. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/setup.cfg +0 -0
  131. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/system_limits.py +0 -0
  132. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/dashboard/core/vector_healing.py +0 -0
  133. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/ia_utils/__init__.py +0 -0
  134. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/ia_utils/adversarial_vector_attack.py +0 -0
  135. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/ia_utils/vector_healing.py +0 -0
  136. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/__init__.py +0 -0
  137. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/client.py +0 -0
  138. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/config.py +0 -0
  139. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/models.py +0 -0
  140. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/molecules.py +0 -0
  141. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/tools/__init__.py +0 -0
  142. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/tools/chemistry_tools.py +0 -0
  143. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/tools/circuit_tools.py +0 -0
  144. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/tools/mitigation_tools.py +0 -0
  145. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/tools/noise_tools.py +0 -0
  146. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/tools/system_tools.py +0 -0
  147. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/tools/wormhole_tools.py +0 -0
  148. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/utils/__init__.py +0 -0
  149. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/utils/cache.py +0 -0
  150. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/tools/mcp_server/utils/images.py +0 -0
  151. {dense_evolution-8.1.78 → dense_evolution-8.1.80}/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.1.78
3
+ Version: 8.1.80
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
@@ -38,6 +38,7 @@ Provides-Extra: dashboard
38
38
  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
+ Requires-Dist: plotly>=5.0.0; extra == "dashboard"
41
42
  Provides-Extra: qiskit
42
43
  Requires-Dist: qiskit>=1.0.0; extra == "qiskit"
43
44
  Provides-Extra: pennylane
@@ -64,6 +65,7 @@ Requires-Dist: cupy-cuda12x>=12.0.0; extra == "full"
64
65
  Requires-Dist: streamlit>=1.30.0; extra == "full"
65
66
  Requires-Dist: qiskit>=1.0.0; extra == "full"
66
67
  Requires-Dist: pylatexenc>=2.10; extra == "full"
68
+ Requires-Dist: plotly>=5.0.0; extra == "full"
67
69
  Requires-Dist: pennylane>=0.35.0; extra == "full"
68
70
  Requires-Dist: basis_set_exchange>=0.9; extra == "full"
69
71
  Requires-Dist: fastapi>=0.110.0; extra == "full"
@@ -82,6 +84,7 @@ Requires-Dist: mkdocs-include-markdown-plugin>=6.0.0; extra == "docs"
82
84
  Requires-Dist: ruff>=0.4.0; extra == "docs"
83
85
  Requires-Dist: pennylane>=0.35.0; extra == "docs"
84
86
  Requires-Dist: basis_set_exchange>=0.9; extra == "docs"
87
+ Requires-Dist: plotly>=5.0.0; extra == "docs"
85
88
  Dynamic: license-file
86
89
 
87
90
  <p align="center">
@@ -335,7 +338,7 @@ If Dense-Evolution is useful in academic work, please cite it via the metadata i
335
338
  Archived on [Zenodo](https://zenodo.org/):
336
339
 
337
340
  - **Concept DOI** (always resolves to the latest version): [10.5281/zenodo.21855643](https://doi.org/10.5281/zenodo.21855643)
338
- - **This release (v8.1.74)**: [10.5281/zenodo.22669081](https://doi.org/10.5281/zenodo.22669081)
341
+ - **This release (v8.1.78)**: [10.5281/zenodo.22706039](https://doi.org/10.5281/zenodo.22706039)
339
342
 
340
343
  ---
341
344
 
@@ -249,7 +249,7 @@ If Dense-Evolution is useful in academic work, please cite it via the metadata i
249
249
  Archived on [Zenodo](https://zenodo.org/):
250
250
 
251
251
  - **Concept DOI** (always resolves to the latest version): [10.5281/zenodo.21855643](https://doi.org/10.5281/zenodo.21855643)
252
- - **This release (v8.1.74)**: [10.5281/zenodo.22669081](https://doi.org/10.5281/zenodo.22669081)
252
+ - **This release (v8.1.78)**: [10.5281/zenodo.22706039](https://doi.org/10.5281/zenodo.22706039)
253
253
 
254
254
  ---
255
255
 
@@ -57,7 +57,7 @@ from .physics.qec import (pauli_commutes, compute_syndrome, erasure_aware_decode
57
57
  blind_minimum_weight_decode, decode_with_erasure_fallback,
58
58
  counts_in_intervals_dimension, nearest_coset_decode)
59
59
 
60
- __version__ = "8.1.78"
60
+ __version__ = "8.1.80"
61
61
 
62
62
  __all__ = [
63
63
  "__version__",
@@ -10,11 +10,13 @@ import numpy as np
10
10
  try:
11
11
  from simulator import DenseSVSimulator
12
12
  from compiler import QuantumTranspiler # pragma: no cover
13
+ from circuits.compiler import _gate_1q_matrix # pragma: no cover
13
14
  from gates import GATE_IDS # pragma: no cover
14
15
  except ModuleNotFoundError:
15
16
  try:
16
17
  from dense_evolution.simulator import DenseSVSimulator
17
18
  from dense_evolution.compiler import QuantumTranspiler
19
+ from dense_evolution.circuits.compiler import _gate_1q_matrix
18
20
  from dense_evolution.gates import GATE_IDS
19
21
  except ModuleNotFoundError: # pragma: no cover
20
22
  class DenseSVSimulator: # type: ignore[no-redef]
@@ -28,10 +30,28 @@ except ModuleNotFoundError:
28
30
  def memory_mb(self) -> float:
29
31
  return (self.dim * np.dtype(self.dtype).itemsize) / 1_000_000
30
32
 
33
+ def _unavailable(self, name):
34
+ raise NotImplementedError(
35
+ f"DenseSVSimulator stub: {name}() is not implemented here -- this "
36
+ "class only exists because the real dense_evolution/JAX modules "
37
+ "were not importable in this deployment (see this module's own "
38
+ "comment above); it is not a working simulator."
39
+ )
40
+
41
+ def get_probabilities(self): self._unavailable("get_probabilities")
42
+ def get_statevector(self): self._unavailable("get_statevector")
43
+ def apply_gate_1q(self, gate, q1): self._unavailable("apply_gate_1q")
44
+ def apply_gate_2q(self, gate, q1, q2): self._unavailable("apply_gate_2q")
45
+
31
46
  class QuantumTranspiler: # type: ignore[no-redef]
32
47
  @staticmethod
33
48
  def transpile(circuit): return circuit
34
49
 
50
+ def _gate_1q_matrix(g_id, param, dtype): # type: ignore[no-redef]
51
+ raise NotImplementedError(
52
+ "_gate_1q_matrix stub: real dense_evolution/JAX not importable in this deployment"
53
+ )
54
+
35
55
  GATE_IDS: dict = {}
36
56
 
37
- __all__ = ["DenseSVSimulator", "QuantumTranspiler", "GATE_IDS"]
57
+ __all__ = ["DenseSVSimulator", "QuantumTranspiler", "GATE_IDS", "_gate_1q_matrix"]
@@ -48,13 +48,17 @@ class LocalPhase:
48
48
 
49
49
 
50
50
  class ConditionalPhase:
51
- """A single 2-qubit gate with ctrl chunk-select (q1 < m), tgt local
52
- (q2 >= m) -- applied to each chunk independently, conditioned on
53
- that chunk's own absolute index (see _case_2q_ctrl_chunk_tgt_local)."""
54
- __slots__ = ("op",)
51
+ """A maximal run of consecutive 2-qubit gates with ctrl chunk-select
52
+ (q1 < m), tgt local (q2 >= m) -- applied to each chunk independently,
53
+ each op conditioned on that chunk's own absolute index (see
54
+ _case_2q_ctrl_chunk_tgt_local). Batched the same way LocalPhase is
55
+ (was: strictly one gate per phase object, so consecutive
56
+ ConditionalPhase-eligible gates did one full disk load/save cycle per
57
+ chunk PER GATE instead of once for the whole run -- prog.txt point 5b)."""
58
+ __slots__ = ("ops",)
55
59
 
56
- def __init__(self, op):
57
- self.op = op # single (g_id, q1, q2, param)
60
+ def __init__(self, ops):
61
+ self.ops = ops # list of (g_id, q1, q2, param) python tuples
58
62
 
59
63
 
60
64
  class MixPhase:
@@ -78,30 +82,41 @@ def partition_ops_into_phases(compiled_ops, m: int):
78
82
  rows = np.asarray(compiled_ops)
79
83
  phases = []
80
84
  pending_local = []
85
+ pending_conditional = []
81
86
 
82
- def flush():
87
+ def flush_local():
83
88
  if pending_local:
84
89
  phases.append(LocalPhase(list(pending_local)))
85
90
  pending_local.clear()
86
91
 
92
+ def flush_conditional():
93
+ if pending_conditional:
94
+ phases.append(ConditionalPhase(list(pending_conditional)))
95
+ pending_conditional.clear()
96
+
87
97
  for row in rows:
88
98
  g_id, q1, q2, param = int(row[0]), int(row[1]), int(row[2]), float(row[3])
89
99
  is_2q = g_id >= 20
90
100
  if not is_2q:
91
101
  if q1 < m:
92
- flush()
102
+ flush_local()
103
+ flush_conditional()
93
104
  phases.append(MixPhase((g_id, q1, q2, param), q1))
94
105
  else:
106
+ flush_conditional()
95
107
  pending_local.append((g_id, q1, q2, param))
96
108
  elif q1 < m and q2 >= m:
97
- flush()
98
- phases.append(ConditionalPhase((g_id, q1, q2, param)))
109
+ flush_local()
110
+ pending_conditional.append((g_id, q1, q2, param))
99
111
  elif q2 < m:
100
- flush()
112
+ flush_local()
113
+ flush_conditional()
101
114
  phases.append(MixPhase((g_id, q1, q2, param), q2))
102
115
  else:
116
+ flush_conditional()
103
117
  pending_local.append((g_id, q1, q2, param))
104
- flush()
118
+ flush_local()
119
+ flush_conditional()
105
120
  return phases
106
121
 
107
122
 
@@ -122,16 +137,17 @@ def _run_local_phase_on_chunk(chunk_arr, ops, m: int, k: int):
122
137
  return c[0]
123
138
 
124
139
 
125
- def _run_conditional_phase_on_chunk(chunk_arr, op, chunk_index: int, m: int, k: int):
126
- """A single ConditionalPhase gate, applied to one chunk whose real
140
+ def _run_conditional_phase_on_chunk(chunk_arr, ops, chunk_index: int, m: int, k: int):
141
+ """A run of ConditionalPhase gates, applied to one chunk whose real
127
142
  absolute index is `chunk_index` (needed for the ctrl-bit decision;
128
- see _case_2q_ctrl_chunk_tgt_local's own docstring)."""
129
- g_id, q1, q2, param = op
143
+ see _case_2q_ctrl_chunk_tgt_local's own docstring). Same load-once/
144
+ apply-all/save-once shape as _run_local_phase_on_chunk."""
130
145
  dtype = chunk_arr.dtype
131
- _, _, _, _, u00, u01, u10, u11 = _gate_matrix_elements(g_id, param, dtype)
132
146
  c = chunk_arr[None, :]
133
147
  idxc = jnp.array([chunk_index], dtype=jnp.int32)
134
- c = _case_2q_ctrl_chunk_tgt_local(c, u00, u01, u10, u11, q1, q2, m, k, idxc)
148
+ for g_id, q1, q2, param in ops:
149
+ _, _, _, _, u00, u01, u10, u11 = _gate_matrix_elements(g_id, param, dtype)
150
+ c = _case_2q_ctrl_chunk_tgt_local(c, u00, u01, u10, u11, q1, q2, m, k, idxc)
135
151
  return c[0]
136
152
 
137
153
 
@@ -197,7 +213,7 @@ def run_disk_overflow_circuit(chunk_paths, compiled_ops, m: int, k: int):
197
213
  elif isinstance(phase, ConditionalPhase):
198
214
  for i, path in enumerate(chunk_paths):
199
215
  arr = jnp.asarray(np.load(path))
200
- arr = _run_conditional_phase_on_chunk(arr, phase.op, i, m, k)
216
+ arr = _run_conditional_phase_on_chunk(arr, phase.ops, i, m, k)
201
217
  np.save(path, np.asarray(arr))
202
218
 
203
219
  elif isinstance(phase, MixPhase):
@@ -74,6 +74,27 @@ class SafeMemoryGuard:
74
74
  """
75
75
 
76
76
  _WARN_MULTIPLIER = 2.0
77
+ # Below this, check_allocation's own margin-after-allocation math
78
+ # reduces to "is ambient free RAM currently below threshold_pct?",
79
+ # independent of required_mb -- for a request this small that's not
80
+ # protecting against anything, since real machines don't run out of
81
+ # memory over a request this size regardless of ambient load. Sized
82
+ # to comfortably cover a dense statevector up to 24 qubits at
83
+ # complex128 (2**24 * 16 bytes = 268.4 MB) with a real margin -- the
84
+ # same 24-qubit figure dashboard_core.system_limits already treats as
85
+ # MPS's own RAM-independent ceiling, and well inside the 16-27 qubit
86
+ # range dense_evolution.chunk.get_dynamic_chunk considers safe on any
87
+ # machine (27 qubits / 2 GB is that function's own practical ceiling
88
+ # for a single dense block). An 8 GB minimum-spec machine can always
89
+ # absorb an allocation this size without real risk, even while
90
+ # running low on RAM from unrelated processes. A 2-qubit statevector
91
+ # (64 bytes) used to be refused on a machine sitting at 8% free RAM
92
+ # from unrelated processes, which was not a real anti-OOM save, just
93
+ # a false positive from a threshold designed for actual multi-GB
94
+ # allocations. Only bypasses when available_mb is itself comfortably
95
+ # above this floor too (see check_allocation below) -- a machine
96
+ # truly down to its last few hundred MB still gets the real check.
97
+ _NEGLIGIBLE_MB = 512.0
77
98
 
78
99
  def __init__(self, threshold_pct: float = 0.15, gc_before_check: bool = True):
79
100
  if not 0.0 < threshold_pct < 1.0:
@@ -134,7 +155,10 @@ class SafeMemoryGuard:
134
155
  if self.gc_before_check:
135
156
  gc.collect()
136
157
 
137
- s = self.status()
158
+ s = self.status()
159
+ if required_mb < self._NEGLIGIBLE_MB and s["available_mb"] > self._NEGLIGIBLE_MB:
160
+ return
161
+
138
162
  tag = f"[{context}] " if context else ""
139
163
  available_after_mb = s["available_mb"] - required_mb
140
164
  free_frac_after = available_after_mb / self._total_mb if self._total_mb > 0 else 0.0
@@ -4,7 +4,7 @@ from typing import List
4
4
  import jax
5
5
  import jax.numpy as jnp
6
6
 
7
- from ._engine_imports import QuantumTranspiler, GATE_IDS
7
+ from ._engine_imports import QuantumTranspiler, GATE_IDS, _gate_1q_matrix
8
8
 
9
9
  __all__ = [
10
10
  "_build_multi_chunk_step", "_build_multi_chunk_runner",
@@ -44,45 +44,17 @@ def _gate_matrix_elements(g_id, param, dtype):
44
44
  be traced (the in-RAM scan) or concrete Python/jnp scalars (a single
45
45
  known gate in a phase); jax.lax.switch works identically either way.
46
46
 
47
- Table is a copy of compiler.py's _apply_gate_fast_step / (this
48
- module's own step() before this extraction) -- must stay in sync
49
- with both, most notably index 14 (GPhase(alpha) = e^{i*alpha} * I)."""
50
- inv2 = jnp.asarray(1.0 / jnp.sqrt(2.0), dtype=dtype)
47
+ The 1-qubit table itself lives in compiler.py's _gate_1q_matrix now
48
+ (was: an independent hand-copied switch here, with a "must stay in
49
+ sync" comment -- prog.txt point 2); only the 2-qubit controlled-U
50
+ table below is local to this module."""
51
51
  half_p = param * jnp.float64(0.5)
52
- cos_p = jnp.cos(half_p).astype(dtype)
53
- sin_p = jnp.sin(half_p).astype(dtype)
54
52
  exp_pos = jnp.exp(1j * param).astype(dtype)
55
- exp_ph4 = jnp.exp(1j * jnp.pi / 4.0).astype(dtype)
56
- exp_mh4 = jnp.exp(-1j * jnp.pi / 4.0).astype(dtype)
57
53
  exp_pos_half = jnp.exp(1j * half_p).astype(dtype)
58
54
  exp_neg_half = jnp.exp(-1j * half_p).astype(dtype)
59
55
 
60
56
  g_id = jnp.asarray(g_id).astype(jnp.int32)
61
- safe_gid = jnp.clip(g_id, 0, 14)
62
- g_1q = jax.lax.switch(
63
- safe_gid,
64
- [
65
- lambda _: jnp.eye(2, dtype=dtype),
66
- lambda _: jnp.array([[inv2, inv2], [inv2, -inv2]], dtype=dtype),
67
- lambda _: jnp.array([[0.0 + 0j, 1.0 + 0j], [1.0 + 0j, 0.0 + 0j]], dtype=dtype),
68
- lambda _: jnp.array([[0.0 + 0j, -1j], [1j, 0.0 + 0j]], dtype=dtype),
69
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, -1.0 + 0j]], dtype=dtype),
70
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, 1j]], dtype=dtype),
71
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, -1j]], dtype=dtype),
72
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, exp_ph4]], dtype=dtype),
73
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, exp_mh4]], dtype=dtype),
74
- lambda _: jnp.array([[cos_p, -1j * sin_p], [-1j * sin_p, cos_p]], dtype=dtype),
75
- lambda _: jnp.array([[cos_p, -sin_p], [sin_p, cos_p]], dtype=dtype),
76
- lambda _: jnp.array([[jnp.exp(-1j * half_p), 0.0 + 0j], [0.0 + 0j, jnp.exp(1j * half_p)]], dtype=dtype),
77
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, exp_pos]], dtype=dtype),
78
- lambda _: jnp.array([[0.5 + 0.5j, 0.5 - 0.5j], [0.5 - 0.5j, 0.5 + 0.5j]], dtype=dtype),
79
- # 14 GPhase(alpha) = e^{i*alpha} * I -- see compiler.py's
80
- # _apply_gate_fast_step index 14 for the derivation; this
81
- # table must stay in sync with that one (see comment above).
82
- lambda _: jnp.array([[exp_pos, 0.0 + 0j], [0.0 + 0j, exp_pos]], dtype=dtype),
83
- ],
84
- operand=None,
85
- )
57
+ g_1q = _gate_1q_matrix(g_id, param, dtype)
86
58
 
87
59
  # Controlled-U submatrix for the 5 two-qubit gate types (mat[2:,2:]
88
60
  # of each gate's full 4x4 form — same values _apply_gate_multi's
@@ -319,59 +291,10 @@ def _build_distributed_chunk_step(num_chunks: int, m: int, k: int, axis_name: st
319
291
 
320
292
  my_id = jax.lax.axis_index(axis_name).astype(jnp.int32)
321
293
 
322
- inv2 = jnp.asarray(1.0 / jnp.sqrt(2.0), dtype=dtype)
323
- half_p = param * jnp.float64(0.5)
324
- cos_p = jnp.cos(half_p).astype(dtype)
325
- sin_p = jnp.sin(half_p).astype(dtype)
326
- exp_pos = jnp.exp(1j * param).astype(dtype)
327
- exp_ph4 = jnp.exp(1j * jnp.pi / 4.0).astype(dtype)
328
- exp_mh4 = jnp.exp(-1j * jnp.pi / 4.0).astype(dtype)
329
- exp_pos_half = jnp.exp(1j * half_p).astype(dtype)
330
- exp_neg_half = jnp.exp(-1j * half_p).astype(dtype)
331
-
332
- safe_gid = jnp.clip(g_id, 0, 14)
333
- g_1q = jax.lax.switch(
334
- safe_gid,
335
- [
336
- lambda _: jnp.eye(2, dtype=dtype),
337
- lambda _: jnp.array([[inv2, inv2], [inv2, -inv2]], dtype=dtype),
338
- lambda _: jnp.array([[0.0 + 0j, 1.0 + 0j], [1.0 + 0j, 0.0 + 0j]], dtype=dtype),
339
- lambda _: jnp.array([[0.0 + 0j, -1j], [1j, 0.0 + 0j]], dtype=dtype),
340
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, -1.0 + 0j]], dtype=dtype),
341
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, 1j]], dtype=dtype),
342
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, -1j]], dtype=dtype),
343
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, exp_ph4]], dtype=dtype),
344
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, exp_mh4]], dtype=dtype),
345
- lambda _: jnp.array([[cos_p, -1j * sin_p], [-1j * sin_p, cos_p]], dtype=dtype),
346
- lambda _: jnp.array([[cos_p, -sin_p], [sin_p, cos_p]], dtype=dtype),
347
- lambda _: jnp.array([[jnp.exp(-1j * half_p), 0.0 + 0j], [0.0 + 0j, jnp.exp(1j * half_p)]], dtype=dtype),
348
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, exp_pos]], dtype=dtype),
349
- lambda _: jnp.array([[0.5 + 0.5j, 0.5 - 0.5j], [0.5 - 0.5j, 0.5 + 0.5j]], dtype=dtype),
350
- # 14 GPhase(alpha) = e^{i*alpha} * I -- must stay in sync
351
- # with _apply_gate_fast_step (compiler.py) and the
352
- # non-distributed copy of this table above.
353
- lambda _: jnp.array([[exp_pos, 0.0 + 0j], [0.0 + 0j, exp_pos]], dtype=dtype),
354
- ],
355
- operand=None,
356
- )
357
-
358
- two_q_idx = jnp.where(g_id == 20, 0,
359
- jnp.where(g_id == 21, 1,
360
- jnp.where(g_id == 22, 2,
361
- jnp.where(g_id == 24, 3, 4))))
362
- U = jax.lax.switch(
363
- two_q_idx,
364
- [
365
- lambda _: jnp.array([[0.0 + 0j, 1.0 + 0j], [1.0 + 0j, 0.0 + 0j]], dtype=dtype),
366
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, -1.0 + 0j]], dtype=dtype),
367
- lambda _: jnp.array([[1.0 + 0j, 0.0 + 0j], [0.0 + 0j, exp_pos]], dtype=dtype),
368
- lambda _: jnp.array([[0.0 + 0j, -1j], [1j, 0.0 + 0j]], dtype=dtype),
369
- lambda _: jnp.array([[exp_neg_half, 0.0 + 0j], [0.0 + 0j, exp_pos_half]], dtype=dtype),
370
- ],
371
- operand=None,
372
- )
373
- g00, g01, g10, g11 = g_1q[0, 0], g_1q[0, 1], g_1q[1, 0], g_1q[1, 1]
374
- u00, u01, u10, u11 = U[0, 0], U[0, 1], U[1, 0], U[1, 1]
294
+ # Same table _build_multi_chunk_step uses (was: an independent
295
+ # hand-copied switch here -- prog.txt point 2, "must stay in
296
+ # sync" comment on both sides).
297
+ g00, g01, g10, g11, u00, u01, u10, u11 = _gate_matrix_elements(g_id, param, dtype)
375
298
 
376
299
  is_2q = g_id >= 20
377
300
  q1_chunk = q1 < m
@@ -51,6 +51,7 @@ complementary.
51
51
  """
52
52
 
53
53
  import dataclasses
54
+ import heapq
54
55
  import warnings
55
56
  from functools import partial
56
57
  from typing import List, Optional, Tuple
@@ -1161,7 +1162,7 @@ class MPSSimulator:
1161
1162
  # candidate as a whole regardless of backend.
1162
1163
  def _sample_bitstring(self, rng: np.random.Generator) -> List[int]:
1163
1164
  bits = []
1164
- state = jnp.ones(1, dtype=complex)
1165
+ state = jnp.ones(1, dtype=self.gammas[0].dtype)
1165
1166
  for i in range(self.n):
1166
1167
  g = self.gammas[i]
1167
1168
  lam = self.lambdas[i + 1] if i < self.n - 1 else jnp.ones(g.shape[2])
@@ -1214,8 +1215,15 @@ class MPSSimulator:
1214
1215
  new_vec = jnp.einsum("l,lr->r", vec_p, gamma[:, bit, :]) * lam
1215
1216
  weight = float(jnp.sum(jnp.abs(new_vec) ** 2))
1216
1217
  candidates.append(((idx_p << 1) | bit, new_vec, weight))
1217
- candidates.sort(key=lambda c: c[2], reverse=True)
1218
- paths = [(idx, vec) for idx, vec, _ in candidates[:k]]
1218
+ # heapq.nlargest instead of a full sort-then-slice (prog.txt
1219
+ # point 5e): only the top k by weight are ever used below, and
1220
+ # this avoids materializing/sorting the full candidates list
1221
+ # when len(candidates) >> k. Final probability order is
1222
+ # re-derived from scratch at the end of this function anyway
1223
+ # (`order = np.argsort(-probabilities)`), so which of two
1224
+ # equal-weight candidates heapq happens to prefer over sort's
1225
+ # stable order has no effect on the result.
1226
+ paths = [(idx, vec) for idx, vec, _ in heapq.nlargest(k, candidates, key=lambda c: c[2])]
1219
1227
 
1220
1228
  indices = np.array([p[0] for p in paths])
1221
1229
  amplitudes = np.array([