diff --git a/exp/pecos-neo/src/ecs/coordinator.rs b/exp/pecos-neo/src/ecs/coordinator.rs index 18bfb8606..b06a85107 100644 --- a/exp/pecos-neo/src/ecs/coordinator.rs +++ b/exp/pecos-neo/src/ecs/coordinator.rs @@ -471,8 +471,12 @@ mod tests { fn test_worker_state_with_entities() { let mut worker: WorkerState = WorkerState::new(0, 42); - worker.world.spawn_with_simulator(SparseStab::new(2)); - worker.world.spawn_with_simulator(SparseStab::new(2)); + worker + .world + .spawn_with_simulator(SparseStab::with_seed(2, 42)); + worker + .world + .spawn_with_simulator(SparseStab::with_seed(2, 42)); assert_eq!(worker.active_count(), 2); @@ -513,7 +517,7 @@ mod tests { // Simple test: return entity count from each world let results = coordinator.run( - || SparseStab::new(1), + || SparseStab::with_seed(1, 42), |world| { // Just return the entity IDs as results world.entities().map(|e| e.0).collect() @@ -538,12 +542,12 @@ mod tests { let coordinator2: ParallelCoordinator = ParallelCoordinator::new(config); let results1 = coordinator1.run( - || SparseStab::new(1), + || SparseStab::with_seed(1, 42), |world| world.entities().map(|e| world.base_seed() + e.0).collect(), ); let results2 = coordinator2.run( - || SparseStab::new(1), + || SparseStab::with_seed(1, 42), |world| world.entities().map(|e| world.base_seed() + e.0).collect(), ); @@ -564,7 +568,7 @@ mod tests { let coordinator: ParallelCoordinator = ParallelCoordinator::new(config); let results = coordinator.run( - || SparseStab::new(1), + || SparseStab::with_seed(1, 42), |world| { world .entities() @@ -596,7 +600,7 @@ mod tests { let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); let results = coordinator.run( - || SparseStab::new(1), + || SparseStab::with_seed(1, 42), |world| { // Run one shot per entity world @@ -665,7 +669,7 @@ mod tests { let mut sync_count = 0; let result: ParallelResult<()> = coordinator.run_with_sync( - || SparseStab::new(1), + || SparseStab::with_seed(1, 42), 5, // 5 steps |_world, _step| { // Do nothing per step diff --git a/exp/pecos-neo/src/ecs/redistribution.rs b/exp/pecos-neo/src/ecs/redistribution.rs index 7bee3050b..468fe6fd6 100644 --- a/exp/pecos-neo/src/ecs/redistribution.rs +++ b/exp/pecos-neo/src/ecs/redistribution.rs @@ -296,9 +296,15 @@ mod tests { let mut worker0: WorkerState = WorkerState::new(0, 42); let mut worker1: WorkerState = WorkerState::new(1, 42); - worker0.world.spawn_with_simulator(SparseStab::new(1)); - worker0.world.spawn_with_simulator(SparseStab::new(1)); - worker1.world.spawn_with_simulator(SparseStab::new(1)); + worker0 + .world + .spawn_with_simulator(SparseStab::with_seed(1, 42)); + worker0 + .world + .spawn_with_simulator(SparseStab::with_seed(1, 42)); + worker1 + .world + .spawn_with_simulator(SparseStab::with_seed(1, 42)); let workers = vec![worker0, worker1]; let weights = collect_weights(&workers); @@ -317,7 +323,9 @@ mod tests { let mut worker = WorkerState::new(id, 42); // Each worker gets 5 entities for _ in 0..5 { - worker.world.spawn_with_simulator(SparseStab::new(1)); + worker + .world + .spawn_with_simulator(SparseStab::with_seed(1, 42)); } worker }) @@ -357,10 +365,16 @@ mod tests { // Worker 0 gets 10 entities, others get 1 each for _ in 0..10 { - workers[0].world.spawn_with_simulator(SparseStab::new(1)); + workers[0] + .world + .spawn_with_simulator(SparseStab::with_seed(1, 42)); } - workers[1].world.spawn_with_simulator(SparseStab::new(1)); - workers[2].world.spawn_with_simulator(SparseStab::new(1)); + workers[1] + .world + .spawn_with_simulator(SparseStab::with_seed(1, 42)); + workers[2] + .world + .spawn_with_simulator(SparseStab::with_seed(1, 42)); let transfers = balance_entity_counts(&mut workers); diff --git a/exp/pecos-neo/src/ecs/world.rs b/exp/pecos-neo/src/ecs/world.rs index c9aee6fa5..40173246c 100644 --- a/exp/pecos-neo/src/ecs/world.rs +++ b/exp/pecos-neo/src/ecs/world.rs @@ -597,7 +597,7 @@ mod tests { fn test_world_spawn_with_simulator() { let mut world: World = World::new(42); - let e = world.spawn_with_simulator(SparseStab::new(2)); + let e = world.spawn_with_simulator(SparseStab::with_seed(2, 42)); assert!(world.simulators.contains(e)); assert!(world.rngs.contains(e)); @@ -611,7 +611,7 @@ mod tests { fn test_world_despawn() { let mut world: World = World::new(42); - let e = world.spawn_with_simulator(SparseStab::new(2)); + let e = world.spawn_with_simulator(SparseStab::with_seed(2, 42)); assert!(world.is_alive(e)); world.despawn(e); @@ -624,7 +624,7 @@ mod tests { fn test_world_clone_entity() { let mut world: World = World::new(42); - let original = world.spawn_with_simulator(SparseStab::new(2)); + let original = world.spawn_with_simulator(SparseStab::with_seed(2, 42)); let clone = world.clone_entity(original).unwrap(); assert_ne!(original, clone); @@ -641,7 +641,7 @@ mod tests { fn test_world_split_entity() { let mut world: World = World::new(42); - let original = world.spawn_with_simulator(SparseStab::new(2)); + let original = world.spawn_with_simulator(SparseStab::with_seed(2, 42)); // Get original weight let orig_weight = world.weights.get(original).unwrap().weight.weight(); @@ -673,7 +673,7 @@ mod tests { let mut world: World = World::new(42); for _ in 0..10 { - world.spawn_with_simulator(SparseStab::new(2)); + world.spawn_with_simulator(SparseStab::with_seed(2, 42)); } let entities: Vec = world.entities().collect(); @@ -685,8 +685,8 @@ mod tests { fn test_world_prune_by_weight() { let mut world: World = World::new(42); - let e1 = world.spawn_with_simulator(SparseStab::new(2)); - let e2 = world.spawn_with_simulator(SparseStab::new(2)); + let e1 = world.spawn_with_simulator(SparseStab::with_seed(2, 42)); + let e2 = world.spawn_with_simulator(SparseStab::with_seed(2, 42)); // Set e2 to very low weight world.weights.get_mut(e2).unwrap().weight = SampleWeight::from_linear(0.001); @@ -702,8 +702,8 @@ mod tests { fn test_world_spawn_with_full_seeding() { let mut world: World = World::new(42); - let e1 = world.spawn_with_full_seeding(SparseStab::new(2)); - let e2 = world.spawn_with_full_seeding(SparseStab::new(2)); + let e1 = world.spawn_with_full_seeding(SparseStab::with_seed(2, 42)); + let e2 = world.spawn_with_full_seeding(SparseStab::with_seed(2, 42)); assert!(world.is_alive(e1)); assert!(world.is_alive(e2)); @@ -719,8 +719,8 @@ mod tests { let mut world1: World = World::new(42); let mut world2: World = World::new(42); - let e1a = world1.spawn_with_full_seeding(SparseStab::new(2)); - let e1b = world2.spawn_with_full_seeding(SparseStab::new(2)); + let e1a = world1.spawn_with_full_seeding(SparseStab::with_seed(2, 42)); + let e1b = world2.spawn_with_full_seeding(SparseStab::with_seed(2, 42)); // Entity IDs should match assert_eq!(e1a, e1b); diff --git a/exp/pecos-neo/src/lib.rs b/exp/pecos-neo/src/lib.rs index f3089ed34..9c94e9f6f 100644 --- a/exp/pecos-neo/src/lib.rs +++ b/exp/pecos-neo/src/lib.rs @@ -359,7 +359,7 @@ mod tests { .add_channel(SingleQubitChannel::depolarizing(0.0)) .add_channel(TwoQubitChannel::depolarizing(0.0)); - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed(42); @@ -388,7 +388,7 @@ mod tests { .add_plugin(&DepolarizingPlugin::new(0.0, 0.0)) .add_plugin(&MeasurementNoisePlugin::symmetric(0.0)); - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed(42); diff --git a/exp/pecos-neo/src/noise/builder.rs b/exp/pecos-neo/src/noise/builder.rs index babd99ad9..3fe42baf7 100644 --- a/exp/pecos-neo/src/noise/builder.rs +++ b/exp/pecos-neo/src/noise/builder.rs @@ -661,7 +661,7 @@ mod tests { .build(); // Simple configuration - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut simple_errors = 0; for seed in 0..shots { let model = NoiseModelBuilder::new().with_p1(p1).build(); diff --git a/exp/pecos-neo/src/noise/composite.rs b/exp/pecos-neo/src/noise/composite.rs index 6701db381..34eacce07 100644 --- a/exp/pecos-neo/src/noise/composite.rs +++ b/exp/pecos-neo/src/noise/composite.rs @@ -336,7 +336,7 @@ mod tests { let noise = ComposableNoiseModel::new().add_channel(channel); // Run with noise - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed(42); @@ -371,7 +371,7 @@ mod tests { .add_channel(flow_channel) .add_channel(meas_channel); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed(42); @@ -563,7 +563,7 @@ mod tests { let noise = ComposableNoiseModel::new().add_channel(crosstalk); - let mut state = SparseStab::new(3); + let mut state = SparseStab::with_seed(3, 42); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed(42); @@ -669,7 +669,7 @@ mod tests { ); let traditional_noise = ComposableNoiseModel::new().add_channel(traditional_channel); - let mut state_trad = SparseStab::new(1); + let mut state_trad = SparseStab::with_seed(1, seed); let mut runner_trad = CircuitRunner::::new() .with_noise(traditional_noise) .with_seed(seed); @@ -685,7 +685,7 @@ mod tests { let flow_channel = CompositeChannelBuilder::single_qubit("flow_sq", flow_noise); let flow_noise_model = ComposableNoiseModel::new().add_channel(flow_channel); - let mut state_flow = SparseStab::new(1); + let mut state_flow = SparseStab::with_seed(1, seed); let mut runner_flow = CircuitRunner::::new() .with_noise(flow_noise_model) .with_seed(seed); @@ -731,7 +731,7 @@ mod tests { let traditional_channel = MeasurementChannel::symmetric(p_meas); let traditional_noise = ComposableNoiseModel::new().add_channel(traditional_channel); - let mut state_trad = SparseStab::new(1); + let mut state_trad = SparseStab::with_seed(1, seed); let mut runner_trad = CircuitRunner::::new() .with_noise(traditional_noise) .with_seed(seed); @@ -749,7 +749,7 @@ mod tests { .with_filter(CompositeEventFilter::AfterMeasurement); let flow_noise_model = ComposableNoiseModel::new().add_channel(flow_channel); - let mut state_flow = SparseStab::new(1); + let mut state_flow = SparseStab::with_seed(1, seed); let mut runner_flow = CircuitRunner::::new() .with_noise(flow_noise_model) .with_seed(seed); @@ -810,7 +810,7 @@ mod tests { .with_p_meas_symmetric(p_meas) .build(); - let mut state_trad = SparseStab::new(1); + let mut state_trad = SparseStab::with_seed(1, seed); let mut runner_trad = CircuitRunner::::new() .with_noise(traditional_model) .with_seed(seed); @@ -835,7 +835,7 @@ mod tests { .add_channel(sq_channel) .add_channel(meas_channel); - let mut state_flow = SparseStab::new(1); + let mut state_flow = SparseStab::with_seed(1, seed); let mut runner_flow = CircuitRunner::::new() .with_noise(flow_model) .with_seed(seed); diff --git a/exp/pecos-neo/src/noise/composite/builder.rs b/exp/pecos-neo/src/noise/composite/builder.rs index 5b1bf99dd..0bb936ae9 100644 --- a/exp/pecos-neo/src/noise/composite/builder.rs +++ b/exp/pecos-neo/src/noise/composite/builder.rs @@ -1340,7 +1340,7 @@ mod tests { for seed in 0..shots { let model = CompositeNoiseModelBuilder::new().with_p1(p1).build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, seed); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(seed); @@ -1373,7 +1373,7 @@ mod tests { let model = CompositeNoiseModelBuilder::new() .with_p_meas(p_0_to_1, p_1_to_0) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, seed); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(seed); @@ -1567,7 +1567,7 @@ mod tests { for seed in 0..shots { // With p2 error let model_with = CompositeNoiseModelBuilder::new().with_p2(p2).build(); - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, seed); let mut runner = CircuitRunner::::new() .with_noise(model_with) .with_seed(seed); @@ -1581,7 +1581,7 @@ mod tests { // Without noise let model_without = CompositeNoiseModelBuilder::new().build(); - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, seed); let mut runner = CircuitRunner::::new() .with_noise(model_without) .with_seed(seed); @@ -1650,7 +1650,7 @@ mod tests { .with_p2_angle_scaling(AngleScaling::linear()) .build(); - let mut state = StateVec::new(2); + let mut state = StateVec::with_seed(2, seed); let mut runner = CircuitRunner::::rotations() .with_noise(model) .with_seed(seed); @@ -1689,7 +1689,7 @@ mod tests { .with_p2_angle_scaling(AngleScaling::linear()) .build(); - let mut state = StateVec::new(2); + let mut state = StateVec::with_seed(2, seed); let mut runner = CircuitRunner::::rotations() .with_noise(model) .with_seed(seed); @@ -1821,7 +1821,7 @@ mod tests { .with_p2(p2) .build(); - let mut state_general = SparseStab::new(2); + let mut state_general = SparseStab::with_seed(2, seed); let mut runner_general = CircuitRunner::::new() .with_noise(general_model) .with_seed(seed); @@ -1841,7 +1841,7 @@ mod tests { .with_p2(p2) .build(); - let mut state_flow = SparseStab::new(2); + let mut state_flow = SparseStab::with_seed(2, seed); let mut runner_flow = CircuitRunner::::new() .with_noise(flow_model) .with_seed(seed); @@ -1888,7 +1888,7 @@ mod tests { .with_p_meas(p_meas_0, p_meas_1) .build(); - let mut state_general = SparseStab::new(1); + let mut state_general = SparseStab::with_seed(1, seed); let mut runner_general = CircuitRunner::::new() .with_noise(general_model) .with_seed(seed); @@ -1904,7 +1904,7 @@ mod tests { .with_p_meas(p_meas_0, p_meas_1) .build(); - let mut state_flow = SparseStab::new(1); + let mut state_flow = SparseStab::with_seed(1, seed); let mut runner_flow = CircuitRunner::::new() .with_noise(flow_model) .with_seed(seed); @@ -1950,7 +1950,7 @@ mod tests { // GeneralNoiseModelBuilder let general_model = GeneralNoiseModelBuilder::new().with_p_prep(p_prep).build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, seed); let mut runner = CircuitRunner::::new() .with_noise(general_model) .with_seed(seed); @@ -1968,7 +1968,7 @@ mod tests { .with_p_prep(p_prep) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, seed); let mut runner = CircuitRunner::::new() .with_noise(flow_model) .with_seed(seed); @@ -2260,7 +2260,7 @@ mod tests { .with_p1_emission_model(emission) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, seed); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(seed); @@ -2356,7 +2356,7 @@ mod tests { .with_p1_emission_weights(emission) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, seed); let mut runner = CircuitRunner::::new() .with_noise(general_model) .with_seed(seed); @@ -2372,7 +2372,7 @@ mod tests { .with_p1_emission_model(emission) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, seed); let mut runner = CircuitRunner::::new() .with_noise(flow_model) .with_seed(seed); @@ -2419,7 +2419,7 @@ mod tests { .with_p2_pauli_weights(TwoQubitPauliWeights::uniform()) .build(); - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, seed); let mut runner = CircuitRunner::::new() .with_noise(general_model) .with_seed(seed); @@ -2436,7 +2436,7 @@ mod tests { .with_p2_pauli_model(TwoQubitPauliWeights::uniform()) .build(); - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, seed); let mut runner = CircuitRunner::::new() .with_noise(flow_model) .with_seed(seed); diff --git a/exp/pecos-neo/src/noise/general_builder.rs b/exp/pecos-neo/src/noise/general_builder.rs index 6033c727f..3e5394cf4 100644 --- a/exp/pecos-neo/src/noise/general_builder.rs +++ b/exp/pecos-neo/src/noise/general_builder.rs @@ -670,12 +670,12 @@ mod tests { .with_p_meas_symmetric(0.1) .build(); - let mut state_a = SparseStab::new(1); + let mut state_a = SparseStab::with_seed(1, 42); let mut runner_a = CircuitRunner::::new() .with_noise(noise_a) .with_seed(42); - let mut state_b = SparseStab::new(1); + let mut state_b = SparseStab::with_seed(1, 42); let mut runner_b = CircuitRunner::::new() .with_noise(noise_b) .with_seed(42); @@ -841,7 +841,7 @@ mod tests { .mz(&[1]) .build(); - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(42); @@ -876,7 +876,7 @@ mod tests { .build(); // Run with GeneralNoiseModelBuilder - count Z basis measurements - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut general_ones = 0; for seed in 0..shots { let model = GeneralNoiseModelBuilder::new().with_p1(p1).build(); @@ -944,7 +944,7 @@ mod tests { .build(); // Run with GeneralNoiseModelBuilder - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut general_errors = 0; for seed in 0..shots { let model = GeneralNoiseModelBuilder::new().with_p2(p2).build(); @@ -1007,7 +1007,7 @@ mod tests { let commands = CommandBuilder::new().pz(&[0]).mz(&[0]).build(); // Run with GeneralNoiseModelBuilder - errors should flip to 1 - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut general_ones = 0; for seed in 0..shots { let model = GeneralNoiseModelBuilder::new() diff --git a/exp/pecos-neo/src/noise/measurement.rs b/exp/pecos-neo/src/noise/measurement.rs index 28b2a93f6..b3cfae714 100644 --- a/exp/pecos-neo/src/noise/measurement.rs +++ b/exp/pecos-neo/src/noise/measurement.rs @@ -313,7 +313,7 @@ mod tests { let commands = CommandBuilder::new().pz(&[0]).mz(&[0]).mz(&[0]).build(); let second_meas_rate = |model: ComposableNoiseModel| -> f64 { - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(42); diff --git a/exp/pecos-neo/src/noise/patterns.rs b/exp/pecos-neo/src/noise/patterns.rs index 8865f081e..4d71391e3 100644 --- a/exp/pecos-neo/src/noise/patterns.rs +++ b/exp/pecos-neo/src/noise/patterns.rs @@ -581,7 +581,7 @@ mod tests { let model = depolarizing_only(0.5, 0.5); let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(42); @@ -594,7 +594,7 @@ mod tests { fn test_depolarizing_with_measurement() { let commands = CommandBuilder::new().pz(&[0]).mz(&[0]).build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut errors = 0; for seed in 0..100 { // Recreate model for each iteration since ComposableNoiseModel doesn't Clone @@ -624,7 +624,7 @@ mod tests { let model = dephasing_only(0.5, 0.5); let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(42); @@ -642,7 +642,7 @@ mod tests { .mz(&[0]) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(42); @@ -662,7 +662,7 @@ mod tests { .mz(&[1]) .build(); - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(42); @@ -680,7 +680,7 @@ mod tests { let model = realistic_device_noise(¶ms); let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(42); @@ -699,7 +699,7 @@ mod tests { .mz(&[1]) .build(); - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(42); diff --git a/exp/pecos-neo/src/noise/per_gate_pauli.rs b/exp/pecos-neo/src/noise/per_gate_pauli.rs index bcd64ddde..c43549031 100644 --- a/exp/pecos-neo/src/noise/per_gate_pauli.rs +++ b/exp/pecos-neo/src/noise/per_gate_pauli.rs @@ -367,7 +367,7 @@ mod tests { const SHOTS: usize = 20_000; fn flip_rate(model: ComposableNoiseModel, commands: &CommandQueue, qubit: usize) -> f64 { - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(42); @@ -524,7 +524,7 @@ mod tests { let model = ComposableNoiseModel::new().add_channel(channel); let commands = CommandBuilder::new().pz(&[0]).mz(&[0]).mz(&[0]).build(); - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(42); diff --git a/exp/pecos-neo/src/program.rs b/exp/pecos-neo/src/program.rs index 4580db75f..2f5825169 100644 --- a/exp/pecos-neo/src/program.rs +++ b/exp/pecos-neo/src/program.rs @@ -517,7 +517,7 @@ mod tests { let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); let mut program = StaticProgram::new(commands, 1); - let mut runner = ProgramRunner::new(SparseStab::new(1)).with_seed(42); + let mut runner = ProgramRunner::new(SparseStab::with_seed(1, 42)).with_seed(42); let result = runner.run_shot(&mut program); @@ -531,7 +531,7 @@ mod tests { let round_commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); let mut program = RepeatedProgram::new(round_commands, 3, 1); - let mut runner = ProgramRunner::new(SparseStab::new(1)).with_seed(42); + let mut runner = ProgramRunner::new(SparseStab::with_seed(1, 42)).with_seed(42); let result = runner.run_shot(&mut program); @@ -555,7 +555,7 @@ mod tests { }; let mut program = ConditionalProgram::new(initial, branch, 1); - let mut runner = ProgramRunner::new(SparseStab::new(1)).with_seed(42); + let mut runner = ProgramRunner::new(SparseStab::with_seed(1, 42)).with_seed(42); let result = runner.run_shot(&mut program); @@ -567,7 +567,7 @@ mod tests { fn test_program_reset() { let commands = CommandBuilder::new().pz(&[0]).mz(&[0]).build(); let mut program = StaticProgram::new(commands, 1); - let mut runner = ProgramRunner::new(SparseStab::new(1)).with_seed(42); + let mut runner = ProgramRunner::new(SparseStab::with_seed(1, 42)).with_seed(42); // Run first shot let result1 = runner.run_shot(&mut program); @@ -590,7 +590,7 @@ mod tests { .build(); let mut program = StaticProgram::new(commands, 2); - let mut runner = ProgramRunner::new(SparseStab::new(2)).with_seed(42); + let mut runner = ProgramRunner::new(SparseStab::with_seed(2, 42)).with_seed(42); let result = runner.run_shot(&mut program); diff --git a/exp/pecos-neo/src/runner.rs b/exp/pecos-neo/src/runner.rs index a583131c6..abe907840 100644 --- a/exp/pecos-neo/src/runner.rs +++ b/exp/pecos-neo/src/runner.rs @@ -2517,7 +2517,7 @@ mod tests { fn test_basic_execution() { let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new().with_seed(42); let outcomes = runner.apply_circuit(&mut state, &commands).unwrap(); @@ -2535,7 +2535,7 @@ mod tests { .mz(&[1]) .build(); - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::new().with_seed(42); let outcomes = runner.apply_circuit(&mut state, &commands).unwrap(); @@ -2551,7 +2551,7 @@ mod tests { let noise = ComposableNoiseModel::new().add_channel(SingleQubitChannel::depolarizing(0.0)); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed(42); @@ -2564,7 +2564,7 @@ mod tests { fn test_apply_circuit_resets_noise() { let commands = CommandBuilder::new().pz(&[0]).mz(&[0]).build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new().with_seed(42); let outcomes1 = runner.apply_circuit(&mut state, &commands).unwrap(); @@ -2588,7 +2588,7 @@ mod tests { let mut noise = ComposableNoiseModel::new().add_channel(LeakageChannel::new()); noise.context_mut().mark_leaked(QubitId(0)); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed(42); @@ -2608,7 +2608,7 @@ mod tests { let mut noise = ComposableNoiseModel::new().add_channel(LeakageChannel::new()); noise.context_mut().mark_leaked(QubitId(0)); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed(42); @@ -2632,7 +2632,7 @@ mod tests { let noise = ComposableNoiseModel::new().add_channel(LeakageChannel::new()); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed(42); @@ -2661,7 +2661,7 @@ mod tests { smallvec::smallvec![QubitId(0)], )); - let mut state = StateVec::new(1); + let mut state = StateVec::with_seed(1, 42); let mut runner = CircuitRunner::::rotations().with_seed(42); let outcomes = runner.apply_circuit(&mut state, &commands).unwrap(); @@ -2687,7 +2687,7 @@ mod tests { .mz(&[1]) .build(); - let mut state = StateVec::new(2); + let mut state = StateVec::with_seed(2, 42); let mut runner = CircuitRunner::::rotations().with_seed(42); let outcomes = runner.apply_circuit(&mut state, &commands).unwrap(); @@ -2710,7 +2710,7 @@ mod tests { .mz(&[2]) .build(); - let mut state = StateVec::new(3); + let mut state = StateVec::with_seed(3, 42); let mut runner = CircuitRunner::::rotations().with_seed(42); let outcomes = runner.apply_circuit(&mut state, &commands).unwrap(); @@ -2732,7 +2732,7 @@ mod tests { .mz(&[2]) .build(); - let mut state = StateVec::new(3); + let mut state = StateVec::with_seed(3, 42); let mut runner = CircuitRunner::::rotations().with_seed(42); let outcomes = runner.apply_circuit(&mut state, &commands).unwrap(); @@ -2755,7 +2755,7 @@ mod tests { let noise = ComposableNoiseModel::new().add_channel(IdleChannel::linear(1.0)); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed(42); @@ -2780,7 +2780,7 @@ mod tests { let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::with_definitions(gates) .with_noise(noise) .with_seed(42); @@ -2840,7 +2840,7 @@ mod tests { .mz(&[0]) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new().with_seed(42); runner.on_signal(move |_: &RoundBoundary| { counter_clone.fetch_add(1, Ordering::Relaxed); @@ -2870,7 +2870,7 @@ mod tests { .mz(&[0]) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new().with_seed(42); runner.on_signal(move |_: &RoundBoundary| { rc.fetch_add(1, Ordering::Relaxed); @@ -2897,7 +2897,7 @@ mod tests { .mz(QubitId(0), ResultId(0)) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::with_definitions(gates_def).with_seed(42); let outcomes = runner.apply_adapted_circuit(&mut state, &circuit).unwrap(); @@ -2916,7 +2916,7 @@ mod tests { .mz(QubitId(1), ResultId(1)) .build(); - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::with_definitions(gates_def).with_seed(42); let outcomes = runner.apply_adapted_circuit(&mut state, &circuit).unwrap(); @@ -2939,7 +2939,7 @@ mod tests { .mz(QubitId(1), ResultId(1)) .build(); - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::with_definitions(gates_def).with_seed(42); let outcomes = runner.apply_adapted_circuit(&mut state, &circuit).unwrap(); @@ -2963,7 +2963,7 @@ mod tests { .mz(QubitId(0), ResultId(0)) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::with_definitions(gates_def); let result = runner.apply_adapted_circuit(&mut state, &circuit); @@ -2982,7 +2982,7 @@ mod tests { .mz(QubitId(0), ResultId(0)) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::with_definitions(gates_def).with_seed(42); let outcomes1 = runner.apply_adapted_circuit(&mut state, &circuit).unwrap(); @@ -3002,7 +3002,7 @@ mod tests { .mx(QubitId(0), ResultId(0)) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::with_definitions(gates_def).with_seed(42); let outcomes = runner.apply_adapted_circuit(&mut state, &circuit).unwrap(); @@ -3034,7 +3034,7 @@ mod tests { .mz(QubitId(0), ResultId(0)) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::with_definitions(gates_def) .with_overrides(overrides) .with_seed(42); @@ -3058,7 +3058,7 @@ mod tests { .mz(QubitId(0), ResultId(0)) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::with_definitions(gates_def) .with_overrides(overrides) .with_seed(42); @@ -3098,7 +3098,7 @@ mod tests { .mz(QubitId(0), ResultId(0)) .build(); - let mut state = StateVec::new(1); + let mut state = StateVec::with_seed(1, 42); let mut runner = CircuitRunner::::rotations_with_definitions(gates_def).with_seed(42); @@ -3118,7 +3118,7 @@ mod tests { .mz(QubitId(0), ResultId(0)) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::with_definitions(gates_def); assert!(!runner.has_rotation_support()); @@ -3142,7 +3142,7 @@ mod tests { .mz(&[0]) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new(); let err = runner @@ -3181,7 +3181,7 @@ mod tests { .mz(&[0]) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::with_definitions(defs).with_seed(42); let outcomes = runner.apply_circuit(&mut state, &circuit).unwrap(); @@ -3199,7 +3199,7 @@ mod tests { .rz(&[0], Angle64::from_radians(std::f64::consts::FRAC_PI_2)) .mz(&[0]) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new().with_seed(42); let outcomes = runner.apply_circuit(&mut state, &control).unwrap(); let bit = outcomes.iter().next().expect("one measurement").outcome; @@ -3213,7 +3213,7 @@ mod tests { #[test] fn test_apply_gate_basic() { - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new().with_seed(42); runner @@ -3232,7 +3232,7 @@ mod tests { #[test] fn test_apply_gate_standard_clifford_inverse_sequences() { - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::new().with_seed(42); runner @@ -3294,7 +3294,7 @@ mod tests { ]; for (gate, inverse, qubits) in cases { - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::new().with_seed(42); runner @@ -3358,7 +3358,7 @@ mod tests { } fn prepare_matrix_test_state(prep_index: usize) -> StateVec { - let mut state = StateVec::new(2); + let mut state = StateVec::with_seed(2, 42); match prep_index { 0 => {} 1 => { diff --git a/exp/pecos-neo/src/sampling/importance_runner.rs b/exp/pecos-neo/src/sampling/importance_runner.rs index bcf1bf036..419326a91 100644 --- a/exp/pecos-neo/src/sampling/importance_runner.rs +++ b/exp/pecos-neo/src/sampling/importance_runner.rs @@ -892,7 +892,7 @@ mod tests { fn test_importance_runner_basic() { let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(1)).with_seed(42); + let mut runner = ImportanceSamplingRunner::new(SparseStab::with_seed(1, 42)).with_seed(42); let result = runner.run_shot(&commands); assert_eq!(result.outcomes.len(), 1); @@ -908,7 +908,7 @@ mod tests { .mz(&[0]) .build(); - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(1)) + let mut runner = ImportanceSamplingRunner::new(SparseStab::with_seed(1, 42)) .with_single_qubit_boost(0.001, 10.0) .with_seed(42); @@ -927,7 +927,7 @@ mod tests { .mz(&[0]) .build(); - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(1)).with_seed(42); + let mut runner = ImportanceSamplingRunner::new(SparseStab::with_seed(1, 42)).with_seed(42); let result = runner.run_shot(&commands); assert_eq!(result.outcomes.len(), 1); @@ -947,7 +947,7 @@ mod tests { let true_rate = 0.001; let boost = 100.0; // Very aggressive boost - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(1)) + let mut runner = ImportanceSamplingRunner::new(SparseStab::with_seed(1, 12345)) .with_single_qubit_boost(true_rate, boost) .with_seed(12345); @@ -980,7 +980,7 @@ mod tests { .mz(&[1]) .build(); - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(2)) + let mut runner = ImportanceSamplingRunner::new(SparseStab::with_seed(2, 42)) .with_two_qubit_boost(0.01, 5.0) .with_seed(42); @@ -992,7 +992,7 @@ mod tests { fn test_measurement_importance_sampling() { let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(1)) + let mut runner = ImportanceSamplingRunner::new(SparseStab::with_seed(1, 42)) .with_measurement_boost(0.001, 100.0) .with_seed(42); @@ -1074,7 +1074,8 @@ mod tests { // ========== Unbiased sampling ========== let mut unbiased_ones = 0; for seed in 0..num_shots { - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(1)).with_seed(seed); + let mut runner = + ImportanceSamplingRunner::new(SparseStab::with_seed(1, seed)).with_seed(seed); let result = runner.run_shot(&commands); if result.outcomes.get_bit(QubitId(0)).unwrap_or(false) { unbiased_ones += 1; @@ -1088,7 +1089,7 @@ mod tests { let mut biased_total_weight = 0.0; for seed in 0..num_shots { - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(1)) + let mut runner = ImportanceSamplingRunner::new(SparseStab::with_seed(1, seed)) .with_outcome_bias(OutcomeBiasConfig::bias_toward_one(0.8)) .with_seed(seed); @@ -1132,7 +1133,7 @@ mod tests { // Bias heavily toward 1 let mut ones = 0; for seed in 0..num_shots { - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(1)) + let mut runner = ImportanceSamplingRunner::new(SparseStab::with_seed(1, seed)) .with_outcome_bias(OutcomeBiasConfig::bias_toward_one(0.9)) .with_seed(seed); @@ -1160,7 +1161,7 @@ mod tests { .mz(&[0]) // No H, so deterministic .build(); - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(1)) + let mut runner = ImportanceSamplingRunner::new(SparseStab::with_seed(1, 42)) .with_outcome_bias(OutcomeBiasConfig::bias_toward_one(0.99)) .with_seed(42); diff --git a/exp/pecos-neo/src/sampling/monte_carlo.rs b/exp/pecos-neo/src/sampling/monte_carlo.rs index 0a261ab1c..2824e4168 100644 --- a/exp/pecos-neo/src/sampling/monte_carlo.rs +++ b/exp/pecos-neo/src/sampling/monte_carlo.rs @@ -399,7 +399,7 @@ mod tests { let results = MonteCarloRunner::run( &commands, &config, - || (CircuitRunner::new(), SparseStab::new(1)), + || (CircuitRunner::new(), SparseStab::with_seed(1, 42)), |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ); @@ -436,7 +436,10 @@ mod tests { || { let noise = ComposableNoiseModel::new().add_channel(SingleQubitChannel::depolarizing(0.0)); - (CircuitRunner::new().with_noise(noise), SparseStab::new(1)) + ( + CircuitRunner::new().with_noise(noise), + SparseStab::with_seed(1, 42), + ) }, |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ); @@ -459,7 +462,7 @@ mod tests { &commands, &config, || { - ImportanceSamplingRunner::new(SparseStab::new(1)) + ImportanceSamplingRunner::new(SparseStab::with_seed(1, 42)) .with_single_qubit_boost(0.001, 10.0) }, |outcomes| { @@ -500,7 +503,7 @@ mod tests { let results = MonteCarloRunner::run( &commands, &config, - || (CircuitRunner::new(), SparseStab::new(1)), + || (CircuitRunner::new(), SparseStab::with_seed(1, 12345)), |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ); @@ -535,14 +538,14 @@ mod tests { let results1 = MonteCarloRunner::run( &commands, &config1, - || (CircuitRunner::new(), SparseStab::new(1)), + || (CircuitRunner::new(), SparseStab::with_seed(1, 42)), |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ); let results2 = MonteCarloRunner::run( &commands, &config2, - || (CircuitRunner::new(), SparseStab::new(1)), + || (CircuitRunner::new(), SparseStab::with_seed(1, 12345)), |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ); @@ -575,14 +578,14 @@ mod tests { let results1 = MonteCarloRunner::run( &commands, &config1, - || (CircuitRunner::new(), SparseStab::new(1)), + || (CircuitRunner::new(), SparseStab::with_seed(1, 42)), |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ); let results2 = MonteCarloRunner::run( &commands, &config2, - || (CircuitRunner::new(), SparseStab::new(1)), + || (CircuitRunner::new(), SparseStab::with_seed(1, 42)), |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ); diff --git a/exp/pecos-neo/src/sampling/path.rs b/exp/pecos-neo/src/sampling/path.rs index d6f3cc705..54bf83840 100644 --- a/exp/pecos-neo/src/sampling/path.rs +++ b/exp/pecos-neo/src/sampling/path.rs @@ -761,7 +761,7 @@ mod tests { .mz(&[0]) .build(); - let mut explorer = PathExplorer::new(SparseStab::new(1)).with_seed(42); + let mut explorer = PathExplorer::new(SparseStab::with_seed(1, 42)).with_seed(42); let result = explorer.run_and_record(&commands); assert_eq!(result.path.len(), 1); @@ -772,7 +772,7 @@ mod tests { fn test_path_explorer_replay() { let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); - let mut explorer = PathExplorer::new(SparseStab::new(1)); + let mut explorer = PathExplorer::new(SparseStab::with_seed(1, 42)); // Force outcome 0 let path0 = EnumeratedPath { bits: 0, len: 1 }; @@ -794,7 +794,7 @@ mod tests { .mz(&[0]) .build(); - let mut explorer = PathExplorer::new(SparseStab::new(1)).with_seed(42); + let mut explorer = PathExplorer::new(SparseStab::with_seed(1, 42)).with_seed(42); let result = explorer.run_and_record(&commands); assert!(!result.outcomes.get_bit(QubitId(0)).unwrap()); @@ -812,7 +812,7 @@ mod tests { .fdg(&[0]) .mz(&[0]) .build(); - let mut explorer = PathExplorer::new(SparseStab::new(1)); + let mut explorer = PathExplorer::new(SparseStab::with_seed(1, 42)); let forced_one = EnumeratedPath { bits: 1, len: 1 }; let result = explorer.run_with_path(&commands, &forced_one); @@ -827,7 +827,7 @@ mod tests { // Should have 50% probability of each outcome let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); - let mut explorer = PathExplorer::new(SparseStab::new(1)); + let mut explorer = PathExplorer::new(SparseStab::with_seed(1, 42)); let mut stats = PathStatistics::new(); // Enumerate all paths (just 2 for 1 measurement) @@ -866,7 +866,7 @@ mod tests { .mz(&[1]) .build(); - let mut explorer = PathExplorer::new(SparseStab::new(2)); + let mut explorer = PathExplorer::new(SparseStab::with_seed(2, 42)); // The first measurement is non-deterministic (50/50) // The second is deterministic (correlated with first) diff --git a/exp/pecos-neo/src/sampling/subset.rs b/exp/pecos-neo/src/sampling/subset.rs index 79e7cb8ab..1dac3d9ed 100644 --- a/exp/pecos-neo/src/sampling/subset.rs +++ b/exp/pecos-neo/src/sampling/subset.rs @@ -2762,7 +2762,7 @@ mod tests { let mut world: World = World::new(config.seed.unwrap()); for _ in 0..config.samples_per_level { - world.spawn_with_simulator(SparseStab::new(1)); + world.spawn_with_simulator(SparseStab::with_seed(1, 123)); } let mut sim = EcsSubsetSimulation::new(world, config); @@ -2804,7 +2804,7 @@ mod tests { let mut world: World = World::new(config.seed.unwrap()); for _ in 0..config.samples_per_level { - world.spawn_with_simulator(SparseStab::new(2)); + world.spawn_with_simulator(SparseStab::with_seed(2, 456)); } let initial_count = world.entity_count(); @@ -2888,7 +2888,7 @@ mod tests { let circuit = bit_flip_syndrome_circuit(); // Run without errors - syndrome should be 0 - let mut sim = SparseStab::new(5); + let mut sim = SparseStab::with_seed(5, 42); let mut runner = CircuitRunner::::new().with_rng(PecosRng::seed_from_u64(42)); // Initialize all qubits to |0> @@ -3236,7 +3236,7 @@ mod tests { // Create world with trajectories let mut world: World = World::new(42); for _ in 0..num_trajectories { - world.spawn_with_simulator(SparseStab::new(num_qubits)); + world.spawn_with_simulator(SparseStab::with_seed(num_qubits, 42)); } // Configure QEC subset simulation diff --git a/exp/pecos-neo/src/tool/simulation.rs b/exp/pecos-neo/src/tool/simulation.rs index 01bcbb8a5..8e56a44b3 100644 --- a/exp/pecos-neo/src/tool/simulation.rs +++ b/exp/pecos-neo/src/tool/simulation.rs @@ -6286,7 +6286,7 @@ mod tests { .build(); let results = sim_neo(circuit) - .quantum(custom_backend(SparseStab::new)) + .quantum(custom_backend(|n| SparseStab::with_seed(n, 42))) .sampling(monte_carlo(10)) .seed(42) .build() @@ -6319,7 +6319,7 @@ mod tests { .run(); let custom_results = sim_neo(circuit) - .quantum(custom_backend(SparseStab::new)) + .quantum(custom_backend(|n| SparseStab::with_seed(n, 42))) .sampling(monte_carlo(50)) .seed(42) .run(); @@ -6353,7 +6353,7 @@ mod tests { let noise = ComposableNoiseModel::new().add_channel(SingleQubitChannel::depolarizing(0.5)); let results = sim_neo(circuit) - .quantum(custom_backend(SparseStab::new)) + .quantum(custom_backend(|n| SparseStab::with_seed(n, 42))) .noise(noise) .sampling(monte_carlo(100)) .seed(42) @@ -6380,13 +6380,13 @@ mod tests { let circuit = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); let results1 = sim_neo(circuit.clone()) - .quantum(custom_backend(SparseStab::new)) + .quantum(custom_backend(|n| SparseStab::with_seed(n, 42))) .sampling(monte_carlo(20)) .seed(42) .run(); let results2 = sim_neo(circuit) - .quantum(custom_backend(SparseStab::new)) + .quantum(custom_backend(|n| SparseStab::with_seed(n, 42))) .sampling(monte_carlo(20)) .seed(42) .run(); @@ -6407,7 +6407,7 @@ mod tests { let circuit = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); let run = |workers: usize| { sim_neo(circuit.clone()) - .quantum(custom_backend(SparseStab::new)) + .quantum(custom_backend(|n| SparseStab::with_seed(n, 7))) .sampling(monte_carlo(50).workers(workers)) .seed(42) .run() @@ -6438,7 +6438,7 @@ mod tests { let circuit = CommandBuilder::new().pz(&[0]).z(&[0]).mz(&[0]).build(); let run = |workers: usize| { sim_neo(circuit.clone()) - .quantum(custom_backend(SparseStab::new)) + .quantum(custom_backend(|n| SparseStab::with_seed(n, 42))) .noise(SingleQubitChannel::depolarizing(0.3)) .sampling(monte_carlo(40).workers(workers)) .seed(7) @@ -6468,7 +6468,7 @@ mod tests { let circuit = CommandBuilder::new().pz(&[0]).x(&[0]).mz(&[0]).build(); let results = sim_neo(circuit) - .quantum(custom_backend(StateVec::new)) + .quantum(custom_backend(|n| StateVec::with_seed(n, 42))) .sampling(monte_carlo(10)) .seed(42) .run(); @@ -6793,7 +6793,9 @@ mod tests { .build(); let results = sim_neo(circuit) - .quantum(custom_backend_with_rotations(StateVec::new)) + .quantum(custom_backend_with_rotations(|n| { + StateVec::with_seed(n, 42) + })) .sampling(monte_carlo(10)) .seed(42) .build() diff --git a/exp/pecos-neo/tests/coordinator_test.rs b/exp/pecos-neo/tests/coordinator_test.rs index c2002cd37..5dbf5cfaa 100644 --- a/exp/pecos-neo/tests/coordinator_test.rs +++ b/exp/pecos-neo/tests/coordinator_test.rs @@ -84,7 +84,7 @@ fn test_coordinator_vs_monte_carlo_bell_state() { let mc_results = MonteCarloRunner::run( &commands, &mc_config, - || (CircuitRunner::new(), SparseStab::new(2)), + || (CircuitRunner::new(), SparseStab::with_seed(2, 42)), |outcomes| { let b0 = outcomes.get_bit(QubitId(0)).unwrap_or(false); let b1 = outcomes.get_bit(QubitId(1)).unwrap_or(false); @@ -111,7 +111,7 @@ fn test_coordinator_vs_monte_carlo_bell_state() { let coordinator: ParallelCoordinator = ParallelCoordinator::new(coord_config); let coord_results = coordinator.run( - || SparseStab::new(2), + || SparseStab::with_seed(2, 42), |world| { let commands = CommandBuilder::new() .pz(&[0]) @@ -190,7 +190,10 @@ fn test_coordinator_vs_monte_carlo_with_noise() { || { let noise = ComposableNoiseModel::new().add_channel(SingleQubitChannel::depolarizing(p1)); - (CircuitRunner::new().with_noise(noise), SparseStab::new(1)) + ( + CircuitRunner::new().with_noise(noise), + SparseStab::with_seed(1, 42), + ) }, |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ); @@ -207,7 +210,7 @@ fn test_coordinator_vs_monte_carlo_with_noise() { let coordinator: ParallelCoordinator = ParallelCoordinator::new(coord_config); let coord_results = coordinator.run( - || SparseStab::new(1), + || SparseStab::with_seed(1, 42), |world| { let commands = CommandBuilder::new().pz(&[0]).x(&[0]).mz(&[0]).build(); @@ -264,7 +267,7 @@ fn test_coordinator_determinism() { let results1: Vec = coord1 .run( - || SparseStab::new(1), + || SparseStab::with_seed(1, 42), |world| { let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); @@ -290,7 +293,7 @@ fn test_coordinator_determinism() { let results2: Vec = coord2 .run( - || SparseStab::new(1), + || SparseStab::with_seed(1, 42), |world| { let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); @@ -339,7 +342,7 @@ fn test_coordinator_sync_points() { let sync_count_clone = Arc::clone(&sync_count); let result = coordinator.run_with_sync::<_, _, _, ()>( - || SparseStab::new(1), + || SparseStab::with_seed(1, 42), 10, // 10 steps |_world, _step| { // Do nothing per step @@ -370,7 +373,7 @@ fn test_coordinator_hadamard_distribution() { let coordinator: ParallelCoordinator = ParallelCoordinator::new(config); let results = coordinator.run( - || SparseStab::new(1), + || SparseStab::with_seed(1, 42), |world| { let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); diff --git a/exp/pecos-neo/tests/determinism_discipline.rs b/exp/pecos-neo/tests/determinism_discipline.rs new file mode 100644 index 000000000..2ba65eed1 --- /dev/null +++ b/exp/pecos-neo/tests/determinism_discipline.rs @@ -0,0 +1,379 @@ +// Copyright 2026 The PECOS Developers +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing permissions and +// limitations under the License. + +use std::collections::BTreeSet; +use std::fs; +use std::path::{Path, PathBuf}; + +struct ForbiddenConstructor { + pattern: &'static str, + alternative: &'static str, +} + +const FORBIDDEN_CONSTRUCTORS: &[ForbiddenConstructor] = &[ + ForbiddenConstructor { + pattern: "SparseStab::new", + alternative: "SparseStab::with_seed(num_qubits, 42)", + }, + ForbiddenConstructor { + pattern: "StateVec::new", + alternative: "StateVec::with_seed(num_qubits, 42)", + }, + ForbiddenConstructor { + pattern: "StateVecEngine::new", + alternative: "StateVecEngine::with_seed(num_qubits, 42)", + }, +]; + +// Entries are (crate-relative file, one-based line, forbidden pattern). +const ALLOWLIST: &[(&str, usize, &str)] = &[]; + +#[derive(Default)] +struct LexState { + block_comment_depth: usize, + in_string: bool, + raw_string_hashes: Option, +} + +#[derive(Default)] +struct ScanResults { + files_visited: usize, + seeded_constructors_in_tests: usize, + violations: Vec, +} + +#[test] +fn pecos_neo_test_simulators_require_explicit_seeds() { + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let tests_dir = manifest_dir.join("tests"); + let src_dir = manifest_dir.join("src"); + let mut results = ScanResults::default(); + + for path in rust_files_under(&tests_dir) { + scan_whole_test_file(&manifest_dir, &path, true, &mut results); + } + + let mut external_test_modules = BTreeSet::new(); + for path in rust_files_under(&src_dir) { + scan_cfg_test_modules( + &manifest_dir, + &path, + &mut external_test_modules, + &mut results, + ); + } + for path in external_test_modules { + scan_whole_test_file(&manifest_dir, &path, false, &mut results); + } + + assert!( + results.files_visited > 0, + "determinism scan did not visit any Rust files" + ); + assert!( + results.seeded_constructors_in_tests > 0, + "determinism scan found no seeded simulator constructors under tests/; the scan may be vacuous" + ); + assert!( + results.violations.is_empty(), + "pecos-neo test code must construct every simulator with an explicit seed; \ + entropy-seeded constructors are forbidden and the allowlist is intentionally empty:\n{}", + results.violations.join("\n") + ); +} + +fn rust_files_under(root: &Path) -> Vec { + fn collect(directory: &Path, files: &mut Vec) { + let entries = fs::read_dir(directory) + .unwrap_or_else(|error| panic!("failed to read {}: {error}", directory.display())); + for entry in entries { + let path = entry.expect("failed to read directory entry").path(); + if path.is_dir() { + collect(&path, files); + } else if path.extension().is_some_and(|extension| extension == "rs") { + files.push(path); + } + } + } + + let mut files = Vec::new(); + collect(root, &mut files); + files.sort(); + files +} + +fn scan_whole_test_file( + manifest_dir: &Path, + path: &Path, + count_seeded_constructors: bool, + results: &mut ScanResults, +) { + let source = read_source(path); + let relative_path = crate_relative_path(manifest_dir, path); + let mut lex_state = LexState::default(); + + results.files_visited += 1; + for (line_index, line) in source.lines().enumerate() { + let code = code_only(line, &mut lex_state); + scan_code_line( + &relative_path, + line_index + 1, + &code, + count_seeded_constructors, + results, + ); + } +} + +fn scan_cfg_test_modules( + manifest_dir: &Path, + path: &Path, + external_test_modules: &mut BTreeSet, + results: &mut ScanResults, +) { + let source = read_source(path); + let relative_path = crate_relative_path(manifest_dir, path); + let mut lex_state = LexState::default(); + let mut pending_cfg_test = false; + let mut brace_depth = 0isize; + let mut test_module_outer_depths = Vec::new(); + + results.files_visited += 1; + for (line_index, line) in source.lines().enumerate() { + let code = code_only(line, &mut lex_state); + let compact: String = code + .chars() + .filter(|character| !character.is_whitespace()) + .collect(); + let already_in_test_module = !test_module_outer_depths.is_empty(); + + if already_in_test_module { + scan_code_line(&relative_path, line_index + 1, &code, false, results); + } + + if compact == "#[cfg(test)]" { + pending_cfg_test = true; + } else if pending_cfg_test && (compact.is_empty() || compact.starts_with("#[")) { + // Permit comments, blank lines, and other attributes between cfg(test) and mod. + } else if pending_cfg_test { + if let Some((module_name, inline)) = module_declaration(&code) { + if inline { + if !already_in_test_module { + scan_code_line(&relative_path, line_index + 1, &code, false, results); + } + test_module_outer_depths.push(brace_depth); + } else if let Some(module_path) = conventional_module_path(path, &module_name) { + external_test_modules.insert(module_path); + } + } + pending_cfg_test = false; + } + + brace_depth += brace_delta(&code); + while test_module_outer_depths + .last() + .is_some_and(|outer_depth| brace_depth <= *outer_depth) + { + test_module_outer_depths.pop(); + } + } +} + +// This is deliberately a lightweight Rust lexer and brace tracker, not a full parser. It handles +// nested block comments plus ordinary/raw strings and ordinary character literals. The module +// detector expects cfg(test) on its own attribute line followed by a conventional mod declaration; +// external modules using #[path] are outside its supported syntax. +fn code_only(line: &str, state: &mut LexState) -> String { + let bytes = line.as_bytes(); + let mut code = String::with_capacity(line.len()); + let mut index = 0; + + while index < bytes.len() { + if state.block_comment_depth > 0 { + if bytes[index..].starts_with(b"/*") { + state.block_comment_depth += 1; + index += 2; + } else if bytes[index..].starts_with(b"*/") { + state.block_comment_depth -= 1; + index += 2; + } else { + index += 1; + } + continue; + } + + if let Some(hashes) = state.raw_string_hashes { + if raw_string_closes_at(bytes, index, hashes) { + state.raw_string_hashes = None; + index += hashes + 1; + } else { + index += 1; + } + continue; + } + + if state.in_string { + match bytes[index] { + b'\\' => index = (index + 2).min(bytes.len()), + b'"' => { + state.in_string = false; + index += 1; + } + _ => index += 1, + } + continue; + } + + if bytes[index..].starts_with(b"//") { + break; + } + if bytes[index..].starts_with(b"/*") { + state.block_comment_depth = 1; + index += 2; + continue; + } + if let Some((prefix_length, hashes)) = raw_string_opens_at(bytes, index) { + state.raw_string_hashes = Some(hashes); + index += prefix_length; + continue; + } + if bytes[index] == b'"' { + state.in_string = true; + index += 1; + continue; + } + if bytes[index] == b'\'' + && let Some(end) = character_literal_end(bytes, index) + { + index = end + 1; + continue; + } + + code.push(char::from(bytes[index])); + index += 1; + } + + code +} + +fn raw_string_opens_at(bytes: &[u8], index: usize) -> Option<(usize, usize)> { + let raw_prefix = if bytes.get(index) == Some(&b'r') { + index + 1 + } else if bytes.get(index..index + 2) == Some(b"br") { + index + 2 + } else { + return None; + }; + + let mut quote_index = raw_prefix; + while bytes.get(quote_index) == Some(&b'#') { + quote_index += 1; + } + (bytes.get(quote_index) == Some(&b'"')) + .then_some((quote_index - index + 1, quote_index - raw_prefix)) +} + +fn raw_string_closes_at(bytes: &[u8], index: usize, hashes: usize) -> bool { + bytes.get(index) == Some(&b'"') + && bytes + .get(index + 1..index + 1 + hashes) + .is_some_and(|suffix| suffix.iter().all(|byte| *byte == b'#')) +} + +fn character_literal_end(bytes: &[u8], start: usize) -> Option { + let mut index = start + 1; + while index < bytes.len() { + match bytes[index] { + b'\\' => index += 2, + b'\'' => return Some(index), + byte if byte.is_ascii_whitespace() => return None, + _ => index += 1, + } + } + None +} + +fn module_declaration(code: &str) -> Option<(String, bool)> { + let tokens: Vec<&str> = code + .split(|character: char| character.is_whitespace() || matches!(character, '{' | ';')) + .filter(|token| !token.is_empty()) + .collect(); + let mod_index = tokens.iter().position(|token| *token == "mod")?; + let module_name = tokens.get(mod_index + 1)?.trim().to_string(); + Some((module_name, code.contains('{'))) +} + +fn conventional_module_path(parent_file: &Path, module_name: &str) -> Option { + let parent_directory = parent_file.parent()?; + let module_base = match parent_file.file_stem()?.to_str()? { + "lib" | "main" | "mod" => parent_directory.to_path_buf(), + stem => parent_directory.join(stem), + }; + let file_module = module_base.join(format!("{module_name}.rs")); + if file_module.is_file() { + return Some(file_module); + } + let directory_module = module_base.join(module_name).join("mod.rs"); + directory_module.is_file().then_some(directory_module) +} + +fn brace_delta(code: &str) -> isize { + code.bytes().fold(0, |depth, byte| match byte { + b'{' => depth + 1, + b'}' => depth - 1, + _ => depth, + }) +} + +fn scan_code_line( + relative_path: &str, + line_number: usize, + code: &str, + count_seeded_constructors: bool, + results: &mut ScanResults, +) { + if count_seeded_constructors + && [ + "SparseStab::with_seed(", + "StateVec::with_seed(", + "StateVecEngine::with_seed(", + "CoinToss::with_seed(", + ] + .iter() + .any(|pattern| code.contains(pattern)) + { + results.seeded_constructors_in_tests += 1; + } + + for forbidden in FORBIDDEN_CONSTRUCTORS { + if code.contains(forbidden.pattern) + && !ALLOWLIST.contains(&(relative_path, line_number, forbidden.pattern)) + { + results.violations.push(format!( + "{relative_path}:{line_number}: found `{}`; use `{}`", + forbidden.pattern, forbidden.alternative + )); + } + } +} + +fn read_source(path: &Path) -> String { + fs::read_to_string(path) + .unwrap_or_else(|error| panic!("failed to read {}: {error}", path.display())) +} + +fn crate_relative_path(manifest_dir: &Path, path: &Path) -> String { + path.strip_prefix(manifest_dir) + .unwrap_or(path) + .display() + .to_string() +} diff --git a/exp/pecos-neo/tests/engine_comparison_test.rs b/exp/pecos-neo/tests/engine_comparison_test.rs index e30f71455..7de29e357 100644 --- a/exp/pecos-neo/tests/engine_comparison_test.rs +++ b/exp/pecos-neo/tests/engine_comparison_test.rs @@ -146,7 +146,7 @@ fn test_monte_carlo_bell_state_no_noise() { let neo_results = MonteCarloRunner::run( &commands, &config, - || (CircuitRunner::new(), SparseStab::new(2)), + || (CircuitRunner::new(), SparseStab::with_seed(2, 42)), |outcomes| { let b0 = outcomes.get_bit(QubitId(0)).unwrap_or(false); let b1 = outcomes.get_bit(QubitId(1)).unwrap_or(false); @@ -230,7 +230,7 @@ fn test_monte_carlo_with_depolarizing_noise() { let neo_noise = GeneralNoiseModelBuilder::new().with_p1(p1).build(); ( CircuitRunner::new().with_noise(neo_noise), - SparseStab::new(1), + SparseStab::with_seed(1, 42), ) }, |outcomes| { @@ -309,7 +309,7 @@ fn test_monte_carlo_measurement_errors() { .build(); ( CircuitRunner::new().with_noise(neo_noise), - SparseStab::new(1), + SparseStab::with_seed(1, 42), ) }, |outcomes| { @@ -356,7 +356,7 @@ fn test_monte_carlo_parallel_execution() { let results_parallel = MonteCarloRunner::run( &commands, &config_parallel, - || (CircuitRunner::new(), SparseStab::new(1)), + || (CircuitRunner::new(), SparseStab::with_seed(1, 42)), |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ); @@ -369,7 +369,7 @@ fn test_monte_carlo_parallel_execution() { let results_single = MonteCarloRunner::run( &commands, &config_single, - || (CircuitRunner::new(), SparseStab::new(1)), + || (CircuitRunner::new(), SparseStab::with_seed(1, 123)), |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ); @@ -451,7 +451,7 @@ fn test_monte_carlo_two_qubit_noise() { let neo_noise = GeneralNoiseModelBuilder::new().with_p2(p2).build(); ( CircuitRunner::new().with_noise(neo_noise), - SparseStab::new(2), + SparseStab::with_seed(2, 42), ) }, |outcomes| { @@ -514,7 +514,7 @@ fn test_monte_carlo_deterministic_circuit() { let results: Vec = MonteCarloRunner::run( &commands, &config, - || (CircuitRunner::new(), SparseStab::new(1)), + || (CircuitRunner::new(), SparseStab::with_seed(1, 42)), |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ) .into_iter() @@ -540,7 +540,7 @@ fn test_monte_carlo_statistical_consistency() { let results: Vec = MonteCarloRunner::run( &commands, &config, - || (CircuitRunner::new(), SparseStab::new(1)), + || (CircuitRunner::new(), SparseStab::with_seed(1, 42)), |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ) .into_iter() @@ -561,9 +561,9 @@ fn test_full_seed_determinism() { let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); // Run twice with same full seed - should produce identical results - let mut state1 = SparseStab::new(1); + let mut state1 = SparseStab::with_seed(1, 42); let mut runner1 = CircuitRunner::::new().with_full_seed(&mut state1, 42); - let mut state2 = SparseStab::new(1); + let mut state2 = SparseStab::with_seed(1, 42); let mut runner2 = CircuitRunner::::new().with_full_seed(&mut state2, 42); let mut results1 = Vec::new(); @@ -621,7 +621,7 @@ fn test_importance_sampling_matches_standard_monte_carlo() { let mut standard_ones = 0; for seed in 0..num_shots { let noise = GeneralNoiseModelBuilder::new().with_p1(p_error).build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, seed as u64); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed(seed as u64); @@ -639,7 +639,7 @@ fn test_importance_sampling_matches_standard_monte_carlo() { let mut total_weight = 0.0; for seed in 0..num_shots { - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(1)) + let mut runner = ImportanceSamplingRunner::new(SparseStab::with_seed(1, seed as u64)) .with_single_qubit_boost(p_error, boost) .with_seed(seed as u64); let result = runner.run_shot(&commands); @@ -701,7 +701,7 @@ fn test_importance_sampling_rare_events() { let mut standard_ones = 0; for seed in 0..num_shots { let noise = GeneralNoiseModelBuilder::new().with_p1(p_error).build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, seed as u64); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed(seed as u64); @@ -717,7 +717,7 @@ fn test_importance_sampling_rare_events() { let mut total_weight = 0.0; for seed in 0..num_shots { - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(1)) + let mut runner = ImportanceSamplingRunner::new(SparseStab::with_seed(1, seed as u64)) .with_single_qubit_boost(p_error, boost) .with_seed(seed as u64); let result = runner.run_shot(&commands); @@ -774,7 +774,7 @@ fn test_importance_sampling_variance_reduction() { let mut ones = 0; for shot in 0..shots_per_trial { let noise = GeneralNoiseModelBuilder::new().with_p1(p_error).build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, (base_seed + shot) as u64); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed((base_seed + shot) as u64); @@ -794,9 +794,10 @@ fn test_importance_sampling_variance_reduction() { let mut total_weight = 0.0; for shot in 0..shots_per_trial { - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(1)) - .with_single_qubit_boost(p_error, boost) - .with_seed((base_seed + shot) as u64); + let mut runner = + ImportanceSamplingRunner::new(SparseStab::with_seed(1, (base_seed + shot) as u64)) + .with_single_qubit_boost(p_error, boost) + .with_seed((base_seed + shot) as u64); let result = runner.run_shot(&commands); let value = if result.outcomes.get_bit(QubitId(0)).unwrap_or(false) { diff --git a/exp/pecos-neo/tests/event_handlers_test.rs b/exp/pecos-neo/tests/event_handlers_test.rs index 8df4fcd62..8627f53c6 100644 --- a/exp/pecos-neo/tests/event_handlers_test.rs +++ b/exp/pecos-neo/tests/event_handlers_test.rs @@ -158,7 +158,7 @@ fn event_handlers_on_runner_directly() { let circuit = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); - let mut state = pecos_simulators::SparseStab::new(1); + let mut state = pecos_simulators::SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_event_handlers(handlers) .with_seed(42); diff --git a/exp/pecos-neo/tests/extensible_integration_test.rs b/exp/pecos-neo/tests/extensible_integration_test.rs index 46bcd4644..c2eda910c 100644 --- a/exp/pecos-neo/tests/extensible_integration_test.rs +++ b/exp/pecos-neo/tests/extensible_integration_test.rs @@ -423,7 +423,7 @@ fn test_noisy_execution_statistics() { let noise = ComposableNoiseModel::new() .add_channel(SingleQubitChannel::depolarizing(high_noise_rate)); let mut program = StaticProgram::new(commands.clone(), 1); - let mut runner = ProgramRunner::new(SparseStab::new(1)) + let mut runner = ProgramRunner::new(SparseStab::with_seed(1, seed as u64)) .with_noise(noise) .with_seed(seed as u64); @@ -528,7 +528,7 @@ fn test_command_source_with_user_gates() { // Create program using the user gate let mut program = UserGateProgram::new(user_gate_id); - let mut runner = ProgramRunner::new(SparseStab::new(2)).with_seed(42); + let mut runner = ProgramRunner::new(SparseStab::with_seed(2, 42)).with_seed(42); let result = runner.run_shot(&mut program); @@ -564,7 +564,8 @@ fn test_conditional_program_with_feedback() { for seed in 0..num_shots { let mut program = ConditionalProgram::new(initial.clone(), branch, 1); - let mut runner = ProgramRunner::new(SparseStab::new(1)).with_seed(seed as u64); + let mut runner = + ProgramRunner::new(SparseStab::with_seed(1, seed as u64)).with_seed(seed as u64); let result = runner.run_shot(&mut program); @@ -916,7 +917,7 @@ fn test_e2e_custom_gate_definition_and_execution() { let num_shots = 100; for seed in 0..num_shots { - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, seed as u64); let mut runner = CircuitRunner::::new().with_seed(seed as u64); let outcomes = runner.apply_circuit(&mut state, &commands).unwrap(); @@ -1131,7 +1132,7 @@ fn test_e2e_custom_gate_noise_limitation() { .mz(&[0]) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(noise) .with_seed(42); @@ -1231,7 +1232,7 @@ fn test_e2e_complete_workflow_with_shot_runner() { .build(); // Use CircuitRunner directly - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::new().with_seed(42); let outcomes = runner.apply_circuit(&mut state, &commands).unwrap(); diff --git a/exp/pecos-neo/tests/noise_comparison_test.rs b/exp/pecos-neo/tests/noise_comparison_test.rs index 8e4d3c7d7..29df0f235 100644 --- a/exp/pecos-neo/tests/noise_comparison_test.rs +++ b/exp/pecos-neo/tests/noise_comparison_test.rs @@ -40,7 +40,7 @@ fn run_general_noise_model( num_qubits: usize, num_shots: usize, ) -> BTreeMap { - let quantum = Box::new(StateVecEngine::new(num_qubits)); + let quantum = Box::new(StateVecEngine::with_seed(num_qubits, 42)); let mut system = QuantumSystem::new(Box::new(noise_model), quantum); system.set_seed(42); @@ -88,7 +88,7 @@ fn run_composable_noise_model( num_qubits: usize, num_shots: usize, ) -> BTreeMap { - let mut state = SparseStab::new(num_qubits); + let mut state = SparseStab::with_seed(num_qubits, 42); let mut runner = CircuitRunner::::new() .with_noise(noise_model) .with_seed(42); @@ -595,7 +595,7 @@ fn test_idle_noise_with_time_scale() { .mz(&[0]) .build(); - let mut state = SparseStab::new(1); + let mut state = SparseStab::with_seed(1, 42); let mut runner = CircuitRunner::::new() .with_noise(model) .with_seed(42); diff --git a/exp/pecos-neo/tests/sampling_demonstration_test.rs b/exp/pecos-neo/tests/sampling_demonstration_test.rs index a39054930..d383d3936 100644 --- a/exp/pecos-neo/tests/sampling_demonstration_test.rs +++ b/exp/pecos-neo/tests/sampling_demonstration_test.rs @@ -40,7 +40,7 @@ fn demo_path_recording() { .mz(&[0]) .build(); - let mut explorer = PathExplorer::new(SparseStab::new(1)).with_seed(42); + let mut explorer = PathExplorer::new(SparseStab::with_seed(1, 42)).with_seed(42); // Run and record the path let result = explorer.run_and_record(&circuit); @@ -64,7 +64,7 @@ fn demo_path_recording() { fn demo_path_replay() { let circuit = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); - let mut explorer = PathExplorer::new(SparseStab::new(1)); + let mut explorer = PathExplorer::new(SparseStab::with_seed(1, 42)); println!("\nPath Replay Demo:"); @@ -100,7 +100,7 @@ fn demo_path_enumeration() { .mz(&[1]) .build(); - let mut explorer = PathExplorer::new(SparseStab::new(2)); + let mut explorer = PathExplorer::new(SparseStab::with_seed(2, 42)); let mut stats = PathStatistics::new(); println!("\nPath Enumeration Demo:"); @@ -143,7 +143,7 @@ fn demo_bell_state_paths() { .mz(&[1]) .build(); - let mut explorer = PathExplorer::new(SparseStab::new(2)); + let mut explorer = PathExplorer::new(SparseStab::with_seed(2, 42)); println!("\nBell State Path Demo:"); println!(" In a Bell state, q1's measurement is DETERMINISTIC after q0 is measured."); @@ -197,7 +197,7 @@ fn demo_importance_sampling_boosted_errors() { println!(" Boost factor: {boost}x"); // Run many shots with boosted error rate - let mut runner = ImportanceSamplingRunner::new(SparseStab::new(1)) + let mut runner = ImportanceSamplingRunner::new(SparseStab::with_seed(1, 42)) .with_single_qubit_boost(p_true, boost) .with_seed(42); @@ -246,7 +246,7 @@ fn demo_variance_comparison() { for trial in 0..num_trials { // Standard Monte Carlo (true error rate) - let mut mc_state = SparseStab::new(1); + let mut mc_state = SparseStab::with_seed(1, trial as u64); let mut mc_runner = CircuitRunner::::new() .with_noise( ComposableNoiseModel::new().add_channel(SingleQubitChannel::depolarizing(p_true)), @@ -265,13 +265,14 @@ fn demo_variance_comparison() { // Importance sampling (boosted) let p_proposal = (p_true * boost).min(0.5_f64); - let mut is_runner = ImportanceSamplingRunner::new(SparseStab::new(1)) - .with_single_qubit_boost(p_true, boost) - .with_noise( - ComposableNoiseModel::new() - .add_channel(SingleQubitChannel::depolarizing(p_proposal)), - ) - .with_seed(1000 + trial as u64); + let mut is_runner = + ImportanceSamplingRunner::new(SparseStab::with_seed(1, 1000 + trial as u64)) + .with_single_qubit_boost(p_true, boost) + .with_noise( + ComposableNoiseModel::new() + .add_channel(SingleQubitChannel::depolarizing(p_proposal)), + ) + .with_seed(1000 + trial as u64); let mut is_stats = WeightedStatistics::new(); for _ in 0..shots_per_trial { @@ -326,7 +327,8 @@ fn demo_outcome_biasing() { println!(" Biasing measurements to explore rare branches."); // Without biasing: 50/50 outcomes - let mut unbiased_runner = ImportanceSamplingRunner::new(SparseStab::new(1)).with_seed(42); + let mut unbiased_runner = + ImportanceSamplingRunner::new(SparseStab::with_seed(1, 42)).with_seed(42); let mut count_one = 0; for _ in 0..1000 { @@ -339,7 +341,7 @@ fn demo_outcome_biasing() { // With biasing toward '1': more '1' outcomes (but with weights) let bias_config = OutcomeBiasConfig::bias_toward_one(0.9); - let mut biased_runner = ImportanceSamplingRunner::new(SparseStab::new(1)) + let mut biased_runner = ImportanceSamplingRunner::new(SparseStab::with_seed(1, 42)) .with_outcome_bias(bias_config) .with_seed(42); @@ -393,7 +395,7 @@ fn demo_conditional_program() { }; let mut program = ConditionalProgram::new(initial, branch_fn, 1); - let mut runner = ProgramRunner::new(SparseStab::new(1)).with_seed(42); + let mut runner = ProgramRunner::new(SparseStab::with_seed(1, 42)).with_seed(42); println!("\nConditional Program Demo:"); @@ -479,7 +481,7 @@ fn demo_repeat_until_success() { success: false, }; - let mut runner = ProgramRunner::new(SparseStab::new(1)).with_seed(42); + let mut runner = ProgramRunner::new(SparseStab::with_seed(1, 42)).with_seed(42); println!("\nRepeat-Until-Success Demo:"); @@ -513,7 +515,7 @@ fn demo_combined_path_and_error_analysis() { .mz(&[1]) .build(); - let mut explorer = PathExplorer::new(SparseStab::new(3)); + let mut explorer = PathExplorer::new(SparseStab::with_seed(3, 42)); let mut error_stats = PathStatistics::new(); println!("\nCombined Path + Error Analysis Demo:"); diff --git a/exp/pecos-neo/tests/sim_neo_comparison_test.rs b/exp/pecos-neo/tests/sim_neo_comparison_test.rs index 08d17996d..1cf9ad081 100644 --- a/exp/pecos-neo/tests/sim_neo_comparison_test.rs +++ b/exp/pecos-neo/tests/sim_neo_comparison_test.rs @@ -461,7 +461,7 @@ fn test_sim_neo_vs_sim_conditional_x_correction() { for shot_idx in 0..NUM_SHOTS { let mut program = ConditionalProgram::new(initial.clone(), branch, 1); let seed = 42u64.wrapping_add(shot_idx as u64); - let mut runner = ProgramRunner::new(SparseStab::new(1)).with_seed(seed); + let mut runner = ProgramRunner::new(SparseStab::with_seed(1, seed)).with_seed(seed); let result = runner.run_shot(&mut program); @@ -552,7 +552,7 @@ fn test_sim_neo_vs_sim_conditional_with_noise() { let seed = 42u64.wrapping_add(shot_idx as u64); // Create fresh noise model for each shot let neo_noise = GeneralNoiseModelBuilder::new().with_p1(p1).build(); - let mut runner = ProgramRunner::new(SparseStab::new(1)) + let mut runner = ProgramRunner::new(SparseStab::with_seed(1, seed)) .with_noise(neo_noise) .with_seed(seed); diff --git a/exp/pecos-neo/tests/splitting_test.rs b/exp/pecos-neo/tests/splitting_test.rs index 9ed4346cb..cc868a035 100644 --- a/exp/pecos-neo/tests/splitting_test.rs +++ b/exp/pecos-neo/tests/splitting_test.rs @@ -24,9 +24,9 @@ fn test_apply_split_decisions_prune() { let mut world: World = World::new(42); // Create some entities - let e1 = world.spawn_with_simulator(SparseStab::new(1)); - let e2 = world.spawn_with_simulator(SparseStab::new(1)); - let e3 = world.spawn_with_simulator(SparseStab::new(1)); + let e1 = world.spawn_with_simulator(SparseStab::with_seed(1, 42)); + let e2 = world.spawn_with_simulator(SparseStab::with_seed(1, 42)); + let e3 = world.spawn_with_simulator(SparseStab::with_seed(1, 42)); assert_eq!(world.active_entities().len(), 3); @@ -46,7 +46,7 @@ fn test_apply_split_decisions_split() { let mut world: World = World::new(42); // Create one entity - let e1 = world.spawn_with_simulator(SparseStab::new(1)); + let e1 = world.spawn_with_simulator(SparseStab::with_seed(1, 42)); assert_eq!(world.active_entities().len(), 1); @@ -71,9 +71,9 @@ fn test_apply_split_decisions_split() { fn test_apply_split_decisions_mixed() { let mut world: World = World::new(42); - let e1 = world.spawn_with_simulator(SparseStab::new(1)); - let e2 = world.spawn_with_simulator(SparseStab::new(1)); - let e3 = world.spawn_with_simulator(SparseStab::new(1)); + let e1 = world.spawn_with_simulator(SparseStab::with_seed(1, 42)); + let e2 = world.spawn_with_simulator(SparseStab::with_seed(1, 42)); + let e3 = world.spawn_with_simulator(SparseStab::with_seed(1, 42)); // e1: keep, e2: prune, e3: split into 3 let decisions = vec![(e1, 1), (e2, 0), (e3, 3)]; @@ -88,9 +88,9 @@ fn test_resample_by_weight_preserves_total_weight() { let mut world: World = World::new(42); // Create entities with different weights - let e1 = world.spawn_with_simulator(SparseStab::new(1)); - let e2 = world.spawn_with_simulator(SparseStab::new(1)); - let e3 = world.spawn_with_simulator(SparseStab::new(1)); + let e1 = world.spawn_with_simulator(SparseStab::with_seed(1, 42)); + let e2 = world.spawn_with_simulator(SparseStab::with_seed(1, 42)); + let e3 = world.spawn_with_simulator(SparseStab::with_seed(1, 42)); // Set weights: e1=1.0, e2=2.0, e3=3.0, total=6.0 world.weights.get_mut(e1).unwrap().weight = SampleWeight::from_linear(1.0); @@ -123,9 +123,9 @@ fn test_resample_by_weight_respects_probabilities() { for trial in 0..trials { let mut world: World = World::new(trial); - let e1 = world.spawn_with_simulator(SparseStab::new(1)); - let e2 = world.spawn_with_simulator(SparseStab::new(1)); - let e3 = world.spawn_with_simulator(SparseStab::new(1)); + let e1 = world.spawn_with_simulator(SparseStab::with_seed(1, trial)); + let e2 = world.spawn_with_simulator(SparseStab::with_seed(1, trial)); + let e3 = world.spawn_with_simulator(SparseStab::with_seed(1, trial)); // Weights: e1=1, e2=2, e3=7 (e3 should be selected ~70% of time) world.weights.get_mut(e1).unwrap().weight = SampleWeight::from_linear(1.0); @@ -221,7 +221,7 @@ fn test_entity_transfer() { let mut world2: World = World::new(43); // Create entity in world1 with specific weight - let e1 = world1.spawn_with_simulator(SparseStab::new(1)); + let e1 = world1.spawn_with_simulator(SparseStab::with_seed(1, 42)); world1.weights.get_mut(e1).unwrap().weight = SampleWeight::from_linear(5.0); assert_eq!(world1.active_entities().len(), 1); @@ -251,7 +251,9 @@ fn test_redistribution_at_sync_points() { let mut worker = WorkerState::new(id, 42); // Each worker gets 5 entities with varying weights for i in 0..5 { - let e = worker.world.spawn_with_simulator(SparseStab::new(1)); + let e = worker + .world + .spawn_with_simulator(SparseStab::with_seed(1, 42)); worker.world.weights.get_mut(e).unwrap().weight = SampleWeight::from_linear(f64::from(i + 1)); } @@ -316,7 +318,9 @@ fn test_subset_simulation_workflow() { .map(|id| { let mut worker = WorkerState::new(id, 42 + id as u64); for _ in 0..entities_per_worker { - worker.world.spawn_with_simulator(SparseStab::new(1)); + worker + .world + .spawn_with_simulator(SparseStab::with_seed(1, 42 + id as u64)); } worker }) @@ -495,7 +499,9 @@ fn test_redistribution_exact_weight_preservation() { .map(|id| { let mut worker = WorkerState::new(id, 100 + id as u64); for i in 0..10 { - let e = worker.world.spawn_with_simulator(SparseStab::new(1)); + let e = worker + .world + .spawn_with_simulator(SparseStab::with_seed(1, 100 + id as u64)); // Set varying weights worker.world.weights.get_mut(e).unwrap().weight = SampleWeight::from_linear(0.1 * f64::from(i + 1)); @@ -535,11 +541,15 @@ fn test_redistribution_extreme_weights() { .collect(); // One entity with very high weight, rest with very low - let e1 = workers[0].world.spawn_with_simulator(SparseStab::new(1)); + let e1 = workers[0] + .world + .spawn_with_simulator(SparseStab::with_seed(1, 42)); workers[0].world.weights.get_mut(e1).unwrap().weight = SampleWeight::from_linear(100.0); for _ in 0..9 { - let e = workers[0].world.spawn_with_simulator(SparseStab::new(1)); + let e = workers[0] + .world + .spawn_with_simulator(SparseStab::with_seed(1, 42)); workers[0].world.weights.get_mut(e).unwrap().weight = SampleWeight::from_linear(0.001); } @@ -574,9 +584,9 @@ fn test_resampling_statistical_correctness() { for trial in 0..trials { let mut world: World = World::new(1000 + trial); - let e1 = world.spawn_with_simulator(SparseStab::new(1)); - let e2 = world.spawn_with_simulator(SparseStab::new(1)); - let e3 = world.spawn_with_simulator(SparseStab::new(1)); + let e1 = world.spawn_with_simulator(SparseStab::with_seed(1, 1000 + trial)); + let e2 = world.spawn_with_simulator(SparseStab::with_seed(1, 1000 + trial)); + let e3 = world.spawn_with_simulator(SparseStab::with_seed(1, 1000 + trial)); // Weights: 1, 3, 6 (proportions: 0.1, 0.3, 0.6) world.weights.get_mut(e1).unwrap().weight = SampleWeight::from_linear(1.0); @@ -637,7 +647,7 @@ fn test_entity_state_preservation_through_transfer() { let mut world1: World = World::new(42); // Create entity and modify its simulator state - let e1 = world1.spawn_with_simulator(SparseStab::new(2)); + let e1 = world1.spawn_with_simulator(SparseStab::with_seed(2, 42)); // Apply some gates to create a non-trivial state if let Some(sim_comp) = world1.simulators.get_mut(e1) { @@ -685,7 +695,7 @@ fn test_splitting_weight_invariants() { let mut world: World = World::new(42); // Create entity with weight 1.0 - let e1 = world.spawn_with_simulator(SparseStab::new(1)); + let e1 = world.spawn_with_simulator(SparseStab::with_seed(1, 42)); let initial_weight = world.total_weight(); assert!((initial_weight - 1.0).abs() < 1e-10); @@ -743,7 +753,7 @@ fn test_resampling_edge_cases() { assert_eq!(count, 0, "Empty world should return 0"); // Test resampling to 0 entities - let e = world.spawn_with_simulator(SparseStab::new(1)); + let e = world.spawn_with_simulator(SparseStab::with_seed(1, 42)); assert!(world.is_alive(e)); let count = world.resample_by_weight(0, &mut rng); @@ -760,7 +770,9 @@ fn test_redistribution_determinism() { .map(|id| { let mut worker = WorkerState::new(id, 42); for i in 0..5 { - let e = worker.world.spawn_with_simulator(SparseStab::new(1)); + let e = worker + .world + .spawn_with_simulator(SparseStab::with_seed(1, 42)); worker.world.weights.get_mut(e).unwrap().weight = SampleWeight::from_linear(f64::from(i + 1)); } @@ -847,7 +859,7 @@ fn test_quantum_circuit_subset_simulation() { for sample in 0..num_samples { let mut syndrome_detections = 0; - let mut state = SparseStab::new(2); + let mut state = SparseStab::with_seed(2, 42); let mut runner = CircuitRunner::::new().with_rng(PecosRng::seed_from_u64(sample)); @@ -888,7 +900,7 @@ fn test_quantum_circuit_subset_simulation() { // Spawn entities (trajectories) for _ in 0..num_samples { - world.spawn_with_simulator(SparseStab::new(2)); + world.spawn_with_simulator(SparseStab::with_seed(2, 12345)); } // Track syndrome detections per entity diff --git a/exp/pecos-neo/tests/statistical_validation_test.rs b/exp/pecos-neo/tests/statistical_validation_test.rs index f4f73da04..59031a82b 100644 --- a/exp/pecos-neo/tests/statistical_validation_test.rs +++ b/exp/pecos-neo/tests/statistical_validation_test.rs @@ -99,7 +99,7 @@ fn test_hadamard_distribution_high_statistics() { let mc_results = MonteCarloRunner::run( &commands, &mc_config, - || (CircuitRunner::new(), SparseStab::new(1)), + || (CircuitRunner::new(), SparseStab::with_seed(1, 42)), |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ); @@ -116,7 +116,7 @@ fn test_hadamard_distribution_high_statistics() { let coordinator: ParallelCoordinator = ParallelCoordinator::new(coord_config); let coord_results = coordinator.run( - || SparseStab::new(1), + || SparseStab::with_seed(1, 42), |world| { let commands = CommandBuilder::new().pz(&[0]).h(&[0]).mz(&[0]).build(); @@ -189,7 +189,7 @@ fn test_bell_state_distribution_high_statistics() { let mc_results = MonteCarloRunner::run( &commands, &mc_config, - || (CircuitRunner::new(), SparseStab::new(2)), + || (CircuitRunner::new(), SparseStab::with_seed(2, 42)), |outcomes| { let b0 = outcomes.get_bit(QubitId(0)).unwrap_or(false); let b1 = outcomes.get_bit(QubitId(1)).unwrap_or(false); @@ -276,7 +276,10 @@ fn test_depolarizing_noise_rate_validation() { &mc_config, || { let noise = GeneralNoiseModelBuilder::new().with_p1(p1).build(); - (CircuitRunner::new().with_noise(noise), SparseStab::new(1)) + ( + CircuitRunner::new().with_noise(noise), + SparseStab::with_seed(1, 42), + ) }, |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ); @@ -333,7 +336,10 @@ fn test_measurement_error_rate_validation() { let noise = GeneralNoiseModelBuilder::new() .with_p_meas(p_meas, 0.0) // Only 0->1 flip .build(); - (CircuitRunner::new().with_noise(noise), SparseStab::new(1)) + ( + CircuitRunner::new().with_noise(noise), + SparseStab::with_seed(1, 42), + ) }, |outcomes| outcomes.get_bit(QubitId(0)).unwrap_or(false), ); @@ -418,7 +424,7 @@ fn test_neo_vs_engines_bell_state_comparison() { let neo_results = MonteCarloRunner::run( &commands, &mc_config, - || (CircuitRunner::new(), SparseStab::new(2)), + || (CircuitRunner::new(), SparseStab::with_seed(2, 42)), |outcomes| { let b0 = outcomes.get_bit(QubitId(0)).unwrap_or(false); let b1 = outcomes.get_bit(QubitId(1)).unwrap_or(false); @@ -527,7 +533,10 @@ fn test_neo_vs_engines_noisy_comparison() { .with_p1(p1) .with_p2(p2) .build(); - (CircuitRunner::new().with_noise(noise), SparseStab::new(2)) + ( + CircuitRunner::new().with_noise(noise), + SparseStab::with_seed(2, 42), + ) }, |outcomes| { let b0 = outcomes.get_bit(QubitId(0)).unwrap_or(false); diff --git a/exp/pecos-neo/tests/surface_code_comparison_test.rs b/exp/pecos-neo/tests/surface_code_comparison_test.rs index b3884d998..e82307c72 100644 --- a/exp/pecos-neo/tests/surface_code_comparison_test.rs +++ b/exp/pecos-neo/tests/surface_code_comparison_test.rs @@ -168,7 +168,10 @@ fn run_general_noise_repetition( num_rounds: usize, num_shots: usize, ) -> SyndromeStatistics { - let quantum = Box::new(StateVecEngine::new(RepetitionCodeD3::num_qubits())); + let quantum = Box::new(StateVecEngine::with_seed( + RepetitionCodeD3::num_qubits(), + 42, + )); let mut system = QuantumSystem::new(Box::new(noise_model), quantum); system.set_seed(42); @@ -337,7 +340,7 @@ fn run_composable_noise_repetition( let noise_model = noise_config.build(); // Run with fresh simulator and RNG state per shot for better independence - let mut state = SparseStab::new(RepetitionCodeD3::num_qubits()); + let mut state = SparseStab::with_seed(RepetitionCodeD3::num_qubits(), 42 + shot as u64); let mut runner = CircuitRunner::::new() .with_noise(noise_model) .with_seed(42 + shot as u64);