This guide helps you migrate from other geometry and vector libraries to Constraint Theory.
- Why Migrate?
- From NumPy
- From SciPy
- From Shapely
- From SymPy
- From Custom Implementations
- Common Migration Patterns
- Performance Comparison
- Limitations and Differences
| Feature | Traditional Libraries | Constraint Theory |
|---|---|---|
| Exactness | Platform-dependent floats | Exact rational coordinates |
| Reproducibility | Requires seeding | Deterministic everywhere |
| Cross-platform | May vary | Identical results |
| Precision drift | Accumulates over time | Zero drift |
| Speed | Variable | ~100ns per operation |
Migrate if you:
- Need exact reproducibility across different machines
- Experience floating-point drift in long-running simulations
- Want deterministic network physics in multiplayer games
- Require verifiable results for scientific publications
- Build CAD/engineering tools needing exact geometry
Stay with your current library if you:
- Need arbitrary precision beyond unit circle
- Work primarily with 3D geometry
- Require exact symbolic computation
- Need geometric operations beyond snapping (intersections, unions, etc.)
Before (NumPy):
import numpy as np
def normalize(v):
"""Normalize a vector."""
magnitude = np.linalg.norm(v)
return v / magnitude
vector = np.array([3.0, 4.0])
normalized = normalize(vector)
# Result: [0.6, 0.8] but 0.6² + 0.8² = 0.9999999999999999After (Constraint Theory):
from constraint_theory import PythagoreanManifold
import numpy as np
manifold = PythagoreanManifold(200)
vector = np.array([3.0, 4.0])
magnitude = np.linalg.norm(vector)
normalized_approx = vector / magnitude
# Snap to exact Pythagorean triple
x, y, noise = manifold.snap(normalized_approx[0], normalized_approx[1])
normalized = np.array([x, y])
# Result: [0.6, 0.8] with 0.6² + 0.8² = 1.0 EXACTLYBefore (NumPy):
import numpy as np
vectors = np.random.randn(1000, 2)
magnitudes = np.linalg.norm(vectors, axis=1, keepdims=True)
normalized = vectors / magnitudes
# All results are approximate floatsAfter (Constraint Theory):
from constraint_theory import PythagoreanManifold
import numpy as np
manifold = PythagoreanManifold(200)
vectors = np.random.randn(1000, 2)
magnitudes = np.linalg.norm(vectors, axis=1, keepdims=True)
normalized_approx = vectors / magnitudes
# Batch snap to exact states
results = manifold.snap_batch(normalized_approx)
normalized = np.array([[x, y] for x, y, _ in results])
noises = np.array([noise for _, _, noise in results])Before (NumPy):
import numpy as np
def direction_from_angle(angle_degrees):
"""Get unit vector from angle."""
angle_rad = np.radians(angle_degrees)
return np.array([np.cos(angle_rad), np.sin(angle_rad)])
# Returns approximate floatsAfter (Constraint Theory):
import numpy as np
from constraint_theory import PythagoreanManifold
manifold = PythagoreanManifold(200)
def exact_direction_from_angle(angle_degrees):
"""Get exact unit vector from angle."""
angle_rad = np.radians(angle_degrees)
x, y = np.cos(angle_rad), np.sin(angle_rad)
sx, sy, noise = manifold.snap(x, y)
return np.array([sx, sy]), noise
# Returns exact Pythagorean coordinatesBefore (SciPy):
from scipy.spatial import KDTree
import numpy as np
# Build KD-tree of reference points
reference_points = np.random.randn(1000, 2)
tree = KDTree(reference_points)
# Find nearest neighbor
query_point = np.array([0.5, 0.7])
distance, index = tree.query(query_point)
nearest = reference_points[index]After (Constraint Theory):
Constraint Theory uses an internal KD-tree for snapping. If you need custom reference points:
from constraint_theory import PythagoreanManifold
import numpy as np
# Use Constraint Theory for unit circle snapping
manifold = PythagoreanManifold(500)
# Snap to nearest exact state
query_point = np.array([0.5, 0.7])
sx, sy, noise = manifold.snap(query_point[0], query_point[1])
nearest = np.array([sx, sy])
# Result is exact and deterministicBefore (SciPy):
from scipy.spatial.distance import cdist
import numpy as np
points = np.random.randn(100, 2)
distances = cdist(points, points)After (Constraint Theory):
For exact distances on the unit circle:
from constraint_theory import PythagoreanManifold
import numpy as np
manifold = PythagoreanManifold(200)
# Snap points to exact states first
points = np.random.randn(100, 2)
# Normalize and snap...
magnitudes = np.linalg.norm(points, axis=1, keepdims=True)
magnitudes[magnitudes == 0] = 1 # Avoid division by zero
normalized = points / magnitudes
results = manifold.snap_batch(normalized)
exact_points = np.array([[x, y] for x, y, _ in results])
# Now distances are based on exact coordinates
distances = cdist(exact_points, exact_points)Before (Shapely):
from shapely.geometry import Point, LineString
import numpy as np
def get_direction_line(origin, angle_degrees, length=1.0):
"""Create a line in a given direction."""
angle_rad = np.radians(angle_degrees)
end_x = origin.x + length * np.cos(angle_rad)
end_y = origin.y + length * np.sin(angle_rad)
return LineString([origin, Point(end_x, end_y)])After (Constraint Theory):
from shapely.geometry import Point, LineString
from constraint_theory import PythagoreanManifold
import numpy as np
manifold = PythagoreanManifold(200)
def get_exact_direction_line(origin, angle_degrees, length=1.0):
"""Create a line with exact direction."""
angle_rad = np.radians(angle_degrees)
dx, dy = np.cos(angle_rad), np.sin(angle_rad)
dx, dy, noise = manifold.snap(dx, dy) # Exact direction
end_x = origin.x + length * dx
end_y = origin.y + length * dy
return LineString([origin, Point(end_x, end_y)])Before (SymPy):
from sympy import Rational, sqrt
# Exact Pythagorean triple
a, b, c = 3, 4, 5
x = Rational(a, c) # 3/5
y = Rational(b, c) # 4/5
# x² + y² = 1 exactly (symbolic)After (Constraint Theory):
from constraint_theory import PythagoreanManifold
manifold = PythagoreanManifold(200)
# Snap to exact Pythagorean triple
x, y, noise = manifold.snap(0.6, 0.8)
# x, y are exact rational coordinates (3/5, 4/5)
# Computed much faster than symbolic mathWhen to use each:
| Use SymPy | Use Constraint Theory |
|---|---|
| Symbolic manipulation | Numerical snapping |
| Exact algebra | Performance-critical |
| Proof verification | Production code |
| Complex expressions | Simple unit vectors |
Before (Custom):
class FixedPointVector:
"""Custom fixed-point vector implementation."""
def __init__(self, x, y, scale=10000):
self.scale = scale
self.x = int(x * scale)
self.y = int(y * scale)
def normalized(self):
mag_sq = self.x * self.x + self.y * self.y
mag = int(mag_sq ** 0.5)
return FixedPointVector(
self.x / mag / self.scale,
self.y / mag / self.scale,
self.scale
)After (Constraint Theory):
from constraint_theory import PythagoreanManifold
manifold = PythagoreanManifold(200)
def exact_normalize(x, y):
"""Get exact normalized vector."""
mag = (x * x + y * y) ** 0.5
if mag == 0:
return 0.0, 0.0
return manifold.snap(x / mag, y / mag)[:2]Before (Custom):
# Pre-computed lookup table of angles
ANGLES = {
0: (1.0, 0.0),
30: (0.866025, 0.5),
45: (0.707107, 0.707107),
60: (0.5, 0.866025),
90: (0.0, 1.0),
# ... more entries
}
def get_direction(angle):
return ANGLES.get(angle, (0.0, 0.0))After (Constraint Theory):
from constraint_theory import PythagoreanManifold
import math
manifold = PythagoreanManifold(200)
def get_exact_direction(angle_degrees):
"""Get exact direction for any angle."""
angle_rad = math.radians(angle_degrees)
x, y = math.cos(angle_rad), math.sin(angle_rad)
return manifold.snap(x, y)[:2]
# Works for ANY angle, not just pre-defined ones# Pattern: Convert approximate normalized vectors to exact
import numpy as np
from constraint_theory import PythagoreanManifold
manifold = PythagoreanManifold(200)
def to_exact(x, y):
"""Convert to exact Pythagorean coordinates."""
mag = (x * x + y * y) ** 0.5
if mag == 0:
return 0.0, 0.0, 0.0
return manifold.snap(x / mag, y / mag)
# Usage
exact_x, exact_y, noise = to_exact(2.0, 3.0)# Pattern: Efficient batch conversion
import numpy as np
from constraint_theory import PythagoreanManifold
manifold = PythagoreanManifold(500)
def batch_to_exact(vectors):
"""Convert batch of vectors to exact coordinates."""
vectors = np.asarray(vectors)
magnitudes = np.linalg.norm(vectors, axis=1, keepdims=True)
magnitudes[magnitudes == 0] = 1
normalized = vectors / magnitudes
results = manifold.snap_batch(normalized)
exact = np.array([[x, y] for x, y, _ in results])
noises = np.array([noise for _, _, noise in results])
return exact, noises# Pattern: Filter by snapping noise
from constraint_theory import PythagoreanManifold
manifold = PythagoreanManifold(200)
def filter_by_tolerance(vectors, max_noise=0.01):
"""Keep only vectors that snap within tolerance."""
results = []
for x, y in vectors:
sx, sy, noise = manifold.snap(x, y)
if noise <= max_noise:
results.append((sx, sy))
return results# Pattern: Reproducible data augmentation for ML
from constraint_theory import PythagoreanManifold
import numpy as np
manifold = PythagoreanManifold(300)
def augment_directions(vectors, seed=42):
"""Deterministic direction augmentation."""
np.random.seed(seed)
# Add small random noise, then snap
noisy = vectors + np.random.randn(*vectors.shape) * 0.05
# Normalize and snap
mags = np.linalg.norm(noisy, axis=1, keepdims=True)
mags[mags == 0] = 1
normalized = noisy / mags
results = manifold.snap_batch(normalized)
return np.array([[x, y] for x, y, _ in results])
# Same seed = same augmentation everywhereimport time
import numpy as np
from constraint_theory import PythagoreanManifold
manifold = PythagoreanManifold(200)
# NumPy normalization
start = time.perf_counter()
for _ in range(100000):
v = np.array([0.577, 0.816])
v = v / np.linalg.norm(v)
numpy_time = time.perf_counter() - start
# Constraint Theory
start = time.perf_counter()
for _ in range(100000):
manifold.snap(0.577, 0.816)
ct_time = time.perf_counter() - start
print(f"NumPy: {numpy_time*1000:.2f}ms")
print(f"Constraint Theory: {ct_time*1000:.2f}ms")
print(f"Speedup: {numpy_time/ct_time:.1f}x")import time
import numpy as np
from constraint_theory import PythagoreanManifold
manifold = PythagoreanManifold(200)
vectors = np.random.randn(100000, 2)
# NumPy batch normalization
start = time.perf_counter()
mags = np.linalg.norm(vectors, axis=1, keepdims=True)
normalized = vectors / mags
numpy_time = time.perf_counter() - start
# Constraint Theory batch
start = time.perf_counter()
results = manifold.snap_batch(vectors / mags)
ct_time = time.perf_counter() - start
print(f"NumPy: {numpy_time*1000:.2f}ms")
print(f"Constraint Theory: {ct_time*1000:.2f}ms")| Feature | Alternative |
|---|---|
| 3D vectors | Use NumPy + snap 2D projections |
| Arbitrary precision | Use SymPy or mpmath |
| Geometric operations (intersection, union) | Use Shapely |
| Symbolic math | Use SymPy |
| Non-unit vectors | Scale manually after snapping |
# NumPy: Returns platform-dependent float
np_normalized = np.array([3, 4]) / 5
# May be 0.6000000000000001 or 0.5999999999999999
# Constraint Theory: Returns exact rational as float
x, y, _ = manifold.snap(0.6, 0.8)
# Always exactly 0.6 and 0.8| Operation | NumPy | Constraint Theory |
|---|---|---|
| Normalize | v / np.linalg.norm(v) |
manifold.snap(x, y) |
| Batch normalize | vectors / norms |
manifold.snap_batch(vectors) |
| Magnitude | np.linalg.norm(v) |
(x*x + y*y)**0.5 (same) |
| Dot product | np.dot(a, b) |
ax*bx + ay*by (same) |
The Python bindings are powered by constraint-theory-core, a high-performance Rust implementation that provides:
- O(log n) KD-tree lookup for nearest-neighbor search
- SIMD optimization for batch processing
- Memory-efficient state storage
- Thread-safe immutable data structures
For performance-critical applications, consider using the Rust crate directly:
// Rust equivalent
use constraint_theory::PythagoreanManifold;
let manifold = PythagoreanManifold::new(200)?;
let (x, y, noise) = manifold.snap(0.577, 0.816)?;Explore the Pythagorean manifold interactively at constraint-theory.superinstance.ai:
- Visualize triple distribution on the unit circle
- Interactive snapping demonstrations
- Compare densities and resolutions
- Understand the noise metric
The visualizations are built with constraint-theory-web.
The mathematical foundations are described in:
- "Deterministic Geometric Snapping via Pythagorean Manifolds" — Core algorithm and complexity analysis
- "Cross-Platform Reproducibility in Numerical Computing" — Applications in scientific computing
- "Exact Constraint Satisfaction for Game Physics" — Game development applications
See constraint-theory-research for papers and proofs.
For maximum performance, use Python for orchestration and call into Rust for heavy computation:
# Python orchestration
from constraint_theory import PythagoreanManifold
import numpy as np
manifold = PythagoreanManifold(1000)
# Batch process in Rust (via Python bindings)
large_dataset = np.random.randn(1_000_000, 2)
results = manifold.snap_batch(large_dataset)Python (orchestration)
↓
constraint-theory-python (this library)
↓
constraint-theory-core (Rust engine)
↓
KD-tree lookup in Rust
- Documentation: API Reference
- Examples: examples/
- Issues: GitHub Issues
- Core Library: constraint-theory-core
- Web Demos: constraint-theory-web
- Research: constraint-theory-research
- Live Demo: constraint-theory.superinstance.ai