Troubleshooting Guide
Common issues and how to fix them.
Tactic Failures
"native_decide evaluated that the proposition is false"
Cause: The bound you're trying to prove is too tight for the current Taylor depth.
Solutions:
-
Increase Taylor depth:
-
Use a looser bound:
-
Use subdivision for tight bounds:
-
Check if the bound is actually true:
"could not unify ... Expr.eval ... with the goal"
error: Tactic `apply` failed: could not unify the conclusion of the term
∀ x ∈ I, Expr.eval (fun x_1 => x) (...) ≤ ↑c
with the goal
∀ x ∈ I, <your expression> ≤ ↑c
Cause: The tactic reified your expression to an Expr AST, but it doesn't match the goal syntactically.
Note: As of v1.2, most cases are now handled automatically. Expressions with numeric coefficients like
2 * x * x + 3 * x + 1should work out of the box. If you still encounter this error, try the solutions below.
This may still happen with: - Very complex nested coefficient expressions - Custom definitions that aren't unfolded - Unusual type coercions
Solutions:
-
First, just try it - most expressions now work:
-
If it still fails, build the Expr AST explicitly:
-
Use the low-level tactics with explicit arguments:
"unsolved goals" with multivariate bounds
Cause: You used certify_bound for a multivariate goal, but it only handles single-variable bounds.
Solution: Use multivariate_bound:
-- Instead of
example : ∀ x ∈ I, ∀ y ∈ J, x + y ≤ 2 := by certify_bound -- Fails
-- Use
example : ∀ x ∈ I, ∀ y ∈ J, x + y ≤ 2 := by multivariate_bound
"Cannot parse as integer: 3.14159"
Cause: Discovery commands only accept integer bounds, not floats.
Solution: Use rational approximations:
-- Instead of
#bounds (fun x => Real.sin x) on [0, 3.14159] -- Fails
-- Use integers
#bounds (fun x => Real.sin x) on [0, 4]
-- Or define a rational interval for tactics
def I_0_pi : IntervalRat := ⟨0, 314159/100000, by norm_num⟩
Warning Messages
"Optimization gap exceeds tolerance"
warning: ⚠️ Optimization gap [-0.17, 0] exceeds tolerance 1/1000.
Consider increasing maxIterations or taylorDepth.
Cause: The branch-and-bound algorithm didn't converge to the requested precision, but the proof still succeeded because the discovered bound is valid.
When to worry: Only if you need tighter bounds. The proof is still correct.
Solutions:
-- Increase Taylor depth
example : ∃ m, ∀ x ∈ I, f x ≥ m := by interval_minimize 20
-- Or just accept slightly looser bounds (the proof is still valid)
Expression Support
What works with raw Lean syntax?
Works well:
-- Basic arithmetic
x * x + 1
x^3
x^(-2)
x^(5/2)
x^(-3/2)
-- Simple coefficients
x * x + x + 1
-- Transcendentals
Real.sin x
Real.cos x
Real.exp x
Real.sin x + Real.cos x
Real.exp (Real.sin x)
Requires positive base (lowered via exp/log):
These are reified as exp(log(x) * q). The tactic automatically proves
0 < x from Set.Icc domain hypotheses when the lower bound is positive.
What requires Expr AST syntax?
Always use Expr AST for:
- interval_roots (root existence)
- root_bound (root absence)
- Low-level tactics (interval_le, interval_ge, etc.)
Example:
open LeanCert.Core
def I12 : IntervalRat := ⟨1, 2, by norm_num⟩
-- Root existence requires Expr AST
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
Precision and Taylor Depth
When to increase Taylor depth
| Situation | Recommended Depth |
|---|---|
| Polynomials only | 10 (default) |
Single transcendental (sin x, exp x) |
10-15 |
Composed transcendentals (exp(sin x)) |
15-20 |
| Tight bounds (within 1% of true value) | 20-30 |
| Very tight bounds | Use interval_bound_subdiv |
When to use fast_bound (dyadic)
Use the dyadic backend when:
- Deeply nested expressions: sin(cos(sin(x)))
- Many operations: x₁ + x₂ + ... + x₁₀₀
- Proofs with rational backend timeout or are slow
-- Dyadic handles nesting well
example : ∀ x ∈ I, Real.cos (Real.sin (Real.cos x)) ≤ 1 := by fast_bound
-- Equivalent but may be slower/fail with many terms
example : ∀ x ∈ I, Real.cos (Real.sin (Real.cos x)) ≤ 1 := by certify_bound
Debugging Tips
Enable tracing
set_option trace.certify_bound true in
example : ∀ x ∈ I, f x ≤ c := by certify_bound
set_option trace.certify_kernel true in
example : ∀ x ∈ I, f x ≤ c := by certify_kernel
Use discovery to check bounds
Before writing a theorem, verify the bound holds:
-- See what bounds actually hold
#bounds (fun x => your_expression) on [lo, hi]
-- Then prove with margin
-- If #bounds says max ≈ 2.72, prove ≤ 3
Use interval_refute to check false bounds
-- Is this bound even true?
example : ∀ x ∈ Set.Icc (-2 : ℝ) 2, x * x ≤ 3 := by
interval_refute -- Finds counterexample at x = ±2
-- The bound is false! x² = 4 > 3 at endpoints
Common Patterns
Discovery → Proof workflow
-- Step 1: Explore
#bounds (fun x => Real.exp x + Real.sin x) on [0, 1]
-- Output: f(x) ∈ [1, 3.56]
-- Step 2: Pick safe bounds (with margin)
-- Discovery says max ≈ 3.56, so prove ≤ 4
-- Step 3: Prove
example : ∀ x ∈ Set.Icc (0:ℝ) 1, Real.exp x + Real.sin x ≤ 4 := by
certify_bound 15