dense-evolution 8.1.7__tar.gz → 8.1.9__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.1.7 → dense_evolution-8.1.9}/PKG-INFO +90 -3
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/README.md +89 -2
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution/__init__.py +2 -1
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution/chunk.py +10 -0
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution/healing.py +2 -2
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution/parser.py +28 -6
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution.egg-info/PKG-INFO +90 -3
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution.egg-info/SOURCES.txt +0 -2
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/ia_utils/vector_healing.py +13 -19
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/pyproject.toml +1 -1
- dense_evolution-8.1.7/dense_evolution/stress_test.py +0 -76
- dense_evolution-8.1.7/dense_evolution/test2.py +0 -76
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dash.py +0 -0
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution/compiler.py +0 -0
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution/gates.py +0 -0
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution/registry.py +0 -0
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution/simulator.py +0 -0
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution.egg-info/dependency_links.txt +0 -0
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution.egg-info/requires.txt +0 -0
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution.egg-info/top_level.txt +0 -0
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/ia_utils/__init__.py +0 -0
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/license.md +0 -0
- {dense_evolution-8.1.7 → dense_evolution-8.1.9}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dense-evolution
|
|
3
|
-
Version: 8.1.
|
|
3
|
+
Version: 8.1.9
|
|
4
4
|
Summary: Micro-optimized High-Performance NISQ Statevector Quantum Circuit Simulator (Hardware-Adaptive Integration of Native NumPy, CUDA-Accelerated CuPy, and Linear Kernel Fusion via JAX JIT/XLA Compilation)
|
|
5
5
|
Author-email: Salvatore Pennacchio <jtatopenn@libero.it>
|
|
6
6
|
License: Business Source License 1.1
|
|
@@ -63,10 +63,16 @@ Dynamic: license-file
|
|
|
63
63
|
|
|
64
64
|
[](https://github.com/tatopenn-cell/Dense-Evolution/actions/workflows/ci.yml)
|
|
65
65
|
[](https://pypi.org/project/dense-evolution/)
|
|
66
|
+
[](https://pypi.org/project/dense-evolution/)
|
|
66
67
|
[](https://www.python.org/)
|
|
67
68
|
[](LICENSE.md)
|
|
68
69
|
[](https://github.com/tatopenn-cell/Dense-Evolution/actions)
|
|
69
70
|
[](https://github.com/tatopenn-cell/Dense-Evolution-Ising-Tests/actions/workflows/ci.yml)
|
|
71
|
+
[](https://github.com/tatopenn-cell/Dense-Evolution/releases)
|
|
72
|
+
[](https://github.com/tatopenn-cell/Dense-Evolution/commits/main)
|
|
73
|
+
[](https://github.com/tatopenn-cell/Dense-Evolution/issues)
|
|
74
|
+
[](https://github.com/tatopenn-cell/Dense-Evolution/stargazers)
|
|
75
|
+
[](https://github.com/google/jax)
|
|
70
76
|
|
|
71
77
|
---
|
|
72
78
|
|
|
@@ -160,6 +166,9 @@ dense_evolution/
|
|
|
160
166
|
├── chunk.py SafeMemoryGuard · MemoryChunker · CircuitChunker · Chunk (Anti-OOM)
|
|
161
167
|
├── simulator.py DenseSVSimulator · run_parametric_batch_jit · vmap batch VQE
|
|
162
168
|
└── dash.py ipywidgets dashboard · VQE engine · QM/MM · MD simulation · 3D wavefunction
|
|
169
|
+
|
|
170
|
+
ia_utils/
|
|
171
|
+
└── vector_healing.py median_healing · enhanced_dense_healing_hybrid (NaN/Inf-safe, lazy JAX import)
|
|
163
172
|
```
|
|
164
173
|
|
|
165
174
|
**Data flow per run:**
|
|
@@ -185,6 +194,7 @@ dense_evolution/
|
|
|
185
194
|
| **VQE + ADAM** | Hellmann-Feynman gradient · positional parameter injection into any OpenQASM 2.0 circuit |
|
|
186
195
|
| **Anti-OOM Engine** | `SafeMemoryGuard` blocks execution before JAX raises `RESOURCE_EXHAUSTED` |
|
|
187
196
|
| **Predictive Healing** | `healing.py` — Φ_AB alignment, dynamic vector, Σ-sync, `MemoryReflectionEngine` |
|
|
197
|
+
| **Vector Sequence Healing** | `ia_utils/` — `median_healing`, `enhanced_dense_healing_hybrid` — NaN/Inf-safe, lazy JAX import |
|
|
188
198
|
| **Backend Agnostic** | NumPy CPU · JAX XLA CPU/TPU · CuPy CUDA — runtime selection, zero code changes |
|
|
189
199
|
| **Live Dashboard** | 8-panel ipywidgets telemetry: probability, VQE energy, entropy, purity, gradient, noise, θ-correction, Pearson heatmap |
|
|
190
200
|
|
|
@@ -240,6 +250,7 @@ sim = DenseSVSimulator(
|
|
|
240
250
|
| Method | Description |
|
|
241
251
|
|---|---|
|
|
242
252
|
| `set_initial_state(state=None)` | Reset to `\|0⟩ⁿ` or inject custom statevector |
|
|
253
|
+
| `run_circuit(circuit, transpile=True)` | Plain (non-JIT) gate execution — takes the tuple format below |
|
|
243
254
|
| `run_circuit_jit_beast_mode(circuit)` | JIT-compiled gate execution — primary execution path |
|
|
244
255
|
| `run_circuit_with_chunking(circuit, chunk_size=500)` | Chunked execution for long circuits |
|
|
245
256
|
| `run_parametric_batch_jit(base_circuit, parameter_batch)` | `vmap` over parameter grid — returns full batch of statevectors |
|
|
@@ -258,16 +269,34 @@ circuit = parser.parse(qasm_str) # → QASMCircuit
|
|
|
258
269
|
valid, msg = parser.validate(circuit)
|
|
259
270
|
```
|
|
260
271
|
|
|
261
|
-
`QASMCircuit` fields: `n_qubits`, `n_cbits`, `ops` (list of gate
|
|
272
|
+
`QASMCircuit` fields: `n_qubits`, `n_cbits`, `ops` (list of gate dicts, e.g.
|
|
273
|
+
`{'name': 'h', 'qubits': [0], 'params': []}`). Use `circuit.to_tuples()` to
|
|
274
|
+
convert `ops` to the `(name, qubit0[, qubit1, ...][, param0, ...])` tuple
|
|
275
|
+
format that `run_circuit` / `run_circuit_jit_beast_mode` expect — don't
|
|
276
|
+
build that format by hand.
|
|
262
277
|
|
|
263
278
|
### `NoiseModel`
|
|
264
279
|
|
|
265
280
|
```python
|
|
266
281
|
noise = NoiseModel()
|
|
267
|
-
noise.
|
|
282
|
+
noise.apply_to_sv(sv, n=4, model='depolarizing', p=0.01, rng=rng)
|
|
268
283
|
desc = NoiseModel.kraus_description('amplitude_damping')
|
|
269
284
|
```
|
|
270
285
|
|
|
286
|
+
### End-to-end: parse → run → apply noise
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
parser = QASMParser()
|
|
290
|
+
circuit = parser.parse(qasm_str) # → QASMCircuit
|
|
291
|
+
sim = DenseSVSimulator(n_qubits=circuit.n_qubits)
|
|
292
|
+
sim.run_circuit(circuit.to_tuples()) # dicts -> tuples, then execute
|
|
293
|
+
|
|
294
|
+
sv_noisy = NoiseModel().apply_to_sv(
|
|
295
|
+
sim.get_statevector(), n=circuit.n_qubits, model='depolarizing', p=0.01,
|
|
296
|
+
rng=np.random.default_rng(42),
|
|
297
|
+
)
|
|
298
|
+
```
|
|
299
|
+
|
|
271
300
|
### `Chunk` (Anti-OOM)
|
|
272
301
|
|
|
273
302
|
```python
|
|
@@ -283,6 +312,17 @@ sim.run_chunk(circuit, chunk_size_gates=500)
|
|
|
283
312
|
|
|
284
313
|
Backward-compatibility aliases: `chunk1 = MemoryChunker`, `chunk2 = Chunk`, `Chunk2Incrociato = Chunk`.
|
|
285
314
|
|
|
315
|
+
### `ia_utils.vector_healing`
|
|
316
|
+
|
|
317
|
+
```python
|
|
318
|
+
from ia_utils.vector_healing import median_healing, enhanced_dense_healing_hybrid
|
|
319
|
+
|
|
320
|
+
healed, radius = median_healing(vettori, radius_baseline=None)
|
|
321
|
+
healed, metadata = enhanced_dense_healing_hybrid(vettori, radius_baseline=None, median_fallback_threshold=0.1)
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
See **IA Utils — Vector Sequence Healing** above for details.
|
|
325
|
+
|
|
286
326
|
---
|
|
287
327
|
|
|
288
328
|
## ▍ Gate Library
|
|
@@ -350,6 +390,42 @@ All core functions compiled via `@jax.jit`. Event history managed by `MemoryRefl
|
|
|
350
390
|
|
|
351
391
|
---
|
|
352
392
|
|
|
393
|
+
## ▍ IA Utils — Vector Sequence Healing
|
|
394
|
+
|
|
395
|
+
`ia_utils/vector_healing.py` — standalone module for cleaning sequences of vectors (e.g. hidden states / embeddings) that may contain `NaN` or `Inf` entries. Both functions preprocess the input (Inf → NaN → column-mean imputation) before healing, so corrupted values never propagate into the output.
|
|
396
|
+
|
|
397
|
+
| Function | Approach | Returns |
|
|
398
|
+
|---|---|---|
|
|
399
|
+
| `median_healing(vettori, radius_baseline=None)` | `scipy.ndimage.median_filter`, dynamic radius `min(20, max(3, n // 3))` | `(healed: np.ndarray, radius: int)` |
|
|
400
|
+
| `enhanced_dense_healing_hybrid(vettori, radius_baseline=None, median_fallback_threshold=0.1)` | Blends the `dense_evolution.healing` Φ-trigger logic with a median fallback, decided per-step | `(healed: np.ndarray, metadata: dict)` |
|
|
401
|
+
|
|
402
|
+
`enhanced_dense_healing_hybrid` metadata:
|
|
403
|
+
|
|
404
|
+
| Key | Type | Description |
|
|
405
|
+
|---|---|---|
|
|
406
|
+
| `fallback_triggered` | `bool` | `True` if the median fallback or dense blending fired at least once |
|
|
407
|
+
| `adaptive_radius_used` | `int` | Baseline radius actually applied |
|
|
408
|
+
| `reconstruction_error` | `float` | Mean norm of the correction applied vs. the sanitized input |
|
|
409
|
+
|
|
410
|
+
```python
|
|
411
|
+
import numpy as np
|
|
412
|
+
from ia_utils.vector_healing import median_healing, enhanced_dense_healing_hybrid
|
|
413
|
+
|
|
414
|
+
vettori = np.random.default_rng(0).normal(size=(50, 128))
|
|
415
|
+
vettori[10, 3] = np.nan # simulate a corrupted hidden state
|
|
416
|
+
vettori[30, 7] = np.inf
|
|
417
|
+
|
|
418
|
+
healed, radius = median_healing(vettori)
|
|
419
|
+
|
|
420
|
+
healed_hybrid, meta = enhanced_dense_healing_hybrid(vettori)
|
|
421
|
+
print(meta)
|
|
422
|
+
# {'fallback_triggered': True, 'adaptive_radius_used': 16, 'reconstruction_error': 11.48}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
`jax` is imported lazily inside `enhanced_dense_healing_hybrid` — `median_healing` and the module import itself work without the `[jax]` extra installed; only calling `enhanced_dense_healing_hybrid` requires it.
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
353
429
|
## ▍ Anti-OOM Chunk Engine
|
|
354
430
|
|
|
355
431
|
All operations parcellized dynamically using a 4-layer architectural shield.
|
|
@@ -468,6 +544,17 @@ All circuits stored as OpenQASM 2.0 strings in `QASM_LIBRARY`.
|
|
|
468
544
|
|
|
469
545
|
## ▍ Changelog
|
|
470
546
|
|
|
547
|
+
### v8.1.9
|
|
548
|
+
- **Fixed**: `ia_utils/vector_healing.py` — `enhanced_dense_healing_hybrid` had an unreachable third branch (a dense/blend fallback): the underlying `trigger` signal from `evaluate_phi_trigger` is strictly binary (0.0/1.0), so the branch could never execute. Collapsed to the genuine 2-state logic (pass-through vs. median fallback); runtime output is unchanged since the branch never ran.
|
|
549
|
+
- **Fixed**: `dashboard_core.py` — `run_simulation` / `run_vqe_telemetry` mutated the process-wide JAX `jax_enable_x64` flag without ever restoring it, so running one float32 simulation silently downgraded numerical precision for unrelated code later in the same process (e.g. the Vector Healing page, which sets no precision of its own). Both now save/restore the flag around their own execution.
|
|
550
|
+
- **Docs**: README's `NoiseModel` example called a nonexistent `.apply()` method with a wrong parameter name (`n_qubits` instead of `n`) — corrected to `apply_to_sv(sv, n=..., ...)`. Documented `QASMCircuit.to_tuples()` and `DenseSVSimulator.run_circuit`, which already existed and work correctly but were never mentioned in the README.
|
|
551
|
+
|
|
552
|
+
### v8.1.8
|
|
553
|
+
- **Fixed**: `parser.py` — controlled two-qubit gates (`cx`/`cy`/`cz`/`cp`/`crz`) parsed from QASM in the dashboard layer had control and target swapped relative to `compiler.py`'s documented `(gate, control, target)` contract, breaking entanglement for circuits run through the dashboard. The core `QASMCircuit.to_tuples()` path was already correct.
|
|
554
|
+
- **Fixed**: `parser.py` — range syntax (`q[0:3]`) on single-qubit gates only applied to the first qubit in the range, silently dropping the rest. Now expands into one gate application per qubit, matching the parser's own documented contract.
|
|
555
|
+
- **Fixed**: `from dense_evolution import Chunk` raised `ImportError` — `Chunk` is now re-exported from the package root. Added `get_probabilities()`/`get_statevector()` to `Chunk` for parity with `DenseSVSimulator`.
|
|
556
|
+
- **Removed**: `dense_evolution/test2.py` and `stress_test.py` — byte-identical, assertion-free debug scripts that shipped inside every install with 0% test coverage. Their one real check (Kraus noise is genuinely stochastic across independent runs) is now a real regression test.
|
|
557
|
+
|
|
471
558
|
### v8.1.7
|
|
472
559
|
- `ia_utils/` — new package: `median_healing`, `enhanced_dense_healing_hybrid` for vector sequence healing (NaN/Inf-safe)
|
|
473
560
|
- `jax` import in `ia_utils.vector_healing` made lazy — importable without the `[jax]` extra
|
|
@@ -18,10 +18,16 @@
|
|
|
18
18
|
|
|
19
19
|
[](https://github.com/tatopenn-cell/Dense-Evolution/actions/workflows/ci.yml)
|
|
20
20
|
[](https://pypi.org/project/dense-evolution/)
|
|
21
|
+
[](https://pypi.org/project/dense-evolution/)
|
|
21
22
|
[](https://www.python.org/)
|
|
22
23
|
[](LICENSE.md)
|
|
23
24
|
[](https://github.com/tatopenn-cell/Dense-Evolution/actions)
|
|
24
25
|
[](https://github.com/tatopenn-cell/Dense-Evolution-Ising-Tests/actions/workflows/ci.yml)
|
|
26
|
+
[](https://github.com/tatopenn-cell/Dense-Evolution/releases)
|
|
27
|
+
[](https://github.com/tatopenn-cell/Dense-Evolution/commits/main)
|
|
28
|
+
[](https://github.com/tatopenn-cell/Dense-Evolution/issues)
|
|
29
|
+
[](https://github.com/tatopenn-cell/Dense-Evolution/stargazers)
|
|
30
|
+
[](https://github.com/google/jax)
|
|
25
31
|
|
|
26
32
|
---
|
|
27
33
|
|
|
@@ -115,6 +121,9 @@ dense_evolution/
|
|
|
115
121
|
├── chunk.py SafeMemoryGuard · MemoryChunker · CircuitChunker · Chunk (Anti-OOM)
|
|
116
122
|
├── simulator.py DenseSVSimulator · run_parametric_batch_jit · vmap batch VQE
|
|
117
123
|
└── dash.py ipywidgets dashboard · VQE engine · QM/MM · MD simulation · 3D wavefunction
|
|
124
|
+
|
|
125
|
+
ia_utils/
|
|
126
|
+
└── vector_healing.py median_healing · enhanced_dense_healing_hybrid (NaN/Inf-safe, lazy JAX import)
|
|
118
127
|
```
|
|
119
128
|
|
|
120
129
|
**Data flow per run:**
|
|
@@ -140,6 +149,7 @@ dense_evolution/
|
|
|
140
149
|
| **VQE + ADAM** | Hellmann-Feynman gradient · positional parameter injection into any OpenQASM 2.0 circuit |
|
|
141
150
|
| **Anti-OOM Engine** | `SafeMemoryGuard` blocks execution before JAX raises `RESOURCE_EXHAUSTED` |
|
|
142
151
|
| **Predictive Healing** | `healing.py` — Φ_AB alignment, dynamic vector, Σ-sync, `MemoryReflectionEngine` |
|
|
152
|
+
| **Vector Sequence Healing** | `ia_utils/` — `median_healing`, `enhanced_dense_healing_hybrid` — NaN/Inf-safe, lazy JAX import |
|
|
143
153
|
| **Backend Agnostic** | NumPy CPU · JAX XLA CPU/TPU · CuPy CUDA — runtime selection, zero code changes |
|
|
144
154
|
| **Live Dashboard** | 8-panel ipywidgets telemetry: probability, VQE energy, entropy, purity, gradient, noise, θ-correction, Pearson heatmap |
|
|
145
155
|
|
|
@@ -195,6 +205,7 @@ sim = DenseSVSimulator(
|
|
|
195
205
|
| Method | Description |
|
|
196
206
|
|---|---|
|
|
197
207
|
| `set_initial_state(state=None)` | Reset to `\|0⟩ⁿ` or inject custom statevector |
|
|
208
|
+
| `run_circuit(circuit, transpile=True)` | Plain (non-JIT) gate execution — takes the tuple format below |
|
|
198
209
|
| `run_circuit_jit_beast_mode(circuit)` | JIT-compiled gate execution — primary execution path |
|
|
199
210
|
| `run_circuit_with_chunking(circuit, chunk_size=500)` | Chunked execution for long circuits |
|
|
200
211
|
| `run_parametric_batch_jit(base_circuit, parameter_batch)` | `vmap` over parameter grid — returns full batch of statevectors |
|
|
@@ -213,16 +224,34 @@ circuit = parser.parse(qasm_str) # → QASMCircuit
|
|
|
213
224
|
valid, msg = parser.validate(circuit)
|
|
214
225
|
```
|
|
215
226
|
|
|
216
|
-
`QASMCircuit` fields: `n_qubits`, `n_cbits`, `ops` (list of gate
|
|
227
|
+
`QASMCircuit` fields: `n_qubits`, `n_cbits`, `ops` (list of gate dicts, e.g.
|
|
228
|
+
`{'name': 'h', 'qubits': [0], 'params': []}`). Use `circuit.to_tuples()` to
|
|
229
|
+
convert `ops` to the `(name, qubit0[, qubit1, ...][, param0, ...])` tuple
|
|
230
|
+
format that `run_circuit` / `run_circuit_jit_beast_mode` expect — don't
|
|
231
|
+
build that format by hand.
|
|
217
232
|
|
|
218
233
|
### `NoiseModel`
|
|
219
234
|
|
|
220
235
|
```python
|
|
221
236
|
noise = NoiseModel()
|
|
222
|
-
noise.
|
|
237
|
+
noise.apply_to_sv(sv, n=4, model='depolarizing', p=0.01, rng=rng)
|
|
223
238
|
desc = NoiseModel.kraus_description('amplitude_damping')
|
|
224
239
|
```
|
|
225
240
|
|
|
241
|
+
### End-to-end: parse → run → apply noise
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
parser = QASMParser()
|
|
245
|
+
circuit = parser.parse(qasm_str) # → QASMCircuit
|
|
246
|
+
sim = DenseSVSimulator(n_qubits=circuit.n_qubits)
|
|
247
|
+
sim.run_circuit(circuit.to_tuples()) # dicts -> tuples, then execute
|
|
248
|
+
|
|
249
|
+
sv_noisy = NoiseModel().apply_to_sv(
|
|
250
|
+
sim.get_statevector(), n=circuit.n_qubits, model='depolarizing', p=0.01,
|
|
251
|
+
rng=np.random.default_rng(42),
|
|
252
|
+
)
|
|
253
|
+
```
|
|
254
|
+
|
|
226
255
|
### `Chunk` (Anti-OOM)
|
|
227
256
|
|
|
228
257
|
```python
|
|
@@ -238,6 +267,17 @@ sim.run_chunk(circuit, chunk_size_gates=500)
|
|
|
238
267
|
|
|
239
268
|
Backward-compatibility aliases: `chunk1 = MemoryChunker`, `chunk2 = Chunk`, `Chunk2Incrociato = Chunk`.
|
|
240
269
|
|
|
270
|
+
### `ia_utils.vector_healing`
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
from ia_utils.vector_healing import median_healing, enhanced_dense_healing_hybrid
|
|
274
|
+
|
|
275
|
+
healed, radius = median_healing(vettori, radius_baseline=None)
|
|
276
|
+
healed, metadata = enhanced_dense_healing_hybrid(vettori, radius_baseline=None, median_fallback_threshold=0.1)
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
See **IA Utils — Vector Sequence Healing** above for details.
|
|
280
|
+
|
|
241
281
|
---
|
|
242
282
|
|
|
243
283
|
## ▍ Gate Library
|
|
@@ -305,6 +345,42 @@ All core functions compiled via `@jax.jit`. Event history managed by `MemoryRefl
|
|
|
305
345
|
|
|
306
346
|
---
|
|
307
347
|
|
|
348
|
+
## ▍ IA Utils — Vector Sequence Healing
|
|
349
|
+
|
|
350
|
+
`ia_utils/vector_healing.py` — standalone module for cleaning sequences of vectors (e.g. hidden states / embeddings) that may contain `NaN` or `Inf` entries. Both functions preprocess the input (Inf → NaN → column-mean imputation) before healing, so corrupted values never propagate into the output.
|
|
351
|
+
|
|
352
|
+
| Function | Approach | Returns |
|
|
353
|
+
|---|---|---|
|
|
354
|
+
| `median_healing(vettori, radius_baseline=None)` | `scipy.ndimage.median_filter`, dynamic radius `min(20, max(3, n // 3))` | `(healed: np.ndarray, radius: int)` |
|
|
355
|
+
| `enhanced_dense_healing_hybrid(vettori, radius_baseline=None, median_fallback_threshold=0.1)` | Blends the `dense_evolution.healing` Φ-trigger logic with a median fallback, decided per-step | `(healed: np.ndarray, metadata: dict)` |
|
|
356
|
+
|
|
357
|
+
`enhanced_dense_healing_hybrid` metadata:
|
|
358
|
+
|
|
359
|
+
| Key | Type | Description |
|
|
360
|
+
|---|---|---|
|
|
361
|
+
| `fallback_triggered` | `bool` | `True` if the median fallback or dense blending fired at least once |
|
|
362
|
+
| `adaptive_radius_used` | `int` | Baseline radius actually applied |
|
|
363
|
+
| `reconstruction_error` | `float` | Mean norm of the correction applied vs. the sanitized input |
|
|
364
|
+
|
|
365
|
+
```python
|
|
366
|
+
import numpy as np
|
|
367
|
+
from ia_utils.vector_healing import median_healing, enhanced_dense_healing_hybrid
|
|
368
|
+
|
|
369
|
+
vettori = np.random.default_rng(0).normal(size=(50, 128))
|
|
370
|
+
vettori[10, 3] = np.nan # simulate a corrupted hidden state
|
|
371
|
+
vettori[30, 7] = np.inf
|
|
372
|
+
|
|
373
|
+
healed, radius = median_healing(vettori)
|
|
374
|
+
|
|
375
|
+
healed_hybrid, meta = enhanced_dense_healing_hybrid(vettori)
|
|
376
|
+
print(meta)
|
|
377
|
+
# {'fallback_triggered': True, 'adaptive_radius_used': 16, 'reconstruction_error': 11.48}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
`jax` is imported lazily inside `enhanced_dense_healing_hybrid` — `median_healing` and the module import itself work without the `[jax]` extra installed; only calling `enhanced_dense_healing_hybrid` requires it.
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
308
384
|
## ▍ Anti-OOM Chunk Engine
|
|
309
385
|
|
|
310
386
|
All operations parcellized dynamically using a 4-layer architectural shield.
|
|
@@ -423,6 +499,17 @@ All circuits stored as OpenQASM 2.0 strings in `QASM_LIBRARY`.
|
|
|
423
499
|
|
|
424
500
|
## ▍ Changelog
|
|
425
501
|
|
|
502
|
+
### v8.1.9
|
|
503
|
+
- **Fixed**: `ia_utils/vector_healing.py` — `enhanced_dense_healing_hybrid` had an unreachable third branch (a dense/blend fallback): the underlying `trigger` signal from `evaluate_phi_trigger` is strictly binary (0.0/1.0), so the branch could never execute. Collapsed to the genuine 2-state logic (pass-through vs. median fallback); runtime output is unchanged since the branch never ran.
|
|
504
|
+
- **Fixed**: `dashboard_core.py` — `run_simulation` / `run_vqe_telemetry` mutated the process-wide JAX `jax_enable_x64` flag without ever restoring it, so running one float32 simulation silently downgraded numerical precision for unrelated code later in the same process (e.g. the Vector Healing page, which sets no precision of its own). Both now save/restore the flag around their own execution.
|
|
505
|
+
- **Docs**: README's `NoiseModel` example called a nonexistent `.apply()` method with a wrong parameter name (`n_qubits` instead of `n`) — corrected to `apply_to_sv(sv, n=..., ...)`. Documented `QASMCircuit.to_tuples()` and `DenseSVSimulator.run_circuit`, which already existed and work correctly but were never mentioned in the README.
|
|
506
|
+
|
|
507
|
+
### v8.1.8
|
|
508
|
+
- **Fixed**: `parser.py` — controlled two-qubit gates (`cx`/`cy`/`cz`/`cp`/`crz`) parsed from QASM in the dashboard layer had control and target swapped relative to `compiler.py`'s documented `(gate, control, target)` contract, breaking entanglement for circuits run through the dashboard. The core `QASMCircuit.to_tuples()` path was already correct.
|
|
509
|
+
- **Fixed**: `parser.py` — range syntax (`q[0:3]`) on single-qubit gates only applied to the first qubit in the range, silently dropping the rest. Now expands into one gate application per qubit, matching the parser's own documented contract.
|
|
510
|
+
- **Fixed**: `from dense_evolution import Chunk` raised `ImportError` — `Chunk` is now re-exported from the package root. Added `get_probabilities()`/`get_statevector()` to `Chunk` for parity with `DenseSVSimulator`.
|
|
511
|
+
- **Removed**: `dense_evolution/test2.py` and `stress_test.py` — byte-identical, assertion-free debug scripts that shipped inside every install with 0% test coverage. Their one real check (Kraus noise is genuinely stochastic across independent runs) is now a real regression test.
|
|
512
|
+
|
|
426
513
|
### v8.1.7
|
|
427
514
|
- `ia_utils/` — new package: `median_healing`, `enhanced_dense_healing_hybrid` for vector sequence healing (NaN/Inf-safe)
|
|
428
515
|
- `jax` import in `ia_utils.vector_healing` made lazy — importable without the `[jax]` extra
|
|
@@ -7,5 +7,6 @@ from .parser import QASMParser, QASMCircuit
|
|
|
7
7
|
from .compiler import QuantumTranspiler
|
|
8
8
|
from .registry import NoiseModel, QuantumHardwareRegistry
|
|
9
9
|
from .gates import GATES, PARAMETRIC_GATES, GATE_IDS
|
|
10
|
+
from .chunk import Chunk
|
|
10
11
|
|
|
11
|
-
__version__ = "8.1.
|
|
12
|
+
__version__ = "8.1.9"
|
|
@@ -334,6 +334,16 @@ class Chunk:
|
|
|
334
334
|
"""RAM used by the physical statevector in MB."""
|
|
335
335
|
return self._inner_sim.memory_mb()
|
|
336
336
|
|
|
337
|
+
def get_probabilities(self):
|
|
338
|
+
"""|amplitude|^2 for every basis state — forwards to the inner
|
|
339
|
+
DenseSVSimulator for parity with its own get_probabilities()."""
|
|
340
|
+
return self._inner_sim.get_probabilities()
|
|
341
|
+
|
|
342
|
+
def get_statevector(self):
|
|
343
|
+
"""Full complex statevector — forwards to the inner DenseSVSimulator
|
|
344
|
+
for parity with its own get_statevector()."""
|
|
345
|
+
return self._inner_sim.get_statevector()
|
|
346
|
+
|
|
337
347
|
# ── Public API ───────────────────────────────────────────────────────────
|
|
338
348
|
|
|
339
349
|
def run_chunk(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import jax
|
|
2
2
|
import jax.numpy as jnp
|
|
3
3
|
import json
|
|
4
|
-
from datetime import datetime
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
5
|
from typing import Dict, Tuple, List, Any
|
|
6
6
|
|
|
7
7
|
|
|
@@ -104,7 +104,7 @@ class MemoryReflectionEngine:
|
|
|
104
104
|
|
|
105
105
|
def record_event(self, event_type: str, value: float, description: str = ""):
|
|
106
106
|
event = {
|
|
107
|
-
"timestamp": datetime.
|
|
107
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
108
108
|
"type": event_type,
|
|
109
109
|
"value": float(value),
|
|
110
110
|
"description": description
|
|
@@ -93,6 +93,18 @@ class QASMParser:
|
|
|
93
93
|
'ccx': 'ccx',
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
# ── gate names that only ever take one qubit ─────────────────────
|
|
97
|
+
# Used to expand range syntax (q[0:3]) into one op per qubit instead
|
|
98
|
+
# of a single op with multiple qubits attached — see BUG FIX 3 note
|
|
99
|
+
# on parse(): the original fix resolved q[0:3] to the qubit list
|
|
100
|
+
# [0,1,2], but nothing expanded that list into separate applications
|
|
101
|
+
# for gates that are only ever single-qubit, so e.g. `h q[0:3]` ended
|
|
102
|
+
# up applying H to qubit 0 only, silently dropping qubits 1 and 2.
|
|
103
|
+
_SINGLE_QUBIT_GATES = frozenset((
|
|
104
|
+
'h', 'x', 'y', 'z', 's', 'sdg', 't', 'tdg', 'sx', 'id',
|
|
105
|
+
'rx', 'ry', 'rz', 'p', 'u1', 'u2', 'u3',
|
|
106
|
+
))
|
|
107
|
+
|
|
96
108
|
# ── statements to skip entirely ──────────────────────────────────
|
|
97
109
|
# BUG FIX (original): 'gate ' had a trailing space making it miss
|
|
98
110
|
# 'gate foo(...)' where the token is 'gate' followed by space.
|
|
@@ -211,11 +223,21 @@ class QASMParser:
|
|
|
211
223
|
# ── gate application ─────────────────────────────────────
|
|
212
224
|
op = self._parse_gate(instr, qubit_map)
|
|
213
225
|
if op is not None:
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
226
|
+
if op['name'] in self._SINGLE_QUBIT_GATES and len(op['qubits']) > 1:
|
|
227
|
+
# range syntax on an inherently single-qubit gate
|
|
228
|
+
# (e.g. `h q[0:3]`) — expand into one op per qubit.
|
|
229
|
+
for q in op['qubits']:
|
|
230
|
+
ops.append({
|
|
231
|
+
'type': op['type'], 'name': op['name'],
|
|
232
|
+
'qubits': [q], 'params': list(op['params']),
|
|
233
|
+
})
|
|
234
|
+
n_qubits = max(n_qubits, q + 1)
|
|
235
|
+
else:
|
|
236
|
+
ops.append(op)
|
|
237
|
+
# update n_qubits from seen qubit indices
|
|
238
|
+
# (handles circuits without explicit qreg declarations)
|
|
239
|
+
if op['qubits']:
|
|
240
|
+
n_qubits = max(n_qubits, max(op['qubits']) + 1)
|
|
219
241
|
|
|
220
242
|
return QASMCircuit(n_qubits, n_cbits, ops)
|
|
221
243
|
|
|
@@ -360,7 +382,7 @@ class QASMParser:
|
|
|
360
382
|
def _resolve_qubits(self,
|
|
361
383
|
s: str,
|
|
362
384
|
qmap: Dict[str, int]) -> List[int]:
|
|
363
|
-
"""
|
|
385
|
+
r"""
|
|
364
386
|
Resolve a comma-separated qubit argument string to absolute indices.
|
|
365
387
|
|
|
366
388
|
Handles
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dense-evolution
|
|
3
|
-
Version: 8.1.
|
|
3
|
+
Version: 8.1.9
|
|
4
4
|
Summary: Micro-optimized High-Performance NISQ Statevector Quantum Circuit Simulator (Hardware-Adaptive Integration of Native NumPy, CUDA-Accelerated CuPy, and Linear Kernel Fusion via JAX JIT/XLA Compilation)
|
|
5
5
|
Author-email: Salvatore Pennacchio <jtatopenn@libero.it>
|
|
6
6
|
License: Business Source License 1.1
|
|
@@ -63,10 +63,16 @@ Dynamic: license-file
|
|
|
63
63
|
|
|
64
64
|
[](https://github.com/tatopenn-cell/Dense-Evolution/actions/workflows/ci.yml)
|
|
65
65
|
[](https://pypi.org/project/dense-evolution/)
|
|
66
|
+
[](https://pypi.org/project/dense-evolution/)
|
|
66
67
|
[](https://www.python.org/)
|
|
67
68
|
[](LICENSE.md)
|
|
68
69
|
[](https://github.com/tatopenn-cell/Dense-Evolution/actions)
|
|
69
70
|
[](https://github.com/tatopenn-cell/Dense-Evolution-Ising-Tests/actions/workflows/ci.yml)
|
|
71
|
+
[](https://github.com/tatopenn-cell/Dense-Evolution/releases)
|
|
72
|
+
[](https://github.com/tatopenn-cell/Dense-Evolution/commits/main)
|
|
73
|
+
[](https://github.com/tatopenn-cell/Dense-Evolution/issues)
|
|
74
|
+
[](https://github.com/tatopenn-cell/Dense-Evolution/stargazers)
|
|
75
|
+
[](https://github.com/google/jax)
|
|
70
76
|
|
|
71
77
|
---
|
|
72
78
|
|
|
@@ -160,6 +166,9 @@ dense_evolution/
|
|
|
160
166
|
├── chunk.py SafeMemoryGuard · MemoryChunker · CircuitChunker · Chunk (Anti-OOM)
|
|
161
167
|
├── simulator.py DenseSVSimulator · run_parametric_batch_jit · vmap batch VQE
|
|
162
168
|
└── dash.py ipywidgets dashboard · VQE engine · QM/MM · MD simulation · 3D wavefunction
|
|
169
|
+
|
|
170
|
+
ia_utils/
|
|
171
|
+
└── vector_healing.py median_healing · enhanced_dense_healing_hybrid (NaN/Inf-safe, lazy JAX import)
|
|
163
172
|
```
|
|
164
173
|
|
|
165
174
|
**Data flow per run:**
|
|
@@ -185,6 +194,7 @@ dense_evolution/
|
|
|
185
194
|
| **VQE + ADAM** | Hellmann-Feynman gradient · positional parameter injection into any OpenQASM 2.0 circuit |
|
|
186
195
|
| **Anti-OOM Engine** | `SafeMemoryGuard` blocks execution before JAX raises `RESOURCE_EXHAUSTED` |
|
|
187
196
|
| **Predictive Healing** | `healing.py` — Φ_AB alignment, dynamic vector, Σ-sync, `MemoryReflectionEngine` |
|
|
197
|
+
| **Vector Sequence Healing** | `ia_utils/` — `median_healing`, `enhanced_dense_healing_hybrid` — NaN/Inf-safe, lazy JAX import |
|
|
188
198
|
| **Backend Agnostic** | NumPy CPU · JAX XLA CPU/TPU · CuPy CUDA — runtime selection, zero code changes |
|
|
189
199
|
| **Live Dashboard** | 8-panel ipywidgets telemetry: probability, VQE energy, entropy, purity, gradient, noise, θ-correction, Pearson heatmap |
|
|
190
200
|
|
|
@@ -240,6 +250,7 @@ sim = DenseSVSimulator(
|
|
|
240
250
|
| Method | Description |
|
|
241
251
|
|---|---|
|
|
242
252
|
| `set_initial_state(state=None)` | Reset to `\|0⟩ⁿ` or inject custom statevector |
|
|
253
|
+
| `run_circuit(circuit, transpile=True)` | Plain (non-JIT) gate execution — takes the tuple format below |
|
|
243
254
|
| `run_circuit_jit_beast_mode(circuit)` | JIT-compiled gate execution — primary execution path |
|
|
244
255
|
| `run_circuit_with_chunking(circuit, chunk_size=500)` | Chunked execution for long circuits |
|
|
245
256
|
| `run_parametric_batch_jit(base_circuit, parameter_batch)` | `vmap` over parameter grid — returns full batch of statevectors |
|
|
@@ -258,16 +269,34 @@ circuit = parser.parse(qasm_str) # → QASMCircuit
|
|
|
258
269
|
valid, msg = parser.validate(circuit)
|
|
259
270
|
```
|
|
260
271
|
|
|
261
|
-
`QASMCircuit` fields: `n_qubits`, `n_cbits`, `ops` (list of gate
|
|
272
|
+
`QASMCircuit` fields: `n_qubits`, `n_cbits`, `ops` (list of gate dicts, e.g.
|
|
273
|
+
`{'name': 'h', 'qubits': [0], 'params': []}`). Use `circuit.to_tuples()` to
|
|
274
|
+
convert `ops` to the `(name, qubit0[, qubit1, ...][, param0, ...])` tuple
|
|
275
|
+
format that `run_circuit` / `run_circuit_jit_beast_mode` expect — don't
|
|
276
|
+
build that format by hand.
|
|
262
277
|
|
|
263
278
|
### `NoiseModel`
|
|
264
279
|
|
|
265
280
|
```python
|
|
266
281
|
noise = NoiseModel()
|
|
267
|
-
noise.
|
|
282
|
+
noise.apply_to_sv(sv, n=4, model='depolarizing', p=0.01, rng=rng)
|
|
268
283
|
desc = NoiseModel.kraus_description('amplitude_damping')
|
|
269
284
|
```
|
|
270
285
|
|
|
286
|
+
### End-to-end: parse → run → apply noise
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
parser = QASMParser()
|
|
290
|
+
circuit = parser.parse(qasm_str) # → QASMCircuit
|
|
291
|
+
sim = DenseSVSimulator(n_qubits=circuit.n_qubits)
|
|
292
|
+
sim.run_circuit(circuit.to_tuples()) # dicts -> tuples, then execute
|
|
293
|
+
|
|
294
|
+
sv_noisy = NoiseModel().apply_to_sv(
|
|
295
|
+
sim.get_statevector(), n=circuit.n_qubits, model='depolarizing', p=0.01,
|
|
296
|
+
rng=np.random.default_rng(42),
|
|
297
|
+
)
|
|
298
|
+
```
|
|
299
|
+
|
|
271
300
|
### `Chunk` (Anti-OOM)
|
|
272
301
|
|
|
273
302
|
```python
|
|
@@ -283,6 +312,17 @@ sim.run_chunk(circuit, chunk_size_gates=500)
|
|
|
283
312
|
|
|
284
313
|
Backward-compatibility aliases: `chunk1 = MemoryChunker`, `chunk2 = Chunk`, `Chunk2Incrociato = Chunk`.
|
|
285
314
|
|
|
315
|
+
### `ia_utils.vector_healing`
|
|
316
|
+
|
|
317
|
+
```python
|
|
318
|
+
from ia_utils.vector_healing import median_healing, enhanced_dense_healing_hybrid
|
|
319
|
+
|
|
320
|
+
healed, radius = median_healing(vettori, radius_baseline=None)
|
|
321
|
+
healed, metadata = enhanced_dense_healing_hybrid(vettori, radius_baseline=None, median_fallback_threshold=0.1)
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
See **IA Utils — Vector Sequence Healing** above for details.
|
|
325
|
+
|
|
286
326
|
---
|
|
287
327
|
|
|
288
328
|
## ▍ Gate Library
|
|
@@ -350,6 +390,42 @@ All core functions compiled via `@jax.jit`. Event history managed by `MemoryRefl
|
|
|
350
390
|
|
|
351
391
|
---
|
|
352
392
|
|
|
393
|
+
## ▍ IA Utils — Vector Sequence Healing
|
|
394
|
+
|
|
395
|
+
`ia_utils/vector_healing.py` — standalone module for cleaning sequences of vectors (e.g. hidden states / embeddings) that may contain `NaN` or `Inf` entries. Both functions preprocess the input (Inf → NaN → column-mean imputation) before healing, so corrupted values never propagate into the output.
|
|
396
|
+
|
|
397
|
+
| Function | Approach | Returns |
|
|
398
|
+
|---|---|---|
|
|
399
|
+
| `median_healing(vettori, radius_baseline=None)` | `scipy.ndimage.median_filter`, dynamic radius `min(20, max(3, n // 3))` | `(healed: np.ndarray, radius: int)` |
|
|
400
|
+
| `enhanced_dense_healing_hybrid(vettori, radius_baseline=None, median_fallback_threshold=0.1)` | Blends the `dense_evolution.healing` Φ-trigger logic with a median fallback, decided per-step | `(healed: np.ndarray, metadata: dict)` |
|
|
401
|
+
|
|
402
|
+
`enhanced_dense_healing_hybrid` metadata:
|
|
403
|
+
|
|
404
|
+
| Key | Type | Description |
|
|
405
|
+
|---|---|---|
|
|
406
|
+
| `fallback_triggered` | `bool` | `True` if the median fallback or dense blending fired at least once |
|
|
407
|
+
| `adaptive_radius_used` | `int` | Baseline radius actually applied |
|
|
408
|
+
| `reconstruction_error` | `float` | Mean norm of the correction applied vs. the sanitized input |
|
|
409
|
+
|
|
410
|
+
```python
|
|
411
|
+
import numpy as np
|
|
412
|
+
from ia_utils.vector_healing import median_healing, enhanced_dense_healing_hybrid
|
|
413
|
+
|
|
414
|
+
vettori = np.random.default_rng(0).normal(size=(50, 128))
|
|
415
|
+
vettori[10, 3] = np.nan # simulate a corrupted hidden state
|
|
416
|
+
vettori[30, 7] = np.inf
|
|
417
|
+
|
|
418
|
+
healed, radius = median_healing(vettori)
|
|
419
|
+
|
|
420
|
+
healed_hybrid, meta = enhanced_dense_healing_hybrid(vettori)
|
|
421
|
+
print(meta)
|
|
422
|
+
# {'fallback_triggered': True, 'adaptive_radius_used': 16, 'reconstruction_error': 11.48}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
`jax` is imported lazily inside `enhanced_dense_healing_hybrid` — `median_healing` and the module import itself work without the `[jax]` extra installed; only calling `enhanced_dense_healing_hybrid` requires it.
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
353
429
|
## ▍ Anti-OOM Chunk Engine
|
|
354
430
|
|
|
355
431
|
All operations parcellized dynamically using a 4-layer architectural shield.
|
|
@@ -468,6 +544,17 @@ All circuits stored as OpenQASM 2.0 strings in `QASM_LIBRARY`.
|
|
|
468
544
|
|
|
469
545
|
## ▍ Changelog
|
|
470
546
|
|
|
547
|
+
### v8.1.9
|
|
548
|
+
- **Fixed**: `ia_utils/vector_healing.py` — `enhanced_dense_healing_hybrid` had an unreachable third branch (a dense/blend fallback): the underlying `trigger` signal from `evaluate_phi_trigger` is strictly binary (0.0/1.0), so the branch could never execute. Collapsed to the genuine 2-state logic (pass-through vs. median fallback); runtime output is unchanged since the branch never ran.
|
|
549
|
+
- **Fixed**: `dashboard_core.py` — `run_simulation` / `run_vqe_telemetry` mutated the process-wide JAX `jax_enable_x64` flag without ever restoring it, so running one float32 simulation silently downgraded numerical precision for unrelated code later in the same process (e.g. the Vector Healing page, which sets no precision of its own). Both now save/restore the flag around their own execution.
|
|
550
|
+
- **Docs**: README's `NoiseModel` example called a nonexistent `.apply()` method with a wrong parameter name (`n_qubits` instead of `n`) — corrected to `apply_to_sv(sv, n=..., ...)`. Documented `QASMCircuit.to_tuples()` and `DenseSVSimulator.run_circuit`, which already existed and work correctly but were never mentioned in the README.
|
|
551
|
+
|
|
552
|
+
### v8.1.8
|
|
553
|
+
- **Fixed**: `parser.py` — controlled two-qubit gates (`cx`/`cy`/`cz`/`cp`/`crz`) parsed from QASM in the dashboard layer had control and target swapped relative to `compiler.py`'s documented `(gate, control, target)` contract, breaking entanglement for circuits run through the dashboard. The core `QASMCircuit.to_tuples()` path was already correct.
|
|
554
|
+
- **Fixed**: `parser.py` — range syntax (`q[0:3]`) on single-qubit gates only applied to the first qubit in the range, silently dropping the rest. Now expands into one gate application per qubit, matching the parser's own documented contract.
|
|
555
|
+
- **Fixed**: `from dense_evolution import Chunk` raised `ImportError` — `Chunk` is now re-exported from the package root. Added `get_probabilities()`/`get_statevector()` to `Chunk` for parity with `DenseSVSimulator`.
|
|
556
|
+
- **Removed**: `dense_evolution/test2.py` and `stress_test.py` — byte-identical, assertion-free debug scripts that shipped inside every install with 0% test coverage. Their one real check (Kraus noise is genuinely stochastic across independent runs) is now a real regression test.
|
|
557
|
+
|
|
471
558
|
### v8.1.7
|
|
472
559
|
- `ia_utils/` — new package: `median_healing`, `enhanced_dense_healing_hybrid` for vector sequence healing (NaN/Inf-safe)
|
|
473
560
|
- `jax` import in `ia_utils.vector_healing` made lazy — importable without the `[jax]` extra
|
|
@@ -10,8 +10,6 @@ dense_evolution/healing.py
|
|
|
10
10
|
dense_evolution/parser.py
|
|
11
11
|
dense_evolution/registry.py
|
|
12
12
|
dense_evolution/simulator.py
|
|
13
|
-
dense_evolution/stress_test.py
|
|
14
|
-
dense_evolution/test2.py
|
|
15
13
|
dense_evolution.egg-info/PKG-INFO
|
|
16
14
|
dense_evolution.egg-info/SOURCES.txt
|
|
17
15
|
dense_evolution.egg-info/dependency_links.txt
|
|
@@ -69,15 +69,20 @@ def enhanced_dense_healing_hybrid(
|
|
|
69
69
|
Se `None`, il raggio viene calcolato dinamicamente
|
|
70
70
|
come `min(20, max(3, n_tokens // 3))`.
|
|
71
71
|
Defaults to None.
|
|
72
|
-
median_fallback_threshold (float):
|
|
73
|
-
|
|
72
|
+
median_fallback_threshold (float): Non più utilizzato dalla logica interna — `trigger`
|
|
73
|
+
(da `evaluate_phi_trigger`) è strettamente binario
|
|
74
|
+
(0.0 o 1.0 per design: ciclo aperto/dinamico → incluso,
|
|
75
|
+
ciclo chiuso/statico → escluso), quindi non esiste un
|
|
76
|
+
valore intermedio su cui questa soglia possa agire.
|
|
77
|
+
Mantenuto nella firma per compatibilità con i chiamanti
|
|
78
|
+
esistenti. Defaults to 0.1.
|
|
74
79
|
|
|
75
80
|
Returns:
|
|
76
81
|
tuple: Contiene:
|
|
77
82
|
- np.ndarray: Vettori curati, della stessa shape dell'input.
|
|
78
83
|
- dict: Metadati di telemetria contenenti:
|
|
79
|
-
- 'fallback_triggered' (bool): `True` se il fallback mediano
|
|
80
|
-
|
|
84
|
+
- 'fallback_triggered' (bool): `True` se il fallback mediano è stato applicato
|
|
85
|
+
almeno una volta durante il healing.
|
|
81
86
|
- 'adaptive_radius_used' (int): Il raggio effettivamente calcolato e applicato.
|
|
82
87
|
- 'reconstruction_error' (float): La norma media di variazione (errore di ricostruzione)
|
|
83
88
|
introdotta rispetto ai vettori originali (potenzialmente corrotti).
|
|
@@ -86,7 +91,6 @@ def enhanced_dense_healing_hybrid(
|
|
|
86
91
|
from dense_evolution.healing import (
|
|
87
92
|
calculate_phi_ab,
|
|
88
93
|
calculate_vettore_dinamico,
|
|
89
|
-
calculate_delta_preemp,
|
|
90
94
|
evaluate_phi_trigger,
|
|
91
95
|
GLOBAL_CONSTANTS,
|
|
92
96
|
)
|
|
@@ -137,24 +141,14 @@ def enhanced_dense_healing_hybrid(
|
|
|
137
141
|
E_B = jnp.linalg.norm(state_B)
|
|
138
142
|
|
|
139
143
|
v_dinamic = calculate_vettore_dinamico(E_A, E_B, phi_ab)
|
|
140
|
-
|
|
141
|
-
trigger, lambda_step, epsilon_dissip = evaluate_phi_trigger(v_dinamic)
|
|
142
|
-
|
|
143
|
-
healed_vector = processed_vettori[i]
|
|
144
|
+
trigger, _, _ = evaluate_phi_trigger(v_dinamic)
|
|
144
145
|
|
|
145
146
|
if float(trigger) > GLOBAL_CONSTANTS['NON_STATIC_THRESHOLD_A']:
|
|
147
|
+
# trigger == 1.0: ciclo aperto/dinamico -> cambio genuino, si tiene il valore
|
|
146
148
|
healed_vector = processed_vettori[i]
|
|
147
|
-
elif float(trigger) < median_fallback_threshold:
|
|
148
|
-
baseline_median = np.median(processed_vettori[lo:i], axis=0)
|
|
149
|
-
healed_vector = baseline_median
|
|
150
|
-
fallback_triggered_at_all = True
|
|
151
149
|
else:
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
blend_factor = min(1.0, blend_factor + GLOBAL_CONSTANTS['DAMPING_BOOST_ON_STASIS'])
|
|
155
|
-
else:
|
|
156
|
-
blend_factor = max(0.0, blend_factor - GLOBAL_CONSTANTS['DAMPING_BOOST_ON_STASIS'])
|
|
157
|
-
healed_vector = (1 - blend_factor) * processed_vettori[i] + blend_factor * baseline_mean
|
|
150
|
+
# trigger == 0.0: ciclo chiuso/statico -> rumore, si sostituisce con la mediana locale
|
|
151
|
+
healed_vector = np.median(processed_vettori[lo:i], axis=0)
|
|
158
152
|
fallback_triggered_at_all = True
|
|
159
153
|
|
|
160
154
|
out[i] = healed_vector
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dense-evolution"
|
|
7
|
-
version = "8.1.
|
|
7
|
+
version = "8.1.9"
|
|
8
8
|
description = "Micro-optimized High-Performance NISQ Statevector Quantum Circuit Simulator (Hardware-Adaptive Integration of Native NumPy, CUDA-Accelerated CuPy, and Linear Kernel Fusion via JAX JIT/XLA Compilation)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
import numpy as np
|
|
3
|
-
from dense_evolution import DenseSVSimulator, QASMParser, QuantumTranspiler, NoiseModel
|
|
4
|
-
|
|
5
|
-
print("====================================================")
|
|
6
|
-
print("🔬 ADVANCED PRODUCTION STRESS-TEST: KRAUS & JIT SIMULATION")
|
|
7
|
-
print("====================================================")
|
|
8
|
-
|
|
9
|
-
try:
|
|
10
|
-
qasm_bench = """
|
|
11
|
-
OPENQASM 2.0;
|
|
12
|
-
include "qelib1.inc";
|
|
13
|
-
qreg q[6];
|
|
14
|
-
h q[0];
|
|
15
|
-
cx q[0], q[1];
|
|
16
|
-
cx q[1], q[2];
|
|
17
|
-
cx q[2], q[3];
|
|
18
|
-
cx q[3], q[4];
|
|
19
|
-
cx q[4], q[5];
|
|
20
|
-
rx(1.570796) q[0];
|
|
21
|
-
ry(0.785398) q[1];
|
|
22
|
-
rz(0.392699) q[2];
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
print("1. Parsing e Transpilazione del circuito QASM...")
|
|
26
|
-
# Questo testa la corretta importazione e funzione di parser.py e compiler.py
|
|
27
|
-
parser = QASMParser()
|
|
28
|
-
circ = parser.parse(qasm_bench)
|
|
29
|
-
tuples = QuantumTranspiler.transpile(circ.to_tuples())
|
|
30
|
-
n_qubits = circ.n_qubits
|
|
31
|
-
print(f"✓ Parsing completato. Qubit: {n_qubits}, Gate transpilati: {len(tuples)}")
|
|
32
|
-
|
|
33
|
-
print("\n2. Validazione Core JIT in modalità ideale (simulator.py)...")
|
|
34
|
-
t0 = time.perf_counter()
|
|
35
|
-
sim_ideale = DenseSVSimulator(n_qubits)
|
|
36
|
-
sim_ideale.run_circuit_jit_beast_mode(tuples)
|
|
37
|
-
t_ideale = time.perf_counter() - t0
|
|
38
|
-
prob_ideale = sim_ideale.get_probabilities()
|
|
39
|
-
print(f"✓ Successo ideale in {t_ideale:.4f} s | Dimensione stato: {len(prob_ideale)}")
|
|
40
|
-
|
|
41
|
-
print("\n3. Validazione NoiseModel (registry.py): Canale stocastico Amplitude Damping...")
|
|
42
|
-
|
|
43
|
-
# Run Noisy 1
|
|
44
|
-
t0 = time.perf_counter()
|
|
45
|
-
sim_noisy1 = DenseSVSimulator(n_qubits)
|
|
46
|
-
sim_noisy1.run_circuit_jit_beast_mode(tuples)
|
|
47
|
-
# Iniezione diretta del rumore Kraus sullo statevector compilato
|
|
48
|
-
sim_noisy1.sv = NoiseModel.apply_to_sv(sim_noisy1.sv, n_qubits, model='amplitude_damping', p=0.15)
|
|
49
|
-
prob_noisy1 = sim_noisy1.get_probabilities()
|
|
50
|
-
t_noisy1 = time.perf_counter() - t0
|
|
51
|
-
|
|
52
|
-
# Run Noisy 2
|
|
53
|
-
sim_noisy2 = DenseSVSimulator(n_qubits)
|
|
54
|
-
sim_noisy2.run_circuit_jit_beast_mode(tuples)
|
|
55
|
-
sim_noisy2.sv = NoiseModel.apply_to_sv(sim_noisy2.sv, n_qubits, model='amplitude_damping', p=0.15)
|
|
56
|
-
prob_noisy2 = sim_noisy2.get_probabilities()
|
|
57
|
-
|
|
58
|
-
print(f"✓ Successo noisy in {t_noisy1:.4f} s")
|
|
59
|
-
|
|
60
|
-
print("\n4. Analisi statistica delle fluttuazioni (Shot Noise Reale)...")
|
|
61
|
-
scostamento_stocastico = np.linalg.norm(prob_noisy1 - prob_noisy2)
|
|
62
|
-
scostamento_ideale = np.linalg.norm(prob_ideale - prob_noisy1)
|
|
63
|
-
|
|
64
|
-
print(f"🔬 Distanza ideale-noisy: {scostamento_ideale:.6f}")
|
|
65
|
-
print(f"🔬 Fluttuazione quantistica indipendente (Shot Noise): {scostamento_stocastico:.6f}")
|
|
66
|
-
|
|
67
|
-
if scostamento_stocastico > 1e-12:
|
|
68
|
-
print("\n✅ TEST SUPERATO: Moduli collegati, PRNG JAX funzionante e rumore autenticamente non-deterministico!")
|
|
69
|
-
else:
|
|
70
|
-
print("\n❌ FALLIMENTO: Il rumore è ancora lineare o statico. Le due run hanno prodotto stati identici.")
|
|
71
|
-
|
|
72
|
-
print("====================================================")
|
|
73
|
-
|
|
74
|
-
except Exception as e:
|
|
75
|
-
print(f"\n❌ CRASH DURANTE L'ELABORAZIONE HARDWARE: {str(e)}")
|
|
76
|
-
print("====================================================")
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
import numpy as np
|
|
3
|
-
from dense_evolution import DenseSVSimulator, QASMParser, QuantumTranspiler, NoiseModel
|
|
4
|
-
|
|
5
|
-
print("====================================================")
|
|
6
|
-
print("TEST: KRAUS & JIT SIMULATION")
|
|
7
|
-
print("====================================================")
|
|
8
|
-
|
|
9
|
-
try:
|
|
10
|
-
qasm_bench = """
|
|
11
|
-
OPENQASM 2.0;
|
|
12
|
-
include "qelib1.inc";
|
|
13
|
-
qreg q[6];
|
|
14
|
-
h q[0];
|
|
15
|
-
cx q[0], q[1];
|
|
16
|
-
cx q[1], q[2];
|
|
17
|
-
cx q[2], q[3];
|
|
18
|
-
cx q[3], q[4];
|
|
19
|
-
cx q[4], q[5];
|
|
20
|
-
rx(1.570796) q[0];
|
|
21
|
-
ry(0.785398) q[1];
|
|
22
|
-
rz(0.392699) q[2];
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
print("1. Parsing e Transpilazione del circuito QASM...")
|
|
26
|
-
# Questo testa la corretta importazione e funzione di parser.py e compiler.py
|
|
27
|
-
parser = QASMParser()
|
|
28
|
-
circ = parser.parse(qasm_bench)
|
|
29
|
-
tuples = QuantumTranspiler.transpile(circ.to_tuples())
|
|
30
|
-
n_qubits = circ.n_qubits
|
|
31
|
-
print(f"✓ Parsing completato. Qubit: {n_qubits}, Gate transpilati: {len(tuples)}")
|
|
32
|
-
|
|
33
|
-
print("\n2. Validazione Core JIT in modalità ideale (simulator.py)...")
|
|
34
|
-
t0 = time.perf_counter()
|
|
35
|
-
sim_ideale = DenseSVSimulator(n_qubits)
|
|
36
|
-
sim_ideale.run_circuit_jit_beast_mode(tuples)
|
|
37
|
-
t_ideale = time.perf_counter() - t0
|
|
38
|
-
prob_ideale = sim_ideale.get_probabilities()
|
|
39
|
-
print(f"✓ Successo ideale in {t_ideale:.4f} s | Dimensione stato: {len(prob_ideale)}")
|
|
40
|
-
|
|
41
|
-
print("\n3. Validazione NoiseModel (registry.py): Canale stocastico Amplitude Damping...")
|
|
42
|
-
|
|
43
|
-
# Run Noisy 1
|
|
44
|
-
t0 = time.perf_counter()
|
|
45
|
-
sim_noisy1 = DenseSVSimulator(n_qubits)
|
|
46
|
-
sim_noisy1.run_circuit_jit_beast_mode(tuples)
|
|
47
|
-
# Iniezione diretta del rumore Kraus sullo statevector compilato
|
|
48
|
-
sim_noisy1.sv = NoiseModel.apply_to_sv(sim_noisy1.sv, n_qubits, model='amplitude_damping', p=0.15)
|
|
49
|
-
prob_noisy1 = sim_noisy1.get_probabilities()
|
|
50
|
-
t_noisy1 = time.perf_counter() - t0
|
|
51
|
-
|
|
52
|
-
# Run Noisy 2
|
|
53
|
-
sim_noisy2 = DenseSVSimulator(n_qubits)
|
|
54
|
-
sim_noisy2.run_circuit_jit_beast_mode(tuples)
|
|
55
|
-
sim_noisy2.sv = NoiseModel.apply_to_sv(sim_noisy2.sv, n_qubits, model='amplitude_damping', p=0.15)
|
|
56
|
-
prob_noisy2 = sim_noisy2.get_probabilities()
|
|
57
|
-
|
|
58
|
-
print(f"✓ Successo noisy in {t_noisy1:.4f} s")
|
|
59
|
-
|
|
60
|
-
print("\n4. Analisi statistica delle fluttuazioni (Shot Noise Reale)...")
|
|
61
|
-
scostamento_stocastico = np.linalg.norm(prob_noisy1 - prob_noisy2)
|
|
62
|
-
scostamento_ideale = np.linalg.norm(prob_ideale - prob_noisy1)
|
|
63
|
-
|
|
64
|
-
print(f"🔬 Distanza ideale-noisy: {scostamento_ideale:.6f}")
|
|
65
|
-
print(f"🔬 Fluttuazione quantistica indipendente (Shot Noise): {scostamento_stocastico:.6f}")
|
|
66
|
-
|
|
67
|
-
if scostamento_stocastico > 1e-12:
|
|
68
|
-
print("\n✅ TEST SUPERATO: Moduli collegati, PRNG JAX funzionante e rumore autenticamente non-deterministico!")
|
|
69
|
-
else:
|
|
70
|
-
print("\n❌ FALLIMENTO: Il rumore è ancora lineare o statico. Le due run hanno prodotto stati identici.")
|
|
71
|
-
|
|
72
|
-
print("====================================================")
|
|
73
|
-
|
|
74
|
-
except Exception as e:
|
|
75
|
-
print(f"\n❌ CRASH DURANTE L'ELABORAZIONE HARDWARE: {str(e)}")
|
|
76
|
-
print("====================================================")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dense_evolution-8.1.7 → dense_evolution-8.1.9}/dense_evolution.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|