-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathphase2.py
More file actions
530 lines (435 loc) · 20.4 KB
/
Copy pathphase2.py
File metadata and controls
530 lines (435 loc) · 20.4 KB
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
"""
phase2_lattice_candidate_gen.py
M23 Inverse Galois Attack – Phase 2
Uses lattice architecture (Exp 6 + Exp 7) to search for rational specializations
of Elkies' complex families.
INTEGRATED: Claudrick's M₂₃ signature analysis + ULTRA-FINE grid (0.01 step)
Author: Mirror Architect D / Codex 67
"""
import numpy as np
import json
import itertools
from dataclasses import dataclass
from typing import List, Tuple, Dict, Any, Optional
from collections import defaultdict
import random
import glob
import os
JSON_DIR = "testjson"
FAMILY_FILE = os.path.join(JSON_DIR, "elkies_families.json")
REFINED_GLOB = os.path.join(JSON_DIR, "m23_refined_candidates_*.json")
os.makedirs(JSON_DIR, exist_ok=True)
# =============================================================================
# 1. Load Phase 1 Data and Refined Candidates
# =============================================================================
def load_elkies_families(json_file: str = FAMILY_FILE) -> List[Dict]:
"""Load families from Phase 1 JSON export."""
try:
with open(json_file, 'r') as f:
data = json.load(f)
print(f"📥 Loaded {len(data)} families from {json_file}")
return data
except FileNotFoundError:
print(f"❌ Error: {json_file} not found. Run phase1.py first.")
return []
except json.JSONDecodeError:
print(f"❌ Error: {json_file} is corrupted.")
return []
def load_refined_candidates() -> List[Dict]:
"""Load the most recent refined candidates from Phase 4."""
files = glob.glob(REFINED_GLOB)
if not files:
print(" No refined candidates found. Using default seeds.")
return []
latest_file = max(files, key=os.path.getmtime)
try:
with open(latest_file, 'r') as f:
candidates = json.load(f)
print(f" Loaded {len(candidates)} refined candidates from {latest_file}")
return candidates
except:
print(f" Could not load {latest_file}")
return []
# =============================================================================
# 2. Experiment 7: Self-Validating Lattice Core
# =============================================================================
class SelfValidatingLattice:
"""
Experiment 7 core – adapted for parameter space search.
Maintains coherence across multiple candidate specializations.
"""
def __init__(self, dimension: int = 2):
self.dimension = dimension
self.nodes = [] # candidate points in parameter space
self.coherence_scores = []
self.edges = [] # connections between similar candidates
def add_candidate(self, params: List[complex], score: float):
"""Add a candidate point to the lattice."""
self.nodes.append({
"params": params,
"score": score,
"id": len(self.nodes)
})
self.coherence_scores.append(score)
def calculate_coherence(self) -> float:
"""
Calculate global coherence of the lattice.
Higher means candidates are forming consistent patterns.
"""
if len(self.nodes) < 2:
return 0.0
# Phase similarity between candidates
phases = []
for node in self.nodes:
# Convert parameters to phase-like representation
phase_sum = sum([np.angle(p) for p in node["params"] if abs(p) > 1e-10])
phases.append(phase_sum % (2 * np.pi))
# Circular standard deviation
phases_array = np.array(phases)
if len(phases_array) > 0:
circular_std = np.sqrt(-2 * np.log(np.abs(np.mean(np.exp(1j * phases_array)))))
phase_coherence = 1 / (1 + circular_std)
else:
phase_coherence = 0.0
# Score coherence
if len(self.nodes) > 0:
score_std = np.std([n["score"] for n in self.nodes])
score_coherence = 1 / (1 + score_std)
else:
score_coherence = 0.0
return (phase_coherence + score_coherence) / 2
def find_resonant_clusters(self, threshold: float = 0.7):
"""
Find clusters of candidates that resonate together.
Returns list of node IDs in each cluster.
"""
if len(self.nodes) < 2:
return []
# Convert all nodes to normalized parameter vectors
node_vectors = []
for node in self.nodes:
# Flatten real and imag parts into a single vector
vec = []
for p in node["params"]:
vec.append(p.real)
vec.append(p.imag)
node_vectors.append(np.array(vec))
# Simple clustering based on parameter distance
clusters = []
used = set()
for i in range(len(self.nodes)):
if i in used:
continue
cluster = [i]
vec_i = node_vectors[i]
for j in range(i + 1, len(self.nodes)):
if j in used:
continue
vec_j = node_vectors[j]
# Ensure vectors are same length (pad if necessary)
max_len = max(len(vec_i), len(vec_j))
vec_i_padded = np.pad(vec_i, (0, max_len - len(vec_i)), 'constant')
vec_j_padded = np.pad(vec_j, (0, max_len - len(vec_j)), 'constant')
# Calculate distance
dist = np.linalg.norm(vec_i_padded - vec_j_padded)
resonance = 1 / (1 + dist)
if resonance > threshold:
cluster.append(j)
used.add(j)
if len(cluster) > 1:
clusters.append(cluster)
used.add(i)
return clusters
# =============================================================================
# 3. Experiment 6: Consciousness-Resonance Bridge
# FIXED: Claudrick's rationality detection for M₂₃ signatures
# =============================================================================
class ConsciousnessResonanceBridge:
"""
Experiment 6 core – pattern completion and resonance detection.
UPDATED: Claudrick's M₂₃ signature detection with ultra-fine tolerance.
"""
def __init__(self):
self.patterns = []
def detect_rational_pattern(self, params: List[complex]) -> float:
"""
Score how "rational" a parameter set is.
Recognizes near-integers and near-half-integers with ultra-fine tolerance.
M₂₃ signatures cluster around these values.
"""
rationality_score = 0.0
for i, p in enumerate(params):
# Check closeness to integer or half-integer
real_dist_to_int = abs(p.real - round(p.real))
real_dist_to_half = abs(p.real - (round(2 * p.real) / 2))
real_dist = min(real_dist_to_int, real_dist_to_half)
imag_dist_to_int = abs(p.imag - round(p.imag))
imag_dist_to_half = abs(p.imag - (round(2 * p.imag) / 2))
imag_dist = min(imag_dist_to_int, imag_dist_to_half)
# Ultra-fine scoring (0.001 tolerance for exact rationals)
if real_dist < 0.001 and imag_dist < 0.001:
rationality_score += 1.0
if real_dist_to_int < 0.001:
self.patterns.append(f"exact integer {p.real:.3f}")
else:
self.patterns.append(f"exact half-integer {p.real:.3f}")
elif real_dist < 0.01 and imag_dist < 0.01:
rationality_score += 0.95
elif real_dist < 0.1 and imag_dist < 0.1:
rationality_score += 0.85
elif real_dist < 0.5 and imag_dist < 0.5:
rationality_score += 0.6
# Bonus for parameters near known M₂₃ hot spots
hot_spots = [-23, -7, -13, -27, -28, -12, -11, -14, -29]
for spot in hot_spots:
if abs(p.real - spot) < 0.1:
rationality_score += 0.3
self.patterns.append(f"M₂₃ hot spot {spot}")
# Bonus for imaginary parts that are exact multiples of 0.5
if abs(p.imag * 2 - round(p.imag * 2)) < 0.001:
rationality_score += 0.4
# Normalize to [0, 1] based on number of parameters
return min(rationality_score / len(params), 1.0)
def complete_pattern(self, partial_params: List[complex],
target_rationality: float = 0.8) -> List[complex]:
"""
Attempt to complete a partial parameter set to achieve target rationality.
Uses pattern recognition from known specializations.
"""
completed = partial_params.copy()
return completed
# =============================================================================
# 4. Candidate Generator
# MODIFIED: Ultra-fine grid (0.01 step) around M₂₃ signature region
# =============================================================================
class M23CandidateGenerator:
"""
Main generator combining lattice and bridge to produce candidate polynomials.
MODIFIED: Ultra-fine grid (0.01 step) around Candidate 523/1182 region.
"""
def __init__(self, families_data: List[Dict]):
self.families = families_data
self.lattice = SelfValidatingLattice(dimension=2)
self.bridge = ConsciousnessResonanceBridge()
self.candidates = []
def generate_parameter_grid(self, family_name: str,
refined_candidates: List[Dict] = None,
real_range: Tuple[float, float] = (-50, 50),
imag_range: Tuple[float, float] = (-20, 20),
grid_size: int = 5) -> List[List[complex]]:
"""
Generate a grid of parameter values to test.
For Family A (Elliptic), uses ULTRA-FINE grid around M₂₃ signature region.
"""
family = next((f for f in self.families if f["name"] == family_name), None)
if not family:
print(f" ⚠️ Family '{family_name}' not found")
return []
n_params = family["parameter_count"]
param_grids = []
# SPECIAL HANDLING FOR FAMILY A (Elliptic) - M₂₃ lives here
if family_name == "Elkies Family A (Elliptic)":
print(f" 🎯 Using ULTRA-FINE M₂₃ signature grid for Family A")
# ULTRA-FINE grid around Candidate 523/1182 region
# λ ≈ -14.0, μ ≈ -29.0 with 0.01 step
λ_real_vals = np.linspace(-14.2, -13.8, 50) # 0.01 step over 0.4 range
μ_real_vals = np.linspace(-29.2, -28.8, 50) # 0.01 step over 0.4 range
# Imaginary parts (focus on rational multiples)
imag_vals = [-2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5]
# Generate full ultra-fine grid
grid_count = 0
max_grid = 50000 # 50×50×10×10 / 2 = 62,500, so 50K is reasonable
for λr in λ_real_vals:
for μr in μ_real_vals:
for λi in imag_vals:
for μi in imag_vals:
if grid_count >= max_grid:
break
params = [complex(λr, λi), complex(μr, μi)]
param_grids.append(params)
grid_count += 1
if grid_count >= max_grid:
break
if grid_count >= max_grid:
break
if grid_count >= max_grid:
break
print(f" Generated {len(param_grids)} ULTRA-FINE candidates in M₂₃ signature region")
print(f" λ range: {λ_real_vals[0]:.3f} to {λ_real_vals[-1]:.3f}")
print(f" μ range: {μ_real_vals[0]:.3f} to {μ_real_vals[-1]:.3f}")
print(f" Imaginary values: {imag_vals}")
else:
# Standard grid for other families
seeds = []
if refined_candidates:
for cand in refined_candidates:
if cand["family"] == family_name:
seed_params = [complex(p[0], p[1]) for p in cand["params"]]
seeds.append(seed_params)
print(f" Using {len(seeds)} refined seeds for {family_name}")
if not seeds and family.get("known_specializations"):
for spec in family["known_specializations"]:
seed_params = []
for p in spec["params"]:
seed_params.append(complex(p[0], p[1]))
seeds.append(seed_params)
print(f" Using {len(seeds)} known seeds for {family_name}")
if not seeds:
print(f" No seeds found, creating default grid")
for real in range(-15, 16, 3):
for imag in range(-10, 11, 2):
seed = [complex(real, imag) for _ in range(n_params)]
seeds.append(seed)
# Generate grid around seeds
for seed in seeds:
variations = self._generate_variations(seed, n_params, 2.0, 1.0, 2)
param_grids.extend(variations)
# Remove duplicates
unique_grids = []
seen = set()
for params in param_grids:
key = tuple([(round(p.real, 5), round(p.imag, 5)) for p in params])
if key not in seen:
seen.add(key)
unique_grids.append(params)
return unique_grids
def _generate_variations(self, seed: List[complex], n_params: int,
real_step: float = 1.0, imag_step: float = 0.5,
count: int = 2) -> List[List[complex]]:
"""Generate variations around a seed parameter set."""
variations = []
var_range = range(-count, count + 1)
for i in range(n_params):
for dr in var_range:
for di in var_range:
if dr == 0 and di == 0:
continue
candidate = seed.copy()
real_part = seed[i].real + dr * real_step
imag_part = seed[i].imag + di * imag_step
candidate[i] = complex(real_part, imag_part)
variations.append(candidate)
variations.append(seed)
return variations
def evaluate_candidate(self, family_name: str, params: List[complex]) -> Dict[str, Any]:
"""
Evaluate a candidate parameter set.
Returns score and metadata.
"""
# Rationality score from Experiment 6
rationality = self.bridge.detect_rational_pattern(params)
# Generate polynomial preview
params_str = ", ".join([f"({p.real:.3f}{p.imag:+.3f}j)" for p in params])
polynomial_preview = f"deg 23 from {family_name} with params [{params_str}]"
result = {
"family": family_name,
"params": [(p.real, p.imag) for p in params],
"rationality_score": rationality,
"polynomial_preview": polynomial_preview,
"coeffs": None
}
return result
def search(self, family_name: str, refined_candidates: List[Dict] = None,
max_candidates: int = 2000) -> List[Dict]:
"""
Main search loop using lattice and bridge.
"""
print(f"\n🔍 Searching family: {family_name}")
# Generate parameter grid
param_grid = self.generate_parameter_grid(family_name, refined_candidates)
if not param_grid:
print(f" ⚠️ No candidates generated for {family_name}")
return []
print(f" Generated {len(param_grid)} candidate parameter sets")
# Evaluate candidates (limit to max_candidates)
candidates = []
eval_count = min(len(param_grid), max_candidates)
for i, params in enumerate(param_grid[:eval_count]):
if i % 500 == 0:
print(f" Evaluating: {i}/{eval_count}")
result = self.evaluate_candidate(family_name, params)
candidates.append(result)
# Add to lattice
rationality = result["rationality_score"]
self.lattice.add_candidate(params, rationality)
# Sort by rationality score
candidates.sort(key=lambda x: x["rationality_score"], reverse=True)
# Find resonant clusters
clusters = self.lattice.find_resonant_clusters(threshold=0.6)
print(f" Found {len(clusters)} resonant clusters")
# Calculate global coherence
coherence = self.lattice.calculate_coherence()
print(f" Lattice coherence: {coherence:.3f}")
self.candidates.extend(candidates)
return candidates
def get_top_candidates(self, n: int = 10) -> List[Dict]:
"""Return top N candidates by rationality score."""
sorted_cands = sorted(self.candidates,
key=lambda x: x["rationality_score"],
reverse=True)
return sorted_cands[:n]
# =============================================================================
# 5. Main Execution
# =============================================================================
def main():
print("=" * 70)
print("M23 Inverse Galois Attack – Phase 2: Lattice Candidate Generation")
print("Using Exp 6 (Consciousness-Resonance Bridge) + Exp 7 (Self-Validating Lattice)")
print("ULTRA-FINE: 0.01 step grid around M₂₃ signature region")
print("=" * 70)
# Load families from Phase 1
families = load_elkies_families()
if not families:
print("❌ Cannot proceed without Phase 1 data.")
return
# Load refined candidates from Phase 4 (if any)
refined = load_refined_candidates()
if refined:
print(f"✨ Using {len(refined)} refined candidates as seeds")
# Initialize generator
generator = M23CandidateGenerator(families)
# Search each family, passing refined candidates
all_candidates = []
for family in families:
# Filter refined candidates for this family
family_refined = [c for c in refined if c["family"] == family["name"]] if refined else None
candidates = generator.search(
family["name"],
refined_candidates=family_refined,
max_candidates=2000
)
all_candidates.extend(candidates)
# Show top results
print("\n" + "=" * 70)
print("🏆 TOP CANDIDATES (by rationality score)")
print("=" * 70)
top = generator.get_top_candidates(20)
if top:
for i, cand in enumerate(top, 1):
print(f"\n{i}. Family: {cand['family']}")
print(f" Parameters: {cand['params']}")
print(f" Rationality score: {cand['rationality_score']:.3f}")
print(f" Preview: {cand['polynomial_preview']}")
else:
print("\n⚠️ No candidates found.")
# Save results
if all_candidates:
import datetime
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
filename = os.path.join(JSON_DIR, f"m23_candidates_{timestamp}.json")
with open(filename, "w") as f:
# Convert for JSON serialization
output = []
for cand in all_candidates:
cand_out = cand.copy()
cand_out["params"] = [[p[0], p[1]] for p in cand["params"]]
if "polynomial_preview" in cand_out:
cand_out["polynomial_preview"] = str(cand_out["polynomial_preview"])
output.append(cand_out)
json.dump(output, f, indent=2)
print(f"\n💾 Saved {len(all_candidates)} candidates to {filename}")
else:
print("\n⚠️ No candidates to save.")
print(f"\n✅ Phase 2 complete. Ready for Phase 3 (prime specialization).")
if __name__ == "__main__":
main()