Skip to content

Commit d51f4f2

Browse files
committed
Simplify orchestrator
1 parent 51f35be commit d51f4f2

7 files changed

Lines changed: 375 additions & 369 deletions

File tree

crates/pecos-neo/README.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,26 @@ This crate provides a composable approach to quantum simulation with:
66

77
- **Typed Commands**: `GateCommand` and `CommandQueue` replacing `ByteMessage`
88
- **Composable Noise**: Event-driven noise channels that can be freely combined
9-
- **Plugin System**: Bevy-inspired architecture for bundling functionality
9+
- **Plugin System**: ECS-inspired architecture for bundling functionality
1010
- **Simple Runner**: Direct simulator execution via `ShotRunner`
1111

1212
## Architecture
1313

14-
The key insight is **composition over configuration**. Instead of a monolithic noise model with dozens of parameters, you compose small, focused channels:
14+
The key insight is **configuration via composition**. Instead of a monolithic noise model with dozens of parameters, you compose small, focused channels:
1515

1616
```
1717
┌─────────────────────────────────────────────────────────────┐
18-
│ ComposableNoiseModel
18+
│ ComposableNoiseModel │
1919
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
2020
│ │ SingleQubit │ │ TwoQubit │ │ Measurement │ ... │
2121
│ │ Channel │ │ Channel │ │ Channel │ │
2222
│ └─────────────┘ └─────────────┘ └─────────────┘ │
23-
│ │ │ │
24-
│ └───────────────┴───────────────┘
25-
│ │
26-
│ NoiseEvent
27-
│ (BeforeGate, AfterGate,
28-
│ AfterMeasurement, etc.)
23+
│ │ │ │ │
24+
│ └───────────────┴───────────────┘ │
25+
│ │ │
26+
│ NoiseEvent │
27+
│ (BeforeGate, AfterGate, │
28+
│ AfterMeasurement, etc.) │
2929
└─────────────────────────────────────────────────────────────┘
3030
```
3131

@@ -161,8 +161,8 @@ use pecos_qsim::StateVec;
161161

162162
let commands = CommandBuilder::new()
163163
.pz(0)
164-
.rx(0, Angle64::HALF_TURN) // RX(pi) = X gate
165-
.rzz(0, 1, Angle64::QUARTER_TURN) // RZZ(pi/2)
164+
.rx(Angle64::HALF_TURN, 0) // RX(pi) = X gate
165+
.rzz(Angle64::QUARTER_TURN, 0, 1) // RZZ(pi/2)
166166
.mz(0)
167167
.build();
168168

@@ -177,8 +177,8 @@ CCX and CRZ are automatically decomposed into supported gates.
177177
## Idle Time Modeling
178178

179179
The `IdleChannel` models T1/T2 decay during idle periods.
180-
Time is specified in abstract time units - the interpretation (nanoseconds, clock cycles, etc.)
181-
is defined by the noise model configuration.
180+
Time is specified in abstract time units - the interpretation (nanoseconds,
181+
clock cycles, etc.) is defined by the noise model configuration.
182182

183183
```rust
184184
use pecos_neo::prelude::*;
@@ -213,6 +213,7 @@ Available time scales: `NANOSECONDS`, `MICROSECONDS`, `MILLISECONDS`, `SECONDS`,
213213
or custom via `TimeScale::from_cycle_time_ns(50.0)` for gate-cycle-based timing.
214214

215215
You can also add precision to coarse units:
216+
216217
```rust
217218
// Think in seconds, but with nanosecond precision (9 decimal places)
218219
let scale = TimeScale::SECONDS.with_precision(9);
@@ -346,7 +347,7 @@ See the `large_scale` example for a benchmark.
346347

347348
## Design Philosophy
348349

349-
1. **Composition over Configuration**: Build complex models from simple pieces
350+
1. **Configuration via Composition**: Build complex models from simple pieces
350351
2. **Explicit over Implicit**: See exactly what channels are active
351352
3. **Flexible Foundation**: The composable system supports any noise model
352353
4. **Convenience Wrappers**: Builders provide familiar APIs for common patterns

crates/pecos-neo/docs/README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,17 @@ The `sim_neo` API supports different execution strategies via orchestrators:
188188

