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;
#[cfg(test)]
#[path = "local_chart_recovery_tests.rs"]
mod recovered_transition_tests;
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;
fn frame_angular_resolution(certificate: &ChartCertificate) -> f64 {
let captured = certificate.captured_variance_fraction;
if !captured.is_finite() || captured <= 0.5 {
return 1.0;
}
let captured = captured.min(1.0);
let epsilon = 1.0 - captured;
let sine = (epsilon / captured).sqrt();
if sine.is_finite() { sine.min(1.0) } else { 1.0 }
}
fn combined_frame_resolution(sin_a: f64, sin_b: f64) -> f64 {
if !(sin_a.is_finite() && sin_b.is_finite()) || sin_a >= 1.0 || sin_b >= 1.0 {
return 1.0;
}
let cos_a = (1.0 - sin_a * sin_a).max(0.0).sqrt();
let cos_b = (1.0 - sin_b * sin_b).max(0.0).sqrt();
if sin_a > cos_b {
return 1.0;
}
(sin_a * cos_b + sin_b * cos_a).min(1.0)
}
const PATCH_COUNT_COVERAGE_MULTIPLIER: f64 = 2.0;
const PATCH_SIZE_OVERLAP_FLOOR: f64 = 3.0;
fn patch_size_overlap_multiplier(intrinsic_dim: usize) -> f64 {
let doubling = 2.0_f64.powi(i32::try_from(intrinsic_dim.max(1)).unwrap_or(i32::MAX));
PATCH_SIZE_OVERLAP_FLOOR.max(doubling)
}
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(d) * 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 smallest_principal_cosine: f64,
pub sign_resolution_budget: 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
}
}
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
}
pub(super) 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 sign_resolution_budget = combined_frame_resolution(
frame_angular_resolution(&chart_i.certificate),
frame_angular_resolution(&chart_j.certificate),
);
let smallest_principal_cosine = match a_mat.svd(false, false) {
Ok((_, sv, _)) => sv.iter().copied().fold(f64::INFINITY, f64::min),
Err(_) => 0.0,
};
let smallest_principal_cosine = if smallest_principal_cosine.is_finite() {
smallest_principal_cosine
} else {
0.0
};
let frame_nondegenerate = smallest_principal_cosine > sign_resolution_budget;
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,
smallest_principal_cosine,
sign_resolution_budget,
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 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::*;
use crate::manifold::tests_topology_fixtures::{
cylinder_strip, embedded_plane, mobius_strip, spherical_band, swiss_roll, torus,
};
#[test]
fn frame_resolution_is_the_tilt_that_leaks_the_measured_residual_2280() {
let pinned = ChartCertificate {
condition: 1.0,
leading_singular: 1.0,
smallest_captured_singular: 1.0,
captured_variance_fraction: 1.0,
min_projection_stretch: 1.0,
};
assert!(frame_angular_resolution(&pinned).abs() < 1e-15);
let unpinned = ChartCertificate {
captured_variance_fraction: 0.5,
..pinned
};
assert!((frame_angular_resolution(&unpinned) - 1.0).abs() < 1e-15);
let good = ChartCertificate {
captured_variance_fraction: 0.99,
..pinned
};
let sine = frame_angular_resolution(&good);
let leaked = sine * sine * 0.99;
assert!(
(leaked - 0.01).abs() < 1e-12,
"a tilt of the resolution must leak the measured residual: {leaked}"
);
let pair = combined_frame_resolution(sine, sine);
assert!(pair > sine && pair < 1.0, "{pair}");
let expected = 2.0 * sine * (1.0 - sine * sine).sqrt();
assert!((pair - expected).abs() < 1e-12, "{pair} vs {expected}");
assert!((combined_frame_resolution(0.9, 0.9) - 1.0).abs() < 1e-15);
}
#[test]
fn the_derived_sign_budget_refuses_edges_the_numerical_floor_admitted_2280() {
let z = torus(48, 20, 2.0, 0.8);
let config = LocalAtlasConfig::balanced(z.nrows(), 2);
let atlas = LocalAtlas::build(z.view(), config).expect("torus atlas builds");
let refused: Vec<&ChartTransition> = atlas
.transitions()
.iter()
.filter(|t| matches!(t.conditioning, TransitionConditioning::Degenerate))
.collect();
assert!(
!refused.is_empty(),
"the derived budget must bite on a torus cover of this coarseness"
);
for t in &refused {
assert!(
t.smallest_principal_cosine > 1.0e-6,
"every refused edge must be one the retired 1e-6 floor would have \
admitted, else the change is invisible: {}",
t.smallest_principal_cosine
);
assert!(
t.smallest_principal_cosine <= t.sign_resolution_budget,
"a refused edge must be refused BY the budget: {} vs {}",
t.smallest_principal_cosine,
t.sign_resolution_budget
);
}
assert!(
atlas.observed_signed_edges().len() < atlas.transitions().len(),
"the observed cocycle must be a strict subcomplex here"
);
}
#[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 = 40usize;
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);
assert!(
config.patch_size < blob_n,
"the fixture's premise: one patch ({}) must fit inside the blob ({blob_n}), or the \
blob center's neighborhood reaches the plane and certifies",
config.patch_size
);
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 = spherical_band(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);
}
}