import numpy as np import matplotlib.pyplot as plt from ideal_poly_volume_toolkit.geometry import delaunay_triangulation_indices, lift_to_sphere_with_inf from scipy.spatial import ConvexHull import torch # Recreate the maximal configuration from seed 104 def get_maximal_config(seed=104): rng = np.random.default_rng(seed) K = 9 # Initialize r = 0.5 + 1.5 * rng.random(K) theta = 2 * np.pi * rng.random(K) z_init = r * np.exp(1j * theta) real_parts = torch.tensor(z_init.real, dtype=torch.float64, requires_grad=True) imag_parts = torch.tensor(z_init.imag, dtype=torch.float64, requires_grad=True) def build_Z_free(real_parts, imag_parts): Z = torch.empty(real_parts.numel() + 2, dtype=torch.complex128) Z[0] = 0 + 0j Z[1] = 1 + 0j Z[2:] = torch.complex(real_parts, imag_parts) return Z opt = torch.optim.LBFGS([real_parts, imag_parts], lr=1.0, max_iter=20, line_search_fn='strong_wolfe') for it in range(100): with torch.no_grad(): Z_np = build_Z_free(real_parts, imag_parts).detach().cpu().numpy() idx = delaunay_triangulation_indices(Z_np) def closure(): opt.zero_grad(set_to_none=True) Z_t = build_Z_free(real_parts, imag_parts) total = torch.zeros((), dtype=torch.float64) for (i, j, k) in idx: from ideal_poly_volume_toolkit.geometry import triangle_volume_from_points_torch total = total + triangle_volume_from_points_torch( Z_t[i], Z_t[j], Z_t[k], series_terms=96 ) loss = -total loss.backward() torch.nn.utils.clip_grad_norm_([real_parts, imag_parts], max_norm=10.0) return loss opt.step(closure) with torch.no_grad(): Zf = build_Z_free(real_parts, imag_parts).detach().cpu().numpy() return Zf, idx # Get the configuration z_points, triangulation = get_maximal_config() # Visualize in complex plane plt.figure(figsize=(10, 10)) # Plot points real_coords = z_points.real imag_coords = z_points.imag plt.scatter(real_coords, imag_coords, s=200, c='red', zorder=5) # Label points for i, z in enumerate(z_points): offset = 0.15 plt.annotate(f'{i}', (z.real + offset, z.imag + offset), fontsize=12) # Draw Delaunay triangles for tri in triangulation: triangle_x = [real_coords[tri[j]] for j in range(3)] + [real_coords[tri[0]]] triangle_y = [imag_coords[tri[j]] for j in range(3)] + [imag_coords[tri[0]]] plt.plot(triangle_x, triangle_y, 'b-', linewidth=1.5, alpha=0.7) plt.xlabel('Real', fontsize=14) plt.ylabel('Imaginary', fontsize=14) plt.title('Maximal 12-vertex Configuration (Volume = 13.032)\nDifferent combinatorial type than icosahedron!', fontsize=16) plt.grid(True, alpha=0.3) plt.axis('equal') plt.tight_layout() plt.savefig('maximal_12vertex_plane.png', dpi=150, bbox_inches='tight') print("Saved: maximal_12vertex_plane.png") # Analyze the sphere structure z_with_inf = np.append(z_points, [np.inf]) sphere_points = lift_to_sphere_with_inf(z_with_inf) hull = ConvexHull(sphere_points) # Find which vertices have degree 4 and 6 vertex_degrees = {} for i in range(12): degree = sum(1 for face in hull.simplices if i in face) vertex_degrees[i] = degree print("\nVertex degrees in detail:") deg_4_vertices = [v for v, d in vertex_degrees.items() if d == 4] deg_5_vertices = [v for v, d in vertex_degrees.items() if d == 5] deg_6_vertices = [v for v, d in vertex_degrees.items() if d == 6] print(f"Degree 4 vertices: {deg_4_vertices}") print(f"Degree 5 vertices: {deg_5_vertices}") print(f"Degree 6 vertices: {deg_6_vertices}") # Map back to complex plane print("\nSpecial vertices in complex plane:") for v in deg_4_vertices: if v < 11: print(f" Vertex {v} (deg 4): z = {z_points[v]:.4f}") else: print(f" Vertex {v} (deg 4): infinity") for v in deg_6_vertices: if v < 11: print(f" Vertex {v} (deg 6): z = {z_points[v]:.4f}") else: print(f" Vertex {v} (deg 6): infinity") print(f"\nThis polyhedron has the same number of faces (20) as the icosahedron,") print(f"but a different combinatorial structure!") print(f"It's a non-regular ideal polyhedron with 12 vertices.") plt.close()