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.
Files changed (165) hide show
  1. dashboard_core/__init__.py +115 -0
  2. dashboard_core/_gate_tables.py +30 -0
  3. dashboard_core/band_structure.py +71 -0
  4. dashboard_core/circuit_builder_component.py +232 -0
  5. dashboard_core/circuit_diagram.py +216 -0
  6. dashboard_core/crypto_protocols.py +77 -0
  7. dashboard_core/engine.py +326 -0
  8. dashboard_core/graphical_builder.py +114 -0
  9. dashboard_core/hamiltonians.py +593 -0
  10. dashboard_core/mass_decomposition_tool.py +47 -0
  11. dashboard_core/mitigation.py +343 -0
  12. dashboard_core/native_hf_diagnostics.py +62 -0
  13. dashboard_core/noise_tools.py +125 -0
  14. dashboard_core/qasm_library.py +233 -0
  15. dashboard_core/qmmm.py +16 -0
  16. dashboard_core/rag_tool.py +45 -0
  17. dashboard_core/state_visuals.py +288 -0
  18. dashboard_core/system_limits.py +60 -0
  19. dashboard_core/vector_healing.py +102 -0
  20. dashboard_core/visuals.py +158 -0
  21. dashboard_core/vqe.py +533 -0
  22. dashboard_core/wormhole.py +580 -0
  23. dense_evolution/__init__.py +114 -0
  24. dense_evolution/autodiff.py +10 -0
  25. dense_evolution/backends/__init__.py +5 -0
  26. dense_evolution/backends/chunk/__init__.py +37 -0
  27. dense_evolution/backends/chunk/_engine_imports.py +57 -0
  28. dense_evolution/backends/chunk/circuit_chunker.py +55 -0
  29. dense_evolution/backends/chunk/core.py +432 -0
  30. dense_evolution/backends/chunk/disk_overflow.py +232 -0
  31. dense_evolution/backends/chunk/geometry.py +95 -0
  32. dense_evolution/backends/chunk/guard.py +190 -0
  33. dense_evolution/backends/chunk/kernels.py +531 -0
  34. dense_evolution/backends/mps.py +1569 -0
  35. dense_evolution/backends/statevector.py +616 -0
  36. dense_evolution/chunk.py +25 -0
  37. dense_evolution/circuits/__init__.py +20 -0
  38. dense_evolution/circuits/compiler.py +488 -0
  39. dense_evolution/circuits/diagram.py +94 -0
  40. dense_evolution/circuits/gates.py +91 -0
  41. dense_evolution/circuits/parser.py +632 -0
  42. dense_evolution/circuits/qft.py +66 -0
  43. dense_evolution/circuits/random_circuit.py +85 -0
  44. dense_evolution/circuits/registry.py +74 -0
  45. dense_evolution/circuits/topology.py +79 -0
  46. dense_evolution/circuits/trotter.py +265 -0
  47. dense_evolution/circuits/uccsd.py +275 -0
  48. dense_evolution/cli.py +199 -0
  49. dense_evolution/compiler.py +9 -0
  50. dense_evolution/config.py +49 -0
  51. dense_evolution/drawing.py +10 -0
  52. dense_evolution/entropy.py +9 -0
  53. dense_evolution/fermions.py +9 -0
  54. dense_evolution/gates.py +9 -0
  55. dense_evolution/harrison_tb.py +16 -0
  56. dense_evolution/healing.py +18 -0
  57. dense_evolution/interop/__init__.py +18 -0
  58. dense_evolution/interop/qiskit_pennylane.py +406 -0
  59. dense_evolution/measurement.py +10 -0
  60. dense_evolution/mitigation/__init__.py +54 -0
  61. dense_evolution/mitigation/healing.py +215 -0
  62. dense_evolution/mitigation/kl_divergence.py +93 -0
  63. dense_evolution/mitigation/magic_entropy.py +163 -0
  64. dense_evolution/mitigation/magic_entropy_shadows.py +262 -0
  65. dense_evolution/mitigation/renyi.py +168 -0
  66. dense_evolution/mitigation/stabilizer_renyi_entropy.py +103 -0
  67. dense_evolution/mitigation/zne.py +990 -0
  68. dense_evolution/mps.py +9 -0
  69. dense_evolution/native_hf/__init__.py +26 -0
  70. dense_evolution/native_hf/_libcint/LICENSE-libcint +10 -0
  71. dense_evolution/native_hf/_libcint/libdecint.dll +0 -0
  72. dense_evolution/native_hf/assembly.py +304 -0
  73. dense_evolution/native_hf/basis.py +117 -0
  74. dense_evolution/native_hf/boys.py +35 -0
  75. dense_evolution/native_hf/bridge.py +112 -0
  76. dense_evolution/native_hf/cartesian.py +64 -0
  77. dense_evolution/native_hf/coulomb.py +196 -0
  78. dense_evolution/native_hf/differentiable.py +53 -0
  79. dense_evolution/native_hf/gaussians.py +79 -0
  80. dense_evolution/native_hf/kinetic.py +52 -0
  81. dense_evolution/native_hf/libcint_bridge.py +167 -0
  82. dense_evolution/native_hf/overlap.py +91 -0
  83. dense_evolution/native_hf/scf.py +404 -0
  84. dense_evolution/noise/__init__.py +79 -0
  85. dense_evolution/noise/coherent_attack.py +264 -0
  86. dense_evolution/noise/cosmic_ray.py +61 -0
  87. dense_evolution/noise/density_matrix_channels.py +78 -0
  88. dense_evolution/noise/differentiable.py +66 -0
  89. dense_evolution/noise/kraus/__init__.py +6 -0
  90. dense_evolution/noise/kraus/amplitude_damping.py +47 -0
  91. dense_evolution/noise/kraus/bitflip.py +22 -0
  92. dense_evolution/noise/kraus/combined.py +16 -0
  93. dense_evolution/noise/kraus/depolarizing.py +47 -0
  94. dense_evolution/noise/kraus/ideal.py +10 -0
  95. dense_evolution/noise/kraus/phaseflip.py +21 -0
  96. dense_evolution/noise/kraus_channels.py +285 -0
  97. dense_evolution/noise/oscillating.py +32 -0
  98. dense_evolution/noise/pink.py +80 -0
  99. dense_evolution/observables.py +11 -0
  100. dense_evolution/parser.py +9 -0
  101. dense_evolution/physics/__init__.py +27 -0
  102. dense_evolution/physics/entropy.py +161 -0
  103. dense_evolution/physics/fermions.py +322 -0
  104. dense_evolution/physics/observables.py +523 -0
  105. dense_evolution/physics/qec.py +1113 -0
  106. dense_evolution/physics/spectral.py +143 -0
  107. dense_evolution/physics/states.py +43 -0
  108. dense_evolution/protocols/__init__.py +27 -0
  109. dense_evolution/protocols/bb84.py +133 -0
  110. dense_evolution/protocols/di_qkd_ghz.py +199 -0
  111. dense_evolution/protocols/dicka_protocol2.py +124 -0
  112. dense_evolution/qec.py +20 -0
  113. dense_evolution/qft.py +9 -0
  114. dense_evolution/qmmm/__init__.py +13 -0
  115. dense_evolution/qmmm/ase_bridge.py +97 -0
  116. dense_evolution/qmmm/forces.py +388 -0
  117. dense_evolution/qmmm/propagation.py +80 -0
  118. dense_evolution/qmmm/region.py +137 -0
  119. dense_evolution/random_circuit.py +15 -0
  120. dense_evolution/registry.py +9 -0
  121. dense_evolution/simulator.py +10 -0
  122. dense_evolution/solvers/__init__.py +19 -0
  123. dense_evolution/solvers/autodiff.py +169 -0
  124. dense_evolution/solvers/harrison_tb.py +189 -0
  125. dense_evolution/solvers/vhd_tb.py +187 -0
  126. dense_evolution/states.py +9 -0
  127. dense_evolution/topology.py +9 -0
  128. dense_evolution/trotter.py +9 -0
  129. dense_evolution/utils/__init__.py +13 -0
  130. dense_evolution/utils/drawing.py +101 -0
  131. dense_evolution/utils/mass_decomposition.py +246 -0
  132. dense_evolution/utils/measurement.py +94 -0
  133. dense_evolution/vhd_tb.py +16 -0
  134. dense_evolution-8.3.0.dist-info/METADATA +366 -0
  135. dense_evolution-8.3.0.dist-info/RECORD +165 -0
  136. dense_evolution-8.3.0.dist-info/WHEEL +5 -0
  137. dense_evolution-8.3.0.dist-info/entry_points.txt +2 -0
  138. dense_evolution-8.3.0.dist-info/licenses/license.md +58 -0
  139. dense_evolution-8.3.0.dist-info/top_level.txt +5 -0
  140. ia_utils/__init__.py +0 -0
  141. ia_utils/adversarial_vector_attack.py +196 -0
  142. ia_utils/rag.py +288 -0
  143. ia_utils/vector_healing.py +399 -0
  144. local_site/__init__.py +0 -0
  145. local_site/app/__init__.py +0 -0
  146. local_site/app/server.py +1009 -0
  147. mcp_server/__init__.py +0 -0
  148. mcp_server/client.py +324 -0
  149. mcp_server/config.py +32 -0
  150. mcp_server/models.py +347 -0
  151. mcp_server/molecules.py +71 -0
  152. mcp_server/server.py +119 -0
  153. mcp_server/tools/__init__.py +0 -0
  154. mcp_server/tools/chemistry_tools.py +225 -0
  155. mcp_server/tools/circuit_tools.py +83 -0
  156. mcp_server/tools/crypto_tools.py +66 -0
  157. mcp_server/tools/mitigation_tools.py +81 -0
  158. mcp_server/tools/noise_tools.py +60 -0
  159. mcp_server/tools/retrieval_tools.py +44 -0
  160. mcp_server/tools/system_tools.py +149 -0
  161. mcp_server/tools/wormhole_tools.py +142 -0
  162. mcp_server/utils/__init__.py +0 -0
  163. mcp_server/utils/cache.py +55 -0
  164. mcp_server/utils/images.py +67 -0
  165. 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