Skip to content

Quickstart

This guide walks through the main use cases for LeanCert.

Python SDK

Finding Bounds

import leancert as lc

x = lc.var('x')
expr = x**2 + lc.sin(x)

# Find min/max on an interval
result = lc.find_bounds(expr, {'x': (0, 1)})

print(f"Minimum: {result.min_bound}")
print(f"Maximum: {result.max_bound}")

Verifying a Bound

# Verify that x^2 + sin(x) ≤ 2 on [0, 1]
# Uses adaptive method with false positive filtering by default
verified = lc.verify_bound(expr, {'x': (0, 1)}, upper=2)

if verified:
    print("Bound verified!")

# For a certificate that can be exported to Lean, use find_bounds:
result = lc.find_bounds(expr, {'x': (0, 1)})
if result.max_bound.hi <= 2:
    print(result.certificate.to_lean_tactic())

Finding Roots

# Find where x^2 - 2 = 0 on [1, 2]
roots = lc.find_roots(x**2 - 2, {'x': (1, 2)})

for root in roots.intervals:
    print(f"Root in [{root.lo}, {root.hi}]")

Symbolic Simplification

LeanCert automatically simplifies expressions to avoid interval explosion:

# Without simplification: (x*100 + 5) - (x*100) would have wide bounds
# With simplification: reduces to 5
expr = (x * 100 + 5) - (x * 100)
simplified = lc.simplify(expr)  # Returns const(5)

Lean Tactics

Point Inequalities (interval_decide)

To prove inequalities involving specific numbers (including transcendentals like π or e), use interval_decide:

import LeanCert.Tactic.IntervalAuto

-- Proves π < 3.15
example : Real.pi < 3.15 := by interval_decide

-- Proves e < 3
example : Real.exp 1 < 3 := by interval_decide

-- For complex expressions with constants
example : Real.sin 1 + Real.cos 1 < 1.5 := by interval_decide

Proving Bounds (certify_bound)

import LeanCert.Tactic.IntervalAuto

open LeanCert.Core

-- Use natural Set.Icc syntax with integer bounds
example :  x  Set.Icc (0 : ) 1, Real.exp x  3 := by certify_bound 15
example :  x  Set.Icc (0 : ) 1, Real.sin x  1 := by certify_bound
example :  x  Set.Icc (0 : ) 1, 0  Real.exp x := by certify_bound

-- Lower bounds work too
example :  x  Set.Icc (0 : ) 1, 0  x * x := by certify_bound

-- Or use explicit IntervalRat for more control
def I01 : IntervalRat := 0, 1, by norm_num
example :  x  I01, Real.exp x  (3 : ) := by certify_bound 15

Kernel-Verified Bounds (certify_kernel)

For higher trust, use certify_kernel. Unlike certify_bound which trusts the Lean compiler (native_decide), certify_kernel uses the dyadic backend and reduces proofs entirely within the Lean kernel (decide) when possible.

import LeanCert.Tactic.DyadicAuto

-- Same syntax as certify_bound, but uses dyadic backend
example :  x  Set.Icc (0 : ) 1, x * x + Real.sin x  2 := by
  certify_kernel

-- Increase precision (bits) for tight bounds
example :  x  Set.Icc (0 : ) 1, Real.exp x  2.72 := by
  certify_kernel 100

-- Convenience variants
example :  x  Set.Icc (0 : ) 1, Real.exp x  2.72 := by
  certify_kernel_precise  -- 100 bits precision

example :  x  Set.Icc (0 : ) 1, x * x  2 := by
  certify_kernel_quick    -- 30 bits, faster
Tactic Backend Verification Trust Level
certify_bound Rational native_decide Compiler + Runtime
certify_kernel Dyadic decide (when possible) Kernel only

Finding Counter-Examples (interval_refute)

If a bound doesn't hold, use interval_refute to find a counter-example:

import LeanCert.Tactic.Refute

