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
10 changes: 10 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ ci-rust: setup-python
set -euo pipefail
cargo fmt --all -- --check
cargo clippy --workspace {{WORKSPACE_EXCLUDE}} --all-targets -- -D warnings
# Workspace Rustdoc must be warning-free (#406): unresolved intra-doc links,
# private-item references, output collisions, and accidental citation links
# are all denied. --no-deps scopes the check to workspace crates only.
RUSTDOCFLAGS="-D warnings" cargo doc --workspace {{WORKSPACE_EXCLUDE}} --no-deps
cargo build --release --workspace {{WORKSPACE_EXCLUDE}}
cargo build --examples --workspace {{WORKSPACE_EXCLUDE}}
# MLIR-free module-seam feature combinations (issue #407). Runs after
Expand Down Expand Up @@ -271,6 +275,12 @@ tooling-full: _tooling-build
ci-docs-assert:
./scripts/assert-validation-docs.sh

# Workspace Rustdoc with warnings denied (#406): unresolved intra-doc links,
# private-item references, output collisions, and accidental citation links.
# Also run as part of `ci-rust`; this recipe runs it in isolation.
ci-rustdoc:
RUSTDOCFLAGS="-D warnings" cargo doc --workspace {{WORKSPACE_EXCLUDE}} --no-deps

