GeomSolver Docs

Architecture

Module organization, data flow, and core design of the 2D geometric constraint solver.

Architecture

The solver is organized into 35+ source files spanning six major modules. Every module has a single responsibility and a clean public interface, making the codebase straightforward to navigate and extend.

Module Overview

ModuleFilesResponsibility
entitiesentities.rs10 geometric entity types and their parameter storage
constraintsconstraints.rs, residual.rs47+ constraint types and residual evaluation
typestypes.rsShared enums, structs, error types
systemsystem.rs, dof.rs, normalize.rs, variable_analysis.rsCentral entry point, DOF analysis, parameter reduction
solversolver/mod.rs, lm.rs, dogleg.rs, bfgs.rs, lbfgs.rs, sparse.rs, propagation.rs, multistart.rs, decomposition.rsAll solver algorithms and decomposition
diagnosticsdiagnostics.rs, validation.rs, tracing.rs, performance.rs, branch.rsVerification, profiling, branch detection
supportweight.rs, underconstrained.rs, redundancy.rs, undo.rs, cross_validation.rs, snapshot.rs, jacobian.rsWeights, underconstrained handling, undo, Jacobian

System Struct — The Central Entry Point

The System struct is the single public API surface. Users create a System, add entities and constraints, then call solve():

let mut sys = System::new();
let p1 = sys.add_point(0.0, 0.0);
let p2 = sys.add_point(5.0, 0.0);
sys.add_constraint(horizontal_constraint(p1, p2));
let result = sys.solve();

Internally, System holds the flat parameter vector, entity metadata, constraint list, and solver configuration. It orchestrates the entire solve pipeline from reduction through to verification.

Variable Mapping and Parameter Reduction

Each entity maps to a contiguous slice of the global parameter vector:

  • Point[x, y] (2 parameters)
  • Line[x1, y1, x2, y2] (4 parameters)
  • Circle[cx, cy, r] (3 parameters)
  • Arc[cx, cy, r, start_angle, end_angle] (5 parameters)
  • Ellipse[cx, cy, a, b, angle] (5 parameters)

Parameter reduction eliminates redundant DOFs before solving. Constraints like Coincident, Horizontal, Vertical, EqualRadius, Concentric, and EqualMinorAxes are applied as substitutions, reducing the parameter count and improving numerical stability. A typical 20-constraint sketch may shrink from 40 parameters to 18 after reduction.

Constraint Graph Decomposition

The solver uses Union-Find to partition the constraint graph into independent connected components. Each component is solved in isolation:

  1. Build an undirected graph where entities are nodes and constraints are edges.
  2. Run Union-Find to identify connected components.
  3. Extract each component's parameter subset and constraint subset.
  4. Solve components in order (or in parallel for independent ones).

This decomposition means a sketch with two disconnected sub-sketches is solved as two small problems rather than one large one, improving both speed and robustness.

Degrees of Freedom (DOF) Analysis

The dof module computes the DOF count before solving:

DOF = Σ(entity_params) − Σ(constraint_equations) + Σ(reductions)
  • DOF > 0: Underconstrained — solver adds SoftAnchor or MinimumNorm regularization.
  • DOF = 0: Well-constrained — standard solve.
  • DOF < 0: Overconstrained — solver proceeds with least-squares, reports redundant constraints.

The DOF count is displayed in diagnostics and used to select the appropriate solver strategy.

Data Flow

The complete data flow through the solver:

Entities + Constraints
        │
        ▼
  Parameter Reduction (normalize.rs)
        │
        ▼
  Constraint Graph Decomposition (Union-Find)
        │
        ▼
  Per-Component Solve Loop:
        │
        ├─► Residual Function r(x)
        │       residual.rs — evaluates all constraint residuals
        │
        ├─► Jacobian J(x)
        │       jacobian.rs — analytical sparse Jacobian (CSC)
        │
        ├─► Solver Algorithm
        │       LM / DogLeg / BFGS / L-BFGS / Sparse CG
        │
        └─► Convergence Check
                ‖r‖ < tol or max iterations reached
        │
        ▼
  Solution Verification (validation.rs)
        │
        ▼
  Diagnostics + Result

Each step in this pipeline is independently testable and replaceable. The modular design allows swapping solver algorithms, adding new constraint types, or inserting custom diagnostics without touching unrelated code.