Skip to main content

bloq_graph/
summary.rs

1//! Reusable module certificates, summaries, and composed correlation supports.
2
3use std::collections::{HashMap, HashSet};
4use std::num::NonZeroUsize;
5use std::sync::Arc;
6
7use glam::IVec3;
8use rustc_hash::{FxHashMap, FxHashSet};
9
10use crate::program::{projection_limit, qualified_name, resource_limit};
11use crate::zx::{
12    EliminationRow, FlowWitness, ModuleSeam, ProjectionLimits, ZXGraph,
13    leading_pivot_elimination_from, signed_gaussian_elimination, signed_gaussian_elimination_from,
14    xor_pauli_maps,
15};
16use crate::{
17    Action, Basis, Block, BlockGraph, BlockKind, Direction, InstancePort, MeasurementObservable,
18    ModuleCertificationError, ModuleCertificationLimits, ModuleError, ModuleInstance,
19    ModuleOrientation, Pauli, PauliBasis, PauliString, PhasedPauliString, Pipe, QuantumConnection,
20    QuantumPort, Stabilizer, StabilizerGenerators, StabilizerRowKind, UDirection,
21    checked_add_position,
22};
23
24/// Geometry and basis data recorded when a module Port is removed.
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub(crate) struct ModulePortSignature {
27    /// Direction from the removed port toward its interior neighbor.
28    pub direction: Direction,
29    /// Whether the removed port seam carries a Hadamard basis change.
30    pub hadamard: bool,
31    /// Interior block's boundary basis on each lattice axis.
32    pub interior_bases: [Option<Basis>; 3],
33}
34
35impl ModulePortSignature {
36    /// Returns this port geometry in `orientation`.
37    pub(crate) fn with_orientation(self, orientation: ModuleOrientation) -> Self {
38        Self {
39            direction: orientation.rotate_direction(self.direction),
40            hadamard: self.hadamard,
41            interior_bases: orientation.rotate_axis_values(self.interior_bases),
42        }
43    }
44}
45
46/// Canonical signed Pauli relation over one module's declared Ports.
47#[derive(Debug, Clone)]
48pub struct ModuleSummary {
49    name: String,
50    limits: ModuleCertificationLimits,
51    dependencies: HashMap<String, Arc<ModuleSummary>>,
52    ports: Vec<QuantumPort>,
53    signatures: Vec<ModulePortSignature>,
54    rows: Vec<SupportedRow>,
55    /// Branch-safe logical rows exported by this module. Unlike `rows`, these
56    /// are public readout representatives rather than the complete boundary
57    /// relation used to compose seams.
58    logical_rows: Vec<SupportedRow>,
59    /// Complete signed certificate basis over this definition's public Ports
60    /// and positioned interior support. Public rows are kept separately in
61    /// `rows`; this basis supplies only the private rank completion at link.
62    certificate_rows: Vec<SupportedRow>,
63    adjustments: Vec<SupportedRow>,
64    measurements: Vec<SummaryMeasurement>,
65    discharged_measurements: Vec<SummaryMeasurement>,
66    protected: Vec<ProtectedSupport>,
67    frontier: Vec<SupportTarget>,
68    protected_groups: Vec<ProtectedGroup>,
69    branch_variants: Vec<ModuleBranchVariant>,
70    projection: Option<Box<ModuleProjection>>,
71}
72
73/// A certificate recipe, evaluated only for a projection explicitly requested
74/// by a caller. The compiler composes guarded surfaces directly instead.
75#[derive(Debug, Clone)]
76struct ModuleProjection {
77    definition: BlockGraph,
78    targets: Vec<IVec3>,
79    limits: ModuleCertificationLimits,
80}
81
82#[derive(Debug, Clone)]
83struct ModuleBranchVariant {
84    assignments: Vec<(IVec3, bool)>,
85    summary: Box<ModuleSummary>,
86}
87
88impl ModuleSummary {
89    /// Returns the summarized module definition name.
90    pub fn name(&self) -> &str {
91        &self.name
92    }
93
94    /// Finds a definition summary already built as part of this root summary.
95    #[doc(hidden)]
96    pub fn definition(&self, name: &str) -> Option<&ModuleSummary> {
97        let mut pending = vec![self];
98        let mut seen = FxHashSet::default();
99        while let Some(summary) = pending.pop() {
100            if summary.name == name {
101                return Some(summary);
102            }
103            if seen.insert(summary.name.as_str()) {
104                pending.extend(summary.dependencies.values().map(Arc::as_ref));
105            }
106        }
107        None
108    }
109
110    /// Returns public quantum ports in interface declaration order.
111    pub fn quantum_ports(&self) -> &[QuantumPort] {
112        &self.ports
113    }
114
115    /// Iterates over signed public boundary relations.
116    pub fn boundary_rows(&self) -> impl ExactSizeIterator<Item = &PhasedPauliString> {
117        self.rows.iter().map(|row| &row.signed)
118    }
119
120    /// Materialize and present the complete composed certificate without
121    /// regenerating the linked graph's external stabilizer table. Rejects
122    /// named measurements without output-safe branch representatives (C0).
123    #[doc(hidden)]
124    pub fn materialize_stabilizers(
125        &self,
126        zx: &ZXGraph,
127        offset: IVec3,
128    ) -> Result<StabilizerGenerators, ModuleCertificationError> {
129        self.materialize_stabilizers_from(zx, ModuleOrientation::IDENTITY, offset)
130    }
131
132    /// Materialize one requested structural projection. Projection topology is
133    /// still selected by the caller, but its stabilizer row space comes from
134    /// bottom-up module composition rather than the flattened graph.
135    #[doc(hidden)]
136    pub fn materialize_projection_stabilizers(
137        &self,
138        zx: &ZXGraph,
139        offset: IVec3,
140        assignments: &[(IVec3, bool)],
141    ) -> Result<StabilizerGenerators, ModuleCertificationError> {
142        let mut key = assignments
143            .iter()
144            .filter(|(_, value)| !value)
145            .map(|&(position, value)| {
146                checked_add_position(position, -offset)
147                    .map(|position| (position, value))
148                    .map_err(|source| ModuleCertificationError::Graph {
149                        module: self.name.clone(),
150                        source,
151                    })
152            })
153            .collect::<Result<Vec<_>, _>>()?;
154        key.sort_unstable_by_key(|(position, value)| (position.to_array(), *value));
155        if key.is_empty() {
156            return self.materialize_stabilizers_from(zx, ModuleOrientation::IDENTITY, offset);
157        }
158        if self.projection.is_some() {
159            let absent = key.iter().map(|&(position, _)| position).collect();
160            return self
161                .select_projection(&absent)?
162                .materialize_stabilizers_from(zx, ModuleOrientation::IDENTITY, offset);
163        }
164        let variant = self
165            .branch_variants
166            .iter()
167            .find(|variant| variant.assignments == key)
168            .ok_or_else(|| {
169                invalid(
170                    &self.name,
171                    "reachable structural projection has no composed module certificate",
172                )
173            })?;
174        variant
175            .summary
176            .materialize_stabilizers_from(zx, ModuleOrientation::IDENTITY, offset)
177    }
178
179    fn select_projection(
180        &self,
181        absent: &FxHashSet<IVec3>,
182    ) -> Result<ModuleSummary, ModuleCertificationError> {
183        let Some(projection) = &self.projection else {
184            return Ok(self.clone());
185        };
186        if absent
187            .iter()
188            .any(|target| !projection.targets.contains(target))
189        {
190            return Err(invalid(&self.name, "projection selects an unknown branch"));
191        }
192        let module = &projection.definition;
193        let graph_error = |source| ModuleCertificationError::Graph {
194            module: module.name.clone(),
195            source,
196        };
197        let mut selected = module.clone_local_definition();
198        selected.replace_local_body(
199            module
200                .local_body()
201                .project_branches_in_definition(
202                    module
203                        .local_body()
204                        .branch_regions()
205                        .map_err(graph_error)?
206                        .iter()
207                        .map(|region| (region.target, !absent.contains(&region.target))),
208                )
209                .map_err(graph_error)?,
210        );
211        if module.instances.is_empty() {
212            return summarize_leaf_body(module, selected.local_body(), projection.limits);
213        }
214        let children = module
215            .instances
216            .iter()
217            .map(|instance| {
218                let base = &self.dependencies[&instance.definition];
219                let mut key = FxHashSet::default();
220                if let Some(child) = &base.projection {
221                    for &target in &child.targets {
222                        if absent.contains(
223                            &instance
224                                .try_transform_position(target)
225                                .map_err(graph_error)?,
226                        ) {
227                            key.insert(target);
228                        }
229                    }
230                }
231                let child = if key.is_empty() {
232                    Arc::clone(base)
233                } else {
234                    Arc::new(base.select_projection(&key)?)
235                };
236                Ok((instance.name.as_str(), (instance, child)))
237            })
238            .collect::<Result<HashMap<_, _>, ModuleCertificationError>>()?;
239        summarize_composite(&selected, module, &children, projection.limits)
240    }
241
242    fn materialize_stabilizers_from(
243        &self,
244        zx: &ZXGraph,
245        orientation: ModuleOrientation,
246        offset: IVec3,
247    ) -> Result<StabilizerGenerators, ModuleCertificationError> {
248        // PauliString holds two BitVecs, each rounded to a 512-bit block.
249        let words = [
250            self.certificate_rows.len(),
251            self.measurements.len(),
252            self.discharged_measurements.len(),
253            self.logical_rows.len(),
254            self.adjustments.len(),
255        ]
256        .into_iter()
257        .try_fold(0usize, usize::checked_add)
258        .and_then(|rows| rows.checked_mul(zx.total_ids().div_ceil(512)))
259        .and_then(|blocks| blocks.checked_mul(16));
260        if words.is_none_or(|words| words > self.limits.max_matrix_words) {
261            return Err(resource_limit(
262                &self.name,
263                "dense matrix words",
264                words.unwrap_or(usize::MAX),
265                self.limits.max_matrix_words,
266            ));
267        }
268        let external_basis = self
269            .certificate_rows
270            .iter()
271            .map(|row| {
272                let stabilizer = materialize_summary_row(
273                    &row.signed,
274                    &row.support,
275                    &self.ports,
276                    zx,
277                    orientation,
278                    offset,
279                    &self.name,
280                )?;
281                let mut paulis = stabilizer.paulis;
282                zx.clear_cross_centers(std::slice::from_mut(&mut paulis));
283                let witness = row
284                    .witness
285                    .transformed(orientation, offset)
286                    .map_err(|source| ModuleCertificationError::Graph {
287                        module: self.name.clone(),
288                        source,
289                    })?;
290                let witnessed =
291                    zx.materialize_flow_witness(&witness, &paulis)
292                        .ok_or_else(|| {
293                            invalid(
294                                &self.name,
295                                "composed certificate witness does not fit the linked graph",
296                            )
297                        })?;
298                if witnessed.paulis != paulis {
299                    return Err(invalid(
300                        &self.name,
301                        "composed certificate witness does not reproduce its positioned support",
302                    ));
303                }
304                Ok(PhasedPauliString::new(paulis, witnessed.phase()))
305            })
306            .collect::<Result<Vec<_>, ModuleCertificationError>>()?;
307        let cached_prefix = self
308            .measurements
309            .iter()
310            .chain(&self.discharged_measurements)
311            .map(|row| {
312                materialize_summary_row(
313                    &row.signed,
314                    &row.support,
315                    &self.ports,
316                    zx,
317                    orientation,
318                    offset,
319                    &self.name,
320                )
321                .and_then(|stabilizer| {
322                    Ok((
323                        transformed_row_kind(&row.kind, orientation, offset, &self.name)?,
324                        stabilizer.paulis,
325                    ))
326                })
327            })
328            .chain(self.logical_rows.iter().map(|row| {
329                materialize_summary_row(
330                    &row.signed,
331                    &row.support,
332                    &self.ports,
333                    zx,
334                    orientation,
335                    offset,
336                    &self.name,
337                )
338                .map(|stabilizer| (StabilizerRowKind::Logical, stabilizer.paulis))
339            }))
340            .collect::<Result<Vec<_>, ModuleCertificationError>>()?;
341        let adjustment_basis = self
342            .adjustments
343            .iter()
344            .map(|row| {
345                let stabilizer = materialize_summary_row(
346                    &row.signed,
347                    &row.support,
348                    &self.ports,
349                    zx,
350                    orientation,
351                    offset,
352                    &self.name,
353                )?;
354                let mut paulis = stabilizer.paulis;
355                zx.clear_cross_centers(std::slice::from_mut(&mut paulis));
356                Ok(paulis)
357            })
358            .collect::<Result<Vec<_>, ModuleCertificationError>>()?;
359        zx.stabilizers_from_composed_basis(
360            &external_basis,
361            &adjustment_basis,
362            &cached_prefix,
363            self.limits,
364        )
365        .map_err(crate::RuntimeBasisError::from)
366        .and_then(|stabilizers| {
367            // C0 / LIM-027: leaf certification alone does not establish
368            // closure after composition. Check the presented readouts,
369            // including selective fills, before using them for decoding.
370            stabilizers.validate_measurements_close_before_outputs_with_limits(self.limits)?;
371            Ok(stabilizers)
372        })
373        .map_err(|source| match source {
374            crate::RuntimeBasisError::Stabilizer(crate::StabilizerError::ResourceLimited {
375                phase,
376                observed,
377                limit,
378            }) => resource_limit(&self.name, phase, observed, limit),
379            source => ModuleCertificationError::Runtime {
380                module: self.name.clone(),
381                source,
382            },
383        })
384    }
385
386    fn port_index(&self, name: &str) -> Option<usize> {
387        self.ports.iter().position(|port| port.name == name)
388    }
389}
390
391fn transformed_row_kind(
392    kind: &StabilizerRowKind,
393    orientation: ModuleOrientation,
394    translation: IVec3,
395    module: &str,
396) -> Result<StabilizerRowKind, ModuleCertificationError> {
397    let mut kind = kind.clone();
398    if let StabilizerRowKind::SelectiveFixing { targets } = &mut kind {
399        for target in targets {
400            target.pos = orientation
401                .try_transform_position(target.pos, translation)
402                .map_err(|source| ModuleCertificationError::Graph {
403                    module: module.to_string(),
404                    source,
405                })?;
406        }
407    }
408    Ok(kind)
409}
410
411fn materialize_summary_row(
412    signed: &PhasedPauliString,
413    support: &PositionedSupport,
414    ports: &[QuantumPort],
415    zx: &ZXGraph,
416    orientation: ModuleOrientation,
417    translation: IVec3,
418    module: &str,
419) -> Result<Stabilizer, ModuleCertificationError> {
420    let mut support = support
421        .transformed(orientation, translation)
422        .map_err(|source| ModuleCertificationError::Graph {
423            module: module.to_string(),
424            source,
425        })?;
426    for (column, port) in ports.iter().enumerate() {
427        let pauli = signed.paulis.get(column);
428        if pauli == Pauli::I {
429            continue;
430        }
431        let position = orientation
432            .try_transform_position(port.position, translation)
433            .map_err(|source| ModuleCertificationError::Graph {
434                module: module.to_string(),
435                source,
436            })?;
437        if let Some(existing) = support.nodes.insert(position, pauli)
438            && existing != pauli
439        {
440            return Err(invalid(
441                module,
442                &format!(
443                    "certificate support repeats public Port {position}: interior {existing}, boundary {pauli}"
444                ),
445            ));
446        }
447    }
448    support.materialize(zx, signed.phase()).ok_or_else(|| {
449        invalid(
450            module,
451            "composed certificate support does not fit the linked graph",
452        )
453    })
454}
455
456#[derive(Clone)]
457struct BindSeam {
458    endpoint: InstancePort,
459    block: IVec3,
460    signature: ModulePortSignature,
461    hadamard: bool,
462    transpose: bool,
463}
464
465#[derive(Default)]
466struct ChildRelation {
467    /// Columns precede `endpoints` and name ports in the parent's interface.
468    parent_ports: Vec<usize>,
469    endpoints: Vec<InstancePort>,
470    rows: Vec<SupportedRow>,
471    logical_rows: Vec<SupportedRow>,
472    certificate_rows: Vec<SupportedRow>,
473    adjustments: Vec<SupportedRow>,
474    measurements: Vec<SummaryMeasurement>,
475    discharged_measurements: Vec<SummaryMeasurement>,
476    protected: Vec<ProtectedSupport>,
477    frontier: Vec<SupportTarget>,
478    protected_groups: Vec<ProtectedGroup>,
479}
480
481impl ChildRelation {
482    fn width(&self) -> usize {
483        self.parent_ports.len() + self.endpoints.len()
484    }
485
486    fn append(&mut self, other: Self, mapping: &[usize], width: usize) {
487        for (target, rows) in [
488            (&mut self.rows, other.rows),
489            (&mut self.logical_rows, other.logical_rows),
490            (&mut self.certificate_rows, other.certificate_rows),
491            (&mut self.adjustments, other.adjustments),
492        ] {
493            target.extend(rows.into_iter().map(|mut row| {
494                row.signed = embed_signed_row(&row.signed, mapping, width);
495                row
496            }));
497        }
498        for (target, rows) in [
499            (&mut self.measurements, other.measurements),
500            (
501                &mut self.discharged_measurements,
502                other.discharged_measurements,
503            ),
504        ] {
505            target.extend(rows.into_iter().map(|mut row| {
506                row.signed = embed_signed_row(&row.signed, mapping, width);
507                row
508            }));
509        }
510        self.parent_ports.extend(other.parent_ports);
511        self.endpoints.extend(other.endpoints);
512        self.protected.extend(other.protected);
513        self.frontier.extend(other.frontier);
514        self.protected_groups.extend(other.protected_groups);
515    }
516
517    fn retire_completed(
518        &mut self,
519        completed: &mut Self,
520        obligations: &FxHashSet<SupportTarget>,
521        module: &str,
522    ) -> Result<(), ModuleCertificationError> {
523        // Boundary-zero certificate rows complete the final physical rank, but
524        // cannot change a later seam equation. Keep their witnesses off the live table.
525        completed.certificate_rows.extend(
526            self.certificate_rows
527                .extract_if(.., |row| row.signed.paulis.is_identity())
528                .map(|mut row| {
529                    row.signed.paulis = PauliString::new(0);
530                    row
531                }),
532        );
533        // A closed adjustment that is zero on every pending obligation cannot
534        // change a future seam solve. Retain it only for final presentation.
535        completed.adjustments.extend(
536            self.adjustments
537                .extract_if(.., |row| {
538                    row.signed.paulis.is_identity()
539                        && !row
540                            .support
541                            .nodes
542                            .keys()
543                            .any(|&position| obligations.contains(&SupportTarget::Node(position)))
544                        && !row.support.edges.keys().any(|&(left, right)| {
545                            obligations.contains(&SupportTarget::Edge(left, right))
546                                || obligations.contains(&SupportTarget::Edge(right, left))
547                        })
548                })
549                .map(|mut row| {
550                    row.signed.paulis = PauliString::new(0);
551                    row
552                }),
553        );
554        resize_discharged_boundaries(&mut self.discharged_measurements, 0, module)?;
555        completed
556            .discharged_measurements
557            .append(&mut self.discharged_measurements);
558        Ok(())
559    }
560}
561
562#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
563enum SupportTarget {
564    Node(IVec3),
565    Edge(IVec3, IVec3),
566}
567
568fn support_target_key(target: &SupportTarget) -> (u8, [i32; 3], [i32; 3]) {
569    match target {
570        SupportTarget::Node(position) => (0, position.to_array(), [0; 3]),
571        SupportTarget::Edge(left, right) => (1, left.to_array(), right.to_array()),
572    }
573}
574
575#[derive(Debug, Clone, Copy)]
576struct ProtectedSupport {
577    target: SupportTarget,
578    forbidden: Option<Pauli>,
579}
580
581#[derive(Debug, Clone)]
582struct ProtectedGroup {
583    targets: Vec<SupportTarget>,
584    permitted_support: Vec<Vec<Pauli>>,
585}
586
587impl ProtectedGroup {
588    fn transformed(
589        self,
590        orientation: ModuleOrientation,
591        translation: IVec3,
592    ) -> Result<Self, crate::BlockGraphError> {
593        Ok(Self {
594            targets: self
595                .targets
596                .into_iter()
597                .map(|target| target.transformed(orientation, translation))
598                .collect::<Result<_, _>>()?,
599            permitted_support: self.permitted_support,
600        })
601    }
602}
603
604fn semantic_protected_supports(module: &BlockGraph, body: &BlockGraph) -> Vec<ProtectedSupport> {
605    let mut protected = HashMap::<SupportTarget, Option<Pauli>>::new();
606    let mut insert = |target, forbidden| {
607        protected
608            .entry(target)
609            .and_modify(|current| {
610                if current.is_none() {
611                    *current = forbidden;
612                }
613            })
614            .or_insert(forbidden);
615    };
616    for block in body.blocks() {
617        if let BlockKind::Selective(kind) = block.kind() {
618            let forbidden = match kind {
619                crate::SelectiveKind::XY => Pauli::Z,
620                crate::SelectiveKind::XZ => Pauli::Y,
621                crate::SelectiveKind::YZ => Pauli::X,
622            };
623            insert(SupportTarget::Node(block.pos()), Some(forbidden));
624        }
625    }
626    for region in module.local_body().branch_definitions() {
627        insert(SupportTarget::Node(region.target), None);
628        for cut in region
629            .incoming_for(false)
630            .iter()
631            .chain(region.incoming_for(true))
632        {
633            insert(SupportTarget::Edge(cut.past, cut.inside), None);
634        }
635    }
636    let mut protected = protected
637        .into_iter()
638        .map(|(target, forbidden)| ProtectedSupport { target, forbidden })
639        .collect::<Vec<_>>();
640    protected.sort_unstable_by_key(|constraint| support_target_key(&constraint.target));
641    protected
642}
643
644/// Positioned support that must survive certificate reduction, but does not
645/// constrain which seam adjustments are legal.
646fn semantic_frontier_supports(
647    module: &BlockGraph,
648    body: &BlockGraph,
649) -> Result<Vec<SupportTarget>, ModuleCertificationError> {
650    let mut frontier = body
651        .blocks()
652        .filter(|block| block.kind().is_t())
653        .map(|block| SupportTarget::Node(block.pos()))
654        .collect::<FxHashSet<_>>();
655    for action in body.actions() {
656        match action {
657            Action::Measure { target, .. } => {
658                let target = match target {
659                    crate::MeasureTarget::Node(position) => SupportTarget::Node(position),
660                    crate::MeasureTarget::Edge { src, dir } => SupportTarget::Edge(
661                        src,
662                        checked_add_position(src, dir.to_ivec3()).map_err(|source| {
663                            ModuleCertificationError::Graph {
664                                module: module.name.clone(),
665                                source,
666                            }
667                        })?,
668                    ),
669                };
670                frontier.insert(target);
671            }
672            Action::Resolve { target, .. } | Action::Branch { target, .. } => {
673                frontier.insert(SupportTarget::Node(target));
674            }
675            Action::Feedback { targets, .. } => {
676                for target in targets {
677                    frontier.insert(match target.direction {
678                        Some(dir) => SupportTarget::Edge(
679                            target.target,
680                            checked_add_position(target.target, dir.to_ivec3()).map_err(
681                                |source| ModuleCertificationError::Graph {
682                                    module: module.name.clone(),
683                                    source,
684                                },
685                            )?,
686                        ),
687                        None => SupportTarget::Node(target.target),
688                    });
689                }
690            }
691            Action::Let { .. } | Action::DiscardIf(_) => {}
692        }
693    }
694    for region in module.local_body().branch_definitions() {
695        frontier.insert(SupportTarget::Node(region.target));
696        frontier.extend(
697            region
698                .incoming_for(false)
699                .iter()
700                .chain(region.incoming_for(true))
701                .map(|cut| SupportTarget::Edge(cut.past, cut.inside)),
702        );
703    }
704    let mut frontier = frontier.into_iter().collect::<Vec<_>>();
705    frontier.sort_unstable_by_key(support_target_key);
706    Ok(frontier)
707}
708
709fn semantic_protected_groups(
710    body: &BlockGraph,
711    measurements: &[SummaryMeasurement],
712    zx: &ZXGraph,
713    limits: ModuleCertificationLimits,
714    module: &str,
715) -> Result<Vec<ProtectedGroup>, ModuleCertificationError> {
716    measurements
717        .iter()
718        .filter_map(|measurement| {
719            let targets = measurement.kind.selective_fixing_targets();
720            (targets.len() > 1).then_some(targets)
721        })
722        .map(|targets| {
723            let positions = targets.iter().map(|target| target.pos).collect::<Vec<_>>();
724            let kinds = positions
725                .iter()
726                .map(|&position| {
727                    let Some(BlockKind::Selective(kind)) =
728                        body.get_block(position).map(Block::kind)
729                    else {
730                        return Err(invalid(module, "selective fixing target is not selective"));
731                    };
732                    Ok(kind)
733                })
734                .collect::<Result<Vec<_>, ModuleCertificationError>>()?;
735            let domain = zx
736                .action_graph()
737                .resolve_value_domain_bounded_with_limits(
738                    &positions,
739                    limits.max_guarded_domain_size,
740                    limits.boolean_limits(),
741                )
742                .map_err(|error| {
743                    match error
744                        .into_stabilizer("selective value domain", limits.max_guarded_domain_size)
745                    {
746                        crate::StabilizerError::ResourceLimited {
747                            phase,
748                            observed,
749                            limit,
750                        } => resource_limit(module, phase, observed, limit),
751                        source => ModuleCertificationError::Graph {
752                            module: module.to_string(),
753                            source: source.into(),
754                        },
755                    }
756                })?;
757            let mut permitted_support = domain
758                .values()
759                .iter()
760                .map(|values| {
761                    kinds
762                        .iter()
763                        .zip(values)
764                        .map(|(kind, &value)| {
765                            Pauli::from(if value {
766                                kind.pauli_if_true()
767                            } else {
768                                kind.pauli_if_false()
769                            })
770                        })
771                        .collect::<Vec<_>>()
772                })
773                .collect::<Vec<_>>();
774            let reachable = permitted_support.iter().cloned().collect::<FxHashSet<_>>();
775            permitted_support.retain(|support| {
776                reachable.contains(
777                    &support
778                        .iter()
779                        .zip(targets)
780                        .map(|(&pauli, target)| pauli ^ target.forbidden)
781                        .collect::<Vec<_>>(),
782                )
783            });
784            Ok(ProtectedGroup {
785                targets: positions.into_iter().map(SupportTarget::Node).collect(),
786                permitted_support,
787            })
788        })
789        .collect()
790}
791
792#[derive(Clone, Copy, PartialEq, Eq, Hash)]
793enum SupportConstraint {
794    Boundary(usize, Pauli),
795    Target(SupportTarget, Pauli),
796}
797
798#[derive(Debug, Clone)]
799struct SupportedRow {
800    signed: PhasedPauliString,
801    support: PositionedSupport,
802    witness: FlowWitness,
803}
804
805#[derive(Debug, Clone)]
806struct SummaryMeasurement {
807    name: String,
808    kind: StabilizerRowKind,
809    signed: PhasedPauliString,
810    support: PositionedSupport,
811    witness: FlowWitness,
812    target: SupportTarget,
813    observable: Pauli,
814    self_readers: Vec<SupportTarget>,
815    owned_positions: FxHashSet<IVec3>,
816}
817
818/// Sparse full-surface support. Keeping positions rather than a hierarchy-wide
819/// dense row makes instance transforms O(surface weight), and connected Port
820/// support can be removed before same-position parent blocks are merged.
821#[derive(Debug, Clone, Default)]
822struct PositionedSupport {
823    nodes: FxHashMap<IVec3, Pauli>,
824    /// Directed edge support in the first endpoint's Pauli frame.
825    edges: FxHashMap<(IVec3, IVec3), Pauli>,
826}
827
828#[derive(Clone, Copy)]
829struct SupportSeam {
830    edge: (IVec3, IVec3),
831    boundary_to_edge_hadamard: bool,
832}
833
834impl PositionedSupport {
835    fn from_stabilizer(stabilizer: &Stabilizer, zx: &ZXGraph) -> Self {
836        // Cross centers are ORs of incident support, not independent GF(2) bits.
837        // Keep raw support through composition and reconstruct at materialization.
838        let mut raw = stabilizer.paulis.clone();
839        zx.clear_cross_centers(std::slice::from_mut(&mut raw));
840        Self {
841            nodes: stabilizer
842                .interior_nodes
843                .iter()
844                .filter(|(position, _)| !stabilizer.port_stabilizer.contains_key(position))
845                .filter_map(|(&p, _)| {
846                    let pauli = raw.get(zx.node_at(p).expect("surface node exists").id);
847                    (pauli != Pauli::I).then_some((p, pauli))
848                })
849                .collect(),
850            edges: stabilizer
851                .interior_edges
852                .iter()
853                .map(|(&edge, &pauli)| (edge, pauli))
854                .collect(),
855        }
856    }
857
858    fn multiply_assign(&mut self, other: &Self) {
859        debug_assert!(
860            self.edges.keys().all(|&(left, right)| {
861                !other.edges.contains_key(&(right, left)) || left == right
862            }),
863            "positioned support edge orientation mismatch"
864        );
865        xor_pauli_maps(&mut self.nodes, &other.nodes);
866        xor_pauli_maps(&mut self.edges, &other.edges);
867    }
868
869    fn get(&self, target: SupportTarget) -> Pauli {
870        match target {
871            SupportTarget::Node(position) => self.nodes.get(&position).copied().unwrap_or(Pauli::I),
872            SupportTarget::Edge(left, right) => self
873                .edges
874                .get(&(left, right))
875                .or_else(|| self.edges.get(&(right, left)))
876                .copied()
877                .unwrap_or(Pauli::I),
878        }
879    }
880
881    fn weight(&self) -> usize {
882        self.nodes.len() + self.edges.len()
883    }
884
885    fn strip_ports(&mut self, ports: &FxHashSet<IVec3>, retained: &[SupportTarget]) {
886        self.nodes.retain(|position, _| !ports.contains(position));
887        self.edges.retain(|&(left, right), _| {
888            (!ports.contains(&left) && !ports.contains(&right))
889                || retained.contains(&SupportTarget::Edge(left, right))
890                || retained.contains(&SupportTarget::Edge(right, left))
891        });
892    }
893
894    fn transformed(
895        &self,
896        orientation: ModuleOrientation,
897        translation: IVec3,
898    ) -> Result<Self, crate::BlockGraphError> {
899        let transform = |position| orientation.try_transform_position(position, translation);
900        Ok(Self {
901            nodes: self
902                .nodes
903                .iter()
904                .map(|(&position, &pauli)| Ok((transform(position)?, pauli)))
905                .collect::<Result<_, crate::BlockGraphError>>()?,
906            edges: self
907                .edges
908                .iter()
909                .map(|(&(left, right), &pauli)| Ok(((transform(left)?, transform(right)?), pauli)))
910                .collect::<Result<_, crate::BlockGraphError>>()?,
911        })
912    }
913
914    fn add_seam(&mut self, seam: SupportSeam, mut pauli: Pauli) -> u8 {
915        if pauli == Pauli::I {
916            return 0;
917        }
918        let phase = 2 * u8::from(seam.boundary_to_edge_hadamard && pauli == Pauli::Y);
919        if seam.boundary_to_edge_hadamard {
920            pauli = pauli.flip();
921        }
922        self.edges.remove(&(seam.edge.1, seam.edge.0));
923        self.edges.insert(seam.edge, pauli);
924        phase
925    }
926
927    fn materialize(&self, zx: &ZXGraph, mut phase: u8) -> Option<Stabilizer> {
928        let mut row = PauliString::new(zx.total_ids());
929        for (&position, &pauli) in &self.nodes {
930            row.set(zx.node_at(position)?.id, pauli);
931        }
932        for (&(source, target), &pauli_at_source) in &self.edges {
933            let source_id = zx.node_at(source)?.id;
934            let target_id = zx.node_at(target)?.id;
935            let forward = zx.edge_id(source_id, target_id)?;
936            let reverse = zx.edge_id(target_id, source_id)?;
937            let edge = &zx.edges()[forward - zx.nodes().len()];
938            let mut stored = pauli_at_source;
939            if source_id > target_id && edge.hadamard {
940                if stored == Pauli::Y {
941                    phase = (phase + 2) % 4;
942                }
943                stored = stored.flip();
944            }
945            row.set(forward, stored);
946            row.set(reverse, stored);
947        }
948        // A spatial rotation can recolor a degree-two identity spider, changing
949        // which component was stored as raw node support. Recover its native
950        // component from the broadcast on all incident arms before rebuilding
951        // crossing centers. Isolated nodes retain their explicit raw support.
952        for node in zx
953            .nodes()
954            .iter()
955            .filter(|node| matches!(node.kind, crate::NodeKind::X | crate::NodeKind::Z))
956        {
957            let Some(neighbors) = zx
958                .neighbors(node.id)
959                .filter(|neighbors| !neighbors.is_empty())
960            else {
961                continue;
962            };
963            let native = node.kind.cross_pauli().flip();
964            let broadcast = neighbors.iter().all(|&neighbor| {
965                let edge = zx.edge_between(node.id, neighbor).expect("incident edge");
966                let axis = if edge.hadamard && node.id > neighbor {
967                    native.flip()
968                } else {
969                    native
970                };
971                row.get(edge.id) & axis
972            });
973            let current = row.get(node.id);
974            if (current & native) != broadcast {
975                row.set(node.id, current ^ native);
976            }
977        }
978        zx.reconstruct_cross_center(std::slice::from_mut(&mut row));
979        Some(zx.pauli_string_to_stabilizer_with_row_phase(row, phase))
980    }
981}
982
983impl SupportTarget {
984    fn transformed(
985        self,
986        orientation: ModuleOrientation,
987        translation: IVec3,
988    ) -> Result<Self, crate::BlockGraphError> {
989        let transform = |position| orientation.try_transform_position(position, translation);
990        Ok(match self {
991            Self::Node(position) => Self::Node(transform(position)?),
992            Self::Edge(left, right) => Self::Edge(transform(left)?, transform(right)?),
993        })
994    }
995}
996
997impl ProtectedSupport {
998    fn transformed(
999        self,
1000        orientation: ModuleOrientation,
1001        translation: IVec3,
1002    ) -> Result<Self, crate::BlockGraphError> {
1003        Ok(Self {
1004            target: self.target.transformed(orientation, translation)?,
1005            forbidden: self.forbidden,
1006        })
1007    }
1008}
1009
1010fn stabilizer_phase(stabilizer: &Stabilizer) -> u8 {
1011    let yy = stabilizer
1012        .interior_edges
1013        .values()
1014        .filter(|&&pauli| pauli == Pauli::Y)
1015        .count()
1016        % 2
1017        == 1;
1018    2 * u8::from(stabilizer.sign ^ yy)
1019}
1020
1021#[derive(Clone)]
1022struct ModuleGeometry {
1023    ports: Vec<QuantumPort>,
1024    signatures: Vec<ModulePortSignature>,
1025}
1026
1027#[derive(Clone, Copy)]
1028struct PortGeometry<'a> {
1029    instance: &'a ModuleInstance,
1030    port: &'a QuantumPort,
1031    signature: ModulePortSignature,
1032}
1033
1034impl BlockGraph {
1035    /// Builds the root's signed quantum summary without flattening child bodies.
1036    /// Native concurrency defaults to the available cores capped at four.
1037    ///
1038    /// # Errors
1039    ///
1040    /// Returns an error if validation, certification, or a resource limit fails.
1041    pub fn summarize_root(
1042        &self,
1043        limits: ModuleCertificationLimits,
1044    ) -> Result<Arc<ModuleSummary>, ModuleCertificationError> {
1045        self.summarize_root_with_jobs(limits, default_module_jobs())
1046    }
1047
1048    /// Builds the root summary using at most `jobs` concurrent module workers.
1049    ///
1050    /// Definitions at the same dependency depth run in parallel on native
1051    /// targets. WebAssembly remains serial.
1052    ///
1053    /// # Errors
1054    ///
1055    /// Returns an error if validation, certification, or a resource limit fails.
1056    pub fn summarize_root_with_jobs(
1057        &self,
1058        limits: ModuleCertificationLimits,
1059        jobs: NonZeroUsize,
1060    ) -> Result<Arc<ModuleSummary>, ModuleCertificationError> {
1061        if !self.has_module_structure() {
1062            let source = self
1063                .clone_local_definition()
1064                .with_inferred_interface()
1065                .map_err(|error| ModuleCertificationError::Graph {
1066                    module: self.name.clone(),
1067                    source: crate::BlockGraphError::ModuleSource(Arc::new(error)),
1068                })?;
1069            return source.summarize_root_with_jobs(limits, jobs);
1070        }
1071        self.validate_with_limits(limits)
1072            .map_err(|error| ModuleCertificationError::Graph {
1073                module: self.name.clone(),
1074                source: crate::BlockGraphError::ModuleSource(Arc::new(error)),
1075            })?;
1076        summarize_program(self, limits, jobs)
1077    }
1078
1079    /// Physical endpoints of direct child-to-child pipes in declaration order.
1080    ///
1081    /// # Panics
1082    ///
1083    /// Panics if validated module geometry is internally inconsistent.
1084    pub fn direct_pipe_endpoints(&self, module: &str) -> Option<Vec<(IVec3, IVec3)>> {
1085        let definition = self.module(module)?;
1086        let mut memo = HashMap::new();
1087        module_geometry(self, module, &mut memo).expect("validated module geometry remains valid");
1088        Some(direct_pipe_endpoints(definition, &memo))
1089    }
1090
1091    /// Physical direct-pipe endpoints for every module, sharing geometry work.
1092    ///
1093    /// # Panics
1094    ///
1095    /// Panics if validated module geometry is internally inconsistent.
1096    pub fn direct_pipe_endpoints_by_module(&self) -> HashMap<String, Vec<(IVec3, IVec3)>> {
1097        let mut memo = HashMap::new();
1098        for module in self.modules() {
1099            module_geometry(self, &module.name, &mut memo)
1100                .expect("validated module geometry remains valid");
1101        }
1102        self.modules()
1103            .map(|module| (module.name.clone(), direct_pipe_endpoints(module, &memo)))
1104            .collect()
1105    }
1106}
1107
1108fn direct_pipe_endpoints(
1109    definition: &BlockGraph,
1110    geometry: &HashMap<String, ModuleGeometry>,
1111) -> Vec<(IVec3, IVec3)> {
1112    let children = definition
1113        .instances
1114        .iter()
1115        .map(|instance| {
1116            (
1117                instance.name.as_str(),
1118                (instance, geometry[&instance.definition].clone()),
1119            )
1120        })
1121        .collect::<HashMap<_, _>>();
1122    let position = |endpoint| {
1123        let port = validated_port(&children, endpoint);
1124        exposed_position(port.instance, port.port, port.signature)
1125            .expect("validated direct endpoint position fits")
1126    };
1127    definition
1128        .quantum_connections
1129        .iter()
1130        .filter_map(|connection| match connection {
1131            QuantumConnection::Pipe { output, input, .. } => {
1132                Some((position(output), position(input)))
1133            }
1134            _ => None,
1135        })
1136        .collect()
1137}
1138
1139impl BlockGraph {
1140    /// Checks the whole source hierarchy's conservative expansion budgets.
1141    ///
1142    /// # Errors
1143    ///
1144    /// Returns typed declaration, cycle, graph, or resource-limit errors.
1145    pub fn validate_resource_limits(
1146        &self,
1147        limits: ModuleCertificationLimits,
1148    ) -> Result<(), crate::BlockGraphError> {
1149        if self.has_module_structure() {
1150            return self
1151                .validate_hierarchy_resource_limits(limits)
1152                .map_err(|error| crate::BlockGraphError::ModuleSource(Arc::new(error)));
1153        }
1154        self.validate_local_resource_limits(limits)
1155    }
1156
1157    /// Checks authored geometry size before cloning or enumerating occupied cells.
1158    /// Both branch arms count; cube footprints use their cached height in cells.
1159    /// This checks `max_expanded_blocks` and `max_occupied_cells` only.
1160    ///
1161    /// # Errors
1162    ///
1163    /// Returns a [`crate::StabilizerError::ResourceLimited`] wrapped in
1164    /// [`crate::BlockGraphError::Stabilizer`] when a count exceeds its limit or
1165    /// cannot fit in `usize`.
1166    pub fn validate_local_resource_limits(
1167        &self,
1168        limits: ModuleCertificationLimits,
1169    ) -> Result<(), crate::BlockGraphError> {
1170        source_expansion_size(self, limits)
1171            .map(|_| ())
1172            .map_err(Into::into)
1173    }
1174}
1175
1176fn add_expansion_size(
1177    size: &mut [usize; 3],
1178    amount: [usize; 3],
1179    limits: ModuleCertificationLimits,
1180) -> Result<(), crate::StabilizerError> {
1181    for ((current, amount), (phase, limit)) in size.iter_mut().zip(amount).zip([
1182        ("expanded blocks", limits.max_expanded_blocks),
1183        ("occupied footprint cells", limits.max_occupied_cells),
1184        ("expanded module instances", limits.max_expanded_instances),
1185    ]) {
1186        let next = current.checked_add(amount);
1187        if next.is_none_or(|next| next > limit) {
1188            return Err(crate::StabilizerError::ResourceLimited {
1189                phase,
1190                observed: next.unwrap_or(usize::MAX),
1191                limit,
1192            });
1193        }
1194        *current = next.expect("checked size fits");
1195    }
1196    Ok(())
1197}
1198
1199fn source_expansion_size(
1200    source: &BlockGraph,
1201    limits: ModuleCertificationLimits,
1202) -> Result<[usize; 3], crate::StabilizerError> {
1203    let mut size = [0usize; 3];
1204    // The shown arm already lives in the body. Count its authored blocks only
1205    // when they differ from that body, so even an unvalidated source is bounded.
1206    let authored = source.branch_definitions().iter().flat_map(|region| {
1207        region.arm(!region.shown_true()).blocks().chain(
1208            region
1209                .shown_arm()
1210                .blocks()
1211                .filter(|block| source.get_block(block.pos()) != Some(*block)),
1212        )
1213    });
1214    for block in source.blocks().chain(authored) {
1215        let cells = match block.kind() {
1216            BlockKind::Walking(kind) => Some(kind.movement_3d()),
1217            BlockKind::PatchRotation(kind) => Some(kind.movement_3d()),
1218            _ => None,
1219        }
1220        .map_or_else(
1221            || block.height_cells() as usize,
1222            |movement| {
1223                // Moving blocks reserve their axis-aligned start/end bounding box.
1224                movement
1225                    .to_array()
1226                    .into_iter()
1227                    .map(|delta| delta.unsigned_abs() as usize + 1)
1228                    .product()
1229            },
1230        );
1231        add_expansion_size(&mut size, [1, cells, 0], limits)?;
1232    }
1233    Ok(size)
1234}
1235
1236/// Count each definition once, then add its cached size for each instance edge.
1237/// Both branch arms and Ports consumed by seams count toward the allocation bound.
1238pub(crate) fn preflight_program_expansion(
1239    program: &BlockGraph,
1240    limits: ModuleCertificationLimits,
1241) -> Result<(), ModuleError> {
1242    let mut sizes = HashMap::<&str, [usize; 3]>::new();
1243    for module in module_postorder(program) {
1244        let error = |source| {
1245            let crate::StabilizerError::ResourceLimited {
1246                phase,
1247                observed,
1248                limit,
1249            } = source
1250            else {
1251                unreachable!("size counting only reports resource limits")
1252            };
1253            program_geometry_error(
1254                &module.name,
1255                resource_limit(&module.name, phase, observed, limit),
1256            )
1257        };
1258        let mut size = source_expansion_size(module.local_body(), limits).map_err(error)?;
1259        add_expansion_size(&mut size, [0, 0, 1], limits).map_err(error)?;
1260        for instance in &module.instances {
1261            add_expansion_size(&mut size, sizes[instance.definition.as_str()], limits)
1262                .map_err(error)?;
1263        }
1264        sizes.insert(&module.name, size);
1265    }
1266    Ok(())
1267}
1268
1269pub(crate) fn validate_program_geometry(program: &BlockGraph) -> Result<(), ModuleError> {
1270    for module in module_postorder(program)
1271        .into_iter()
1272        .filter(|module| !module.instances.is_empty())
1273    {
1274        validate_composite_geometry(program, module)
1275            .map_err(|error| program_geometry_error(&module.name, error))?;
1276    }
1277    let mut memo = HashMap::new();
1278    for module in program.modules() {
1279        module_geometry(program, &module.name, &mut memo)?;
1280    }
1281    Ok(())
1282}
1283
1284fn module_postorder(program: &BlockGraph) -> Vec<&BlockGraph> {
1285    module_postorder_from(
1286        program,
1287        program.modules().map(|module| module.name.as_str()),
1288    )
1289}
1290
1291fn module_postorder_from<'a>(
1292    program: &'a BlockGraph,
1293    roots: impl IntoIterator<Item = &'a str>,
1294) -> Vec<&'a BlockGraph> {
1295    let definitions = program
1296        .modules()
1297        .map(|module| (module.name.as_str(), module))
1298        .collect::<HashMap<_, _>>();
1299    let mut seen = FxHashSet::default();
1300    let mut ordered = Vec::new();
1301    for root in roots {
1302        let mut pending = vec![(root, false)];
1303        while let Some((name, exiting)) = pending.pop() {
1304            let module = definitions[name];
1305            if exiting {
1306                ordered.push(module);
1307            } else if seen.insert(name) {
1308                pending.push((name, true));
1309                pending.extend(
1310                    module
1311                        .instances
1312                        .iter()
1313                        .rev()
1314                        .map(|instance| (instance.definition.as_str(), false)),
1315                );
1316            }
1317        }
1318    }
1319    ordered
1320}
1321
1322fn module_geometry(
1323    program: &BlockGraph,
1324    name: &str,
1325    memo: &mut HashMap<String, ModuleGeometry>,
1326) -> Result<ModuleGeometry, ModuleError> {
1327    if let Some(geometry) = memo.get(name) {
1328        return Ok(geometry.clone());
1329    }
1330    for module in module_postorder_from(program, [name]) {
1331        if memo.contains_key(&module.name) {
1332            continue;
1333        }
1334        let name = module.name.as_str();
1335        let geometry = if module.instances.is_empty() {
1336            let body = module.copy_local_geometry().fix_shadowed_faces();
1337            let signatures = module
1338                .interface
1339                .quantum_ports
1340                .iter()
1341                .map(|port| port_signature(name, &body, port.position))
1342                .collect::<Result<Vec<_>, _>>()
1343                .map_err(|error| program_geometry_error(name, error))?;
1344            ModuleGeometry {
1345                ports: module.interface.quantum_ports.clone(),
1346                signatures,
1347            }
1348        } else {
1349            let mut children = HashMap::new();
1350            for instance in &module.instances {
1351                let geometry = memo[&instance.definition].clone();
1352                children.insert(instance.name.as_str(), (instance, geometry));
1353            }
1354
1355            let mut binds = Vec::new();
1356            for connection in &module.quantum_connections {
1357                match connection {
1358                    QuantumConnection::Input {
1359                        block,
1360                        input,
1361                        hadamard,
1362                    } => {
1363                        binds.push(geometry_bind_seam(
1364                            input, *block, *hadamard, true, &children,
1365                        ));
1366                    }
1367                    QuantumConnection::Output {
1368                        output,
1369                        block,
1370                        hadamard,
1371                    } => {
1372                        binds.push(geometry_bind_seam(
1373                            output, *block, *hadamard, false, &children,
1374                        ));
1375                    }
1376                    QuantumConnection::Pipe {
1377                        output,
1378                        input,
1379                        hadamard,
1380                    } => {
1381                        geometry_direct_seam(output, input, *hadamard, &children, name)
1382                            .map_err(|error| program_geometry_error(name, error))?;
1383                    }
1384                }
1385            }
1386            validate_bind_faces(module, &binds)
1387                .map_err(|error| program_geometry_error(name, error))?;
1388            let extra_pipes = binds
1389                .iter()
1390                .map(|bind| (bind.block, bind.signature.direction.as_udirection()))
1391                .collect::<Vec<_>>();
1392            let body = module
1393                .copy_local_geometry()
1394                .fix_shadowed_faces_with(&extra_pipes);
1395            validate_bind_bases(module, &body, &binds)
1396                .map_err(|error| program_geometry_error(name, error))?;
1397            ModuleGeometry {
1398                ports: module.interface.quantum_ports.clone(),
1399                signatures: parent_signatures(module, &body, &binds)
1400                    .map_err(|error| program_geometry_error(name, error))?,
1401            }
1402        };
1403        memo.insert(name.to_string(), geometry);
1404    }
1405    Ok(memo[name].clone())
1406}
1407
1408fn program_geometry_error(module: &str, error: ModuleCertificationError) -> ModuleError {
1409    ModuleError::InvalidGeometry {
1410        module: module.to_string(),
1411        source: error,
1412        span: None,
1413    }
1414}
1415
1416/// Default worker count for summarizing or compiling a module hierarchy:
1417/// the machine's parallelism capped at 4, and always 1 on wasm.
1418pub fn default_module_jobs() -> NonZeroUsize {
1419    #[cfg(not(target_arch = "wasm32"))]
1420    {
1421        const MAX_JOBS: NonZeroUsize = NonZeroUsize::new(4).expect("4 is nonzero");
1422        std::thread::available_parallelism().map_or(NonZeroUsize::MIN, |jobs| jobs.min(MAX_JOBS))
1423    }
1424    #[cfg(target_arch = "wasm32")]
1425    {
1426        NonZeroUsize::MIN
1427    }
1428}
1429
1430/// Maps `f` over `items` across at most `jobs` scoped worker threads, keeping
1431/// the results in input order.
1432///
1433/// Chunked rather than work-stealing: the callers
1434/// map over module definitions, whose per-item cost is uneven but whose counts
1435/// are small.
1436///
1437/// wasm has no threads, so it always runs serially.
1438///
1439/// # Panics
1440///
1441/// Panics if `f` panics in a worker thread.
1442///
1443// ponytail: scoped workers are enough; add a pool only if spawn profiles hot.
1444pub fn map_jobs<T: Sync, R: Send>(
1445    items: &[T],
1446    jobs: NonZeroUsize,
1447    f: impl Fn(&T) -> R + Sync,
1448) -> Vec<R> {
1449    #[cfg(target_arch = "wasm32")]
1450    let _ = jobs;
1451    #[cfg(not(target_arch = "wasm32"))]
1452    if items.len() > 1 && jobs.get() > 1 {
1453        let worker_count = jobs.get().min(items.len());
1454        let f = &f;
1455        let cancellation = crate::CancellationToken::current();
1456        return std::thread::scope(|scope| {
1457            let workers = (0..worker_count)
1458                .map(|worker| {
1459                    let start = items.len() * worker / worker_count;
1460                    let end = items.len() * (worker + 1) / worker_count;
1461                    let chunk = &items[start..end];
1462                    let cancellation = cancellation.clone();
1463                    scope.spawn(move || {
1464                        let run = || chunk.iter().map(f).collect::<Vec<_>>();
1465                        match cancellation {
1466                            Some(token) => token.scope(run),
1467                            None => run(),
1468                        }
1469                    })
1470                })
1471                .collect::<Vec<_>>();
1472            workers
1473                .into_iter()
1474                .flat_map(|worker| worker.join().expect("map_jobs worker does not panic"))
1475                .collect()
1476        });
1477    }
1478    items.iter().map(f).collect()
1479}
1480
1481fn summarize_program(
1482    program: &BlockGraph,
1483    limits: ModuleCertificationLimits,
1484    jobs: NonZeroUsize,
1485) -> Result<Arc<ModuleSummary>, ModuleCertificationError> {
1486    preflight_program_expansion(program, limits).map_err(|error| match error {
1487        ModuleError::InvalidGeometry { source, .. } => source,
1488        _ => unreachable!("size preflight only reports resource limits"),
1489    })?;
1490    let mut depths = HashMap::new();
1491    let mut levels: Vec<Vec<&BlockGraph>> = Vec::new();
1492    let mut guarded = false;
1493    for module in module_postorder_from(program, [program.root().name.as_str()]) {
1494        guarded |= module.local_body().has_continuing_branches();
1495        let depth = module
1496            .instances
1497            .iter()
1498            .map(|instance| depths[instance.definition.as_str()] + 1)
1499            .max()
1500            .unwrap_or(0);
1501        levels.resize_with(levels.len().max(depth + 1), Vec::new);
1502        levels[depth].push(module);
1503        depths.insert(module.name.as_str(), depth);
1504    }
1505
1506    let mut summaries = HashMap::new();
1507    for level in levels {
1508        let results = map_jobs(&level, jobs, |&module| {
1509            summarize_definition(program, module, limits, &summaries, guarded)
1510        });
1511        for (module, summary) in level.iter().zip(results) {
1512            summaries.insert(module.name.clone(), Arc::new(summary?));
1513        }
1514    }
1515    Ok(Arc::clone(
1516        summaries
1517            .get(&program.root().name)
1518            .expect("dependency order includes the root module"),
1519    ))
1520}
1521
1522fn summarize_definition(
1523    program: &BlockGraph,
1524    module: &BlockGraph,
1525    limits: ModuleCertificationLimits,
1526    summaries: &HashMap<String, Arc<ModuleSummary>>,
1527    guarded: bool,
1528) -> Result<ModuleSummary, ModuleCertificationError> {
1529    let projection = if guarded {
1530        let linked = crate::flatten_module_definition(program, module, "").map_err(|source| {
1531            ModuleCertificationError::Graph {
1532                module: module.name.clone(),
1533                source,
1534            }
1535        })?;
1536        let targets = linked
1537            .graph
1538            .branch_regions()
1539            .map_err(|source| ModuleCertificationError::Graph {
1540                module: module.name.clone(),
1541                source,
1542            })?
1543            .into_iter()
1544            .map(|region| region.target)
1545            .collect::<Vec<_>>();
1546        if !targets.is_empty() {
1547            let certify = || -> Result<(), crate::BlockGraphError> {
1548                let topology = crate::GuardedTopology::new(&linked.graph, limits)?;
1549                crate::GuardedSurfaceSpace::new(topology, &linked.sites, limits)?
1550                    .plan_readouts()
1551                    .map(drop)
1552            };
1553            certify().map_err(|source| ModuleCertificationError::Graph {
1554                module: module.name.clone(),
1555                source,
1556            })?;
1557            Some(Box::new(ModuleProjection {
1558                definition: module.clone_local_definition(),
1559                targets,
1560                limits,
1561            }))
1562        } else {
1563            None
1564        }
1565    } else {
1566        None
1567    };
1568    if module.instances.is_empty() {
1569        let mut summary = summarize_leaf(module, limits)?;
1570        if guarded {
1571            summary.projection = projection;
1572            return Ok(summary);
1573        }
1574        summary.branch_variants = branch_assignments(module, limits)?
1575            .into_iter()
1576            .map(|assignments| {
1577                let mut key = assignments
1578                    .iter()
1579                    .copied()
1580                    .filter(|(_, value)| !value)
1581                    .collect::<Vec<_>>();
1582                key.sort_unstable_by_key(|(position, value)| (position.to_array(), *value));
1583                let body = module
1584                    .local_body()
1585                    .project_branches_deferred(assignments.iter().copied())
1586                    .map_err(|source| ModuleCertificationError::Graph {
1587                        module: module.name.clone(),
1588                        source,
1589                    })?;
1590                Ok(ModuleBranchVariant {
1591                    assignments: key,
1592                    summary: Box::new(summarize_leaf_body(module, &body, limits)?),
1593                })
1594            })
1595            .collect::<Result<_, ModuleCertificationError>>()?;
1596        return Ok(summary);
1597    }
1598    let children = module
1599        .instances
1600        .iter()
1601        .map(|instance| {
1602            let summary = summaries
1603                .get(&instance.definition)
1604                .expect("dependency summary is ready");
1605            (instance.name.as_str(), (instance, Arc::clone(summary)))
1606        })
1607        .collect();
1608    let mut canonical = module.clone_local_definition();
1609    canonical.replace_local_body(module.local_body().canonical_true_branch_view().map_err(
1610        |source| ModuleCertificationError::Graph {
1611            module: module.name.clone(),
1612            source,
1613        },
1614    )?);
1615    let mut summary = summarize_composite(&canonical, module, &children, limits)?;
1616    if guarded {
1617        summary.projection = projection;
1618    } else {
1619        summary.branch_variants = summarize_composite_variants(module, summaries, limits)?;
1620    }
1621    Ok(summary)
1622}
1623
1624fn branch_assignments(
1625    module: &BlockGraph,
1626    limits: ModuleCertificationLimits,
1627) -> Result<Vec<Vec<(IVec3, bool)>>, ModuleCertificationError> {
1628    let targets = module
1629        .local_body()
1630        .branch_regions()
1631        .map_err(|source| ModuleCertificationError::Graph {
1632            module: module.name.clone(),
1633            source,
1634        })?
1635        .into_iter()
1636        .map(|region| region.target)
1637        .collect::<Vec<_>>();
1638    if targets.is_empty() {
1639        return Ok(Vec::new());
1640    }
1641    if targets.len() > limits.max_guarded_domain_size {
1642        return Err(resource_limit(
1643            &module.name,
1644            "structural module alternatives",
1645            targets.len(),
1646            limits.max_guarded_domain_size,
1647        ));
1648    }
1649    Ok((0..targets.len())
1650        .map(|alternative| {
1651            targets
1652                .iter()
1653                .enumerate()
1654                .map(|(index, &target)| (target, index != alternative))
1655                .collect()
1656        })
1657        .collect())
1658}
1659
1660fn summarize_composite_variants(
1661    module: &BlockGraph,
1662    summaries: &HashMap<String, Arc<ModuleSummary>>,
1663    limits: ModuleCertificationLimits,
1664) -> Result<Vec<ModuleBranchVariant>, ModuleCertificationError> {
1665    let local_assignments = branch_assignments(module, limits)?;
1666    let variant_count = local_assignments.len().saturating_add(
1667        module
1668            .instances
1669            .iter()
1670            .map(|instance| summaries[&instance.definition].branch_variants.len())
1671            .sum::<usize>(),
1672    );
1673    if variant_count > limits.max_guarded_domain_size {
1674        return Err(resource_limit(
1675            &module.name,
1676            "structural module alternatives",
1677            variant_count,
1678            limits.max_guarded_domain_size,
1679        ));
1680    }
1681    let mut variants = Vec::with_capacity(variant_count);
1682    let canonical_children = module
1683        .instances
1684        .iter()
1685        .map(|instance| {
1686            (
1687                instance.name.as_str(),
1688                (instance, Arc::clone(&summaries[&instance.definition])),
1689            )
1690        })
1691        .collect::<HashMap<_, _>>();
1692    for assignments in local_assignments {
1693        let body = module
1694            .local_body()
1695            .project_branches_in_definition(assignments.iter().copied())
1696            .map_err(|source| ModuleCertificationError::Graph {
1697                module: module.name.clone(),
1698                source,
1699            })?;
1700        let mut projected = module.clone_local_definition();
1701        projected.replace_local_body(body);
1702        variants.push(ModuleBranchVariant {
1703            assignments: assignments
1704                .into_iter()
1705                .filter(|(_, value)| !value)
1706                .collect(),
1707            summary: Box::new(summarize_composite(
1708                &projected,
1709                module,
1710                &canonical_children,
1711                limits,
1712            )?),
1713        });
1714    }
1715
1716    let mut canonical = module.clone_local_definition();
1717    canonical.replace_local_body(module.local_body().canonical_true_branch_view().map_err(
1718        |source| ModuleCertificationError::Graph {
1719            module: module.name.clone(),
1720            source,
1721        },
1722    )?);
1723    for (selected, instance) in module.instances.iter().enumerate() {
1724        let child = &summaries[&instance.definition];
1725        for alternative in &child.branch_variants {
1726            let children = module
1727                .instances
1728                .iter()
1729                .enumerate()
1730                .map(|(index, instance)| {
1731                    let summary = if index == selected {
1732                        Arc::new(alternative.summary.as_ref().clone())
1733                    } else {
1734                        Arc::clone(&summaries[&instance.definition])
1735                    };
1736                    (instance.name.as_str(), (instance, summary))
1737                })
1738                .collect::<HashMap<_, _>>();
1739            let mut assignments = alternative
1740                .assignments
1741                .iter()
1742                .map(|&(target, value)| {
1743                    instance
1744                        .try_transform_position(target)
1745                        .map(|target| (target, value))
1746                        .map_err(|source| ModuleCertificationError::Graph {
1747                            module: module.name.clone(),
1748                            source,
1749                        })
1750                })
1751                .collect::<Result<Vec<_>, _>>()?;
1752            assignments.sort_unstable_by_key(|(position, value)| (position.to_array(), *value));
1753            variants.push(ModuleBranchVariant {
1754                assignments,
1755                summary: Box::new(summarize_composite(&canonical, module, &children, limits)?),
1756            });
1757        }
1758    }
1759    Ok(variants)
1760}
1761
1762fn summarize_leaf(
1763    module: &BlockGraph,
1764    limits: ModuleCertificationLimits,
1765) -> Result<ModuleSummary, ModuleCertificationError> {
1766    let body = module
1767        .local_body()
1768        .canonical_true_branch_view()
1769        .map_err(|source| ModuleCertificationError::Graph {
1770            module: module.name.clone(),
1771            source,
1772        })?;
1773    summarize_leaf_body(module, &body, limits)
1774}
1775
1776fn summarize_leaf_body(
1777    module: &BlockGraph,
1778    body: &BlockGraph,
1779    limits: ModuleCertificationLimits,
1780) -> Result<ModuleSummary, ModuleCertificationError> {
1781    let certificate = crate::program::certify_leaf_body(
1782        &module.name,
1783        body,
1784        &module.interface.quantum_ports,
1785        limits,
1786    )?;
1787    summarize_leaf_certificate(module, body, certificate, limits)
1788}
1789
1790fn summarize_readouts(
1791    body: &BlockGraph,
1792    zx: &ZXGraph,
1793    stabilizers: &StabilizerGenerators,
1794    table: &crate::zx::ProjectedExternalTable,
1795    port_columns: &[usize],
1796) -> Vec<SummaryMeasurement> {
1797    let measurement_columns = zx.measurement_columns();
1798    let measurement_observables = zx
1799        .action_graph()
1800        .ordered_nodes()
1801        .filter_map(|node| {
1802            let Action::Measure { name, .. } = &node.action else {
1803                return None;
1804            };
1805            let observable = match node.measurement? {
1806                MeasurementObservable::Concrete(PauliBasis::X) => Pauli::X,
1807                MeasurementObservable::Concrete(PauliBasis::Z) => Pauli::Z,
1808                MeasurementObservable::Concrete(PauliBasis::Y)
1809                | MeasurementObservable::Selective(_) => Pauli::Y,
1810            };
1811            Some((name.as_str(), observable))
1812        })
1813        .collect::<HashMap<_, _>>();
1814    let owned_positions = body
1815        .blocks()
1816        .filter(|block| !block.kind().is_port())
1817        .map(Block::pos)
1818        .collect::<FxHashSet<_>>();
1819    // One basis per certificate, reduced against every generator below.
1820    let flow_basis = table.flow_witness_basis();
1821    stabilizers
1822        .generators
1823        .iter()
1824        .enumerate()
1825        .filter_map(|(index, generator)| {
1826            let (name, target, observable, self_readers) = match &generator.kind {
1827                StabilizerRowKind::Measurement { name } => (
1828                    name.clone(),
1829                    support_target(zx, measurement_columns[name.as_str()]),
1830                    measurement_observables[name.as_str()],
1831                    self_reader_targets(zx, name),
1832                ),
1833                StabilizerRowKind::SelectiveFixing { targets } => (
1834                    format!("#fix{index}"),
1835                    SupportTarget::Node(targets[0].pos),
1836                    Pauli::I,
1837                    Vec::new(),
1838                ),
1839                StabilizerRowKind::Logical => return None,
1840            };
1841            let support = PositionedSupport::from_stabilizer(&generator.stabilizer, zx);
1842            let mut raw = generator.stabilizer.paulis.clone();
1843            zx.clear_cross_centers(std::slice::from_mut(&mut raw));
1844            let witness = flow_basis
1845                .witness_for_row(&raw)
1846                .expect("certified generator belongs to the projected row space");
1847            Some(SummaryMeasurement {
1848                name,
1849                kind: generator.kind.clone(),
1850                signed: PhasedPauliString::new(
1851                    PauliString::from_terms(
1852                        port_columns.len(),
1853                        port_columns.iter().enumerate().map(|(target, &source)| {
1854                            (target, generator.stabilizer.paulis.get(source))
1855                        }),
1856                    ),
1857                    stabilizer_phase(&generator.stabilizer),
1858                ),
1859                support,
1860                witness,
1861                target,
1862                observable,
1863                self_readers,
1864                owned_positions: owned_positions.clone(),
1865            })
1866        })
1867        .collect::<Vec<_>>()
1868}
1869
1870fn summarize_leaf_certificate(
1871    module: &BlockGraph,
1872    source: &BlockGraph,
1873    certificate: crate::LeafModuleCertificate,
1874    limits: ModuleCertificationLimits,
1875) -> Result<ModuleSummary, ModuleCertificationError> {
1876    let body = source.fix_shadowed_faces();
1877    let signatures = module
1878        .interface
1879        .quantum_ports
1880        .iter()
1881        .map(|port| port_signature(&module.name, &body, port.position))
1882        .collect::<Result<Vec<_>, _>>()?;
1883    let zx = &certificate.stabilizers.zx_graph;
1884    let rows = certificate
1885        .table
1886        .boundary_rows
1887        .iter()
1888        .map(|row| {
1889            let full = certificate.table.materialize(row);
1890            // Only support is consumed; `row.signed` already owns the certificate phase.
1891            let stabilizer = zx.materialize_stabilizer_with_sign(full.paulis, false);
1892            SupportedRow {
1893                signed: row.signed.clone(),
1894                support: PositionedSupport::from_stabilizer(&stabilizer, zx),
1895                witness: row.flow_witness.clone(),
1896            }
1897        })
1898        .collect::<Vec<_>>();
1899    let port_columns = module
1900        .interface
1901        .quantum_ports
1902        .iter()
1903        .map(|port| {
1904            zx.node_at(port.position)
1905                .expect("validated module port is a ZX node")
1906                .id
1907        })
1908        .collect::<Vec<_>>();
1909    let measurements = summarize_readouts(
1910        &body,
1911        zx,
1912        &certificate.stabilizers,
1913        &certificate.table,
1914        &port_columns,
1915    );
1916    let logical_rows = certificate
1917        .stabilizers
1918        .generators
1919        .iter()
1920        .filter(|generator| matches!(generator.kind, StabilizerRowKind::Logical))
1921        .map(|generator| SupportedRow {
1922            signed: PhasedPauliString::new(
1923                PauliString::from_terms(
1924                    port_columns.len(),
1925                    port_columns
1926                        .iter()
1927                        .enumerate()
1928                        .map(|(target, &source)| (target, generator.stabilizer.paulis.get(source))),
1929                ),
1930                stabilizer_phase(&generator.stabilizer),
1931            ),
1932            support: PositionedSupport::from_stabilizer(&generator.stabilizer, zx),
1933            witness: FlowWitness::default(),
1934        })
1935        .collect::<Vec<_>>();
1936    let protected_groups =
1937        semantic_protected_groups(&body, &measurements, zx, limits, &module.name)?;
1938    let (discharged_measurements, measurements): (Vec<_>, Vec<_>) = measurements
1939        .into_iter()
1940        .partition(measurement_can_discharge);
1941    let protected = semantic_protected_supports(module, &body);
1942    let frontier = semantic_frontier_supports(module, &body)?;
1943    let adjustments = adjustment_rows(
1944        zx,
1945        &certificate.table,
1946        &rows,
1947        &measurements,
1948        &protected,
1949        &frontier,
1950        module.interface.quantum_ports.len(),
1951    );
1952    let certificate_rows = retained_certificate_rows(
1953        zx,
1954        &certificate.table,
1955        &rows,
1956        module.interface.quantum_ports.len(),
1957    );
1958    Ok(ModuleSummary {
1959        name: module.name.clone(),
1960        limits,
1961        dependencies: HashMap::new(),
1962        ports: module.interface.quantum_ports.clone(),
1963        signatures,
1964        rows,
1965        logical_rows,
1966        certificate_rows,
1967        adjustments,
1968        measurements,
1969        discharged_measurements,
1970        protected,
1971        frontier,
1972        protected_groups,
1973        branch_variants: Vec::new(),
1974        projection: None,
1975    })
1976}
1977
1978fn measurement_can_discharge(measurement: &SummaryMeasurement) -> bool {
1979    matches!(measurement.kind, StabilizerRowKind::Measurement { .. })
1980        && measurement.signed.paulis.is_identity()
1981        && support_target_is_owned(measurement.target, &measurement.owned_positions)
1982        && measurement
1983            .self_readers
1984            .iter()
1985            .all(|&target| support_target_is_owned(target, &measurement.owned_positions))
1986}
1987
1988fn support_target_is_owned(target: SupportTarget, owned: &FxHashSet<IVec3>) -> bool {
1989    match target {
1990        SupportTarget::Node(position) => owned.contains(&position),
1991        SupportTarget::Edge(left, right) => owned.contains(&left) && owned.contains(&right),
1992    }
1993}
1994
1995fn support_target(zx: &ZXGraph, column: usize) -> SupportTarget {
1996    if column < zx.nodes().len() {
1997        SupportTarget::Node(zx.nodes()[column].pos)
1998    } else {
1999        let edge = &zx.edges()[column - zx.nodes().len()];
2000        SupportTarget::Edge(zx.nodes()[edge.n1].pos, zx.nodes()[edge.n2].pos)
2001    }
2002}
2003
2004fn self_reader_targets(zx: &ZXGraph, measurement: &str) -> Vec<SupportTarget> {
2005    let actions = zx.action_graph().ordered_nodes().collect::<Vec<_>>();
2006    let Some(start) = actions.iter().position(
2007        |node| matches!(&node.action, Action::Measure { name, .. } if name == measurement),
2008    ) else {
2009        return Vec::new();
2010    };
2011    let mut successors = vec![Vec::new(); actions.len()];
2012    for (from, to, _) in zx.action_graph().dependencies() {
2013        successors[from].push(to);
2014    }
2015    let mut seen = FxHashSet::default();
2016    let mut stack = successors[start].clone();
2017    while let Some(ordinal) = stack.pop() {
2018        if seen.insert(ordinal) {
2019            stack.extend(successors[ordinal].iter().copied());
2020        }
2021    }
2022    let mut targets = FxHashSet::default();
2023    for ordinal in seen {
2024        match &actions[ordinal].action {
2025            Action::Resolve { target, .. } | Action::Branch { target, .. } => {
2026                targets.insert(SupportTarget::Node(*target));
2027            }
2028            Action::Feedback {
2029                targets: feedbacks, ..
2030            } => {
2031                for feedback in feedbacks {
2032                    let node = zx
2033                        .node_at(feedback.target)
2034                        .expect("validated feedback target");
2035                    let neighbor = match feedback.direction {
2036                        Some(dir) => zx
2037                            .node_at(
2038                                checked_add_position(feedback.target, dir.to_ivec3())
2039                                    .expect("validated feedback edge"),
2040                            )
2041                            .map(|node| node.id),
2042                        None if node.kind == crate::NodeKind::Port => zx
2043                            .neighbors(node.id)
2044                            .and_then(|neighbors| (neighbors.len() == 1).then(|| neighbors[0])),
2045                        None => None,
2046                    };
2047                    targets.insert(match neighbor {
2048                        Some(neighbor) => support_target(
2049                            zx,
2050                            zx.edge_id(node.id, neighbor).expect("feedback wire exists"),
2051                        ),
2052                        None => SupportTarget::Node(feedback.target),
2053                    });
2054                }
2055            }
2056            Action::Let { .. } | Action::Measure { .. } | Action::DiscardIf(_) => {}
2057        }
2058    }
2059    targets.into_iter().collect()
2060}
2061
2062fn retained_certificate_rows(
2063    zx: &ZXGraph,
2064    table: &crate::zx::ProjectedExternalTable,
2065    boundary_rows: &[SupportedRow],
2066    boundary_width: usize,
2067) -> Vec<SupportedRow> {
2068    let mut rows = boundary_rows.to_vec();
2069    rows.extend(table.closed_rows.iter().map(|row| SupportedRow {
2070        signed: PhasedPauliString::new(PauliString::new(boundary_width), row.signed.phase()),
2071        support: PositionedSupport::from_stabilizer(
2072            &zx.materialize_stabilizer_with_sign(row.signed.paulis.clone(), false),
2073            zx,
2074        ),
2075        witness: row.flow_witness.clone(),
2076    }));
2077    rows
2078}
2079
2080fn adjustment_rows(
2081    zx: &ZXGraph,
2082    table: &crate::zx::ProjectedExternalTable,
2083    boundary_rows: &[SupportedRow],
2084    measurements: &[SummaryMeasurement],
2085    protected: &[ProtectedSupport],
2086    frontier: &[SupportTarget],
2087    boundary_width: usize,
2088) -> Vec<SupportedRow> {
2089    let mut rows = retained_certificate_rows(zx, table, boundary_rows, boundary_width);
2090    let mut targets = measurements
2091        .iter()
2092        .map(|measurement| measurement.target)
2093        .chain(
2094            measurements
2095                .iter()
2096                .flat_map(|measurement| measurement.self_readers.iter().copied()),
2097        )
2098        .chain(protected.iter().map(|constraint| constraint.target))
2099        .chain(frontier.iter().copied())
2100        .collect::<FxHashSet<_>>()
2101        .into_iter()
2102        .collect::<Vec<_>>();
2103    targets.sort_unstable_by_key(support_target_key);
2104    let rank = signed_gaussian_elimination(
2105        &mut rows,
2106        (0..boundary_width)
2107            .flat_map(|column| {
2108                [Pauli::X, Pauli::Z].map(move |axis| SupportConstraint::Boundary(column, axis))
2109            })
2110            .chain(targets.into_iter().flat_map(|target| {
2111                [Pauli::X, Pauli::Z].map(move |axis| SupportConstraint::Target(target, axis))
2112            })),
2113        |row, constraint| match *constraint {
2114            SupportConstraint::Boundary(column, axis) => row.signed.paulis.get(column) & axis,
2115            SupportConstraint::Target(target, axis) => row.support.get(target) & axis,
2116        },
2117    );
2118    rows.truncate(rank);
2119    rows
2120}
2121
2122fn summarize_composite(
2123    module: &BlockGraph,
2124    semantic_module: &BlockGraph,
2125    children: &HashMap<&str, (&ModuleInstance, Arc<ModuleSummary>)>,
2126    limits: ModuleCertificationLimits,
2127) -> Result<ModuleSummary, ModuleCertificationError> {
2128    let parent_width = module.interface.quantum_ports.len();
2129    let mut relations = Vec::with_capacity(module.instances.len());
2130    let mut owners = HashMap::new();
2131    for instance in &module.instances {
2132        let summary = &children[instance.name.as_str()].1;
2133        let endpoints = summary
2134            .ports
2135            .iter()
2136            .map(|port| InstancePort {
2137                instance: instance.name.clone(),
2138                port: port.name.clone(),
2139            })
2140            .collect::<Vec<_>>();
2141        let owner = relations.len();
2142        for endpoint in &endpoints {
2143            owners.insert(endpoint.clone(), owner);
2144        }
2145        let port_positions = summary
2146            .ports
2147            .iter()
2148            .map(|port| port.position)
2149            .collect::<Vec<_>>();
2150        let port_position_set = port_positions.iter().copied().collect::<FxHashSet<_>>();
2151        let retained_targets = summary
2152            .measurements
2153            .iter()
2154            .chain(&summary.discharged_measurements)
2155            .flat_map(|measurement| {
2156                std::iter::once(measurement.target).chain(measurement.self_readers.iter().copied())
2157            })
2158            .collect::<Vec<_>>();
2159        let rows = instantiate_rows(
2160            &summary.rows,
2161            instance,
2162            &port_position_set,
2163            &retained_targets,
2164            &module.name,
2165        )?;
2166        let logical_rows = instantiate_rows(
2167            &summary.logical_rows,
2168            instance,
2169            &port_position_set,
2170            &retained_targets,
2171            &module.name,
2172        )?;
2173        let certificate_rows = instantiate_rows(
2174            &summary.certificate_rows,
2175            instance,
2176            &port_position_set,
2177            &retained_targets,
2178            &module.name,
2179        )?;
2180        let adjustments = instantiate_rows(
2181            &summary.adjustments,
2182            instance,
2183            &port_position_set,
2184            &retained_targets,
2185            &module.name,
2186        )?;
2187        let measurements = instantiate_measurements(
2188            &summary.measurements,
2189            instance,
2190            &port_positions,
2191            &retained_targets,
2192            &module.name,
2193        )?;
2194        let discharged_measurements = instantiate_measurements(
2195            &summary.discharged_measurements,
2196            instance,
2197            &port_positions,
2198            &retained_targets,
2199            &module.name,
2200        )?;
2201        let orientation = instance.orientation();
2202        let graph_error = |source| ModuleCertificationError::Graph {
2203            module: module.name.clone(),
2204            source,
2205        };
2206        let protected = summary
2207            .protected
2208            .iter()
2209            .map(|&target| {
2210                target
2211                    .transformed(orientation, instance.translation)
2212                    .map_err(graph_error)
2213            })
2214            .collect::<Result<Vec<_>, ModuleCertificationError>>()?;
2215        let frontier = summary
2216            .frontier
2217            .iter()
2218            .map(|&target| {
2219                target
2220                    .transformed(orientation, instance.translation)
2221                    .map_err(graph_error)
2222            })
2223            .collect::<Result<Vec<_>, ModuleCertificationError>>()?;
2224        let protected_groups = summary
2225            .protected_groups
2226            .iter()
2227            .cloned()
2228            .map(|group| {
2229                group
2230                    .transformed(orientation, instance.translation)
2231                    .map_err(graph_error)
2232            })
2233            .collect::<Result<Vec<_>, ModuleCertificationError>>()?;
2234        relations.push(Some(ChildRelation {
2235            parent_ports: Vec::new(),
2236            endpoints,
2237            rows,
2238            logical_rows,
2239            certificate_rows,
2240            adjustments,
2241            measurements,
2242            discharged_measurements,
2243            protected,
2244            frontier,
2245            protected_groups,
2246        }));
2247    }
2248
2249    let mut binds = Vec::new();
2250    for connection in &module.quantum_connections {
2251        match connection {
2252            QuantumConnection::Input {
2253                block,
2254                input,
2255                hadamard,
2256            } => {
2257                binds.push(bind_seam(input, *block, *hadamard, true, children));
2258            }
2259            QuantumConnection::Output {
2260                output,
2261                block,
2262                hadamard,
2263            } => {
2264                binds.push(bind_seam(output, *block, *hadamard, false, children));
2265            }
2266            QuantumConnection::Pipe {
2267                output,
2268                input,
2269                hadamard,
2270            } => {
2271                let effective_hadamard =
2272                    direct_seam_hadamard(output, input, *hadamard, children, &module.name)?;
2273                let output_geometry = summarized_port(children, output);
2274                let input_geometry = summarized_port(children, input);
2275                let support_seam = SupportSeam {
2276                    edge: (
2277                        exposed_position(
2278                            output_geometry.instance,
2279                            output_geometry.port,
2280                            output_geometry.signature,
2281                        )?,
2282                        exposed_position(
2283                            input_geometry.instance,
2284                            input_geometry.port,
2285                            input_geometry.signature,
2286                        )?,
2287                    ),
2288                    boundary_to_edge_hadamard: output_geometry.signature.hadamard,
2289                };
2290                compose_child_seam(
2291                    (output, input),
2292                    effective_hadamard,
2293                    support_seam,
2294                    &mut relations,
2295                    &mut owners,
2296                    limits.max_frontier_width,
2297                    &module.name,
2298                )?;
2299            }
2300        }
2301    }
2302
2303    ensure_composition_width(&module.name, parent_width, limits.max_frontier_width)?;
2304    validate_bind_faces(module, &binds)?;
2305    let seams = binds
2306        .iter()
2307        .map(|bind| ModuleSeam {
2308            block: bind.block,
2309            direction: bind.signature.direction,
2310        })
2311        .collect::<Vec<_>>();
2312    let extra_pipes = seams
2313        .iter()
2314        .map(|seam| (seam.block, seam.direction.as_udirection()))
2315        .collect::<Vec<_>>();
2316    let fixed_body = module
2317        .copy_local_geometry()
2318        .fix_shadowed_faces_with(&extra_pipes);
2319    validate_bind_bases(module, &fixed_body, &binds)?;
2320    let signatures = parent_signatures(module, &fixed_body, &binds)?;
2321    let parent_protected = semantic_protected_supports(semantic_module, &fixed_body);
2322    let parent_frontier = semantic_frontier_supports(semantic_module, &fixed_body)?;
2323    // Include obligations from all children, even those not admitted yet.
2324    let obligations = relations
2325        .iter()
2326        .flatten()
2327        .flat_map(|relation| {
2328            relation
2329                .measurements
2330                .iter()
2331                .flat_map(|measurement| {
2332                    std::iter::once(measurement.target)
2333                        .chain(measurement.self_readers.iter().copied())
2334                })
2335                .chain(relation.protected.iter().map(|support| support.target))
2336                .chain(
2337                    relation
2338                        .protected_groups
2339                        .iter()
2340                        .flat_map(|group| group.targets.iter().copied()),
2341                )
2342        })
2343        .chain(parent_protected.iter().map(|support| support.target))
2344        .collect::<FxHashSet<_>>();
2345    let mut completed = ChildRelation::default();
2346    for relation in relations.iter_mut().flatten() {
2347        relation.retire_completed(&mut completed, &obligations, &module.name)?;
2348    }
2349
2350    let (connector, seam_nodes) =
2351        ZXGraph::from_module_body(&fixed_body, &seams).map_err(|source| {
2352            ModuleCertificationError::Graph {
2353                module: module.name.clone(),
2354                source: source.into(),
2355            }
2356        })?;
2357    if connector.total_ids() > limits.max_local_columns {
2358        return Err(resource_limit(
2359            &module.name,
2360            "local ZX columns",
2361            connector.total_ids(),
2362            limits.max_local_columns,
2363        ));
2364    }
2365    let parent_ports = module
2366        .interface
2367        .quantum_ports
2368        .iter()
2369        .enumerate()
2370        .map(|(index, port)| {
2371            (
2372                connector
2373                    .node_at(port.position)
2374                    .expect("validated parent port")
2375                    .id,
2376                index,
2377            )
2378        })
2379        .collect::<HashMap<_, _>>();
2380    let seam_indices = seam_nodes
2381        .iter()
2382        .enumerate()
2383        .map(|(index, &node)| (node, index))
2384        .collect::<HashMap<_, _>>();
2385    // Single-wire Port wrappers already fit in six columns. Keeping their
2386    // binds together avoids paying for several tiny projections per definition.
2387    let connector_components = if connector.action_graph().ordered_nodes().next().is_some()
2388        || parent_width <= 2
2389            && fixed_body.block_count() == parent_width
2390            && binds.len() == parent_width
2391            && parent_width + 2 * binds.len() <= limits.max_frontier_width
2392            && fixed_body.blocks().all(|block| block.kind().is_port())
2393    {
2394        let nodes = (0..connector.nodes().len()).collect();
2395        vec![(connector, nodes)]
2396    } else {
2397        connector.into_connector_components()
2398    };
2399    // Each connector admits only the child relations on its own boundary.
2400    // Finished components stay separate until the public interface is assembled.
2401    for (connector, original_nodes) in connector_components {
2402        let connector_parents = original_nodes
2403            .iter()
2404            .filter_map(|node| parent_ports.get(node).copied())
2405            .collect::<Vec<_>>();
2406        let connector_binds = original_nodes
2407            .iter()
2408            .enumerate()
2409            .filter_map(|(local, original)| {
2410                seam_indices
2411                    .get(original)
2412                    .map(|&index| (&binds[index], local))
2413            })
2414            .collect::<Vec<_>>();
2415        let mut touched = connector_binds
2416            .iter()
2417            .map(|(bind, _)| owners[&bind.endpoint])
2418            .collect::<Vec<_>>();
2419        touched.sort_unstable();
2420        touched.dedup();
2421        let slot = touched.first().copied().unwrap_or_else(|| {
2422            relations.push(None);
2423            relations.len() - 1
2424        });
2425        let children_to_join = touched
2426            .iter()
2427            .map(|&owner| {
2428                relations[owner]
2429                    .take()
2430                    .expect("live endpoint has a relation")
2431            })
2432            .collect::<Vec<_>>();
2433        let mut joined = compose_parent_connector(
2434            module,
2435            children,
2436            children_to_join,
2437            connector,
2438            connector_parents,
2439            &connector_binds,
2440            &parent_protected,
2441            &parent_frontier,
2442            limits,
2443        )?;
2444        joined.retire_completed(&mut completed, &obligations, &module.name)?;
2445        for (bind, _) in &connector_binds {
2446            owners.remove(&bind.endpoint);
2447        }
2448        for endpoint in &joined.endpoints {
2449            owners.insert(endpoint.clone(), slot);
2450        }
2451        relations[slot] = Some(joined);
2452    }
2453    let mut combined = ChildRelation::default();
2454    for relation in relations.into_iter().flatten() {
2455        assert!(
2456            relation.endpoints.is_empty(),
2457            "all child endpoints are bound"
2458        );
2459        let mapping = relation.parent_ports.clone();
2460        combined.append(relation, &mapping, parent_width);
2461    }
2462    combined.append(completed, &[], parent_width);
2463    let ChildRelation {
2464        mut rows,
2465        mut logical_rows,
2466        mut certificate_rows,
2467        mut adjustments,
2468        mut measurements,
2469        mut discharged_measurements,
2470        mut protected,
2471        mut frontier,
2472        protected_groups,
2473        ..
2474    } = combined;
2475    merge_protected_supports(&mut protected, &parent_protected);
2476    frontier.extend(parent_frontier);
2477    frontier.sort_unstable_by_key(support_target_key);
2478    frontier.dedup();
2479    let retained = (0..parent_width).collect::<Vec<_>>();
2480    rows = compose_supported_rows(rows, &mut [], &[], &[], &[], &retained, &module.name)?;
2481    logical_rows = compose_supported_rows(
2482        logical_rows,
2483        &mut [],
2484        &[],
2485        &[],
2486        &[],
2487        &retained,
2488        &module.name,
2489    )?;
2490    certificate_rows = compose_certificate_rows(certificate_rows, &[], &retained);
2491    adjustments = compose_supported_rows(
2492        adjustments,
2493        &mut measurements,
2494        &protected,
2495        &frontier,
2496        &[],
2497        &retained,
2498        &module.name,
2499    )?;
2500    normalize_fixing_rows(
2501        &mut measurements,
2502        &adjustments,
2503        &protected,
2504        limits,
2505        &module.name,
2506    )?;
2507    normalize_measurement_rows(
2508        &mut measurements,
2509        &adjustments,
2510        &protected,
2511        &protected_groups,
2512        limits,
2513        &module.name,
2514    )?;
2515    let (newly_discharged, remaining) = measurements
2516        .into_iter()
2517        .partition(measurement_can_discharge);
2518    measurements = remaining;
2519    discharged_measurements.extend(newly_discharged);
2520    Ok(ModuleSummary {
2521        name: module.name.clone(),
2522        limits,
2523        dependencies: children
2524            .values()
2525            .map(|(_, summary)| (summary.name.clone(), Arc::clone(summary)))
2526            .collect(),
2527        ports: module.interface.quantum_ports.clone(),
2528        signatures,
2529        rows,
2530        logical_rows,
2531        certificate_rows,
2532        adjustments,
2533        measurements,
2534        discharged_measurements,
2535        protected,
2536        frontier,
2537        protected_groups,
2538        branch_variants: Vec::new(),
2539        projection: None,
2540    })
2541}
2542
2543#[expect(
2544    clippy::too_many_arguments,
2545    reason = "connector composition consumes independent certified inputs"
2546)]
2547fn compose_parent_connector(
2548    module: &BlockGraph,
2549    children: &HashMap<&str, (&ModuleInstance, Arc<ModuleSummary>)>,
2550    relations: Vec<ChildRelation>,
2551    connector: ZXGraph,
2552    connector_parents: Vec<usize>,
2553    binds: &[(&BindSeam, usize)],
2554    parent_protected: &[ProtectedSupport],
2555    parent_frontier: &[SupportTarget],
2556    limits: ModuleCertificationLimits,
2557) -> Result<ChildRelation, ModuleCertificationError> {
2558    let existing_parents = relations
2559        .iter()
2560        .map(|r| r.parent_ports.len())
2561        .sum::<usize>();
2562    let parent_width = existing_parents + connector_parents.len();
2563    let child_width = relations.iter().map(|r| r.endpoints.len()).sum::<usize>();
2564    let connector_start = parent_width + child_width;
2565    let width = connector_start + binds.len();
2566    ensure_composition_width(&module.name, width, limits.max_frontier_width)?;
2567
2568    let mut joined = ChildRelation::default();
2569    let mut next_parent = 0;
2570    let mut next_child = parent_width;
2571    for relation in relations {
2572        let parents = next_parent..next_parent + relation.parent_ports.len();
2573        let endpoints = next_child..next_child + relation.endpoints.len();
2574        next_parent = parents.end;
2575        next_child = endpoints.end;
2576        joined.append(
2577            relation,
2578            &parents.chain(endpoints).collect::<Vec<_>>(),
2579            width,
2580        );
2581    }
2582    joined
2583        .parent_ports
2584        .extend(connector_parents.iter().copied());
2585    let endpoint_columns = joined
2586        .endpoints
2587        .iter()
2588        .enumerate()
2589        .map(|(index, endpoint)| (endpoint, parent_width + index))
2590        .collect::<HashMap<_, _>>();
2591    let connector_columns = connector_parents
2592        .iter()
2593        .map(|&index| {
2594            connector
2595                .node_at(module.interface.quantum_ports[index].position)
2596                .expect("component contains its parent port")
2597                .id
2598        })
2599        .chain(binds.iter().map(|&(_, node)| node))
2600        .collect::<Vec<_>>();
2601    let table = connector
2602        .projected_external_table(
2603            &connector_columns,
2604            ProjectionLimits {
2605                max_frontier_width: limits.max_frontier_width,
2606                max_witness_nodes: limits.max_witness_nodes,
2607            },
2608        )
2609        .map_err(|error| projection_limit(&module.name, error))?;
2610    let seam_positions = binds
2611        .iter()
2612        .map(|&(_, node)| connector.nodes()[node].pos)
2613        .collect::<FxHashSet<_>>();
2614    let connector_rows = table
2615        .boundary_rows
2616        .iter()
2617        .map(|row| {
2618            let full = table.materialize(row);
2619            // The boundary row already carries the authoritative certificate phase.
2620            let stabilizer = connector.materialize_stabilizer_with_sign(full.paulis, false);
2621            let mut support = PositionedSupport::from_stabilizer(&stabilizer, &connector);
2622            support.strip_ports(&seam_positions, &[]);
2623            let mut witness = row.flow_witness.clone();
2624            witness.strip_positions(&seam_positions);
2625            SupportedRow {
2626                signed: row.signed.clone(),
2627                support,
2628                witness,
2629            }
2630        })
2631        .collect::<Vec<_>>();
2632    let connector_certificates =
2633        retained_certificate_rows(&connector, &table, &connector_rows, connector_columns.len());
2634    let mapping = (existing_parents..parent_width)
2635        .chain(connector_start..width)
2636        .collect::<Vec<_>>();
2637    // Parent actions own readouts just like leaf actions. Preserve their signed
2638    // witnesses while the connector's virtual Ports are composed with children.
2639    if connector.action_graph().ordered_nodes().next().is_some() {
2640        let stabilizers = connector
2641            .stabilizers_with_limits(limits)
2642            .map_err(|source| ModuleCertificationError::Runtime {
2643                module: module.name.clone(),
2644                source: source.into(),
2645            })?;
2646        let mut measurements = summarize_readouts(
2647            module.local_body(),
2648            &connector,
2649            &stabilizers,
2650            &table,
2651            &connector_columns,
2652        );
2653        joined.protected_groups.extend(semantic_protected_groups(
2654            module.local_body(),
2655            &measurements,
2656            &connector,
2657            limits,
2658            &module.name,
2659        )?);
2660        for measurement in &mut measurements {
2661            measurement.signed = embed_signed_row(&measurement.signed, &mapping, width);
2662            measurement.support.strip_ports(&seam_positions, &[]);
2663            measurement.witness.strip_positions(&seam_positions);
2664        }
2665        joined.measurements.extend(measurements);
2666    }
2667    joined
2668        .rows
2669        .extend(embed_rows(&connector_rows, &mapping, width));
2670    joined
2671        .logical_rows
2672        .extend(embed_rows(&connector_rows, &mapping, width));
2673    joined
2674        .certificate_rows
2675        .extend(embed_rows(&connector_certificates, &mapping, width));
2676    let mut adjustments = embed_rows(&connector_rows, &mapping, width);
2677    adjustments.append(&mut joined.adjustments);
2678    joined.adjustments = adjustments;
2679
2680    let seam_pairs = binds
2681        .iter()
2682        .enumerate()
2683        .map(|(index, &(bind, _))| {
2684            let port = summarized_port(children, &bind.endpoint);
2685            (
2686                endpoint_columns[&bind.endpoint],
2687                connector_start + index,
2688                bind.hadamard,
2689                bind.transpose,
2690                SupportSeam {
2691                    edge: (
2692                        bind.block,
2693                        exposed_position(port.instance, port.port, port.signature)
2694                            .expect("validated bind endpoint fits"),
2695                    ),
2696                    boundary_to_edge_hadamard: bind.hadamard,
2697                },
2698            )
2699        })
2700        .collect::<Vec<_>>();
2701    let bound = binds
2702        .iter()
2703        .map(|(bind, _)| &bind.endpoint)
2704        .collect::<HashSet<_>>();
2705    let retained = (0..parent_width)
2706        .chain(
2707            joined
2708                .endpoints
2709                .iter()
2710                .enumerate()
2711                .filter_map(|(index, endpoint)| {
2712                    (!bound.contains(endpoint)).then_some(parent_width + index)
2713                }),
2714        )
2715        .collect::<Vec<_>>();
2716    let mut protected = joined.protected.clone();
2717    merge_protected_supports(&mut protected, parent_protected);
2718    let mut frontier = joined.frontier.clone();
2719    frontier.extend_from_slice(parent_frontier);
2720    for rows in [&mut joined.rows, &mut joined.logical_rows] {
2721        *rows = compose_supported_rows(
2722            std::mem::take(rows),
2723            &mut [],
2724            &[],
2725            &[],
2726            &seam_pairs,
2727            &retained,
2728            &module.name,
2729        )?;
2730    }
2731    joined.certificate_rows =
2732        compose_certificate_rows(joined.certificate_rows, &seam_pairs, &retained);
2733    joined.adjustments = compose_supported_rows(
2734        joined.adjustments,
2735        &mut joined.measurements,
2736        &protected,
2737        &frontier,
2738        &seam_pairs,
2739        &retained,
2740        &module.name,
2741    )?;
2742    resize_discharged_boundaries(
2743        &mut joined.discharged_measurements,
2744        retained.len(),
2745        &module.name,
2746    )?;
2747    joined
2748        .endpoints
2749        .retain(|endpoint| !bound.contains(endpoint));
2750    Ok(joined)
2751}
2752
2753fn merge_protected_supports(protected: &mut Vec<ProtectedSupport>, added: &[ProtectedSupport]) {
2754    for constraint in added {
2755        if let Some(existing) = protected
2756            .iter_mut()
2757            .find(|existing| existing.target == constraint.target)
2758        {
2759            if existing.forbidden.is_none() {
2760                existing.forbidden = constraint.forbidden;
2761            }
2762        } else {
2763            protected.push(*constraint);
2764        }
2765    }
2766    protected.sort_unstable_by_key(|constraint| support_target_key(&constraint.target));
2767}
2768
2769fn resize_discharged_boundaries(
2770    measurements: &mut [SummaryMeasurement],
2771    width: usize,
2772    module: &str,
2773) -> Result<(), ModuleCertificationError> {
2774    for measurement in measurements {
2775        if !measurement.signed.paulis.is_identity() {
2776            return Err(invalid(
2777                module,
2778                &format!(
2779                    "discharged measurement '{}' retains boundary support",
2780                    measurement.name
2781                ),
2782            ));
2783        }
2784        measurement.signed.paulis = PauliString::new(width);
2785    }
2786    Ok(())
2787}
2788
2789fn normalize_fixing_rows(
2790    rows: &mut [SummaryMeasurement],
2791    adjustments: &[SupportedRow],
2792    protected: &[ProtectedSupport],
2793    limits: ModuleCertificationLimits,
2794    module: &str,
2795) -> Result<(), ModuleCertificationError> {
2796    let mut visited = 0;
2797    for row in rows.iter_mut().filter(|row| row.kind.is_selective_fixing()) {
2798        let own = row
2799            .kind
2800            .selective_fixing_targets()
2801            .iter()
2802            .map(|target| (SupportTarget::Node(target.pos), target.forbidden))
2803            .collect::<HashMap<_, _>>();
2804        let constraints = protected
2805            .iter()
2806            .flat_map(|constraint| {
2807                if own.contains_key(&constraint.target) {
2808                    vec![
2809                        (constraint.target, Pauli::X, false),
2810                        (constraint.target, Pauli::Z, false),
2811                    ]
2812                } else {
2813                    let support = row.support.get(constraint.target);
2814                    vec![
2815                        (constraint.target, Pauli::X, support & Pauli::X),
2816                        (constraint.target, Pauli::Z, support & Pauli::Z),
2817                    ]
2818                }
2819            })
2820            .collect::<Vec<_>>();
2821        let combination = MeasurementNormalization {
2822            row,
2823            adjustments,
2824            visited: &mut visited,
2825            limits,
2826            module,
2827        }
2828        .solve(&constraints)?
2829        .ok_or_else(|| {
2830            invalid(
2831                module,
2832                &format!(
2833                    "selective fixing '{}' cannot be decoupled after module composition",
2834                    row.name
2835                ),
2836            )
2837        })?;
2838        for index in combination {
2839            multiply_measurement(row, &adjustments[index]);
2840        }
2841        for (&target, &forbidden) in &own {
2842            if row.support.get(target) != forbidden {
2843                return Err(invalid(
2844                    module,
2845                    &format!("selective fixing '{}' lost its target", row.name),
2846                ));
2847            }
2848        }
2849        for constraint in protected {
2850            if !own.contains_key(&constraint.target)
2851                && row.support.get(constraint.target) != Pauli::I
2852            {
2853                return Err(invalid(
2854                    module,
2855                    &format!(
2856                        "selective fixing '{}' remains coupled after module composition",
2857                        row.name
2858                    ),
2859                ));
2860            }
2861        }
2862    }
2863    Ok(())
2864}
2865
2866enum NormalizationFactor<'a> {
2867    Group(&'a ProtectedGroup),
2868    Site(&'a ProtectedSupport),
2869}
2870
2871enum NormalizationPoint {
2872    Factor(usize),
2873    Partial {
2874        factor: usize,
2875        support: usize,
2876        start: usize,
2877    },
2878}
2879
2880enum NormalizationChoices<'a> {
2881    Site {
2882        target: SupportTarget,
2883        values: std::vec::IntoIter<Pauli>,
2884    },
2885    Group {
2886        group: &'a ProtectedGroup,
2887        current: Vec<Pauli>,
2888        permitted: bool,
2889        next: usize,
2890    },
2891    Partial {
2892        group: &'a ProtectedGroup,
2893        support: usize,
2894        start: usize,
2895        next: usize,
2896    },
2897}
2898
2899struct NormalizationFrame<'a> {
2900    factor: usize,
2901    constraints: usize,
2902    partial: usize,
2903    choices: NormalizationChoices<'a>,
2904}
2905
2906struct MeasurementNormalization<'a> {
2907    row: &'a SummaryMeasurement,
2908    adjustments: &'a [SupportedRow],
2909    visited: &'a mut usize,
2910    limits: ModuleCertificationLimits,
2911    module: &'a str,
2912}
2913
2914impl MeasurementNormalization<'_> {
2915    fn solve(
2916        &mut self,
2917        constraints: &[(SupportTarget, Pauli, bool)],
2918    ) -> Result<Option<Vec<usize>>, ModuleCertificationError> {
2919        let limit = self.limits.max_normalization_states;
2920        if *self.visited == limit {
2921            return Err(resource_limit(
2922                self.module,
2923                "measurement normalization states",
2924                self.visited.saturating_add(1),
2925                limit,
2926            ));
2927        }
2928        *self.visited += 1;
2929        let rows = self.adjustments.len();
2930        let columns = constraints.len();
2931        let bytes = rows.checked_mul(columns).and_then(|projection| {
2932            columns
2933                .checked_add(rows)?
2934                .checked_mul(columns.min(rows))?
2935                .checked_add(projection)?
2936                .checked_add(columns)?
2937                .checked_add(rows)
2938        });
2939        let words = bytes.map(|bytes| bytes.div_ceil(8));
2940        if words.is_none_or(|words| words > self.limits.max_matrix_words) {
2941            return Err(resource_limit(
2942                self.module,
2943                "dense matrix words",
2944                words.unwrap_or(usize::MAX),
2945                self.limits.max_matrix_words,
2946            ));
2947        }
2948        let projected = self
2949            .adjustments
2950            .iter()
2951            .map(|candidate| {
2952                constraints
2953                    .iter()
2954                    .map(|&(target, axis, _)| {
2955                        pauli_component_parity(candidate.support.get(target), axis)
2956                    })
2957                    .collect::<Vec<_>>()
2958            })
2959            .collect::<Vec<_>>();
2960        let target = constraints
2961            .iter()
2962            .map(|&(_, _, value)| value)
2963            .collect::<Vec<_>>();
2964        Ok(solve_binary_combination(&projected, &target))
2965    }
2966
2967    fn constrain(
2968        &self,
2969        constraints: &mut Vec<(SupportTarget, Pauli, bool)>,
2970        target: SupportTarget,
2971        desired: Pauli,
2972    ) {
2973        constraints.extend([Pauli::X, Pauli::Z].map(|axis| {
2974            (
2975                target,
2976                axis,
2977                (self.row.support.get(target) ^ desired) & axis,
2978            )
2979        }));
2980    }
2981
2982    fn search(
2983        &mut self,
2984        factors: &[NormalizationFactor<'_>],
2985        constraints: &mut Vec<(SupportTarget, Pauli, bool)>,
2986    ) -> Result<Option<Vec<usize>>, ModuleCertificationError> {
2987        let mut point = NormalizationPoint::Factor(0);
2988        let mut frames = Vec::<NormalizationFrame<'_>>::new();
2989        let mut partial = Vec::new();
2990        loop {
2991            let combination = self.solve(constraints)?;
2992            if combination.is_some() {
2993                let next = match point {
2994                    NormalizationPoint::Factor(index) => {
2995                        let Some(factor) = factors.get(index) else {
2996                            return Ok(combination);
2997                        };
2998                        let choices = match factor {
2999                            NormalizationFactor::Site(constraint) => {
3000                                let current = self.row.support.get(constraint.target);
3001                                let mut values = match constraint.forbidden {
3002                                    Some(forbidden) => [Pauli::I, Pauli::X, Pauli::Z, Pauli::Y]
3003                                        .into_iter()
3004                                        .filter(|&pauli| pauli != forbidden)
3005                                        .collect::<Vec<_>>(),
3006                                    None => vec![current],
3007                                };
3008                                values.sort_by_key(|&pauli| pauli != current);
3009                                NormalizationChoices::Site {
3010                                    target: constraint.target,
3011                                    values: values.into_iter(),
3012                                }
3013                            }
3014                            NormalizationFactor::Group(group) => {
3015                                let current = group
3016                                    .targets
3017                                    .iter()
3018                                    .map(|&target| self.row.support.get(target))
3019                                    .collect::<Vec<_>>();
3020                                let permitted = current.iter().all(|&pauli| pauli == Pauli::I)
3021                                    || group
3022                                        .permitted_support
3023                                        .iter()
3024                                        .any(|support| partial_support_matches(&current, support));
3025                                NormalizationChoices::Group {
3026                                    group,
3027                                    current,
3028                                    permitted,
3029                                    next: 0,
3030                                }
3031                            }
3032                        };
3033                        Some((index, choices))
3034                    }
3035                    NormalizationPoint::Partial {
3036                        factor,
3037                        support,
3038                        start,
3039                    } => {
3040                        let NormalizationFactor::Group(group) = factors[factor] else {
3041                            unreachable!("partial choices belong to a group")
3042                        };
3043                        let chosen = &partial[start..];
3044                        let template = &group.permitted_support[support];
3045                        let repeated = group.permitted_support[..support].iter().any(|earlier| {
3046                            partial_support_matches(chosen, earlier)
3047                                && template[chosen.len()..] == earlier[chosen.len()..]
3048                        });
3049                        if repeated {
3050                            None
3051                        } else if chosen.len() == template.len() {
3052                            if chosen.iter().any(|&pauli| pauli != Pauli::I)
3053                                && chosen
3054                                    .iter()
3055                                    .zip(&group.targets)
3056                                    .any(|(&pauli, &target)| pauli != self.row.support.get(target))
3057                            {
3058                                point = NormalizationPoint::Factor(factor + 1);
3059                                continue;
3060                            }
3061                            None
3062                        } else {
3063                            Some((
3064                                factor,
3065                                NormalizationChoices::Partial {
3066                                    group,
3067                                    support,
3068                                    start,
3069                                    next: 0,
3070                                },
3071                            ))
3072                        }
3073                    }
3074                };
3075                if let Some((factor, choices)) = next {
3076                    frames.push(NormalizationFrame {
3077                        factor,
3078                        constraints: constraints.len(),
3079                        partial: partial.len(),
3080                        choices,
3081                    });
3082                }
3083            }
3084            // Resume the deepest unfinished choice. Both factors and partial
3085            // supports share heap frames, so source width never grows the call stack.
3086            loop {
3087                let Some(frame) = frames.last_mut() else {
3088                    return Ok(None);
3089                };
3090                constraints.truncate(frame.constraints);
3091                partial.truncate(frame.partial);
3092                let next = match &mut frame.choices {
3093                    NormalizationChoices::Site { target, values } => values.next().map(|desired| {
3094                        self.constrain(constraints, *target, desired);
3095                        NormalizationPoint::Factor(frame.factor + 1)
3096                    }),
3097                    NormalizationChoices::Group {
3098                        group,
3099                        current,
3100                        permitted,
3101                        next,
3102                    } => {
3103                        let choice = *next;
3104                        *next += 1;
3105                        match choice {
3106                            0 => {
3107                                if !*permitted {
3108                                    continue;
3109                                }
3110                                for (&target, &desired) in group.targets.iter().zip(current.iter())
3111                                {
3112                                    self.constrain(constraints, target, desired);
3113                                }
3114                                Some(NormalizationPoint::Factor(frame.factor + 1))
3115                            }
3116                            1 => {
3117                                if current.iter().all(|&pauli| pauli == Pauli::I) {
3118                                    continue;
3119                                }
3120                                for &target in &group.targets {
3121                                    self.constrain(constraints, target, Pauli::I);
3122                                }
3123                                Some(NormalizationPoint::Factor(frame.factor + 1))
3124                            }
3125                            _ => group.permitted_support.get(choice - 2).map(|support| {
3126                                // A permitted cap is I or its basis: one affine
3127                                // equation prunes the entire remaining subtree.
3128                                constraints.extend(group.targets.iter().zip(support).map(
3129                                    |(&target, &basis)| {
3130                                        let axis = basis.flip();
3131                                        (
3132                                            target,
3133                                            axis,
3134                                            pauli_component_parity(
3135                                                self.row.support.get(target),
3136                                                axis,
3137                                            ),
3138                                        )
3139                                    },
3140                                ));
3141                                NormalizationPoint::Partial {
3142                                    factor: frame.factor,
3143                                    support: choice - 2,
3144                                    start: partial.len(),
3145                                }
3146                            }),
3147                        }
3148                    }
3149                    NormalizationChoices::Partial {
3150                        group,
3151                        support,
3152                        start,
3153                        next,
3154                    } => {
3155                        let column = partial.len() - *start;
3156                        let basis = group.permitted_support[*support][column];
3157                        let desired = match *next {
3158                            0 => Some(Pauli::I),
3159                            1 if basis != Pauli::I => Some(basis),
3160                            _ => None,
3161                        };
3162                        *next += 1;
3163                        desired.map(|desired| {
3164                            partial.push(desired);
3165                            self.constrain(constraints, group.targets[column], desired);
3166                            NormalizationPoint::Partial {
3167                                factor: frame.factor,
3168                                support: *support,
3169                                start: *start,
3170                            }
3171                        })
3172                    }
3173                };
3174                if let Some(next) = next {
3175                    point = next;
3176                    break;
3177                }
3178                frames.pop();
3179            }
3180        }
3181    }
3182}
3183
3184fn pauli_component_parity(pauli: Pauli, axes: Pauli) -> bool {
3185    ((pauli & Pauli::X) && (axes & Pauli::X)) ^ ((pauli & Pauli::Z) && (axes & Pauli::Z))
3186}
3187
3188fn partial_support_matches(partial: &[Pauli], support: &[Pauli]) -> bool {
3189    partial
3190        .iter()
3191        .zip(support)
3192        .all(|(&pauli, &basis)| pauli == Pauli::I || pauli == basis)
3193}
3194
3195fn normalize_measurement_rows(
3196    rows: &mut [SummaryMeasurement],
3197    adjustments: &[SupportedRow],
3198    protected: &[ProtectedSupport],
3199    protected_groups: &[ProtectedGroup],
3200    limits: ModuleCertificationLimits,
3201    module: &str,
3202) -> Result<(), ModuleCertificationError> {
3203    let mut visited = 0;
3204    for index in 0..rows.len() {
3205        if !matches!(rows[index].kind, StabilizerRowKind::Measurement { .. })
3206            || measurement_support_is_permitted(&rows[index], protected, protected_groups)
3207        {
3208            continue;
3209        }
3210
3211        let row = &rows[index];
3212        let grouped = protected_groups
3213            .iter()
3214            .flat_map(|group| group.targets.iter().copied())
3215            .collect::<FxHashSet<_>>();
3216        let choice_factors = protected_groups
3217            .iter()
3218            .map(NormalizationFactor::Group)
3219            .chain(
3220                protected
3221                    .iter()
3222                    .filter(|constraint| !grouped.contains(&constraint.target))
3223                    .map(NormalizationFactor::Site),
3224            )
3225            .collect::<Vec<_>>();
3226
3227        let mut invariants = vec![(row.target, Pauli::X), (row.target, Pauli::Z)];
3228        invariants.extend(
3229            row.self_readers
3230                .iter()
3231                .copied()
3232                .flat_map(|target| [(target, Pauli::X), (target, Pauli::Z)]),
3233        );
3234        invariants.extend(
3235            rows.iter()
3236                .enumerate()
3237                .filter(|(other, _)| *other != index)
3238                .flat_map(|(_, other)| {
3239                    other
3240                        .observable
3241                        .iter_xz()
3242                        .map(move |axis| (other.target, axis))
3243                }),
3244        );
3245
3246        let mut constraints = invariants
3247            .into_iter()
3248            .map(|(target, axis)| (target, axis, false))
3249            .collect();
3250        let combination = MeasurementNormalization {
3251            row,
3252            adjustments,
3253            visited: &mut visited,
3254            limits,
3255            module,
3256        }
3257        .search(&choice_factors, &mut constraints)?
3258        .ok_or_else(|| {
3259            invalid(
3260                module,
3261                &format!(
3262                    "measurement '{}' cannot normalize protected support after module composition",
3263                    row.name
3264                ),
3265            )
3266        })?;
3267        let row = &mut rows[index];
3268        for adjustment in combination {
3269            multiply_measurement(row, &adjustments[adjustment]);
3270        }
3271        if !measurement_support_is_permitted(row, protected, protected_groups) {
3272            return Err(invalid(
3273                module,
3274                &format!(
3275                    "measurement '{}' retains invalid protected support after module composition",
3276                    row.name
3277                ),
3278            ));
3279        }
3280    }
3281    Ok(())
3282}
3283
3284fn measurement_support_is_permitted(
3285    row: &SummaryMeasurement,
3286    protected: &[ProtectedSupport],
3287    groups: &[ProtectedGroup],
3288) -> bool {
3289    protected
3290        .iter()
3291        .all(|constraint| constraint.forbidden != Some(row.support.get(constraint.target)))
3292        && groups.iter().all(|group| {
3293            let support = group
3294                .targets
3295                .iter()
3296                .map(|&target| row.support.get(target))
3297                .collect::<Vec<_>>();
3298            support.iter().all(|&pauli| pauli == Pauli::I)
3299                || group
3300                    .permitted_support
3301                    .iter()
3302                    .any(|choice| partial_support_matches(&support, choice))
3303        })
3304}
3305
3306fn solve_binary_combination(rows: &[Vec<bool>], target: &[bool]) -> Option<Vec<usize>> {
3307    let mut basis = vec![None::<(Vec<bool>, Vec<bool>)>; target.len()];
3308    for (index, source) in rows.iter().enumerate() {
3309        let mut row = source.clone();
3310        let mut coeff = vec![false; rows.len()];
3311        coeff[index] = true;
3312        for column in 0..target.len() {
3313            if !row[column] {
3314                continue;
3315            }
3316            if let Some((pivot, pivot_coeff)) = &basis[column] {
3317                xor_bits(&mut row, pivot);
3318                xor_bits(&mut coeff, pivot_coeff);
3319            } else {
3320                basis[column] = Some((row, coeff));
3321                break;
3322            }
3323        }
3324    }
3325
3326    let mut residual = target.to_vec();
3327    let mut coeff = vec![false; rows.len()];
3328    for column in 0..target.len() {
3329        if !residual[column] {
3330            continue;
3331        }
3332        let (pivot, pivot_coeff) = basis[column].as_ref()?;
3333        xor_bits(&mut residual, pivot);
3334        xor_bits(&mut coeff, pivot_coeff);
3335    }
3336    residual.iter().all(|&bit| !bit).then(|| {
3337        coeff
3338            .iter()
3339            .enumerate()
3340            .filter_map(|(i, &set)| set.then_some(i))
3341            .collect()
3342    })
3343}
3344
3345fn xor_bits(left: &mut [bool], right: &[bool]) {
3346    for (left, &right) in left.iter_mut().zip(right) {
3347        *left ^= right;
3348    }
3349}
3350
3351/// Rebases one leaf's rows into the parent: drop the support that sat on the
3352/// instance's own ports (the seam the parent now owns), then rotate and
3353/// translate what remains. Mirrors [`instantiate_measurements`] for the four
3354/// `SupportedRow` lists a summary carries.
3355fn instantiate_rows(
3356    rows: &[SupportedRow],
3357    instance: &ModuleInstance,
3358    port_positions: &FxHashSet<IVec3>,
3359    retained_targets: &[SupportTarget],
3360    module: &str,
3361) -> Result<Vec<SupportedRow>, ModuleCertificationError> {
3362    let shift = |source| ModuleCertificationError::Graph {
3363        module: module.to_string(),
3364        source,
3365    };
3366    let orientation = instance.orientation();
3367    rows.iter()
3368        .map(|row| {
3369            let mut row = row.clone();
3370            row.support.strip_ports(port_positions, retained_targets);
3371            row.witness.strip_positions(port_positions);
3372            row.witness = row
3373                .witness
3374                .transformed(orientation, instance.translation)
3375                .map_err(shift)?;
3376            row.support = row
3377                .support
3378                .transformed(orientation, instance.translation)
3379                .map_err(shift)?;
3380            Ok(row)
3381        })
3382        .collect()
3383}
3384
3385fn instantiate_measurements(
3386    measurements: &[SummaryMeasurement],
3387    instance: &ModuleInstance,
3388    port_positions: &[IVec3],
3389    retained_targets: &[SupportTarget],
3390    module: &str,
3391) -> Result<Vec<SummaryMeasurement>, ModuleCertificationError> {
3392    let port_position_set = port_positions.iter().copied().collect::<FxHashSet<_>>();
3393    let orientation = instance.orientation();
3394    let graph_error = |source| ModuleCertificationError::Graph {
3395        module: module.to_string(),
3396        source,
3397    };
3398    measurements
3399        .iter()
3400        .map(|measurement| {
3401            let mut measurement = measurement.clone();
3402            measurement.name = format!("{}__{}", instance.name, measurement.name);
3403            match &mut measurement.kind {
3404                StabilizerRowKind::Measurement { name } => {
3405                    *name = measurement.name.clone();
3406                }
3407                StabilizerRowKind::SelectiveFixing { targets } => {
3408                    for target in targets {
3409                        target.pos = instance
3410                            .try_transform_position(target.pos)
3411                            .map_err(graph_error)?;
3412                    }
3413                }
3414                StabilizerRowKind::Logical => {}
3415            }
3416            measurement
3417                .support
3418                .strip_ports(&port_position_set, retained_targets);
3419            measurement.witness.strip_positions(&port_position_set);
3420            measurement.witness = measurement
3421                .witness
3422                .transformed(orientation, instance.translation)
3423                .map_err(graph_error)?;
3424            measurement.support = measurement
3425                .support
3426                .transformed(orientation, instance.translation)
3427                .map_err(graph_error)?;
3428            measurement.target = measurement
3429                .target
3430                .transformed(orientation, instance.translation)
3431                .map_err(graph_error)?;
3432            measurement.self_readers = measurement
3433                .self_readers
3434                .iter()
3435                .map(|&target| {
3436                    target
3437                        .transformed(orientation, instance.translation)
3438                        .map_err(graph_error)
3439                })
3440                .collect::<Result<Vec<_>, ModuleCertificationError>>()?;
3441            measurement.owned_positions = measurement
3442                .owned_positions
3443                .iter()
3444                .map(|&position| {
3445                    orientation
3446                        .try_transform_position(position, instance.translation)
3447                        .map_err(graph_error)
3448                })
3449                .collect::<Result<FxHashSet<_>, ModuleCertificationError>>()?;
3450            Ok(measurement)
3451        })
3452        .collect()
3453}
3454
3455fn validate_composite_geometry(
3456    program: &BlockGraph,
3457    module: &BlockGraph,
3458) -> Result<(), ModuleCertificationError> {
3459    let mut footprint = CompositeFootprint::default();
3460    let mut next_branch = 0;
3461    add_module_footprint(
3462        program,
3463        module,
3464        (ModuleOrientation::IDENTITY, IVec3::ZERO),
3465        "",
3466        true,
3467        &mut footprint,
3468        &mut next_branch,
3469    )
3470    .map_err(|source| ModuleCertificationError::Graph {
3471        module: module.name.clone(),
3472        source,
3473    })
3474}
3475
3476struct FootprintOrigin {
3477    definition: String,
3478    instance_path: String,
3479    orientation: ModuleOrientation,
3480}
3481
3482#[derive(Clone)]
3483struct FootprintBlock {
3484    position: IVec3,
3485    kind: BlockKind,
3486    branch: Option<usize>,
3487    origin: Arc<FootprintOrigin>,
3488    local_position: IVec3,
3489}
3490
3491impl FootprintBlock {
3492    fn materialized_site(&self) -> Arc<crate::MaterializedModuleSite> {
3493        Arc::new(crate::MaterializedModuleSite {
3494            definition: self.origin.definition.clone(),
3495            instance_path: self.origin.instance_path.clone(),
3496            local_position: self.local_position,
3497            orientation: self.origin.orientation,
3498        })
3499    }
3500}
3501
3502#[derive(Default)]
3503struct CompositeFootprint {
3504    occupied: HashMap<IVec3, Vec<FootprintBlock>>,
3505}
3506
3507impl CompositeFootprint {
3508    fn add(
3509        &mut self,
3510        block: Block,
3511        branch: Option<usize>,
3512        origin: &Arc<FootprintOrigin>,
3513        local_position: IVec3,
3514    ) -> Result<(), crate::BlockGraphError> {
3515        let candidate = FootprintBlock {
3516            position: block.pos(),
3517            kind: block.kind(),
3518            branch,
3519            origin: Arc::clone(origin),
3520            local_position,
3521        };
3522        if let Some(other) = self
3523            .occupied
3524            .get(&block.pos())
3525            .into_iter()
3526            .flatten()
3527            .find(|other| {
3528                other.position == block.pos() && !mutually_exclusive(branch, other.branch)
3529            })
3530        {
3531            return Err(crate::BlockGraphError::ModuleBlockOverlap {
3532                position: block.pos(),
3533                first: other.materialized_site(),
3534                second: candidate.materialized_site(),
3535            });
3536        }
3537        let positions = block.checked_reserved_positions()?;
3538        for &position in &positions {
3539            if let Some(other) = self
3540                .occupied
3541                .get(&position)
3542                .into_iter()
3543                .flatten()
3544                .find(|other| {
3545                    !mutually_exclusive(branch, other.branch)
3546                        && !candidate.kind.allows_reserved_overlap(
3547                            candidate.position,
3548                            other.kind,
3549                            other.position,
3550                            position,
3551                        )
3552                })
3553            {
3554                return Err(crate::BlockGraphError::ModuleBlockOverlap {
3555                    position,
3556                    first: other.materialized_site(),
3557                    second: candidate.materialized_site(),
3558                });
3559            }
3560        }
3561        for position in positions {
3562            self.occupied
3563                .entry(position)
3564                .or_default()
3565                .push(candidate.clone());
3566        }
3567        Ok(())
3568    }
3569}
3570
3571fn mutually_exclusive(left: Option<usize>, right: Option<usize>) -> bool {
3572    left.is_some() && left == right
3573}
3574
3575fn add_module_footprint(
3576    program: &BlockGraph,
3577    definition: &BlockGraph,
3578    transform: (ModuleOrientation, IVec3),
3579    instance_path: &str,
3580    include_ports: bool,
3581    footprint: &mut CompositeFootprint,
3582    next_branch: &mut usize,
3583) -> Result<(), crate::BlockGraphError> {
3584    let definitions = program
3585        .modules()
3586        .map(|module| (module.name.as_str(), module))
3587        .collect::<HashMap<_, _>>();
3588    let mut pending = vec![(
3589        definition,
3590        transform,
3591        instance_path.to_string(),
3592        include_ports,
3593    )];
3594    while let Some((definition, (orientation, translation), instance_path, include_ports)) =
3595        pending.pop()
3596    {
3597        let origin = Arc::new(FootprintOrigin {
3598            definition: definition.name.clone(),
3599            instance_path: instance_path.to_string(),
3600            orientation,
3601        });
3602        definition
3603            .copy_local_geometry()
3604            .with_orientation_lenient(orientation)?;
3605        let regions = definition.local_body().branch_regions()?;
3606        let shown = regions
3607            .iter()
3608            .flat_map(|region| region.shown_arm().blocks().map(Block::pos))
3609            .collect::<FxHashSet<_>>();
3610        for block in definition
3611            .local_body()
3612            .blocks()
3613            .filter(|block| !shown.contains(&block.pos()))
3614            .filter(|block| include_ports || !block.kind().is_port())
3615        {
3616            footprint.add(
3617                crate::graph::oriented_block(block, orientation)?.try_with_shift(translation)?,
3618                None,
3619                &origin,
3620                block.pos(),
3621            )?;
3622        }
3623        for region in regions {
3624            let branch = *next_branch;
3625            *next_branch += 1;
3626            for block in region.on_false().blocks().chain(region.on_true().blocks()) {
3627                footprint.add(
3628                    crate::graph::oriented_block(block, orientation)?
3629                        .try_with_shift(translation)?,
3630                    Some(branch),
3631                    &origin,
3632                    block.pos(),
3633                )?;
3634            }
3635        }
3636        for instance in definition.instances.iter().rev() {
3637            let child_translation =
3638                orientation.try_transform_position(instance.translation, translation)?;
3639            let child_orientation = orientation.then(instance.rotation);
3640            let child_path = qualified_name(&instance_path, &instance.name);
3641            pending.push((
3642                definitions[instance.definition.as_str()],
3643                (child_orientation, child_translation),
3644                child_path,
3645                false,
3646            ));
3647        }
3648    }
3649    Ok(())
3650}
3651
3652fn bind_seam(
3653    endpoint: &InstancePort,
3654    block: IVec3,
3655    hadamard: bool,
3656    transpose: bool,
3657    children: &HashMap<&str, (&ModuleInstance, Arc<ModuleSummary>)>,
3658) -> BindSeam {
3659    let mut signature = summarized_port(children, endpoint).signature;
3660    signature.hadamard ^= hadamard;
3661    BindSeam {
3662        endpoint: endpoint.clone(),
3663        block,
3664        signature,
3665        hadamard,
3666        transpose,
3667    }
3668}
3669
3670fn geometry_bind_seam(
3671    endpoint: &InstancePort,
3672    block: IVec3,
3673    hadamard: bool,
3674    transpose: bool,
3675    children: &HashMap<&str, (&ModuleInstance, ModuleGeometry)>,
3676) -> BindSeam {
3677    let mut signature = validated_port(children, endpoint).signature;
3678    signature.hadamard ^= hadamard;
3679    BindSeam {
3680        endpoint: endpoint.clone(),
3681        block,
3682        signature,
3683        hadamard,
3684        transpose,
3685    }
3686}
3687
3688fn geometry_direct_seam(
3689    output: &InstancePort,
3690    input: &InstancePort,
3691    hadamard: bool,
3692    children: &HashMap<&str, (&ModuleInstance, ModuleGeometry)>,
3693    module: &str,
3694) -> Result<bool, ModuleCertificationError> {
3695    direct_seam_hadamard_parts(
3696        validated_port(children, output),
3697        validated_port(children, input),
3698        hadamard,
3699        module,
3700    )
3701}
3702
3703fn direct_seam_hadamard(
3704    output: &InstancePort,
3705    input: &InstancePort,
3706    hadamard: bool,
3707    children: &HashMap<&str, (&ModuleInstance, Arc<ModuleSummary>)>,
3708    module: &str,
3709) -> Result<bool, ModuleCertificationError> {
3710    direct_seam_hadamard_parts(
3711        summarized_port(children, output),
3712        summarized_port(children, input),
3713        hadamard,
3714        module,
3715    )
3716}
3717
3718fn direct_seam_hadamard_parts(
3719    output: PortGeometry<'_>,
3720    input: PortGeometry<'_>,
3721    hadamard: bool,
3722    module: &str,
3723) -> Result<bool, ModuleCertificationError> {
3724    let output_pos = exposed_position(output.instance, output.port, output.signature)?;
3725    let input_pos = exposed_position(input.instance, input.port, input.signature)?;
3726    let direction = Direction::iter()
3727        .find(|direction| {
3728            checked_add_position(output_pos, direction.to_ivec3()).ok() == Some(input_pos)
3729        })
3730        .ok_or_else(|| invalid(module, "direct pipe endpoints are not adjacent"))?;
3731    if direction != output.signature.direction.negate() || direction != input.signature.direction {
3732        return Err(invalid(
3733            module,
3734            "direct pipe faces point in different directions",
3735        ));
3736    }
3737    if !compatible_bases(
3738        output.signature.interior_bases,
3739        input.signature.interior_bases,
3740        direction.as_udirection(),
3741        hadamard,
3742    ) {
3743        return Err(invalid(module, "direct pipe face bases are incompatible"));
3744    }
3745    Ok(output.signature.hadamard ^ hadamard ^ input.signature.hadamard)
3746}
3747
3748fn compose_child_seam(
3749    (output, input): (&InstancePort, &InstancePort),
3750    hadamard: bool,
3751    support_seam: SupportSeam,
3752    relations: &mut [Option<ChildRelation>],
3753    owners: &mut HashMap<InstancePort, usize>,
3754    limit: usize,
3755    module: &str,
3756) -> Result<(), ModuleCertificationError> {
3757    let output_owner = owners[output];
3758    let input_owner = owners[input];
3759    let width = relations[output_owner]
3760        .as_ref()
3761        .expect("live endpoint has a relation")
3762        .endpoints
3763        .len()
3764        + if input_owner == output_owner {
3765            0
3766        } else {
3767            relations[input_owner]
3768                .as_ref()
3769                .expect("live endpoint has a relation")
3770                .endpoints
3771                .len()
3772        };
3773    ensure_composition_width(module, width, limit)?;
3774
3775    let mut relation = relations[output_owner]
3776        .take()
3777        .expect("live endpoint has a relation");
3778    if input_owner != output_owner {
3779        let input_relation = relations[input_owner]
3780            .take()
3781            .expect("live endpoint has a relation");
3782        let output_width = relation.width();
3783        let mut combined = ChildRelation::default();
3784        combined.append(relation, &(0..output_width).collect::<Vec<_>>(), width);
3785        combined.append(
3786            input_relation,
3787            &(output_width..width).collect::<Vec<_>>(),
3788            width,
3789        );
3790        relation = combined;
3791    }
3792
3793    let left = relation
3794        .endpoints
3795        .iter()
3796        .position(|endpoint| endpoint == output)
3797        .expect("output endpoint belongs to its relation");
3798    let right = relation
3799        .endpoints
3800        .iter()
3801        .position(|endpoint| endpoint == input)
3802        .expect("input endpoint belongs to its relation");
3803    let retained = (0..width)
3804        .filter(|&column| column != left && column != right)
3805        .collect::<Vec<_>>();
3806    let seam = [(left, right, hadamard, true, support_seam)];
3807    for rows in [&mut relation.rows, &mut relation.logical_rows] {
3808        *rows = compose_supported_rows(
3809            std::mem::take(rows),
3810            &mut [],
3811            &[],
3812            &[],
3813            &seam,
3814            &retained,
3815            module,
3816        )?;
3817    }
3818    relation.certificate_rows =
3819        compose_certificate_rows(relation.certificate_rows, &seam, &retained);
3820    relation.adjustments = compose_supported_rows(
3821        relation.adjustments,
3822        &mut relation.measurements,
3823        &relation.protected,
3824        &relation.frontier,
3825        &seam,
3826        &retained,
3827        module,
3828    )?;
3829    for measurement in relation.discharged_measurements.iter_mut() {
3830        debug_assert!(measurement.signed.paulis.is_identity());
3831        measurement.signed.paulis = PauliString::new(retained.len());
3832    }
3833    relation
3834        .endpoints
3835        .retain(|endpoint| endpoint != output && endpoint != input);
3836
3837    owners.remove(output);
3838    owners.remove(input);
3839    for endpoint in &relation.endpoints {
3840        owners.insert(endpoint.clone(), output_owner);
3841    }
3842    relations[output_owner] = Some(relation);
3843    Ok(())
3844}
3845
3846fn ensure_composition_width(
3847    module: &str,
3848    width: usize,
3849    limit: usize,
3850) -> Result<(), ModuleCertificationError> {
3851    if width <= limit {
3852        Ok(())
3853    } else {
3854        Err(resource_limit(module, "composition columns", width, limit))
3855    }
3856}
3857
3858fn summarized_port<'a>(
3859    children: &'a HashMap<&str, (&ModuleInstance, Arc<ModuleSummary>)>,
3860    endpoint: &InstancePort,
3861) -> PortGeometry<'a> {
3862    let (instance, summary) = children
3863        .get(endpoint.instance.as_str())
3864        .map(|(instance, summary)| (*instance, summary.as_ref()))
3865        .expect("program validation resolved the child instance");
3866    let index = summary
3867        .port_index(&endpoint.port)
3868        .expect("program validation resolved the child port");
3869    PortGeometry {
3870        instance,
3871        port: &summary.ports[index],
3872        signature: summary.signatures[index].with_orientation(instance.orientation()),
3873    }
3874}
3875
3876fn validated_port<'a>(
3877    children: &'a HashMap<&str, (&ModuleInstance, ModuleGeometry)>,
3878    endpoint: &InstancePort,
3879) -> PortGeometry<'a> {
3880    let (instance, geometry) = children
3881        .get(endpoint.instance.as_str())
3882        .map(|(instance, geometry)| (*instance, geometry))
3883        .expect("program validation resolved the child instance");
3884    let index = geometry
3885        .ports
3886        .iter()
3887        .position(|port| port.name == endpoint.port)
3888        .expect("program validation resolved the child port");
3889    PortGeometry {
3890        instance,
3891        port: &geometry.ports[index],
3892        signature: geometry.signatures[index].with_orientation(instance.orientation()),
3893    }
3894}
3895
3896fn exposed_position(
3897    instance: &ModuleInstance,
3898    port: &QuantumPort,
3899    signature: ModulePortSignature,
3900) -> Result<IVec3, ModuleCertificationError> {
3901    instance
3902        .try_transform_position(port.position)
3903        .and_then(|position| checked_add_position(position, signature.direction.to_ivec3()))
3904        .map_err(|error| ModuleCertificationError::Graph {
3905            module: instance.name.clone(),
3906            source: error,
3907        })
3908}
3909
3910fn validate_bind_faces(
3911    module: &BlockGraph,
3912    binds: &[BindSeam],
3913) -> Result<(), ModuleCertificationError> {
3914    let mut used = FxHashSet::default();
3915    for bind in binds {
3916        let neighbor = checked_add_position(bind.block, bind.signature.direction.to_ivec3())
3917            .map_err(|source| ModuleCertificationError::Graph {
3918                module: module.name.clone(),
3919                source,
3920            })?;
3921        if module.local_body().has_pipe_between(bind.block, neighbor) {
3922            return Err(invalid(&module.name, "bind reuses an authored pipe face"));
3923        }
3924        if !used.insert((bind.block, bind.signature.direction)) {
3925            return Err(invalid(&module.name, "two binds reuse one block face"));
3926        }
3927    }
3928    Ok(())
3929}
3930
3931fn validate_bind_bases(
3932    module: &BlockGraph,
3933    body: &BlockGraph,
3934    binds: &[BindSeam],
3935) -> Result<(), ModuleCertificationError> {
3936    for bind in binds {
3937        let mut pipe = Pipe::new(bind.block, bind.signature.direction);
3938        if bind.signature.hadamard {
3939            pipe = pipe.with_hadamard();
3940        }
3941        let parent_bases = body.infer_pipe_endpoint_face_bases(&pipe, bind.block);
3942        if !compatible_bases(
3943            parent_bases,
3944            bind.signature.interior_bases,
3945            bind.signature.direction.as_udirection(),
3946            bind.signature.hadamard,
3947        ) {
3948            return Err(invalid(&module.name, "bind face bases are incompatible"));
3949        }
3950    }
3951    Ok(())
3952}
3953
3954fn parent_signatures(
3955    module: &BlockGraph,
3956    body: &BlockGraph,
3957    binds: &[BindSeam],
3958) -> Result<Vec<ModulePortSignature>, ModuleCertificationError> {
3959    module
3960        .interface
3961        .quantum_ports
3962        .iter()
3963        .map(|port| {
3964            let local = module.local_body().neighbor_positions(port.position);
3965            let bound = binds
3966                .iter()
3967                .filter(|bind| bind.block == port.position)
3968                .collect::<Vec<_>>();
3969            match (local.as_slice(), bound.as_slice()) {
3970                ([_], []) => port_signature(&module.name, body, port.position),
3971                ([], [bind]) => Ok(bind.signature),
3972                _ => Err(invalid(
3973                    &module.name,
3974                    "each exported Port must have one local or bound pipe",
3975                )),
3976            }
3977        })
3978        .collect()
3979}
3980
3981fn port_signature(
3982    module: &str,
3983    body: &BlockGraph,
3984    position: IVec3,
3985) -> Result<ModulePortSignature, ModuleCertificationError> {
3986    let neighbors = body.neighbor_positions(position);
3987    let [neighbor] = neighbors.as_slice() else {
3988        return Err(invalid(module, "module Port must have one pipe"));
3989    };
3990    let pipe = body
3991        .get_pipe(position, *neighbor)
3992        .expect("neighbor position names the incident pipe");
3993    let direction = if pipe.src() == position {
3994        pipe.dir()
3995    } else {
3996        pipe.dir().negate()
3997    };
3998    Ok(ModulePortSignature {
3999        direction,
4000        hadamard: pipe.is_hadamard(),
4001        interior_bases: body.infer_pipe_endpoint_face_bases(pipe, *neighbor),
4002    })
4003}
4004
4005fn compatible_bases(
4006    left: [Option<Basis>; 3],
4007    right: [Option<Basis>; 3],
4008    pipe_axis: UDirection,
4009    hadamard: bool,
4010) -> bool {
4011    (0..3)
4012        .filter(|&axis| axis != pipe_axis.index())
4013        .all(|axis| {
4014            !matches!(
4015                (left[axis], right[axis]),
4016                (Some(left), Some(right)) if (left != right) ^ hadamard
4017            )
4018        })
4019}
4020
4021fn embed_rows(rows: &[SupportedRow], mapping: &[usize], width: usize) -> Vec<SupportedRow> {
4022    rows.iter()
4023        .map(|row| SupportedRow {
4024            signed: embed_signed_row(&row.signed, mapping, width),
4025            support: row.support.clone(),
4026            witness: row.witness.clone(),
4027        })
4028        .collect()
4029}
4030
4031fn embed_signed_row(row: &PhasedPauliString, mapping: &[usize], width: usize) -> PhasedPauliString {
4032    PhasedPauliString::new(
4033        PauliString::from_terms(
4034            width,
4035            mapping
4036                .iter()
4037                .enumerate()
4038                .map(|(source, &target)| (target, row.paulis.get(source))),
4039        ),
4040        row.phase(),
4041    )
4042}
4043
4044struct FrontierRow {
4045    order: usize,
4046    row: SupportedRow,
4047}
4048
4049fn remap_row_columns(
4050    row: &mut SupportedRow,
4051    source_columns: Option<&[usize]>,
4052    target_columns: &[usize],
4053) {
4054    // Pending rows still use global columns; active rows use `source_columns`.
4055    row.signed.paulis = PauliString::from_terms(
4056        target_columns.len(),
4057        row.signed
4058            .paulis
4059            .iter_support()
4060            .filter_map(|(source, pauli)| {
4061                let source = source_columns.map_or(source, |columns| columns[source]);
4062                target_columns
4063                    .binary_search(&source)
4064                    .ok()
4065                    .map(|target| (target, pauli))
4066            }),
4067    );
4068}
4069
4070fn eliminate_frontier_seam(rows: &mut Vec<FrontierRow>, left: usize, right: usize) {
4071    let mut solved = 0;
4072    for axis in [Pauli::X, Pauli::Z] {
4073        let mismatch = |row: &FrontierRow| {
4074            (row.row.signed.paulis.get(left) ^ row.row.signed.paulis.get(right)) & axis
4075        };
4076        let Some(pivot) = (solved..rows.len()).find(|&row| mismatch(&rows[row])) else {
4077            continue;
4078        };
4079        rows.swap(pivot, solved);
4080        let (before, pivot_and_after) = rows.split_at_mut(solved);
4081        let (pivot, after) = pivot_and_after
4082            .split_first_mut()
4083            .expect("solved pivot is in bounds");
4084        let last_use = after
4085            .iter()
4086            .rposition(mismatch)
4087            .map(|index| before.len() + index);
4088        for (index, row) in before.iter_mut().chain(after).enumerate() {
4089            if mismatch(row) {
4090                // This pivot is discarded. Its final surviving user can keep
4091                // the larger support and witness buffers. These payloads commute;
4092                // signed Pauli multiplication must retain its original order.
4093                if Some(index) == last_use {
4094                    if row.row.support.weight() < pivot.row.support.weight() {
4095                        std::mem::swap(&mut row.row.support, &mut pivot.row.support);
4096                    }
4097                    if row.row.witness.source_count() < pivot.row.witness.source_count() {
4098                        std::mem::swap(&mut row.row.witness, &mut pivot.row.witness);
4099                    }
4100                }
4101                EliminationRow::multiply_assign(&mut row.row, &pivot.row);
4102            }
4103        }
4104        solved += 1;
4105    }
4106    rows.drain(..solved);
4107}
4108
4109/// Contracts a measurement-free table without admitting future rows or
4110/// columns. Rows whose last seam closes keep their support/witness here, then
4111/// rejoin only for the caller's final canonical reduction.
4112fn compose_frontier_rows(
4113    rows: Vec<SupportedRow>,
4114    seams: &[(usize, usize, bool, bool, SupportSeam)],
4115    retained: &[usize],
4116    keep_closed: impl Fn(&SupportedRow) -> bool,
4117) -> Vec<SupportedRow> {
4118    let Some(width) = rows.first().map(|row| row.signed.paulis.len()) else {
4119        return rows;
4120    };
4121    let mut seam_stage = vec![None; width];
4122    for (stage, &(left, right, ..)) in seams.iter().enumerate() {
4123        debug_assert!(seam_stage[left].is_none());
4124        debug_assert!(seam_stage[right].is_none());
4125        seam_stage[left] = Some(stage);
4126        seam_stage[right] = Some(stage);
4127    }
4128
4129    let mut pending = (0..seams.len())
4130        .map(|_| Vec::<FrontierRow>::new())
4131        .collect::<Vec<_>>();
4132    let mut finished = Vec::new();
4133    for (order, row) in rows.into_iter().enumerate() {
4134        let first_stage = row
4135            .signed
4136            .paulis
4137            .iter_support()
4138            .filter_map(|(column, _)| seam_stage[column])
4139            .min();
4140        let mut row = FrontierRow { order, row };
4141        if let Some(stage) = first_stage {
4142            pending[stage].push(row);
4143        } else {
4144            remap_row_columns(&mut row.row, None, retained);
4145            if !row.row.signed.paulis.is_identity() || keep_closed(&row.row) {
4146                finished.push(row);
4147            }
4148        }
4149    }
4150
4151    let mut active = Vec::<FrontierRow>::new();
4152    let mut columns = retained.to_vec();
4153    for (stage, &(left, right, hadamard, transpose, support_seam)) in seams.iter().enumerate() {
4154        let mut next_columns = retained.to_vec();
4155        next_columns.extend(active.iter().flat_map(|row| {
4156            row.row
4157                .signed
4158                .paulis
4159                .iter_support()
4160                .map(|(column, _)| columns[column])
4161        }));
4162        next_columns.extend(pending[stage].iter().flat_map(|row| {
4163            row.row
4164                .signed
4165                .paulis
4166                .iter_support()
4167                .map(|(column, _)| column)
4168        }));
4169        next_columns.extend([left, right]);
4170        next_columns.sort_unstable();
4171        next_columns.dedup();
4172
4173        for row in &mut active {
4174            remap_row_columns(&mut row.row, Some(&columns), &next_columns);
4175        }
4176        for row in &mut pending[stage] {
4177            remap_row_columns(&mut row.row, None, &next_columns);
4178        }
4179        active.append(&mut pending[stage]);
4180        active.sort_unstable_by_key(|row| row.order);
4181        columns = next_columns;
4182
4183        let left = columns
4184            .binary_search(&left)
4185            .expect("live frontier contains the seam's left column");
4186        let right = columns
4187            .binary_search(&right)
4188            .expect("live frontier contains the seam's right column");
4189        if hadamard {
4190            for row in &mut active {
4191                conjugate_supported_h(&mut row.row, right);
4192            }
4193        }
4194        eliminate_frontier_seam(&mut active, left, right);
4195        for row in &mut active {
4196            contract_supported_row(&mut row.row, left, right, transpose, support_seam);
4197        }
4198
4199        let mut next_active = Vec::with_capacity(active.len());
4200        for mut row in active.drain(..) {
4201            let reaches_future = row.row.signed.paulis.iter_support().any(|(column, _)| {
4202                seam_stage[columns[column]].is_some_and(|row_stage| row_stage > stage)
4203            });
4204            if reaches_future {
4205                next_active.push(row);
4206            } else {
4207                remap_row_columns(&mut row.row, Some(&columns), retained);
4208                if !row.row.signed.paulis.is_identity() || keep_closed(&row.row) {
4209                    finished.push(row);
4210                }
4211            }
4212        }
4213        active = next_active;
4214    }
4215    debug_assert!(active.is_empty());
4216    debug_assert!(pending.iter().all(Vec::is_empty));
4217
4218    finished.sort_unstable_by_key(|row| row.order);
4219    finished.into_iter().map(|row| row.row).collect()
4220}
4221
4222fn compose_supported_rows(
4223    mut rows: Vec<SupportedRow>,
4224    measurements: &mut [SummaryMeasurement],
4225    protected: &[ProtectedSupport],
4226    frontier: &[SupportTarget],
4227    seams: &[(usize, usize, bool, bool, SupportSeam)],
4228    retained: &[usize],
4229    module: &str,
4230) -> Result<Vec<SupportedRow>, ModuleCertificationError> {
4231    if measurements.is_empty() && seams.len() > 1 {
4232        rows = compose_frontier_rows(rows, seams, retained, |row| {
4233            protected
4234                .iter()
4235                .any(|constraint| row.support.get(constraint.target) != Pauli::I)
4236                || frontier
4237                    .iter()
4238                    .any(|&target| row.support.get(target) != Pauli::I)
4239        });
4240    } else {
4241        for &(left, right, hadamard, transpose, support_seam) in seams {
4242            if hadamard {
4243                for row in &mut rows {
4244                    conjugate_supported_h(row, right);
4245                }
4246                for measurement in &mut *measurements {
4247                    conjugate_measurement_h(measurement, right);
4248                }
4249            }
4250
4251            if !measurements.is_empty() {
4252                let mut adjustment_basis = AdjustmentBasis::new(&rows, measurements, protected);
4253                for index in 0..measurements.len() {
4254                    let mut candidates = safe_adjustments(
4255                        &mut adjustment_basis,
4256                        measurements,
4257                        index,
4258                        protected,
4259                        module,
4260                    )?;
4261                    let measurement = &mut measurements[index];
4262                    eliminate_supported_seam(
4263                        &mut candidates,
4264                        std::slice::from_mut(measurement),
4265                        left,
4266                        right,
4267                    );
4268                    if measurement.signed.paulis.get(left) != measurement.signed.paulis.get(right) {
4269                        return Err(invalid(
4270                            module,
4271                            &format!(
4272                                "measurement '{}' cannot close across a module seam",
4273                                measurement.name
4274                            ),
4275                        ));
4276                    }
4277                }
4278            }
4279
4280            let eliminated = eliminate_supported_seam(&mut rows, &mut [], left, right);
4281            rows.drain(..eliminated);
4282
4283            for row in &mut rows {
4284                contract_supported_row(row, left, right, transpose, support_seam);
4285            }
4286            rows.retain(|row| {
4287                !row.signed.paulis.is_identity()
4288                    || measurements.iter().any(|measurement| {
4289                        row.support.get(measurement.target) != Pauli::I
4290                            || measurement
4291                                .self_readers
4292                                .iter()
4293                                .any(|&target| row.support.get(target) != Pauli::I)
4294                    })
4295                    || protected
4296                        .iter()
4297                        .any(|constraint| row.support.get(constraint.target) != Pauli::I)
4298                    || frontier
4299                        .iter()
4300                        .any(|&target| row.support.get(target) != Pauli::I)
4301            });
4302            for measurement in &mut *measurements {
4303                contract_measurement(measurement, left, right, transpose, support_seam);
4304            }
4305        }
4306
4307        for row in &mut rows {
4308            remap_row_columns(row, None, retained);
4309        }
4310    }
4311    let mut rank = signed_gaussian_elimination(
4312        &mut rows,
4313        (0..retained.len()).flat_map(|column| [Pauli::X, Pauli::Z].map(move |axis| (column, axis))),
4314        |row, &(column, axis)| row.signed.paulis.get(column) & axis,
4315    );
4316    if rank < rows.len() {
4317        let mut targets = measurements
4318            .iter()
4319            .map(|measurement| measurement.target)
4320            .chain(
4321                measurements
4322                    .iter()
4323                    .flat_map(|measurement| measurement.self_readers.iter().copied()),
4324            )
4325            .chain(protected.iter().map(|constraint| constraint.target))
4326            .chain(frontier.iter().copied())
4327            .collect::<FxHashSet<_>>()
4328            .into_iter()
4329            .collect::<Vec<_>>();
4330        targets.sort_unstable_by_key(support_target_key);
4331        rank = eliminate_support_targets(&mut rows, rank, &targets);
4332    }
4333    rows.truncate(rank);
4334    for measurement in measurements {
4335        measurement.signed.paulis = PauliString::from_terms(
4336            retained.len(),
4337            retained
4338                .iter()
4339                .enumerate()
4340                .map(|(target, &source)| (target, measurement.signed.paulis.get(source))),
4341        );
4342    }
4343    Ok(rows)
4344}
4345
4346/// Compose a complete certificate basis without dropping boundary-zero rows.
4347/// These rows are private rank completion, not public observables.
4348fn compose_certificate_rows(
4349    mut rows: Vec<SupportedRow>,
4350    seams: &[(usize, usize, bool, bool, SupportSeam)],
4351    retained: &[usize],
4352) -> Vec<SupportedRow> {
4353    if seams.len() > 1 {
4354        rows = compose_frontier_rows(rows, seams, retained, |row| row.support.weight() != 0);
4355    } else {
4356        for &(left, right, hadamard, transpose, support_seam) in seams {
4357            if hadamard {
4358                for row in &mut rows {
4359                    conjugate_supported_h(row, right);
4360                }
4361            }
4362            let eliminated = eliminate_supported_seam(&mut rows, &mut [], left, right);
4363            rows.drain(..eliminated);
4364            for row in &mut rows {
4365                contract_supported_row(row, left, right, transpose, support_seam);
4366            }
4367        }
4368        for row in &mut rows {
4369            remap_row_columns(row, None, retained);
4370        }
4371        rows.retain(|row| !row.signed.paulis.is_identity() || row.support.weight() != 0);
4372    }
4373
4374    let boundary_rank = signed_gaussian_elimination(
4375        &mut rows,
4376        (0..retained.len()).flat_map(|column| [Pauli::X, Pauli::Z].map(move |axis| (column, axis))),
4377        |row, &(column, axis)| row.signed.paulis.get(column) & axis,
4378    );
4379    // Live composition needs a basis only on the remaining boundary. Keep all
4380    // residual witnesses for final rank completion; reducing their physical
4381    // support at every connector makes earlier prefixes grow through later rows.
4382    if !seams.is_empty() || boundary_rank == rows.len() {
4383        return rows;
4384    }
4385    let mut targets = rows
4386        .iter()
4387        .flat_map(|row| {
4388            row.support
4389                .nodes
4390                .keys()
4391                .copied()
4392                .map(SupportTarget::Node)
4393                .chain(
4394                    row.support
4395                        .edges
4396                        .keys()
4397                        .copied()
4398                        .map(|(left, right)| SupportTarget::Edge(left, right)),
4399                )
4400        })
4401        .collect::<FxHashSet<_>>()
4402        .into_iter()
4403        .collect::<Vec<_>>();
4404    targets.sort_unstable_by_key(support_target_key);
4405    let rank = eliminate_support_targets(&mut rows, boundary_rank, &targets);
4406    rows.truncate(rank);
4407    rows
4408}
4409
4410/// Continue the same ordered reduction using cached leading support targets.
4411fn eliminate_support_targets(
4412    rows: &mut [SupportedRow],
4413    solved: usize,
4414    targets: &[SupportTarget],
4415) -> usize {
4416    if targets.is_empty() {
4417        return solved;
4418    }
4419    let columns: FxHashMap<_, _> = targets
4420        .iter()
4421        .copied()
4422        .enumerate()
4423        .map(|(column, target)| (target, column))
4424        .collect();
4425    debug_assert_eq!(columns.len(), targets.len(), "support targets are unique");
4426    leading_pivot_elimination_from(
4427        rows,
4428        solved,
4429        |row| {
4430            let present = row
4431                .support
4432                .nodes
4433                .keys()
4434                .copied()
4435                .map(SupportTarget::Node)
4436                .chain(row.support.edges.keys().flat_map(|&(left, right)| {
4437                    [
4438                        SupportTarget::Edge(left, right),
4439                        SupportTarget::Edge(right, left),
4440                    ]
4441                }));
4442            present
4443                .filter_map(|target| {
4444                    let &column = columns.get(&target)?;
4445                    let pauli = row.support.get(target);
4446                    (pauli != Pauli::I)
4447                        .then_some((column, if pauli & Pauli::X { Pauli::X } else { Pauli::Z }))
4448                })
4449                .min_by_key(|&(column, axis)| (column, axis == Pauli::Z))
4450        },
4451        |row, &(column, axis)| row.support.get(targets[column]) & axis,
4452    )
4453}
4454
4455/// A seam's row supports stay fixed while each measurement selects its own
4456/// constraints. Project them once; individual reductions clone only packed rows.
4457struct AdjustmentBasis<'a> {
4458    sources: Vec<&'a SupportedRow>,
4459    candidates: Vec<PhasedPauliString>,
4460    columns: FxHashMap<SupportTarget, usize>,
4461    boundary_width: usize,
4462    selector_start: usize,
4463    prefix_rank: usize,
4464    next_measurement: usize,
4465}
4466
4467impl<'a> AdjustmentBasis<'a> {
4468    fn new(
4469        rows: &'a [SupportedRow],
4470        measurements: &[SummaryMeasurement],
4471        protected: &[ProtectedSupport],
4472    ) -> Self {
4473        let mut sources = rows.iter().collect::<Vec<_>>();
4474        sources.sort_by_key(|row| row.support.weight());
4475        let boundary_width = sources.first().map_or(0, |row| row.signed.paulis.len());
4476        let mut targets = measurements
4477            .iter()
4478            .flat_map(|measurement| {
4479                std::iter::once(measurement.target).chain(measurement.self_readers.iter().copied())
4480            })
4481            .chain(protected.iter().map(|constraint| constraint.target))
4482            .collect::<Vec<_>>();
4483        targets.sort_unstable_by_key(support_target_key);
4484        targets.dedup();
4485        // Auxiliary support bits and source selectors use X-only columns, so
4486        // their XORs cannot contribute phases to the signed boundary rows.
4487        let selector_start = boundary_width + 2 * targets.len();
4488        let candidates = sources
4489            .iter()
4490            .enumerate()
4491            .map(|(source, row)| {
4492                let mut paulis = PauliString::from_terms(
4493                    selector_start + sources.len(),
4494                    row.signed.paulis.iter_support(),
4495                );
4496                for (column, &target) in targets.iter().enumerate() {
4497                    let value = row.support.get(target);
4498                    for (offset, axis) in [Pauli::X, Pauli::Z].into_iter().enumerate() {
4499                        if value & axis {
4500                            paulis.set(boundary_width + 2 * column + offset, Pauli::X);
4501                        }
4502                    }
4503                }
4504                paulis.set(selector_start + source, Pauli::X);
4505                PhasedPauliString::new(paulis, row.signed.phase())
4506            })
4507            .collect();
4508        let columns = targets
4509            .into_iter()
4510            .enumerate()
4511            .map(|(column, target)| (target, boundary_width + 2 * column))
4512            .collect();
4513        Self {
4514            sources,
4515            candidates,
4516            columns,
4517            boundary_width,
4518            selector_start,
4519            prefix_rank: 0,
4520            next_measurement: 0,
4521        }
4522    }
4523}
4524
4525fn safe_adjustments(
4526    basis: &mut AdjustmentBasis<'_>,
4527    measurements: &[SummaryMeasurement],
4528    index: usize,
4529    protected: &[ProtectedSupport],
4530    module: &str,
4531) -> Result<Vec<SupportedRow>, ModuleCertificationError> {
4532    debug_assert_eq!(index, basis.next_measurement);
4533    let measurement = &measurements[index];
4534    let mut constraints = measurements
4535        .iter()
4536        .enumerate()
4537        .skip(index)
4538        .flat_map(|(other, candidate)| {
4539            let axes = if other == index {
4540                Pauli::Y
4541            } else {
4542                candidate.observable
4543            };
4544            axes.iter_xz().map(move |axis| (candidate.target, axis))
4545        })
4546        .collect::<Vec<_>>();
4547    constraints.extend(
4548        measurement
4549            .self_readers
4550            .iter()
4551            .copied()
4552            .flat_map(|target| [(target, Pauli::X), (target, Pauli::Z)]),
4553    );
4554    // A joint fixing names several caps; preserving only its first target
4555    // lets seam adjustments change the flip axis on the remaining caps.
4556    constraints.extend(
4557        measurement
4558            .kind
4559            .selective_fixing_targets()
4560            .iter()
4561            .flat_map(|target| {
4562                [Pauli::X, Pauli::Z].map(|axis| (SupportTarget::Node(target.pos), axis))
4563            }),
4564    );
4565    for constraint in protected {
4566        if measurement
4567            .kind
4568            .selective_fixing_targets()
4569            .iter()
4570            .any(|target| SupportTarget::Node(target.pos) == constraint.target)
4571        {
4572            continue;
4573        }
4574        if let Some(forbidden) = constraint.forbidden {
4575            let difference = measurement.support.get(constraint.target) ^ forbidden;
4576            let Some(axis) = difference.iter_xz().next() else {
4577                return Err(invalid(
4578                    module,
4579                    &format!(
4580                        "measurement '{}' has forbidden selective support",
4581                        measurement.name
4582                    ),
4583                ));
4584            };
4585            constraints.push((constraint.target, axis));
4586        } else {
4587            constraints.extend([(constraint.target, Pauli::X), (constraint.target, Pauli::Z)]);
4588        }
4589    }
4590
4591    let sources = &basis.sources;
4592    let boundary_width = basis.boundary_width;
4593    let selector_start = basis.selector_start;
4594    let mut candidates = basis.candidates.clone();
4595    let eliminated = signed_gaussian_elimination_from(
4596        &mut candidates,
4597        basis.prefix_rank,
4598        constraints
4599            .into_iter()
4600            .map(|(target, axis)| basis.columns[&target] + usize::from(axis == Pauli::Z)),
4601        |row, &column| row.paulis.get(column) == Pauli::X,
4602    );
4603    let mut candidates = candidates
4604        .into_iter()
4605        .skip(eliminated)
4606        .map(|row| {
4607            let mut support = PositionedSupport::default();
4608            let mut witness = FlowWitness::default();
4609            for (column, _) in row
4610                .paulis
4611                .iter_support()
4612                .filter(|&(column, _)| column >= selector_start)
4613            {
4614                let source = sources[column - selector_start];
4615                support.multiply_assign(&source.support);
4616                witness.xor_assign(&source.witness);
4617            }
4618            SupportedRow {
4619                signed: PhasedPauliString::new(
4620                    PauliString::from_terms(
4621                        boundary_width,
4622                        (0..boundary_width).map(|column| (column, row.paulis.get(column))),
4623                    ),
4624                    row.phase(),
4625                ),
4626                support,
4627                witness,
4628            }
4629        })
4630        .collect::<Vec<_>>();
4631    candidates.sort_by_key(|row| row.support.weight());
4632    // The next measurement has the same constraints through this observable.
4633    // Retain all prefix rows: later pivots must still update earlier rows' phases.
4634    let column = basis.columns[&measurement.target];
4635    basis.prefix_rank = signed_gaussian_elimination_from(
4636        &mut basis.candidates,
4637        basis.prefix_rank,
4638        measurement
4639            .observable
4640            .iter_xz()
4641            .map(|axis| column + usize::from(axis == Pauli::Z)),
4642        |row, &column| row.paulis.get(column) == Pauli::X,
4643    );
4644    basis.next_measurement += 1;
4645    Ok(candidates)
4646}
4647
4648fn eliminate_supported_seam(
4649    rows: &mut [SupportedRow],
4650    measurements: &mut [SummaryMeasurement],
4651    left: usize,
4652    right: usize,
4653) -> usize {
4654    let mut solved = 0;
4655    for axis in [Pauli::X, Pauli::Z] {
4656        let mismatch = |row: &SupportedRow| {
4657            (row.signed.paulis.get(left) ^ row.signed.paulis.get(right)) & axis
4658        };
4659        let Some(pivot) = (solved..rows.len()).find(|&row| mismatch(&rows[row])) else {
4660            continue;
4661        };
4662        rows.swap(pivot, solved);
4663        let (before, pivot_and_after) = rows.split_at_mut(solved);
4664        let (pivot, after) = pivot_and_after
4665            .split_first_mut()
4666            .expect("solved pivot is in bounds");
4667        for row in before.iter_mut().chain(after) {
4668            if mismatch(row) {
4669                EliminationRow::multiply_assign(row, pivot);
4670            }
4671        }
4672        for measurement in &mut *measurements {
4673            if (measurement.signed.paulis.get(left) ^ measurement.signed.paulis.get(right)) & axis {
4674                multiply_measurement(measurement, pivot);
4675            }
4676        }
4677        solved += 1;
4678    }
4679    solved
4680}
4681
4682impl EliminationRow for SupportedRow {
4683    fn multiply_assign(&mut self, pivot: &Self) {
4684        self.signed.multiply_assign(&pivot.signed);
4685        self.support.multiply_assign(&pivot.support);
4686        self.witness.xor_assign(&pivot.witness);
4687    }
4688}
4689
4690fn conjugate_supported_h(row: &mut SupportedRow, column: usize) {
4691    row.signed.conjugate_h(column);
4692}
4693
4694fn multiply_measurement(measurement: &mut SummaryMeasurement, row: &SupportedRow) {
4695    measurement.signed.multiply_assign(&row.signed);
4696    measurement.support.multiply_assign(&row.support);
4697    measurement.witness.xor_assign(&row.witness);
4698}
4699
4700fn conjugate_measurement_h(measurement: &mut SummaryMeasurement, column: usize) {
4701    measurement.signed.conjugate_h(column);
4702}
4703
4704fn contract_supported_row(
4705    row: &mut SupportedRow,
4706    left: usize,
4707    right: usize,
4708    transpose: bool,
4709    seam: SupportSeam,
4710) {
4711    let pauli = row.signed.paulis.get(left);
4712    if transpose && pauli == Pauli::Y {
4713        row.signed.shift_phase(2);
4714    }
4715    row.signed.paulis.set(left, Pauli::I);
4716    row.signed.paulis.set(right, Pauli::I);
4717    let seam_phase = row.support.add_seam(seam, pauli);
4718    row.signed.shift_phase(seam_phase);
4719}
4720
4721fn contract_measurement(
4722    measurement: &mut SummaryMeasurement,
4723    left: usize,
4724    right: usize,
4725    transpose: bool,
4726    seam: SupportSeam,
4727) {
4728    let pauli = measurement.signed.paulis.get(left);
4729    if transpose && pauli == Pauli::Y {
4730        measurement.signed.shift_phase(2);
4731    }
4732    measurement.signed.paulis.set(left, Pauli::I);
4733    measurement.signed.paulis.set(right, Pauli::I);
4734    let seam_phase = measurement.support.add_seam(seam, pauli);
4735    measurement.signed.shift_phase(seam_phase);
4736}
4737
4738fn invalid(module: &str, message: &str) -> ModuleCertificationError {
4739    ModuleCertificationError::InvalidConnection {
4740        module: module.to_string(),
4741        message: message.to_string(),
4742    }
4743}
4744
4745#[cfg(test)]
4746mod certificate_tests {
4747    use super::*;
4748    use crate::{Expr, FeedbackTarget, GalleryItem};
4749
4750    #[test]
4751    fn discarded_seam_pivot_preserves_signed_order_and_support_cancellation() {
4752        let edge = (IVec3::ZERO, IVec3::Z);
4753        let support =
4754            |nodes: &[(IVec3, Pauli)], edges: &[((IVec3, IVec3), Pauli)]| PositionedSupport {
4755                nodes: nodes.iter().copied().collect(),
4756                edges: edges.iter().copied().collect(),
4757            };
4758        let row = |order, pauli, support| FrontierRow {
4759            order,
4760            row: SupportedRow {
4761                signed: PhasedPauliString::positive(PauliString::from_terms(
4762                    3,
4763                    [(0, Pauli::X), (2, pauli)],
4764                )),
4765                support,
4766                witness: FlowWitness::default(),
4767            },
4768        };
4769        let mut rows = vec![
4770            row(
4771                0,
4772                Pauli::X,
4773                support(
4774                    &[(IVec3::ZERO, Pauli::X), (IVec3::X, Pauli::X)],
4775                    &[(edge, Pauli::Z)],
4776                ),
4777            ),
4778            row(
4779                1,
4780                Pauli::Z,
4781                support(&[(IVec3::ZERO, Pauli::Z)], &[(edge, Pauli::Z)]),
4782            ),
4783            row(2, Pauli::Y, support(&[(IVec3::ZERO, Pauli::X)], &[])),
4784        ];
4785        eliminate_frontier_seam(&mut rows, 0, 1);
4786        assert_eq!(rows.len(), 2);
4787        // Z*X = iY, while Y*X = -iZ. Moving the signed pivot instead of
4788        // just its support would reverse these phases on the final user.
4789        for (actual, (order, phase, pauli)) in rows.iter().zip([(1, 1, Pauli::Y), (2, 3, Pauli::Z)])
4790        {
4791            assert_eq!(actual.order, order);
4792            assert_eq!(
4793                actual.row.signed,
4794                PhasedPauliString::new(PauliString::from_terms(3, [(2, pauli)]), phase)
4795            );
4796        }
4797        assert_eq!(
4798            rows[0].row.support.nodes,
4799            FxHashMap::from_iter([(IVec3::ZERO, Pauli::Y), (IVec3::X, Pauli::X)])
4800        );
4801        assert!(rows[0].row.support.edges.is_empty());
4802        assert_eq!(
4803            rows[1].row.support.nodes,
4804            FxHashMap::from_iter([(IVec3::X, Pauli::X)])
4805        );
4806        assert_eq!(
4807            rows[1].row.support.edges,
4808            FxHashMap::from_iter([(edge, Pauli::Z)])
4809        );
4810    }
4811
4812    fn test_measurement(
4813        boundary: PauliString,
4814        support: PositionedSupport,
4815        target: SupportTarget,
4816    ) -> SummaryMeasurement {
4817        SummaryMeasurement {
4818            name: "m".into(),
4819            kind: StabilizerRowKind::Measurement { name: "m".into() },
4820            signed: PhasedPauliString::positive(boundary),
4821            support,
4822            witness: FlowWitness::default(),
4823            target,
4824            observable: Pauli::Z,
4825            self_readers: Vec::new(),
4826            owned_positions: FxHashSet::default(),
4827        }
4828    }
4829
4830    fn test_supported_rows(seed: u32) -> Vec<SupportedRow> {
4831        (0..9u32)
4832            .map(|index| {
4833                let bits = seed
4834                    .wrapping_mul(0x9e37_79b9)
4835                    .wrapping_add(index.wrapping_mul(0x85eb_ca6b));
4836                let pauli = |shift| {
4837                    [Pauli::I, Pauli::X, Pauli::Z, Pauli::Y][((bits >> shift) & 3) as usize]
4838                };
4839                SupportedRow {
4840                    signed: PhasedPauliString::new(
4841                        PauliString::from_terms(
4842                            3,
4843                            (0..3).map(|column| (column, pauli(2 * column))),
4844                        ),
4845                        (bits >> 18) as u8,
4846                    ),
4847                    support: PositionedSupport {
4848                        nodes: [IVec3::ZERO, IVec3::Y, IVec3::Z]
4849                            .into_iter()
4850                            .enumerate()
4851                            .map(|(i, position)| (position, pauli(6 + i * 2)))
4852                            .filter(|&(_, pauli)| pauli != Pauli::I)
4853                            .collect(),
4854                        edges: [((IVec3::X, IVec3::X * 2), pauli(12))]
4855                            .into_iter()
4856                            .filter(|&(_, pauli)| pauli != Pauli::I)
4857                            .collect(),
4858                    },
4859                    witness: FlowWitness::default(),
4860                }
4861            })
4862            .collect()
4863    }
4864
4865    #[test]
4866    fn joining_a_port_preserves_the_record_on_its_edge() {
4867        let edge = (IVec3::ZERO, IVec3::X);
4868        let target = SupportTarget::Edge(edge.0, edge.1);
4869        let support = PositionedSupport {
4870            edges: [(edge, Pauli::Z)].into_iter().collect(),
4871            ..PositionedSupport::default()
4872        };
4873        let mut measurements = [test_measurement(
4874            PauliString::from_terms(2, [(0, Pauli::Z)]),
4875            support.clone(),
4876            target,
4877        )];
4878        measurements[0].observable = Pauli::Z;
4879        let mut rows = vec![
4880            SupportedRow {
4881                signed: measurements[0].signed.clone(),
4882                support,
4883                witness: FlowWitness::default(),
4884            },
4885            SupportedRow {
4886                signed: PhasedPauliString::positive(PauliString::from_terms(2, [(1, Pauli::Z)])),
4887                support: PositionedSupport::default(),
4888                witness: FlowWitness::default(),
4889            },
4890        ];
4891        let ports = [edge.0].into_iter().collect();
4892        for row in &mut rows {
4893            row.support.strip_ports(&ports, &[target]);
4894        }
4895        measurements[0].support.strip_ports(&ports, &[target]);
4896        compose_supported_rows(
4897            rows,
4898            &mut measurements,
4899            &[],
4900            &[],
4901            &[(
4902                0,
4903                1,
4904                false,
4905                false,
4906                SupportSeam {
4907                    edge,
4908                    boundary_to_edge_hadamard: false,
4909                },
4910            )],
4911            &[],
4912            "test",
4913        )
4914        .unwrap();
4915        assert_eq!(measurements[0].support.get(target), Pauli::Z);
4916    }
4917
4918    #[test]
4919    fn seam_adjustments_preserve_every_joint_fixing_target() {
4920        let positions = [IVec3::ZERO, IVec3::X];
4921        let protected = positions.map(|pos| ProtectedSupport {
4922            target: SupportTarget::Node(pos),
4923            forbidden: Some(Pauli::Y),
4924        });
4925        let mut fixing = test_measurement(
4926            PauliString::new(1),
4927            PositionedSupport {
4928                nodes: positions.into_iter().map(|pos| (pos, Pauli::Y)).collect(),
4929                ..PositionedSupport::default()
4930            },
4931            protected[0].target,
4932        );
4933        fixing.kind = StabilizerRowKind::SelectiveFixing {
4934            targets: positions
4935                .map(|pos| crate::SelectiveFixingTarget {
4936                    pos,
4937                    forbidden: Pauli::Y,
4938                })
4939                .to_vec(),
4940        };
4941        fixing.observable = Pauli::I;
4942        let adjustments = [SupportedRow {
4943            signed: PhasedPauliString::positive(PauliString::from_terms(1, [(0, Pauli::X)])),
4944            support: PositionedSupport {
4945                nodes: FxHashMap::from_iter([(positions[1], Pauli::Z)]),
4946                ..PositionedSupport::default()
4947            },
4948            witness: FlowWitness::default(),
4949        }];
4950        let measurements = [fixing];
4951        let mut basis = AdjustmentBasis::new(&adjustments, &measurements, &protected);
4952        let safe = safe_adjustments(&mut basis, &measurements, 0, &protected, "test").unwrap();
4953        assert!(
4954            safe.is_empty(),
4955            "adjustment would change the second cap from Y to X"
4956        );
4957    }
4958
4959    #[test]
4960    fn cached_support_targets_preserve_signed_rows_and_witnesses() {
4961        let summary = GalleryItem::GHZ
4962            .build()
4963            .summarize_root(ModuleCertificationLimits::DEFAULT)
4964            .unwrap();
4965        assert!(
4966            summary
4967                .certificate_rows
4968                .iter()
4969                .any(|row| row.witness.source_count() != 0)
4970        );
4971        let mut targets = [IVec3::ZERO, IVec3::Y, IVec3::Z]
4972            .into_iter()
4973            .map(SupportTarget::Node)
4974            .chain((0..70).map(|x| SupportTarget::Node(IVec3::new(x, 10, 0))))
4975            .chain([
4976                SupportTarget::Edge(IVec3::X, IVec3::X * 2),
4977                SupportTarget::Edge(IVec3::X * 2, IVec3::X),
4978            ])
4979            .collect::<Vec<_>>();
4980        targets.sort_unstable_by_key(support_target_key);
4981        for seed in 0..64 {
4982            for reverse_edges in [false, true] {
4983                let mut rows = test_supported_rows(seed);
4984                for (row, source) in rows.iter_mut().zip(summary.certificate_rows.iter().cycle()) {
4985                    row.witness = source.witness.clone();
4986                    if reverse_edges {
4987                        row.support.edges = row
4988                            .support
4989                            .edges
4990                            .drain()
4991                            .map(|((left, right), value)| ((right, left), value))
4992                            .collect();
4993                    }
4994                }
4995                let solved = signed_gaussian_elimination(
4996                    &mut rows,
4997                    (0..3).flat_map(|column| [Pauli::X, Pauli::Z].map(move |axis| (column, axis))),
4998                    |row, &(column, axis)| row.signed.paulis.get(column) & axis,
4999                );
5000                for targets in [&targets[..0], &targets[..3], targets.as_slice()] {
5001                    let mut expected = rows.clone();
5002                    let expected_rank = signed_gaussian_elimination_from(
5003                        &mut expected,
5004                        solved,
5005                        targets.iter().copied().flat_map(|target| {
5006                            [Pauli::X, Pauli::Z].map(move |axis| (target, axis))
5007                        }),
5008                        |row, &(target, axis)| row.support.get(target) & axis,
5009                    );
5010                    let mut actual = rows.clone();
5011                    assert_eq!(
5012                        eliminate_support_targets(&mut actual, solved, targets),
5013                        expected_rank
5014                    );
5015                    for (actual, expected) in actual.iter().zip(&expected) {
5016                        assert_eq!(actual.signed, expected.signed, "seed {seed}");
5017                        assert_eq!(actual.support.nodes, expected.support.nodes, "seed {seed}");
5018                        assert_eq!(actual.support.edges, expected.support.edges, "seed {seed}");
5019                        let mut difference = actual.witness.clone();
5020                        difference.xor_assign(&expected.witness);
5021                        assert_eq!(difference.source_count(), 0, "seed {seed}");
5022                    }
5023                }
5024            }
5025        }
5026    }
5027
5028    #[test]
5029    fn packed_adjustments_match_eager_signed_elimination() {
5030        let target = SupportTarget::Node(IVec3::ZERO);
5031        let edge = SupportTarget::Edge(IVec3::X, IVec3::X * 2);
5032        let reader = SupportTarget::Node(IVec3::Z);
5033        let protected = [ProtectedSupport {
5034            target: SupportTarget::Node(IVec3::Y),
5035            forbidden: None,
5036        }];
5037        let mut measurements = [
5038            test_measurement(PauliString::new(3), PositionedSupport::default(), target),
5039            test_measurement(PauliString::new(3), PositionedSupport::default(), edge),
5040        ];
5041        measurements[0].self_readers.push(reader);
5042        measurements[1].observable = Pauli::X;
5043        for seed in 0..64u32 {
5044            let rows = test_supported_rows(seed);
5045            let mut basis = AdjustmentBasis::new(&rows, &measurements, &protected);
5046            for index in 0..measurements.len() {
5047                let constraints = measurements
5048                    .iter()
5049                    .enumerate()
5050                    .flat_map(|(other, measurement)| {
5051                        let axes = if other == index {
5052                            Pauli::Y
5053                        } else {
5054                            measurement.observable
5055                        };
5056                        axes.iter_xz().map(move |axis| (measurement.target, axis))
5057                    })
5058                    .chain(
5059                        measurements[index]
5060                            .self_readers
5061                            .iter()
5062                            .copied()
5063                            .flat_map(|target| [(target, Pauli::X), (target, Pauli::Z)]),
5064                    )
5065                    .chain(
5066                        protected
5067                            .iter()
5068                            .flat_map(|p| [(p.target, Pauli::X), (p.target, Pauli::Z)]),
5069                    );
5070                let mut expected = rows.clone();
5071                expected.sort_by_key(|row| row.support.weight());
5072                let rank = signed_gaussian_elimination(
5073                    &mut expected,
5074                    constraints,
5075                    |row, &(target, axis)| row.support.get(target) & axis,
5076                );
5077                expected.drain(..rank);
5078                expected.sort_by_key(|row| row.support.weight());
5079                let actual =
5080                    safe_adjustments(&mut basis, &measurements, index, &protected, "test").unwrap();
5081                assert_eq!(
5082                    actual.len(),
5083                    expected.len(),
5084                    "seed {seed}, measurement {index}"
5085                );
5086                for (actual, expected) in actual.iter().zip(&expected) {
5087                    assert_eq!(
5088                        actual.signed, expected.signed,
5089                        "seed {seed}, measurement {index}"
5090                    );
5091                    assert_eq!(
5092                        actual.support.nodes, expected.support.nodes,
5093                        "seed {seed}, measurement {index}"
5094                    );
5095                    assert_eq!(
5096                        actual.support.edges, expected.support.edges,
5097                        "seed {seed}, measurement {index}"
5098                    );
5099                }
5100            }
5101        }
5102    }
5103
5104    #[test]
5105    fn composed_normalization_preserves_current_group_before_other_templates() {
5106        let targets = (0..4)
5107            .map(|x| SupportTarget::Node(IVec3::new(x, 0, 0)))
5108            .collect::<Vec<_>>();
5109        let support = |paulis: [Pauli; 4]| PositionedSupport {
5110            nodes: targets
5111                .iter()
5112                .zip(paulis)
5113                .filter_map(|(&target, pauli)| {
5114                    let SupportTarget::Node(position) = target else {
5115                        unreachable!()
5116                    };
5117                    (pauli != Pauli::I).then_some((position, pauli))
5118                })
5119                .collect(),
5120            edges: FxHashMap::default(),
5121        };
5122        let mut rows = [test_measurement(
5123            PauliString::new(0),
5124            support([Pauli::Z, Pauli::I, Pauli::Z, Pauli::Y]),
5125            SupportTarget::Node(IVec3::new(10, 0, 0)),
5126        )];
5127        let adjustments = [
5128            [Pauli::Z, Pauli::X, Pauli::Z, Pauli::Z],
5129            [Pauli::I, Pauli::I, Pauli::I, Pauli::X],
5130        ]
5131        .map(|paulis| SupportedRow {
5132            signed: PhasedPauliString::positive(PauliString::new(0)),
5133            support: support(paulis),
5134            witness: FlowWitness::default(),
5135        });
5136        normalize_measurement_rows(
5137            &mut rows,
5138            &adjustments,
5139            &[ProtectedSupport {
5140                target: targets[3],
5141                forbidden: Some(Pauli::Y),
5142            }],
5143            &[ProtectedGroup {
5144                targets: targets[..3].to_vec(),
5145                permitted_support: vec![vec![Pauli::X; 3], vec![Pauli::Z; 3]],
5146            }],
5147            ModuleCertificationLimits::UNLIMITED,
5148            "order",
5149        )
5150        .unwrap();
5151        assert_eq!(
5152            targets
5153                .iter()
5154                .map(|&target| rows[0].support.get(target))
5155                .collect::<Vec<_>>(),
5156            [Pauli::Z, Pauli::I, Pauli::Z, Pauli::Z]
5157        );
5158    }
5159
5160    #[test]
5161    fn flat_source_limit_counts_cube_height_before_geometry_work() {
5162        let graph = crate::parse_blog_to_graph("BLOG 1.0\n0: ZXZ [0,0,0] height=4d\n").unwrap();
5163        let limits = ModuleCertificationLimits {
5164            max_expanded_blocks: 1,
5165            max_occupied_cells: 3,
5166            ..ModuleCertificationLimits::UNLIMITED
5167        };
5168        assert!(matches!(
5169            graph.validate_resource_limits(limits),
5170            Err(crate::BlockGraphError::Stabilizer(
5171                crate::StabilizerError::ResourceLimited {
5172                    phase: "occupied footprint cells",
5173                    observed: 4,
5174                    limit: 3,
5175                }
5176            ))
5177        ));
5178        graph
5179            .validate_resource_limits(ModuleCertificationLimits {
5180                max_occupied_cells: 4,
5181                ..limits
5182            })
5183            .unwrap();
5184    }
5185
5186    #[test]
5187    fn wide_correlated_support_normalizes_without_a_powerset() {
5188        let positions = (0..64).map(|x| IVec3::new(x, 0, 0)).collect::<Vec<_>>();
5189        for (initial, adjustment, desired, other) in [
5190            (Pauli::Y, Pauli::Z, Pauli::X, Pauli::Z),
5191            (Pauli::Z, Pauli::X, Pauli::Y, Pauli::X),
5192        ] {
5193            let group = ProtectedGroup {
5194                targets: positions.iter().copied().map(SupportTarget::Node).collect(),
5195                permitted_support: vec![vec![desired; 64], vec![other; 64]],
5196            };
5197            let support = |pauli| PositionedSupport {
5198                nodes: positions
5199                    .iter()
5200                    .copied()
5201                    .map(|position| (position, pauli))
5202                    .collect(),
5203                edges: FxHashMap::default(),
5204            };
5205            let row = test_measurement(
5206                PauliString::new(0),
5207                support(initial),
5208                SupportTarget::Node(IVec3::new(100, 0, 0)),
5209            );
5210            let adjustments = [SupportedRow {
5211                signed: PhasedPauliString::positive(PauliString::new(0)),
5212                support: support(adjustment),
5213                witness: FlowWitness::default(),
5214            }];
5215            for (limit, expected) in [(0, 1), (16, 17)] {
5216                let error = normalize_measurement_rows(
5217                    &mut [row.clone()],
5218                    &adjustments,
5219                    &[],
5220                    std::slice::from_ref(&group),
5221                    ModuleCertificationLimits {
5222                        max_normalization_states: limit,
5223                        ..ModuleCertificationLimits::UNLIMITED
5224                    },
5225                    "wide",
5226                )
5227                .unwrap_err();
5228                assert!(
5229                    matches!(&error, ModuleCertificationError::ResourceLimited {
5230                module, phase: "measurement normalization states", observed, limit: actual_limit,
5231            } if module == "wide" && *observed == expected && *actual_limit == limit),
5232                    "{error}"
5233                );
5234            }
5235            let mut rows = [row];
5236            normalize_measurement_rows(
5237                &mut rows,
5238                &adjustments,
5239                &[],
5240                std::slice::from_ref(&group),
5241                ModuleCertificationLimits {
5242                    max_normalization_states: 160,
5243                    ..ModuleCertificationLimits::UNLIMITED
5244                },
5245                "wide",
5246            )
5247            .unwrap();
5248            assert!(
5249                positions
5250                    .iter()
5251                    .all(|&position| rows[0].support.get(SupportTarget::Node(position)) == desired)
5252            );
5253        }
5254    }
5255
5256    #[cfg(not(target_arch = "wasm32"))]
5257    #[test]
5258    fn many_protected_factors_use_heap_frames() {
5259        std::thread::Builder::new()
5260            .stack_size(64 * 1024)
5261            .spawn(|| {
5262                let width = 4_096;
5263                let protected = (0..width)
5264                    .map(|x| ProtectedSupport {
5265                        target: SupportTarget::Node(IVec3::new(x as i32, 0, 0)),
5266                        forbidden: Some(Pauli::X),
5267                    })
5268                    .collect::<Vec<_>>();
5269                let support = PositionedSupport {
5270                    nodes: (0..width)
5271                        .map(|x| (IVec3::new(x as i32, 0, 0), Pauli::X))
5272                        .collect(),
5273                    edges: FxHashMap::default(),
5274                };
5275                let row = test_measurement(
5276                    PauliString::new(0),
5277                    support.clone(),
5278                    SupportTarget::Node(IVec3::new(width as i32, 0, 0)),
5279                );
5280                let adjustments = [SupportedRow {
5281                    signed: PhasedPauliString::positive(PauliString::new(0)),
5282                    support,
5283                    witness: FlowWitness::default(),
5284                }];
5285                let limits = ModuleCertificationLimits {
5286                    max_normalization_states: 8,
5287                    max_matrix_words: 32_768,
5288                    ..ModuleCertificationLimits::DEFAULT
5289                };
5290                assert!(matches!(
5291                    normalize_measurement_rows(
5292                        &mut [row.clone()],
5293                        &adjustments,
5294                        &protected,
5295                        &[],
5296                        limits,
5297                        "deep"
5298                    ),
5299                    Err(ModuleCertificationError::ResourceLimited {
5300                        phase: "measurement normalization states",
5301                        observed: 9,
5302                        limit: 8,
5303                        ..
5304                    })
5305                ));
5306                let mut rows = [row];
5307                normalize_measurement_rows(
5308                    &mut rows,
5309                    &adjustments,
5310                    &protected,
5311                    &[],
5312                    ModuleCertificationLimits {
5313                        max_normalization_states: width + 1,
5314                        ..limits
5315                    },
5316                    "deep",
5317                )
5318                .unwrap();
5319                assert!(rows[0].support.nodes.is_empty());
5320            })
5321            .unwrap()
5322            .join()
5323            .unwrap();
5324    }
5325
5326    #[test]
5327    fn normalization_limit_counts_visited_assignments() {
5328        let invalid_position = IVec3::ZERO;
5329        let targets = (0..13)
5330            .map(|x| SupportTarget::Node(IVec3::new(x, 0, 0)))
5331            .collect::<Vec<_>>();
5332        let protected = targets
5333            .iter()
5334            .copied()
5335            .map(|target| ProtectedSupport {
5336                target,
5337                forbidden: Some(Pauli::Z),
5338            })
5339            .collect::<Vec<_>>();
5340        let support = PositionedSupport {
5341            nodes: FxHashMap::from_iter([(invalid_position, Pauli::Z)]),
5342            edges: FxHashMap::default(),
5343        };
5344        let mut rows = [test_measurement(
5345            PauliString::new(0),
5346            support,
5347            SupportTarget::Node(IVec3::new(20, 0, 0)),
5348        )];
5349        let adjustment = |pauli| SupportedRow {
5350            signed: PhasedPauliString::positive(PauliString::new(0)),
5351            support: PositionedSupport {
5352                nodes: FxHashMap::from_iter([(invalid_position, pauli)]),
5353                edges: FxHashMap::default(),
5354            },
5355            witness: FlowWitness::default(),
5356        };
5357
5358        normalize_measurement_rows(
5359            &mut rows,
5360            &[adjustment(Pauli::X), adjustment(Pauli::Z)],
5361            &protected,
5362            &[],
5363            ModuleCertificationLimits {
5364                max_normalization_states: 15,
5365                ..ModuleCertificationLimits::UNLIMITED
5366            },
5367            "test",
5368        )
5369        .unwrap();
5370
5371        // The available Z adjustment cancels the original Z support.
5372        assert!(rows[0].support.nodes.is_empty());
5373    }
5374
5375    #[test]
5376    fn closed_adjustments_stay_live_when_a_pending_obligation_reads_them() {
5377        let row = |boundary, support| SupportedRow {
5378            signed: PhasedPauliString::new(PauliString::from_terms(1, [(0, boundary)]), 2),
5379            support,
5380            witness: FlowWitness::default(),
5381        };
5382        let mut relation = ChildRelation {
5383            adjustments: vec![
5384                row(
5385                    Pauli::I,
5386                    PositionedSupport {
5387                        nodes: FxHashMap::from_iter([(IVec3::ZERO, Pauli::Z)]),
5388                        ..PositionedSupport::default()
5389                    },
5390                ),
5391                row(
5392                    Pauli::I,
5393                    PositionedSupport {
5394                        edges: FxHashMap::from_iter([((IVec3::X, IVec3::X + IVec3::Z), Pauli::Z)]),
5395                        ..PositionedSupport::default()
5396                    },
5397                ),
5398                row(Pauli::X, PositionedSupport::default()),
5399            ],
5400            ..ChildRelation::default()
5401        };
5402        // The not-yet-admitted reader names the opposite direction of this edge.
5403        let obligations =
5404            FxHashSet::from_iter([SupportTarget::Edge(IVec3::X + IVec3::Z, IVec3::X)]);
5405        let mut completed = ChildRelation::default();
5406        relation
5407            .retire_completed(&mut completed, &obligations, "test")
5408            .unwrap();
5409        assert_eq!(relation.adjustments.len(), 2);
5410        assert_eq!(
5411            relation.adjustments[0]
5412                .support
5413                .get(*obligations.iter().next().unwrap()),
5414            Pauli::Z
5415        );
5416        assert_eq!(relation.adjustments[1].signed.paulis.get(0), Pauli::X);
5417        assert_eq!(completed.adjustments.len(), 1);
5418        assert_eq!(completed.adjustments[0].signed.phase(), 2);
5419        assert_eq!(
5420            completed.adjustments[0]
5421                .support
5422                .get(SupportTarget::Node(IVec3::ZERO)),
5423            Pauli::Z
5424        );
5425    }
5426
5427    #[test]
5428    fn discharged_measurement_boundary_is_not_erased() {
5429        let mut measurements = [test_measurement(
5430            PauliString::from_terms(1, [(0, Pauli::X)]),
5431            PositionedSupport::default(),
5432            SupportTarget::Node(IVec3::ZERO),
5433        )];
5434
5435        let error = resize_discharged_boundaries(&mut measurements, 2, "test").unwrap_err();
5436
5437        assert!(matches!(
5438            error,
5439            ModuleCertificationError::InvalidConnection { message, .. }
5440                if message.contains("discharged measurement 'm' retains boundary support")
5441        ));
5442        assert_eq!(measurements[0].signed.paulis.weight(), 1);
5443    }
5444
5445    #[test]
5446    fn multiplying_positioned_support_reconstructs_cross_centers() {
5447        let zx = ZXGraph::try_from(
5448            &crate::GalleryItem::CNOT
5449                .build()
5450                .materialize_root_graph()
5451                .expect("gallery flat projection"),
5452        )
5453        .unwrap();
5454        let node = zx
5455            .nodes()
5456            .iter()
5457            .find(|node| {
5458                matches!(node.kind, crate::NodeKind::X | crate::NodeKind::Z)
5459                    && zx.edges().iter().filter(|edge| edge.n1 == node.id).count() == 3
5460            })
5461            .unwrap();
5462        let edges = zx
5463            .edges()
5464            .iter()
5465            .filter(|edge| edge.n1 == node.id)
5466            .map(|edge| edge.id)
5467            .collect::<Vec<_>>();
5468        let row = |a: usize, b: usize| {
5469            let mut row = PauliString::new(zx.total_ids());
5470            for index in [a, b] {
5471                let edge = &zx.edges()[edges[index] - zx.nodes().len()];
5472                let mut pauli = node.kind.cross_pauli();
5473                if edge.hadamard && node.id == edge.n1.max(edge.n2) {
5474                    pauli = pauli.flip();
5475                }
5476                row.set(edge.id, pauli);
5477                row.set(zx.edge_id(edge.n2, edge.n1).unwrap(), pauli);
5478            }
5479            zx.materialize_stabilizer_with_sign(row, false)
5480        };
5481        let left = row(0, 1);
5482        let right = row(0, 2);
5483        let mut support = PositionedSupport::from_stabilizer(&left, &zx);
5484        support.multiply_assign(&PositionedSupport::from_stabilizer(&right, &zx));
5485        let product = support.materialize(&zx, 0).unwrap();
5486        assert_eq!(product.paulis.get(node.id), node.kind.cross_pauli());
5487        assert_eq!(product.paulis.get(edges[0]), Pauli::I);
5488        assert_ne!(product.paulis.get(edges[1]), Pauli::I);
5489        assert_ne!(product.paulis.get(edges[2]), Pauli::I);
5490    }
5491
5492    fn identity_wrapper(program: &BlockGraph) -> BlockGraph {
5493        let mut child = program.root().clone();
5494        child.name = "Child".into();
5495        let mut body = BlockGraph::new();
5496        let quantum_connections = child
5497            .interface
5498            .quantum_ports
5499            .iter()
5500            .map(|port| {
5501                let role = match port.direction {
5502                    crate::PortDirection::Input => crate::PortRole::Input,
5503                    crate::PortDirection::Output => crate::PortRole::Output,
5504                };
5505                body.try_add_block(
5506                    Block::new(port.position, BlockKind::Port)
5507                        .with_port_role(role)
5508                        .unwrap(),
5509                )
5510                .unwrap();
5511                let endpoint = InstancePort {
5512                    instance: "child".into(),
5513                    port: port.name.clone(),
5514                };
5515                match port.direction {
5516                    crate::PortDirection::Input => QuantumConnection::Input {
5517                        block: port.position,
5518                        input: endpoint,
5519                        hadamard: false,
5520                    },
5521                    crate::PortDirection::Output => QuantumConnection::Output {
5522                        output: endpoint,
5523                        block: port.position,
5524                        hadamard: false,
5525                    },
5526                }
5527            })
5528            .collect();
5529        let root = BlockGraph::definition(
5530            "main",
5531            body,
5532            child.interface.clone(),
5533            vec![ModuleInstance {
5534                name: "child".into(),
5535                definition: child.name.clone(),
5536                rotation: crate::ModuleRotation::IDENTITY,
5537                translation: IVec3::ZERO,
5538            }],
5539            quantum_connections,
5540            Vec::new(),
5541        );
5542        BlockGraph::from_definitions(vec![child, root]).unwrap()
5543    }
5544
5545    #[test]
5546    fn shallower_sibling_preserves_queued_dependency_levels() {
5547        let wire = "in input: data = 0\nout output: data = 2\n
5548            0: Port [0,0,-1] role=input\n1: XZZ [0,0,0]\n2: Port [0,0,1] role=output\n
5549            0 -> +Z\n1 -> +Z\n";
5550        let program = crate::parse_inline_graph(&format!(
5551            "BLOG 1.0\nmodule Wire {{\n{wire}}}\nmodule Late {{\n{wire}}}\n
5552            module Nested {{
5553                in input: data = 0\nout output: data = 2
5554                0: Port [0,0,-1] role=input\n2: Port [0,0,1] role=output
5555                wire: Wire @ [0,0,0]
5556                0 -> wire.input\nwire.output -> 2
5557            }}
5558            module main {{
5559                in input: data = 0\nout output: data = 2
5560                0: Port [0,0,-1] role=input\n2: Port [0,0,2] role=output
5561                nested: Nested @ [0,0,0]
5562                late: Late @ [0,0,1]
5563                0 -> nested.input\nnested.output -> late.input\nlate.output -> 2
5564            }}"
5565        ))
5566        .unwrap();
5567        for jobs in [1, 2] {
5568            let summary = program
5569                .summarize_root_with_jobs(
5570                    ModuleCertificationLimits::DEFAULT,
5571                    NonZeroUsize::new(jobs).unwrap(),
5572                )
5573                .unwrap();
5574            assert_eq!(summary.boundary_rows().len(), 2);
5575            assert!(summary.definition("Nested").is_some());
5576            assert!(summary.definition("Late").is_some());
5577        }
5578    }
5579
5580    #[test]
5581    fn parent_readout_survives_child_composition() {
5582        let program = crate::parse_inline_graph(
5583            "BLOG 1.0\n\nmodule Wire {\n\
5584             in input: data = 0\nout output: data = 2\n\
5585             0: Port [0,0,-1]\n1: ZXZ [0,0,0]\n2: Port [0,0,1]\n\
5586             0 -> +Z\n1 -> +Z\n}\n\nmodule main {\n\
5587             in input: data = 10\nout result = m\n\
5588             wire: Wire @ [0,0,0]\n\
5589             10: Port [0,0,-1] role=input\n11: X [0,0,1]\n\
5590             10 -> wire.input\nwire.output -> 11\nm = measure 11\n}\n",
5591        )
5592        .unwrap();
5593        let summary = program
5594            .summarize_root(ModuleCertificationLimits::DEFAULT)
5595            .unwrap();
5596        assert!(
5597            summary
5598                .measurements
5599                .iter()
5600                .chain(&summary.discharged_measurements)
5601                .any(|row| row.name == "m")
5602        );
5603        let graph = program
5604            .materialize_root_graph()
5605            .unwrap()
5606            .fix_shadowed_faces();
5607        let zx = ZXGraph::try_from(&graph).unwrap();
5608        let composed = summary.materialize_stabilizers(&zx, IVec3::ZERO).unwrap();
5609        let flat = graph.analyze_actions().unwrap().1;
5610        assert_eq!(composed.generators.len(), flat.generators.len());
5611        for (composed, flat) in composed.generators.iter().zip(&flat.generators) {
5612            assert_eq!(composed.kind, flat.kind);
5613            assert_eq!(composed.stabilizer.paulis, flat.stabilizer.paulis);
5614            assert_eq!(composed.stabilizer.sign, flat.stabilizer.sign);
5615        }
5616    }
5617
5618    #[test]
5619    fn classical_parent_action_keeps_independent_connectors_within_frontier_limit() {
5620        let program = crate::parse_inline_graph(
5621            "BLOG 1.0\nmodule Wire {\n\
5622             in input: data = 0\nout output: data = 2\n\
5623             0: Port [0,0,-1]\n1: ZXZ [0,0,0]\n2: Port [0,0,1]\n\
5624             0 -> +Z\n1 -> +Z\n}\nmodule main {\n\
5625             in a: data = 10\nout a_out: data = 11\n\
5626             in b: data = 12\nout b_out: data = 13\nin enable\nout done = flag\n\
5627             a: Wire @ [0,0,0]\nb: Wire @ [2,0,0]\n\
5628             10: Port [0,0,-1] role=input\n11: Port [0,0,1] role=output\n\
5629             12: Port [2,0,-1] role=input\n13: Port [2,0,1] role=output\n\
5630             10 -> a.input\na.output -> 11\n12 -> b.input\nb.output -> 13\n\
5631             flag = enable | !enable\n}\n",
5632        )
5633        .unwrap();
5634        let summary = program
5635            .summarize_root(ModuleCertificationLimits {
5636                max_frontier_width: 6,
5637                ..ModuleCertificationLimits::DEFAULT
5638            })
5639            .unwrap();
5640        assert_eq!(summary.quantum_ports().len(), 4);
5641    }
5642
5643    #[test]
5644    fn identity_wrapper_preserves_materialized_stabilizers() {
5645        let program = identity_wrapper(&GalleryItem::CCZInjectedMaj.build());
5646        let summary = program
5647            .summarize_root(ModuleCertificationLimits::UNLIMITED)
5648            .unwrap();
5649        let graph = program.materialize_root_graph().unwrap();
5650        let zx = ZXGraph::try_from(&graph).unwrap();
5651        let composed = summary.materialize_stabilizers(&zx, IVec3::ZERO).unwrap();
5652        let flat = graph.analyze_actions().unwrap().1;
5653
5654        assert_eq!(composed.generators.len(), flat.generators.len());
5655        for (composed, flat) in composed.generators.iter().zip(&flat.generators) {
5656            assert_eq!(composed.kind, flat.kind);
5657            assert_eq!(composed.stabilizer.paulis, flat.stabilizer.paulis);
5658            assert_eq!(composed.stabilizer.sign, flat.stabilizer.sign);
5659        }
5660    }
5661
5662    #[test]
5663    fn composed_phase_cache_matches_flat_derivation_and_tracks_t_conversion() {
5664        for item in [
5665            GalleryItem::CNOT,
5666            GalleryItem::CZTemporalH,
5667            GalleryItem::S,
5668            GalleryItem::T,
5669            GalleryItem::CCZInjectedMaj,
5670            GalleryItem::PhaseGradientK4,
5671        ] {
5672            let program = item.build();
5673            let summary = program
5674                .summarize_root(ModuleCertificationLimits::UNLIMITED)
5675                .unwrap();
5676            let graph = program.materialize_root_graph().unwrap();
5677            let zx = ZXGraph::try_from(&graph).unwrap();
5678            let composed = summary.materialize_stabilizers(&zx, IVec3::ZERO).unwrap();
5679            let cached = composed.zx_graph.stabilizer_phase_basis.get().unwrap();
5680            let mut queries = composed
5681                .generators
5682                .iter()
5683                .map(|row| row.stabilizer.paulis.clone())
5684                .chain(composed.auxiliary_rows().iter().cloned())
5685                .collect::<Vec<_>>();
5686            let products = queries
5687                .windows(2)
5688                .map(|rows| {
5689                    let mut product = rows[0].clone();
5690                    product ^= &rows[1];
5691                    product
5692                })
5693                .collect::<Vec<_>>();
5694            queries.extend(products);
5695            let flat = ZXGraph::try_from(&graph).unwrap();
5696            let mut raw_queries = queries.clone();
5697            flat.clear_cross_centers(&mut raw_queries);
5698            assert_eq!(
5699                composed.zx_graph.stabilizer_row_phases(&queries),
5700                flat.external_stabilizer_row_phases(&raw_queries),
5701                "{item:?}"
5702            );
5703            let runtime =
5704                crate::RuntimeStabilizerBasis::from_generators(&composed).with_t_nodes_as_ports();
5705            let retained = runtime.zx_graph().stabilizer_phase_basis.get().unwrap();
5706            assert!(Arc::ptr_eq(cached, retained), "{item:?}");
5707            let mut fresh_demoted = runtime.zx_graph().clone();
5708            fresh_demoted.stabilizer_phase_basis.take();
5709            assert_eq!(
5710                runtime.zx_graph().stabilizer_row_phases(&queries),
5711                fresh_demoted.stabilizer_row_phases(&queries),
5712                "{item:?} after T conversion"
5713            );
5714        }
5715    }
5716
5717    #[test]
5718    fn rotated_phase_gradient_summary_preserves_flat_nonlogical_rows() {
5719        let program = GalleryItem::PhaseGradientK4.build();
5720        let summary = program
5721            .summarize_root(ModuleCertificationLimits::DEFAULT)
5722            .unwrap();
5723        let graph = program.materialize_root_graph().unwrap();
5724        let zx = ZXGraph::try_from(&graph).unwrap();
5725        let composed = summary.materialize_stabilizers(&zx, IVec3::ZERO).unwrap();
5726        let flat = graph.analyze_actions().unwrap().1;
5727
5728        assert_eq!(composed.generators.len(), flat.generators.len());
5729        for (composed, flat) in composed.generators.iter().zip(&flat.generators) {
5730            assert_eq!(composed.kind, flat.kind);
5731            // Composition preserves child readout representatives; flat analysis
5732            // may choose a different logical basis for the same graph.
5733            if matches!(composed.kind, StabilizerRowKind::Logical) {
5734                continue;
5735            }
5736            assert_eq!(
5737                composed.stabilizer.paulis, flat.stabilizer.paulis,
5738                "{:?}",
5739                composed.kind
5740            );
5741            assert_eq!(
5742                composed.stabilizer.sign, flat.stabilizer.sign,
5743                "{:?}",
5744                composed.kind
5745            );
5746        }
5747    }
5748
5749    #[test]
5750    fn leaf_certificate_preserves_signed_rows() {
5751        for item in [
5752            GalleryItem::CCZInjectedAnd,
5753            GalleryItem::CCZInjectedMaj,
5754            GalleryItem::UMA,
5755        ] {
5756            let program = item.build();
5757            let summary = program
5758                .summarize_root(ModuleCertificationLimits::UNLIMITED)
5759                .unwrap();
5760            let graph = program.materialize_root_graph().unwrap();
5761            let zx = ZXGraph::try_from(&graph).unwrap();
5762            for row in &summary.certificate_rows {
5763                let stabilizer = materialize_summary_row(
5764                    &row.signed,
5765                    &row.support,
5766                    &summary.ports,
5767                    &zx,
5768                    ModuleOrientation::IDENTITY,
5769                    IVec3::ZERO,
5770                    summary.name(),
5771                )
5772                .unwrap();
5773                let mut paulis = stabilizer.paulis.clone();
5774                zx.clear_cross_centers(std::slice::from_mut(&mut paulis));
5775                assert_eq!(
5776                    stabilizer_phase(&stabilizer),
5777                    zx.external_stabilizer_row_phases(&[paulis])[0],
5778                    "{item:?} certificate"
5779                );
5780            }
5781            for row in &summary.measurements {
5782                let stabilizer = materialize_summary_row(
5783                    &row.signed,
5784                    &row.support,
5785                    &summary.ports,
5786                    &zx,
5787                    ModuleOrientation::IDENTITY,
5788                    IVec3::ZERO,
5789                    summary.name(),
5790                )
5791                .unwrap();
5792                let mut paulis = stabilizer.paulis.clone();
5793                zx.clear_cross_centers(std::slice::from_mut(&mut paulis));
5794                assert_eq!(
5795                    stabilizer_phase(&stabilizer),
5796                    zx.external_stabilizer_row_phases(&[paulis])[0],
5797                    "{item:?} {}",
5798                    row.name
5799                );
5800            }
5801            let composed = summary.materialize_stabilizers(&zx, IVec3::ZERO).unwrap();
5802            let flat = graph.analyze_actions().unwrap().1;
5803            assert_eq!(composed.generators.len(), flat.generators.len());
5804            for (composed, flat) in composed.generators.iter().zip(&flat.generators) {
5805                assert_eq!(composed.kind, flat.kind);
5806                assert_eq!(composed.stabilizer.paulis, flat.stabilizer.paulis);
5807                assert_eq!(composed.stabilizer.sign, flat.stabilizer.sign);
5808            }
5809        }
5810    }
5811
5812    #[test]
5813    fn composed_adder_rejects_unavailable_causal_readout() {
5814        let program = crate::BlockGraph::from_text(bloq_test::ONE_BIT_ADDER_SOURCE).unwrap();
5815        let summary = program
5816            .summarize_root(ModuleCertificationLimits::UNLIMITED)
5817            .unwrap();
5818        let graph = program
5819            .materialize_root_graph()
5820            .unwrap()
5821            .canonical_true_branch_view()
5822            .unwrap();
5823        let offset = IVec3::new(0, 0, -*graph.spans().unwrap().2.start());
5824        let graph = graph.with_zero_min_z().unwrap().fix_shadowed_faces();
5825        let zx = ZXGraph::try_from(&graph).unwrap();
5826
5827        let result = summary.materialize_stabilizers(&zx, offset).map(|_| ());
5828        assert!(
5829            matches!(
5830                result,
5831                Err(ModuleCertificationError::Runtime {
5832                    source: crate::RuntimeBasisError::Stabilizer(
5833                        crate::StabilizerError::UnavailableControlParity { ref mvar, .. }
5834                    ),
5835                    ..
5836                }) if mvar == "uma__m_ikprime"
5837            ),
5838            "{result:?}"
5839        );
5840    }
5841
5842    #[test]
5843    fn composed_adder_certificate_matches_flat_row_space() {
5844        let program = crate::BlockGraph::from_text(bloq_test::ONE_BIT_ADDER_SOURCE).unwrap();
5845        let summary = program
5846            .summarize_root(ModuleCertificationLimits::UNLIMITED)
5847            .unwrap();
5848        let graph = program
5849            .materialize_root_graph()
5850            .unwrap()
5851            .canonical_true_branch_view()
5852            .unwrap();
5853        let offset = IVec3::new(0, 0, -*graph.spans().unwrap().2.start());
5854        let graph = graph.with_zero_min_z().unwrap().fix_shadowed_faces();
5855        let zx = ZXGraph::try_from(&graph).unwrap();
5856
5857        let composed = summary
5858            .certificate_rows
5859            .iter()
5860            .map(|row| {
5861                let stabilizer = materialize_summary_row(
5862                    &row.signed,
5863                    &row.support,
5864                    &summary.ports,
5865                    &zx,
5866                    ModuleOrientation::IDENTITY,
5867                    offset,
5868                    summary.name(),
5869                )
5870                .unwrap();
5871                let mut paulis = stabilizer.paulis;
5872                zx.clear_cross_centers(std::slice::from_mut(&mut paulis));
5873                paulis
5874            })
5875            .collect::<Vec<_>>();
5876        let flat = zx.to_external_generator_table();
5877        let composed_rank = crate::zx::reduce_to_basis(&composed, zx.total_ids()).len();
5878        let flat_rank = crate::zx::reduce_to_basis(&flat, zx.total_ids()).len();
5879        let mut combined = composed;
5880        combined.extend(flat);
5881        let combined_rank = crate::zx::reduce_to_basis(&combined, zx.total_ids()).len();
5882
5883        assert_eq!(composed_rank, flat_rank);
5884        assert_eq!(combined_rank, flat_rank);
5885    }
5886
5887    #[test]
5888    fn semantic_frontier_retains_resource_and_frame_support() {
5889        let response = IVec3::new(2, 0, 0);
5890        let resource = IVec3::new(3, 0, 0);
5891        let mut body = BlockGraph::new();
5892        body.add_block(Block::new(response, BlockKind::Cube(crate::CubeKind::ZXZ)));
5893        body.add_block(Block::new(resource, BlockKind::T));
5894        body.set_actions_with_inputs(
5895            vec![Action::Feedback {
5896                targets: vec![FeedbackTarget {
5897                    pauli: PauliBasis::X,
5898                    target: response,
5899                    direction: None,
5900                }],
5901                condition: Some(Expr::Var("frame".into())),
5902            }],
5903            ["frame".to_string()],
5904        )
5905        .unwrap();
5906        let module = BlockGraph::definition(
5907            "test",
5908            body.clone(),
5909            Default::default(),
5910            Vec::new(),
5911            Vec::new(),
5912            Vec::new(),
5913        );
5914        let frontier = semantic_frontier_supports(&module, &body).unwrap();
5915        assert!(frontier.contains(&SupportTarget::Node(response)));
5916        assert!(frontier.contains(&SupportTarget::Node(resource)));
5917
5918        let rows = compose_supported_rows(
5919            vec![SupportedRow {
5920                signed: PhasedPauliString::positive(PauliString::try_from("XX").unwrap()),
5921                support: PositionedSupport {
5922                    nodes: FxHashMap::from_iter([(response, Pauli::X)]),
5923                    edges: FxHashMap::default(),
5924                },
5925                witness: FlowWitness::default(),
5926            }],
5927            &mut [],
5928            &[],
5929            &frontier,
5930            &[(
5931                0,
5932                1,
5933                false,
5934                false,
5935                SupportSeam {
5936                    edge: (IVec3::ZERO, IVec3::Z),
5937                    boundary_to_edge_hadamard: false,
5938                },
5939            )],
5940            &[],
5941            "test",
5942        )
5943        .unwrap();
5944
5945        assert_eq!(rows.len(), 1);
5946        assert_eq!(rows[0].support.get(SupportTarget::Node(response)), Pauli::X);
5947    }
5948
5949    #[test]
5950    fn signed_spatial_hadamard_y_seam_has_both_minus_factors() {
5951        let edge = (IVec3::ZERO, IVec3::Y);
5952        let row = SupportedRow {
5953            signed: PhasedPauliString::positive(PauliString::from_terms(
5954                2,
5955                [(0, Pauli::Y), (1, Pauli::Y)],
5956            )),
5957            support: PositionedSupport::default(),
5958            witness: FlowWitness::default(),
5959        };
5960        let closed = compose_certificate_rows(
5961            vec![row],
5962            &[(
5963                0,
5964                1,
5965                true,
5966                true,
5967                SupportSeam {
5968                    edge,
5969                    boundary_to_edge_hadamard: false,
5970                },
5971            )],
5972            &[],
5973        );
5974        assert_eq!(closed.len(), 1);
5975        assert_eq!(
5976            closed[0].signed.phase(),
5977            0,
5978            "HYH and Y transpose each add -1"
5979        );
5980        assert_eq!(closed[0].support.edges[&edge], Pauli::Y);
5981    }
5982}