-- A false theorem - interval_refute finds where it fails
example :  x  Set.Icc (-2 : ) 2, x * x  3 := by
  interval_refute
  -- Output: Counter-example found at x ≈ ±2, where x² = 4 > 3

Proving Root Existence

import LeanCert.Tactic.Discovery

open LeanCert.Core

def I12 : IntervalRat := 1, 2, by norm_num

-- Prove √2 exists via sign change
example :  x  I12, Expr.eval (fun _ => x)
    (Expr.add (Expr.mul (Expr.var 0) (Expr.var 0)) (Expr.neg (Expr.const 2))) = 0 := by
  interval_roots

Multivariate Bounds

import LeanCert.Tactic.IntervalAuto

-- Prove bounds over multiple variables
example :  x  Set.Icc (0:) 1,  y  Set.Icc (0:) 1,
    x + y  (2 : ) := by
  multivariate_bound

example :  x  Set.Icc (0:) 1,  y  Set.Icc (0:) 1,  z  Set.Icc (0:) 1,
    x + y + z  (3 : ) := by
  multivariate_bound

Proving Absence of Roots

import LeanCert.Tactic.IntervalAuto

open LeanCert.Core

def I01 : IntervalRat := 0, 1, by norm_num

-- Prove f(x) ≠ 0 by showing function stays positive/negative
example :  x  I01, Expr.eval (fun _ => x)
    (Expr.add (Expr.mul (Expr.var 0) (Expr.var 0)) (Expr.const 1))  (0 : ) := by
  root_bound

Discovery Commands

For interactive exploration in the editor:

import LeanCert.Discovery

-- Find the global minimum
#find_min (fun x => x^2 + Real.sin x) on [-2, 2]

-- Explore function behavior
#explore (Expr.cos (Expr.var 0)) on [0, 4]

Discovering Bounds (Existential)

import LeanCert.Tactic.Discovery

-- Automatically find and prove a minimum exists
example :  m : ,  x  Set.Icc (0:) 1, x^2  m := by
  interval_minimize

-- Find maximum
example :  M : ,  x  Set.Icc (0:) 1, x^2  M := by
  interval_maximize

-- Multivariate optimization
example :  m : ,  x  Set.Icc (0:) 1,  y  Set.Icc (0:) 1,
    x*x + y*y  m := by
  interval_minimize_mv

High-Performance Dyadic Backend

For deep expressions (neural networks, optimization loops, nested transcendentals), use the dyadic backend to avoid rational denominator explosion:

import LeanCert.Engine.IntervalEvalDyadic

open LeanCert.Core LeanCert.Engine

-- Convert interval to dyadic
def I : IntervalDyadic := IntervalDyadic.ofIntervalRat 0, 1, by norm_num (-53)

-- Evaluate with standard precision (53 bits)
def result := evalIntervalDyadic expr (fun _ => I) {}

-- Use fast mode for very deep expressions
def fast := evalIntervalDyadic expr (fun _ => I) DyadicConfig.fast

-- Use high precision for tight bounds
def precise := evalIntervalDyadic expr (fun _ => I) DyadicConfig.highPrecision

The dyadic backend keeps mantissa size bounded regardless of expression depth, while rational denominators grow exponentially.

Direct API

For more control, use the certificate API directly:

import LeanCert.Validity

open LeanCert.Core LeanCert.Engine LeanCert.Validity

def exprXSq : Expr := Expr.mul (Expr.var 0) (Expr.var 0)

def exprXSq_core : ExprSupportedCore exprXSq :=
  ExprSupportedCore.mul (ExprSupportedCore.var 0) (ExprSupportedCore.var 0)

def I01 : IntervalRat := 0, 1, by norm_num

-- Use native_decide to verify computationally
theorem xsq_le_one :  x  I01, Expr.eval (fun _ => x) exprXSq  (1 : ) :=
  verify_upper_bound exprXSq exprXSq_core I01 1 {} (by native_decide)