Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| Check arithmeticity of local maxima found during 20-vertex optimization. | |
| Tests the conjecture that local maxima are more likely to be arithmetic. | |
| """ | |
| import numpy as np | |
| import json | |
| import os | |
| from scipy.spatial import Delaunay | |
| from ideal_poly_volume_toolkit.rivin_holonomy import Triangulation, generators_from_triangulation | |
| def build_triangulation_from_config(vertices_dict): | |
| """Convert vertex configuration to triangulation for holonomy computation.""" | |
| # Extract finite vertices (excluding infinity) | |
| vertices = [] | |
| for k, v in sorted(vertices_dict.items()): | |
| if k != 'z_inf': | |
| vertices.append(complex(v['real'], v['imag'])) | |
| # Convert to 2D points | |
| points_2d = np.array([[v.real, v.imag] for v in vertices]) | |
| # Get Delaunay triangulation | |
| tri = Delaunay(points_2d) | |
| triangles = tri.simplices | |
| # Build adjacency structure | |
| F = len(triangles) | |
| adjacency = {} | |
| edge_id_map = {} | |
| edge_id = 0 | |
| 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])) | |
| 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]): | |
| 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 and orientation | |
| order = {t: [0, 1, 2] for t in range(F)} | |
| orientation = {} | |
| for edge, eid in edge_id_map.items(): | |
| for (t, s), (u, su, e) in adjacency.items(): | |
| if e == eid: | |
| orientation[eid] = ((t, s), (u, su)) | |
| break | |
| return Triangulation(F, adjacency, order, orientation), triangles | |
| def check_arithmeticity(config): | |
| """Check if a configuration has arithmetic holonomy.""" | |
| try: | |
| T, triangles = build_triangulation_from_config(config['vertices']) | |
| # Zero shears for ideal polyhedra | |
| Z = {eid: 0.0 for eid in range(len(T.Ori))} | |
| # Compute generators | |
| gens = generators_from_triangulation(T, Z, root=0) | |
| # Extract traces | |
| traces = [] | |
| integral_traces = 0 | |
| close_to_algebraic = 0 | |
| 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) | |
| if abs(trace - nearest_int) < 0.001: | |
| integral_traces += 1 | |
| # Check proximity to simple algebraic numbers | |
| # (e.g., ±√2, ±√3, golden ratio, etc.) | |
| algebraic_values = [ | |
| np.sqrt(2), -np.sqrt(2), np.sqrt(3), -np.sqrt(3), | |
| (1 + np.sqrt(5))/2, (1 - np.sqrt(5))/2, # golden ratio | |
| np.sqrt(5), -np.sqrt(5) | |
| ] | |
| for alg in algebraic_values: | |
| if abs(trace - alg) < 0.001: | |
| close_to_algebraic += 1 | |
| break | |
| # Analyze trace field | |
| all_integral = (integral_traces == len(traces)) | |
| mostly_integral = (integral_traces >= len(traces) * 0.8) | |
| has_algebraic = (close_to_algebraic > 0) | |
| return { | |
| 'traces': traces, | |
| 'num_generators': len(traces), | |
| 'integral_traces': integral_traces, | |
| 'all_integral': all_integral, | |
| 'mostly_integral': mostly_integral, | |
| 'has_algebraic': has_algebraic, | |
| 'likely_arithmetic': all_integral or (mostly_integral and has_algebraic) | |
| } | |
| except Exception as e: | |
| return { | |
| 'error': str(e), | |
| 'likely_arithmetic': False | |
| } | |
| def analyze_all_local_maxima(): | |
| """Analyze all saved local maxima for arithmeticity.""" | |
| # Check if local maxima file exists | |
| if not os.path.exists('20vertex_local_maxima.json'): | |
| print("No local maxima file found yet. Waiting for optimization to save some...") | |
| return | |
| with open('20vertex_local_maxima.json', 'r') as f: | |
| data = json.load(f) | |
| print(f"\n{'='*70}") | |
| print("ARITHMETICITY ANALYSIS OF LOCAL MAXIMA") | |
| print(f"{'='*70}") | |
| print(f"Found {data['local_maxima_count']} local maxima to analyze\n") | |
| arithmetic_count = 0 | |
| results = [] | |
| for i, config in enumerate(data['configurations']): | |
| print(f"\nConfiguration {i+1}:") | |
| print(f" Volume: {config['volume']:.8f}") | |
| print(f" Ratio to dodecahedron: {config['volume']/data['dodecahedron_volume']:.6f}") | |
| arith_result = check_arithmeticity(config) | |
| if 'error' in arith_result: | |
| print(f" Error in analysis: {arith_result['error']}") | |
| else: | |
| print(f" Generators: {arith_result['num_generators']}") | |
| print(f" Integral traces: {arith_result['integral_traces']}/{arith_result['num_generators']}") | |
| print(f" Traces: {[f'{t:.6f}' for t in arith_result['traces']]}") | |
| if arith_result['likely_arithmetic']: | |
| print(f" *** LIKELY ARITHMETIC! ***") | |
| arithmetic_count += 1 | |
| results.append({ | |
| 'volume': config['volume'], | |
| 'arithmetic': arith_result.get('likely_arithmetic', False), | |
| 'traces': arith_result.get('traces', []) | |
| }) | |
| # Summary | |
| print(f"\n{'='*70}") | |
| print("SUMMARY:") | |
| print(f"{'='*70}") | |
| print(f"Total local maxima analyzed: {len(data['configurations'])}") | |
| print(f"Likely arithmetic: {arithmetic_count} ({arithmetic_count/len(data['configurations'])*100:.1f}%)") | |
| # Save results | |
| output = { | |
| 'analysis_date': str(datetime.now()), | |
| 'local_maxima_count': len(data['configurations']), | |
| 'arithmetic_count': arithmetic_count, | |
| 'results': results, | |
| 'conjecture_support': arithmetic_count > len(data['configurations']) * 0.5 | |
| } | |
| with open('20vertex_arithmetic_analysis.json', 'w') as f: | |
| json.dump(output, f, indent=2) | |
| print(f"\nResults saved to 20vertex_arithmetic_analysis.json") | |
| if output['conjecture_support']: | |
| print("\n*** CONJECTURE SUPPORTED: Majority of local maxima appear arithmetic! ***") | |
| else: | |
| print("\n*** More data needed to support conjecture ***") | |
| if __name__ == "__main__": | |
| from datetime import datetime | |
| analyze_all_local_maxima() |