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,322 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Majorana-fermion -> qubit (Jordan-Wigner) mapping.
|
|
3
|
+
|
|
4
|
+
Standard convention, one qubit per two Majorana modes:
|
|
5
|
+
chi_{2j-1} = (prod_{k<j} Z_k) X_j
|
|
6
|
+
chi_{2j} = (prod_{k<j} Z_k) Y_j
|
|
7
|
+
mode_index is 1-indexed (chi_1 .. chi_{2*n_qubits}). Each chi_i is
|
|
8
|
+
Hermitian and satisfies chi_i^2 = I by this normalization; the anticommutation
|
|
9
|
+
relation {chi_a, chi_b} = 2*delta_ab*I holds exactly (verified in
|
|
10
|
+
tests/unit/test_fermions.py against the actual matrices, not assumed from the
|
|
11
|
+
textbook formula alone).
|
|
12
|
+
|
|
13
|
+
Originated in research/wormhole_syk.py (a traversable-wormhole-inspired
|
|
14
|
+
quantum teleportation reproduction, arXiv:2604.10090) -- promoted here
|
|
15
|
+
because Jordan-Wigner fermion mapping is a generic building block, not
|
|
16
|
+
specific to that one experiment, and nothing like it existed anywhere in
|
|
17
|
+
this package before (dashboard_core/hamiltonians.py only has PennyLane's
|
|
18
|
+
molecule-specific Hartree-Fock Jordan-Wigner, not a general Majorana map).
|
|
19
|
+
|
|
20
|
+
Combine the returned Pauli term with dense_evolution.pauli_hamiltonian_to_matrix
|
|
21
|
+
to build any Majorana-operator Hamiltonian as a dense matrix, e.g. a
|
|
22
|
+
sparse SYK model: H = sum_{ijkl} J_ijkl * chi_i*chi_j*chi_k*chi_l.
|
|
23
|
+
|
|
24
|
+
total_parity_operator (the "Klein factor" for a set of Majorana modes) was
|
|
25
|
+
promoted alongside majorana_pauli_terms from Dense-Evolution-Discovery's
|
|
26
|
+
wormhole_magic_entropy.py (2026-08-29): a second, independently-Jordan-
|
|
27
|
+
Wigner-mapped fermionic register (e.g. the "R" side of a two-copy/thermofield-
|
|
28
|
+
double construction) puts its Majoranas on disjoint qubits, so cross-register
|
|
29
|
+
Majorana products COMMUTE by construction instead of anticommuting -- the
|
|
30
|
+
well-known "Klein factor" problem from bosonization / fermionic-entanglement
|
|
31
|
+
literature (e.g. Fidkowski-Kitaev). Multiplying one register's operators by
|
|
32
|
+
its own total_parity_operator before combining them with the other
|
|
33
|
+
register's restores the correct anticommutation; see that function's
|
|
34
|
+
docstring for the algebraic proof.
|
|
35
|
+
|
|
36
|
+
hubbard_hamiltonian_pauli_terms uses the OTHER standard Jordan-Wigner
|
|
37
|
+
convention -- ordinary spin-orbital creation/annihilation operators
|
|
38
|
+
(c_q = sigma+_q * Z-string, not Majoranas) -- promoted from
|
|
39
|
+
Dense-Evolution-Discovery's hubbard_square_arovas.py (2026-09-01), which
|
|
40
|
+
reproduces Arovas, Bandyopadhyay & Zhu, "The Hubbard Model" (Annual Review
|
|
41
|
+
of Condensed Matter Physics 2022, arXiv:2103.12097). Nothing like it
|
|
42
|
+
existed anywhere in this package before: dashboard_core/hamiltonians.py
|
|
43
|
+
only has PennyLane's molecule-specific Hartree-Fock Jordan-Wigner (routed
|
|
44
|
+
through PennyLane's own internal mapping, not this module's Pauli-term
|
|
45
|
+
machinery), not a general lattice-fermion-model builder.
|
|
46
|
+
"""
|
|
47
|
+
from .observables import multiply_pauli_terms
|
|
48
|
+
|
|
49
|
+
__all__ = [
|
|
50
|
+
'majorana_pauli_terms', 'total_parity_operator',
|
|
51
|
+
'hubbard_hamiltonian_pauli_terms', 'square_lattice_edges',
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def majorana_pauli_terms(mode_index, n_qubits):
|
|
56
|
+
"""Jordan-Wigner term for one Majorana mode.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
mode_index : int
|
|
61
|
+
1-indexed Majorana mode, 1 <= mode_index <= 2*n_qubits.
|
|
62
|
+
n_qubits : int
|
|
63
|
+
Number of qubits the fermionic system is mapped onto
|
|
64
|
+
(n_majorana_modes = 2*n_qubits).
|
|
65
|
+
|
|
66
|
+
Returns
|
|
67
|
+
-------
|
|
68
|
+
(float, dict)
|
|
69
|
+
A (coeff, pauli_dict) term -- coeff is always 1.0, pauli_dict is
|
|
70
|
+
{qubit: 'X'|'Y'|'Z'} -- ready for
|
|
71
|
+
dense_evolution.pauli_hamiltonian_to_matrix.
|
|
72
|
+
"""
|
|
73
|
+
if not (1 <= mode_index <= 2 * n_qubits):
|
|
74
|
+
raise ValueError(f"mode_index must be in [1, {2*n_qubits}], got {mode_index}")
|
|
75
|
+
j = (mode_index - 1) // 2
|
|
76
|
+
is_even = (mode_index % 2 == 0)
|
|
77
|
+
pauli = {k: 'Z' for k in range(j)}
|
|
78
|
+
pauli[j] = 'Y' if is_even else 'X'
|
|
79
|
+
return (1.0, pauli)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def total_parity_operator(mode_indices, n_qubits):
|
|
83
|
+
"""Total fermion-parity ("Klein factor") operator for a set of Majorana
|
|
84
|
+
modes: i^(N/2) times the ORDERED product of majorana_pauli_terms(m,
|
|
85
|
+
n_qubits) for every m in `mode_indices` (N = len(mode_indices)),
|
|
86
|
+
computed via multiply_pauli_terms (exact symbolic Pauli algebra, no
|
|
87
|
+
numerical approximation).
|
|
88
|
+
|
|
89
|
+
The i^(N/2) PHASE CORRECTION is not optional decoration -- found
|
|
90
|
+
necessary by testing, not assumed from the general anticommutation
|
|
91
|
+
argument alone: for N mutually anticommuting HERMITIAN operators, the
|
|
92
|
+
raw ordered product Pi = chi_1*chi_2*...*chi_N satisfies
|
|
93
|
+
Pi^dagger = chi_N*...*chi_1 = (-1)**(N*(N-1)/2) * Pi (reversing N
|
|
94
|
+
anticommuting factors takes N*(N-1)/2 transpositions, each contributing
|
|
95
|
+
-1) -- so Pi itself is Hermitian only when N*(N-1)/2 is even (N=4, 8,
|
|
96
|
+
12, ... i.e. N%4==0), and ANTI-Hermitian when N*(N-1)/2 is odd (N=2, 6,
|
|
97
|
+
10, ... i.e. N%4==2). This was caught by a test at N=6 (n_qubits=3)
|
|
98
|
+
that the original N=8-only manual check never exercised. Multiplying
|
|
99
|
+
by i^(N/2) fixes this for every even N: verified numerically for
|
|
100
|
+
N=2,4,6,8,10 that i**(N/2) * Pi is exactly Hermitian AND squares to
|
|
101
|
+
exactly the identity in every case (see tests/unit/test_fermions.py).
|
|
102
|
+
|
|
103
|
+
Why this fixes cross-register anticommutation: an even number of
|
|
104
|
+
mutually anticommuting, squares-to-identity operators, correctly
|
|
105
|
+
phase-normalized to be Hermitian and square to I (as above), still
|
|
106
|
+
anticommutes with each individual factor -- multiplying an overall
|
|
107
|
+
scalar phase never changes an operator's (anti)commutation relations
|
|
108
|
+
with OTHER operators. Concretely: if psi_L (from THIS register) and
|
|
109
|
+
psi_R (from an independently Jordan-Wigner-mapped SECOND register,
|
|
110
|
+
e.g. dense_evolution.physics.fermions.majorana_pauli_terms called
|
|
111
|
+
again with its own qubit offset) act on disjoint qubits, they commute
|
|
112
|
+
by construction -- but P_L = total_parity_operator(all_of_this_
|
|
113
|
+
register's_modes, n_qubits) anticommutes with every psi_L, so
|
|
114
|
+
replacing psi_R with multiply_pauli_terms([P_L, psi_R]) (P_L applied
|
|
115
|
+
first) makes it anticommute with psi_L instead, while leaving
|
|
116
|
+
{psi_R, psi_R'} (two operators from the SAME second register)
|
|
117
|
+
unchanged, since P_L^2 = I factors out trivially:
|
|
118
|
+
{P_L*psi_R, P_L*psi_R'} = P_L^2 * {psi_R, psi_R'}.
|
|
119
|
+
|
|
120
|
+
len(mode_indices) must be even -- an odd-length parity operator would
|
|
121
|
+
anticommute with an EVEN number of factors' worth of sign flips, i.e.
|
|
122
|
+
NOT anticommute with its own members, defeating the purpose (raises
|
|
123
|
+
ValueError rather than silently returning something that doesn't have
|
|
124
|
+
the intended algebraic property).
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
mode_indices : iterable of int
|
|
129
|
+
1-indexed Majorana modes (same indexing as majorana_pauli_terms),
|
|
130
|
+
typically ALL of one register's modes (range(1, n_majorana+1)) to
|
|
131
|
+
get that register's total parity, though any even-length subset
|
|
132
|
+
is algebraically valid.
|
|
133
|
+
n_qubits : int
|
|
134
|
+
Same meaning as majorana_pauli_terms's n_qubits.
|
|
135
|
+
|
|
136
|
+
Returns
|
|
137
|
+
-------
|
|
138
|
+
(complex, dict)
|
|
139
|
+
A (coeff, pauli_dict) term, same shape as majorana_pauli_terms's
|
|
140
|
+
return -- ready for pauli_hamiltonian_to_matrix / pauli_expectation
|
|
141
|
+
/ another multiply_pauli_terms call.
|
|
142
|
+
|
|
143
|
+
Examples
|
|
144
|
+
--------
|
|
145
|
+
>>> total_parity_operator([1, 2], n_qubits=1) # i^1 * chi_1*chi_2 = i*(i*Z) = -Z
|
|
146
|
+
((-1+0j), {0: 'Z'})
|
|
147
|
+
"""
|
|
148
|
+
mode_indices = list(mode_indices)
|
|
149
|
+
n = len(mode_indices)
|
|
150
|
+
if n % 2 != 0:
|
|
151
|
+
raise ValueError(
|
|
152
|
+
f"total_parity_operator needs an EVEN number of modes to anticommute "
|
|
153
|
+
f"with each of its own members, got {n}"
|
|
154
|
+
)
|
|
155
|
+
factors = [majorana_pauli_terms(m, n_qubits) for m in mode_indices]
|
|
156
|
+
coeff, pauli_dict = multiply_pauli_terms(factors)
|
|
157
|
+
return coeff * (1j ** (n / 2)), pauli_dict
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def square_lattice_edges(lx, ly, periodic=True, periodic_y=None):
|
|
161
|
+
"""Nearest-neighbor site-index pairs (i, j) on an Lx by Ly square
|
|
162
|
+
lattice, site index = y*lx + x (row-major). One x-bond and one
|
|
163
|
+
y-bond generated per site; a periodic direction wraps via i ->
|
|
164
|
+
(i+1) % L, the same convention as the 1D ring below -- an L=2
|
|
165
|
+
periodic direction generates the same physical bond twice (once
|
|
166
|
+
from each end), matching that same known behavior already present
|
|
167
|
+
in the 1D n_sites=2 case, not a new quirk introduced here.
|
|
168
|
+
|
|
169
|
+
`periodic` sets the x-direction boundary; `periodic_y` sets the
|
|
170
|
+
y-direction independently (defaults to the same value as `periodic`
|
|
171
|
+
when not given, so a single `periodic=True/False` still means "both
|
|
172
|
+
directions" for the common torus/open cases). Pass periodic=True,
|
|
173
|
+
periodic_y=False for a "cylinder" -- periodic around one direction,
|
|
174
|
+
open (a finite "leg" ladder) along the other -- the same geometry
|
|
175
|
+
Arovas, Bandyopadhyay & Zhu's Hubbard-model review (arXiv:2103.12097,
|
|
176
|
+
already cited below) discusses for W-leg cylinder DMRG studies
|
|
177
|
+
("periodic boundary conditions have been enforced around the
|
|
178
|
+
cylinder" while the leg direction stays open/finite), not an
|
|
179
|
+
invented boundary condition.
|
|
180
|
+
|
|
181
|
+
With ly=1 this reduces exactly to the 1D ring
|
|
182
|
+
hubbard_hamiltonian_pauli_terms builds internally (verified in
|
|
183
|
+
tests/unit/test_fermions.py), so passing edges=square_lattice_edges(
|
|
184
|
+
n_sites, 1, periodic) to hubbard_hamiltonian_pauli_terms reproduces
|
|
185
|
+
its own default 1D behavior; ly>1 is the actual 2D generalization,
|
|
186
|
+
cross-checked there against an independent brute-force fermionic
|
|
187
|
+
construction on a real 2x2 lattice, both fully open and
|
|
188
|
+
periodic-in-x-only -- kept small since the hopping loop keys each
|
|
189
|
+
term only on that edge's own qubit indices, so nothing about the
|
|
190
|
+
check depends on lattice size.
|
|
191
|
+
|
|
192
|
+
Parameters
|
|
193
|
+
----------
|
|
194
|
+
lx, ly : int
|
|
195
|
+
Lattice extent along x and y.
|
|
196
|
+
periodic : bool, default True
|
|
197
|
+
Wrap the x direction. Also used for y when `periodic_y` is None.
|
|
198
|
+
periodic_y : bool, optional
|
|
199
|
+
Wrap the y direction independently of `periodic`.
|
|
200
|
+
|
|
201
|
+
Returns
|
|
202
|
+
-------
|
|
203
|
+
list of (int, int)
|
|
204
|
+
Site-index pairs, ready for hubbard_hamiltonian_pauli_terms's
|
|
205
|
+
`edges` parameter.
|
|
206
|
+
"""
|
|
207
|
+
if periodic_y is None:
|
|
208
|
+
periodic_y = periodic
|
|
209
|
+
edges = []
|
|
210
|
+
for y in range(ly):
|
|
211
|
+
for x in range(lx):
|
|
212
|
+
i = y * lx + x
|
|
213
|
+
if x + 1 < lx:
|
|
214
|
+
edges.append((i, y * lx + (x + 1)))
|
|
215
|
+
elif periodic and lx > 1:
|
|
216
|
+
edges.append((i, y * lx))
|
|
217
|
+
if y + 1 < ly:
|
|
218
|
+
edges.append((i, (y + 1) * lx + x))
|
|
219
|
+
elif periodic_y and ly > 1:
|
|
220
|
+
edges.append((i, x))
|
|
221
|
+
return edges
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def hubbard_hamiltonian_pauli_terms(n_sites, t, U, periodic=True, edges=None):
|
|
225
|
+
"""Jordan-Wigner mapping of the Hubbard Hamiltonian
|
|
226
|
+
H = -t * sum_<ij>,sigma (c^dagger_i,sigma c_j,sigma + h.c.)
|
|
227
|
+
+ U * sum_i n_i,up * n_i,down
|
|
228
|
+
onto n_qubits=2*n_sites qubits: qubits [0, n_sites) are the spin-up
|
|
229
|
+
orbitals, qubits [n_sites, 2*n_sites) spin-down, both site-ordered.
|
|
230
|
+
<ij> runs over nearest-neighbor sites; by default that's a 1D ring
|
|
231
|
+
(site i to site (i+1) % n_sites), with periodic=False dropping the
|
|
232
|
+
wraparound bond (site n_sites-1 to site 0) for an open chain instead.
|
|
233
|
+
|
|
234
|
+
Pass `edges` explicitly (a list of (i, j) site-index pairs, 0 <= i,
|
|
235
|
+
j < n_sites) to describe a different lattice -- e.g. a 2D square
|
|
236
|
+
lattice via square_lattice_edges(lx, ly, periodic) with n_sites=
|
|
237
|
+
lx*ly -- and `periodic` is then ignored (the wraparound choice is
|
|
238
|
+
already baked into the edges you pass). The hopping/Jordan-Wigner
|
|
239
|
+
machinery below only ever uses the qubit-index Z-string between two
|
|
240
|
+
given sites (see the wraparound-bond note below), so it was already
|
|
241
|
+
lattice-agnostic; only the default 1D edge list was ring-specific.
|
|
242
|
+
|
|
243
|
+
The wraparound bond needed a self-test before being trusted: some
|
|
244
|
+
Jordan-Wigner conventions need an extra fermion-parity correction for
|
|
245
|
+
a periodic-boundary term written as a *short* Pauli string. This
|
|
246
|
+
function instead always uses the full-length Jordan-Wigner string
|
|
247
|
+
between the two mapped qubit indices (c_i^dagger c_j = sigma+_i *
|
|
248
|
+
(Z-string between i and j) * sigma-_j, i<j), which is the exact
|
|
249
|
+
fermionic identity for ANY pair of modes regardless of whether they
|
|
250
|
+
are lattice-adjacent -- so no extra correction is needed here, and
|
|
251
|
+
this was verified directly against an independent brute-force
|
|
252
|
+
fermionic operator construction (not just argued from the formula):
|
|
253
|
+
max diff 0.00e+00 (machine-exact) at n_sites=2,3,4, both periodic and
|
|
254
|
+
open (Dense-Evolution-Discovery's hubbard_square_arovas.py), and at a
|
|
255
|
+
2D lattice via square_lattice_edges, both open and periodic-in-x-only
|
|
256
|
+
(see tests).
|
|
257
|
+
|
|
258
|
+
Parameters
|
|
259
|
+
----------
|
|
260
|
+
n_sites : int
|
|
261
|
+
Number of lattice sites (n_qubits = 2*n_sites).
|
|
262
|
+
t : float
|
|
263
|
+
Hopping amplitude.
|
|
264
|
+
U : float
|
|
265
|
+
On-site interaction strength.
|
|
266
|
+
periodic : bool, default True
|
|
267
|
+
Include the wraparound bond (site n_sites-1 to site 0). With
|
|
268
|
+
n_sites=4, this is the "Hubbard square" studied in Arovas,
|
|
269
|
+
Bandyopadhyay & Zhu, "The Hubbard Model" (Annual Review of
|
|
270
|
+
Condensed Matter Physics 2022, arXiv:2103.12097) -- Table 2 (p.6)
|
|
271
|
+
gives a closed-form small-U/t perturbative ground-state energy
|
|
272
|
+
for this exact model, verified directly against exact
|
|
273
|
+
diagonalization in the Discovery experiment above, and identifies
|
|
274
|
+
this ground state's orbital symmetry as x^2-y^2 (i.e. B1g/d-wave),
|
|
275
|
+
checkable via the sign pattern of pairing correlations
|
|
276
|
+
<Delta_0^dagger Delta_j> with Delta_i = c_i,up * c_i,down
|
|
277
|
+
(positive for axis neighbors, negative for the diagonal).
|
|
278
|
+
Ignored when `edges` is passed explicitly.
|
|
279
|
+
edges : list of (int, int), optional
|
|
280
|
+
Explicit nearest-neighbor site pairs, overriding the default 1D
|
|
281
|
+
ring. See square_lattice_edges for a 2D square-lattice builder.
|
|
282
|
+
|
|
283
|
+
Returns
|
|
284
|
+
-------
|
|
285
|
+
list of (float, dict)
|
|
286
|
+
Pauli terms in the same (coeff, {qubit: 'X'|'Y'|'Z'}) form
|
|
287
|
+
majorana_pauli_terms returns -- ready for
|
|
288
|
+
dense_evolution.pauli_hamiltonian_to_matrix or
|
|
289
|
+
pauli_sum_expectation.
|
|
290
|
+
"""
|
|
291
|
+
n_qubits = 2 * n_sites
|
|
292
|
+
terms = []
|
|
293
|
+
|
|
294
|
+
if edges is None:
|
|
295
|
+
edges = [(i, (i + 1) % n_sites) for i in range(n_sites)]
|
|
296
|
+
if not periodic:
|
|
297
|
+
edges = [(i, j) for i, j in edges if not (i == n_sites - 1 and j == 0)]
|
|
298
|
+
|
|
299
|
+
for i, j in edges:
|
|
300
|
+
for offset in (0, n_sites):
|
|
301
|
+
qi, qj = offset + i, offset + j
|
|
302
|
+
low, high = min(qi, qj), max(qi, qj)
|
|
303
|
+
z_span = range(low + 1, high)
|
|
304
|
+
|
|
305
|
+
pauli_xx = {k: 'Z' for k in z_span}
|
|
306
|
+
pauli_xx[low] = 'X'
|
|
307
|
+
pauli_xx[high] = 'X'
|
|
308
|
+
terms.append((-0.5 * t, pauli_xx))
|
|
309
|
+
|
|
310
|
+
pauli_yy = {k: 'Z' for k in z_span}
|
|
311
|
+
pauli_yy[low] = 'Y'
|
|
312
|
+
pauli_yy[high] = 'Y'
|
|
313
|
+
terms.append((-0.5 * t, pauli_yy))
|
|
314
|
+
|
|
315
|
+
for i in range(n_sites):
|
|
316
|
+
idx_up, idx_dn = i, n_sites + i
|
|
317
|
+
terms.append((0.25 * U, {}))
|
|
318
|
+
terms.append((-0.25 * U, {idx_up: 'Z'}))
|
|
319
|
+
terms.append((-0.25 * U, {idx_dn: 'Z'}))
|
|
320
|
+
terms.append((0.25 * U, {idx_up: 'Z', idx_dn: 'Z'}))
|
|
321
|
+
|
|
322
|
+
return terms
|