Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
File size: 6,926 Bytes
f9b644c d7d27f0 f9b644c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
#!/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() |