# Local convenience: re-run just the sample corpus catalog lint (schema,
# path existence, category coverage, required README sections, and a real
# `quonc` typecheck for every `ci: smoke` entry in samples/catalog.yaml;
Expand Down
6 changes: 3 additions & 3 deletions backend/src/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ pub struct NeutralAtomTargetDescriptor {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error_model: Option<NeutralAtomErrorModelDescriptor>,
/// Optional movement-induced heating / atom-loss parameters (issue #310,
/// [Atomique] Eqs. (1)–(2)). Sibling to `error_model`; omitted targets
/// \[Atomique\] Eqs. (1)–(2)). Sibling to `error_model`; omitted targets
/// still load and the report simply skips the `atom_loss_budget` section.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub atom_loss_model: Option<NeutralAtomLossModelDescriptor>,
Expand Down Expand Up @@ -245,10 +245,10 @@ pub struct NeutralAtomErrorModelDescriptor {
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct NeutralAtomLossModelDescriptor {
/// Heating per µm of atom travel ([Atomique] Eq. (1)).
/// Heating per µm of atom travel (\[Atomique\] Eq. (1)).
pub heating_rate_per_um: f64,
/// Dimensionless loss coefficient → `1 − exp(−loss_coeff × H)`
/// ([Atomique] Eq. (2)).
/// (\[Atomique\] Eq. (2)).
pub loss_coeff: f64,
}

Expand Down
28 changes: 14 additions & 14 deletions backend/src/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ impl FixedTarget {
///
/// Use this for descriptor loading where `num_qubits` arrives from JSON
/// independent of the topology built from the same document. Returns
/// [`BackendError::InvalidTargetConfig`] on mismatch.
/// [`crate::error::BackendError::InvalidTargetConfig`] on mismatch.
pub fn try_new(
num_qubits: usize,
topology: ConnectivityGraph,
Expand Down Expand Up @@ -368,7 +368,7 @@ pub struct NeutralAtomTarget {
/// derived from [`Self::fidelity`] (ADR-0017).
pub error_model: Option<NeutralAtomErrorModel>,
/// Optional movement-induced heating / atom-loss parameters (issue #310,
/// [Atomique] Wang et al. ISCA 2024, arXiv:2311.15123, Eqs. (1)–(2)).
/// \[Atomique\] Wang et al. ISCA 2024, arXiv:2311.15123, Eqs. (1)–(2)).
///
/// Sibling to `error_model`; not derived from fidelity. When present, the
/// NA resource report attaches an analytic `atom_loss_budget` section
Expand All @@ -378,13 +378,13 @@ pub struct NeutralAtomTarget {
///
/// **Provenance / placeholder status (architecture_model.md §2 / §8.6):**
/// the heating→loss coefficients are *placeholder analytic knobs*, not
/// measured device calibrations. [Atomique] Sec. IV gives the model shape;
/// measured device calibrations. \[Atomique\] Sec. IV gives the model shape;
/// its numeric fidelity table is deliberately ×10-optimistic relative to
/// the 2022 experiments it scales from (see
/// `docs/neutral_atom/literature_notes.md` [Atomique]) — do not quote its
/// `docs/neutral_atom/literature_notes.md` \[Atomique\]) — do not quote its
/// numbers as measured values. The model accumulates heating against the
/// *actual per-atom travel distance* through Quon's √-law movement
/// schedule and does **not** import [Atomique]'s fixed 300 µs-per-stage
/// schedule and does **not** import \[Atomique\]'s fixed 300 µs-per-stage
/// movement timing (the documented §5 divergence).
pub atom_loss_model: Option<NeutralAtomLossModel>,
pub cost_model: NeutralAtomCostModel,
Expand All @@ -395,7 +395,7 @@ impl NeutralAtomTarget {
self.native_gates.iter().any(|g| g == gate)
}

/// Return the physical error model, or [`BackendError::MissingErrorModel`].
/// Return the physical error model, or [`crate::error::BackendError::MissingErrorModel`].
///
/// Call this when QEC error-budget reporting or `--emit-qec-experiment` is
/// requested. Do not convert from `fidelity`.
Expand Down Expand Up @@ -496,7 +496,7 @@ pub struct AodSpeedModel {
/// Jerk limit `J` (m/s³) for the [`AodSpeedModelKind::JerkLimited`] timing
/// model. Unused (and serializes as `0.0`) under `Sqrt`. Provenance:
/// placeholder pending access to the QMAP eval scripts' calibration (see
/// `docs/neutral_atom/literature_notes.md`'s [RAP] caveats — the QMAP repo's
/// `docs/neutral_atom/literature_notes.md`'s \[RAP\] caveats — the QMAP repo's
/// newer eval scripts use a jerk-limited model that differs from the
/// paper's √-law except at d = 110 µm); the value is target-specific, not a
/// universal constant (architecture_model.md §8.6).
Expand All @@ -509,7 +509,7 @@ pub struct AodSpeedModel {

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AodSpeedModelKind {
/// √-law `t = √(d/a)` (the reproduced [RAP] Table I timing model; default).
/// √-law `t = √(d/a)` (the reproduced \[RAP\] Table I timing model; default).
Sqrt,
/// Jerk-limited symmetric S-curve: acceleration ramps at jerk `J` up to
/// `acceleration_m_s2`, optionally cruises at `max_velocity_m_s`, then
Expand Down Expand Up @@ -613,7 +613,7 @@ impl TryFrom<NeutralAtomErrorModelSnapshot> for NeutralAtomErrorModel {
}
}
/// Optional movement-induced heating / atom-loss parameters (issue #310;
/// [Atomique] Wang et al. ISCA 2024, arXiv:2311.15123, Eqs. (1)–(2)).
/// \[Atomique\] Wang et al. ISCA 2024, arXiv:2311.15123, Eqs. (1)–(2)).
///
/// Sibling to [`NeutralAtomErrorModel`] and [`NeutralAtomFidelity`]; not
/// derived from either. Wire JSON lives in
Expand All @@ -623,9 +623,9 @@ impl TryFrom<NeutralAtomErrorModelSnapshot> for NeutralAtomErrorModel {
/// # Model
///
/// Per-atom heating accumulates with travel:
/// `H_a = heating_rate_per_um × cumulative_distance_um_a` ([Atomique] Eq. (1),
/// `H_a = heating_rate_per_um × cumulative_distance_um_a` (\[Atomique\] Eq. (1),
/// distance-only term). Per-atom loss probability follows:
/// `p_a = 1 − exp(−loss_coeff × H_a)` ([Atomique] Eq. (2)). The report's
/// `p_a = 1 − exp(−loss_coeff × H_a)` (\[Atomique\] Eq. (2)). The report's
/// `expected_atoms_lost = Σ_a p_a`.
///
/// `heating_rate_per_um = 0` zeros every `H_a` (heating still reported as 0);
Expand All @@ -638,14 +638,14 @@ impl TryFrom<NeutralAtomErrorModelSnapshot> for NeutralAtomErrorModel {
/// Placeholder analytic knobs (architecture_model.md §2 / §8.6), not measured
/// calibrations. The model accumulates heating against actual per-atom travel
/// distance through Quon's √-law movement schedule — it does **not** import
/// [Atomique]'s fixed 300 µs-per-stage movement timing (§5 divergence).
/// \[Atomique\]'s fixed 300 µs-per-stage movement timing (§5 divergence).
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct NeutralAtomLossModel {
/// Heating gained per µm of atom travel
/// (`H = heating_rate_per_um × cumulative_distance_um`; [Atomique] Eq. (1)).
/// (`H = heating_rate_per_um × cumulative_distance_um`; \[Atomique\] Eq. (1)).
pub heating_rate_per_um: f64,
/// Dimensionless loss coefficient mapping accumulated heating `H` to a
/// per-atom loss probability `1 − exp(−loss_coeff × H)` ([Atomique]
/// per-atom loss probability `1 − exp(−loss_coeff × H)` (\[Atomique\]
/// Eq. (2)). Non-negative; `0` reports heating with zero loss probability.
pub loss_coeff: f64,
}
Expand Down
3 changes: 2 additions & 1 deletion docs/agents/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Static analysis and refinement-type checks for the Quon workspace.
| `just rap-table-i` | #111 local-only convenience: `cargo test --release -p quonc --test rap_table_i -- --include-ignored --nocapture` (the metrics-dump test; the fast structural preflight already runs in `just ci-rust`). **Not invoked by any CI job** — see the `rust` row below. |
| `just na-rap-sweep` | #306 local-only: both `--na-placer` modes over every checked-in RAP Table I row (`ising_n42`, `ising_n98`), one qmap-comparable CSV (`python/na_rap_table_i_sweep.py`). Not CI — see `docs/neutral_atom/rap_table_i_methodology.md`'s "Full sweep harness (#306)". |
| `just ci-docs-assert` | `./scripts/assert-validation-docs.sh` |
| `just ci-rustdoc` | Workspace Rustdoc with warnings denied (`RUSTDOCFLAGS="-D warnings" cargo doc --workspace --exclude flux_verify --no-deps`); unresolved intra-doc links, private-item references, output collisions, and accidental citation links all fail (#406). Also run as a step in `just ci-rust`. |
| `just ci-website` | Starlight `pnpm build` under `website/` |

Inside Devbox: `devbox run -- just <recipe>` (or `just` after `devbox shell`).
Expand All @@ -33,7 +34,7 @@ This table is an adapter of the **Justfile** recipes invoked by `.github/workflo

| Workflow | Trigger | What runs |
| -------- | ------- | --------- |
| [ci.yml](../../.github/workflows/ci.yml) `rust` | every push and PR | `just ci-rust`: fmt, clippy, release build (+ examples for lit oracles), `cargo test --workspace --exclude flux_verify` with `QUON_REQUIRE_LIT` so [`quonc/tests/lit.rs`](../../quonc/tests/lit.rs) hard-fails without lit/FileCheck/oracles, and [`quonc/tests/samples_catalog.rs`](../../quonc/tests/samples_catalog.rs) lints `samples/catalog.yaml` and typechecks every `ci: smoke` entry with the debug `quonc` this same `cargo test` builds (ADR-0025 / #185) — the RAP Table I preflight test (#111) runs here too, while the full `rap_table_i --include-ignored` metrics dump is **local-only** (`just rap-table-i`, not invoked by this or any other CI job): pre-#297 its routing-aware A* peaked ~17.5 GB RSS and OOM'd GitHub's 16 GB hosted runners; #297's heuristic search dropped that to ~64 MB, but the recipe has not been re-wired into CI since (documented follow-up, not done here or in #306) — see `docs/neutral_atom/rap_table_i_methodology.md`'s "Runtime / CI wiring" correction; then Qiskit Aer: `test/verify/{bell,teleport,bernstein_vazirani,routing,grover,qft,ising,qaoa,shor}.py` with `QUONC=target/release/quonc`, then QEC Python smokes (`test_qec_stim_smoke`, `test_quon_qec_sinter`, `test_quon_qec_benchmarks` / #254). |
| [ci.yml](../../.github/workflows/ci.yml) `rust` | every push and PR | `just ci-rust`: fmt, clippy, workspace Rustdoc with warnings denied (`ci-rustdoc`, #406), release build (+ examples for lit oracles), `cargo test --workspace --exclude flux_verify` with `QUON_REQUIRE_LIT` so [`quonc/tests/lit.rs`](../../quonc/tests/lit.rs) hard-fails without lit/FileCheck/oracles, and [`quonc/tests/samples_catalog.rs`](../../quonc/tests/samples_catalog.rs) lints `samples/catalog.yaml` and typechecks every `ci: smoke` entry with the debug `quonc` this same `cargo test` builds (ADR-0025 / #185) — the RAP Table I preflight test (#111) runs here too, while the full `rap_table_i --include-ignored` metrics dump is **local-only** (`just rap-table-i`, not invoked by this or any other CI job): pre-#297 its routing-aware A* peaked ~17.5 GB RSS and OOM'd GitHub's 16 GB hosted runners; #297's heuristic search dropped that to ~64 MB, but the recipe has not been re-wired into CI since (documented follow-up, not done here or in #306) — see `docs/neutral_atom/rap_table_i_methodology.md`'s "Runtime / CI wiring" correction; then Qiskit Aer: `test/verify/{bell,teleport,bernstein_vazirani,routing,grover,qft,ising,qaoa,shor}.py` with `QUONC=target/release/quonc`, then QEC Python smokes (`test_qec_stim_smoke`, `test_quon_qec_sinter`, `test_quon_qec_benchmarks` / #254). |
| [ci.yml](../../.github/workflows/ci.yml) `docs` | every push and PR | `just ci-docs-assert` + `just ci-website` |
| [ci.yml](../../.github/workflows/ci.yml) `tooling` | every push and PR | `just ci-tooling`: `quonfmt --check`, `quonlint`, `quon_lsp` smoke on CI corpus |
| [release.yml](../../.github/workflows/release.yml) | tags `v*` (+ manual dry-run) | `devbox run release` — static MLIR/LLVM + release-built static libz3; link audit; upload `quon-{version}-{arch}-{os}.tar.gz` to GitHub Releases |
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ impl CliffordClass {

// ── Nat expressions ───────────────────────────────────────────────────────────

/// Type-level natural number expression (appears in QReg<n>, Circuit<n,...>).
/// Type-level natural number expression (appears in `QReg<n>`, `Circuit<n,…>`).
#[derive(Debug, Clone, PartialEq)]
pub enum NatExpr {
Lit(u64),
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/refinement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl RefinementCtx {
}

/// Verify that `inferred` equals `annotated` for all assignments — the no-assumption
/// equality used by branch-join reconciliation. A thin wrapper over [`prove_eq`].
/// equality used by branch-join reconciliation. A thin wrapper over [`Self::prove_eq`].
pub fn verify_equal(
&self,
inferred: &DepthExpr,
Expand Down Expand Up @@ -109,7 +109,7 @@ impl RefinementCtx {

/// Prove `lhs ≤ rhs` under `assumptions` — the depth-as-upper-bound check (SPEC §3.3): a
/// synthesized depth `lhs` satisfies an annotation `rhs` when it is no larger. `Hole` on the
/// annotation side accepts anything; equal/constant fast paths mirror [`prove_eq`].
/// annotation side accepts anything; equal/constant fast paths mirror [`Self::prove_eq`].
pub fn prove_le(
&self,
assumptions: &[Assumption],
Expand Down
9 changes: 4 additions & 5 deletions frontend/src/specialized_circuit.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! `SpecializedCircuit` — the Melior-free first-order gate DAG between
//! `elaborate` and `lower` (issue #206).
//!
//! Parametric specialization ([`elaborate`](crate::elaborate)) already produces
//! Parametric specialization ([`crate::elaborate`]) already produces
//! a first-order gate tree — `Compose` / `GateApp` / `Adjoint` over concrete
//! qubit indices and literal rotation angles — but the interface stayed surface
//! `Expr`, and the inverse / placement / `flatten_app` helpers were duplicated
Expand All @@ -11,9 +11,8 @@
//! - **Interface** ([`SpecializedCircuit`]): the elaborator's output and lower's
//! only input — a gate DAG with resolved in/out widths, depth, and Clifford
//! class. No classical parameters remain.
//! - **Implementation** ([`SpecializedCircuit::specialize`],
//! [`SpecializedCircuit::adjoint`], [`collect_gate_placements`],
//! [`reverse_and_invert`]): specialization, adjoint/inverse normalization, and
//! [`SpecializedCircuit::adjoint`], `collect_gate_placements`,
//! `reverse_and_invert`): specialization, adjoint/inverse normalization, and
//! placement — all Melior-free, all living once here.
//! - **Adapter** (in `lower.rs`): Melior builders that consume a
//! `SpecializedCircuit` and emit `quantum.circ`. Nothing in this module
Expand Down Expand Up @@ -206,7 +205,7 @@ impl SpecializedCircuit {
/// The adjoint circuit: reverse gate order and invert each gate, swapping
/// the in/out widths (`Circuit<n,m>† : Circuit<m,n>`). Depth and Clifford
/// class are preserved. This is the typed adjoint normalization; the
/// AST-level kernel is [`reverse_and_invert`].
/// AST-level kernel is `reverse_and_invert`.
pub fn adjoint(&self) -> Result<Self, ElabError> {
let body = reverse_and_invert(&self.body)?;
Ok(Self {
Expand Down
18 changes: 9 additions & 9 deletions frontend/src/typecheck/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Bidirectional type checker facade — dispatches into one judgment module per form
//! (issue #9, SPEC §3.8; epic #207). The **classical Γ** judgment (synth/check, unify
//! coordination, exhaustiveness, patterns) lives in [`classical`]; the **Circuit**
//! judgment lives in [`circuit`] (#323, ADR-0028); first-order unification in [`unify`]
//! (`Table`); exhaustiveness/reachability in [`exhaust`]; the linear context `Δ` in
//! [`linear`]. The quantum monad (`Q<τ>`, `<-` binds, `run { }`), the borrow block, and
//! coordination, exhaustiveness, patterns) lives in `classical`; the **Circuit**
//! judgment lives in `circuit` (#323, ADR-0028); first-order unification in `unify`
//! (`Table`); exhaustiveness/reachability in `exhaust`; the linear context `Δ` in
//! `linear`. The quantum monad (`Q<τ>`, `<-` binds, `run { }`), the borrow block, and
//! the Z3 refinement bridge stay here as slices #325 and #326.
//!
//! Judgment form:
Expand All @@ -22,11 +22,11 @@
//!
//! * **Bidirectional, not full inference.** User functions are fully annotated, so the
//! only polymorphism is the classical prelude (`map`, `fold`, `zip`, …). Those are
//! [`Scheme`]s instantiated with fresh metavariables at each use; everything else flows
//! `Scheme`s instantiated with fresh metavariables at each use; everything else flows
//! through synthesis and checking. There is no let-generalization.
//! * **One unifier.** Application, branch joining, and subsumption all bottom out in
//! [`Table::unify`]. Metavariables are zonked away before a type is returned to a caller.
//! * **Exhaustiveness** is delegated to the [`exhaust`] usefulness algorithm.
//! `Table::unify`. Metavariables are zonked away before a type is returned to a caller.
//! * **Exhaustiveness** is delegated to the `exhaust` usefulness algorithm.

pub(crate) mod builtins;
pub(crate) mod circuit;
Expand Down Expand Up @@ -182,7 +182,7 @@ impl TypeChecker {

/// Initialize the LSP annotation/resolution sinks (issue #45). When enabled, the
/// checker owns the sinks for the duration of `check_decls` and records into them
/// during synthesis; call [`take_sinks`] to extract the accumulated results.
/// during synthesis; call [`Self::take_sinks`] to extract the accumulated results.
pub fn enable_sinks(&mut self) {
self.annotations = Some(TypeAnnotations::default());
self.resolutions = Some(ResolutionMap::default());
Expand Down Expand Up @@ -350,7 +350,7 @@ impl TypeChecker {
}
}

/// Resolved top-level function type after [`check_decls`] (issue #16 lowering).
/// Resolved top-level function type after [`Self::check_decls`] (issue #16 lowering).
pub fn fn_type_of(&self, name: &str) -> Option<&Ty> {
self.globals.get(name)
}
Expand Down
Loading
Loading