189189
| Orchestrator | Use Case |
190190
|--------------|----------|
191-
| `Sequential` (default) | Simple sequential execution |
192-
| `MonteCarlo { workers }` | Parallel execution (noiseless or noisy) |
193-
| `ImportanceSampling` | Biased sampling for rare event estimation |
191+
| `MonteCarlo { workers: 1 }` (default) | Single-worker execution via Tool schedule |
192+
| `MonteCarlo { workers: n }` | Parallel execution across n workers |
193+
| `ImportanceSampling` | Biased sampling for rare event estimation (via Tool schedule) |
194+
195+
All orchestrators run through the Tool/Schedule/Plugin system, so user-registered
196+
plugins fire correctly regardless of orchestrator. `ImportanceSampling` uses
197+
`ImportanceSamplingSimPlugin` (which replaces `UnifiedSimulationPlugin`) to run
198+
`ImportanceSamplingRunner` inside the standard Stage pipeline.
194199

195200
```rust
196-
// Sequential (default)
201+
// Default (single worker)
197202
sim_neo(circuit).shots(1000).run();
198203

199204
// Parallel Monte Carlo (works with or without noise)
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ pub use plugin::{Plugin, PluginGroup};
9797
pub use resource::{Resource, Resources};
9898
pub use simulation::{
9999
Circuit, CustomBackendBuilder, ImportanceSamplingBuilder, NoiseResource, Orchestrator,
100-
QuantumBackend, SimConfig, SimNeoBuilder, SimNeoInput, Simulation, SimulationPlugin,
101-
SimulationResults, SimulatorFactory, SparseStabBuilder, StateVecBuilder, custom_backend,
102-
importance_sampling, sim_neo, sim_neo_builder, sparse_stab, state_vector,
100+
QuantumBackend, SimConfig, SimNeoBuilder, SimNeoInput, Simulation, SimulationResults,
101+
SimulatorFactory, SparseStabBuilder, StateVecBuilder, custom_backend, importance_sampling,
102+
sim_neo, sim_neo_builder, sparse_stab, state_vector,
103103
};
104104
#[cfg(feature = "engines-adapter")]
105105
pub use simulation::{PendingEngineBuilder, TypedProgram};

crates/pecos-neo/src/tool/core.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,15 @@ impl Tool {
238238
self.schedule.run_stage(Stage::Finish, &mut self.resources);
239239
}
240240

241+
/// Run the complete shot loop using the schedule directly on provided resources.
242+
///
243+
/// Unlike `run_shots()`, this always runs Startup (no `has_run_startup` guard)
244+
/// and operates on the provided resources rather than the Tool's own resources.
245+
/// Used by parallel workers that each have their own Resources.
246+
pub fn run_shots_on(&self, resources: &mut Resources, shots: usize) {
247+
self.schedule.run_shots(resources, shots);
248+
}
249+
241250
/// Reset the tool for another run.
242251
///
243252
/// This clears the startup flag, allowing `Startup` systems to run again.
@@ -256,6 +265,12 @@ impl Tool {
256265
pub fn resources_mut(&mut self) -> &mut Resources {
257266
&mut self.resources
258267
}
268+
269+
/// Get a reference to the schedule (for advanced use).
270+
#[must_use]
271+
pub fn schedule(&self) -> &Schedule {
272+
&self.schedule
273+
}
259274
}
260275

261276
#[cfg(test)]

crates/pecos-neo/src/tool/design.md

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ pub struct Circuit(pub CommandQueue);
123123
pub struct SimConfig {
124124
pub shots: usize,
125125
pub seed: Option<u64>,
126-
pub workers: usize,
127126
}
128127
pub struct SimulationResults { ... }
129128
```
@@ -179,16 +178,12 @@ impl SimNeoBuilder {
179178
/// Build the simulation handle
180179
pub fn build(self) -> Simulation {
181180
let tool = Tool::new()
182-
.add_plugin(SimulationPlugin)
183-
.add_plugin(NoisePlugin::new(self.noise))
184-
.insert_resource(Circuit(self.circuit))
185-
.insert_resource(SimConfig {
186-
shots: self.shots,
187-
seed: self.seed,
188-
workers: self.workers,
189-
});
190-
191-
Simulation { tool }
181+
.add_plugin(UnifiedSimulationPlugin { explicit_num_qubits: None })
182+
.insert_resource(ProgramSourceResource(source))
183+
.insert_resource(self.config)
184+
.insert_resource(QuantumBackendResource(self.quantum_backend));
185+
186+
Simulation { tool, orchestrator: self.orchestrator, parallel_data }
192187
}
193188
}
194189
```
@@ -200,6 +195,8 @@ Reusable handle that wraps a configured Tool:
200195
```rust
201196
pub struct Simulation {
202197
tool: Tool,
198+
orchestrator: Orchestrator,
199+
parallel_data: Option<ParallelExecutionData>,
203200
}
204201

