| set_option showInferredTerminationBy true | |
| def countUp (n i acc : Nat) : Nat := | |
| if i < n then | |
| countUp n (i+1) (acc + i) | |
| else | |
| acc | |
| def all42 (xs : Array Nat) (i : Nat) : Bool := | |
| if h : i < xs.size then | |
| if xs[i] = 42 then | |
| all42 xs (i+1) | |
| else | |
| false | |
| else | |
| true | |
| def henrik1 (xs : Array Nat) (i : Nat) : Bool := | |
| if h : i < xs.size then | |
| if xs[i] = 42 then | |
| henrik1 (xs.push 42) (i+2) | |
| else | |
| false | |
| else | |
| true | |
| def merge (xs ys : Array Nat) : Array Nat := | |
| let rec loop (i j : Nat) (acc : Array Nat) : Array Nat := | |
| if _ : i < xs.size then | |
| if _ : j < ys.size then | |
| if xs[i] < ys[j] then | |
| loop (i+1) j (acc.push xs[i]) | |
| else | |
| loop i (j+1) (acc.push ys[j]) | |
| else | |
| loop (i+1) j (acc.push xs[i]) | |
| else | |
| if _ : j < ys.size then | |
| loop i (j+1) (acc.push ys[j]) | |
| else | |
| acc | |
| loop 0 0 #[] | |
| def distinct (xs : Array Nat) : Bool := | |
| let rec loop (i j : Nat) : Bool := | |
| if _ : i < xs.size then | |
| if _ : j < i then | |
| if xs[j] = xs[i] then | |
| false | |
| else | |
| loop i (j+1) | |
| else | |
| loop (i+1) 0 | |
| else | |
| true | |
| loop 0 0 | |
| -- This examples shows a limitation of our current `decreasing_tactic`. | |
| -- Guesslex infers `termination_by (Array.size xs - i, i)` but because `decreasing_with` is using | |
| -- repeat (first | apply Prod.Lex.right | apply Prod.Lex.left) | |
| -- it cannot solve this goal. But if we leave the Prod.Lex-handling to omega, it works. | |
| -- See https://github.com/leanprover/lean4/issues/3906 | |
| def weird (xs : Array Nat) (i : Nat) : Bool := | |
| if _ : i < xs.size then | |
| if _ : 0 < i then | |
| if xs[i] = 42 then | |
| weird xs.pop (i - 1) | |
| else | |
| weird xs (i+1) | |
| else | |
| weird xs (i+1) | |
| else | |
| true | |
| decreasing_by all_goals (try simp only [Array.size_pop]); omega | |
| /-- | |
| This checks | |
| * the presentation of complex measures in the table | |
| * that multiple recursive calls do not lead to the same argument tried multiple times. | |
| * it uses `e` instead of `e - 0` | |
| * that we do not get measures from refined arguments | |
| -/ | |
| def failure (xs : Array Nat) (i : Nat) : Bool := | |
| if h : i < xs.size then failure xs i && failure xs i && failure xs (i + 1) else | |
| if h : i + 1 < xs.size then failure xs i else | |
| let j := i | |
| if h : j < xs.size then failure xs (j+1) else | |
| if h : 0 < i then failure xs (j+1) else | |
| if h : 42 < i then failure xs (j+1) else | |
| if h : xs.size < i then failure xs (j+1) else | |
| if h : 42 < i + i then failure xs (j+1) else | |
| match i with | |
| | 0 => true | |
| | i+1 => | |
| if h : i < xs.size + 5 then | |
| failure xs i | |
| else | |
| false | |
| mutual | |
| def mutual_failure (xs : Array Nat) (i : Nat) : Bool := | |
| if h : i < xs.size then | |
| mutual_failure2 xs i && mutual_failure2 xs i && mutual_failure2 xs (i + 1) | |
| else | |
| if h : i + 1 < xs.size then | |
| mutual_failure2 xs i | |
| else | |
| let j := i | |
| if h : j < xs.size then | |
| mutual_failure2 xs (j+1) | |
| else | |
| match i with | |
| | 0 => true | |
| | i+1 => | |
| if h : i < xs.size then | |
| mutual_failure2 xs i | |
| else | |
| false | |
| def mutual_failure2 (xs : Array Nat) (i : Nat) : Bool := | |
| if h : i < xs.size then | |
| mutual_failure xs i && mutual_failure xs i && mutual_failure xs (i + 1) | |
| else | |
| let j := i | |
| if h : j < xs.size then | |
| mutual_failure xs (j+1) | |
| else | |
| match i with | |
| | 0 => true | |
| | i+1 => | |
| if h : i < xs.size then | |
| mutual_failure xs i | |
| else | |
| false | |
| end |