use ndarray::{Array1, Array2, ArrayView1, ArrayView2};
use std::collections::{BTreeMap, BTreeSet};
use std::fmt;
use gam_linalg::faer_ndarray::FaerSvd;
use super::AtlasOrientability;
use super::intrinsic_seed::farthest_point_landmarks;
const CHART_RANK_FLOOR_FRAC: f64 = 1.0e-8;
const CHART_INJECTIVITY_FLOOR_FRAC: f64 = 1.0e-6;
const TRANSITION_CONDITION_FLOOR_FRAC: f64 = 1.0e-6;
const FRAME_OVERLAP_DETERMINANT_FLOOR: f64 = 1.0e-6;
const PATCH_COUNT_COVERAGE_MULTIPLIER: f64 = 2.0;
const PATCH_SIZE_OVERLAP_MULTIPLIER: f64 = 3.0;
const MIN_ATLAS_ROW_COVERAGE: f64 = 0.5;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct LocalAtlasConfig {
pub intrinsic_dim: usize,
pub patch_count: usize,
pub patch_size: usize,
pub min_overlap: usize,
}
impl LocalAtlasConfig {
#[must_use]
pub fn balanced(n_points: usize, intrinsic_dim: usize) -> Self {
let d = intrinsic_dim.max(1);
let n = n_points.max(1);
let patch_count = ((PATCH_COUNT_COVERAGE_MULTIPLIER * (n as f64).sqrt()).ceil() as usize)
.max(d + 2)
.min(n);
let occupancy = (n as f64 / patch_count as f64).max(1.0);
let patch_size = ((PATCH_SIZE_OVERLAP_MULTIPLIER * occupancy).ceil() as usize)
.max(2 * (d + 1))
.min(n);
Self {
intrinsic_dim,
patch_count,
patch_size,
min_overlap: d + 2,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum LocalChartError {
EmptyInput,
InsufficientRows { have: usize, need: usize },
NonFiniteAmbient { row: usize, col: usize, value: f64 },
IntrinsicDimTooLarge {
intrinsic_dim: usize,
ambient_dim: usize,
},
DegeneratePatch {
center: usize,
intrinsic_dim: usize,
smallest_captured_singular: f64,
leading_singular: f64,
},
NonInjectiveChart {
center: usize,
min_projected_sq_distance: f64,
min_ambient_sq_distance: f64,
},
SvdFailure { center: usize, detail: String },
AtlasCoverageTooLow {
certified: usize,
requested: usize,
covered_rows: usize,
total_rows: usize,
min_row_coverage: f64,
},
}
impl fmt::Display for LocalChartError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::EmptyInput => write!(f, "local_charts: ambient block is empty"),
Self::InsufficientRows { have, need } => write!(
f,
"local_charts: need at least {need} rows for one patch, got {have}"
),
Self::NonFiniteAmbient { row, col, value } => write!(
f,
"local_charts: ambient Z must be finite; Z[{row}, {col}] = {value}"
),
Self::IntrinsicDimTooLarge {
intrinsic_dim,
ambient_dim,
} => write!(
f,
"local_charts: chart dimension {intrinsic_dim} exceeds ambient dimension {ambient_dim}"
),
Self::DegeneratePatch {
center,
intrinsic_dim,
smallest_captured_singular,
leading_singular,
} => write!(
f,
"local_charts: patch at row {center} does not span {intrinsic_dim} dimensions \
(smallest captured singular value {smallest_captured_singular:.3e} vs leading \
{leading_singular:.3e})"
),
Self::NonInjectiveChart {
center,
min_projected_sq_distance,
min_ambient_sq_distance,
} => write!(
f,
"local_charts: chart at row {center} is not injective on its neighborhood \
(min projected sq distance {min_projected_sq_distance:.3e} vs min ambient \
{min_ambient_sq_distance:.3e})"
),
Self::SvdFailure { center, detail } => {
write!(
f,
"local_charts: SVD failed for patch at row {center}: {detail}"
)
}
Self::AtlasCoverageTooLow {
certified,
requested,
covered_rows,
total_rows,
min_row_coverage,
} => write!(
f,
"local_charts: only {certified}/{requested} centers certified, covering \
{covered_rows}/{total_rows} rows (below the {min_row_coverage:.2} floor); \
the surviving charts describe a minority of the sample"
),
}
}
}
impl std::error::Error for LocalChartError {}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ChartCertificate {
pub condition: f64,
pub leading_singular: f64,
pub smallest_captured_singular: f64,
pub captured_variance_fraction: f64,
pub min_projection_stretch: f64,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LocalPatch {
pub center: usize,
pub members: Vec<usize>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct LocalChart {
pub center: usize,
pub mean: Array1<f64>,
pub frame: Array2<f64>,
pub singular_values: Array1<f64>,
pub coords: Array2<f64>,
pub certificate: ChartCertificate,
}
impl LocalChart {
#[must_use]
pub fn project(&self, x: ArrayView1<'_, f64>) -> Array1<f64> {
let d = self.frame.ncols();
let mut out = Array1::<f64>::zeros(d);
for ax in 0..d {
let mut acc = 0.0;
for c in 0..self.frame.nrows() {
acc += self.frame[[c, ax]] * (x[c] - self.mean[c]);
}
out[ax] = acc;
}
out
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TransitionConditioning {
WellConditioned,
Degenerate,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ChartTransition {
pub from_patch: usize,
pub to_patch: usize,
pub overlap_id: usize,
pub shared_rows: Vec<usize>,
pub rotation: Array2<f64>,
pub translation: Array1<f64>,
pub sign: i8,
pub residual: f64,
pub conditioning: TransitionConditioning,
}
impl ChartTransition {
#[must_use]
pub fn apply(&self, coordinate: ArrayView1<'_, f64>) -> Array1<f64> {
let d = self.rotation.nrows();
let mut out = Array1::<f64>::zeros(d);
for i in 0..d {
let mut acc = self.translation[i];
for j in 0..d {
acc += self.rotation[[i, j]] * coordinate[j];
}
out[i] = acc;
}
out
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct CoCollapseCandidate {
pub from_patch: usize,
pub to_patch: usize,
pub overlap_id: usize,
pub mutual_coverage: f64,
pub transition_residual: f64,
}
#[derive(Clone, Debug, PartialEq)]
pub struct RejectedCenter {
pub center: usize,
pub reason: LocalChartError,
}
impl fmt::Display for RejectedCenter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "dropped center at row {}: {}", self.center, self.reason)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct LocalAtlas {
intrinsic_dim: usize,
ambient_dim: usize,
patches: Vec<LocalPatch>,
charts: Vec<LocalChart>,
transitions: Vec<ChartTransition>,
rejected_centers: Vec<RejectedCenter>,
}
impl LocalAtlas {
pub fn build(
z: ArrayView2<'_, f64>,
config: LocalAtlasConfig,
) -> Result<Self, LocalChartError> {
let (n, p) = z.dim();
if n == 0 || p == 0 {
return Err(LocalChartError::EmptyInput);
}
for ((row, col), &value) in z.indexed_iter() {
if !value.is_finite() {
return Err(LocalChartError::NonFiniteAmbient { row, col, value });
}
}
let d = config.intrinsic_dim.max(1);
if d > p {
return Err(LocalChartError::IntrinsicDimTooLarge {
intrinsic_dim: d,
ambient_dim: p,
});
}
let patch_size = config.patch_size.min(n).max(d + 1);
if n < patch_size {
return Err(LocalChartError::InsufficientRows {
have: n,
need: patch_size,
});
}
let min_overlap = config.min_overlap.max(d + 1);
let centers = farthest_point_landmarks(z, config.patch_count.max(1).min(n));
let mut patches: Vec<LocalPatch> = Vec::with_capacity(centers.len());
let mut charts: Vec<LocalChart> = Vec::with_capacity(centers.len());
let mut rejected_centers: Vec<RejectedCenter> = Vec::new();
for ¢er in ¢ers {
match certified_neighborhood_chart(z, center, patch_size, d) {
Ok((members, chart)) => {
patches.push(LocalPatch { center, members });
charts.push(chart);
}
Err(
reason @ (LocalChartError::DegeneratePatch { .. }
| LocalChartError::NonInjectiveChart { .. }
| LocalChartError::SvdFailure { .. }),
) => rejected_centers.push(RejectedCenter { center, reason }),
Err(other) => return Err(other),
}
}
if charts.is_empty() {
return Err(rejected_centers
.into_iter()
.next()
.map_or(LocalChartError::EmptyInput, |rejected| rejected.reason));
}
let covered_rows = {
let mut covered: BTreeSet<usize> = BTreeSet::new();
for patch in &patches {
covered.extend(patch.members.iter().copied());
}
covered.len()
};
if (covered_rows as f64) < MIN_ATLAS_ROW_COVERAGE * n as f64 {
return Err(LocalChartError::AtlasCoverageTooLow {
certified: charts.len(),
requested: centers.len(),
covered_rows,
total_rows: n,
min_row_coverage: MIN_ATLAS_ROW_COVERAGE,
});
}
let mut transitions: Vec<ChartTransition> = Vec::new();
let mut overlap_id = 0usize;
for i in 0..patches.len() {
for j in (i + 1)..patches.len() {
let shared = sorted_intersection(&patches[i].members, &patches[j].members);
if shared.len() < min_overlap {
continue;
}
let transition = build_transition(&charts, &patches, i, j, overlap_id, &shared);
transitions.push(transition);
overlap_id += 1;
}
}
Ok(Self {
intrinsic_dim: d,
ambient_dim: p,
patches,
charts,
transitions,
rejected_centers,
})
}
#[must_use]
pub fn intrinsic_dim(&self) -> usize {
self.intrinsic_dim
}
#[must_use]
pub fn ambient_dim(&self) -> usize {
self.ambient_dim
}
#[must_use]
pub fn patches(&self) -> &[LocalPatch] {
&self.patches
}
#[must_use]
pub fn charts(&self) -> &[LocalChart] {
&self.charts
}
#[must_use]
pub fn transitions(&self) -> &[ChartTransition] {
&self.transitions
}
#[must_use]
pub fn chart_count(&self) -> usize {
self.charts.len()
}
#[must_use]
pub fn rejected_centers(&self) -> &[RejectedCenter] {
&self.rejected_centers
}
#[must_use]
pub fn observed_signed_edges(&self) -> Vec<(usize, usize, usize, i8)> {
self.transitions
.iter()
.filter(|transition| {
matches!(
transition.conditioning,
TransitionConditioning::WellConditioned
)
})
.map(|t| (t.from_patch, t.to_patch, t.overlap_id, t.sign))
.collect()
}
#[must_use]
pub fn observed_orientability(&self) -> AtlasOrientability {
let mut orientation: BTreeMap<usize, i8> = BTreeMap::new();
let mut adj: BTreeMap<usize, Vec<(usize, i8)>> = BTreeMap::new();
for (a, b, _, sign) in self.observed_signed_edges() {
adj.entry(a).or_default().push((b, sign));
adj.entry(b).or_default().push((a, sign));
}
for root in 0..self.charts.len() {
if orientation.contains_key(&root) {
continue;
}
orientation.insert(root, 1);
let mut queue = std::collections::VecDeque::from([root]);
while let Some(chart) = queue.pop_front() {
let here = orientation[&chart];
if let Some(neighbors) = adj.get(&chart) {
for &(next, sign) in neighbors {
let required = here * sign;
match orientation.get(&next) {
Some(&existing) if existing != required => {
return AtlasOrientability::NonOrientable;
}
Some(_) => {}
None => {
orientation.insert(next, required);
queue.push_back(next);
}
}
}
}
}
}
AtlasOrientability::Orientable
}
#[must_use]
pub fn directed_rotation(&self, from: usize, to: usize) -> Option<(Array2<f64>, i8)> {
self.transitions.iter().find_map(|t| {
if t.from_patch == from && t.to_patch == to {
Some((t.rotation.clone(), t.sign))
} else if t.from_patch == to && t.to_patch == from {
Some((transpose(&t.rotation), t.sign))
} else {
None
}
})
}
#[must_use]
pub fn triangle_cocycle_defect(&self, a: usize, b: usize, c: usize) -> Option<f64> {
let (r_ab, _) = self.directed_rotation(a, b)?;
let (r_bc, _) = self.directed_rotation(b, c)?;
let (r_ca, _) = self.directed_rotation(c, a)?;
let product = matmul(&r_ca, &matmul(&r_bc, &r_ab));
let d = product.nrows();
let mut acc = 0.0;
for i in 0..d {
for j in 0..d {
let target = if i == j { 1.0 } else { 0.0 };
let diff = product[[i, j]] - target;
acc += diff * diff;
}
}
Some(acc.sqrt())
}
#[must_use]
pub fn triangle_sign_product(&self, a: usize, b: usize, c: usize) -> Option<i8> {
let (_, s_ab) = self.directed_rotation(a, b)?;
let (_, s_bc) = self.directed_rotation(b, c)?;
let (_, s_ca) = self.directed_rotation(c, a)?;
Some(s_ab * s_bc * s_ca)
}
#[must_use]
pub fn co_collapse_candidates(
&self,
coverage_threshold: f64,
residual_threshold: f64,
) -> Vec<CoCollapseCandidate> {
let mut out = Vec::new();
for transition in &self.transitions {
if !matches!(
transition.conditioning,
TransitionConditioning::WellConditioned
) {
continue;
}
let members_from = self.patches[transition.from_patch].members.len();
let members_to = self.patches[transition.to_patch].members.len();
let smaller = members_from.min(members_to);
if smaller == 0 {
continue;
}
let mutual_coverage = transition.shared_rows.len() as f64 / smaller as f64;
if mutual_coverage >= coverage_threshold && transition.residual <= residual_threshold {
out.push(CoCollapseCandidate {
from_patch: transition.from_patch,
to_patch: transition.to_patch,
overlap_id: transition.overlap_id,
mutual_coverage,
transition_residual: transition.residual,
});
}
}
out.sort_by_key(|candidate| candidate.overlap_id);
out
}
}
fn distance_order(z: ArrayView2<'_, f64>, center: usize) -> Vec<usize> {
let n = z.nrows();
let mut scored: Vec<(f64, usize)> = (0..n).map(|r| (sq_distance(z, center, r), r)).collect();
scored.sort_by(|a, b| a.0.total_cmp(&b.0).then_with(|| a.1.cmp(&b.1)));
scored.into_iter().map(|(_, r)| r).collect()
}
fn certified_neighborhood_chart(
z: ArrayView2<'_, f64>,
center: usize,
patch_size: usize,
d: usize,
) -> Result<(Vec<usize>, LocalChart), LocalChartError> {
let order = distance_order(z, center);
let floor = (2 * (d + 1)).min(patch_size).max(d + 1);
let mut size = patch_size;
loop {
let mut members: Vec<usize> = order.iter().take(size).copied().collect();
members.sort_unstable();
match build_local_chart(z, center, &members, d) {
Ok(chart) => return Ok((members, chart)),
Err(_) if size > floor => size -= 1,
Err(err) => return Err(err),
}
}
}
fn sq_distance(z: ArrayView2<'_, f64>, a: usize, b: usize) -> f64 {
let mut acc = 0.0;
for c in 0..z.ncols() {
let diff = z[[a, c]] - z[[b, c]];
acc += diff * diff;
}
acc
}
fn sorted_intersection(a: &[usize], b: &[usize]) -> Vec<usize> {
let mut out = Vec::new();
let (mut i, mut j) = (0usize, 0usize);
while i < a.len() && j < b.len() {
match a[i].cmp(&b[j]) {
std::cmp::Ordering::Less => i += 1,
std::cmp::Ordering::Greater => j += 1,
std::cmp::Ordering::Equal => {
out.push(a[i]);
i += 1;
j += 1;
}
}
}
out
}
fn build_local_chart(
z: ArrayView2<'_, f64>,
center: usize,
members: &[usize],
d: usize,
) -> Result<LocalChart, LocalChartError> {
let m = members.len();
let p = z.ncols();
let mut mean = Array1::<f64>::zeros(p);
for &row in members {
for c in 0..p {
mean[c] += z[[row, c]];
}
}
mean.mapv_inplace(|v| v / m as f64);
let mut centered = Array2::<f64>::zeros((m, p));
for (r, &row) in members.iter().enumerate() {
for c in 0..p {
centered[[r, c]] = z[[row, c]] - mean[c];
}
}
let (_, svals, vt) = centered
.svd(false, true)
.map_err(|err| LocalChartError::SvdFailure {
center,
detail: format!("{err:?}"),
})?;
let vt = vt.expect("svd(_, true) returns Vᵀ");
let rank = svals.len();
if rank < d {
return Err(LocalChartError::DegeneratePatch {
center,
intrinsic_dim: d,
smallest_captured_singular: 0.0,
leading_singular: svals.first().copied().unwrap_or(0.0),
});
}
let leading = svals[0];
let smallest_captured = svals[d - 1];
if !(leading > 0.0) || smallest_captured <= CHART_RANK_FLOOR_FRAC * leading {
return Err(LocalChartError::DegeneratePatch {
center,
intrinsic_dim: d,
smallest_captured_singular: smallest_captured,
leading_singular: leading,
});
}
let mut frame = Array2::<f64>::zeros((p, d));
for ax in 0..d {
for c in 0..p {
frame[[c, ax]] = vt[[ax, c]];
}
let mut pivot = 0usize;
let mut best = frame[[0, ax]].abs();
for c in 1..p {
let v = frame[[c, ax]].abs();
if v > best {
best = v;
pivot = c;
}
}
if frame[[pivot, ax]] < 0.0 {
for c in 0..p {
frame[[c, ax]] = -frame[[c, ax]];
}
}
}
let coords = centered.dot(&frame);
let mut min_proj_sq = f64::INFINITY;
let mut min_amb_sq = f64::INFINITY;
let mut min_stretch = f64::INFINITY;
for a in 0..m {
for b in (a + 1)..m {
let mut amb = 0.0;
for c in 0..p {
let diff = centered[[a, c]] - centered[[b, c]];
amb += diff * diff;
}
let mut proj = 0.0;
for ax in 0..d {
let diff = coords[[a, ax]] - coords[[b, ax]];
proj += diff * diff;
}
if amb < min_amb_sq {
min_amb_sq = amb;
}
if proj < min_proj_sq {
min_proj_sq = proj;
}
if amb > 0.0 {
let stretch = (proj / amb).sqrt();
if stretch < min_stretch {
min_stretch = stretch;
}
}
}
}
if !min_amb_sq.is_finite() {
min_amb_sq = 0.0;
min_proj_sq = 0.0;
min_stretch = 1.0;
}
if min_proj_sq <= CHART_INJECTIVITY_FLOOR_FRAC * min_amb_sq && min_amb_sq > 0.0 {
return Err(LocalChartError::NonInjectiveChart {
center,
min_projected_sq_distance: min_proj_sq,
min_ambient_sq_distance: min_amb_sq,
});
}
let total_variance: f64 = svals.iter().map(|s| s * s).sum();
let captured: f64 = svals.iter().take(d).map(|s| s * s).sum();
let captured_variance_fraction = if total_variance > 0.0 {
captured / total_variance
} else {
0.0
};
let singular_values = Array1::from_iter(svals.iter().take(d).copied());
let certificate = ChartCertificate {
condition: leading / smallest_captured,
leading_singular: leading,
smallest_captured_singular: smallest_captured,
captured_variance_fraction,
min_projection_stretch: if min_stretch.is_finite() {
min_stretch
} else {
1.0
},
};
Ok(LocalChart {
center,
mean,
frame,
singular_values,
coords,
certificate,
})
}
fn build_transition(
charts: &[LocalChart],
patches: &[LocalPatch],
from_patch: usize,
to_patch: usize,
overlap_id: usize,
shared: &[usize],
) -> ChartTransition {
let chart_i = &charts[from_patch];
let chart_j = &charts[to_patch];
let members_i = &patches[from_patch].members;
let members_j = &patches[to_patch].members;
let d = chart_i.frame.ncols();
let s = shared.len();
let mut c_from = Array2::<f64>::zeros((d, s));
let mut c_to = Array2::<f64>::zeros((d, s));
for (col, &row) in shared.iter().enumerate() {
let li = members_i
.binary_search(&row)
.expect("shared row is a member of patch i");
let lj = members_j
.binary_search(&row)
.expect("shared row is a member of patch j");
for ax in 0..d {
c_from[[ax, col]] = chart_i.coords[[li, ax]];
c_to[[ax, col]] = chart_j.coords[[lj, ax]];
}
}
let mut mean_from = Array1::<f64>::zeros(d);
let mut mean_to = Array1::<f64>::zeros(d);
for ax in 0..d {
let mut sf = 0.0;
let mut st = 0.0;
for col in 0..s {
sf += c_from[[ax, col]];
st += c_to[[ax, col]];
}
mean_from[ax] = sf / s as f64;
mean_to[ax] = st / s as f64;
}
for ax in 0..d {
for col in 0..s {
c_from[[ax, col]] -= mean_from[ax];
c_to[[ax, col]] -= mean_to[ax];
}
}
let a_mat = frame_overlap(&chart_j.frame, &chart_i.frame);
let det_a = determinant(&a_mat);
let sign: i8 = if det_a >= 0.0 { 1 } else { -1 };
let frame_nondegenerate = det_a.abs() > FRAME_OVERLAP_DETERMINANT_FLOOR;
let m_mat = c_to.dot(&c_from.t());
let (rotation, conditioning) = match m_mat.svd(true, true) {
Ok((Some(u), sv, Some(vt))) => {
let mut r = u.dot(&vt);
if (determinant(&r) >= 0.0) != (sign >= 0) {
let mut flipped = u;
let last = d - 1;
for row in 0..d {
flipped[[row, last]] = -flipped[[row, last]];
}
r = flipped.dot(&vt);
}
let leading = sv.first().copied().unwrap_or(0.0);
let smallest = sv.get(d - 1).copied().unwrap_or(0.0);
let well_posed = leading > 0.0 && smallest > TRANSITION_CONDITION_FLOOR_FRAC * leading;
let conditioning = if well_posed && frame_nondegenerate {
TransitionConditioning::WellConditioned
} else {
TransitionConditioning::Degenerate
};
(r, conditioning)
}
_ => (signed_identity(d, sign), TransitionConditioning::Degenerate),
};
let rc = rotation.dot(&c_from);
let mut num = 0.0;
let mut den = 0.0;
for ax in 0..d {
for col in 0..s {
let diff = c_to[[ax, col]] - rc[[ax, col]];
num += diff * diff;
den += c_to[[ax, col]] * c_to[[ax, col]];
}
}
let residual = if den > 0.0 { (num / den).sqrt() } else { 0.0 };
let mut translation = mean_to.clone();
for i in 0..d {
let mut acc = 0.0;
for j in 0..d {
acc += rotation[[i, j]] * mean_from[j];
}
translation[i] -= acc;
}
ChartTransition {
from_patch,
to_patch,
overlap_id,
shared_rows: shared.to_vec(),
rotation,
translation,
sign,
residual,
conditioning,
}
}
fn frame_overlap(frame_to: &Array2<f64>, frame_from: &Array2<f64>) -> Array2<f64> {
frame_to.t().dot(frame_from)
}
fn signed_identity(d: usize, sign: i8) -> Array2<f64> {
let mut m = Array2::<f64>::eye(d);
if sign < 0 && d > 0 {
m[[d - 1, d - 1]] = -1.0;
}
m
}
fn matmul(a: &Array2<f64>, b: &Array2<f64>) -> Array2<f64> {
a.dot(b)
}
fn transpose(a: &Array2<f64>) -> Array2<f64> {
a.t().to_owned()
}
fn determinant(m: &Array2<f64>) -> f64 {
let n = m.nrows();
let mut a = m.clone();
let mut det = 1.0;
for col in 0..n {
let mut pivot = col;
let mut best = a[[col, col]].abs();
for r in (col + 1)..n {
let v = a[[r, col]].abs();
if v > best {
best = v;
pivot = r;
}
}
if best == 0.0 {
return 0.0;
}
if pivot != col {
for c in 0..n {
a.swap([col, c], [pivot, c]);
}
det = -det;
}
det *= a[[col, col]];
for r in (col + 1)..n {
let factor = a[[r, col]] / a[[col, col]];
for c in col..n {
let sub = factor * a[[col, c]];
a[[r, c]] -= sub;
}
}
}
det
}
#[cfg(test)]
mod tests {
use super::*;
fn swiss_roll(n_t: usize, n_h: usize) -> Array2<f64> {
let n = n_t * n_h;
let mut z = Array2::<f64>::zeros((n, 3));
let mut r = 0usize;
for it in 0..n_t {
let t = 1.0 + 3.0 * std::f64::consts::PI * (it as f64) / (n_t as f64 - 1.0);
for ih in 0..n_h {
let h = 2.0 * (ih as f64) / (n_h as f64 - 1.0);
z[[r, 0]] = t * t.cos();
z[[r, 1]] = t * t.sin();
z[[r, 2]] = h;
r += 1;
}
}
z
}
fn embedded_plane(n_x: usize, n_y: usize) -> Array2<f64> {
let u = [0.5, 0.5, 0.5, 0.5];
let v = [0.5, -0.5, 0.5, -0.5];
let n = n_x * n_y;
let mut z = Array2::<f64>::zeros((n, 4));
let mut r = 0usize;
for ix in 0..n_x {
for iy in 0..n_y {
let a = ix as f64;
let b = iy as f64;
for c in 0..4 {
z[[r, c]] = a * u[c] + b * v[c];
}
r += 1;
}
}
z
}
fn sphere(n_lat: usize, n_lon: usize) -> Array2<f64> {
let n = n_lat * n_lon;
let mut z = Array2::<f64>::zeros((n, 3));
let mut r = 0usize;
for i in 0..n_lat {
let lat = -1.2 + 2.4 * (i as f64) / (n_lat as f64 - 1.0); for j in 0..n_lon {
let lon = std::f64::consts::TAU * (j as f64) / (n_lon as f64);
z[[r, 0]] = lat.cos() * lon.cos();
z[[r, 1]] = lat.cos() * lon.sin();
z[[r, 2]] = lat.sin();
r += 1;
}
}
z
}
fn cylinder_strip(n_u: usize, n_v: usize) -> Array2<f64> {
let n = n_u * n_v;
let mut z = Array2::<f64>::zeros((n, 3));
let mut r = 0usize;
for iu in 0..n_u {
let u = std::f64::consts::TAU * (iu as f64) / (n_u as f64);
for iv in 0..n_v {
let v = -0.4 + 0.8 * (iv as f64) / (n_v as f64 - 1.0);
z[[r, 0]] = 2.0 * u.cos();
z[[r, 1]] = 2.0 * u.sin();
z[[r, 2]] = v;
r += 1;
}
}
z
}
fn mobius_strip(n_u: usize, n_v: usize) -> Array2<f64> {
let n = n_u * n_v;
let mut z = Array2::<f64>::zeros((n, 3));
let mut r = 0usize;
for iu in 0..n_u {
let u = std::f64::consts::TAU * (iu as f64) / (n_u as f64);
for iv in 0..n_v {
let v = -0.4 + 0.8 * (iv as f64) / (n_v as f64 - 1.0);
let radial = 2.0 + v * (u / 2.0).cos();
z[[r, 0]] = radial * u.cos();
z[[r, 1]] = radial * u.sin();
z[[r, 2]] = v * (u / 2.0).sin();
r += 1;
}
}
z
}
fn genuine_triple(atlas: &LocalAtlas) -> Option<(usize, usize, usize)> {
let k = atlas.chart_count();
for a in 0..k {
for b in (a + 1)..k {
if atlas.directed_rotation(a, b).is_none() {
continue;
}
for c in (b + 1)..k {
if atlas.directed_rotation(b, c).is_some()
&& atlas.directed_rotation(a, c).is_some()
{
let ab = sorted_intersection(
&atlas.patches()[a].members,
&atlas.patches()[b].members,
);
let triple = sorted_intersection(&ab, &atlas.patches()[c].members);
if !triple.is_empty() {
return Some((a, b, c));
}
}
}
}
}
None
}
#[test]
fn swiss_roll_charts_injective_and_cocycle_closes_2280() {
let z = swiss_roll(40, 8);
let config = LocalAtlasConfig::balanced(z.nrows(), 2);
let atlas = LocalAtlas::build(z.view(), config).expect("swiss roll atlas must build");
assert!(atlas.chart_count() >= 3, "need several charts to overlap");
for chart in atlas.charts() {
assert!(
chart.certificate.min_projection_stretch > 0.0,
"chart at row {} must be injective (positive lower stretch)",
chart.center
);
assert!(
chart.certificate.captured_variance_fraction > 0.7,
"a swiss-roll patch is mostly planar (above the 2/3 isotropic baseline); \
captured var {} too low",
chart.certificate.captured_variance_fraction
);
}
let (a, b, c) = genuine_triple(&atlas).expect("swiss roll must have a triple overlap");
let defect = atlas.triangle_cocycle_defect(a, b, c).unwrap();
assert!(
defect < 0.5,
"flat (contractible) triple cocycle must nearly close, defect {defect:.3e}"
);
assert_eq!(
atlas.triangle_sign_product(a, b, c),
Some(1),
"an orientable triple has sign product +1"
);
}
#[test]
fn embedded_plane_cocycle_closes_to_rounding_2280() {
let z = embedded_plane(12, 12);
let config = LocalAtlasConfig::balanced(z.nrows(), 2);
let atlas = LocalAtlas::build(z.view(), config).expect("plane atlas must build");
for chart in atlas.charts() {
assert!(
chart.certificate.captured_variance_fraction > 1.0 - 1e-9,
"an exact plane patch captures all variance"
);
assert!(
(chart.certificate.min_projection_stretch - 1.0).abs() < 1e-6,
"an isometric chart has unit lower stretch"
);
}
let (a, b, c) = genuine_triple(&atlas).expect("plane must have a triple overlap");
let defect = atlas.triangle_cocycle_defect(a, b, c).unwrap();
assert!(
defect < 1e-8,
"exact-plane triple cocycle must close to rounding, defect {defect:.3e}"
);
assert_eq!(
atlas.observed_orientability(),
AtlasOrientability::Orientable
);
}
#[test]
fn sphere_charts_injective_and_orientable_2280() {
let z = sphere(14, 20);
let config = LocalAtlasConfig::balanced(z.nrows(), 2);
let atlas = LocalAtlas::build(z.view(), config).expect("sphere atlas must build");
for chart in atlas.charts() {
assert!(
chart.certificate.min_projection_stretch > 0.0,
"sphere chart at row {} must be injective",
chart.center
);
}
assert_eq!(
atlas.observed_orientability(),
AtlasOrientability::Orientable,
"the sphere is orientable"
);
let (a, b, c) = genuine_triple(&atlas).expect("sphere must have a triple overlap");
assert_eq!(
atlas.triangle_sign_product(a, b, c),
Some(1),
"an orientable triple has sign product +1"
);
let defect = atlas.triangle_cocycle_defect(a, b, c).unwrap();
assert!(
defect < 0.75,
"a small sphere triple cocycle nearly closes, defect {defect:.3e}"
);
}
#[test]
fn orientation_sign_recovers_mobius_vs_cylinder_2280() {
let cyl = cylinder_strip(60, 5);
let cyl_atlas = LocalAtlas::build(cyl.view(), LocalAtlasConfig::balanced(cyl.nrows(), 2))
.expect("cylinder atlas must build");
assert_eq!(
cyl_atlas.observed_orientability(),
AtlasOrientability::Orientable,
"a cylinder is orientable"
);
let mob = mobius_strip(60, 5);
let mob_atlas = LocalAtlas::build(mob.view(), LocalAtlasConfig::balanced(mob.nrows(), 2))
.expect("mobius atlas must build");
assert_eq!(
mob_atlas.observed_orientability(),
AtlasOrientability::NonOrientable,
"a Möbius strip is non-orientable: the sign cocycle has a negative-holonomy loop"
);
}
#[test]
fn degenerate_patch_rejected_with_typed_error_2280() {
let n = 30usize;
let mut z = Array2::<f64>::zeros((n, 3));
for r in 0..n {
let t = r as f64;
z[[r, 0]] = t;
z[[r, 1]] = 2.0 * t;
z[[r, 2]] = -t;
}
let config = LocalAtlasConfig::balanced(n, 2);
let err = LocalAtlas::build(z.view(), config).unwrap_err();
assert!(
matches!(
err,
LocalChartError::DegeneratePatch {
intrinsic_dim: 2,
..
}
),
"collinear data cannot yield a 2-chart; got {err}"
);
}
#[test]
fn atlas_drops_a_degenerate_center_and_keeps_the_rest_2280() {
let plane = embedded_plane(12, 12);
let plane_n = plane.nrows();
let blob_n = 25usize;
let n = plane_n + blob_n;
let mut z = Array2::<f64>::zeros((n, 4));
for r in 0..plane_n {
for c in 0..4 {
z[[r, c]] = plane[[r, c]];
}
}
for t in 0..blob_n {
z[[plane_n + t, 0]] = 200.0 + 0.02 * t as f64;
}
let config = LocalAtlasConfig::balanced(n, 2);
let atlas =
LocalAtlas::build(z.view(), config).expect("a mostly-healthy sample must still build");
assert!(
!atlas.rejected_centers().is_empty(),
"the degenerate blob center must be recorded as dropped, not aborted"
);
for rejected in atlas.rejected_centers() {
assert!(
rejected.center >= plane_n,
"only blob rows ({plane_n}..) are unchartable; dropped center {} is on the plane",
rejected.center
);
assert!(
matches!(rejected.reason, LocalChartError::DegeneratePatch { .. }),
"a collinear neighborhood drops with DegeneratePatch; got {}",
rejected.reason
);
}
let rendered = format!("{}", atlas.rejected_centers()[0]);
assert!(
rendered.contains("dropped center at row")
&& rendered.contains("does not span"),
"a dropped center must render a legible reason; got {rendered:?}"
);
assert!(
atlas.chart_count() >= 1,
"the plane's charts survive the dropped blob center"
);
let covered: BTreeSet<usize> = atlas
.patches()
.iter()
.flat_map(|p| p.members.iter().copied())
.collect();
assert!(
covered.len() as f64 >= MIN_ATLAS_ROW_COVERAGE * n as f64,
"surviving charts must clear the coverage floor: {} of {n}",
covered.len()
);
let again = LocalAtlas::build(z.view(), config).unwrap();
assert_eq!(atlas, again, "skip-and-continue must be deterministic");
}
#[test]
fn atlas_refuses_when_certified_coverage_falls_below_floor_2280() {
let plane = embedded_plane(4, 4);
let plane_n = plane.nrows();
let blob_n = 100usize;
let n = plane_n + blob_n;
let mut z = Array2::<f64>::zeros((n, 4));
for r in 0..plane_n {
for c in 0..4 {
z[[r, c]] = plane[[r, c]];
}
}
for t in 0..blob_n {
z[[plane_n + t, 0]] = 1000.0;
z[[plane_n + t, 1]] = t as f64;
}
let config = LocalAtlasConfig::balanced(n, 2);
let err = LocalAtlas::build(z.view(), config).unwrap_err();
match err {
LocalChartError::AtlasCoverageTooLow {
certified,
covered_rows,
total_rows,
..
} => {
assert!(certified >= 1, "the plane still certified some charts");
assert!(
(covered_rows as f64) < 0.5 * total_rows as f64,
"coverage {covered_rows}/{total_rows} must be below the floor to refuse"
);
}
other => panic!("a minority-coverage sub-atlas must refuse via AtlasCoverageTooLow; got {other}"),
}
}
#[test]
fn clean_atlas_drops_no_centers_2280() {
let z = embedded_plane(10, 10);
let atlas =
LocalAtlas::build(z.view(), LocalAtlasConfig::balanced(z.nrows(), 2)).unwrap();
assert!(
atlas.rejected_centers().is_empty(),
"a clean plane certifies every center; nothing should be dropped"
);
assert!(atlas.chart_count() > 0, "a clean plane yields charts");
}
#[test]
fn atlas_is_bit_identical_run_to_run_2280() {
let z = swiss_roll(30, 6);
let config = LocalAtlasConfig::balanced(z.nrows(), 2);
let a = LocalAtlas::build(z.view(), config).unwrap();
let b = LocalAtlas::build(z.view(), config).unwrap();
assert_eq!(a, b, "local atlas must be bit-identical run-to-run");
}
#[test]
fn observed_signed_edges_are_canonical_but_not_certificates_2280() {
let z = sphere(12, 16);
let atlas = LocalAtlas::build(z.view(), LocalAtlasConfig::balanced(z.nrows(), 2)).unwrap();
let edges = atlas.observed_signed_edges();
assert!(!edges.is_empty(), "a covered sphere has overlaps");
let mut seen_overlaps = std::collections::BTreeSet::new();
for (a, b, overlap, sign) in edges {
assert!(a < b, "canonical undirected edge must have a < b");
assert!(matches!(sign, -1 | 1), "sign must be ±1, got {sign}");
assert!(a < atlas.chart_count() && b < atlas.chart_count());
assert!(seen_overlaps.insert(overlap), "overlap ids must be unique");
}
}
#[test]
fn one_dimensional_transition_sign_is_plus_or_minus_one_2280() {
let n = 60usize;
let mut z = Array2::<f64>::zeros((n, 3));
for r in 0..n {
let t = 0.2 * r as f64;
z[[r, 0]] = t.cos();
z[[r, 1]] = t.sin();
z[[r, 2]] = 0.1 * t;
}
let atlas = LocalAtlas::build(z.view(), LocalAtlasConfig::balanced(n, 1)).unwrap();
assert_eq!(atlas.intrinsic_dim(), 1);
for t in atlas.transitions() {
assert_eq!(t.rotation.dim(), (1, 1));
assert!(
(t.rotation[[0, 0]].abs() - 1.0).abs() < 1e-9,
"a 1-D orthogonal factor is ±1, got {}",
t.rotation[[0, 0]]
);
assert_eq!(t.sign as f64, t.rotation[[0, 0]].signum());
}
}
#[test]
fn determinant_reads_orthogonal_sign() {
let mut reflection = Array2::<f64>::eye(3);
reflection[[2, 2]] = -1.0;
assert!((determinant(&reflection) + 1.0).abs() < 1e-12);
let rotation = Array2::<f64>::eye(3);
assert!((determinant(&rotation) - 1.0).abs() < 1e-12);
}
#[test]
fn co_collapse_flags_duplicate_charts_2280() {
let z = embedded_plane(6, 6); let config = LocalAtlasConfig {
intrinsic_dim: 2,
patch_count: 2,
patch_size: z.nrows(),
min_overlap: 3,
};
let atlas = LocalAtlas::build(z.view(), config).expect("duplicate-patch atlas must build");
assert_eq!(
atlas.chart_count(),
2,
"config pins two whole-cloud patches"
);
let candidates = atlas.co_collapse_candidates(0.9, 1.0e-6);
assert_eq!(
candidates.len(),
1,
"the two identical-support charts are one co-collapse candidate"
);
let candidate = candidates[0];
assert!(
candidate.mutual_coverage > 0.99,
"duplicate charts must have near-total mutual coverage, got {}",
candidate.mutual_coverage
);
assert!(
candidate.transition_residual < 1.0e-6,
"an exact-isometry glue must have ~zero transition residual, got {}",
candidate.transition_residual
);
}
#[test]
fn co_collapse_thresholds_bracket_the_gate_2280() {
let z = embedded_plane(6, 6);
let config = LocalAtlasConfig {
intrinsic_dim: 2,
patch_count: 2,
patch_size: z.nrows(),
min_overlap: 3,
};
let atlas = LocalAtlas::build(z.view(), config).unwrap();
assert!(
atlas.co_collapse_candidates(1.5, f64::INFINITY).is_empty(),
"no pair can exceed a coverage bar above 1"
);
let permissive = atlas.co_collapse_candidates(0.0, f64::INFINITY);
let well_conditioned = atlas.observed_signed_edges().len();
assert_eq!(
permissive.len(),
well_conditioned,
"the fully permissive query flags exactly the well-conditioned transitions"
);
}
#[test]
fn co_collapse_spares_healthy_swiss_roll_atlas_2280() {
let z = swiss_roll(40, 8);
let atlas = LocalAtlas::build(z.view(), LocalAtlasConfig::balanced(z.nrows(), 2)).unwrap();
let permissive = atlas.co_collapse_candidates(0.0, f64::INFINITY).len();
assert!(
permissive > 0,
"the swiss-roll atlas has overlapping charts"
);
let strict_coverage = atlas.co_collapse_candidates(0.98, f64::INFINITY).len();
assert!(
strict_coverage < permissive,
"a strict coverage bar must spare healthy partial-overlap adjacency \
(strict {strict_coverage} vs permissive {permissive})"
);
let strict_residual = atlas.co_collapse_candidates(0.0, 0.0).len();
assert!(
strict_residual < permissive,
"a strict residual bar must spare curved (nonzero-residual) glues \
(strict {strict_residual} vs permissive {permissive})"
);
}
}