callensxavier commited on
Commit
3cd1783
·
verified ·
1 Parent(s): 849a14a

Upload simulator.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. simulator.py +136 -2
simulator.py CHANGED
@@ -5,7 +5,7 @@
5
  # =======================================================================
6
 
7
  import numpy as np
8
- from typing import Tuple, List, Optional
9
 
10
  class Tensor3D:
11
  """Represents a single node tensor in the 3D PEPS network."""
@@ -19,20 +19,29 @@ class Tensor3D:
19
  # Normalize tensor initially
20
  self.data /= np.linalg.norm(self.data)
21
 
 
22
  class PepsGrid3D:
23
- """Represents the 3D Projected Entangled Pair State (PEPS) grid of size L x L x L."""
 
 
 
 
24
  def __init__(self, L: int, bond_dim: int = 2):
25
  self.L = L
26
  self.bond_dim = bond_dim
27
  self.qubits = L * L * L
28
  self.grid = [[[Tensor3D(2, bond_dim) for _ in range(L)] for _ in range(L)] for _ in range(L)]
29
 
 
30
  # Draw random disordered Edwards-Anderson couplings J_ij ~ N(0, 1.0)
31
  self.J_x = np.random.normal(0.0, 1.0, (L, L, L))
32
  self.J_y = np.random.normal(0.0, 1.0, (L, L, L))
33
  self.J_z = np.random.normal(0.0, 1.0, (L, L, L))
34
  # Random transverse fields h_i ~ N(0, 0.5)
35
  self.h = np.random.normal(0.0, 0.5, (L, L, L))
 
 
 
36
 
37
  def get_hamiltonian_expectation(self) -> float:
38
  """Calculates simulated energy expectation value <H>."""
@@ -53,6 +62,31 @@ class PepsGrid3D:
53
  energy += self.J_z[x, y, z] * 0.25
54
  return energy
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  def contract_boundary_step(self, x_slice: int) -> np.ndarray:
57
  """
58
  Simulates boundary contraction of a 2D slice from the 3D grid.
@@ -69,3 +103,103 @@ class PepsGrid3D:
69
  random_boundary = np.random.normal(0.0, 1.0, (flat_size, flat_size))
70
  U, S, Vt = np.linalg.svd(random_boundary, full_matrices=False)
71
  return S
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  # =======================================================================
6
 
7
  import numpy as np
8
+ from typing import Tuple, List, Optional, Dict
9
 
10
  class Tensor3D:
11
  """Represents a single node tensor in the 3D PEPS network."""
 
19
  # Normalize tensor initially
20
  self.data /= np.linalg.norm(self.data)
21
 
22
+
23
  class PepsGrid3D:
24
+ """
25
+ Represents the 3D Projected Entangled Pair State (PEPS) grid of size L x L x L
26
+ simulating the non-equilibrium dynamics and ground state annealing of the
27
+ disordered 3D Edwards-Anderson spin glass.
28
+ """
29
  def __init__(self, L: int, bond_dim: int = 2):
30
  self.L = L
31
  self.bond_dim = bond_dim
32
  self.qubits = L * L * L
33
  self.grid = [[[Tensor3D(2, bond_dim) for _ in range(L)] for _ in range(L)] for _ in range(L)]
34
 
35
+ np.random.seed(42)
36
  # Draw random disordered Edwards-Anderson couplings J_ij ~ N(0, 1.0)
37
  self.J_x = np.random.normal(0.0, 1.0, (L, L, L))
38
  self.J_y = np.random.normal(0.0, 1.0, (L, L, L))
39
  self.J_z = np.random.normal(0.0, 1.0, (L, L, L))
40
  # Random transverse fields h_i ~ N(0, 0.5)
41
  self.h = np.random.normal(0.0, 0.5, (L, L, L))
42
+
43
+ # Initialize classical Ising spin configuration S_i in {-1, +1}
44
+ self.spins = np.random.choice([-1, 1], size=(L, L, L))
45
 
46
  def get_hamiltonian_expectation(self) -> float:
47
  """Calculates simulated energy expectation value <H>."""
 
62
  energy += self.J_z[x, y, z] * 0.25
63
  return energy
64
 
65
+ def calculate_exact_spin_energy(self) -> float:
66
+ """
67
+ Calculates the exact physical energy of the current spin configuration:
68
+ E = - sum_{<i,j>} J_ij S_i S_j - sum_i h_i S_i
69
+ """
70
+ energy = 0.0
71
+ L = self.L
72
+ for x in range(L):
73
+ for y in range(L):
74
+ for z in range(L):
75
+ S = self.spins[x, y, z]
76
+ # Local transverse field interaction
77
+ energy -= self.h[x, y, z] * S
78
+
79
+ # Couple with right neighbor (+x)
80
+ if x + 1 < L:
81
+ energy -= self.J_x[x, y, z] * S * self.spins[x+1, y, z]
82
+ # Couple with front neighbor (+y)
83
+ if y + 1 < L:
84
+ energy -= self.J_y[x, y, z] * S * self.spins[x, y+1, z]
85
+ # Couple with upper neighbor (+z)
86
+ if z + 1 < L:
87
+ energy -= self.J_z[x, y, z] * S * self.spins[x, y, z+1]
88
+ return energy
89
+
90
  def contract_boundary_step(self, x_slice: int) -> np.ndarray:
91
  """
