Confirm that projection is Euclidean-equivariant
This commit is contained in:
parent
e61047cb86
commit
1e3505dd01
@ -490,6 +490,9 @@ pub mod irisawa {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use nalgebra::Vector3;
|
||||||
|
use std::f64::consts::FRAC_1_SQRT_2;
|
||||||
|
|
||||||
use super::{*, irisawa::realize_irisawa_hexlet};
|
use super::{*, irisawa::realize_irisawa_hexlet};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -617,6 +620,91 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn translation(u: Vector3<f64>) -> DMatrix<f64> {
|
||||||
|
const ELEMENT_DIM: usize = 5;
|
||||||
|
DMatrix::from_column_slice(ELEMENT_DIM, ELEMENT_DIM, &[
|
||||||
|
1.0, 0.0, 0.0, 0.0, u[0],
|
||||||
|
0.0, 1.0, 0.0, 0.0, u[1],
|
||||||
|
0.0, 0.0, 1.0, 0.0, u[2],
|
||||||
|
2.0*u[0], 2.0*u[1], 2.0*u[2], 1.0, u.norm_squared(),
|
||||||
|
0.0, 0.0, 0.0, 0.0, 1.0
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
// confirm that projection onto a configuration subspace is equivariant with
|
||||||
|
// respect to Euclidean motions
|
||||||
|
#[test]
|
||||||
|
fn proj_equivar_test() {
|
||||||
|
// find a pair of spheres that meet at 120°
|
||||||
|
const SCALED_TOL: f64 = 1.0e-12;
|
||||||
|
let gram = {
|
||||||
|
let mut gram_to_be = PartialMatrix::new();
|
||||||
|
gram_to_be.push_sym(0, 0, 1.0);
|
||||||
|
gram_to_be.push_sym(1, 1, 1.0);
|
||||||
|
gram_to_be.push_sym(0, 1, 0.5);
|
||||||
|
gram_to_be
|
||||||
|
};
|
||||||
|
let guess_orig = DMatrix::from_columns(&[
|
||||||
|
sphere(0.0, 0.0, 0.5, 1.0),
|
||||||
|
sphere(0.0, 0.0, -0.5, 1.0)
|
||||||
|
]);
|
||||||
|
let (config_orig, tangent_orig, success_orig, history_orig) = realize_gram(
|
||||||
|
&gram, guess_orig.clone(), &[],
|
||||||
|
SCALED_TOL, 0.5, 0.9, 1.1, 200, 110
|
||||||
|
);
|
||||||
|
assert_eq!(config_orig, guess_orig);
|
||||||
|
assert_eq!(success_orig, true);
|
||||||
|
assert_eq!(history_orig.scaled_loss.len(), 1);
|
||||||
|
|
||||||
|
// find another pair of spheres that meet at 120°. we'll think of this
|
||||||
|
// solution as a transformed version of the original one
|
||||||
|
let guess_tfm = {
|
||||||
|
let a = 0.5 * FRAC_1_SQRT_2;
|
||||||
|
DMatrix::from_columns(&[
|
||||||
|
sphere(a, 0.0, 7.0 + a, 1.0),
|
||||||
|
sphere(-a, 0.0, 7.0 - a, 1.0)
|
||||||
|
])
|
||||||
|
};
|
||||||
|
let (config_tfm, tangent_tfm, success_tfm, history_tfm) = realize_gram(
|
||||||
|
&gram, guess_tfm.clone(), &[],
|
||||||
|
SCALED_TOL, 0.5, 0.9, 1.1, 200, 110
|
||||||
|
);
|
||||||
|
assert_eq!(config_tfm, guess_tfm);
|
||||||
|
assert_eq!(success_tfm, true);
|
||||||
|
assert_eq!(history_tfm.scaled_loss.len(), 1);
|
||||||
|
|
||||||
|
// project a nudge to the tangent space of the solution variety at the
|
||||||
|
// original solution
|
||||||
|
let motion_orig = DVector::from_column_slice(&[0.0, 0.0, 1.0, 0.0]);
|
||||||
|
let motion_orig_proj = tangent_orig.proj(&motion_orig.as_view(), 0);
|
||||||
|
|
||||||
|
// project the equivalent nudge to the tangent space of the solution
|
||||||
|
// variety at the transformed solution
|
||||||
|
let motion_tfm = DVector::from_column_slice(&[FRAC_1_SQRT_2, 0.0, FRAC_1_SQRT_2, 0.0]);
|
||||||
|
let motion_tfm_proj = tangent_tfm.proj(&motion_tfm.as_view(), 0);
|
||||||
|
|
||||||
|
// take the transformation that sends the original solution to the
|
||||||
|
// transformed solution and apply it to the motion that the original
|
||||||
|
// solution makes in response to the nudge
|
||||||
|
const ELEMENT_DIM: usize = 5;
|
||||||
|
let rot = DMatrix::from_column_slice(ELEMENT_DIM, ELEMENT_DIM, &[
|
||||||
|
FRAC_1_SQRT_2, 0.0, -FRAC_1_SQRT_2, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0, 0.0, 0.0,
|
||||||
|
FRAC_1_SQRT_2, 0.0, FRAC_1_SQRT_2, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 0.0, 1.0
|
||||||
|
]);
|
||||||
|
let transl = translation(Vector3::new(0.0, 0.0, 7.0));
|
||||||
|
let motion_proj_tfm = transl * rot * motion_orig_proj;
|
||||||
|
|
||||||
|
// confirm that the projection of the nudge is equivariant. we loosen
|
||||||
|
// the comparison tolerance because the transformation seems to
|
||||||
|
// introduce some numerical error
|
||||||
|
const SCALED_TOL_TFM: f64 = 1.0e-9;
|
||||||
|
let tol_sq = ((guess_orig.nrows() * guess_orig.ncols()) as f64) * SCALED_TOL_TFM * SCALED_TOL_TFM;
|
||||||
|
assert!((motion_proj_tfm - motion_tfm_proj).norm_squared() < tol_sq);
|
||||||
|
}
|
||||||
|
|
||||||
// at the frozen indices, the optimization steps should have exact zeros,
|
// at the frozen indices, the optimization steps should have exact zeros,
|
||||||
// and the realized configuration should match the initial guess
|
// and the realized configuration should match the initial guess
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user