GeomSolver Docs

Python Bindings

Using the solver from Python via maturin/pyO3.

Python Bindings

The solver ships as a native Python extension built with PyO3 and maturin.

Installation

From Prebuilt Wheel

pip install geom_solver-0.1.0-cp312-cp312-manylinux_2_35_x86_64.whl

From Source

cd py-lib
pip install maturin
maturin develop --release

API

System Class

from geom_solver import System

sys = System()

# Add entities
p1 = sys.add_point(0.0, 0.0)
p2 = sys.add_point(5.0, 0.0)
line = sys.add_line(p1, p2)
circle = sys.add_circle(2.5, 3.0, 1.5)

# Add constraints
from geom_solver import distance_constraint, horizontal_constraint
sys.add_constraint(distance_constraint(p1, p2, 5.0))
sys.add_constraint(horizontal_constraint(p1, p2))

# Solve
result = sys.solve()

Entity Methods

MethodReturnsDescription
add_point(x, y)intAdd a point, returns entity index
add_line(p1, p2)intAdd a line through two points
add_circle(cx, cy, r)intAdd a circle
add_arc(cx, cy, r, start, end)intAdd a circular arc

Constraint Builder Functions

from geom_solver import (
    distance_constraint,
    horizontal_constraint,
    vertical_constraint,
    perpendicular_constraint,
    parallel_constraint,
    angle_constraint,
    point_on_line_constraint,
    point_on_circle_constraint,
    tangent_line_circle_constraint,
    tangent_circle_circle_constraint,
    radius_constraint,
    equal_radius_constraint,
    concentric_constraint,
    coincident_constraint,
    midpoint_constraint,
    fix_point_constraint,
    fix_radius_constraint,
)

Each builder returns a constraint object that is passed to sys.add_constraint().

SolveResult

result = sys.solve()

result.success       # bool — did the solver converge?
result.residual_norm # float — final ‖r‖₂
result.iterations    # int — number of iterations
result.algorithm     # str — algorithm used ("LM", "DogLeg", etc.)
result.params        # list[float] — solved parameter values

DOF Analysis and Diagnostics

dof = sys.dof()
print(f"Degrees of freedom: {dof}")

diagnostics = sys.diagnostics()
print(diagnostics.report())

Solution Verification

result = sys.solve()
verification = sys.verify_solution()
if not verification.all_satisfied:
    for c in verification.violated:
        print(f"Violated: {c}")

Intelligent Multi-Start

# Enable multi-start with 20 attempts
result = sys.solve(multistart=True, max_attempts=20)

Tracing

sys.set_tracing(True)
result = sys.solve()
for event in result.trace:
    print(f"Iter {event.iteration}: ‖r‖ = {event.residual_norm:.6f}")

Priority Weights

from geom_solver import ConstraintPriority

# Critical constraint (weight = 100.0)
sys.add_constraint(distance_constraint(p1, p2, 5.0),
                   priority=ConstraintPriority.Critical)

# Soft constraint (weight = 0.1)
sys.add_constraint(angle_constraint(l1, l2, 0.5),
                   priority=ConstraintPriority.Soft)

Underconstrained Config

# Use MinimumNorm for underconstrained systems
sys.set_underconstrained_mode("minimum_norm")

# Or use soft anchors
sys.set_underconstrained_mode("soft_anchor", stiffness=0.01)

JSON Serialization

# Serialize to JSON
json_str = sys.to_json()

# Deserialize from JSON
sys2 = System.from_json(json_str)
result = sys2.solve()

Complete Example

from geom_solver import (
    System, distance_constraint, horizontal_constraint,
    vertical_constraint, fix_point_constraint
)

# Create a rectangle constrained to 10×5
sys = System()
p0 = sys.add_point(0.0, 0.0)
p1 = sys.add_point(10.0, 0.0)
p2 = sys.add_point(10.0, 5.0)
p3 = sys.add_point(0.0, 5.0)

# Fix one corner
sys.add_constraint(fix_point_constraint(p0))

# Opposite sides equal
sys.add_constraint(distance_constraint(p0, p1, 10.0))
sys.add_constraint(distance_constraint(p1, p2, 5.0))
sys.add_constraint(horizontal_constraint(p0, p1))
sys.add_constraint(vertical_constraint(p1, p2))

result = sys.solve()
print(f"Success: {result.success}")
print(f"P2 = ({sys.get_point(p2).x:.3f}, {sys.get_point(p2).y:.3f})")