dense-evolution 8.3.0__py3-none-win_amd64.whl
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.
- dashboard_core/__init__.py +115 -0
- dashboard_core/_gate_tables.py +30 -0
- dashboard_core/band_structure.py +71 -0
- dashboard_core/circuit_builder_component.py +232 -0
- dashboard_core/circuit_diagram.py +216 -0
- dashboard_core/crypto_protocols.py +77 -0
- dashboard_core/engine.py +326 -0
- dashboard_core/graphical_builder.py +114 -0
- dashboard_core/hamiltonians.py +593 -0
- dashboard_core/mass_decomposition_tool.py +47 -0
- dashboard_core/mitigation.py +343 -0
- dashboard_core/native_hf_diagnostics.py +62 -0
- dashboard_core/noise_tools.py +125 -0
- dashboard_core/qasm_library.py +233 -0
- dashboard_core/qmmm.py +16 -0
- dashboard_core/rag_tool.py +45 -0
- dashboard_core/state_visuals.py +288 -0
- dashboard_core/system_limits.py +60 -0
- dashboard_core/vector_healing.py +102 -0
- dashboard_core/visuals.py +158 -0
- dashboard_core/vqe.py +533 -0
- dashboard_core/wormhole.py +580 -0
- dense_evolution/__init__.py +114 -0
- dense_evolution/autodiff.py +10 -0
- dense_evolution/backends/__init__.py +5 -0
- dense_evolution/backends/chunk/__init__.py +37 -0
- dense_evolution/backends/chunk/_engine_imports.py +57 -0
- dense_evolution/backends/chunk/circuit_chunker.py +55 -0
- dense_evolution/backends/chunk/core.py +432 -0
- dense_evolution/backends/chunk/disk_overflow.py +232 -0
- dense_evolution/backends/chunk/geometry.py +95 -0
- dense_evolution/backends/chunk/guard.py +190 -0
- dense_evolution/backends/chunk/kernels.py +531 -0
- dense_evolution/backends/mps.py +1569 -0
- dense_evolution/backends/statevector.py +616 -0
- dense_evolution/chunk.py +25 -0
- dense_evolution/circuits/__init__.py +20 -0
- dense_evolution/circuits/compiler.py +488 -0
- dense_evolution/circuits/diagram.py +94 -0
- dense_evolution/circuits/gates.py +91 -0
- dense_evolution/circuits/parser.py +632 -0
- dense_evolution/circuits/qft.py +66 -0
- dense_evolution/circuits/random_circuit.py +85 -0
- dense_evolution/circuits/registry.py +74 -0
- dense_evolution/circuits/topology.py +79 -0
- dense_evolution/circuits/trotter.py +265 -0
- dense_evolution/circuits/uccsd.py +275 -0
- dense_evolution/cli.py +199 -0
- dense_evolution/compiler.py +9 -0
- dense_evolution/config.py +49 -0
- dense_evolution/drawing.py +10 -0
- dense_evolution/entropy.py +9 -0
- dense_evolution/fermions.py +9 -0
- dense_evolution/gates.py +9 -0
- dense_evolution/harrison_tb.py +16 -0
- dense_evolution/healing.py +18 -0
- dense_evolution/interop/__init__.py +18 -0
- dense_evolution/interop/qiskit_pennylane.py +406 -0
- dense_evolution/measurement.py +10 -0
- dense_evolution/mitigation/__init__.py +54 -0
- dense_evolution/mitigation/healing.py +215 -0
- dense_evolution/mitigation/kl_divergence.py +93 -0
- dense_evolution/mitigation/magic_entropy.py +163 -0
- dense_evolution/mitigation/magic_entropy_shadows.py +262 -0
- dense_evolution/mitigation/renyi.py +168 -0
- dense_evolution/mitigation/stabilizer_renyi_entropy.py +103 -0
- dense_evolution/mitigation/zne.py +990 -0
- dense_evolution/mps.py +9 -0
- dense_evolution/native_hf/__init__.py +26 -0
- dense_evolution/native_hf/_libcint/LICENSE-libcint +10 -0
- dense_evolution/native_hf/_libcint/libdecint.dll +0 -0
- dense_evolution/native_hf/assembly.py +304 -0
- dense_evolution/native_hf/basis.py +117 -0
- dense_evolution/native_hf/boys.py +35 -0
- dense_evolution/native_hf/bridge.py +112 -0
- dense_evolution/native_hf/cartesian.py +64 -0
- dense_evolution/native_hf/coulomb.py +196 -0
- dense_evolution/native_hf/differentiable.py +53 -0
- dense_evolution/native_hf/gaussians.py +79 -0
- dense_evolution/native_hf/kinetic.py +52 -0
- dense_evolution/native_hf/libcint_bridge.py +167 -0
- dense_evolution/native_hf/overlap.py +91 -0
- dense_evolution/native_hf/scf.py +404 -0
- dense_evolution/noise/__init__.py +79 -0
- dense_evolution/noise/coherent_attack.py +264 -0
- dense_evolution/noise/cosmic_ray.py +61 -0
- dense_evolution/noise/density_matrix_channels.py +78 -0
- dense_evolution/noise/differentiable.py +66 -0
- dense_evolution/noise/kraus/__init__.py +6 -0
- dense_evolution/noise/kraus/amplitude_damping.py +47 -0
- dense_evolution/noise/kraus/bitflip.py +22 -0
- dense_evolution/noise/kraus/combined.py +16 -0
- dense_evolution/noise/kraus/depolarizing.py +47 -0
- dense_evolution/noise/kraus/ideal.py +10 -0
- dense_evolution/noise/kraus/phaseflip.py +21 -0
- dense_evolution/noise/kraus_channels.py +285 -0
- dense_evolution/noise/oscillating.py +32 -0
- dense_evolution/noise/pink.py +80 -0
- dense_evolution/observables.py +11 -0
- dense_evolution/parser.py +9 -0
- dense_evolution/physics/__init__.py +27 -0
- dense_evolution/physics/entropy.py +161 -0
- dense_evolution/physics/fermions.py +322 -0
- dense_evolution/physics/observables.py +523 -0
- dense_evolution/physics/qec.py +1113 -0
- dense_evolution/physics/spectral.py +143 -0
- dense_evolution/physics/states.py +43 -0
- dense_evolution/protocols/__init__.py +27 -0
- dense_evolution/protocols/bb84.py +133 -0
- dense_evolution/protocols/di_qkd_ghz.py +199 -0
- dense_evolution/protocols/dicka_protocol2.py +124 -0
- dense_evolution/qec.py +20 -0
- dense_evolution/qft.py +9 -0
- dense_evolution/qmmm/__init__.py +13 -0
- dense_evolution/qmmm/ase_bridge.py +97 -0
- dense_evolution/qmmm/forces.py +388 -0
- dense_evolution/qmmm/propagation.py +80 -0
- dense_evolution/qmmm/region.py +137 -0
- dense_evolution/random_circuit.py +15 -0
- dense_evolution/registry.py +9 -0
- dense_evolution/simulator.py +10 -0
- dense_evolution/solvers/__init__.py +19 -0
- dense_evolution/solvers/autodiff.py +169 -0
- dense_evolution/solvers/harrison_tb.py +189 -0
- dense_evolution/solvers/vhd_tb.py +187 -0
- dense_evolution/states.py +9 -0
- dense_evolution/topology.py +9 -0
- dense_evolution/trotter.py +9 -0
- dense_evolution/utils/__init__.py +13 -0
- dense_evolution/utils/drawing.py +101 -0
- dense_evolution/utils/mass_decomposition.py +246 -0
- dense_evolution/utils/measurement.py +94 -0
- dense_evolution/vhd_tb.py +16 -0
- dense_evolution-8.3.0.dist-info/METADATA +366 -0
- dense_evolution-8.3.0.dist-info/RECORD +165 -0
- dense_evolution-8.3.0.dist-info/WHEEL +5 -0
- dense_evolution-8.3.0.dist-info/entry_points.txt +2 -0
- dense_evolution-8.3.0.dist-info/licenses/license.md +58 -0
- dense_evolution-8.3.0.dist-info/top_level.txt +5 -0
- ia_utils/__init__.py +0 -0
- ia_utils/adversarial_vector_attack.py +196 -0
- ia_utils/rag.py +288 -0
- ia_utils/vector_healing.py +399 -0
- local_site/__init__.py +0 -0
- local_site/app/__init__.py +0 -0
- local_site/app/server.py +1009 -0
- mcp_server/__init__.py +0 -0
- mcp_server/client.py +324 -0
- mcp_server/config.py +32 -0
- mcp_server/models.py +347 -0
- mcp_server/molecules.py +71 -0
- mcp_server/server.py +119 -0
- mcp_server/tools/__init__.py +0 -0
- mcp_server/tools/chemistry_tools.py +225 -0
- mcp_server/tools/circuit_tools.py +83 -0
- mcp_server/tools/crypto_tools.py +66 -0
- mcp_server/tools/mitigation_tools.py +81 -0
- mcp_server/tools/noise_tools.py +60 -0
- mcp_server/tools/retrieval_tools.py +44 -0
- mcp_server/tools/system_tools.py +149 -0
- mcp_server/tools/wormhole_tools.py +142 -0
- mcp_server/utils/__init__.py +0 -0
- mcp_server/utils/cache.py +55 -0
- mcp_server/utils/images.py +67 -0
- mcp_server/utils/truncation.py +38 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Native (PennyLane-free) UCCSD excitation circuits.
|
|
3
|
+
|
|
4
|
+
UCCSD's single/double fermionic excitation generators
|
|
5
|
+
(a_p^dagger a_q - h.c., a_p^dagger a_q^dagger a_r a_s - h.c.) were
|
|
6
|
+
previously only reachable through PennyLane's own FermionicSingleExcitation/
|
|
7
|
+
FermionicDoubleExcitation decomposition (see dashboard/core/vqe.py's
|
|
8
|
+
_uccsd_tape_to_qasm) -- not because a native circuit is theoretically
|
|
9
|
+
impossible, but because deriving the exact (non-Trotterized) circuit
|
|
10
|
+
identity requires real derivation, not just wiring PennyLane through.
|
|
11
|
+
|
|
12
|
+
This module IS that derivation, done directly against
|
|
13
|
+
dense_evolution.physics.fermions.majorana_pauli_terms (already-verified
|
|
14
|
+
Jordan-Wigner mapping) rather than against PennyLane's internals, and
|
|
15
|
+
every circuit identity below was verified against scipy.linalg.expm of
|
|
16
|
+
the exact generator matrix (independently reconstructed from raw
|
|
17
|
+
Jordan-Wigner ladder operators, not from PennyLane) before being written
|
|
18
|
+
here -- see tests/unit/test_uccsd.py.
|
|
19
|
+
|
|
20
|
+
Single excitation (any orbital distance): exact closed form, always.
|
|
21
|
+
G_pq = a_p^dagger a_q - a_q^dagger a_p decomposes (via
|
|
22
|
+
a_p^dagger=(chi_X(p)-i*chi_Y(p))/2) into exactly 2 Pauli strings that
|
|
23
|
+
share the Jordan-Wigner Z-string between p and q and differ only by an
|
|
24
|
+
X<->Y swap at p and q. This is the standard "Givens rotation" generator
|
|
25
|
+
(G^2 = 2I): exact circuit is CNOT(p,q), fold each Z-string qubit's
|
|
26
|
+
parity onto p via CNOT(k,p), CRY(2*theta, control=q, target=p), then
|
|
27
|
+
undo. Verified for adjacent and long-Z-string pairs alike (any p<q).
|
|
28
|
+
|
|
29
|
+
Double excitation: exact closed form when the occupied pair (p,q) is
|
|
30
|
+
adjacent (q=p+1) AND the virtual pair (r,s) is adjacent (s=r+1) -- the
|
|
31
|
+
gap between q and r (HOMO-LUMO gap) can be any length, no restriction.
|
|
32
|
+
This is the case dashboard/core/vqe.py's UCCSD ansatz always produces
|
|
33
|
+
for a 2-occupied/2-virtual active space (e.g. H2 in a minimal basis),
|
|
34
|
+
and generally whenever qml.qchem.excitations pairs consecutive occupied
|
|
35
|
+
orbitals with consecutive virtual orbitals. G_pqrs (8 Pauli terms)
|
|
36
|
+
reduces to a clean 2-level coupling between |p=0,q=1,r=1,s=1,...> and
|
|
37
|
+
its bit-flip, realized via a CNOT fan (mirroring the p,q,r,s pattern
|
|
38
|
+
onto q) plus a triple-controlled RY (Toffoli-mediated, 2 ancilla
|
|
39
|
+
qubits, always returned to |0>).
|
|
40
|
+
|
|
41
|
+
For a double excitation where the occupied pair or the virtual pair is
|
|
42
|
+
itself non-adjacent (occurs for active spaces with 3+ occupied or 3+
|
|
43
|
+
virtual orbitals, e.g. LiH/BeH2), the same closed-form Z-string folding
|
|
44
|
+
used for single excitations does NOT carry over cleanly (verified
|
|
45
|
+
directly: the naive fold leaves genuine leakage, not just an
|
|
46
|
+
unsimplified-but-correct circuit) -- deriving a comparably compact
|
|
47
|
+
closed form for that case is unresolved, so double_excitation_ops falls
|
|
48
|
+
back to per-term exponentiation of the 8 Pauli terms via
|
|
49
|
+
dense_evolution.circuits.trotter.pauli_rotation_ops for that specific
|
|
50
|
+
case, applied sequentially in a fixed term order.
|
|
51
|
+
|
|
52
|
+
That fallback turned out to be exact too, not a Trotter approximation:
|
|
53
|
+
verified exhaustively (every computational basis state, several p<q<r<s
|
|
54
|
+
choices including non-adjacent pairs, theta up to pi) against
|
|
55
|
+
scipy.linalg.expm of the exact generator matrix, to floating-point
|
|
56
|
+
precision (~1e-15) at every theta tested, not just small theta the way
|
|
57
|
+
a genuine first-order Trotter error would show. The 8 terms don't
|
|
58
|
+
commute as operators on the full Hilbert space, but the generator only
|
|
59
|
+
ever couples two basis states for any fixed setting of the qubits it
|
|
60
|
+
doesn't act on (same structure as the closed-form case), and within
|
|
61
|
+
that 2-dimensional invariant subspace the per-term exponentials
|
|
62
|
+
apparently compose without error -- not derived from first principles
|
|
63
|
+
here, just confirmed by the exhaustive check above. Only the GATE COUNT
|
|
64
|
+
differs from the closed form, not correctness.
|
|
65
|
+
"""
|
|
66
|
+
from typing import List, Tuple
|
|
67
|
+
|
|
68
|
+
from .trotter import pauli_rotation_ops
|
|
69
|
+
|
|
70
|
+
__all__ = ['find_excitations', 'single_excitation_ops', 'double_excitation_ops']
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def find_excitations(electrons: int, n_qubits: int):
|
|
74
|
+
"""
|
|
75
|
+
Enumerate spin-conserving single/double excitation index tuples for
|
|
76
|
+
a Hartree-Fock reference with the given electron count -- pure
|
|
77
|
+
classical combinatorics (occupied = orbitals [0, electrons), virtual
|
|
78
|
+
= the rest, even index = spin-up, odd = spin-down under the standard
|
|
79
|
+
Jordan-Wigner interleaved spin-orbital ordering), no quantum
|
|
80
|
+
computation involved. Verified to reproduce
|
|
81
|
+
qml.qchem.excitations(electrons, n_qubits) exactly across several
|
|
82
|
+
(electrons, n_qubits) pairs -- see tests/unit/test_uccsd.py -- kept
|
|
83
|
+
here so finding *which* excitations exist doesn't need PennyLane
|
|
84
|
+
installed any more than building their circuits does.
|
|
85
|
+
|
|
86
|
+
Returns (singles, doubles): singles is a list of [p, q] (p occupied,
|
|
87
|
+
q virtual, same spin); doubles is a list of [p, q, r, s] with
|
|
88
|
+
p<q both occupied, r<s both virtual, total spin conserved.
|
|
89
|
+
"""
|
|
90
|
+
occupied = list(range(electrons))
|
|
91
|
+
virtual = list(range(electrons, n_qubits))
|
|
92
|
+
singles = [[p, q] for p in occupied for q in virtual if p % 2 == q % 2]
|
|
93
|
+
doubles = []
|
|
94
|
+
for i, p in enumerate(occupied):
|
|
95
|
+
for q in occupied[i + 1:]:
|
|
96
|
+
for j, r in enumerate(virtual):
|
|
97
|
+
for s in virtual[j + 1:]:
|
|
98
|
+
if (p % 2 + q % 2) == (r % 2 + s % 2):
|
|
99
|
+
doubles.append([p, q, r, s])
|
|
100
|
+
return singles, doubles
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# ── Pauli-string algebra (needed only for the per-term fallback path's
|
|
104
|
+
# generator decomposition -- the closed-form circuits below are pure
|
|
105
|
+
# combinatorial gate templates and never call this at all) ──────────────
|
|
106
|
+
|
|
107
|
+
_MUL = {
|
|
108
|
+
('I', 'I'): ('I', 1), ('I', 'X'): ('X', 1), ('I', 'Y'): ('Y', 1), ('I', 'Z'): ('Z', 1),
|
|
109
|
+
('X', 'I'): ('X', 1), ('Y', 'I'): ('Y', 1), ('Z', 'I'): ('Z', 1),
|
|
110
|
+
('X', 'X'): ('I', 1), ('Y', 'Y'): ('I', 1), ('Z', 'Z'): ('I', 1),
|
|
111
|
+
('X', 'Y'): ('Z', 1j), ('Y', 'X'): ('Z', -1j),
|
|
112
|
+
('Y', 'Z'): ('X', 1j), ('Z', 'Y'): ('X', -1j),
|
|
113
|
+
('Z', 'X'): ('Y', 1j), ('X', 'Z'): ('Y', -1j),
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _pauli_mul_term(term_a, term_b):
|
|
118
|
+
ca, da = term_a
|
|
119
|
+
cb, db = term_b
|
|
120
|
+
phase = ca * cb
|
|
121
|
+
out = {}
|
|
122
|
+
for q in set(da) | set(db):
|
|
123
|
+
la, lb = da.get(q, 'I'), db.get(q, 'I')
|
|
124
|
+
letter, ph = _MUL[(la, lb)]
|
|
125
|
+
phase *= ph
|
|
126
|
+
if letter != 'I':
|
|
127
|
+
out[q] = letter
|
|
128
|
+
return (phase, out)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _psum_mul(terms_a, terms_b):
|
|
132
|
+
return [_pauli_mul_term(ta, tb) for ta in terms_a for tb in terms_b]
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _psum_scale(terms, s):
|
|
136
|
+
return [(c * s, d) for c, d in terms]
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _psum_combine(terms):
|
|
140
|
+
acc = {}
|
|
141
|
+
for c, d in terms:
|
|
142
|
+
key = tuple(sorted(d.items()))
|
|
143
|
+
acc[key] = acc.get(key, 0) + c
|
|
144
|
+
return [(c, dict(key)) for key, c in acc.items() if abs(c) > 1e-12]
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _chi(mode_index, n_qubits):
|
|
148
|
+
from ..physics.fermions import majorana_pauli_terms
|
|
149
|
+
return majorana_pauli_terms(mode_index, n_qubits)[1]
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _a_dagger(p, n_qubits):
|
|
153
|
+
return [(0.5, _chi(2 * p + 1, n_qubits)), (-0.5j, _chi(2 * p + 2, n_qubits))]
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _a(p, n_qubits):
|
|
157
|
+
return [(0.5, _chi(2 * p + 1, n_qubits)), (0.5j, _chi(2 * p + 2, n_qubits))]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _double_excitation_generator(p, q, r, s, n_qubits):
|
|
161
|
+
"""8 Pauli terms of a_p^dagger a_q^dagger a_r a_s - h.c. (JW-mapped).
|
|
162
|
+
Used only by the per-term fallback path -- verified against direct
|
|
163
|
+
fermionic ladder operators in tests/unit/test_uccsd.py."""
|
|
164
|
+
term1 = _psum_mul(_psum_mul(_a_dagger(p, n_qubits), _a_dagger(q, n_qubits)),
|
|
165
|
+
_psum_mul(_a(r, n_qubits), _a(s, n_qubits)))
|
|
166
|
+
term2 = _psum_mul(_psum_mul(_a_dagger(s, n_qubits), _a_dagger(r, n_qubits)),
|
|
167
|
+
_psum_mul(_a(q, n_qubits), _a(p, n_qubits)))
|
|
168
|
+
return _psum_combine(term1 + _psum_scale(term2, -1))
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# ── Single excitation: exact closed form, any p<q ───────────────────────
|
|
172
|
+
|
|
173
|
+
def single_excitation_ops(p: int, q: int, theta: float) -> List[Tuple]:
|
|
174
|
+
"""
|
|
175
|
+
Exact circuit for exp(theta * (a_p^dagger a_q - a_q^dagger a_p)),
|
|
176
|
+
the UCCS single-excitation unitary, for ANY p < q (any Jordan-Wigner
|
|
177
|
+
Z-string length in between) -- no Trotter error, ever.
|
|
178
|
+
|
|
179
|
+
Gate count: 2*(1 + (q-p-1)) CX + 1 CRY (itself 2 CX + 2 RY), so
|
|
180
|
+
2*(q-p) + 2 CX total.
|
|
181
|
+
"""
|
|
182
|
+
if not p < q:
|
|
183
|
+
raise ValueError(f"single_excitation_ops requires p < q, got p={p}, q={q}")
|
|
184
|
+
inter = list(range(p + 1, q))
|
|
185
|
+
ops: List[Tuple] = []
|
|
186
|
+
ops.append(('cx', p, q))
|
|
187
|
+
for k in inter:
|
|
188
|
+
ops.append(('cx', k, p))
|
|
189
|
+
ops.extend(_cry_ops(2 * theta, control=q, target=p))
|
|
190
|
+
for k in reversed(inter):
|
|
191
|
+
ops.append(('cx', k, p))
|
|
192
|
+
ops.append(('cx', p, q))
|
|
193
|
+
return ops
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _cry_ops(theta, control, target):
|
|
197
|
+
"""CRY(theta) from native RY+CX: RY(theta/2)_t ; CX(c,t) ; RY(-theta/2)_t ; CX(c,t)."""
|
|
198
|
+
return [
|
|
199
|
+
('ry', target, theta / 2),
|
|
200
|
+
('cx', control, target),
|
|
201
|
+
('ry', target, -theta / 2),
|
|
202
|
+
('cx', control, target),
|
|
203
|
+
]
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
# ── Double excitation ────────────────────────────────────────────────────
|
|
207
|
+
|
|
208
|
+
def double_excitation_ops(p: int, q: int, r: int, s: int, theta: float,
|
|
209
|
+
ancilla1: int = None, ancilla2: int = None) -> List[Tuple]:
|
|
210
|
+
"""
|
|
211
|
+
Circuit for exp(theta * (a_p^dagger a_q^dagger a_r a_s - h.c.)), the
|
|
212
|
+
UCCD double-excitation unitary, for p < q < r < s.
|
|
213
|
+
|
|
214
|
+
Exact closed form (no Trotter error) when ancilla1/ancilla2 are both
|
|
215
|
+
given AND the occupied pair is adjacent (q == p+1) AND the virtual
|
|
216
|
+
pair is adjacent (s == r+1) -- the gap between q and r can be any
|
|
217
|
+
length. This is what qml.qchem.excitations always produces for a
|
|
218
|
+
2-occupied/2-virtual active space, and sometimes for larger ones.
|
|
219
|
+
|
|
220
|
+
Falls back to per-term exponentiation of the 8-term Pauli
|
|
221
|
+
decomposition whenever no ancillas are given, or the pairs aren't
|
|
222
|
+
adjacent -- verified exact (not an approximation), just more gates
|
|
223
|
+
than the closed form; see the module docstring for why the closed
|
|
224
|
+
form doesn't generalize to a non-adjacent occupied or virtual pair
|
|
225
|
+
yet.
|
|
226
|
+
|
|
227
|
+
ancilla1, ancilla2 : two qubits that MUST be |0> on entry and are
|
|
228
|
+
guaranteed returned to |0> on exit -- only touched by the
|
|
229
|
+
closed-form path (never referenced by the per-term fallback), so
|
|
230
|
+
the same two ancillas can be reused across every double excitation
|
|
231
|
+
in an ansatz. Omit both (leave as None) to force the ancilla-free
|
|
232
|
+
per-term path unconditionally -- e.g. when the caller's qubit
|
|
233
|
+
register has no spare qubits to offer.
|
|
234
|
+
"""
|
|
235
|
+
if not p < q < r < s:
|
|
236
|
+
raise ValueError(f"double_excitation_ops requires p<q<r<s, got {p},{q},{r},{s}")
|
|
237
|
+
|
|
238
|
+
have_ancillas = ancilla1 is not None and ancilla2 is not None
|
|
239
|
+
if have_ancillas and q == p + 1 and s == r + 1:
|
|
240
|
+
return _double_excitation_ops_closed_form(p, q, r, s, theta, ancilla1, ancilla2)
|
|
241
|
+
return _double_excitation_ops_per_term(p, q, r, s, theta)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def _double_excitation_ops_closed_form(p, q, r, s, theta, a1, a2) -> List[Tuple]:
|
|
245
|
+
ops: List[Tuple] = []
|
|
246
|
+
ops.append(('cx', q, s))
|
|
247
|
+
ops.append(('cx', q, r))
|
|
248
|
+
ops.append(('cx', q, p))
|
|
249
|
+
ops.append(('x', p))
|
|
250
|
+
ops.extend(_toffoli_ops(p, r, a1))
|
|
251
|
+
ops.extend(_toffoli_ops(a1, s, a2))
|
|
252
|
+
ops.extend(_cry_ops(-2 * theta, control=a2, target=q))
|
|
253
|
+
ops.extend(_toffoli_ops(a1, s, a2))
|
|
254
|
+
ops.extend(_toffoli_ops(p, r, a1))
|
|
255
|
+
ops.append(('x', p))
|
|
256
|
+
ops.append(('cx', q, p))
|
|
257
|
+
ops.append(('cx', q, r))
|
|
258
|
+
ops.append(('cx', q, s))
|
|
259
|
+
return ops
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _toffoli_ops(c1, c2, t):
|
|
263
|
+
from .compiler import QuantumTranspiler
|
|
264
|
+
return QuantumTranspiler.decompose_toffoli(c1, c2, t)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _double_excitation_ops_per_term(p, q, r, s, theta) -> List[Tuple]:
|
|
268
|
+
n_qubits = s + 1
|
|
269
|
+
terms = _double_excitation_generator(p, q, r, s, n_qubits)
|
|
270
|
+
ops: List[Tuple] = []
|
|
271
|
+
for coeff, pauli_dict in terms:
|
|
272
|
+
real_part = (coeff / 1j).real
|
|
273
|
+
angle = -theta * real_part
|
|
274
|
+
ops.extend(pauli_rotation_ops(pauli_dict, angle))
|
|
275
|
+
return ops
|
dense_evolution/cli.py
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`dense-evolution` console script (see pyproject.toml [project.scripts]).
|
|
3
|
+
|
|
4
|
+
Three real subcommands:
|
|
5
|
+
serve starts the local Composer kernel (local_site.app.server)
|
|
6
|
+
that the published Composer page (docs/composer.md)
|
|
7
|
+
talks to.
|
|
8
|
+
offline-composer downloads the real published Composer page (the same
|
|
9
|
+
HTML Github Pages serves, not a hand-rolled copy) plus
|
|
10
|
+
the same-origin assets it references, into a local
|
|
11
|
+
folder -- so it opens via file:// with no internet at
|
|
12
|
+
all, while still talking to the local kernel above.
|
|
13
|
+
mcp starts the dense_evolution_mcp MCP server (mcp_server/),
|
|
14
|
+
a thin adapter that exposes the same Composer kernel
|
|
15
|
+
endpoints as MCP tools for an agent to call directly.
|
|
16
|
+
Requires `serve` running separately -- this process
|
|
17
|
+
talks to that kernel over HTTP, it doesn't embed it.
|
|
18
|
+
|
|
19
|
+
fastapi/uvicorn/pydantic (composer) and mcp/httpx (mcp) are optional
|
|
20
|
+
extras, not core dependencies -- imported here, inside their own command
|
|
21
|
+
branch, not at module level, so `import dense_evolution` itself never
|
|
22
|
+
requires them.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import sys
|
|
26
|
+
|
|
27
|
+
USAGE = """usage: dense-evolution <command>
|
|
28
|
+
|
|
29
|
+
commands:
|
|
30
|
+
serve Start the local Composer kernel (http://127.0.0.1:8800)
|
|
31
|
+
that the published Composer page (docs/composer.md)
|
|
32
|
+
connects to.
|
|
33
|
+
offline-composer [DEST] Download the real published Composer page and its
|
|
34
|
+
assets into DEST (default: ./composer-offline) so
|
|
35
|
+
it works via file:// with no internet.
|
|
36
|
+
mcp Start the dense_evolution_mcp MCP server (stdio
|
|
37
|
+
transport) so an agent can call the Composer
|
|
38
|
+
kernel's endpoints directly. Requires `serve`
|
|
39
|
+
running separately (default http://127.0.0.1:8800,
|
|
40
|
+
override with DENSE_EVOLUTION_KERNEL_URL).
|
|
41
|
+
|
|
42
|
+
Requires the composer extra: pip install dense-evolution[composer]
|
|
43
|
+
The mcp command requires the mcp extra: pip install dense-evolution[mcp]
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
COMPOSER_PAGE_URL = "https://tatopenn-cell.github.io/Dense-Evolution/composer/"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _require_composer_extra():
|
|
50
|
+
try:
|
|
51
|
+
import fastapi, uvicorn, pydantic # noqa: F401
|
|
52
|
+
except ImportError as exc:
|
|
53
|
+
print(
|
|
54
|
+
"dense-evolution needs the composer extra:\n"
|
|
55
|
+
" pip install dense-evolution[composer]\n"
|
|
56
|
+
f"(missing: {exc.name})",
|
|
57
|
+
file=sys.stderr,
|
|
58
|
+
)
|
|
59
|
+
sys.exit(1)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _cmd_serve():
|
|
63
|
+
_require_composer_extra()
|
|
64
|
+
from local_site.app.server import main as serve_main
|
|
65
|
+
serve_main()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _require_mcp_extra():
|
|
69
|
+
try:
|
|
70
|
+
import mcp, httpx # noqa: F401
|
|
71
|
+
except ImportError as exc:
|
|
72
|
+
print(
|
|
73
|
+
"dense-evolution needs the mcp extra:\n"
|
|
74
|
+
" pip install dense-evolution[mcp]\n"
|
|
75
|
+
f"(missing: {exc.name})",
|
|
76
|
+
file=sys.stderr,
|
|
77
|
+
)
|
|
78
|
+
sys.exit(1)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _cmd_mcp():
|
|
82
|
+
_require_mcp_extra()
|
|
83
|
+
from mcp_server.server import main as mcp_main
|
|
84
|
+
mcp_main()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _cmd_offline_composer(dest: str):
|
|
88
|
+
"""Mirrors COMPOSER_PAGE_URL into `dest`: the page itself plus every
|
|
89
|
+
same-origin <link href>/<script src> it references (Material's shared
|
|
90
|
+
theme CSS/JS bundle, the Composer-specific app.js/style.css), each
|
|
91
|
+
saved at the same relative path it already uses on the live site --
|
|
92
|
+
mkdocs/Material already generate those as page-relative, precisely so
|
|
93
|
+
a subtree like this stays self-consistent once copied elsewhere. Not a
|
|
94
|
+
full recursive mirror (fonts referenced only from inside a CSS url()
|
|
95
|
+
are not followed -- Material falls back to system fonts without them,
|
|
96
|
+
a cosmetic gap, not a functional one): scoped to what the page's own
|
|
97
|
+
<head>/<body> actually link to, which is everything the Composer UI
|
|
98
|
+
itself needs to run."""
|
|
99
|
+
import os
|
|
100
|
+
import urllib.request
|
|
101
|
+
from html.parser import HTMLParser
|
|
102
|
+
from urllib.parse import urljoin, urlparse
|
|
103
|
+
|
|
104
|
+
class _AssetFinder(HTMLParser):
|
|
105
|
+
def __init__(self):
|
|
106
|
+
super().__init__()
|
|
107
|
+
self.assets = []
|
|
108
|
+
|
|
109
|
+
def handle_starttag(self, tag, attrs):
|
|
110
|
+
attrs = dict(attrs)
|
|
111
|
+
# mkdocs Material's <head> has plenty of other <link> rels
|
|
112
|
+
# (canonical, prev, next, preconnect, ...) that point at other
|
|
113
|
+
# *pages* (directories, not files) or aren't fetchable assets
|
|
114
|
+
# at all -- verified directly against the real page: following
|
|
115
|
+
# rel="prev"/"next" tried to write a file at a directory-shaped
|
|
116
|
+
# path and failed with a permission error. Only stylesheet/icon
|
|
117
|
+
# links are real same-origin files worth mirroring.
|
|
118
|
+
if tag == "link" and attrs.get("href") and attrs.get("rel") in ("stylesheet", "icon"):
|
|
119
|
+
self.assets.append(attrs["href"])
|
|
120
|
+
elif tag == "script" and attrs.get("src"):
|
|
121
|
+
self.assets.append(attrs["src"])
|
|
122
|
+
elif tag == "img" and attrs.get("src"):
|
|
123
|
+
self.assets.append(attrs["src"])
|
|
124
|
+
|
|
125
|
+
print(f"Scarico {COMPOSER_PAGE_URL} ...")
|
|
126
|
+
with urllib.request.urlopen(COMPOSER_PAGE_URL, timeout=30) as resp:
|
|
127
|
+
html_bytes = resp.read()
|
|
128
|
+
html_text = html_bytes.decode("utf-8", errors="replace")
|
|
129
|
+
|
|
130
|
+
parser = _AssetFinder()
|
|
131
|
+
parser.feed(html_text)
|
|
132
|
+
|
|
133
|
+
page_url = urlparse(COMPOSER_PAGE_URL)
|
|
134
|
+
base_origin = f"{page_url.scheme}://{page_url.netloc}"
|
|
135
|
+
# mkdocs generates every relative link (../assets/...) relative to the
|
|
136
|
+
# SITE root, not to whatever folder happens to hold index.html -- so
|
|
137
|
+
# the page itself has to be saved at the same depth under `dest` it
|
|
138
|
+
# already has under the site root (site_root_path stripped from its
|
|
139
|
+
# own path leaves "composer/"), or its own "../assets/..." references
|
|
140
|
+
# end up pointing one directory above `dest` instead of inside it.
|
|
141
|
+
# site_root_path is derived from COMPOSER_PAGE_URL itself (this
|
|
142
|
+
# project's one fixed, known URL), not guessed from each asset URL.
|
|
143
|
+
site_root_path = page_url.path.rsplit("composer/", 1)[0]
|
|
144
|
+
|
|
145
|
+
def _relative_to_site_root(url: str) -> str:
|
|
146
|
+
path = urlparse(url).path
|
|
147
|
+
if path.startswith(site_root_path):
|
|
148
|
+
path = path[len(site_root_path):]
|
|
149
|
+
return path.lstrip("/")
|
|
150
|
+
|
|
151
|
+
os.makedirs(dest, exist_ok=True)
|
|
152
|
+
page_relative_path = _relative_to_site_root(COMPOSER_PAGE_URL) + "index.html"
|
|
153
|
+
page_local_path = os.path.join(dest, page_relative_path)
|
|
154
|
+
os.makedirs(os.path.dirname(page_local_path), exist_ok=True)
|
|
155
|
+
with open(page_local_path, "w", encoding="utf-8") as f:
|
|
156
|
+
f.write(html_text)
|
|
157
|
+
|
|
158
|
+
seen = set()
|
|
159
|
+
for href in parser.assets:
|
|
160
|
+
absolute_url = urljoin(COMPOSER_PAGE_URL, href)
|
|
161
|
+
if not absolute_url.startswith(base_origin) or absolute_url in seen:
|
|
162
|
+
continue # a genuinely external resource (e.g. a CDN) -- not ours to mirror
|
|
163
|
+
seen.add(absolute_url)
|
|
164
|
+
|
|
165
|
+
relative_path = _relative_to_site_root(absolute_url)
|
|
166
|
+
local_path = os.path.join(dest, relative_path)
|
|
167
|
+
os.makedirs(os.path.dirname(local_path), exist_ok=True)
|
|
168
|
+
try:
|
|
169
|
+
with urllib.request.urlopen(absolute_url, timeout=30) as resp:
|
|
170
|
+
data = resp.read()
|
|
171
|
+
with open(local_path, "wb") as f:
|
|
172
|
+
f.write(data)
|
|
173
|
+
print(f" scaricato: {relative_path}")
|
|
174
|
+
except Exception as exc:
|
|
175
|
+
print(f" saltato (non essenziale): {relative_path} ({exc})")
|
|
176
|
+
|
|
177
|
+
print(f"\nCopia offline pronta: {page_local_path}")
|
|
178
|
+
return page_local_path
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def main(argv=None):
|
|
182
|
+
args = argv if argv is not None else sys.argv[1:]
|
|
183
|
+
if args == ["serve"]:
|
|
184
|
+
_cmd_serve()
|
|
185
|
+
return
|
|
186
|
+
if args and args[0] == "offline-composer":
|
|
187
|
+
dest = args[1] if len(args) > 1 else "composer-offline"
|
|
188
|
+
_cmd_offline_composer(dest)
|
|
189
|
+
return
|
|
190
|
+
if args == ["mcp"]:
|
|
191
|
+
_cmd_mcp()
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
print(USAGE, file=sys.stderr if args else sys.stdout)
|
|
195
|
+
sys.exit(1 if args else 0)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
if __name__ == "__main__":
|
|
199
|
+
main()
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Backward-compatibility shim -- the real implementation moved to
|
|
2
|
+
dense_evolution.circuits.compiler as part of the Phase 2 subpackage split
|
|
3
|
+
(see prog.txt). Kept so `from dense_evolution.compiler import QuantumTranspiler`
|
|
4
|
+
(used by external consumers, e.g. Dense-Evolution-Discovery) keeps working
|
|
5
|
+
unchanged. Import from dense_evolution.circuits.compiler directly in new code.
|
|
6
|
+
"""
|
|
7
|
+
from dense_evolution.circuits.compiler import QuantumTranspiler
|
|
8
|
+
|
|
9
|
+
__all__ = ['QuantumTranspiler']
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Centralized JAX precision control for dense_evolution.
|
|
3
|
+
|
|
4
|
+
jax_enable_x64 is a process-wide JAX flag: once set, it affects every
|
|
5
|
+
JAX array in the process, not just dense_evolution's own. Before this
|
|
6
|
+
module existed, registry.py, compiler.py and statevector.py each called
|
|
7
|
+
jax.config.update("jax_enable_x64", True) unconditionally at MODULE
|
|
8
|
+
IMPORT time -- so merely `import dense_evolution`, even without ever
|
|
9
|
+
constructing a simulator, silently overrode a precision a caller had
|
|
10
|
+
already configured for unrelated JAX code running earlier in the same
|
|
11
|
+
process. mps.py and chunk.py never did this; their own docstrings
|
|
12
|
+
already documented the intended convention (see mps.py): dense_evolution
|
|
13
|
+
enables x64 lazily, only when something that actually needs complex128
|
|
14
|
+
precision is used, not as an import-time side effect.
|
|
15
|
+
|
|
16
|
+
This module is that single point. ensure_x64() is idempotent and safe
|
|
17
|
+
to call from every float64 entry point (DenseSVSimulator.__init__,
|
|
18
|
+
QuantumHardwareRegistry.__init__, circuit_to_energy_fn); set_precision()
|
|
19
|
+
is the public opt-out for a caller who wants to choose precision
|
|
20
|
+
explicitly, before constructing anything, and have that choice stick.
|
|
21
|
+
"""
|
|
22
|
+
import jax
|
|
23
|
+
|
|
24
|
+
_explicit = False
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def set_precision(float64: bool = True) -> None:
|
|
28
|
+
"""
|
|
29
|
+
Explicitly configure JAX's process-wide numeric precision.
|
|
30
|
+
|
|
31
|
+
Call this yourself, before constructing anything, if you need
|
|
32
|
+
control over exactly when/whether dense_evolution enables x64 --
|
|
33
|
+
for example because another float32-only JAX library must be
|
|
34
|
+
initialized first. Once called, dense_evolution's own lazy
|
|
35
|
+
ensure_x64() (used internally by DenseSVSimulator, etc.) no longer
|
|
36
|
+
forces float64 back on, so an explicit set_precision(False) sticks.
|
|
37
|
+
"""
|
|
38
|
+
global _explicit
|
|
39
|
+
jax.config.update("jax_enable_x64", float64)
|
|
40
|
+
_explicit = True
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def ensure_x64() -> None:
|
|
44
|
+
"""Enable jax_enable_x64 unless a caller has already explicitly
|
|
45
|
+
configured precision via set_precision(). Called internally,
|
|
46
|
+
lazily, by dense_evolution components that need complex128
|
|
47
|
+
precision -- never at import time."""
|
|
48
|
+
if not _explicit:
|
|
49
|
+
jax.config.update("jax_enable_x64", True)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Backward-compatibility shim -- the real implementation moved to
|
|
2
|
+
dense_evolution.utils.drawing as part of the Phase 2 subpackage split
|
|
3
|
+
(see prog.txt). Kept so `from dense_evolution.drawing import draw_circuit`
|
|
4
|
+
(used by external consumers, e.g. Dense-Evolution-Discovery) keeps working
|
|
5
|
+
unchanged. Import from dense_evolution.utils.drawing directly in new code.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dense_evolution.utils.drawing import draw_circuit
|
|
9
|
+
|
|
10
|
+
__all__ = ["draw_circuit"]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Backward-compatibility shim -- the real implementation moved to
|
|
2
|
+
dense_evolution.physics.entropy as part of the Phase 2 subpackage split
|
|
3
|
+
(see prog.txt). Kept so `from dense_evolution.entropy import partial_trace, von_neumann_entropy, mutual_information`
|
|
4
|
+
(used by external consumers, e.g. Dense-Evolution-Discovery) keeps working
|
|
5
|
+
unchanged. Import from dense_evolution.physics.entropy directly in new code.
|
|
6
|
+
"""
|
|
7
|
+
from dense_evolution.physics.entropy import partial_trace, von_neumann_entropy, mutual_information, central_charge
|
|
8
|
+
|
|
9
|
+
__all__ = ['partial_trace', 'von_neumann_entropy', 'mutual_information', 'central_charge']
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Backward-compatibility shim -- the real implementation moved to
|
|
2
|
+
dense_evolution.physics.fermions as part of the Phase 2 subpackage split
|
|
3
|
+
(see prog.txt). Kept so `from dense_evolution.fermions import majorana_pauli_terms`
|
|
4
|
+
(used by external consumers, e.g. Dense-Evolution-Discovery) keeps working
|
|
5
|
+
unchanged. Import from dense_evolution.physics.fermions directly in new code.
|
|
6
|
+
"""
|
|
7
|
+
from dense_evolution.physics.fermions import majorana_pauli_terms
|
|
8
|
+
|
|
9
|
+
__all__ = ['majorana_pauli_terms']
|
dense_evolution/gates.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Backward-compatibility shim -- the real implementation moved to
|
|
2
|
+
dense_evolution.circuits.gates as part of the Phase 2 subpackage split
|
|
3
|
+
(see prog.txt). Kept so `from dense_evolution.gates import GATES`
|
|
4
|
+
(used by external consumers, e.g. Dense-Evolution-Discovery) keeps working
|
|
5
|
+
unchanged. Import from dense_evolution.circuits.gates directly in new code.
|
|
6
|
+
"""
|
|
7
|
+
from dense_evolution.circuits.gates import GATES, PARAMETRIC_GATES, GATE_IDS
|
|
8
|
+
|
|
9
|
+
__all__ = ['GATES', 'PARAMETRIC_GATES', 'GATE_IDS']
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Backward-compatibility shim -- the real implementation moved to
|
|
2
|
+
dense_evolution.solvers.harrison_tb as part of the Phase 2 subpackage
|
|
3
|
+
split (see prog.txt). Kept so `from dense_evolution.harrison_tb import
|
|
4
|
+
zincblende_hamiltonian` (used by external consumers, e.g.
|
|
5
|
+
Dense-Evolution-Discovery) keeps working unchanged. Import from
|
|
6
|
+
dense_evolution.solvers.harrison_tb directly in new code.
|
|
7
|
+
"""
|
|
8
|
+
from dense_evolution.solvers.harrison_tb import (
|
|
9
|
+
ELEMENTS, ETA, HBAR2_OVER_M_EV_ANG2,
|
|
10
|
+
hopping_integral, sp3_bond_block, sp3_dimer_hamiltonian, zincblende_hamiltonian,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"ELEMENTS", "ETA", "HBAR2_OVER_M_EV_ANG2",
|
|
15
|
+
"hopping_integral", "sp3_bond_block", "sp3_dimer_hamiltonian", "zincblende_hamiltonian",
|
|
16
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Backward-compatibility shim -- the real implementation moved to
|
|
2
|
+
dense_evolution.mitigation.healing as part of the Phase 2 subpackage
|
|
3
|
+
split (see prog.txt). Kept so `from dense_evolution.healing import
|
|
4
|
+
calculate_phi_ab` (used by external consumers, e.g. tools/ia_utils and
|
|
5
|
+
Dense-Evolution-Discovery) keeps working unchanged. Import from
|
|
6
|
+
dense_evolution.mitigation.healing directly in new code.
|
|
7
|
+
"""
|
|
8
|
+
from dense_evolution.mitigation.healing import (
|
|
9
|
+
calculate_advanced_sigma, calculate_phi_ab, calculate_vettore_dinamico,
|
|
10
|
+
calculate_vettore_statico, calculate_delta_preemp, evaluate_phi_trigger,
|
|
11
|
+
calculate_jax_reflection, MemoryReflectionEngine, GLOBAL_CONSTANTS,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"calculate_advanced_sigma", "calculate_phi_ab", "calculate_vettore_dinamico",
|
|
16
|
+
"calculate_vettore_statico", "calculate_delta_preemp", "evaluate_phi_trigger",
|
|
17
|
+
"calculate_jax_reflection", "MemoryReflectionEngine", "GLOBAL_CONSTANTS",
|
|
18
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Interop subpackage: bridges to Qiskit and PennyLane circuits/backends."""
|
|
2
|
+
from .qiskit_pennylane import (
|
|
3
|
+
from_qiskit,
|
|
4
|
+
from_pennylane,
|
|
5
|
+
run_qiskit_circuit,
|
|
6
|
+
run_pennylane_circuit,
|
|
7
|
+
noise_model_from_qiskit_backend,
|
|
8
|
+
to_stim,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"from_qiskit",
|
|
13
|
+
"from_pennylane",
|
|
14
|
+
"run_qiskit_circuit",
|
|
15
|
+
"run_pennylane_circuit",
|
|
16
|
+
"noise_model_from_qiskit_backend",
|
|
17
|
+
"to_stim",
|
|
18
|
+
]
|