Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| Optimize ideal polyhedron volume for 7 vertices. | |
| User hypothesis: Maximum might be octahedron with one stellated face. | |
| """ | |
| import numpy as np | |
| import torch | |
| from ideal_poly_volume_toolkit.geometry import ( | |
| delaunay_triangulation_indices, | |
| triangle_volume_from_points_torch, | |
| ) | |
| from scipy.optimize import differential_evolution | |
| import time | |
| def spherical_to_complex(theta, phi): | |
| """Convert spherical coordinates to complex via stereographic projection.""" | |
| return np.tan(theta/2) * np.exp(1j * phi) | |
| def compute_volume_numpy(params): | |
| """Compute volume for numpy array input.""" | |
| # First 3 points fixed to break symmetry | |
| z1 = complex(0, 0) | |
| z2 = complex(1, 0) | |
| # Other 4 points from parameters (spherical coords) | |
| complex_points = [z1, z2] | |
| for i in range(4): | |
| theta = params[2*i] | |
| phi = params[2*i + 1] | |
| z = spherical_to_complex(theta, phi) | |
| complex_points.append(z) | |
| # Convert to numpy array | |
| Z_np = np.array(complex_points, dtype=np.complex128) | |
| # Delaunay triangulation | |
| try: | |
| idx = delaunay_triangulation_indices(Z_np) | |
| except: | |
| return 1000.0 # Penalty for degenerate configuration | |
| # Convert to torch for volume computation | |
| Z_torch = torch.tensor(Z_np, dtype=torch.complex128) | |
| # Compute total volume | |
| total_volume = 0 | |
| for (i, j, k) in idx: | |
| try: | |
| vol = triangle_volume_from_points_torch(Z_torch[i], Z_torch[j], Z_torch[k], series_terms=96) | |
| total_volume += vol.item() | |
| except: | |
| return 1000.0 # Penalty for invalid configuration | |
| return -total_volume # Negative for minimization | |
| def analyze_hull_structure(Z_np, idx): | |
| """Analyze the combinatorial structure of the triangulation.""" | |
| n_vertices = len(Z_np) | |
| n_faces = len(idx) | |
| # Count edges | |
| edges = set() | |
| for (i, j, k) in idx: | |
| edges.add((min(i,j), max(i,j))) | |
| edges.add((min(i,k), max(i,k))) | |
| edges.add((min(j,k), max(j,k))) | |
| n_edges = len(edges) | |
| # Vertex degrees | |
| vertex_degrees = [0] * n_vertices | |
| for edge in edges: | |
| vertex_degrees[edge[0]] += 1 | |
| vertex_degrees[edge[1]] += 1 | |
| # Classify polyhedron | |
| polyhedron_type = "Unknown" | |
| if n_vertices == 6 and n_faces == 8: | |
| polyhedron_type = "Octahedron" | |
| elif n_vertices == 7 and n_faces == 10: | |
| polyhedron_type = "Pentagonal bipyramid" | |
| elif n_vertices == 7 and n_faces == 9: | |
| polyhedron_type = "Stellated octahedron (likely)" | |
| return { | |
| 'n_vertices': n_vertices, | |
| 'n_faces': n_faces, | |
| 'n_edges': n_edges, | |
| 'vertex_degrees': sorted(vertex_degrees), | |
| 'triangles': idx, | |
| 'polyhedron_type': polyhedron_type | |
| } | |
| # Run optimization with multiple random starts | |
| print("Optimizing 7-vertex ideal polyhedron volume...") | |
| print("="*70) | |
| best_volume = 0 | |
| best_params = None | |
| best_hull_info = None | |
| best_complex_points = None | |
| n_trials = 20 | |
| for trial in range(n_trials): | |
| print(f"\nTrial {trial+1}/{n_trials}...") | |
| # Bounds: theta in (0, pi), phi in [0, 2*pi) | |
| bounds = [(0.1, np.pi-0.1), (0, 2*np.pi)] * 4 | |
| result = differential_evolution( | |
| compute_volume_numpy, | |
| bounds, | |
| maxiter=500, | |
| popsize=30, | |
| polish=True, | |
| workers=1, | |
| seed=42 + trial * 13 | |
| ) | |
| volume = -result.fun | |
| if volume > best_volume: | |
| best_volume = volume | |
| best_params = result.x | |
| # Reconstruct best configuration for analysis | |
| z1 = complex(0, 0) | |
| z2 = complex(1, 0) | |
| complex_points = [z1, z2] | |
| for i in range(4): | |
| theta = best_params[2*i] | |
| phi = best_params[2*i + 1] | |
| z = spherical_to_complex(theta, phi) | |
| complex_points.append(z) | |
| Z_np = np.array(complex_points, dtype=np.complex128) | |
| try: | |
| idx = delaunay_triangulation_indices(Z_np) | |
| except: | |
| continue # Skip degenerate configurations | |
| best_hull_info = analyze_hull_structure(Z_np, idx) | |
| best_complex_points = complex_points | |
| print(f" Volume: {volume:.6f}") | |
| print("\n" + "="*70) | |
| print("RESULTS:") | |
| print("="*70) | |
| print(f"Best volume found: {best_volume:.6f}") | |
| # Analyze the best configuration | |
| if best_hull_info: | |
| print(f"\nCombinatorial structure:") | |
| print(f" Vertices: {best_hull_info['n_vertices']}") | |
| print(f" Triangular faces: {best_hull_info['n_faces']}") | |
| print(f" Edges: {best_hull_info['n_edges']}") | |
| print(f" Vertex degrees: {best_hull_info['vertex_degrees']}") | |
| print(f" Classification: {best_hull_info['polyhedron_type']}") | |
| # Print configuration details | |
| print(f"\nVertex configuration:") | |
| for i, z in enumerate(best_complex_points): | |
| print(f" z[{i}] = {z.real:.4f} + {z.imag:.4f}i") | |
| # Save configuration | |
| np.savez('optimal_7vertex.npz', | |
| params=best_params, | |
| volume=best_volume, | |
| hull_info=best_hull_info, | |
| complex_points=best_complex_points) | |
| print(f"\nConfiguration saved to optimal_7vertex.npz") | |
| # Compare with regular octahedron | |
| regular_octahedron_vol = 5.3333 # Approximate | |
| print(f"\nComparison:") | |
| print(f" Regular octahedron (6 vertices): ≈ {regular_octahedron_vol:.4f}") | |
| print(f" Optimal 7-vertex configuration: {best_volume:.6f}") | |
| if best_volume > regular_octahedron_vol: | |
| print(f" ✓ 7-vertex configuration exceeds regular octahedron by {(best_volume/regular_octahedron_vol - 1)*100:.1f}%") | |
| else: | |
| print(f" Regular octahedron is {(regular_octahedron_vol/best_volume - 1)*100:.1f}% larger") |