Verifying sympy.geometry

This chapter walks through the bundled sympy_geometry.deppy sidecar — a complete, runnable verification of properties of sympy.geometry's Point / Segment / Triangle / Polygon / Circle classes, without modifying a single line of SymPy's source code.

Try it yourself. The sidecar sympy_geometry.deppy ships at the repo root. Run it with:
python -m deppy.pipeline.run_verify sympy_geometry.deppy --out sympy_geometry.lean
Today's verdict (verified at the time of this writing): 14 foundations, 5 specs, 38 sidecar axioms (38 grounded, 38 mechanized to concrete Lean Props), 4 method-body links (3 EXACT, 1 partial), 11 verify blocks (11/11 accepted by ProofKernel.verify), Lean round-trip OK — ✓ CERTIFIED. A decorator-based variant lives at examples/decorated_geometry.py; run it via python -m deppy.pipeline.run_verify --from-module examples.decorated_geometry.

What's in the sidecar

The sympy_geometry.deppy file lays out the trust chain: foundations (generic mathematical facts) → sidecar axioms (claims about sympy.geometry's behaviour) → verify blocks (kernel-checked properties of named methods) → proofs (compositions citing the foundations and axioms).

Section Count What it covers
foundations14Real_sqrt_nonneg, Real_add_comm, Real_sub_sq_swap, Real_translate_killed_in_diff, Real_avg_minus_endpoints, … — generic Int/Real arithmetic facts. 6 are Z3-discharged at TrustLevel.Z3_VERIFIED.
specs5Point, Segment, Triangle, Circle, Polygon — each lists its axioms + a Python guarantee.
axioms38Library claims like dist_nonneg, dist_pythagoras, midpoint_average, centroid_2_to_1, circle_radius_equidistant. All 38 are GROUNDED (their target methods exist on the live module).
verify blocks11Kernel-checked properties on real methods: Point.distance, Segment.contains, Triangle.area, Triangle.centroid, Polygon.area, Circle.radius, plus one PSDL block exercising the Python-syntax tactic language.
proofs45Compositions: 20 derived, 25 cited, 0 sorry.

A taste of the file

Foundations come first — admitted on user authority, but several get checked by Z3:

# sympy_geometry.deppy — foundations (excerpt)
foundation Real_sqrt_nonneg: "sqrt(x) >= 0 when x >= 0"
foundation Real_sqrt_sq_nonneg: "sqrt(x)**2 == x when x >= 0"
foundation Real_sub_sq_swap: "(a - b)**2 == (b - a)**2"
foundation Real_add_comm: "a + b == b + a"
foundation Real_avg_minus_endpoints: "2*a - (a + b) == a - b"

Next, the spec block for sympy.geometry.point.Point lists axioms about its distance and collinearity behaviour:

# sympy_geometry.deppy — Point spec (excerpt)
spec sympy.geometry.point.Point:
  guarantee: "Euclidean distance is a metric on R²; collinearity is the vanishing cross product"
  pure: true
  axiom dist_nonneg: "Point.distance(p, q) >= 0"
  axiom dist_zero_iff_equal: "(Point.distance(p, q) == 0) == (p == q)"
  axiom dist_symmetric: "Point.distance(p, q) == Point.distance(q, p)"
  axiom dist_pythagoras: "Point.distance(p, q)**2 == (p.x - q.x)**2 + (p.y - q.y)**2"
  axiom collinear_iff_zero_cross: "is_collinear(A, B, C) == ((B.x-A.x)*(C.y-A.y) == (C.x-A.x)*(B.y-A.y))"

Verify blocks pin properties to specific live methods so the kernel can run them:

# sympy_geometry.deppy — verify blocks (excerpt)
verify dist_nonneg_code:
  function: sympy.geometry.point.Point.distance
  property: "Point.distance(p, q) >= 0"
  via: foundation Real_sqrt_nonneg
  fibration: isinstance Point
  cubical: true

verify circle_radius_eq_code:
  function: sympy.geometry.ellipse.Circle.radius
  property: "Circle(c, r).radius == r"
  via: foundation Real_add_comm
  # NB: this claim is *false* under placeholder semantics —
  # Z3 counterexample search rejects it; the certificate
  # omits the theorem and reports it in the audit summary.

The last verify block exercises PSDL, the Python-syntax tactic language whose body becomes a deppy ProofTerm tree (kernel-verified) plus a Lean tactic (best-effort documentation):

# sympy_geometry.deppy — PSDL block
verify dist_nonneg_psdl:
  function: sympy.geometry.point.Point.distance
  property: "Point.distance(p, q) >= 0"
  via: foundation Real_sqrt_nonneg
  binders: p: Point, q: Point
  psdl_proof: |
    if isinstance(other, Point):
        # body returns sqrt(sum_zip_sub_sq(self, other))
        inline(Point.distance, sqrt(sum_zip_sub_sq(self, other)))
        apply(Real_sqrt_nonneg)
        assert sum_zip_sub_sq(self, other) >= 0, "z3"
    else:
        raise NotImplementedError  # exception fibre — vacuous

What the pipeline does

python -m deppy.pipeline.run_verify sympy_geometry.deppy runs every step in order; each step is real (no metadata stubs) and recorded in the JSON sidecar emitted alongside the .lean file:

1
Foundation Z3 discharge. Each foundation whose statement is pure Int arithmetic is fed to Z3. Today: 14 attempted, 6 verified at TrustLevel.Z3_VERIFIED.
2
Counterexample search. Z3 negates each arithmetic foundation and looks for a falsifying model. Today: 3 attempted, 0 counterexamples (an earlier draft of the file had a foundation that was true over reals but false over Int — the search caught it).
3
Mechanization. Each grounded axiom's Python statement becomes a concrete Lean Prop over a flat-Int signature inferred from the AST. Today: 38/38 mechanized.
4
Body translation. For each verify block's function:, deppy inspect.getsource's the live method and translates the AST to Lean. Today: 4 methods linked, 3 EXACT, 1 partial (Circle.tangent_lines's final else branch uses sympy.solve on a symbolic equation — honestly untranslatable, marked sorry).
5
Verify-block kernel verification. For each verify block, deppy builds a ProofTerm tree (Unfold + AxiomInvocation) and runs ProofKernel.verify. PSDL blocks compile their Python body to a richer ProofTerm tree. Today: 11/11 accepted.
6
Per-verify counterexample search. After kernel acceptance, Z3 substitutes mechanization's placeholder semantics into the property and searches for a falsifying model. Today: circle_radius_eq_code is rejected — its claim is provably false under placeholder semantics, so the certificate omits the theorem and reports the rejection in the audit summary.
7
Lean certificate emission. All accepted theorems are written to sympy_geometry.lean along with the foundation discharge, mechanization preamble, body links, cubical-analysis comments, and per-verify theorems.
8
Lean round-trip. The pipeline shells out to lean and checks the file actually compiles. Today: 0 errors, 0 sorrys.
9
JSON sidecar. Alongside the .lean, an audit-grade sympy_geometry.json records the verdict, per-section counters, and the Lean goal-state on failure (when applicable).
10
certify_or_die. The final verdict refuses to certify when any of: Lean rejected, a counterexample was found for an admitted foundation, a code-proof's soundness gate failed, an expects_sha256 drifted, or a verify block was rejected by per-verify counterexample search. Today: ✓ CERTIFIED.

Highlight: the PSDL block

verify dist_nonneg_psdl is the only verify block with a psdl_proof: body. PSDL — the Python-Semantic Deppy Language — lets you write the proof in literal Python with a small library of cubical-flavoured primitives. See Part 5: PSDL for the full reference.

Each PSDL line maps to a deppy ProofTerm subclass and a Lean tactic line:

PSDL line Kernel ProofTerm Lean tactic
if isinstance(other, Point):Fiber(scrutinee=other, [(Point, …), (else, …)])by_cases h : isinstance other Point
inline(Point.distance, …)Unfold(Point_distance, Refl(…))unfold Point_distance
apply(Real_sqrt_nonneg)AxiomInvocation(Real_sqrt_nonneg)exact Foundation_Real_sqrt_nonneg
assert P, "z3"Cut(h, RefnT(Bool, P), Z3Proof(P), …)have h : P := by omega
raise NotImplementedErrorStructural("vacuous: NotImplementedError")exact absurd ‹_› (by simp)

The deppy kernel verifies the resulting ProofTerm tree independently of Lean — so when Lean's elaborator can't follow a PSDL idiom (isinstance other Point isn't a Lean predicate), the deppy verdict still holds and the Lean side falls back to a synthesised unfold + first | rfl | omega | … closer.

Highlight: a real false claim caught at run-time

verify circle_radius_eq_code claims Circle(c, r).radius == r. Mathematically true for a real Circle, but under deppy's placeholder mechanization (Circle_radius : Int → Int → Int defined as constantly 0), the claim becomes 0 = r — false for r ≠ 0. The per-verify counterexample search catches it:

verify circle_radius_eq_code — REJECTED
  property: Circle(c, r).radius == r
  Z3 found a counterexample showing this claim is
  false under the placeholder semantics:
    after placeholder substitution ``0 == r``: With r=1: 0 == r → False
    (real counterexample — claim is provably false)
  No theorem emitted; the block is reported in the audit
  summary as ``rejected``.

The kernel's structural ProofTerm tree (Unfold(Circle_radius, AxiomInvocation(Real_add_comm))) type-checks — that's the kernel rubber-stamping the shape. The Z3 search is the second gate that demands the shape actually entail the claim under some interpretation. When placeholder semantics expose a contradiction, the certificate refuses to admit the theorem and records the rejection. This is the system catching itself.

Architecture diagram

sympy_geometry.deppy          run_verify pipeline
┌──────────────────┐          ┌──────────────────────────────┐
│ foundation R…    │          │ 1. Foundation Z3 discharge   │
│ spec Point:      │          │ 2. Counterexample search      │
│   axiom dist…    │──parse──▶│ 3. Mechanize to Lean Props   │
│ verify NAME:     │          │ 4. Body translate (live src) │
│   psdl_proof: |  │          │ 5. ProofKernel.verify        │
│ proof T: by:…    │          │ 6. Per-verify counterexample │
└──────────────────┘          │ 7. Lean certificate emit     │
                              │ 8. lean round-trip           │
                              │ 9. JSON sidecar emit         │
                              │10. certify_or_die            │
                              └──────────────────────────────┘
                                        │
                                        ▼
                        ┌────────────────────────────────┐
                        │ 11/11 verify blocks      ✓    │
                        │ 38/38 axioms mechanized   ✓    │
                        │ 6/14 foundations Z3       ✓    │
                        │ Lean round-trip OK        ✓    │
                        │ ✓ CERTIFIED                    │
                        └────────────────────────────────┘

Full Output

Running the verification produces:

$ python -m deppy.pipeline.run_verify sympy_geometry.deppy --out sympy_geometry.lean

  ...
  Foundations:
    foundations / Z3-attempted / verified:  14 / 10 / 7
  Counterexample search:
    foundations attempted / counterexamples: 3 / 0
  Subsystem invocations (B1–B16 audit batch):
    invoked / successful:                   45 / 44
  ProofTerm subclasses (C1–C7 audit batch):
    constructed / kernel-accepted:          38 / 27
  ``verify`` blocks (.deppy → kernel.verify):
    accepted by ProofKernel.verify:         11 / 11
  Specs (informational):                    5
  Proofs total:                             45
    derived (real proof bodies):            20
    cited  (renaming of trusted axioms):    25
    sorry  (unrecognised by-clause):        0
  ────────────────────────────────────────────────────────────
  deppy.lean.lean_runner round-trip:        OK
  ────────────────────────────────────────────────────────────
  ✓ CERTIFIED — top-level certify_or_die: PASS
  ════════════════════════════════════════════════════════════
  Certificate at: sympy_geometry.lean
  JSON sidecar:   sympy_geometry.json

Exercises

Exercise 4.9: Add a sidecar axiom for the angle bisector theorem: if D is where the angle bisector at vertex A meets side BC, then BD/DC = AB/AC. Validate it on the test triangles.
Exercise 4.10: Extend the nine-point circle tests to verify the remaining 3 of the 9 points — the midpoints of the segments from each vertex to the orthocenter. (Hint: these are Point((v.x + oc.x)/2, (v.y + oc.y)/2).)
Exercise 4.11: Write a .deppy sidecar for sympy.geometry.Ellipse. Specify: (a) the area formula π·a·b, (b) the eccentricity formula, (c) that a Circle is an Ellipse with a == b.
Exercise 4.12 (Challenge): Add a second deliberately false axiom — for example, "the circumradius is always less than the inradius." Verify that the runtime validation catches it. Then try to construct a scenario where the axiom is close to true but fails on a specific triangle class.