GeomSolver Docs

Testing

Unit tests, proptest-based Jacobian verification, and quick bench tests.

Testing

The solver includes a comprehensive test suite covering unit tests, property-based tests, and quick benchmarks.

Unit Tests

Located in src/tests.rs, the unit tests cover:

  • All 47+ constraint types with concrete geometric configurations
  • Each test calls sys.solve() followed by check_constraints_satisfied()
  • Tests verify convergence, residual bounds, and geometric correctness
  • Edge cases: degenerate configurations, overconstrained systems, near-singular Jacobians
# Run all unit tests
cargo test

# Run a specific test
cargo test test_distance_constraint

# Run with output
cargo test -- --nocapture

Proptest-Based Jacobian Verification

The property-based test suite in src/proptest_jacobian.rs is the primary guarantee of Jacobian correctness.

Strategy

For each constraint type, the proptest framework:

  1. Generates 50 random configurations with random entity positions and constraint parameters
  2. Computes the analytical Jacobian using the hand-derived partial derivatives
  3. Computes the numerical Jacobian using central differences: ∂r/∂x ≈ (r(x+h) − r(x−h)) / 2h
  4. Compares the two matrices element-by-element

Tolerances

MetricTolerance
Absolute difference< 1e-4
Relative difference< 1e-2

The relative tolerance is generous to accommodate the inherent inaccuracy of finite differences, while the absolute tolerance catches gross errors.

Coverage

All 47+ constraint types are covered:

  • Point constraints: Distance, Horizontal, Vertical, PointOnLine, PointOnCircle, Coincident, Midpoint, etc.
  • Line constraints: Horizontal, Vertical, Perpendicular, Parallel, Angle, EqualLength
  • Circle/Arc constraints: TangentLineCircle, TangentCircleCircle, Radius, EqualRadius, Concentric
  • Ellipse constraints: TangentLineEllipse, EqualMinorAxes, EqualMajorAxes
  • Hyperbola/Parabola constraints: TangentLineHyperbola, PointOnHyperbola, etc.

Near-Degenerate Case Filtering

Random generation occasionally produces near-degenerate cases (e.g., two points nearly coincident for a distance constraint). These are filtered out:

proptest! {
    #[test]
    fn proptest_distance_jacobian(a in -100.0..100.0, b in -100.0..100.0, d in 0.1..100.0) {
        // Skip if points are too close (numerical instability)
        prop_assume!(d > 0.1);
        // ... compare Jacobians
    }
}

Quick Bench Test

benchmarks/quick_bench.rs provides fast wall-clock benchmarks for development:

cargo test --test quick_bench

Unlike Criterion benchmarks, these run in seconds and give approximate timing data. Useful for quick regression checks during development.

Running Tests

# All tests (unit + proptest)
cargo test

# Only unit tests (skip proptests)
cargo test --lib

# Only proptests
cargo test proptest

# Quick bench
cargo test --test quick_bench

# Verbose output
cargo test -- --nocapture

Proptest Regression File

When a proptest fails, the failing seed is recorded in:

proptest-regressions/proptest_jacobian.txt

This file allows deterministic replay of failing cases. To replay:

PROPTEST_CASES=1 cargo test proptest_jacobian

The regression file is committed to version control to ensure CI always tests previously-failing seeds.