Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/rust-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ jobs:
echo "Testing $crate..."
cd "crates/$crate" && cargo clippy --locked --all-targets -- -D warnings && cd ../..
done
cargo clippy --locked -p pecos-neo --lib -- -D warnings
echo "Testing pecos without default features..."
cd crates/pecos && cargo clippy --locked --all-targets --no-default-features -- -D warnings && cd ../..

Expand Down
2 changes: 2 additions & 0 deletions docs/experimental/composable-noise.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Composable Noise Models (pecos-neo)

Enable the `composite-noise` Cargo feature on `pecos-neo` to use composite noise primitives and patterns.

> This covers the Rust composable noise API in `pecos-neo`. For the Python noise builder API, see [Noise Model Builders](../user-guide/noise-model-builders.md).
>
> Source: `exp/pecos-neo/src/noise/`
Expand Down
3 changes: 2 additions & 1 deletion exp/pecos-neo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,15 @@ pecos-qasm.workspace = true
criterion.workspace = true
proptest = "1.4"
# Enable our own features for doctests and integration tests
pecos-neo = { path = ".", features = ["qasm"] }
pecos-neo = { path = ".", features = ["qasm", "composite-noise"] }

[[bench]]
name = "hot_path"
harness = false

[features]
default = []
composite-noise = []
qasm = ["dep:pecos-qasm"]

