1use bloq_graph::{BlockGraph, ModuleCertificationLimits};
2
3use crate::error::InvalidDistance;
4
5pub const MAX_CODE_DISTANCE: u32 = 255;
10
11const SPATIAL_HADAMARD_DISTANCE_WARNING: &str = "fixed-bulk spatial Hadamard pipes can reduce the effective circuit distance below the requested code distance; check the emitted circuit's distance before relying on it";
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub struct CompileConfig {
29 code_distance: u32,
30 prepare_t_with_mpps: bool,
31 certification_limits: ModuleCertificationLimits,
32}
33
34impl CompileConfig {
35 #[must_use]
51 pub const fn is_valid_distance(code_distance: u32) -> bool {
52 code_distance >= 3 && code_distance <= MAX_CODE_DISTANCE && code_distance % 2 == 1
53 }
54
55 pub fn try_new(code_distance: u32) -> Result<Self, InvalidDistance> {
62 if !Self::is_valid_distance(code_distance) {
63 return Err(InvalidDistance(code_distance));
64 }
65 Ok(Self {
66 code_distance,
67 prepare_t_with_mpps: false,
68 certification_limits: ModuleCertificationLimits::DEFAULT,
69 })
70 }
71
72 #[must_use]
79 pub fn new(code_distance: u32) -> Self {
80 Self::try_new(code_distance).expect("code distance must be odd and in 3..=255")
81 }
82
83 #[must_use]
85 pub fn code_distance(&self) -> u32 {
86 self.code_distance
87 }
88
89 #[must_use]
92 pub fn prepare_t_with_mpps(&self) -> bool {
93 self.prepare_t_with_mpps
94 }
95
96 #[must_use]
98 pub const fn with_prepare_t_with_mpps(mut self, enabled: bool) -> Self {
99 self.prepare_t_with_mpps = enabled;
100 self
101 }
102
103 #[must_use]
105 pub const fn certification_limits(&self) -> ModuleCertificationLimits {
106 self.certification_limits
107 }
108
109 #[must_use]
111 pub const fn with_certification_limits(mut self, limits: ModuleCertificationLimits) -> Self {
112 self.certification_limits = limits;
113 self
114 }
115}
116
117#[must_use]
125pub fn spatial_hadamard_distance_warning(graph: &BlockGraph) -> Option<&'static str> {
126 graph
127 .pipes()
128 .any(|pipe| pipe.is_hadamard() && pipe.dir().is_spatial())
129 .then_some(SPATIAL_HADAMARD_DISTANCE_WARNING)
130}
131
132impl Default for CompileConfig {
133 fn default() -> Self {
134 Self::new(3)
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use bloq_graph::{Block, BlockKind, Direction, Pipe};
142 use glam::IVec3;
143
144 #[test]
145 fn distance_bound_limits_quadratic_grid_materialization() {
146 assert_eq!(
147 CompileConfig::try_new(MAX_CODE_DISTANCE)
148 .unwrap()
149 .code_distance(),
150 MAX_CODE_DISTANCE
151 );
152 assert_eq!(
153 CompileConfig::try_new(MAX_CODE_DISTANCE + 2),
154 Err(InvalidDistance(MAX_CODE_DISTANCE + 2))
155 );
156 }
157
158 #[test]
159 fn spatial_hadamard_distance_warning_only_matches_fixed_bulk_walls() {
160 let mut graph = BlockGraph::new();
161 graph.add_block(Block::new(
162 IVec3::ZERO,
163 BlockKind::Cube(bloq_graph::CubeKind::XZX),
164 ));
165 graph.add_block(Block::new(
166 IVec3::X,
167 BlockKind::Cube(bloq_graph::CubeKind::XXZ),
168 ));
169 graph.add_pipe(Pipe::new(IVec3::ZERO, Direction::XPLUS).with_hadamard());
170
171 assert_eq!(
172 spatial_hadamard_distance_warning(&graph),
173 Some(SPATIAL_HADAMARD_DISTANCE_WARNING)
174 );
175 graph
176 .set_pipe_hadamard(IVec3::ZERO, IVec3::X, false)
177 .unwrap();
178 graph.add_block(Block::new(
179 IVec3::Z,
180 BlockKind::Cube(bloq_graph::CubeKind::XZX),
181 ));
182 graph.add_pipe(Pipe::new(IVec3::ZERO, Direction::ZPLUS).with_hadamard());
183 assert!(spatial_hadamard_distance_warning(&graph).is_none());
184 }
185}