#[must_use]
pub const fn n_cart(l: usize) -> usize {
(l + 1) * (l + 2) / 2
}
#[must_use]
pub fn cart_components(l: usize) -> Vec<[usize; 3]> {
let mut out = Vec::with_capacity(n_cart(l));
for lx in (0..=l).rev() {
for ly in (0..=(l - lx)).rev() {
out.push([lx, ly, l - lx - ly]);
}
}
out
}
#[must_use]
pub fn cart_index(c: [usize; 3]) -> usize {
let l = c[0] + c[1] + c[2];
let d = l - c[0]; d * (d + 1) / 2 + c[2]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn counts_match_formula() {
assert_eq!(n_cart(0), 1);
assert_eq!(n_cart(1), 3);
assert_eq!(n_cart(2), 6);
assert_eq!(n_cart(3), 10);
assert_eq!(n_cart(4), 15);
}
#[test]
fn p_ordering_is_xyz() {
assert_eq!(cart_components(1), vec![[1, 0, 0], [0, 1, 0], [0, 0, 1]]);
}
#[test]
fn d_ordering_is_canonical() {
assert_eq!(
cart_components(2),
vec![
[2, 0, 0],
[1, 1, 0],
[1, 0, 1],
[0, 2, 0],
[0, 1, 1],
[0, 0, 2]
]
);
}
#[test]
fn component_count_is_consistent() {
for l in 0..=6 {
let comps = cart_components(l);
assert_eq!(comps.len(), n_cart(l));
for c in comps {
assert_eq!(c[0] + c[1] + c[2], l);
}
}
}
#[test]
fn cart_index_inverts_cart_components() {
for l in 0..=6 {
for (i, c) in cart_components(l).into_iter().enumerate() {
assert_eq!(cart_index(c), i, "l={l} component {c:?}");
}
}
}
#[test]
fn cart_index_tracks_raise_and_lower() {
assert_eq!(cart_index([1, 1, 0]), 1);
let f = cart_components(3);
assert_eq!(f[cart_index([2, 1, 0])], [2, 1, 0]);
assert_eq!(cart_index([1, 0, 0]), 0);
}
}