use super::*;
fn linear_crop(width: usize, height: usize) -> Vec<u8> {
let mut data = vec![0u8; width * height * 3];
for y in 0..height {
for x in 0..width {
let value = u8::try_from(2 * x + 3 * y).expect("crop kept below 256");
for channel in 0..3 {
data[(y * width + x) * 3 + channel] = value;
}
}
}
data
}
const FIXTURE_LANDMARKS: [Point; LANDMARK_COUNT] = [
Point::new(18.5, 16.0),
Point::new(41.0, 13.5),
Point::new(30.5, 25.0),
Point::new(21.0, 35.5),
Point::new(40.0, 33.0),
];
fn residual(
params: [f64; 4],
source: &[Point; LANDMARK_COUNT],
target: &[Point; LANDMARK_COUNT],
) -> f64 {
let [a, b, tx, ty] = params;
let mut total = 0.0;
for (s, t) in source.iter().zip(target.iter()) {
let (px, py) = (f64::from(s.x()), f64::from(s.y()));
let mapped_x = a * px - b * py + tx;
let mapped_y = b * px + a * py + ty;
let dx = mapped_x - f64::from(t.x());
let dy = mapped_y - f64::from(t.y());
total += dx * dx + dy * dy;
}
total
}
#[test]
fn arcface_template_matches_the_pinned_upstream_constants() {
let expected: [(f32, f32); LANDMARK_COUNT] = [
(38.2946, 51.6963),
(73.5318, 51.5014),
(56.0252, 71.7366),
(41.5493, 92.3655),
(70.7299, 92.2041),
];
for (index, (point, (x, y))) in ARCFACE_TEMPLATE.iter().zip(expected).enumerate() {
assert_eq!(
(point.x(), point.y()),
(x, y),
"template point {index} drifted from the pinned upstream value"
);
}
assert_eq!(TEMPLATE_SIZE, 112);
assert_eq!(TEMPLATE_BYTES, 112 * 112 * 3);
}
#[test]
fn exact_similarity_landmarks_recover_the_analytic_inverse() {
let (scale, theta) = (0.5f64, 0.3f64);
let (tx, ty) = (12.0f64, -7.0f64);
let (cos, sin) = (theta.cos() * scale, theta.sin() * scale);
let mut landmarks = [Point::new(0.0, 0.0); LANDMARK_COUNT];
for (slot, template) in landmarks.iter_mut().zip(ARCFACE_TEMPLATE.iter()) {
let (x, y) = (f64::from(template.x()), f64::from(template.y()));
*slot = Point::new(
(cos * x - sin * y + tx) as f32,
(sin * x + cos * y + ty) as f32,
);
}
let recovered = SimilarityTransform::estimate(&landmarks, &ARCFACE_TEMPLATE)
.expect("a non-degenerate similarity image is solvable");
assert!(
(recovered.scale() - 1.0 / scale).abs() < 1e-4,
"recovered scale {} is not 1/{scale}",
recovered.scale()
);
assert!(
(recovered.rotation() + theta).abs() < 1e-5,
"recovered rotation {} is not -{theta}",
recovered.rotation()
);
for (i, (landmark, template)) in landmarks.iter().zip(ARCFACE_TEMPLATE.iter()).enumerate() {
let (mx, my) = recovered.apply(*landmark);
assert!(
(mx - f64::from(template.x())).abs() < 2e-3 && (my - f64::from(template.y())).abs() < 2e-3,
"landmark {i} maps to ({mx}, {my}), not onto its template point"
);
}
}
#[test]
fn recovered_transform_is_the_least_squares_minimiser() {
let solved = SimilarityTransform::estimate(&FIXTURE_LANDMARKS, &ARCFACE_TEMPLATE)
.expect("the fixture landmarks are non-degenerate");
let params = [solved.a(), solved.b(), solved.tx(), solved.ty()];
let best = residual(params, &FIXTURE_LANDMARKS, &ARCFACE_TEMPLATE);
for (index, name) in ["a", "b", "tx", "ty"].into_iter().enumerate() {
for step in [-1e-3f64, 1e-3] {
let mut perturbed = params;
perturbed[index] += step;
let worse = residual(perturbed, &FIXTURE_LANDMARKS, &ARCFACE_TEMPLATE);
assert!(
worse > best,
"moving {name} by {step} did not increase the residual ({worse} vs {best}); the solved \
parameters are not the least-squares minimiser"
);
}
}
}
#[test]
fn bilinear_sampling_is_exact_on_an_affine_ramp() {
let (width, height) = (40usize, 30usize);
let data = linear_crop(width, height);
let crop = FaceCrop::new(&data, width, height).expect("geometry is valid");
let inverse = SimilarityTransform::new(1.0, 0.0, 3.25, 1.5);
let warped = warp_bilinear(crop, &inverse).expect("an identity-scaled inverse stays inside int");
let mut checked = 0usize;
for v in 0..TEMPLATE_SIZE {
for u in 0..TEMPLATE_SIZE {
if u + 4 >= width || v + 3 >= height {
continue;
}
let expected = u8::try_from(2 * u + 3 * v + 11).expect("ramp stays below 256");
let base = (v * TEMPLATE_SIZE + u) * 3;
assert_eq!(
&warped[base..base + 3],
&[expected, expected, expected],
"template pixel ({u}, {v}) is not the exact bilinear value of the ramp"
);
checked += 1;
}
}
assert!(checked > 500, "only {checked} pixels were inside the crop");
}
#[test]
fn taps_outside_the_crop_contribute_the_zero_border() {
let (width, height) = (20usize, 20usize);
let data = vec![200u8; width * height * 3];
let crop = FaceCrop::new(&data, width, height).expect("geometry is valid");
let landmarks = [
Point::new(8.0, 9.0),
Point::new(18.0, 9.0),
Point::new(13.0, 14.0),
Point::new(9.0, 19.0),
Point::new(17.0, 19.0),
];
let aligned = FaceAlign::to_template(crop, &landmarks).expect("solvable");
let pixels = aligned.pixels();
assert_eq!(
&pixels[0..3],
&[0, 0, 0],
"the top-left corner is not the border"
);
let last = TEMPLATE_BYTES - 3;
assert_eq!(
&pixels[last..],
&[0, 0, 0],
"the bottom-right corner is not the border"
);
let centre = ((TEMPLATE_SIZE / 2) * TEMPLATE_SIZE + TEMPLATE_SIZE / 2) * 3;
assert_eq!(
&pixels[centre..centre + 3],
&[200, 200, 200],
"the template centre should sample the crop's flat interior"
);
}
#[test]
fn inverse_round_trips_a_point() {
let forward = SimilarityTransform::new(1.7875, -0.1252, 5.1247, 24.1454);
let back = forward.inverse().expect("a nonzero scale is invertible");
let p = Point::new(11.25, -3.5);
let (fx, fy) = forward.apply(p);
let mapped = Point::new(fx as f32, fy as f32);
let (rx, ry) = back.apply(mapped);
assert!(
(rx - f64::from(p.x())).abs() < 1e-4 && (ry - f64::from(p.y())).abs() < 1e-4,
"round trip landed at ({rx}, {ry}), not ({}, {})",
p.x(),
p.y()
);
}
#[test]
fn a_zero_scale_transform_has_no_inverse() {
assert!(
SimilarityTransform::new(0.0, 0.0, 5.0, 5.0)
.inverse()
.is_none()
);
}
#[test]
fn estimate_itself_rejects_landmarks_with_no_spread() {
let coincident = [Point::new(8.0, 8.0); LANDMARK_COUNT];
let error = SimilarityTransform::estimate(&coincident, &ARCFACE_TEMPLATE)
.expect_err("five coincident points determine no similarity");
assert!(
matches!(error, Error::DegenerateLandmarks(payload) if payload.spread() == 0.0),
"expected DegenerateLandmarks(0.0) from `estimate` itself, got {error:?}"
);
}
#[test]
fn estimate_refuses_a_target_with_no_spread() {
let flat_target = [Point::new(11.0, -4.0); LANDMARK_COUNT];
let error = SimilarityTransform::estimate(&FIXTURE_LANDMARKS, &flat_target)
.expect_err("a target with no spread collapses the plane onto a point");
assert!(
matches!(&error, Error::NonInvertibleTransform(payload) if payload.scale() == 0.0),
"expected NonInvertibleTransform(0) from `estimate` itself, got {error:?}"
);
assert!(
!error.to_string().contains("landmark"),
"a well-spread source must not be reported as landmarks with no spread, got {error}"
);
}
const UNDERFLOWING_SOURCE: [Point; LANDMARK_COUNT] = [
Point::new(f32::MAX, 0.0),
Point::new(-f32::MAX, 0.0),
Point::new(f32::from_bits(1), 0.0),
Point::new(0.0, 0.0),
Point::new(0.0, 0.0),
];
fn underflowing_target(x: f32) -> [Point; LANDMARK_COUNT] {
[
Point::new(0.0, 0.0),
Point::new(0.0, 0.0),
Point::new(x, 0.0),
Point::new(0.0, 0.0),
Point::new(0.0, 0.0),
]
}
#[test]
fn estimate_refuses_a_solve_whose_determinant_underflows() {
const SCALE: f64 = 6.1049899689109305e-168;
let target = underflowing_target(f32::from_bits(1));
let error = SimilarityTransform::estimate(&UNDERFLOWING_SOURCE, &target)
.expect_err("the minimiser has no inverse in `cv2.warpAffine`'s arithmetic");
assert!(
matches!(&error, Error::NonInvertibleTransform(payload) if payload.scale() == SCALE),
"expected NonInvertibleTransform({SCALE:e}) from `estimate` itself, got {error:?}"
);
assert_ne!(SCALE, 0.0, "a zero scale would be the already-known case");
assert!(
(1.0 / SCALE).is_finite(),
"the inverse scale is 1.6e167 — the transform IS invertible, just not there"
);
assert_eq!(
SCALE * SCALE,
0.0,
"`a·a + b·b` underflows, which is what `cv2.warpAffine` divides by"
);
assert!(
SimilarityTransform::new(SCALE, 0.0, 0.0, 0.0)
.inverse()
.is_none(),
"the value `estimate` now refuses is exactly the value `inverse` refuses"
);
}
#[test]
fn the_producer_and_the_inverse_ask_one_question() {
const SCALE: f64 = 4.3566665269975455e-155;
const DETERMINANT: f64 = 1.898054322746085e-309;
assert!(
DETERMINANT > 0.0 && !DETERMINANT.is_normal() && !(1.0 / DETERMINANT).is_finite(),
"the separating value must be one the two spellings disagree about"
);
let target = underflowing_target(1e-32);
let error = SimilarityTransform::estimate(&UNDERFLOWING_SOURCE, &target)
.expect_err("a subnormal determinant has no usable reciprocal either");
assert!(
matches!(&error, Error::NonInvertibleTransform(payload) if payload.scale() == SCALE),
"expected NonInvertibleTransform({SCALE:e}), got {error:?}"
);
assert_eq!(
SCALE * SCALE,
DETERMINANT,
"the refused scale is the one whose determinant is subnormal"
);
for (a, b) in [
(SCALE, 0.0),
(6.1049899689109305e-168, 0.0),
(0.0, 0.0),
(1.7875, -0.1252),
(f64::MAX, f64::MAX),
(f64::NAN, 0.0),
] {
assert_eq!(
reciprocal_determinant(a, b).is_some(),
SimilarityTransform::new(a, b, 0.0, 0.0).inverse().is_some(),
"the producer's predicate and `inverse` disagree at a={a:e} b={b:e}"
);
}
}
#[test]
fn a_transform_that_does_not_invert_reports_its_own_scale_not_a_landmark_spread() {
const SUBNORMAL: f64 = f64::from_bits(1);
let collapsed = SimilarityTransform::new(SUBNORMAL, 0.0, 1.0, 2.0);
assert!(collapsed.inverse().is_none(), "the witness has no inverse");
assert_eq!(collapsed.scale(), SUBNORMAL, "and its scale is not zero");
assert_eq!(
collapsed.scale() as f32,
0.0,
"and `f32` would render it as the zero this payload must not report"
);
let error = collapsed
.checked_inverse()
.expect_err("a transform with no inverse cannot align anything");
assert!(
matches!(&error, Error::NonInvertibleTransform(payload) if payload.scale() == SUBNORMAL),
"the payload must carry the scale that collapsed, got {error:?}"
);
let message = error.to_string();
assert!(
message.contains("5e-324"),
"the message must name the collapsed scale, got {message:?}"
);
assert!(
!message.contains("landmark"),
"the landmarks are spread; blaming them is the falsehood, got {message:?}"
);
let flat_target = [Point::new(11.0, -4.0); LANDMARK_COUNT];
let error = SimilarityTransform::estimate(&FIXTURE_LANDMARKS, &flat_target)
.expect_err("a zero-scale minimiser is refused where it is produced");
assert!(
matches!(&error, Error::NonInvertibleTransform(payload) if payload.scale() == 0.0),
"expected NonInvertibleTransform(0), got {error:?}"
);
assert!(
!error.to_string().contains("landmark"),
"a well-spread source must not be reported as landmarks with no spread"
);
}
#[test]
fn coincident_landmarks_are_rejected() {
let data = vec![0u8; 16 * 16 * 3];
let crop = FaceCrop::new(&data, 16, 16).expect("geometry is valid");
let landmarks = [Point::new(8.0, 8.0); LANDMARK_COUNT];
let error = FaceAlign::to_template(crop, &landmarks).expect_err("no transform is determined");
assert!(
matches!(error, Error::DegenerateLandmarks(payload) if payload.spread() == 0.0),
"expected DegenerateLandmarks, got {error:?}"
);
}
#[test]
fn a_non_finite_landmark_is_rejected_by_index() {
let data = vec![0u8; 16 * 16 * 3];
let crop = FaceCrop::new(&data, 16, 16).expect("geometry is valid");
let mut landmarks = FIXTURE_LANDMARKS;
landmarks[3] = Point::new(f32::NAN, 4.0);
let error = FaceAlign::to_template(crop, &landmarks).expect_err("NaN is not a landmark");
assert!(
matches!(error, Error::NonFiniteLandmark(payload)
if payload.index() == 3 && payload.set() == LandmarkSet::Source),
"expected NonFiniteLandmark(source, 3), got {error:?}"
);
}
#[test]
fn estimate_rejects_a_non_finite_target_and_names_the_set_it_came_from() {
let mut target = ARCFACE_TEMPLATE;
target[2] = Point::new(56.0252, f32::INFINITY);
let error = SimilarityTransform::estimate(&FIXTURE_LANDMARKS, &target)
.expect_err("an infinite target coordinate determines no transform");
assert!(
matches!(error, Error::NonFiniteLandmark(payload)
if payload.index() == 2 && payload.set() == LandmarkSet::Target),
"expected NonFiniteLandmark(target, 2), got {error:?}"
);
let mut source = FIXTURE_LANDMARKS;
source[2] = Point::new(30.5, f32::NAN);
let from_source = SimilarityTransform::estimate(&source, &ARCFACE_TEMPLATE)
.expect_err("a NaN source coordinate determines no transform");
assert!(
matches!(from_source, Error::NonFiniteLandmark(payload)
if payload.index() == 2 && payload.set() == LandmarkSet::Source),
"expected NonFiniteLandmark(source, 2), got {from_source:?}"
);
assert_ne!(
LandmarkSet::Source,
LandmarkSet::Target,
"the two sides must not compare equal, or naming them proves nothing"
);
}
#[test]
fn a_solved_transform_with_a_non_finite_parameter_is_never_handed_out() {
for (index, parameter) in [
TransformParameter::A,
TransformParameter::B,
TransformParameter::Tx,
TransformParameter::Ty,
]
.into_iter()
.enumerate()
{
let mut params = [1.0f64, 0.5, 2.0, 3.0];
params[index] = f64::NAN;
let [a, b, tx, ty] = params;
let error =
SimilarityTransform::checked(a, b, tx, ty).expect_err("a NaN parameter is not a transform");
assert!(
matches!(error, Error::NonFiniteTransform(payload) if payload.parameter() == parameter),
"expected NonFiniteTransform({parameter}), got {error:?}"
);
}
assert!(SimilarityTransform::checked(1.0, 0.5, 2.0, 3.0).is_ok());
}
#[test]
fn an_inverse_is_refused_when_any_parameter_is_non_finite() {
assert!(
SimilarityTransform::new(1.0, 0.0, f64::NAN, 0.0)
.inverse()
.is_none(),
"a NaN translation must not invert to Some"
);
assert!(
SimilarityTransform::new(1.0, 0.0, 0.0, f64::NEG_INFINITY)
.inverse()
.is_none(),
"an infinite translation must not invert to Some"
);
assert!(
SimilarityTransform::new(f64::NAN, 0.0, 1.0, 2.0)
.inverse()
.is_none(),
"the rotation side must still be refused"
);
for infinite in [f64::INFINITY, f64::NEG_INFINITY] {
assert!(
SimilarityTransform::new(infinite, 0.0, 1.0, 2.0)
.inverse()
.is_none(),
"an infinite rotation coefficient has no inverse"
);
assert!(
SimilarityTransform::new(0.0, infinite, 1.0, 2.0)
.inverse()
.is_none(),
"the same on the other rotation coefficient"
);
}
assert!(
inverse_rotation(f64::from_bits(1), 0.0).is_none(),
"the smallest subnormal scale is outside the band `inverse` declares"
);
const IN_BAND: f64 = 2e-154;
let determinant = IN_BAND * IN_BAND;
assert!(
determinant.is_normal() && (1.0 / determinant).is_normal(),
"the witness's rotation must be INSIDE the band, or it proves nothing about the exit check"
);
let (rotation, _) = inverse_rotation(IN_BAND, 0.0).expect("an in-band rotation inverts");
assert_eq!(rotation, 5e153, "and its inverse coefficient is finite");
assert!(
SimilarityTransform::new(IN_BAND, 0.0, 1e200, 0.0)
.inverse()
.is_none(),
"an inverse translation that overflows is still no inverse, and only the check on the way \
OUT can say so"
);
assert!(
SimilarityTransform::new(1.7875, -0.1252, 5.1247, 24.1454)
.inverse()
.is_some(),
"a finite invertible transform must still invert"
);
}
#[test]
fn cv_round_breaks_ties_to_even_and_refuses_what_leaves_int() {
for (value, want) in [
(0.5f64, 0i32),
(1.5, 2),
(2.5, 2),
(3.5, 4),
(-0.5, 0),
(-1.5, -2),
(-2.5, -2),
(0.49, 0),
(0.51, 1),
(-0.51, -1),
] {
assert_eq!(
cv_round(value),
Some(want),
"cvRound({value}) must be {want} (nearest, ties to even)"
);
}
for out in [1e300, -1e300, f64::INFINITY, f64::NEG_INFINITY, f64::NAN] {
assert_eq!(cv_round(out), None, "{out} is outside `int`");
}
assert_eq!(cv_round(f64::from(i32::MAX)), Some(i32::MAX));
assert_eq!(cv_round(f64::from(i32::MIN)), Some(i32::MIN));
assert_eq!(cv_round(f64::from(i32::MAX) + 1.0), None);
assert_eq!(cv_round(f64::from(i32::MIN) - 1.0), None);
}
#[test]
fn the_fixed_point_pixel_cast_rounds_half_up_and_saturates() {
let one = 1i64 << REMAP_COEF_BITS;
let half = 1i64 << (REMAP_COEF_BITS - 1);
assert_eq!(fixed_point_to_u8(0), 0);
assert_eq!(fixed_point_to_u8(half - 1), 0);
assert_eq!(fixed_point_to_u8(half), 1, "an exact half must round UP");
assert_eq!(fixed_point_to_u8(one + half), 2, "and so must the next one");
assert_eq!(fixed_point_to_u8(255 * one), 255);
assert_eq!(fixed_point_to_u8(256 * one), 255, "must saturate, not wrap");
assert_eq!(fixed_point_to_u8(-one), 0, "must clamp, not wrap");
}
#[test]
fn the_saturating_weight_table_cell_is_invisible_for_u8_sources() {
for v00 in 0..=255i64 {
for v11 in 0..=255i64 {
assert_eq!(
fixed_point_to_u8(v00 * 32768),
fixed_point_to_u8(v00 * 32767 + v11),
"taps ({v00}, {v11}) separate the exact weight table from OpenCV's saturated one"
);
}
}
for fy in 0..INTER_TAB_SIZE {
for fx in 0..INTER_TAB_SIZE {
let weights = bilinear_weights(fx, fy);
assert!(
weights.iter().all(|w| *w >= 0),
"weight table cell ({fx}, {fy}) has a negative entry: {weights:?}"
);
assert_eq!(
weights.iter().sum::<i64>(),
1 << REMAP_COEF_BITS,
"weight table cell ({fx}, {fy}) does not sum to one unit: {weights:?}"
);
}
}
}
#[test]
fn crop_geometry_is_validated() {
let data = vec![0u8; 12];
assert!(matches!(
FaceCrop::new(&data, 0, 4).expect_err("a zero axis is unusable"),
Error::CropDimensions(_)
));
let error = FaceCrop::new(&data, 3, 3).expect_err("9 pixels need 27 bytes");
assert!(
matches!(error, Error::CropDataLength(payload) if payload.got() == 12 && payload.expected() == 27),
"expected CropDataLength(12, 27), got {error:?}"
);
assert!(FaceCrop::new(&data, 2, 2).is_ok());
}
#[test]
fn the_tap_is_exact_rather_than_saturated_into_the_crop() {
const WIDE: usize = 40_000;
let mut row = vec![0u8; WIDE * 3];
row[32_767 * 3] = 200; row[33_000 * 3] = 25; let mut out = [0u8; 3];
sample_fixed_point(
&row,
WIDE,
1,
33_000 << INTER_BITS, 0,
&mut out,
);
assert_eq!(
out[0], 25,
"the exact tap must read the column asked for, not the one `i16` saturation aliases it onto"
);
let mut widest = vec![9u8; MAX_CROP_AXIS * 3];
widest[(MAX_CROP_AXIS - 1) * 3] = 111;
for column in [
i64::from(i16::MAX) - 1,
i64::from(i16::MAX),
i64::from(i16::MAX) + 5_000,
i64::from(i16::MIN),
i64::from(i16::MIN) - 5_000,
] {
let mut border = [7u8; 3];
sample_fixed_point(
&widest,
MAX_CROP_AXIS,
1,
column << INTER_BITS,
0,
&mut border,
);
assert_eq!(
border, [0u8; 3],
"a tap at {column} is outside the widest admitted crop and must read the border"
);
}
let data = vec![0u8; WIDE * 2 * 3];
let error = FaceCrop::new(&data, WIDE, 2).expect_err("wider than the fixed-point tap domain");
assert!(
matches!(error, Error::CropDimensions(p) if p.width() == WIDE && p.height() == 2),
"expected CropDimensions({WIDE}, 2), got {error:?}"
);
let tall = vec![0u8; 2 * WIDE * 3];
assert!(
matches!(
FaceCrop::new(&tall, 2, WIDE).expect_err("the bound is per axis"),
Error::CropDimensions(_)
),
"the height axis is bounded too"
);
assert_eq!(MAX_CROP_AXIS, i16::MAX as usize - 1);
let admitted = vec![0u8; MAX_CROP_AXIS * 3];
assert!(
FaceCrop::new(&admitted, MAX_CROP_AXIS, 1).is_ok(),
"the widest admitted crop must still be admitted"
);
let refused = vec![0u8; (MAX_CROP_AXIS + 1) * 3];
assert!(
FaceCrop::new(&refused, MAX_CROP_AXIS + 1, 1).is_err(),
"one pixel past the bound must be refused"
);
let mut last = [7u8; 3];
sample_fixed_point(
&widest,
MAX_CROP_AXIS,
1,
(MAX_CROP_AXIS as i64 - 1) << INTER_BITS,
0,
&mut last,
);
assert_eq!(
last[0], 111,
"the last column of the widest admitted crop must still be readable"
);
}
#[test]
fn from_template_pixels_requires_the_exact_length() {
let exact = vec![0u8; TEMPLATE_BYTES];
let short = vec![0u8; TEMPLATE_BYTES - 1];
assert!(AlignedFace::from_template_pixels(&exact).is_ok());
let error =
AlignedFace::from_template_pixels(&short).expect_err("a short buffer is not a template");
assert!(
matches!(error, Error::CropDataLength(payload) if payload.expected() == TEMPLATE_BYTES),
"expected CropDataLength, got {error:?}"
);
assert!(
AlignedFace::from_template_pixels(&exact)
.expect("valid")
.transform()
.is_none(),
"pixels the caller aligned elsewhere must carry no transform"
);
}
#[test]
fn aligning_records_the_transform_it_used() {
let data = vec![7u8; 64 * 48 * 3];
let crop = FaceCrop::new(&data, 64, 48).expect("geometry is valid");
let aligned = FaceAlign::to_template(crop, &FIXTURE_LANDMARKS).expect("solvable");
let transform = aligned
.transform()
.expect("alignment records its transform");
let solved =
SimilarityTransform::estimate(&FIXTURE_LANDMARKS, &ARCFACE_TEMPLATE).expect("solvable");
assert_eq!(*transform, solved);
assert_eq!(aligned.width(), TEMPLATE_SIZE);
assert_eq!(aligned.height(), TEMPLATE_SIZE);
}
const WITNESS: [Point; LANDMARK_COUNT] = [
Point::new(48.073_643, 97.059_7),
Point::new(103.453_03, 115.633_26),
Point::new(68.999_21, 127.547_72),
Point::new(37.211_536, 152.986_66),
Point::new(82.014_03, 169.196_21),
];
const SKIMAGE_OPENBLAS: [f64; 6] = [
0.628_153_825_248_663_7,
0.202_666_161_104_246_54,
-13.507_243_940_956_57,
-0.202_666_161_104_246_54,
0.628_153_825_248_663_7,
2.451_227_246_254_319_4,
];
const SKIMAGE_ACCELERATE: [f64; 6] = [
0.628_153_890_096_049_4,
0.202_666_202_037_496_08,
-13.507_253_770_385_248,
-0.202_666_205_667_098_56,
0.628_153_970_067_602_8,
2.451_211_088_017_999,
];
fn invert_2x3(m: [f64; 6]) -> [f64; 6] {
let d = m[0] * m[4] - m[1] * m[3];
let d = if d == 0.0 { 0.0 } else { 1.0 / d };
let (n0, n1, n3, n4) = (m[4] * d, m[1] * -d, m[3] * -d, m[0] * d);
[
n0,
n1,
-n0 * m[2] - n1 * m[5],
n3,
n4,
-n3 * m[2] - n4 * m[5],
]
}
fn coordinate_divergence(left: [f64; 6], right: [f64; 6]) -> usize {
let (a, b) = (
SourceGrid::new(invert_2x3(left)).expect("a face-shaped matrix stays inside int"),
SourceGrid::new(invert_2x3(right)).expect("a face-shaped matrix stays inside int"),
);
(0..TEMPLATE_SIZE)
.map(|v| {
let (oa, ob) = (a.row_origin(v), b.row_origin(v));
(0..TEMPLATE_SIZE)
.filter(|&u| a.at(oa, u) != b.at(ob, u))
.count()
})
.sum()
}
#[test]
fn the_solve_diverges_from_skimage_by_less_than_skimage_diverges_from_itself() {
let solved = SimilarityTransform::estimate(&WITNESS, &ARCFACE_TEMPLATE)
.expect("the witness landmarks are non-degenerate");
let inverse = solved.inverse().expect("a solvable witness inverts");
assert_eq!(
invert_2x3(solved.matrix()),
inverse.matrix(),
"the test's general inversion must reproduce the production similarity one"
);
assert_eq!(
coordinate_divergence(solved.matrix(), SKIMAGE_OPENBLAS),
10,
"the solve's distance from `skimage` under OpenBLAS"
);
assert_eq!(
coordinate_divergence(solved.matrix(), SKIMAGE_ACCELERATE),
5,
"the solve's distance from the SAME `skimage` under Accelerate"
);
assert_eq!(
coordinate_divergence(SKIMAGE_OPENBLAS, SKIMAGE_ACCELERATE),
15,
"two correct builds of the reference disagree with EACH OTHER by more than \
this module disagrees with either; there is no single matrix to be exact against"
);
let nearest = SimilarityTransform::new(
SKIMAGE_ACCELERATE[0],
-SKIMAGE_ACCELERATE[1],
SKIMAGE_ACCELERATE[2],
SKIMAGE_ACCELERATE[5],
);
assert_ne!(
nearest.matrix(),
SKIMAGE_ACCELERATE,
"the Accelerate reference was expected to carry a shear this type cannot hold"
);
}
#[test]
fn the_divergence_counts_are_sensitive_to_the_matrix_they_measure() {
let solved = SimilarityTransform::estimate(&WITNESS, &ARCFACE_TEMPLATE).expect("solvable");
for m in [solved.matrix(), SKIMAGE_OPENBLAS, SKIMAGE_ACCELERATE] {
assert_eq!(
coordinate_divergence(m, m),
0,
"a matrix cannot differ from itself"
);
}
assert_eq!(
coordinate_divergence(SKIMAGE_OPENBLAS, SKIMAGE_OPENBLAS),
0,
"tracking one build would zero its count"
);
assert_eq!(
coordinate_divergence(SKIMAGE_OPENBLAS, SKIMAGE_ACCELERATE),
15,
"and would leave the other one untouched"
);
let mut moved = solved.matrix();
moved[2] += 1e-6;
assert_ne!(
coordinate_divergence(moved, SKIMAGE_OPENBLAS),
coordinate_divergence(solved.matrix(), SKIMAGE_OPENBLAS),
"a translation move the size of the measured divergence must be visible in the count"
);
}
#[test]
fn a_fraction_below_the_five_bit_half_step_takes_the_pure_left_pixel() {
const FRACTION: f64 = 0.015;
let (width, height) = (4usize, 2usize);
let mut data = vec![255u8; width * height * 3];
for y in 0..height {
for channel in 0..3 {
data[(y * width) * 3 + channel] = 0;
}
}
let crop = FaceCrop::new(&data, width, height).expect("geometry is valid");
let warped = warp_bilinear(crop, &SimilarityTransform::new(1.0, 0.0, FRACTION, 0.0))
.expect("a unit-scale translation stays inside int");
assert_eq!(
warped[0], 0,
"template pixel (0, 0) sampled a 0-to-255 edge at fraction {FRACTION} (under the 1/64 \
half-step) and got {}, where cv2.warpAffine's 5-bit INTER_LINEAR quantises the fraction to 0 \
and takes the pure left pixel",
warped[0]
);
let u3 = 3 * 3;
assert_eq!(
warped[u3], 255,
"template pixel (3, 0) got {}, where OpenCV's quantised fraction 0 takes source column 3 \
whole and never reaches the border",
warped[u3]
);
}
const CANCELLING_LANDMARKS: [Point; LANDMARK_COUNT] = [
Point::new(108.922_34, 130.0),
Point::new(128.855_71, 130.0),
Point::new(174.0, 130.0),
Point::new(131.146_21, 130.0),
Point::new(107.075_73, 130.0),
];
#[test]
fn opposite_coordinate_saturations_must_not_cancel_into_a_valid_tap() {
const SIDE: usize = 256;
let mut data = vec![0u8; SIDE * SIDE * 3];
data[..3].copy_from_slice(&[200, 201, 202]); let crop = FaceCrop::new(&data, SIDE, SIDE).expect("geometry is valid");
let transform = SimilarityTransform::estimate(&CANCELLING_LANDMARKS, &ARCFACE_TEMPLATE)
.expect("finite, spread landmarks solve");
let inverse = transform
.inverse()
.expect("a finite nonzero scale has a finite inverse");
let m = inverse.matrix();
let (source_x, source_y) = (m[0] + m[2], m[3] + m[5]);
assert!(
source_x < -1.8e9 && source_y > 7.6e7,
"the witness must map destination (1,0) far outside the crop, got ({source_x:e}, {source_y:e})"
);
let outcome = FaceAlign::to_template(crop, &CANCELLING_LANDMARKS);
let sampled = outcome
.as_ref()
.ok()
.map(|face| [face.pixels()[3], face.pixels()[4], face.pixels()[5]]);
let error = match outcome {
Err(error) => error,
Ok(_) => panic!(
"destination (1,0) inverse-maps to ({source_x:e}, {source_y:e}) — border — but the split \
terms saturated to `i32::MIN` and `i32::MAX` and cancelled; it sampled {sampled:?}, which \
is the crop's own pixel (0,0)"
),
};
assert!(
matches!(&error, Error::CoordinateOverflow(_)),
"expected CoordinateOverflow, got {error:?}"
);
let message = error.to_string();
assert!(
message.contains("outside the `int` domain"),
"the message must name the domain that was left, got {message:?}"
);
let error = SourceGrid::new(m)
.err()
.expect("this map does not fit in `int`");
assert!(
matches!(&error, Error::CoordinateOverflow(p) if p.term() != CoordinateTerm::Sum),
"a term leaves `int` before any sum does, got {error:?}"
);
let at_the_boundary = f64::from(i32::MAX) / AB_SCALE;
let error = SourceGrid::new([0.0, 0.0, at_the_boundary, 0.0, 0.0, 0.0])
.err()
.expect("`i32::MAX + round_delta` is not an `int`");
assert!(
matches!(
&error,
Error::CoordinateOverflow(p)
if p.term() == CoordinateTerm::RowOrigin
&& p.axis() == CoordinateAxis::X
&& p.value() == f64::from(i32::MAX) + f64::from(ROUND_DELTA)
),
"expected the fold past `i32::MAX` to be reported at 2147483663, got {error:?}"
);
assert!(
SourceGrid::new([
0.0,
0.0,
(f64::from(i32::MAX) - f64::from(ROUND_DELTA)) / AB_SCALE,
0.0,
0.0,
0.0
])
.is_ok(),
"a row origin that folds to exactly `i32::MAX` is inside the domain"
);
let column = f64::from(i32::MAX) * 0.94 / (111.0 * AB_SCALE);
let row = f64::from(i32::MAX) * 0.5 / AB_SCALE;
let error = SourceGrid::new([column, 0.0, row, 0.0, 0.0, 0.0])
.err()
.expect("two representable terms whose sum is not");
assert!(
matches!(
&error,
Error::CoordinateOverflow(p)
if p.term() == CoordinateTerm::Sum
&& p.axis() == CoordinateAxis::X
&& p.value() > f64::from(i32::MAX)
),
"expected a Sum overflow on the horizontal coordinate, got {error:?}"
);
}
#[test]
fn an_out_of_band_rotation_has_no_inverse_by_declaration() {
assert!(
SimilarityTransform::new(f64::MAX, f64::MAX, 0.0, 0.0)
.inverse()
.is_none(),
"out of band, the inverse is undefined by declaration — a `Some` here is a rescue, and every \
rescue this module tried was itself met by the next value outside its enumeration"
);
}
struct Xorshift(u64);
impl Xorshift {
fn next(&mut self) -> u64 {
let mut x = self.0;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
self.0 = x;
x
}
fn bits_f32(&mut self) -> f32 {
f32::from_bits(self.next() as u32)
}
fn unit(&mut self) -> f64 {
(self.next() >> 11) as f64 / (1u64 << 53) as f64
}
fn choose<T: Copy>(&mut self, values: &[T]) -> T {
values[(self.next() as usize) % values.len()]
}
}
struct SweepTally {
sets: u64,
ok: u64,
degenerate: u64,
non_invertible: u64,
non_finite_transform: u64,
determinant_min: f64,
determinant_max: f64,
}
impl SweepTally {
fn new() -> Self {
Self {
sets: 0,
ok: 0,
degenerate: 0,
non_invertible: 0,
non_finite_transform: 0,
determinant_min: f64::INFINITY,
determinant_max: 0.0,
}
}
fn feed(
&mut self,
source: &[Point; LANDMARK_COUNT],
target: &[Point; LANDMARK_COUNT],
arm: &str,
index: usize,
) {
let finite =
|set: &[Point; LANDMARK_COUNT]| set.iter().all(|p| p.x().is_finite() && p.y().is_finite());
if !finite(source) || !finite(target) {
return;
}
self.sets += 1;
let solved = match SimilarityTransform::estimate(source, target) {
Ok(solved) => solved,
Err(Error::DegenerateLandmarks(_)) => {
self.degenerate += 1;
return;
}
Err(Error::NonInvertibleTransform(_)) => {
self.non_invertible += 1;
return;
}
Err(Error::NonFiniteTransform(_)) => {
self.non_finite_transform += 1;
return;
}
Err(other) => panic!("{arm}#{index}: unexpected {other:?}"),
};
self.ok += 1;
let (a, b) = (solved.a(), solved.b());
for (name, value) in [("a", a), ("b", b), ("tx", solved.tx()), ("ty", solved.ty())] {
assert!(
value.is_finite(),
"{arm}#{index}: solved `{name}` is {value:e}"
);
}
assert!(
(a, b) != (0.0, 0.0),
"{arm}#{index}: the solve collapsed the plane onto a point, which only a target with no \
spread should reach"
);
let determinant = a * a + b * b;
let reciprocal = 1.0 / determinant;
assert!(
determinant.is_normal() && reciprocal.is_normal(),
"{arm}#{index}: `estimate` returned a={a:e} b={b:e} with a²+b²={determinant:e} \
(1/D={reciprocal:e}), outside the band its own postcondition is supposed to enforce"
);
self.determinant_min = self.determinant_min.min(determinant);
self.determinant_max = self.determinant_max.max(determinant);
let inverted = solved.inverse().unwrap_or_else(|| {
panic!("{arm}#{index}: a={a:e} b={b:e} is in band and still did not invert")
});
for (name, value) in [
("a", inverted.a()),
("b", inverted.b()),
("tx", inverted.tx()),
("ty", inverted.ty()),
] {
assert!(
value.is_finite(),
"{arm}#{index}: inverse `{name}` is {value:e}"
);
}
inverted.inverse().unwrap_or_else(|| {
panic!(
"{arm}#{index}: a={a:e} b={b:e} solved, inverted, and the inverse did not invert — the \
closure `estimate`'s postcondition is over"
)
});
}
}
fn centred_template() -> [(f64, f64); LANDMARK_COUNT] {
let (cx, cy) = centroid(&ARCFACE_TEMPLATE);
ARCFACE_TEMPLATE.map(|p| (f64::from(p.x()) - cx, f64::from(p.y()) - cy))
}
#[test]
fn the_invertibility_postcondition_refuses_nothing_this_sweep_constructs() {
let mut rng = Xorshift(0x9E37_79B9_7F4A_7C15);
let mut tally = SweepTally::new();
let point = |x: f32, y: f32| Point::new(x, y);
let origin = [point(0.0, 0.0); LANDMARK_COUNT];
for index in 0..20_000 {
let mut source = origin;
for slot in &mut source {
*slot = point(rng.bits_f32(), rng.bits_f32());
}
tally.feed(&source, &ARCFACE_TEMPLATE, "randbits-source", index);
}
for index in 0..15_000 {
let mut source = origin;
let mut target = origin;
for slot in source.iter_mut().chain(target.iter_mut()) {
*slot = point(rng.bits_f32(), rng.bits_f32());
}
tally.feed(&source, &target, "randbits-both", index);
}
const MAGNITUDES: [f32; 12] = [
1.4e-45, 1e-44, 1e-40, 1.17e-38, 1e-30, 1e-10, 1.0, 1e3, 3.2767e4, 1e10, 1e30, 3.4e38,
];
let mut index = 0usize;
for magnitude in MAGNITUDES {
for sign in [1.0f32, -1.0] {
let base = sign * magnitude;
let step = |n: i32| {
let mut value = base;
for _ in 0..n.abs() {
value = if n > 0 {
value.next_up()
} else {
value.next_down()
};
}
value
};
for k in [1i32, 2, 3, 7, 100] {
let spread = [
point(base, base),
point(step(k), base),
point(base, step(k)),
point(step(-k), step(k)),
point(step(k), step(-k)),
];
tally.feed(&spread, &ARCFACE_TEMPLATE, "ulp-spread", index);
let collinear = [
point(base, base),
point(step(k), base),
point(step(2 * k), base),
point(step(3 * k), base),
point(step(4 * k), base),
];
tally.feed(&collinear, &ARCFACE_TEMPLATE, "collinear", index);
let four_plus_one = [
point(base, base),
point(base, base),
point(base, base),
point(base, base),
point(step(k), step(k)),
];
tally.feed(&four_plus_one, &ARCFACE_TEMPLATE, "four-plus-one", index);
index += 1;
}
let huge_and_tiny = [
point(base, base),
point(1.4e-45, 0.0),
point(0.0, 1.4e-45),
point(-1.4e-45, 0.0),
point(0.0, -1.4e-45),
];
tally.feed(&huge_and_tiny, &ARCFACE_TEMPLATE, "huge-and-tiny", index);
let mixed = [
point(base, base),
point(-base, -base),
point(-base, base),
point(base, -base),
point(-base, -base),
];
tally.feed(&mixed, &ARCFACE_TEMPLATE, "mixed-signs", index);
index += 1;
}
}
let centred = centred_template();
index = 0;
for scale in [1e-3f64, 1.0, 1e3, 1e6] {
for degrees in [0.0f64, 45.0, 89.999, 90.0, 90.001, 135.0, 180.0, 270.0] {
let (sin, cos) = degrees.to_radians().sin_cos();
let mut rotated = origin;
for (slot, (x, y)) in rotated.iter_mut().zip(centred) {
*slot = point(
((cos * x - sin * y) * scale) as f32,
((sin * x + cos * y) * scale) as f32,
);
}
tally.feed(&rotated, &ARCFACE_TEMPLATE, "rotation", index);
let mirrored = rotated.map(|p| point(-p.x(), p.y()));
tally.feed(&mirrored, &ARCFACE_TEMPLATE, "mirrored", index);
index += 1;
}
}
index = 0;
for k in [1e-3f32, 1.0, 1e3, 1e6, 1e10, 1e20, 1e30, 1e36, 4e36] {
let mut quarter_turn = origin;
for (slot, (x, y)) in quarter_turn.iter_mut().zip(centred) {
*slot = point((-y * f64::from(k)) as f32, (x * f64::from(k)) as f32);
}
tally.feed(&quarter_turn, &ARCFACE_TEMPLATE, "orthogonal", index);
for landmark in 0..LANDMARK_COUNT {
for axis in 0..2 {
for up in [true, false] {
let mut perturbed = quarter_turn;
let (x, y) = (perturbed[landmark].x(), perturbed[landmark].y());
perturbed[landmark] = if axis == 0 {
point(if up { x.next_up() } else { x.next_down() }, y)
} else {
point(x, if up { y.next_up() } else { y.next_down() })
};
tally.feed(&perturbed, &ARCFACE_TEMPLATE, "orthogonal-plus-ulp", index);
index += 1;
}
}
}
}
const TINY: [Point; LANDMARK_COUNT] = [
Point::new(0.0, 0.0),
Point::new(1.4e-45, 0.0),
Point::new(0.0, 1.4e-45),
Point::new(-1.4e-45, 0.0),
Point::new(0.0, -1.4e-45),
];
const HUGE: [Point; LANDMARK_COUNT] = [
Point::new(3.4e38, 3.4e38),
Point::new(-3.4e38, 3.4e38),
Point::new(3.4e38, -3.4e38),
Point::new(-3.4e38, -3.4e38),
Point::new(0.0, 0.0),
];
tally.feed(&HUGE, &TINY, "huge-to-tiny", 0);
tally.feed(&TINY, &HUGE, "tiny-to-huge", 0);
for index in 0..15_000 {
let scale = 10f64.powf(rng.unit() * 12.0 - 6.0);
let (sin, cos) = (rng.unit() * core::f64::consts::TAU).sin_cos();
let ox = (rng.unit() - 0.5) * rng.choose(&[1e0, 1e3, 1e6, 1e9, 3e38]);
let oy = (rng.unit() - 0.5) * rng.choose(&[1e0, 1e3, 1e6, 1e9, 3e38]);
let mut source = origin;
for (slot, (x, y)) in source.iter_mut().zip(centred) {
*slot = point(
((cos * x - sin * y) * scale + ox) as f32,
((sin * x + cos * y) * scale + oy) as f32,
);
}
tally.feed(&source, &ARCFACE_TEMPLATE, "face-like", index);
}
assert_eq!(
tally.non_invertible, 0,
"the invertibility postcondition refused {} of {} sets; it is documented as firing on no \
construction this sweep reaches",
tally.non_invertible, tally.sets
);
assert_eq!(
tally.non_finite_transform, 0,
"the `NonFiniteTransform` backstop fired, so the Cauchy–Schwarz UPPER bound in \
`SimilarityTransform::estimate` does not hold over finite `f32` sets"
);
assert!(
tally.sets > 45_000 && tally.ok > 40_000,
"the sweep must actually solve what it feeds: {} sets, {} solved, {} degenerate",
tally.sets,
tally.ok,
tally.degenerate
);
assert!(
tally.determinant_min < 1e-160,
"the sweep no longer reaches the small end: min a²+b² = {:e}",
tally.determinant_min
);
assert!(
tally.determinant_max > 1e160,
"the sweep no longer reaches the large end: max a²+b² = {:e}",
tally.determinant_max
);
for (end, determinant) in [
("smallest", tally.determinant_min),
("largest", tally.determinant_max),
] {
assert!(
determinant.is_normal() && (1.0 / determinant).is_normal(),
"the {end} a²+b² the sweep produced ({determinant:e}) is outside the band, so the margin \
reported in `SimilarityTransform::inverse` is gone"
);
}
}
const CLOSURE_WITNESS_SOURCE: [Point; LANDMARK_COUNT] = [
Point::new(f32::from_bits(0x7f7f_ffff), f32::from_bits(0x78b5_04f4)),
Point::new(-f32::from_bits(0x7f7f_ffff), -f32::from_bits(0x78b5_04f4)),
Point::new(f32::from_bits(0x787b_e944), 0.0),
Point::new(-f32::from_bits(0x787b_e944), 0.0),
Point::new(f32::from_bits(0x0000_0001), 0.0),
];
const CLOSURE_WITNESS_TARGET: [Point; LANDMARK_COUNT] = [
Point::new(0.0, 0.0),
Point::new(0.0, 0.0),
Point::new(0.0, 0.0),
Point::new(0.0, 0.0),
Point::new(f32::from_bits(0x0b0d_6bdd), f32::from_bits(0x0b0d_6bdd)),
];
#[test]
fn estimate_refuses_a_solve_whose_inverse_does_not_invert() {
const D: u64 = 0x0010_0000_0000_0000; const D_INVERSE: u64 = 0x7fd0_0000_0000_0001; const SCALE: f64 = f64::from_bits(0x2000_0000_0000_0000);
let error = SimilarityTransform::estimate(&CLOSURE_WITNESS_SOURCE, &CLOSURE_WITNESS_TARGET)
.expect_err("a solve whose inverse does not invert is not a transform this type holds");
assert!(
matches!(&error, Error::NonInvertibleTransform(payload) if payload.scale() == SCALE),
"expected NonInvertibleTransform({SCALE:e}) from `estimate` itself, got {error:?}"
);
const A: f64 = f64::from_bits(0x1ff6_a09e_667f_3bcd);
assert_eq!(
A.hypot(A),
SCALE,
"the witness's scale is the one the error names"
);
assert!(
!(A * A).is_normal() && A * A != 0.0,
"each square is subnormal on its own, which is where the precision is lost"
);
let determinant = A * A + A * A;
assert_eq!(
determinant.to_bits(),
D,
"the determinant is exactly `0x1p-1022`"
);
assert!(
determinant.is_normal() && (1.0 / determinant).is_normal(),
"and it is INSIDE the band, which is why `estimate` used to return Ok"
);
let refused = SimilarityTransform::new(A, A, 0.0, 0.0);
assert!(
reciprocal_determinant(refused.a(), refused.b()).is_some(),
"the band on the value itself still admits it — the value is not the problem"
);
let (ia, ib) = inverse_rotation(refused.a(), refused.b())
.expect("the reference arithmetic that inverts it has an answer");
let inverse_determinant = ia * ia + ib * ib;
assert_eq!(
inverse_determinant.to_bits(),
D_INVERSE,
"the INVERSE's determinant is one ulp above `0x1p+1022`"
);
assert!(
inverse_determinant.is_normal() && !(1.0 / inverse_determinant).is_normal(),
"finite, normal, and with a SUBNORMAL reciprocal — so the inverse of the inverse has no answer"
);
assert!(
refused.inverse().is_none(),
"`inverse` refuses to hand out a value its own arithmetic could not invert again"
);
}
const SECOND_LEVEL_WITNESS_SOURCE: [Point; LANDMARK_COUNT] = [
Point::new(f32::from_bits(0x7f7f_ffff), f32::from_bits(0x7ea9_2ed0)),
Point::new(-f32::from_bits(0x7f7f_ffff), -f32::from_bits(0x7ea9_2ed0)),
Point::new(f32::from_bits(0x7864_cbcb), 0.0),
Point::new(-f32::from_bits(0x7864_cbcb), 0.0),
Point::new(f32::from_bits(0x0000_0001), 0.0),
];
const SECOND_LEVEL_WITNESS_TARGET: [Point; LANDMARK_COUNT] = [
Point::new(0.0, 0.0),
Point::new(0.0, 0.0),
Point::new(0.0, 0.0),
Point::new(0.0, 0.0),
Point::new(f32::from_bits(0x0a31_14b8), f32::from_bits(0x0b59_6012)),
];
#[test]
fn estimate_refuses_a_solve_whose_inverses_inverse_does_not_invert() {
const D: u64 = 0x0010_0000_0000_0001;
const D_INVERSE: u64 = 0x7fd0_0000_0000_0000;
const D_INVERSE_TWICE: u64 = 0x000f_ffff_ffff_ffff;
const SCALE: f64 = f64::from_bits(0x2000_0000_0000_0001);
let error =
SimilarityTransform::estimate(&SECOND_LEVEL_WITNESS_SOURCE, &SECOND_LEVEL_WITNESS_TARGET)
.expect_err("the inverse inverts, and ITS inverse does not");
assert!(
matches!(&error, Error::NonInvertibleTransform(payload) if payload.scale() == SCALE),
"expected NonInvertibleTransform({SCALE:e}) from `estimate` itself, got {error:?}"
);
const A: f64 = f64::from_bits(0x1fd9_8b3b_c005_7dc5);
const B: f64 = f64::from_bits(0x1fff_5b38_653b_e879);
assert_eq!(
A.hypot(B),
SCALE,
"the witness's scale is the one the error names"
);
let determinant = A * A + B * B;
assert_eq!(determinant.to_bits(), D, "the solve's own determinant");
assert!(
determinant.is_normal() && (1.0 / determinant).is_normal(),
"which is INSIDE the band, so the round-5 postcondition admits it"
);
let (ia, ib) = inverse_rotation(A, B).expect("and so the first inverse exists");
let inverse_determinant = ia * ia + ib * ib;
assert_eq!(
inverse_determinant.to_bits(),
D_INVERSE,
"the inverse's determinant"
);
assert!(
inverse_determinant.is_normal() && (1.0 / inverse_determinant).is_normal(),
"ALSO inside the band, so a one-level postcondition admits it too"
);
let (ja, jb) = inverse_rotation(ia, ib).expect("the second inverse's rotation still computes");
let twice = ja * ja + jb * jb;
assert_eq!(
twice.to_bits(),
D_INVERSE_TWICE,
"and the third determinant"
);
assert!(
!twice.is_normal() && twice != 0.0,
"which is SUBNORMAL — the reference divides by it and gets no usable reciprocal"
);
let admitted_by_one_level = SimilarityTransform::new(A, B, 0.0, 0.0);
let once = admitted_by_one_level
.inverse()
.expect("a one-level postcondition sees an inverse here and stops");
assert!(
once.inverse().is_none(),
"and the level it does not look at is the one that has no answer"
);
}
#[test]
fn the_closure_is_the_postcondition_at_both_producers() {
const A: f64 = f64::from_bits(0x1ff6_a09e_667f_3bcd);
let outside = SimilarityTransform::new(A, A, 0.0, 0.0);
assert!(
reciprocal_determinant(outside.a(), outside.b()).is_some(),
"the entry band admits it, so only a check on the CANDIDATE can refuse it"
);
assert!(
outside.inverse().is_none(),
"the candidate check is what makes this None"
);
const IN_BAND: f64 = 2e-154;
let determinant = IN_BAND * IN_BAND;
assert!(
determinant.is_normal() && (1.0 / determinant).is_normal(),
"the rotation must be inside the band or this proves nothing about the translation"
);
assert!(
SimilarityTransform::new(IN_BAND, 0.0, 1e200, 0.0)
.inverse()
.is_none(),
"an inverse whose translation left `f64` is no inverse"
);
let solved = SimilarityTransform::estimate(&FIXTURE_LANDMARKS, &ARCFACE_TEMPLATE)
.expect("a face-shaped solve");
let once = solved.inverse().expect("estimate's output inverts");
once
.inverse()
.expect("and that inverse inverts — the property the postcondition is over");
}