Spaces:
Sleeping
Sleeping
| import numpy as np | |
| import json | |
| from scipy.spatial import Delaunay | |
| from ideal_poly_volume_toolkit.rivin_holonomy import Triangulation, generators_from_triangulation | |
| def compute_holonomy_traces(vertices_complex, triangles): | |
| """ | |
| Compute holonomy generators and their traces for an ideal polyhedron. | |
| Returns traces and checks if they're close to integers. | |
| """ | |
| # Convert complex vertices to 2D points for triangulation | |
| vertices_2d = np.array([[z['real'], z['imag']] for z in vertices_complex if isinstance(z, dict)]) | |
| # Build adjacency structure from Delaunay triangulation | |
| F = len(triangles) # number of triangles | |
| adjacency = {} | |
| edge_id_map = {} | |
| edge_id = 0 | |
| # Build adjacency between triangles | |
| for i, tri_i in enumerate(triangles): | |
| for side_i in range(3): | |
| v1_i, v2_i = tri_i[side_i], tri_i[(side_i + 1) % 3] | |
| edge = tuple(sorted([v1_i, v2_i])) | |
| # Find matching triangle | |
| for j, tri_j in enumerate(triangles): | |
| if i == j: | |
| continue | |
| for side_j in range(3): | |
| v1_j, v2_j = tri_j[side_j], tri_j[(side_j + 1) % 3] | |
| if set([v1_j, v2_j]) == set([v1_i, v2_i]): | |
| # Found matching edge | |
| if (i, side_i) not in adjacency: | |
| if edge not in edge_id_map: | |
| edge_id_map[edge] = edge_id | |
| edge_id += 1 | |
| adjacency[(i, side_i)] = (j, side_j, edge_id_map[edge]) | |
| # Define order (counterclockwise) for each triangle | |
| order = {t: [0, 1, 2] for t in range(F)} | |
| # Define orientations for edges | |
| orientation = {} | |
| for edge, eid in edge_id_map.items(): | |
| # Find triangles containing this edge | |
| for (t, s), (u, su, e) in adjacency.items(): | |
| if e == eid: | |
| orientation[eid] = ((t, s), (u, su)) | |
| break | |
| # Create triangulation object | |
| T = Triangulation(F, adjacency, order, orientation) | |
| # Zero shears (ideal polyhedra have no shearing) | |
| Z = {eid: 0.0 for eid in range(edge_id)} | |
| # Compute generators | |
| gens = generators_from_triangulation(T, Z, root=0) | |
| # Extract traces | |
| traces = [] | |
| trace_analysis = [] | |
| print(f"\nHolonomy analysis for {F} triangles:") | |
| print("-" * 70) | |
| print(f"Number of generators: {len(gens)}") | |
| print("\nTraces of holonomy generators:") | |
| for i, (u, v, tokens, M) in enumerate(gens): | |
| trace = M[0][0] + M[1][1] | |
| traces.append(trace) | |
| # Check proximity to integers | |
| nearest_int = round(trace) | |
| distance = abs(trace - nearest_int) | |
| is_close = distance < 0.01 | |
| trace_analysis.append({ | |
| 'generator': i, | |
| 'edge': (u, v), | |
| 'trace': trace, | |
| 'nearest_integer': nearest_int, | |
| 'distance': distance, | |
| 'possibly_integral': is_close | |
| }) | |
| print(f" Generator {i} (edge {u}-{v}): trace = {trace:.6f}") | |
| print(f" Nearest integer: {nearest_int}, distance: {distance:.6f}") | |
| if is_close: | |
| print(f" *** CLOSE TO INTEGER! ***") | |
| return traces, trace_analysis | |
| # Load optimal configurations | |
| with open('optimal_configurations.json', 'r') as f: | |
| data = json.load(f) | |
| print("="*70) | |
| print("ARITHMETICITY CHECK FOR MAXIMAL IDEAL POLYHEDRA") | |
| print("="*70) | |
| # Check the maximal 8-vertex configuration | |
| print("\n1. MAXIMAL 8-VERTEX CONFIGURATION (volume = 6.488)") | |
| print("-"*70) | |
| config = data['discovered_configurations']['maximal_8vertex'] | |
| vertices = [] | |
| for k, v in config['vertices_complex'].items(): | |
| if isinstance(v, dict): | |
| vertices.append(v) | |
| triangles = config['delaunay_triangles'] | |
| traces1, analysis1 = compute_holonomy_traces(vertices, triangles) | |
| # Check for arithmetic patterns | |
| integral_count = sum(1 for a in analysis1 if a['possibly_integral']) | |
| print(f"\nSummary: {integral_count}/{len(analysis1)} traces are close to integers") | |
| # Check the golden ratio configuration | |
| print("\n\n2. GOLDEN RATIO 8-VERTEX CONFIGURATION (volume = 6.002)") | |
| print("-"*70) | |
| config = data['discovered_configurations']['golden_ratio_8vertex'] | |
| vertices = [] | |
| for k, v in config['vertices_complex'].items(): | |
| if isinstance(v, dict): | |
| vertices.append(v) | |
| triangles = config['delaunay_triangles'] | |
| traces2, analysis2 = compute_holonomy_traces(vertices, triangles) | |
| integral_count = sum(1 for a in analysis2 if a['possibly_integral']) | |
| print(f"\nSummary: {integral_count}/{len(analysis2)} traces are close to integers") | |
| # Check trace field generation | |
| print("\n\n3. TRACE FIELD ANALYSIS") | |
| print("-"*70) | |
| def analyze_trace_field(traces): | |
| """Check if traces generate an algebraic number field close to integers.""" | |
| # Look for algebraic relations | |
| products = [] | |
| sums = [] | |
| for i in range(len(traces)): | |
| for j in range(i, len(traces)): | |
| products.append(traces[i] * traces[j]) | |
| sums.append(traces[i] + traces[j]) | |
| all_values = traces + products + sums | |
| integral_values = [] | |
| for val in all_values: | |
| nearest = round(val) | |
| if abs(val - nearest) < 0.01: | |
| integral_values.append((val, nearest)) | |
| return integral_values | |
| print("\nMaximal configuration trace field:") | |
| integral_vals1 = analyze_trace_field(traces1) | |
| print(f"Found {len(integral_vals1)} values close to integers in trace field") | |
| print("\nGolden ratio configuration trace field:") | |
| integral_vals2 = analyze_trace_field(traces2) | |
| print(f"Found {len(integral_vals2)} values close to integers in trace field") | |
| print("\n\nCONCLUSION:") | |
| print("-"*70) | |
| print("If many traces are close to integers, the polyhedron may be arithmetic.") | |
| print("Arithmetic hyperbolic 3-manifolds have holonomies in PSL(2,O_K) where") | |
| print("O_K is the ring of integers in a number field K.") | |
| print("\nFor ideal polyhedra, arithmeticity would mean the configuration") | |
| print("has deep number-theoretic significance!") |