BuddyMath / geometry_types.py
dotandru's picture
feat: implement Geometric Sanity Engine (V1.0) and fix project ID in functions
4de02b8
Raw
History Blame Contribute Delete
3.7 kB
# geometry_types.py - V1.0 (Geometric Sanity Engine — Type Contracts)
# CTO NOTE: All coordinate arithmetic uses SymPy Rational to guarantee
# exact arithmetic — no float drift, no rounding surprises.
from dataclasses import dataclass, field
from sympy import Rational, simplify, sqrt
import logging
logger = logging.getLogger(__name__)
@dataclass
class Point:
name: str
x: object # SymPy expression or numeric
y: object
def __eq__(self, other):
if not isinstance(other, Point):
return False
return (simplify(self.x - other.x) == 0 and
simplify(self.y - other.y) == 0)
def __repr__(self):
return f"{self.name}({self.x}, {self.y})"
def distance_to(self, other: "Point"):
"""Exact SymPy distance between two points."""
return sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
@dataclass
class Line:
"""Represents the line ax + by + c = 0."""
a: object
b: object
c: object
def y_at(self, x_val):
"""Compute y given x (assuming b ≠ 0)."""
if simplify(self.b) == 0:
raise ValueError("[Line.y_at] Vertical line — b=0, y is undefined for a given x.")
return Rational(-self.a * x_val - self.c, self.b)
def contains(self, p: "Point") -> bool:
"""Returns True if point p satisfies ax + by + c = 0."""
val = simplify(self.a * p.x + self.b * p.y + self.c)
return val == 0
def __repr__(self):
return f"Line({self.a}x + {self.b}y + {self.c} = 0)"
@dataclass
class Segment:
p1: Point
p2: Point
def midpoint(self) -> Point:
"""Returns the midpoint with exact rational arithmetic."""
from sympy import Rational as R
mid_x = (self.p1.x + self.p2.x) / 2
mid_y = (self.p1.y + self.p2.y) / 2
return Point(
name=f"mid_{self.p1.name}{self.p2.name}",
x=simplify(mid_x),
y=simplify(mid_y)
)
def length(self):
"""Exact SymPy length of the segment."""
return self.p1.distance_to(self.p2)
def __repr__(self):
return f"Segment({self.p1.name}{self.p2.name})"
@dataclass
class Circle:
center: Point
radius: object # SymPy expression (can be symbolic)
def contains(self, p: Point) -> bool:
"""Returns True if p lies exactly on the circle boundary."""
lhs = (p.x - self.center.x)**2 + (p.y - self.center.y)**2
return simplify(lhs - self.radius**2) == 0
def __repr__(self):
return f"Circle(center={self.center}, r={self.radius})"
@dataclass
class GeometryAnchor:
"""
V1.0: The single source of truth for verified geometric facts.
Populated by `constraint_checks.py` and consumed by `geometric_sanity.py`.
"""
points: list = field(default_factory=list)
lines: list = field(default_factory=list)
segments: list = field(default_factory=list)
circles: list = field(default_factory=list)
verified_facts: list = field(default_factory=list)
warnings: list = field(default_factory=list)
def add_fact(self, fact: str):
logger.info(f"[GEO-ANCHOR] ✓ FACT: {fact}")
self.verified_facts.append(fact)
def add_warning(self, warning: str):
logger.warning(f"[GEO-ANCHOR] ✗ WARNING: {warning}")
self.warnings.append(warning)
def is_clean(self) -> bool:
"""True if no geometric contradictions were detected."""
return len(self.warnings) == 0
def summary(self) -> dict:
return {
"verified_facts": self.verified_facts,
"warnings": self.warnings,
"has_contradictions": not self.is_clean()
}