92
  Simulates boundary contraction of a 2D slice from the 3D grid.
 
103
  random_boundary = np.random.normal(0.0, 1.0, (flat_size, flat_size))
104
  U, S, Vt = np.linalg.svd(random_boundary, full_matrices=False)
105
  return S
106
+
107
+ def simulated_annealing_step(self, temp: float) -> Tuple[float, float]:
108
+ """
109
+ Performs one full Monte Carlo sweep (annealing step) of the 3D spin lattice.
110
+ Returns the new energy and the accept ratio of spin flips.
111
+ """
112
+ L = self.L
113
+ flips_attempted = 0
114
+ flips_accepted = 0
115
+
116
+ for x in range(L):
117
+ for y in range(L):
118
+ for z in range(L):
119
+ # Calculate local field contribution
120
+ S_i = self.spins[x, y, z]
121
+
122
+ # Local field h_i
123
+ local_field = self.h[x, y, z]
124
+
125
+ # Neighbors interaction sum
126
+ # -x, +x
127
+ if x > 0:
128
+ local_field += self.J_x[x-1, y, z] * self.spins[x-1, y, z]
129
+ if x + 1 < L:
130
+ local_field += self.J_x[x, y, z] * self.spins[x+1, y, z]
131
+
132
+ # -y, +y
133
+ if y > 0:
134
+ local_field += self.J_y[x, y-1, z] * self.spins[x, y-1, z]
135
+ if y + 1 < L:
136
+ local_field += self.J_y[x, y, z] * self.spins[x, y+1, z]
137
+
138
+ # -z, +z
139
+ if z > 0:
140
+ local_field += self.J_z[x, y, z-1] * self.spins[x, y, z-1]
141
+ if z + 1 < L:
142
+ local_field += self.J_z[x, y, z] * self.spins[x, y, z+1]
143
+
144
+ # Delta E for flipping S_i is 2 * S_i * (Sum J_ij S_j + h_i)
145
+ dE = 2.0 * S_i * local_field
146
+
147
+ flips_attempted += 1
148
+ # Metropolis acceptance criterion
149
+ if dE <= 0.0 or (temp > 0.0 and np.random.uniform(0.0, 1.0) < np.exp(-dE / temp)):
150
+ self.spins[x, y, z] *= -1
151
+ flips_accepted += 1
152
+
153
+ accept_ratio = flips_accepted / flips_attempted if flips_attempted > 0 else 0.0
154
+ return self.calculate_exact_spin_energy(), accept_ratio
155
+
156
+ def verify_gauge_invariance(self) -> float:
157
+ """
158
+ Fuzzy gauge invariance checking.
159
+ In spin glasses, the transformation:
160
+ S_i -> eta_i * S_i, J_ij -> eta_i * eta_j * J_ij (where eta_i in {-1, +1})
161
+ is a local symmetry leaving the physical Hamiltonian energy E completely invariant!
162
+
163
+ This method executes a random gauge transform and returns the absolute energy discrepancy.
164
+ """
165
+ L = self.L
166
+ initial_energy = self.calculate_exact_spin_energy()
167
+
168
+ # 1. Generate random gauge factors eta_i in {-1, +1}
169
+ eta = np.random.choice([-1, 1], size=(L, L, L))
170
+
171
+ # 2. Store original couplings and spins
172
+ orig_spins = self.spins.copy()
173
+ orig_J_x = self.J_x.copy()
174
+ orig_J_y = self.J_y.copy()
175
+ orig_J_z = self.J_z.copy()
176
+ orig_h = self.h.copy()
177
+
178
+ # 3. Apply local gauge transformation
179
+ self.spins = self.spins * eta
180
+ self.h = self.h * eta # fields scale as local spin transform to preserve h_i S_i
181
+
182
+ # Couplings transform as: J_ij -> J_ij * eta_i * eta_j
183
+ for x in range(L):
184
+ for y in range(L):
185
+ for z in range(L):
186
+ eta_i = eta[x, y, z]
187
+ if x + 1 < L:
188
+ self.J_x[x, y, z] *= eta_i * eta[x+1, y, z]
189
+ if y + 1 < L:
190
+ self.J_y[x, y, z] *= eta_i * eta[x, y+1, z]
191
+ if z + 1 < L:
192
+ self.J_z[x, y, z] *= eta_i * eta[x, y, z+1]
193
+
194
+ # Calculate energy in gauged basis
195
+ gauged_energy = self.calculate_exact_spin_energy()
196
+
197
+ # Restore original basis
198
+ self.spins = orig_spins
199
+ self.J_x = orig_J_x
200
+ self.J_y = orig_J_y
201
+ self.J_z = orig_J_z
202
+ self.h = orig_h
203
+
204
+ # Return discrepancy
205
+ return abs(gauged_energy - initial_energy)