Complexitylib guide

2.2. Polynomial Time🔗

ComputableInPolyTime f encIn encOut says that some multi-tape Turing machine with a binary alphabet and finitely many states computes f, reading encIn a and writing encOut (f a), within time and space bounded by polynomials in the length of encIn a. This is the notion that definitions and theorems use.

You rarely build machines. Closure rules for the usual operations are registered with fun_prop, so a function written with certified operations gets its certificate automatically:

example : ComputableInPolyTime (fun p : ℕ × ℕ => p.1 * p.2 + 1) (encPair encNat encNat) encNat := ⊢ ComputableInPolyTime (fun p => p.1 * p.2 + 1) (encPair encNat encNat) encNat All goals completed! 🐙 example : ComputableInPolyTime (fun l : List ℕ => l.map (· + 1)) (encList encNat) (encList encNat) := ⊢ ComputableInPolyTime (fun l => List.map (fun x => x + 1) l) (encList encNat) (encList encNat) All goals completed! 🐙

Loops whose body depends on the rest of the input, such as a filter that compares each element with another part of the input, need the polytime tactic, which chooses loop rules and composes certificates. Membership tests and their negations are certified too:

example : ComputableInPolyTime (fun p : List ℕ × ℕ => p.1.filter (· ≤ p.2)) (encPair (encList encNat) encNat) (encList encNat) := ⊢ ComputableInPolyTime (fun p => List.filter (fun x => decide (x ≤ p.2)) p.1) (encPair (encList encNat) encNat) (encList encNat) All goals completed! 🐙 example : ComputableInPolyTime (fun p : List ℕ × List ℕ => p.1.filter fun x => x ∉ p.2) (encPair (encList encNat) (encList encNat)) (encList encNat) := ⊢ ComputableInPolyTime (fun p => List.filter (fun x => decide (x ∉ p.2)) p.1) (encPair (encList encNat) (encList encNat)) (encList encNat) All goals completed! 🐙

Both tactics prove only the cost. That f computes what you intend is a separate proof.