Repository navigation
Expand file tree
/
Copy pathseed_management.py
More file actions
715 lines (567 loc) · 25.3 KB
/
Copy pathseed_management.py
File metadata and controls
715 lines (567 loc) · 25.3 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
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
"""
TNFR Seed Management System
Comprehensive seed capture and reproducibility framework for factorization experiments.
Captures and restores the Python and legacy NumPy global RNG states and the
manager's component seeds. Environment and experiment parameters are recorded
for comparison; independent Generator instances, graph state, external library
RNGs and the recorded environment are not restored.
Design Principles:
1. Reproduce the captured global RNG continuations
2. Record the component seeds and environment used by an experiment
3. Serialize state for compatible Python and NumPy RNG implementations
4. Hierarchical seeding for multi-scale reproducibility
5. Audit trail for debugging non-deterministic issues
Mathematical Foundation:
- Deterministic evolution: EPI(t+dt) = f(EPI(t), seed_state)
- State reproducibility: Same supported RNG state → identical RNG continuation
- Hierarchical consistency: Master seed → component seeds → operation seeds
- Audit scope: Recorded seeds and observations do not trace every random operation
"""
import hashlib
import json
import os
import platform
import random
import sys
import time
from dataclasses import asdict, dataclass
from numbers import Integral
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
import numpy as np
_COMPONENT_SEEDS = (
"node_initialization",
"coupling_dynamics",
"phase_evolution",
"operator_sequence",
"global_network",
"partition_level",
"node_level",
"spectral_analysis",
"clustering",
"threshold_jitter",
)
@dataclass
class SystemEnvironment:
"""Capture of system environment affecting reproducibility."""
platform_system: str
platform_release: str
python_version: str
numpy_version: str
random_state_type: str
# Process information
process_id: int
working_directory: str
# Timing information
utc_timestamp: float
local_timezone: str
# Hardware fingerprint (for debugging)
cpu_count: int
memory_total_gb: Optional[float]
@dataclass
class RandomSeedState:
"""Complete random number generator state."""
# Python random module state
python_random_state: tuple
# NumPy random state
numpy_random_state: dict
# Custom TNFR seeds
master_seed: int
node_initialization_seed: int
coupling_dynamics_seed: int
phase_evolution_seed: int
operator_sequence_seed: int
# Hierarchical seeds for different scales
global_network_seed: int
partition_level_seed: int
node_level_seed: int
# Verification-specific seeds
spectral_analysis_seed: int
clustering_seed: int
threshold_jitter_seed: int
@dataclass
class ExperimentParameters:
"""Complete set of experiment parameters affecting results."""
# Primary factorization parameters
modulus_n: int
partition_strategy: str
verification_mode: str
# Network topology parameters
node_count: int
initial_topology: str
coupling_strength_range: Tuple[float, float]
# TNFR physics parameters
structural_frequency_range: Tuple[float, float]
phase_initialization_mode: str
coherence_threshold: float
dnfr_budget: float
# Algorithm parameters
max_iterations: int
convergence_tolerance: float
spectral_clustering_k: int
# Performance parameters
timeout_seconds: float
memory_limit_mb: int
# Advanced parameters
operator_sequence_constraints: List[str]
adaptive_threshold_enabled: bool
feedback_learning_enabled: bool
@dataclass
class ReproducibilityMetadata:
"""Metadata for experiment reproducibility."""
experiment_id: str
creation_timestamp: float
# Version information
tnfr_version: str
experiment_version: str
# Checksums for integrity
parameter_checksum: str
seed_state_checksum: str
environment_checksum: str
# Dependency tracking
dependencies: Dict[str, str]
# Execution metadata
execution_hostname: str
execution_user: Optional[str]
execution_duration_ms: float
class TNFRSeedManager:
"""Comprehensive seed management for TNFR experiments."""
def __init__(self, master_seed: Optional[int] = None):
"""Initialize seed manager with optional master seed."""
self.master_seed = (
self._generate_master_seed() if master_seed is None else master_seed
)
self.seed_history = []
self.current_experiment_id = None
# Initialize all RNG states from master seed
self._initialize_from_master_seed()
def _generate_master_seed(self) -> int:
"""Generate cryptographically secure master seed."""
# Combine multiple entropy sources
entropy_sources = [
int(time.time() * 1000000) % (2**31), # High-resolution timestamp
hash(str(os.urandom(16))) % (2**31), # OS random bytes
id(object()) % (2**31), # Memory address randomness
hash(platform.node()) % (2**31), # Machine identifier
]
# XOR combine entropy sources
master_seed = 0
for source in entropy_sources:
master_seed ^= source
# Ensure positive 32-bit integer
return abs(master_seed) % (2**31)
def _initialize_from_master_seed(self):
"""Initialize all RNG states from master seed using deterministic derivation."""
# Use master seed to derive component seeds
seed_generator = random.Random(self.master_seed)
# Derive hierarchical seeds
self.global_network_seed = seed_generator.randint(1, 2**30)
self.partition_level_seed = seed_generator.randint(1, 2**30)
self.node_level_seed = seed_generator.randint(1, 2**30)
# Derive process-specific seeds
self.node_initialization_seed = seed_generator.randint(1, 2**30)
self.coupling_dynamics_seed = seed_generator.randint(1, 2**30)
self.phase_evolution_seed = seed_generator.randint(1, 2**30)
self.operator_sequence_seed = seed_generator.randint(1, 2**30)
# Derive analysis seeds
self.spectral_analysis_seed = seed_generator.randint(1, 2**30)
self.clustering_seed = seed_generator.randint(1, 2**30)
self.threshold_jitter_seed = seed_generator.randint(1, 2**30)
# Set global random states
random.seed(self.master_seed)
np.random.seed(self.master_seed % (2**32)) # NumPy requires uint32
def capture_complete_state(self) -> Dict[str, Any]:
"""Capture supported RNG states, component seeds and environment metadata."""
# Capture environment
environment = self._capture_system_environment()
# Capture random states
seed_state = RandomSeedState(
python_random_state=random.getstate(),
numpy_random_state=self._get_numpy_state(),
master_seed=self.master_seed,
node_initialization_seed=self.node_initialization_seed,
coupling_dynamics_seed=self.coupling_dynamics_seed,
phase_evolution_seed=self.phase_evolution_seed,
operator_sequence_seed=self.operator_sequence_seed,
global_network_seed=self.global_network_seed,
partition_level_seed=self.partition_level_seed,
node_level_seed=self.node_level_seed,
spectral_analysis_seed=self.spectral_analysis_seed,
clustering_seed=self.clustering_seed,
threshold_jitter_seed=self.threshold_jitter_seed,
)
return {
"environment": asdict(environment),
"seed_state": asdict(seed_state),
"capture_timestamp": time.time(),
"master_seed": self.master_seed,
}
def restore_complete_state(self, state_data: Dict[str, Any]) -> bool:
"""Restore captured RNG state after validating it without live writes.
Both in-memory tuples and the lists produced by JSON are accepted.
Invalid payloads return False without changing manager or global RNGs.
This does not restore graph state or independently created generators.
"""
try:
seed_state = state_data["seed_state"]
master_seed = state_data["master_seed"]
if master_seed != seed_state["master_seed"]:
raise ValueError("master_seed disagrees with captured seed state")
seeds = {
name + "_seed": seed_state[name + "_seed"] for name in _COMPONENT_SEEDS
}
for value in (master_seed, *seeds.values()):
if isinstance(value, bool) or not isinstance(value, Integral):
raise ValueError("captured seeds must be integers")
version, internal, gaussian = seed_state["python_random_state"]
python_probe = random.Random()
python_probe.setstate((version, tuple(internal), gaussian))
numpy_probe = np.random.RandomState()
numpy_probe.set_state(
self._numpy_state_tuple(seed_state["numpy_random_state"])
)
except (KeyError, TypeError, ValueError, OverflowError) as e:
print(f"Failed to restore state: {e}")
return False
# Commit only states already accepted by independent instances of the
# same RNG implementations. No live state changes occur on rejection.
random.setstate(python_probe.getstate())
np.random.set_state(numpy_probe.get_state())
self.master_seed = master_seed
for name, value in seeds.items():
setattr(self, name, value)
return True
def create_experiment_context(
self,
experiment_params: ExperimentParameters,
experiment_id: Optional[str] = None,
) -> str:
"""Create reproducible experiment context with full state capture."""
# Generate experiment ID
if experiment_id is None:
experiment_id = self._generate_experiment_id(experiment_params)
self.current_experiment_id = experiment_id
# Capture complete state
complete_state = self.capture_complete_state()
# Create metadata
metadata = ReproducibilityMetadata(
experiment_id=experiment_id,
creation_timestamp=time.time(),
tnfr_version=self._get_tnfr_version(),
experiment_version="1.0",
parameter_checksum=self._compute_checksum(asdict(experiment_params)),
seed_state_checksum=self._compute_checksum(complete_state["seed_state"]),
environment_checksum=self._compute_checksum(complete_state["environment"]),
dependencies=self._get_dependency_versions(),
execution_hostname=platform.node(),
execution_user=os.getenv("USER") or os.getenv("USERNAME"),
execution_duration_ms=0.0, # Will be updated on completion
)
# Store experiment context
context_data = {
"metadata": asdict(metadata),
"parameters": asdict(experiment_params),
"reproducibility_state": complete_state,
}
self._store_experiment_context(experiment_id, context_data)
return experiment_id
def get_seeded_random(self, seed_type: str) -> random.Random:
"""Get seeded random generator for specific use case."""
seed_map = {
"node_initialization": self.node_initialization_seed,
"coupling_dynamics": self.coupling_dynamics_seed,
"phase_evolution": self.phase_evolution_seed,
"operator_sequence": self.operator_sequence_seed,
"global_network": self.global_network_seed,
"partition_level": self.partition_level_seed,
"node_level": self.node_level_seed,
"spectral_analysis": self.spectral_analysis_seed,
"clustering": self.clustering_seed,
"threshold_jitter": self.threshold_jitter_seed,
}
if seed_type not in seed_map:
raise ValueError(f"Unknown seed type: {seed_type}")
return random.Random(seed_map[seed_type])
def get_seeded_numpy_random(self, seed_type: str) -> np.random.Generator:
"""Get seeded NumPy random generator for specific use case."""
seed_map = {
"node_initialization": self.node_initialization_seed,
"coupling_dynamics": self.coupling_dynamics_seed,
"phase_evolution": self.phase_evolution_seed,
"operator_sequence": self.operator_sequence_seed,
"global_network": self.global_network_seed,
"partition_level": self.partition_level_seed,
"node_level": self.node_level_seed,
"spectral_analysis": self.spectral_analysis_seed,
"clustering": self.clustering_seed,
"threshold_jitter": self.threshold_jitter_seed,
}
if seed_type not in seed_map:
raise ValueError(f"Unknown seed type: {seed_type}")
seed = seed_map[seed_type] % (2**32) # NumPy requires uint32
return np.random.default_rng(seed)
def validate_reproducibility(
self, experiment_id: str, test_iterations: int = 3
) -> Dict[str, Any]:
"""Validate experiment reproducibility by running multiple times."""
# Load experiment context
context_data = self._load_experiment_context(experiment_id)
if not context_data:
return {"valid": False, "error": "Experiment context not found"}
# Extract parameters
params = ExperimentParameters(**context_data["parameters"])
# Run test iterations
results = []
for i in range(test_iterations):
# Restore state
if not self.restore_complete_state(context_data["reproducibility_state"]):
return {
"valid": False,
"error": "Captured RNG state restoration failed",
}
# Run mock experiment (would be actual factorization in practice)
result = self._run_reproducibility_test(params)
results.append(result)
# Check consistency
consistency_check = self._analyze_result_consistency(results)
return {
"valid": consistency_check["is_consistent"],
"test_iterations": test_iterations,
"consistency_score": consistency_check["consistency_score"],
"differences": consistency_check["differences"],
"results": results,
}
def _capture_system_environment(self) -> SystemEnvironment:
"""Capture system environment information."""
try:
import psutil
except ImportError:
memory_total_gb = None
else:
memory_total_gb = psutil.virtual_memory().total / (1024**3)
return SystemEnvironment(
platform_system=platform.system(),
platform_release=platform.release(),
python_version=sys.version,
numpy_version=np.__version__,
random_state_type=str(type(random.getstate())),
process_id=os.getpid(),
working_directory=str(Path.cwd()),
utc_timestamp=time.time(),
local_timezone=str(time.tzname),
cpu_count=os.cpu_count() or 1,
memory_total_gb=memory_total_gb,
)
def _get_numpy_state(self) -> dict:
"""Get NumPy random state in serializable format."""
# Get bit generator state
bit_gen_state = np.random.get_state()
return {
"generator": bit_gen_state[0],
"state": bit_gen_state[1].tolist(),
"pos": int(bit_gen_state[2]),
"has_gauss": int(bit_gen_state[3]),
"cached_gaussian": (
float(bit_gen_state[4]) if bit_gen_state[4] is not None else None
),
}
@staticmethod
def _numpy_state_tuple(state_dict: dict) -> tuple:
"""Decode the captured legacy NumPy state without modifying an RNG."""
return (
state_dict["generator"],
np.array(state_dict["state"], dtype=np.uint32),
state_dict["pos"],
state_dict["has_gauss"],
state_dict["cached_gaussian"],
)
def _set_numpy_state(self, state_dict: dict):
"""Restore NumPy random state from serializable format."""
np.random.set_state(self._numpy_state_tuple(state_dict))
def _generate_experiment_id(self, params: ExperimentParameters) -> str:
"""Generate unique experiment identifier."""
# Create identifier from parameters and timestamp
param_str = (
f"{params.modulus_n}_{params.partition_strategy}_{params.node_count}"
)
timestamp_str = str(int(time.time() * 1000))
seed_str = str(self.master_seed)
# Hash to create unique ID
combined = f"{param_str}_{timestamp_str}_{seed_str}"
hash_obj = hashlib.md5(combined.encode())
return f"exp_{hash_obj.hexdigest()[:12]}"
def _compute_checksum(self, data: Any) -> str:
"""Compute deterministic checksum for data integrity."""
# Convert to JSON with sorted keys for deterministic output
json_str = json.dumps(data, sort_keys=True, default=str)
return hashlib.sha256(json_str.encode()).hexdigest()[:16]
def _get_tnfr_version(self) -> str:
"""Get TNFR version for compatibility tracking."""
# In practice, would read from package metadata
return "0.9.5" # Current version
def _get_dependency_versions(self) -> Dict[str, str]:
"""Get versions of key dependencies."""
dependencies = {"python": sys.version.split()[0], "numpy": np.__version__}
# Try to get other package versions
try:
import scipy
dependencies["scipy"] = scipy.__version__
except ImportError:
pass
try:
import networkx
dependencies["networkx"] = networkx.__version__
except ImportError:
pass
return dependencies
def _store_experiment_context(
self, experiment_id: str, context_data: Dict[str, Any]
):
"""Store experiment context for later retrieval."""
# Create contexts directory
contexts_dir = Path("experiment_contexts")
contexts_dir.mkdir(exist_ok=True)
# Store context data
context_file = contexts_dir / f"{experiment_id}.json"
with open(context_file, "w") as f:
json.dump(context_data, f, indent=2, default=str)
def _load_experiment_context(self, experiment_id: str) -> Optional[Dict[str, Any]]:
"""Load experiment context from storage."""
context_file = Path("experiment_contexts") / f"{experiment_id}.json"
if not context_file.exists():
return None
with open(context_file, "r") as f:
return json.load(f)
def _run_reproducibility_test(
self, params: ExperimentParameters
) -> Dict[str, float]:
"""Run lightweight reproducibility test (mock factorization)."""
# Use seeded random generators
node_rng = self.get_seeded_numpy_random("node_initialization")
coupling_rng = self.get_seeded_numpy_random("coupling_dynamics")
# Simulate node initialization
initial_phases = node_rng.uniform(0, 2 * np.pi, params.node_count)
structural_freqs = node_rng.uniform(
*params.structural_frequency_range, params.node_count
)
# Simulate coupling dynamics
coupling_matrix = coupling_rng.uniform(
*params.coupling_strength_range, (params.node_count, params.node_count)
)
# Simulate coherence computation
phase_diffs = np.abs(initial_phases[:, None] - initial_phases[None, :])
coherence_contributions = np.cos(phase_diffs) * coupling_matrix
final_coherence = np.mean(coherence_contributions)
# Simulate sense index
sense_index = np.mean(structural_freqs) / (1.0 + np.std(phase_diffs))
# Simulate verification confidence
spectral_rng = self.get_seeded_numpy_random("spectral_analysis")
eigenvalue_gap = spectral_rng.exponential(0.3)
verification_confidence = min(1.0, final_coherence + eigenvalue_gap)
return {
"final_coherence": float(final_coherence),
"sense_index": float(sense_index),
"verification_confidence": float(verification_confidence),
"eigenvalue_gap": float(eigenvalue_gap),
"phase_checksum": float(np.sum(initial_phases)),
}
def _analyze_result_consistency(
self, results: List[Dict[str, float]]
) -> Dict[str, Any]:
"""Analyze consistency of reproducibility test results."""
if len(results) < 2:
return {"is_consistent": True, "consistency_score": 1.0, "differences": {}}
# Check exact equality for all metrics
first_result = results[0]
differences = {}
for key in first_result:
values = [result[key] for result in results]
# Check if all values are identical
if not all(abs(v - values[0]) < 1e-15 for v in values):
differences[key] = {
"values": values,
"max_diff": max(values) - min(values),
"std_dev": float(np.std(values)),
}
# Calculate consistency score
is_consistent = len(differences) == 0
consistency_score = (
1.0 if is_consistent else (1.0 - len(differences) / len(first_result))
)
return {
"is_consistent": is_consistent,
"consistency_score": consistency_score,
"differences": differences,
}
# Utility functions for integration
def create_demo_experiment_params(modulus_n: int = 77) -> ExperimentParameters:
"""Create demo experiment parameters."""
return ExperimentParameters(
modulus_n=modulus_n,
partition_strategy="spectral_paley",
verification_mode="comprehensive",
node_count=10,
initial_topology="ring",
coupling_strength_range=(0.5, 0.9),
structural_frequency_range=(0.8, 1.5),
phase_initialization_mode="uniform_random",
coherence_threshold=0.75,
dnfr_budget=100.0,
max_iterations=50,
convergence_tolerance=1e-6,
spectral_clustering_k=2,
timeout_seconds=300.0,
memory_limit_mb=512,
operator_sequence_constraints=["emission", "coupling", "coherence"],
adaptive_threshold_enabled=True,
feedback_learning_enabled=True,
)
if __name__ == "__main__":
"""Demo script showing seed management system usage."""
print("TNFR SEED MANAGEMENT SYSTEM DEMO")
print("=" * 50)
# Create seed manager
seed_manager = TNFRSeedManager(master_seed=42)
print(f"Master seed: {seed_manager.master_seed}")
# Create experiment parameters
params = create_demo_experiment_params(77)
print(
f"Experiment parameters: n={params.modulus_n}, strategy={params.partition_strategy}"
)
# Create experiment context
experiment_id = seed_manager.create_experiment_context(params)
print(f"Created experiment: {experiment_id}")
# Demonstrate seeded random generation
print("\nSeeded random generation:")
node_rng = seed_manager.get_seeded_random("node_initialization")
print(f"Node initialization samples: {[node_rng.random() for _ in range(3)]}")
coupling_rng = seed_manager.get_seeded_numpy_random("coupling_dynamics")
print(f"Coupling dynamics samples: {coupling_rng.random(3)}")
# Test reproducibility
print(f"\nTesting reproducibility...")
validation_result = seed_manager.validate_reproducibility(
experiment_id, test_iterations=3
)
print(f"Reproducibility valid: {validation_result['valid']}")
print(f"Consistency score: {validation_result['consistency_score']:.6f}")
if validation_result["differences"]:
print("Detected differences:")
for key, diff_data in validation_result["differences"].items():
print(f" {key}: max_diff={diff_data['max_diff']:.2e}")
else:
print("✅ Perfect reproducibility achieved!")
# Demonstrate state capture/restore
print(f"\nTesting state capture/restore...")
# Capture current state
state = seed_manager.capture_complete_state()
# Generate some random numbers
before_numbers = [random.random() for _ in range(3)]
print(f"Numbers before restore: {before_numbers}")
# Restore state and generate same numbers
seed_manager.restore_complete_state(state)
after_numbers = [random.random() for _ in range(3)]
print(f"Numbers after restore: {after_numbers}")
# Check if identical
identical = all(abs(a - b) < 1e-15 for a, b in zip(before_numbers, after_numbers))
print(f"State restore successful: {identical}")
print(f"\n✅ Seed management system demo completed!")