dense-evolution 8.2.3__tar.gz → 8.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.
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/PKG-INFO +11 -3
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/README.md +8 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/__init__.py +6 -2
- dense_evolution-8.3.0/dense_evolution/native_hf/libcint_bridge.py +167 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/physics/__init__.py +5 -1
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/physics/qec.py +359 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/qec.py +5 -2
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution.egg-info/PKG-INFO +11 -3
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution.egg-info/requires.txt +2 -3
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/pyproject.toml +5 -11
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/hamiltonians.py +21 -4
- dense_evolution-8.2.3/dense_evolution/native_hf/libcint_bridge.py +0 -225
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/autodiff.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/backends/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/backends/chunk/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/backends/chunk/_engine_imports.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/backends/chunk/circuit_chunker.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/backends/chunk/core.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/backends/chunk/disk_overflow.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/backends/chunk/geometry.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/backends/chunk/guard.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/backends/chunk/kernels.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/backends/mps.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/backends/statevector.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/chunk.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/circuits/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/circuits/compiler.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/circuits/diagram.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/circuits/gates.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/circuits/parser.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/circuits/qft.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/circuits/random_circuit.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/circuits/registry.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/circuits/topology.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/circuits/trotter.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/circuits/uccsd.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/cli.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/compiler.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/config.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/drawing.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/entropy.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/fermions.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/gates.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/harrison_tb.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/healing.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/interop/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/interop/qiskit_pennylane.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/measurement.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/mitigation/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/mitigation/healing.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/mitigation/kl_divergence.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/mitigation/magic_entropy.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/mitigation/magic_entropy_shadows.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/mitigation/renyi.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/mitigation/stabilizer_renyi_entropy.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/mitigation/zne.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/mps.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/native_hf/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/native_hf/assembly.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/native_hf/basis.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/native_hf/boys.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/native_hf/bridge.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/native_hf/cartesian.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/native_hf/coulomb.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/native_hf/differentiable.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/native_hf/gaussians.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/native_hf/kinetic.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/native_hf/overlap.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/native_hf/scf.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/coherent_attack.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/cosmic_ray.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/density_matrix_channels.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/differentiable.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/kraus/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/kraus/amplitude_damping.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/kraus/bitflip.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/kraus/combined.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/kraus/depolarizing.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/kraus/ideal.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/kraus/phaseflip.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/kraus_channels.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/oscillating.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/noise/pink.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/observables.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/parser.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/physics/entropy.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/physics/fermions.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/physics/observables.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/physics/spectral.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/physics/states.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/protocols/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/protocols/bb84.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/protocols/di_qkd_ghz.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/protocols/dicka_protocol2.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/qft.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/qmmm/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/qmmm/ase_bridge.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/qmmm/forces.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/qmmm/propagation.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/qmmm/region.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/random_circuit.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/registry.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/simulator.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/solvers/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/solvers/autodiff.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/solvers/harrison_tb.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/solvers/vhd_tb.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/states.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/topology.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/trotter.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/utils/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/utils/drawing.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/utils/mass_decomposition.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/utils/measurement.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution/vhd_tb.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution.egg-info/SOURCES.txt +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution.egg-info/dependency_links.txt +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution.egg-info/entry_points.txt +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/dense_evolution.egg-info/top_level.txt +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/license.md +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/research/local_site/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/research/local_site/app/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/research/local_site/app/server.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/setup.cfg +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/_gate_tables.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/band_structure.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/circuit_builder_component.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/circuit_diagram.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/crypto_protocols.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/engine.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/graphical_builder.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/mass_decomposition_tool.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/mitigation.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/native_hf_diagnostics.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/noise_tools.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/qasm_library.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/qmmm.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/rag_tool.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/state_visuals.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/system_limits.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/vector_healing.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/visuals.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/vqe.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/dashboard/core/wormhole.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/ia_utils/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/ia_utils/adversarial_vector_attack.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/ia_utils/rag.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/ia_utils/vector_healing.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/client.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/config.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/models.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/molecules.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/server.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/tools/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/tools/chemistry_tools.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/tools/circuit_tools.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/tools/crypto_tools.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/tools/mitigation_tools.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/tools/noise_tools.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/tools/retrieval_tools.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/tools/system_tools.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/tools/wormhole_tools.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/utils/__init__.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/utils/cache.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/tools/mcp_server/utils/images.py +0 -0
- {dense_evolution-8.2.3 → dense_evolution-8.3.0}/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.
|
|
3
|
+
Version: 8.3.0
|
|
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> ·
|
|
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
|
[](https://github.com/tatopenn-cell/Dense-Evolution/actions/workflows/ci.yml)
|
|
112
119
|
[](https://tatopenn-cell.github.io/Dense-Evolution/)
|
|
113
120
|
[](https://codecov.io/gh/tatopenn-cell/Dense-Evolution)
|
|
@@ -295,6 +302,7 @@ sim.run_chunk(circuit.to_tuples(), chunk_size_gates=500)
|
|
|
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
303
|
- **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/).
|
|
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/).
|
|
298
306
|
- **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
307
|
- **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
308
|
|
|
@@ -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> ·
|
|
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
|
[](https://github.com/tatopenn-cell/Dense-Evolution/actions/workflows/ci.yml)
|
|
12
19
|
[](https://tatopenn-cell.github.io/Dense-Evolution/)
|
|
13
20
|
[](https://codecov.io/gh/tatopenn-cell/Dense-Evolution)
|
|
@@ -195,6 +202,7 @@ sim.run_chunk(circuit.to_tuples(), chunk_size_gates=500)
|
|
|
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
203
|
- **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/).
|
|
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/).
|
|
198
206
|
- **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
207
|
- **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
208
|
|
|
@@ -58,9 +58,11 @@ from .circuits.trotter import (pauli_rotation_ops, trotter_evolve_ops, continuou
|
|
|
58
58
|
from .circuits.uccsd import find_excitations, single_excitation_ops, double_excitation_ops
|
|
59
59
|
from .physics.qec import (pauli_commutes, compute_syndrome, erasure_aware_decode, pymatching_decode,
|
|
60
60
|
blind_minimum_weight_decode, decode_with_erasure_fallback,
|
|
61
|
-
counts_in_intervals_dimension, nearest_coset_decode
|
|
61
|
+
counts_in_intervals_dimension, nearest_coset_decode, erasure_ml_decode,
|
|
62
|
+
peeling_decode, union_find_decode, matching_erasure_decode,
|
|
63
|
+
estimate_edge_probabilities_from_detection_events)
|
|
62
64
|
|
|
63
|
-
__version__ = "8.
|
|
65
|
+
__version__ = "8.3.0"
|
|
64
66
|
|
|
65
67
|
__all__ = [
|
|
66
68
|
"__version__",
|
|
@@ -105,6 +107,8 @@ __all__ = [
|
|
|
105
107
|
"majorana_pauli_terms", "total_parity_operator", "hubbard_hamiltonian_pauli_terms", "square_lattice_edges",
|
|
106
108
|
"pauli_commutes", "compute_syndrome", "erasure_aware_decode", "pymatching_decode", "blind_minimum_weight_decode",
|
|
107
109
|
"decode_with_erasure_fallback", "counts_in_intervals_dimension", "nearest_coset_decode",
|
|
110
|
+
"erasure_ml_decode", "peeling_decode", "union_find_decode", "matching_erasure_decode",
|
|
111
|
+
"estimate_edge_probabilities_from_detection_events",
|
|
108
112
|
# Utils -- drawing, measurement, random circuits
|
|
109
113
|
"draw_circuit", "plot_circuit", "sample_counts", "statevector_fidelity", "random_circuit",
|
|
110
114
|
]
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""libcint bridge for native_hf's one- and two-electron integrals.
|
|
2
|
+
|
|
3
|
+
native_hf's own build_repulsion_tensor (assembly.py) computes the ERI
|
|
4
|
+
tensor via JAX-jitted Obara-Saika recursions -- correct, differentiable,
|
|
5
|
+
but pays a JIT-compilation tax on mixed-angular-momentum bases (~532s on
|
|
6
|
+
Ne/6-31G* even after the primitive-count-padding fix), and its one-electron
|
|
7
|
+
assembly ran out of memory during XLA compilation for a 4-heavy-atom
|
|
8
|
+
molecule at 6-31G* on a Kaggle CPU kernel. libcint (Sun, J. Comput. Chem.
|
|
9
|
+
36, 1664 (2015), BSD-2) computes the identical integrals with C kernels
|
|
10
|
+
compiled once, ahead of time.
|
|
11
|
+
|
|
12
|
+
libcint is linked statically, together with csrc/cint_driver.c, into one
|
|
13
|
+
shared library shipped inside the platform wheels of dense-evolution
|
|
14
|
+
(dense_evolution/native_hf/_libcint/, built by
|
|
15
|
+
.github/scripts/build-libcint.sh in .github/workflows/libcint.yml) and
|
|
16
|
+
called through ctypes, with the atm/bas/env arrays built here from
|
|
17
|
+
native_hf's own ContractedShell list. The driver loops over shell blocks
|
|
18
|
+
in C (8-fold ERI symmetry, int2e_optimizer) and writes every integral
|
|
19
|
+
already rescaled and in native_hf's AO order. A source install has no
|
|
20
|
+
bundled library: run build-libcint.sh and point DENSE_EVOLUTION_LIBCINT at
|
|
21
|
+
the resulting file.
|
|
22
|
+
|
|
23
|
+
Shells are passed to libcint in native_hf's own order, so AO blocks line
|
|
24
|
+
up shell by shell. Two convention differences remain inside each shell,
|
|
25
|
+
confirmed empirically on Ne/6-31G*:
|
|
26
|
+
- Cartesian component order: libcint orders px,py,pz and
|
|
27
|
+
xx,xy,xz,yy,yz,zz; native_hf's cartesian_powers orders px,pz,py and
|
|
28
|
+
xx,xz,xy,zz,yz,yy.
|
|
29
|
+
- Normalization: libcint's raw Cartesian d components are not unit
|
|
30
|
+
self-overlap (xx/yy/zz vs. xy/xz/yz differ by exactly a factor of 3).
|
|
31
|
+
native_hf's primitive-normalized coefficients differ from libcint's
|
|
32
|
+
radial convention by a per-shell constant too. Both are removed by a
|
|
33
|
+
per-AO rescale computed from libcint's own overlap diagonal at call
|
|
34
|
+
time, exact for whatever exponent/element/degree is in play.
|
|
35
|
+
Degrees above 2 raise NotImplementedError (native_hf itself caps at 2).
|
|
36
|
+
"""
|
|
37
|
+
import ctypes
|
|
38
|
+
import os
|
|
39
|
+
import sys
|
|
40
|
+
from pathlib import Path
|
|
41
|
+
|
|
42
|
+
import numpy as np
|
|
43
|
+
|
|
44
|
+
from dense_evolution.native_hf.basis import build_molecule_shells
|
|
45
|
+
from dense_evolution.native_hf.cartesian import cartesian_powers
|
|
46
|
+
|
|
47
|
+
_LIBCINT_CARTESIAN_ORDER = {
|
|
48
|
+
0: [(0, 0, 0)],
|
|
49
|
+
1: [(1, 0, 0), (0, 1, 0), (0, 0, 1)],
|
|
50
|
+
2: [(2, 0, 0), (1, 1, 0), (1, 0, 1), (0, 2, 0), (0, 1, 1), (0, 0, 2)],
|
|
51
|
+
}
|
|
52
|
+
_LIB_NAMES = {"win32": "libdecint.dll", "darwin": "libdecint.dylib"}
|
|
53
|
+
_PTR_ENV_START = 20
|
|
54
|
+
_POINT_NUC = 1
|
|
55
|
+
_KINDS = {"ovlp": 0, "kin": 1, "nuc": 2}
|
|
56
|
+
_lib = None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def load_libcint() -> ctypes.CDLL:
|
|
60
|
+
"""The bundled libcint + driver shared library (or DENSE_EVOLUTION_LIBCINT's),
|
|
61
|
+
loaded once; ImportError if neither exists."""
|
|
62
|
+
global _lib
|
|
63
|
+
if _lib is not None:
|
|
64
|
+
return _lib
|
|
65
|
+
path = os.environ.get("DENSE_EVOLUTION_LIBCINT") or str(
|
|
66
|
+
Path(__file__).with_name("_libcint") / _LIB_NAMES.get(sys.platform, "libdecint.so")
|
|
67
|
+
)
|
|
68
|
+
if not os.path.isfile(path):
|
|
69
|
+
raise ImportError(
|
|
70
|
+
f"native_hf.libcint_bridge needs the bundled libcint library, expected at {path}. "
|
|
71
|
+
"It ships inside the dense-evolution wheels for Windows, macOS and Linux "
|
|
72
|
+
"(pip install dense-evolution); for a source install, run "
|
|
73
|
+
".github/scripts/build-libcint.sh and set DENSE_EVOLUTION_LIBCINT to the library file."
|
|
74
|
+
)
|
|
75
|
+
lib = ctypes.CDLL(path)
|
|
76
|
+
tail = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p]
|
|
77
|
+
lib.de_int1e.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int] + [ctypes.c_void_p] * 3 + tail
|
|
78
|
+
lib.de_int1e.restype = None
|
|
79
|
+
lib.de_int2e.argtypes = [ctypes.c_void_p, ctypes.c_int] + [ctypes.c_void_p] * 3 + tail
|
|
80
|
+
lib.de_int2e.restype = None
|
|
81
|
+
_lib = lib
|
|
82
|
+
return lib
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _permutation_libcint_to_native_hf(degree: int) -> np.ndarray:
|
|
86
|
+
"""perm such that native_hf_ordered[i] == libcint_ordered[perm[i]]."""
|
|
87
|
+
if degree not in _LIBCINT_CARTESIAN_ORDER:
|
|
88
|
+
raise NotImplementedError(
|
|
89
|
+
f"libcint_bridge only has a verified AO-order mapping for degree <= 2; "
|
|
90
|
+
f"degree={degree} would need the same empirical check first, not an "
|
|
91
|
+
f"assumed extension of the pattern."
|
|
92
|
+
)
|
|
93
|
+
native_order = [tuple(int(x) for x in p) for p in cartesian_powers(degree)]
|
|
94
|
+
libcint_order = _LIBCINT_CARTESIAN_ORDER[degree]
|
|
95
|
+
return np.array([libcint_order.index(p) for p in native_order])
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class _Cint:
|
|
99
|
+
"""atm/bas/env arrays for one molecule plus per-shell AO offsets, the
|
|
100
|
+
native_hf AO permutation, evaluated by the C driver."""
|
|
101
|
+
|
|
102
|
+
def __init__(self, atomic_numbers: list, geometry_bohr: np.ndarray, basis_name: str):
|
|
103
|
+
self.lib = load_libcint()
|
|
104
|
+
shells = build_molecule_shells(atomic_numbers, geometry_bohr, basis_name)
|
|
105
|
+
env = [0.0] * _PTR_ENV_START
|
|
106
|
+
atm, bas = [], []
|
|
107
|
+
for z, r in zip(atomic_numbers, np.asarray(geometry_bohr, dtype=float)):
|
|
108
|
+
atm.append([int(z), len(env), _POINT_NUC, len(env) + 3, 0, 0])
|
|
109
|
+
env.extend([r[0], r[1], r[2], 0.0])
|
|
110
|
+
for s in shells:
|
|
111
|
+
e = np.asarray(s.exponents, dtype=float)
|
|
112
|
+
c = np.asarray(s.coefficients, dtype=float)
|
|
113
|
+
bas.append([s.atom_index, s.degree, e.shape[0], 1, 0, len(env), len(env) + e.shape[0], 0])
|
|
114
|
+
env.extend(e)
|
|
115
|
+
env.extend(c)
|
|
116
|
+
self.atm = np.ascontiguousarray(atm, dtype=np.int32)
|
|
117
|
+
self.bas = np.ascontiguousarray(bas, dtype=np.int32)
|
|
118
|
+
self.env = np.ascontiguousarray(env, dtype=np.float64)
|
|
119
|
+
self.sizes = [len(cartesian_powers(s.degree)) for s in shells]
|
|
120
|
+
self.offsets = np.concatenate([[0], np.cumsum(self.sizes)]).astype(int)
|
|
121
|
+
self.n = int(self.offsets[-1])
|
|
122
|
+
self.perm = np.concatenate(
|
|
123
|
+
[o + _permutation_libcint_to_native_hf(s.degree) for o, s in zip(self.offsets, shells)]
|
|
124
|
+
)
|
|
125
|
+
self.ao_loc = np.ascontiguousarray(self.offsets, dtype=np.int32)
|
|
126
|
+
self.pos = np.ascontiguousarray(np.argsort(self.perm), dtype=np.int32)
|
|
127
|
+
|
|
128
|
+
def _tail(self):
|
|
129
|
+
return (self.atm.ctypes.data, self.atm.shape[0], self.bas.ctypes.data, self.bas.shape[0], self.env.ctypes.data)
|
|
130
|
+
|
|
131
|
+
def one(self, kind: str, r: np.ndarray, pos: np.ndarray) -> np.ndarray:
|
|
132
|
+
out = np.empty((self.n, self.n))
|
|
133
|
+
r = np.ascontiguousarray(r, dtype=np.float64)
|
|
134
|
+
self.lib.de_int1e(_KINDS[kind], out.ctypes.data, self.n, self.ao_loc.ctypes.data, r.ctypes.data, pos.ctypes.data, *self._tail())
|
|
135
|
+
return out
|
|
136
|
+
|
|
137
|
+
def rescale(self) -> np.ndarray:
|
|
138
|
+
S = self.one("ovlp", np.ones(self.n), np.arange(self.n, dtype=np.int32))
|
|
139
|
+
return 1.0 / np.sqrt(np.diag(S))
|
|
140
|
+
|
|
141
|
+
def two(self, r: np.ndarray) -> np.ndarray:
|
|
142
|
+
out = np.empty((self.n,) * 4)
|
|
143
|
+
self.lib.de_int2e(out.ctypes.data, self.n, self.ao_loc.ctypes.data, r.ctypes.data, self.pos.ctypes.data, *self._tail())
|
|
144
|
+
return out
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def build_overlap_and_core_hamiltonian_libcint(
|
|
148
|
+
atomic_numbers: list, geometry_bohr: np.ndarray, basis_name: str
|
|
149
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
150
|
+
"""Same contract as assembly.build_overlap_matrix + build_core_hamiltonian
|
|
151
|
+
combined, computed via libcint. Returns (S, H_core) in native_hf's own AO
|
|
152
|
+
ordering/normalization, ready for scf.run_scf alongside
|
|
153
|
+
build_repulsion_tensor_libcint's output."""
|
|
154
|
+
c = _Cint(atomic_numbers, geometry_bohr, basis_name)
|
|
155
|
+
r = c.rescale()
|
|
156
|
+
return c.one("ovlp", r, c.pos), c.one("kin", r, c.pos) + c.one("nuc", r, c.pos)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def build_repulsion_tensor_libcint(atomic_numbers: list, geometry_bohr: np.ndarray, basis_name: str) -> np.ndarray:
|
|
160
|
+
"""Same contract as assembly.build_repulsion_tensor, computed via libcint
|
|
161
|
+
with 8-fold permutational symmetry; takes (atomic_numbers, geometry_bohr,
|
|
162
|
+
basis_name) rather than a shells list.
|
|
163
|
+
|
|
164
|
+
geometry_bohr: shape (n_atoms, 3), atomic units, same convention as
|
|
165
|
+
build_molecule_shells."""
|
|
166
|
+
c = _Cint(atomic_numbers, geometry_bohr, basis_name)
|
|
167
|
+
return c.two(c.rescale())
|
|
@@ -7,7 +7,9 @@ from .entropy import partial_trace, von_neumann_entropy, mutual_information, cen
|
|
|
7
7
|
from .fermions import majorana_pauli_terms, total_parity_operator, hubbard_hamiltonian_pauli_terms, square_lattice_edges
|
|
8
8
|
from .qec import (pauli_commutes, compute_syndrome, erasure_aware_decode, pymatching_decode,
|
|
9
9
|
blind_minimum_weight_decode, decode_with_erasure_fallback,
|
|
10
|
-
counts_in_intervals_dimension, nearest_coset_decode
|
|
10
|
+
counts_in_intervals_dimension, nearest_coset_decode, erasure_ml_decode,
|
|
11
|
+
peeling_decode, union_find_decode, matching_erasure_decode,
|
|
12
|
+
estimate_edge_probabilities_from_detection_events)
|
|
11
13
|
from .spectral import has_exact_degeneracy, matrix_function_eigh, spectral_evolve
|
|
12
14
|
|
|
13
15
|
__all__ = [
|
|
@@ -19,5 +21,7 @@ __all__ = [
|
|
|
19
21
|
"majorana_pauli_terms", "total_parity_operator", "hubbard_hamiltonian_pauli_terms", "square_lattice_edges",
|
|
20
22
|
"pauli_commutes", "compute_syndrome", "erasure_aware_decode", "pymatching_decode", "blind_minimum_weight_decode",
|
|
21
23
|
"decode_with_erasure_fallback", "counts_in_intervals_dimension", "nearest_coset_decode",
|
|
24
|
+
"erasure_ml_decode", "peeling_decode", "union_find_decode", "matching_erasure_decode",
|
|
25
|
+
"estimate_edge_probabilities_from_detection_events",
|
|
22
26
|
"has_exact_degeneracy", "matrix_function_eigh", "spectral_evolve",
|
|
23
27
|
]
|
|
@@ -72,6 +72,7 @@ report a fractal dimension as absurd as 142 in 3 dimensions purely
|
|
|
72
72
|
from fit noise, not from any real structure in the data.
|
|
73
73
|
"""
|
|
74
74
|
import itertools
|
|
75
|
+
from collections import deque
|
|
75
76
|
from typing import Optional, Sequence
|
|
76
77
|
|
|
77
78
|
import numpy as np
|
|
@@ -752,3 +753,361 @@ def nearest_coset_decode(measured_bits: str, coset_a: Sequence[str], coset_b: Se
|
|
|
752
753
|
d_a = _min_hamming_distance(measured_bits, coset_a)
|
|
753
754
|
d_b = _min_hamming_distance(measured_bits, coset_b)
|
|
754
755
|
return 0 if d_a <= d_b else 1
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
def estimate_edge_probabilities_from_detection_events(check_matrix, events) -> np.ndarray:
|
|
759
|
+
"""Error probability of every qubit, from detection events (Spitz et al.).
|
|
760
|
+
|
|
761
|
+
Implements the exact inversion of S. T. Spitz, B. Tarasinski,
|
|
762
|
+
C. W. J. Beenakker and T. E. O'Brien, "Adaptive weight estimator for
|
|
763
|
+
quantum error correction in a time-dependent environment",
|
|
764
|
+
arXiv:1712.02360, Eqs. (13) and (16). For a code in which every qubit is
|
|
765
|
+
checked by at most two checks (repetition and surface codes), each qubit is
|
|
766
|
+
an edge between two checks, or between one check and the boundary. A qubit
|
|
767
|
+
shared by checks ``i`` and ``j`` has probability
|
|
768
|
+
|
|
769
|
+
``p = 1/2 - sqrt(1/4 - (<v_i v_j> - <v_i><v_j>) / (1 - 2 <v_i xor v_j>))``
|
|
770
|
+
|
|
771
|
+
where ``v`` are the detection events and ``<.>`` the average over cycles. A
|
|
772
|
+
qubit on the boundary of check ``i`` has
|
|
773
|
+
|
|
774
|
+
``p = 1/2 + (<v_i> - 1/2) / prod(1 - 2 p_ij)`` over the other qubits of ``i``.
|
|
775
|
+
|
|
776
|
+
The result can be passed as ``weights`` (``-log(p / (1 - p))``) to
|
|
777
|
+
`pymatching_decode`.
|
|
778
|
+
|
|
779
|
+
Parameters
|
|
780
|
+
----------
|
|
781
|
+
check_matrix : array_like of shape (n_checks, n_qubits)
|
|
782
|
+
0/1 matrix, entry ``[c, q] = 1`` when check ``c`` detects an error on
|
|
783
|
+
qubit ``q``. Every column has one or two ones; no two qubits may join
|
|
784
|
+
the same pair of checks.
|
|
785
|
+
events : array_like of shape (n_cycles, n_checks)
|
|
786
|
+
0/1 detection events: ``1`` when a check changed value since the
|
|
787
|
+
previous cycle (the syndrome of one cycle's new errors).
|
|
788
|
+
|
|
789
|
+
Returns
|
|
790
|
+
-------
|
|
791
|
+
numpy.ndarray of shape (n_qubits,)
|
|
792
|
+
Estimated error probability of each qubit, clipped to [0, 0.5].
|
|
793
|
+
|
|
794
|
+
Raises
|
|
795
|
+
------
|
|
796
|
+
ValueError
|
|
797
|
+
If the shapes do not match, ``events`` is not 0/1, a column of
|
|
798
|
+
``check_matrix`` does not have one or two ones, or two qubits join the
|
|
799
|
+
same pair of checks.
|
|
800
|
+
|
|
801
|
+
Notes
|
|
802
|
+
-----
|
|
803
|
+
Valid for independent errors and one error type at a time. Needs about
|
|
804
|
+
``1 / p`` cycles per qubit for a stable estimate (the paper's Eq. 18). A
|
|
805
|
+
pair of checks whose correlation is below the statistical noise gives a
|
|
806
|
+
probability near zero.
|
|
807
|
+
|
|
808
|
+
Examples
|
|
809
|
+
--------
|
|
810
|
+
>>> import numpy as np
|
|
811
|
+
>>> from dense_evolution.physics.qec import estimate_edge_probabilities_from_detection_events
|
|
812
|
+
>>> checks = np.array([[1, 0], [1, 1]])
|
|
813
|
+
>>> events = np.array([[1, 1]] * 20 + [[0, 0]] * 80)
|
|
814
|
+
>>> p = estimate_edge_probabilities_from_detection_events(checks, events)
|
|
815
|
+
>>> bool(p[0] < 0.5 and p[1] < 0.5)
|
|
816
|
+
True
|
|
817
|
+
"""
|
|
818
|
+
h = np.asarray(check_matrix, dtype=int)
|
|
819
|
+
v = np.asarray(events, dtype=float)
|
|
820
|
+
if h.ndim != 2:
|
|
821
|
+
raise ValueError("check_matrix must be 2-D (n_checks, n_qubits)")
|
|
822
|
+
if v.ndim != 2 or v.shape[1] != h.shape[0]:
|
|
823
|
+
raise ValueError(
|
|
824
|
+
f"events must have shape (n_cycles, {h.shape[0]}), got {v.shape}"
|
|
825
|
+
)
|
|
826
|
+
if v.shape[0] == 0:
|
|
827
|
+
raise ValueError("events needs at least one cycle")
|
|
828
|
+
if not np.isin(v, (0.0, 1.0)).all():
|
|
829
|
+
raise ValueError("events must contain only 0 and 1")
|
|
830
|
+
|
|
831
|
+
n_q = h.shape[1]
|
|
832
|
+
ends = []
|
|
833
|
+
for q in range(n_q):
|
|
834
|
+
rows = np.flatnonzero(h[:, q])
|
|
835
|
+
if len(rows) not in (1, 2):
|
|
836
|
+
raise ValueError(
|
|
837
|
+
f"qubit {q} is checked by {len(rows)} checks; need one or two"
|
|
838
|
+
)
|
|
839
|
+
ends.append(tuple(int(r) for r in rows))
|
|
840
|
+
pairs = [e for e in ends if len(e) == 2]
|
|
841
|
+
if len(set(pairs)) != len(pairs):
|
|
842
|
+
raise ValueError("two qubits join the same pair of checks")
|
|
843
|
+
|
|
844
|
+
mean = v.mean(axis=0)
|
|
845
|
+
p = np.zeros(n_q)
|
|
846
|
+
for q, e in enumerate(ends):
|
|
847
|
+
if len(e) == 2:
|
|
848
|
+
i, j = e
|
|
849
|
+
cov = (v[:, i] * v[:, j]).mean() - mean[i] * mean[j]
|
|
850
|
+
xor = np.abs(v[:, i] - v[:, j]).mean()
|
|
851
|
+
denom = 1.0 - 2.0 * xor
|
|
852
|
+
inside = 0.25 - cov / denom if denom > 0 else 0.25
|
|
853
|
+
p[q] = 0.5 - np.sqrt(max(inside, 0.0))
|
|
854
|
+
for q, e in enumerate(ends):
|
|
855
|
+
if len(e) == 1:
|
|
856
|
+
i = e[0]
|
|
857
|
+
prod = 1.0
|
|
858
|
+
for r, other in enumerate(ends):
|
|
859
|
+
if len(other) == 2 and i in other:
|
|
860
|
+
prod *= 1.0 - 2.0 * p[r]
|
|
861
|
+
if prod <= 0:
|
|
862
|
+
p[q] = 0.5
|
|
863
|
+
else:
|
|
864
|
+
p[q] = 0.5 + (mean[i] - 0.5) / prod
|
|
865
|
+
return np.clip(p, 0.0, 0.5)
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
def erasure_ml_decode(
|
|
869
|
+
observed_syndrome: tuple,
|
|
870
|
+
heralded_qubits: Sequence[int],
|
|
871
|
+
n_qubits: int,
|
|
872
|
+
stabilizers: Sequence[str],
|
|
873
|
+
) -> Optional[str]:
|
|
874
|
+
"""Maximum-likelihood decoder for erasures at known locations, for any
|
|
875
|
+
stabilizer code.
|
|
876
|
+
|
|
877
|
+
With the erased qubits known, the error is supported on them, and the
|
|
878
|
+
syndrome becomes a linear system over GF(2) in the X and Z bits of those
|
|
879
|
+
qubits (Delfosse & Zemor, arXiv:1703.01517; Kuo & Ouyang,
|
|
880
|
+
arXiv:2411.13509). Solving it by Gaussian elimination costs O(n^3), where
|
|
881
|
+
`erasure_aware_decode` tries 4**m assignments for m erased qubits. Any
|
|
882
|
+
solution is a valid correction when every zero-syndrome operator on the
|
|
883
|
+
erased qubits is a stabilizer element, so degenerate errors (several
|
|
884
|
+
errors that differ by a stabilizer) are decoded too, not rejected.
|
|
885
|
+
|
|
886
|
+
Parameters
|
|
887
|
+
----------
|
|
888
|
+
observed_syndrome : sequence of int
|
|
889
|
+
One bit per stabilizer, same convention as `compute_syndrome`.
|
|
890
|
+
heralded_qubits : sequence of int
|
|
891
|
+
Indices of the erased qubits.
|
|
892
|
+
n_qubits : int
|
|
893
|
+
Number of physical qubits.
|
|
894
|
+
stabilizers : sequence of str
|
|
895
|
+
Stabilizer generators as Pauli strings of length `n_qubits`.
|
|
896
|
+
|
|
897
|
+
Returns
|
|
898
|
+
-------
|
|
899
|
+
str or None
|
|
900
|
+
A Pauli string supported on the erased qubits that reproduces the
|
|
901
|
+
syndrome and is equivalent, up to a stabilizer, to every other
|
|
902
|
+
solution. `None` when no error on the erased qubits explains the
|
|
903
|
+
syndrome, or when the erased qubits contain a logical operator so the
|
|
904
|
+
correction is ambiguous. With no erased qubits it returns the identity
|
|
905
|
+
for a zero syndrome and `None` otherwise.
|
|
906
|
+
|
|
907
|
+
Raises
|
|
908
|
+
------
|
|
909
|
+
ValueError
|
|
910
|
+
If the syndrome length does not match the stabilizers, a stabilizer
|
|
911
|
+
has the wrong length, or an erased index is out of range.
|
|
912
|
+
|
|
913
|
+
Examples
|
|
914
|
+
--------
|
|
915
|
+
>>> stabs = ['IIIXXXX', 'IXXIIXX', 'XIXIXIX', 'IIIZZZZ', 'IZZIIZZ', 'ZIZIZIZ']
|
|
916
|
+
>>> syndrome = compute_syndrome('XIIIIIX', stabs)
|
|
917
|
+
>>> erasure_ml_decode(syndrome, [0, 6], 7, stabs)
|
|
918
|
+
'XIIIIIX'
|
|
919
|
+
"""
|
|
920
|
+
stabs = list(stabilizers)
|
|
921
|
+
if len(observed_syndrome) != len(stabs):
|
|
922
|
+
raise ValueError(
|
|
923
|
+
f"observed_syndrome has {len(observed_syndrome)} entries but there are "
|
|
924
|
+
f"{len(stabs)} stabilizers"
|
|
925
|
+
)
|
|
926
|
+
for i, s in enumerate(stabs):
|
|
927
|
+
if len(s) != n_qubits:
|
|
928
|
+
raise ValueError(f"stabilizers[{i}] has length {len(s)}, expected n_qubits={n_qubits}")
|
|
929
|
+
erased = sorted({int(q) for q in heralded_qubits})
|
|
930
|
+
if any(q < 0 or q >= n_qubits for q in erased):
|
|
931
|
+
raise ValueError(f"heralded_qubits must be in range(0, {n_qubits})")
|
|
932
|
+
|
|
933
|
+
syn = np.array(observed_syndrome, dtype=np.uint8) % 2
|
|
934
|
+
k = len(erased)
|
|
935
|
+
if k == 0:
|
|
936
|
+
return 'I' * n_qubits if not syn.any() else None
|
|
937
|
+
|
|
938
|
+
sym = np.array([_pauli_to_symplectic(s) for s in stabs], dtype=np.uint8)
|
|
939
|
+
sx, sz = sym[:, :n_qubits], sym[:, n_qubits:]
|
|
940
|
+
a = np.concatenate([sz[:, erased], sx[:, erased]], axis=1)
|
|
941
|
+
rref, pivots = _gf2_rref(np.concatenate([a, syn[:, None]], axis=1))
|
|
942
|
+
if 2 * k in pivots:
|
|
943
|
+
return None
|
|
944
|
+
|
|
945
|
+
sol = np.zeros(2 * k, dtype=np.uint8)
|
|
946
|
+
for row, col in enumerate(pivots):
|
|
947
|
+
sol[col] = rref[row, 2 * k]
|
|
948
|
+
free = [c for c in range(2 * k) if c not in pivots]
|
|
949
|
+
stab_rref, stab_pivots = _gf2_rref(sym)
|
|
950
|
+
|
|
951
|
+
def embed(v):
|
|
952
|
+
full = np.zeros(2 * n_qubits, dtype=np.uint8)
|
|
953
|
+
for j, q in enumerate(erased):
|
|
954
|
+
full[q] = v[j]
|
|
955
|
+
full[n_qubits + q] = v[k + j]
|
|
956
|
+
return full
|
|
957
|
+
|
|
958
|
+
for f in free:
|
|
959
|
+
vec = np.zeros(2 * k, dtype=np.uint8)
|
|
960
|
+
vec[f] = 1
|
|
961
|
+
for row, col in enumerate(pivots):
|
|
962
|
+
if rref[row, f]:
|
|
963
|
+
vec[col] = 1
|
|
964
|
+
if not _in_gf2_span(embed(vec), stab_rref, stab_pivots):
|
|
965
|
+
return None
|
|
966
|
+
|
|
967
|
+
full = embed(sol)
|
|
968
|
+
letters = {(0, 0): 'I', (1, 0): 'X', (0, 1): 'Z', (1, 1): 'Y'}
|
|
969
|
+
return ''.join(letters[(int(full[q]), int(full[n_qubits + q]))] for q in range(n_qubits))
|
|
970
|
+
|
|
971
|
+
|
|
972
|
+
def _peel(h, erased, syn):
|
|
973
|
+
m = h.shape[0]
|
|
974
|
+
adj = {}
|
|
975
|
+
for q in erased:
|
|
976
|
+
rows = np.flatnonzero(h[:, q])
|
|
977
|
+
u, v = (int(rows[0]), int(rows[1])) if len(rows) == 2 else (int(rows[0]), m)
|
|
978
|
+
adj.setdefault(u, []).append((v, q))
|
|
979
|
+
adj.setdefault(v, []).append((u, q))
|
|
980
|
+
syn = [int(b) for b in syn] + [0]
|
|
981
|
+
seen, order, parent = set(), [], {}
|
|
982
|
+
starts = ([m] if m in adj else []) + [v for v in adj if v != m]
|
|
983
|
+
for s in starts:
|
|
984
|
+
if s in seen:
|
|
985
|
+
continue
|
|
986
|
+
seen.add(s)
|
|
987
|
+
queue = deque([s])
|
|
988
|
+
while queue:
|
|
989
|
+
u = queue.popleft()
|
|
990
|
+
order.append(u)
|
|
991
|
+
for v, q in adj[u]:
|
|
992
|
+
if v not in seen:
|
|
993
|
+
seen.add(v)
|
|
994
|
+
parent[v] = (u, q)
|
|
995
|
+
queue.append(v)
|
|
996
|
+
corr = set()
|
|
997
|
+
for u in reversed(order):
|
|
998
|
+
if u in parent:
|
|
999
|
+
p, q = parent[u]
|
|
1000
|
+
if syn[u]:
|
|
1001
|
+
corr.add(q)
|
|
1002
|
+
syn[p] ^= 1
|
|
1003
|
+
syn[u] = 0
|
|
1004
|
+
elif u != m and syn[u]:
|
|
1005
|
+
return None
|
|
1006
|
+
if any(syn[v] for v in range(m) if v not in seen):
|
|
1007
|
+
return None
|
|
1008
|
+
return corr
|
|
1009
|
+
|
|
1010
|
+
|
|
1011
|
+
def peeling_decode(stabilizers, observed_syndrome, heralded_qubits, n_qubits) -> Optional[str]:
|
|
1012
|
+
"""Peeling decoder for a CSS code whose X-type and Z-type checks each join
|
|
1013
|
+
every qubit to at most two checks (repetition and surface codes)."""
|
|
1014
|
+
stabs = list(stabilizers)
|
|
1015
|
+
syn = np.array(observed_syndrome, dtype=np.uint8)
|
|
1016
|
+
erased = sorted({int(q) for q in heralded_qubits})
|
|
1017
|
+
zi = [i for i, s in enumerate(stabs) if 'Z' in s and 'X' not in s]
|
|
1018
|
+
xi = [i for i, s in enumerate(stabs) if 'X' in s and 'Z' not in s]
|
|
1019
|
+
hz = np.array([[c != 'I' for c in stabs[i]] for i in zi], dtype=np.uint8)
|
|
1020
|
+
hx = np.array([[c != 'I' for c in stabs[i]] for i in xi], dtype=np.uint8)
|
|
1021
|
+
x_part = _peel(hz, erased, syn[zi])
|
|
1022
|
+
z_part = _peel(hx, erased, syn[xi])
|
|
1023
|
+
if x_part is None or z_part is None:
|
|
1024
|
+
return None
|
|
1025
|
+
return ''.join('IXZY'[(q in x_part) + 2 * (q in z_part)] for q in range(n_qubits))
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
def _uf_grow(h, erased, syn):
|
|
1029
|
+
m, n = h.shape
|
|
1030
|
+
ends = []
|
|
1031
|
+
for q in range(n):
|
|
1032
|
+
rows = np.flatnonzero(h[:, q])
|
|
1033
|
+
ends.append((int(rows[0]), int(rows[1])) if len(rows) == 2 else (int(rows[0]), m))
|
|
1034
|
+
parent = list(range(m + 1))
|
|
1035
|
+
|
|
1036
|
+
def find(x):
|
|
1037
|
+
while parent[x] != x:
|
|
1038
|
+
parent[x] = parent[parent[x]]
|
|
1039
|
+
x = parent[x]
|
|
1040
|
+
return x
|
|
1041
|
+
|
|
1042
|
+
support = [0] * n
|
|
1043
|
+
for q in erased:
|
|
1044
|
+
support[q] = 2
|
|
1045
|
+
parent[find(ends[q][0])] = find(ends[q][1])
|
|
1046
|
+
s = [int(b) for b in syn] + [0]
|
|
1047
|
+
|
|
1048
|
+
def odd_roots():
|
|
1049
|
+
par = {}
|
|
1050
|
+
for v in range(m + 1):
|
|
1051
|
+
r = find(v)
|
|
1052
|
+
par[r] = par.get(r, 0) ^ s[v]
|
|
1053
|
+
return {r for r, p in par.items() if p and r != find(m)}
|
|
1054
|
+
|
|
1055
|
+
odd = odd_roots()
|
|
1056
|
+
while odd:
|
|
1057
|
+
grown = False
|
|
1058
|
+
for q in range(n):
|
|
1059
|
+
if support[q] < 2:
|
|
1060
|
+
ru, rv = find(ends[q][0]), find(ends[q][1])
|
|
1061
|
+
inc = (ru in odd) + (rv in odd and rv != ru)
|
|
1062
|
+
if inc:
|
|
1063
|
+
support[q] = min(2, support[q] + inc)
|
|
1064
|
+
grown = True
|
|
1065
|
+
if not grown:
|
|
1066
|
+
return None
|
|
1067
|
+
for q in range(n):
|
|
1068
|
+
if support[q] == 2:
|
|
1069
|
+
parent[find(ends[q][0])] = find(ends[q][1])
|
|
1070
|
+
odd = odd_roots()
|
|
1071
|
+
return [q for q in range(n) if support[q] == 2]
|
|
1072
|
+
|
|
1073
|
+
|
|
1074
|
+
def _css_split(stabilizers, observed_syndrome):
|
|
1075
|
+
stabs = list(stabilizers)
|
|
1076
|
+
syn = np.array(observed_syndrome, dtype=np.uint8)
|
|
1077
|
+
zi = [i for i, s in enumerate(stabs) if 'Z' in s and 'X' not in s]
|
|
1078
|
+
xi = [i for i, s in enumerate(stabs) if 'X' in s and 'Z' not in s]
|
|
1079
|
+
hz = np.array([[c != 'I' for c in stabs[i]] for i in zi], dtype=np.uint8)
|
|
1080
|
+
hx = np.array([[c != 'I' for c in stabs[i]] for i in xi], dtype=np.uint8)
|
|
1081
|
+
return hz, syn[zi], hx, syn[xi]
|
|
1082
|
+
|
|
1083
|
+
|
|
1084
|
+
def union_find_decode(stabilizers, observed_syndrome, heralded_qubits, n_qubits) -> Optional[str]:
|
|
1085
|
+
"""Union-Find decoder with erasures and Pauli errors (Delfosse and
|
|
1086
|
+
Nickerson, arXiv:1709.06218): clusters start from the erased qubits and
|
|
1087
|
+
grow by half-edges until every cluster has even syndrome parity or touches
|
|
1088
|
+
the boundary, then each grown cluster is peeled."""
|
|
1089
|
+
hz, sz, hx, sx = _css_split(stabilizers, observed_syndrome)
|
|
1090
|
+
erased = sorted({int(q) for q in heralded_qubits})
|
|
1091
|
+
parts = []
|
|
1092
|
+
for h, s in ((hz, sz), (hx, sx)):
|
|
1093
|
+
grown = _uf_grow(h, erased, s)
|
|
1094
|
+
if grown is None:
|
|
1095
|
+
return None
|
|
1096
|
+
part = _peel(h, grown, s)
|
|
1097
|
+
if part is None:
|
|
1098
|
+
return None
|
|
1099
|
+
parts.append(part)
|
|
1100
|
+
return ''.join('IXZY'[(q in parts[0]) + 2 * (q in parts[1])] for q in range(n_qubits))
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
def matching_erasure_decode(stabilizers, observed_syndrome, heralded_qubits, n_qubits) -> str:
|
|
1104
|
+
"""Minimum-weight perfect matching with weight 0 on the erased qubits
|
|
1105
|
+
(Stace, Barrett and Doherty, arXiv:0904.3556), via pymatching."""
|
|
1106
|
+
import pymatching
|
|
1107
|
+
|
|
1108
|
+
hz, sz, hx, sx = _css_split(stabilizers, observed_syndrome)
|
|
1109
|
+
w = np.ones(n_qubits)
|
|
1110
|
+
w[list(heralded_qubits)] = 0.0
|
|
1111
|
+
xp = pymatching.Matching.from_check_matrix(hz, weights=w).decode(sz)
|
|
1112
|
+
zp = pymatching.Matching.from_check_matrix(hx, weights=w).decode(sx)
|
|
1113
|
+
return ''.join('IXZY'[int(xp[q]) + 2 * int(zp[q])] for q in range(n_qubits))
|
|
@@ -7,11 +7,14 @@ unchanged. Import from dense_evolution.physics.qec directly in new code.
|
|
|
7
7
|
from dense_evolution.physics.qec import (
|
|
8
8
|
pauli_commutes, compute_syndrome, erasure_aware_decode, pymatching_decode,
|
|
9
9
|
blind_minimum_weight_decode, decode_with_erasure_fallback,
|
|
10
|
-
counts_in_intervals_dimension, nearest_coset_decode,
|
|
10
|
+
counts_in_intervals_dimension, nearest_coset_decode, erasure_ml_decode,
|
|
11
|
+
peeling_decode, union_find_decode, matching_erasure_decode,
|
|
12
|
+
estimate_edge_probabilities_from_detection_events,
|
|
11
13
|
)
|
|
12
14
|
|
|
13
15
|
__all__ = [
|
|
14
16
|
'pauli_commutes', 'compute_syndrome', 'erasure_aware_decode', 'pymatching_decode',
|
|
15
17
|
'blind_minimum_weight_decode', 'decode_with_erasure_fallback',
|
|
16
|
-
'counts_in_intervals_dimension', 'nearest_coset_decode',
|
|
18
|
+
'counts_in_intervals_dimension', 'nearest_coset_decode', 'erasure_ml_decode', 'peeling_decode', 'union_find_decode', 'matching_erasure_decode',
|
|
19
|
+
'estimate_edge_probabilities_from_detection_events',
|
|
17
20
|
]
|