Skip to main content

qec_code/codes/
color_666.rs

1use serde::{Deserialize, Serialize};
2
3use crate::error::{QecError, Result};
4
5pub const COLOR_666_CONSTRUCTION_ID: &str = "color_666";
6pub const COLOR_666_TRIANGULAR_LAYOUT: &str = "triangular";
7pub const COLOR_666_STEANE_PERMUTATION: [usize; 7] = [0, 3, 6, 5, 1, 4, 2];
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub enum Color666Layout {
12    Triangular,
13}
14
15impl Color666Layout {
16    pub const fn as_str(self) -> &'static str {
17        match self {
18            Self::Triangular => COLOR_666_TRIANGULAR_LAYOUT,
19        }
20    }
21
22    pub fn parse(value: &str) -> Result<Self> {
23        match value {
24            COLOR_666_TRIANGULAR_LAYOUT => Ok(Self::Triangular),
25            _ => Err(QecError::InvalidCssConstruction {
26                construction: COLOR_666_CONSTRUCTION_ID.to_owned(),
27                reason: format!(
28                    "unsupported layout {value:?}; supported: {COLOR_666_TRIANGULAR_LAYOUT}"
29                ),
30            }),
31        }
32    }
33}
34
35#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
36pub struct Color666FamilySpec {
37    pub distance: usize,
38    pub layout: Color666Layout,
39}
40
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct Color666SparseChecks {
43    pub num_cols: usize,
44    pub rows: Vec<Vec<usize>>,
45}
46
47pub fn color_666_sparse_checks(spec: &Color666FamilySpec) -> Result<Color666SparseChecks> {
48    validate_distance(spec.distance)?;
49    let num_cols = color_666_num_qubits(spec.distance)?;
50    let rows = match spec.layout {
51        Color666Layout::Triangular => triangular_face_supports(spec.distance, num_cols)?,
52    };
53    Ok(Color666SparseChecks { num_cols, rows })
54}
55
56fn validate_distance(distance: usize) -> Result<()> {
57    if distance < 3 {
58        return Err(QecError::InvalidCssConstruction {
59            construction: COLOR_666_CONSTRUCTION_ID.to_owned(),
60            reason: format!("distance must be at least 3, got {distance}"),
61        });
62    }
63    if distance % 2 == 0 {
64        return Err(QecError::InvalidCssConstruction {
65            construction: COLOR_666_CONSTRUCTION_ID.to_owned(),
66            reason: format!("distance must be odd, got {distance}"),
67        });
68    }
69    Ok(())
70}
71
72fn color_666_num_qubits(distance: usize) -> Result<usize> {
73    distance
74        .checked_mul(distance)
75        .and_then(|square| square.checked_mul(3))
76        .and_then(|triple| triple.checked_add(1))
77        .map(|value| value / 4)
78        .ok_or_else(|| QecError::InvalidCssConstruction {
79            construction: COLOR_666_CONSTRUCTION_ID.to_owned(),
80            reason: "size arithmetic overflow while computing n=(3d^2+1)/4".to_owned(),
81        })
82}
83
84fn triangular_bound(distance: usize) -> Result<usize> {
85    distance
86        .checked_sub(1)
87        .and_then(|value| value.checked_mul(3))
88        .map(|value| value / 2)
89        .ok_or_else(|| QecError::InvalidCssConstruction {
90            construction: COLOR_666_CONSTRUCTION_ID.to_owned(),
91            reason: "size arithmetic overflow while computing triangular lattice bound".to_owned(),
92        })
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
96struct LatticeIndex {
97    row: usize,
98    column: usize,
99}
100
101fn is_plaquette(index: LatticeIndex) -> bool {
102    index.column % 3 == 2 - (index.row % 3)
103}
104
105fn is_site(index: LatticeIndex) -> bool {
106    !is_plaquette(index)
107}
108
109fn site_index_map(bound: usize, num_cols: usize) -> Result<Vec<Vec<Option<usize>>>> {
110    let mut next = 0usize;
111    let mut map = vec![Vec::new(); bound + 1];
112    for row in 0..=bound {
113        map[row] = vec![None; row + 1];
114        for column in 0..=row {
115            let index = LatticeIndex { row, column };
116            if is_site(index) {
117                if next >= num_cols {
118                    return Err(QecError::InvalidCssConstruction {
119                        construction: COLOR_666_CONSTRUCTION_ID.to_owned(),
120                        reason: "site count exceeded n=(3d^2+1)/4".to_owned(),
121                    });
122                }
123                map[row][column] = Some(next);
124                next += 1;
125            }
126        }
127    }
128    if next != num_cols {
129        return Err(QecError::InvalidCssConstruction {
130            construction: COLOR_666_CONSTRUCTION_ID.to_owned(),
131            reason: format!("site count {next} did not match n={num_cols}"),
132        });
133    }
134    Ok(map)
135}
136
137fn triangular_face_supports(distance: usize, num_cols: usize) -> Result<Vec<Vec<usize>>> {
138    let bound = triangular_bound(distance)?;
139    let site_indices = site_index_map(bound, num_cols)?;
140    let mut rows = Vec::new();
141
142    for row in 0..=bound {
143        for column in 0..=row {
144            let index = LatticeIndex { row, column };
145            if is_plaquette(index) {
146                let mut support = face_support(bound, &site_indices, index);
147                support.sort_unstable();
148                rows.push(support);
149            }
150        }
151    }
152
153    Ok(rows)
154}
155
156fn face_support(
157    bound: usize,
158    site_indices: &[Vec<Option<usize>>],
159    face: LatticeIndex,
160) -> Vec<usize> {
161    let row = face.row as isize;
162    let column = face.column as isize;
163    let mut support = Vec::with_capacity(6);
164    for (neighbor_row, neighbor_column) in [
165        (row - 1, column - 1),
166        (row - 1, column),
167        (row, column - 1),
168        (row, column + 1),
169        (row + 1, column),
170        (row + 1, column + 1),
171    ] {
172        if neighbor_row < 0 || neighbor_column < 0 {
173            continue;
174        }
175        let neighbor_row = neighbor_row as usize;
176        let neighbor_column = neighbor_column as usize;
177        if neighbor_row > bound || neighbor_column > neighbor_row {
178            continue;
179        }
180        if let Some(site_index) = site_indices[neighbor_row][neighbor_column] {
181            support.push(site_index);
182        }
183    }
184    support
185}
186
187#[cfg(test)]
188mod tests {
189    use super::*;
190
191    #[test]
192    fn triangular_d3_rows_match_issue_fixture() {
193        let checks = color_666_sparse_checks(&Color666FamilySpec {
194            distance: 3,
195            layout: Color666Layout::Triangular,
196        })
197        .unwrap();
198
199        assert_eq!(checks.num_cols, 7);
200        assert_eq!(
201            checks.rows,
202            vec![vec![0, 1, 2, 3], vec![1, 2, 4, 5], vec![2, 3, 5, 6]]
203        );
204    }
205
206    #[test]
207    fn triangular_d5_rows_match_reviewed_fixture() {
208        let checks = color_666_sparse_checks(&Color666FamilySpec {
209            distance: 5,
210            layout: Color666Layout::Triangular,
211        })
212        .unwrap();
213
214        assert_eq!(checks.num_cols, 19);
215        assert_eq!(
216            checks.rows,
217            vec![
218                vec![0, 1, 2, 3],
219                vec![1, 2, 4, 5],
220                vec![2, 3, 5, 6, 8, 9],
221                vec![4, 5, 7, 8, 10, 11],
222                vec![6, 9, 12, 13],
223                vec![7, 10, 14, 15],
224                vec![8, 9, 11, 12, 16, 17],
225                vec![10, 11, 15, 16],
226                vec![12, 13, 17, 18],
227            ]
228        );
229    }
230
231    #[test]
232    fn rejects_invalid_distance_values() {
233        assert!(color_666_sparse_checks(&Color666FamilySpec {
234            distance: 2,
235            layout: Color666Layout::Triangular,
236        })
237        .is_err());
238        assert!(color_666_sparse_checks(&Color666FamilySpec {
239            distance: 4,
240            layout: Color666Layout::Triangular,
241        })
242        .is_err());
243        assert!(color_666_sparse_checks(&Color666FamilySpec {
244            distance: usize::MAX,
245            layout: Color666Layout::Triangular,
246        })
247        .is_err());
248    }
249
250    #[test]
251    fn defensive_lattice_helpers_report_count_and_bound_errors() {
252        assert!(matches!(
253            triangular_bound(0),
254            Err(QecError::InvalidCssConstruction {
255                construction,
256                reason
257            }) if construction == COLOR_666_CONSTRUCTION_ID
258                && reason.contains("triangular lattice bound")
259        ));
260        assert!(matches!(
261            site_index_map(1, 1),
262            Err(QecError::InvalidCssConstruction {
263                construction,
264                reason
265            }) if construction == COLOR_666_CONSTRUCTION_ID
266                && reason.contains("exceeded")
267        ));
268        assert!(matches!(
269            site_index_map(1, 4),
270            Err(QecError::InvalidCssConstruction {
271                construction,
272                reason
273            }) if construction == COLOR_666_CONSTRUCTION_ID
274                && reason.contains("did not match")
275        ));
276    }
277}