Exact Mathematical Modeling
leancert.ast is an immutable, bridge-independent meaning layer. Constructing
an AST does not run a solver and never sets a verified flag.
Capability status
Stability: Stable schema v1 · Authority: Deterministic semantic model · Proof status: No AST object is a proof by itself
Exact values
Semantic claims accept exact integers, Fraction, Decimal, and decimal
strings through ast.rational:
from decimal import Decimal
from fractions import Fraction
from leancert import ast
a = ast.rational("0.1")
b = ast.rational(Decimal("0.2"))
c = ast.rational(Fraction(3, 10))
assert ast.semantically_equal(a + b, c)
Python floats are rejected because the SDK cannot infer which decimal value a binary approximation was intended to mean:
Symbols have identity
Variables are identified by a namespace/name SymbolId; their display name is
metadata. This prevents accidental capture when claims are normalized or
serialized.
Domains close claims
from leancert import ast
x = ast.var("x")
open_claim = ast.sin(x) <= 1
closed_claim = ast.close_claim(open_claim, where={x: (0, 1)})
close_claim requires exact coverage of every free variable. The canonical
encoding uses binder depths, so alpha-renaming a bound variable does not change
the claim's meaning.
Use ast.interval(lo, hi) and ast.box(...) when a first-class semantic
domain is clearer than tuple shorthand. The older leancert.Interval and
leancert.Box types belong to the programmatic Solver compatibility API;
they are not interchangeable with semantic AST domains without an explicit
legacy conversion.
Canonical bytes and semantic digests
payload = ast.encode_canonical(closed_claim)
digest = ast.semantic_digest(closed_claim)
round_trip = ast.decode_canonical_strict(payload)
assert ast.alpha_equivalent(closed_claim, round_trip)
A semantic digest commits to the AST schema version, normalization version, canonical semantic bytes, and resolved external declaration identities. Annotations and source spans do not affect it.
Built-in and external functions
The semantic AST includes arithmetic, transcendental and special functions, vectors, integrals, derivatives, root claims, and eventual claims. Definite integrals are constructed explicitly:
Contract 2.6 routes exact rational-polynomial integral equalities and checked
one-sided integral bounds through prove(). Other integral shapes and
derivative expressions still have stable AST meaning without necessarily
having a negotiated checker. In general, presence in the AST does not
guarantee that the current Bridge supports every claim shape.
External functions require package, revision, semantic, and declaration identity before they can receive an authoritative semantic digest.
Legacy expressions
lc.var("x") constructs the pre-1.0 programmatic expression type. Use
ast.legacy_expression, ast.legacy_interval, ast.legacy_box, or
ast.legacy_bound_claim when migrating intentionally. Conversion is not
verification.
For programmatically generated legacy expressions, see Simplification. For advanced semantic-AST inspection and rewrites, see AST Utilities.