205202
impl Simulation {
@@ -251,21 +248,26 @@ let results3 = sim.shots(5000).seed(456).run();
251248

252249
## Plugins
253250

254-
### SimulationPlugin
251+
### UnifiedSimulationPlugin
255252

256-
Core simulation functionality:
253+
Core simulation functionality. Handles both static circuits and classical engines
254+
via a unified `QuantumRunner` + `CommandSource` abstraction. The same systems run
255+
in both single-worker and parallel execution (each parallel worker gets its own
256+
`Resources` and runs the shared schedule).
257257

258258
```rust
259-
pub struct SimulationPlugin;
259+
struct UnifiedSimulationPlugin {
260+
explicit_num_qubits: Option<usize>,
261+
}
260262

261-
impl Plugin for SimulationPlugin {
263+
impl Plugin for UnifiedSimulationPlugin {
262264
fn build(&self, tool: &mut Tool) {
263265
tool.insert_resource(SimulationResults::new())
264-
.add_system(Stage::Startup, initialize_simulator)
265-
.add_system(Stage::PreShot, reset_and_seed)
266-
.add_system(Stage::Execute, run_circuit)
267-
.add_system(Stage::PostShot, collect_outcomes)
268-
.add_system(Stage::Finish, aggregate_results);
266+
.insert_resource(ExplicitNumQubits(self.explicit_num_qubits))
267+
.add_system(Stage::Startup, unified_simulation_startup)
268+
.add_system(Stage::PreShot, unified_simulation_pre_shot)
269+
.add_system(Stage::Execute, unified_simulation_execute)
270+
.add_system(Stage::PostShot, unified_simulation_post_shot);
269271
}
270272
}
271273
```
@@ -289,25 +291,37 @@ impl Plugin for NoisePlugin {
289291
}
290292
```
291293

292-
### ImportanceSamplingPlugin
294+
### `ImportanceSamplingSimPlugin`
293295

294-
Importance sampling for rare events:
296+
When the importance sampling orchestrator is selected, this plugin replaces
297+
`UnifiedSimulationPlugin`. It uses `ImportanceSamplingRunner` internally for
298+
biased noise with weight tracking, running through the same Stage/Schedule
299+
system as Monte Carlo execution.
295300

296301
```rust
297-
pub struct ImportanceSamplingPlugin {
298-
config: ImportanceConfig,
302+
struct ImportanceSamplingSimPlugin {
303+
is_config: ImportanceSamplingBuilder,
304+
explicit_num_qubits: Option<usize>,
299305
}
300306

301-
impl Plugin for ImportanceSamplingPlugin {
307+
impl Plugin for ImportanceSamplingSimPlugin {
302308
fn build(&self, tool: &mut Tool) {
303-
tool.insert_resource(self.config.clone())
304-
.insert_resource(WeightedStatistics::new())
305-
.add_system(Stage::PostShot, update_weights)
306-
.add_system(Stage::Finish, compute_importance_statistics);
309+
// Registers IS-specific systems at Startup/PreShot/Execute/PostShot
310+
// Uses ImportanceSamplingRunner<SparseStab> for execution
307311
}
308312
}
309313
```
310314

315+
This means user-registered plugins and hooks fire correctly during IS execution,
316+
just as they do for Monte Carlo.
317+
318+
### `ImportanceSamplingPlugin`
319+
320+
A standalone plugin for manual weight tracking (pre-shot reset, post-shot
321+
recording, finish statistics). Available for users building custom Tool
322+
configurations. Not used by the IS orchestrator path, which handles its own
323+
weight storage via `SimulationResults.weights`.
324+
311325
## Results
312326

313327
### SimulationResults
@@ -393,15 +407,15 @@ let results = tool.resource::<MyResults>();
393407
- [ ] Basic `run()` execution loop
394408

395409
### Phase 2: Simulation Support
396-
- [ ] `SimulationPlugin` with core systems
410+
- [x] `UnifiedSimulationPlugin` with core systems
397411
- [ ] `NoisePlugin` integration
398-
- [ ] `SimNeoBuilder` and `sim_neo()`
399-
- [ ] `Simulation` handle with reconfiguration
400-
- [ ] `SimulationResults` type
412+
- [x] `SimNeoBuilder` and `sim_neo()`
413+
- [x] `Simulation` handle with reconfiguration
414+
- [x] `SimulationResults` type
401415

402416
### Phase 3: Advanced Features
403-
- [ ] `ImportanceSamplingPlugin`
404-
- [ ] Parallel execution (workers)
417+
- [x] `ImportanceSamplingPlugin`
418+
- [x] Parallel execution (MonteCarlo orchestrator with workers > 1)
405419
- [ ] `FTValidatorBuilder` and FT validation
406420

407421
### Phase 4: Integration

0 commit comments

Comments
 (0)