import numpy as np
import scipy.linalg
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
##############################################################################
1. Parámetros y configuración
##############################################################################
hbar = 1.0
t_hop = 1.0
G = 1.0
M = 1.0
lambda_g = 0.2
dt = 0.02
steps = 50
factor para la evolución cuántica: exp(-iH dt / hbar)
factor_evol = -1j * dt / hbar
##############################################################################
2. Definición del icosaedro base (sin deformación)
##############################################################################
phi = (1 + np.sqrt(5)) / 2.0
base_vertices = np.array([
[-1, phi, 0],
[ 1, phi, 0],
[-1, -phi, 0],
[ 1, -phi, 0],
[ 0, -1, phi],
[ 0, 1, phi],
[ 0, -1, -phi],
[ 0, 1, -phi],
[ phi, 0, -1],
[ phi, 0, 1],
[-phi, 0, -1],
[-phi, 0, 1]
], dtype=float)
Normalizamos para que un vértice tenga radio 1
r0 = np.linalg.norm(base_vertices[0])
base_vertices /= r0
Lista de aristas del icosaedro (12 vértices, 30 aristas)
edges = [
(0,1), (0,5), (0,7), (0,10), (0,11),
(1,5), (1,7), (1,8), (1,9),
(2,3), (2,6), (2,7), (2,9), (2,11),
(3,6), (3,7), (3,8), (3,9),
(4,5), (4,6), (4,9), (4,10), (4,11),
(5,9), (5,10),
(6,7), (6,9), (6,10),
(7,8),
(8,9), (8,10),
(10,11)
]
def build_adjacency_matrix():
"""
Construye la matriz de adyacencia (12x12) con -t_hop en las posiciones
correspondientes a las aristas.
"""
A = np.zeros((12, 12), dtype=complex)
for (i, j) in edges:
A[i, j] = -t_hop
A[j, i] = -t_hop
return A
##############################################################################
3. Potencial logarítmico estático (sin deformar vértices)
##############################################################################
def build_potential_log(vertices):
"""
Calcula el potencial gravitatorio discreto V_G(i) = - sum(G*M / dist(i,j))
y luego aplica la corrección logarítmica V_log(i) = lambda_g * log(1 + V_G(i)).
Como la geometría no cambia, este potencial es constante en el tiempo.
"""
N = len(vertices)
V_G = np.zeros(N, dtype=float)
for i in range(N):
for j in range(N):
if i != j:
dist_ij = np.linalg.norm(vertices[i] - vertices[j])
V_G[i] += - (G * M / dist_ij)
# Evitamos valores no válidos en la log    
min_val = np.min(V_G)    
shift = 0.0    
if min_val <= -1.0:    
    shift = -(min_val + 0.9999)    
    
V_log = lambda_g * np.log(1.0 + V_G + shift)    
return V_log
##############################################################################
4. Construcción del Hamiltoniano estático
##############################################################################
adjacency = build_adjacency_matrix()
El icosaedro permanece siempre igual (sin "update_vertices")
Por tanto, calculamos el potencial logarítmico solo una vez:
V_log_static = build_potential_log(base_vertices)
Hamiltoniano total fijo: H = adjacency + diag(V_log_static)
H_static = adjacency + np.diag(V_log_static)
Operador de evolución para un paso de tiempo dt
U_static = scipy.linalg.expm(factor_evol * H_static)
##############################################################################
5. Estado cuántico inicial y bucle de evolución
##############################################################################
psi = np.zeros(12, dtype=complex)
psi[0] = 1.0 # partícula localizada en el vértice 0 al inicio
psi_t_history = [psi.copy()]
for _ in range(steps):
psi = U_static @ psi
# Renormalizamos para evitar errores numéricos
norm_psi = np.linalg.norm(psi)
if norm_psi > 1e-12:
psi /= norm_psi
psi_t_history.append(psi.copy())
##############################################################################
6. Visualización de resultados
##############################################################################
prob_t = np.array([np.abs(state)**2 for state in psi_t_history])
Evolución de la probabilidad
plt.figure(figsize=(10,6))
for i in range(12):
plt.plot(prob_t[:, i], label=f'Vértice {i}')
plt.xlabel('Paso de tiempo')
plt.ylabel('Probabilidad')
plt.title('Evolución de la probabilidad en un icosaedro estático (potencial fijo)')
plt.legend(bbox_to_anchor=(1.05, 1.0), loc='upper left')
plt.tight_layout()
plt.show()
Visualización 3D de la configuración final (los vértices no cambian)
final_prob = prob_t[-1]
fig = plt.figure(figsize=(7,7))
ax = fig.add_subplot(111, projection='3d')
colors = plt.cm.viridis(final_prob / final_prob.max())
for i in range(12):
x, y, z = base_vertices[i]
ax.scatter(x, y, z, color=colors[i], s=50 + 400*final_prob[i])
ax.set_title('Configuración final en el icosaedro estático')
plt.show()
Antony Padilla Morales