[lints]
Expand Down
7 changes: 7 additions & 0 deletions exp/pecos-neo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,10 @@ for outcome in &results.outcomes {
## Documentation

See the [full documentation](docs/README.md) for examples, guides, and reference material.

## Cargo features

Both features are off by default.

- `qasm`: QASM program support.
- `composite-noise`: Composite noise decision-tree primitives, builders, and patterns.
82 changes: 0 additions & 82 deletions exp/pecos-neo/benches/hot_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1227,87 +1227,6 @@ fn bench_batch_processor(c: &mut Criterion) {
group.finish();
}

/// Compare trait object dispatch vs compiled enum dispatch for composite primitives
fn bench_dispatch_comparison(c: &mut Criterion) {
use pecos_neo::noise::NoiseContext;
use pecos_neo::noise::composite::prelude::*;
use pecos_neo::noise::composite::{CompiledAction, CompiledCondition, CompiledPrimitive};

let mut group = c.benchmark_group("dispatch_comparison");

// Create equivalent noise trees: trait-object and compiled versions

// Simple probability + pauli
let trait_simple: Box<dyn Primitive> = Box::new(prob(0.01, pauli()));
let compiled_simple = CompiledPrimitive::prob(
0.01,
CompiledPrimitive::action(CompiledAction::Pauli(PauliWeights::uniform())),
);

// More complex tree with conditions
let trait_complex = seq![skip_if_leaked(), prob(0.01, when_leaked(seep(), pauli())),];
let compiled_complex = CompiledPrimitive::seq(vec![
CompiledPrimitive::skip_if(CompiledCondition::Leaked),
CompiledPrimitive::prob(
0.01,
CompiledPrimitive::when(
CompiledCondition::Leaked,
CompiledPrimitive::action(CompiledAction::Seep(PauliWeights::uniform())),
CompiledPrimitive::action(CompiledAction::Pauli(PauliWeights::uniform())),
),
),
]);

// Benchmark simple tree
group.bench_function("trait_simple_pauli", |b| {
let mut ctx = NoiseContext::new();
let mut rng = PecosRng::seed_from_u64(42);
b.iter(|| black_box(trait_simple.apply(QubitId(0), &mut ctx, &mut rng)));
});

group.bench_function("compiled_simple_pauli", |b| {
let mut ctx = NoiseContext::new();
let mut rng = PecosRng::seed_from_u64(42);
b.iter(|| black_box(compiled_simple.apply(QubitId(0), &mut ctx, &mut rng)));
});

// Benchmark complex tree
group.bench_function("trait_complex_tree", |b| {
let mut ctx = NoiseContext::new();
let mut rng = PecosRng::seed_from_u64(42);
b.iter(|| black_box(trait_complex.apply(QubitId(0), &mut ctx, &mut rng)));
});

group.bench_function("compiled_complex_tree", |b| {
let mut ctx = NoiseContext::new();
let mut rng = PecosRng::seed_from_u64(42);
b.iter(|| black_box(compiled_complex.apply(QubitId(0), &mut ctx, &mut rng)));
});

// Benchmark many iterations to amortize setup
group.bench_function("trait_1000_iterations", |b| {
let mut ctx = NoiseContext::new();
let mut rng = PecosRng::seed_from_u64(42);
b.iter(|| {
for _ in 0..1000 {
black_box(trait_complex.apply(QubitId(0), &mut ctx, &mut rng));
}
});
});

group.bench_function("compiled_1000_iterations", |b| {
let mut ctx = NoiseContext::new();
let mut rng = PecosRng::seed_from_u64(42);
b.iter(|| {
for _ in 0..1000 {
black_box(compiled_complex.apply(QubitId(0), &mut ctx, &mut rng));
}
});
});

group.finish();
}

criterion_group!(
benches,
bench_noise_emission,
Expand All @@ -1322,7 +1241,6 @@ criterion_group!(
bench_composite_vs_channel_noise,
bench_batch_filtering,
bench_batch_processor,
bench_dispatch_comparison,
);

criterion_main!(benches);
13 changes: 2 additions & 11 deletions exp/pecos-neo/docs/design/noise-composite.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
| CompositeChannel integration | Complete | `composite/channel.rs` |
| CompositeNoiseModelBuilder | Complete | `composite/builder.rs` |
| Geometric sampling optimization | Complete | `composite/batch.rs` |
| Compiled primitives | Complete | `composite/compiled.rs` |
| Crosstalk channel | Complete | `composite/channel.rs` |
| Two-stage primitives | Complete | `composite/primitive.rs` |

Expand Down Expand Up @@ -399,13 +398,6 @@ for i in fault_mask.iter_ones() {
}
```

### Compilation

Primitive trees can compile to optimized code:
- Eliminate virtual dispatch
- Inline small actions
- Optimal branch ordering

## Visualization

Multiple views for different needs:
Expand Down Expand Up @@ -470,7 +462,7 @@ This design relates to existing pecos-neo infrastructure:
| `GeneralNoiseModelBuilder` | A preset that builds primitive trees |

Options:
1. **Internal implementation**: Primitives compile to existing channel interface
1. **Internal implementation**: Primitives integrate through the existing channel interface
2. **Alternative API**: New way to build models, coexists with channels
3. **Replacement**: Migrate to primitives, deprecate channels

Expand All @@ -489,7 +481,7 @@ Recommendation: Start with option 1 (internal), validate the design works.
|------|----------|
| **Constrained** | Small fixed primitive set |
| **Grounded** | Primitives map to physical processes |
| **Fast** | Early exit, RNG batching, compilation |
| **Fast** | Early exit, RNG batching |
| **Flexible** | Primitives compose freely |
| **Understandable** | Trees visualize as flowcharts |
| **Tricky cases** | Outcome primitives + Crosstalk special construct |
Expand Down Expand Up @@ -562,7 +554,6 @@ crates/pecos-neo/src/noise/

**Deliverables:**
- Geometric sampling for batch processing: Complete (`composite/batch.rs`)
- Tree compilation: Complete (`composite/compiled.rs`)
- RNG batching: Complete (`GeometricSampler`)
- Benchmarks: Available in `benches/hot_path.rs`

Expand Down
13 changes: 2 additions & 11 deletions exp/pecos-neo/docs/dev/noise.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Noise System Usage Guide

Composite decision-tree APIs require the `composite-noise` Cargo feature on `pecos-neo`.

This guide covers practical usage of the pecos-neo noise modeling system.

## Overview
Expand Down Expand Up @@ -310,17 +312,6 @@ let channel = CompositeChannel::new("fast_depol", prob(0.001, depolarize()))
.with_filter(CompositeEventFilter::SingleQubitGate);
```

### Compiled Primitives

Complex primitive trees can be compiled for better performance:

```rust
use pecos_neo::noise::composite::compiled::CompiledPrimitive;

let primitive = seq(vec![...]);
let compiled = CompiledPrimitive::compile(&primitive);
```

## Debugging Noise Models

### Introspection
Expand Down
2 changes: 2 additions & 0 deletions exp/pecos-neo/docs/user-guides/noise.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Adding Noise

Enable the `composite-noise` Cargo feature on `pecos-neo` to use composite noise primitives and patterns.

## Quickest Option

One-liner on `sim_neo`:
Expand Down
10 changes: 3 additions & 7 deletions exp/pecos-neo/src/noise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
//! - **Composed**: Build decision trees using primitives (prob, when, seq, etc.)
//! - **Custom**: Implement your own channels for complete control
//!
//! Decision-tree primitives are available with the `composite-noise` Cargo feature.
//!
//! # Quick Start
//!
//! Import everything with the prelude:
Expand All @@ -32,13 +34,6 @@
//! .with_measurement_error(0.02)
//! .build();
//!
//! // Composed: build custom decision trees
//! let composed = NoiseModelBuilder::new()
//! .with_single_qubit_noise(seq![
//! skip_if_leaked(),
//! prob(0.001, when_leaked(seep(), pauli())),
//! ])
//! .build();
//! ```
//!
//! Mixed approach (combine builder with custom channels):
Expand Down Expand Up @@ -99,6 +94,7 @@
pub mod builder;
pub mod category_channel;
pub mod composer;
#[cfg(feature = "composite-noise")]
pub mod composite;
pub mod context;
pub mod correlated;
Expand Down
47 changes: 22 additions & 25 deletions exp/pecos-neo/src/noise/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
//! This module provides [`NoiseModelBuilder`], the primary way to construct noise models.
//! It unifies simple parameter-based configuration with composable channel construction.
//!
//! Decision-tree construction requires the `composite-noise` Cargo feature.
//!
//! # Philosophy
//!
//! The noise system is built on a few key concepts:
Expand All @@ -34,26 +36,16 @@
//! .with_measurement_error(0.02)
//! .build();
//!
//! // Composed: build custom decision trees
//! let composed = NoiseModelBuilder::new()
//! .with_single_qubit_noise(seq![
//! skip_if_leaked(),
//! prob(0.001, when_leaked(seep(), pauli())),
//! ])
//! .with_two_qubit_noise(seq![
//! skip_if_leaked(),
//! prob(0.01, two_qubit_pauli()),
//! ])
//! .build();
//!
//! // Mixed: combine both approaches
//! let mixed = NoiseModelBuilder::new()
//! .with_depolarizing(0.001, 0.01) // Simple base rates
//! .with_channel(LeakageChannel::new()) // Add custom channel
//! .build();
//! ```

#[cfg(feature = "composite-noise")]
use super::composite::Primitive;
#[cfg(feature = "composite-noise")]
use super::composite::channel::{CompositeChannel, CompositeChannelBuilder};
use super::crosstalk::CrosstalkChannel;
use super::idle::IdleChannel;
Expand Down Expand Up @@ -90,19 +82,6 @@ use pecos_core::TimeScale;
/// .build();
/// ```
///
/// ## Custom composed noise
///
/// ```
/// use pecos_neo::noise::prelude::*;
///
/// let model = NoiseModelBuilder::new()
/// .with_single_qubit_noise(seq![
/// skip_if_leaked(),
/// prob(0.001, pauli()),
/// ])
/// .build();
/// ```
///
/// ## Adding existing channels
///
/// ```
Expand Down Expand Up @@ -413,7 +392,21 @@ impl NoiseModelBuilder {
/// ])
/// .build();
/// ```
///
/// ## Custom composed noise
///
/// ```
/// use pecos_neo::noise::prelude::*;
///
/// let model = NoiseModelBuilder::new()
/// .with_single_qubit_noise(seq![
/// skip_if_leaked(),
/// prob(0.001, pauli()),
/// ])
/// .build();
/// ```
#[must_use]
#[cfg(feature = "composite-noise")]
pub fn with_single_qubit_noise<P: Primitive + Clone + 'static>(mut self, primitive: P) -> Self {
let channel = CompositeChannelBuilder::single_qubit("single_qubit", primitive);
self.custom_channels.push(Box::new(channel));
Expand All @@ -425,6 +418,7 @@ impl NoiseModelBuilder {
///
/// This overrides the simple p2-based configuration.
#[must_use]
#[cfg(feature = "composite-noise")]
pub fn with_two_qubit_noise<P: Primitive + Clone + 'static>(mut self, primitive: P) -> Self {
let channel = CompositeChannelBuilder::two_qubit("two_qubit", primitive);
self.custom_channels.push(Box::new(channel));
Expand All @@ -436,6 +430,7 @@ impl NoiseModelBuilder {
///
/// This overrides the simple p_meas-based configuration.
#[must_use]
#[cfg(feature = "composite-noise")]
pub fn with_measurement_noise<P: Primitive + Clone + 'static>(mut self, primitive: P) -> Self {
let channel = CompositeChannelBuilder::after_measurement("measurement", primitive);
self.custom_channels.push(Box::new(channel));
Expand All @@ -447,6 +442,7 @@ impl NoiseModelBuilder {
///
/// This overrides the simple p_prep-based configuration.
#[must_use]
#[cfg(feature = "composite-noise")]
pub fn with_preparation_noise<P: Primitive + Clone + 'static>(mut self, primitive: P) -> Self {
let channel = CompositeChannelBuilder::preparation("preparation", primitive);
self.custom_channels.push(Box::new(channel));
Expand All @@ -471,6 +467,7 @@ impl NoiseModelBuilder {
/// .build();
/// ```
#[must_use]
#[cfg(feature = "composite-noise")]
pub fn with_custom_channel<P: Primitive + Clone + 'static>(
mut self,
channel: CompositeChannel<P>,
Expand Down
2 changes: 0 additions & 2 deletions exp/pecos-neo/src/noise/composite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ pub mod batch;
pub mod batch_composite;
mod builder;
pub mod channel;
mod compiled;
mod condition;
mod primitive;
mod response;
Expand All @@ -176,7 +175,6 @@ pub use channel::{
BatchCompositeChannel, CompositeChannel, CompositeChannelBuilder, CompositeCrosstalkChannel,
CompositeEventFilter,
};
pub use compiled::{CompiledAction, CompiledCondition, CompiledPrimitive};
pub use condition::{
Active, Always, AnyQubitLeaked, Condition, FnCondition, GateTypeIs, Leaked, Never, NotLeaked,
OutcomeIs, PartnerLeaked,
Expand Down
Loading
Loading