feat: GuessLex: if no measure is found, explain why (#2960)
by showing the matrix of calls and measures, and what we know about that
call (=, <, ≤, ?), e.g.
guessLexFailures.lean:27:0-33:31: error: Could not find a decreasing
measure.
The arguments relate at each recursive call as follows:
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
x1 x2 x3
1) 29:6-25 = = =
2) 30:6-23 = ? <
3) 31:6-23 < _ _
Please use `termination_by` to specify a decreasing measure
It’s a bit more verbose for mutual functions.
It will use the user-specified argument names for functions written
```
foo (n : Nat) := …
```
but not with pattern matching like
```
foo : Nat → …
| n => …
```
This can be refined later and separately (and maybe right away in
`expandMatchAltsWhereDecls`).
This commit is contained in:
parent
9290b491bb
commit
17825bf81d
5 changed files with 400 additions and 58 deletions
|
|
@ -207,6 +207,8 @@ def SavedLocalContext.run {α} (slc : SavedLocalContext) (k : MetaM α) :
|
|||
/-- A `RecCallWithContext` focuses on a single recursive call in a unary predefinition,
|
||||
and runs the given action in the context of that call. -/
|
||||
structure RecCallWithContext where
|
||||
/-- Syntax location of reursive call -/
|
||||
ref : Syntax
|
||||
/-- Function index of caller -/
|
||||
caller : Nat
|
||||
/-- Parameters of caller -/
|
||||
|
|
@ -218,9 +220,9 @@ structure RecCallWithContext where
|
|||
ctxt : SavedLocalContext
|
||||
|
||||
/-- Store the current recursive call and its context. -/
|
||||
def RecCallWithContext.create (caller : Nat) (params : Array Expr) (callee : Nat) (args : Array Expr) :
|
||||
MetaM RecCallWithContext := do
|
||||
return { caller, params, callee, args, ctxt := (← SavedLocalContext.create) }
|
||||
def RecCallWithContext.create (ref : Syntax) (caller : Nat) (params : Array Expr) (callee : Nat)
|
||||
(args : Array Expr) : MetaM RecCallWithContext := do
|
||||
return { ref, caller, params, callee, args, ctxt := (← SavedLocalContext.create) }
|
||||
|
||||
/-- Given the packed argument of a (possibly) mutual and (possibly) nary call,
|
||||
return the function index that is called and the arguments individually.
|
||||
|
|
@ -273,18 +275,21 @@ def collectRecCalls (unaryPreDef : PreDefinition) (fixedPrefixSize : Nat) (ariti
|
|||
let arg := args[fixedPrefixSize]!
|
||||
let (caller, params) ← unpackArg arities param
|
||||
let (callee, args) ← unpackArg arities arg
|
||||
RecCallWithContext.create caller params callee args
|
||||
RecCallWithContext.create (← getRef) caller params callee args
|
||||
|
||||
/-- A `GuessLexRel` described how a recursive call affects a measure; whether it
|
||||
decreases strictly, non-strictly, is equal, or else. -/
|
||||
inductive GuessLexRel | lt | eq | le | no_idea
|
||||
deriving Repr, DecidableEq
|
||||
|
||||
instance : ToString GuessLexRel where
|
||||
toString | .lt => "<"
|
||||
| .eq => "="
|
||||
| .le => "≤"
|
||||
| .no_idea => "?"
|
||||
|
||||
instance : ToFormat GuessLexRel where
|
||||
format | .lt => "<"
|
||||
| .eq => "="
|
||||
| .le => "≤"
|
||||
| .no_idea => "?"
|
||||
format r := toString r
|
||||
|
||||
/-- Given a `GuessLexRel`, produce a binary `Expr` that relates two `Nat` values accordingly. -/
|
||||
def GuessLexRel.toNatRel : GuessLexRel → Expr
|
||||
|
|
@ -370,16 +375,13 @@ def RecCallCache.eval (rc: RecCallCache) (paramIdx argIdx : Nat) : MetaM GuessLe
|
|||
rc.cache.modify (·.modify paramIdx (·.set! argIdx res))
|
||||
return res
|
||||
|
||||
/-- Pretty-print the cache entries -/
|
||||
def RecCallCache.pretty (rc : RecCallCache) : IO Format := do
|
||||
let mut r := Format.nil
|
||||
let d ← rc.cache.get
|
||||
for h₁ : paramIdx in [:d.size] do
|
||||
for h₂ : argIdx in [:(d[paramIdx]'h₁.2).size] do
|
||||
if let .some entry := (d[paramIdx]'h₁.2)[argIdx]'h₂.2 then
|
||||
r := r ++
|
||||
f!"(Param {paramIdx}, arg {argIdx}): {entry}" ++ Format.line
|
||||
return r
|
||||
|
||||
/-- Print a single cache entry as a string, without forcing it -/
|
||||
def RecCallCache.prettyEntry (rcc : RecCallCache) (paramIdx argIdx : Nat) : MetaM String := do
|
||||
let cachedEntries ← rcc.cache.get
|
||||
return match cachedEntries[paramIdx]![argIdx]! with
|
||||
| .some rel => toString rel
|
||||
| .none => "_"
|
||||
|
||||
/-- The measures that we order lexicographically can be comparing arguments,
|
||||
or numbering the functions -/
|
||||
|
|
@ -551,6 +553,103 @@ def buildTermWF (declNames : Array Name) (varNamess : Array (Array Name))
|
|||
}
|
||||
return .ext termByElements
|
||||
|
||||
|
||||
/--
|
||||
Given a matrix (row-major) of strings, arranges them in tabular form.
|
||||
First column is left-aligned, others right-aligned.
|
||||
Single space as column separator.
|
||||
-/
|
||||
def formatTable : Array (Array String) → String := fun xss => Id.run do
|
||||
let mut colWidths := xss[0]!.map (fun _ => 0)
|
||||
for i in [:xss.size] do
|
||||
for j in [:xss[i]!.size] do
|
||||
if xss[i]![j]!.length > colWidths[j]! then
|
||||
colWidths := colWidths.set! j xss[i]![j]!.length
|
||||
let mut str := ""
|
||||
for i in [:xss.size] do
|
||||
for j in [:xss[i]!.size] do
|
||||
let s := xss[i]![j]!
|
||||
if j > 0 then -- right-align
|
||||
for _ in [:colWidths[j]! - s.length] do
|
||||
str := str ++ " "
|
||||
str := str ++ s
|
||||
if j = 0 then -- left-align
|
||||
for _ in [:colWidths[j]! - s.length] do
|
||||
str := str ++ " "
|
||||
if j + 1 < xss[i]!.size then
|
||||
str := str ++ " "
|
||||
if i + 1 < xss.size then
|
||||
str := str ++ "\n"
|
||||
return str
|
||||
|
||||
/-- Concise textual representation of the source location of a recursive call -/
|
||||
def RecCallWithContext.posString (rcc : RecCallWithContext) : MetaM String := do
|
||||
let fileMap ← getFileMap
|
||||
let .some pos := rcc.ref.getPos? | return ""
|
||||
let position := fileMap.toPosition pos
|
||||
let endPosStr := match rcc.ref.getTailPos? with
|
||||
| some endPos =>
|
||||
let endPosition := fileMap.toPosition endPos
|
||||
if endPosition.line = position.line then
|
||||
s!"-{endPosition.column}"
|
||||
else
|
||||
s!"-{endPosition.line}:{endPosition.column}"
|
||||
| none => ""
|
||||
return s!"{position.line}:{position.column}{endPosStr}"
|
||||
|
||||
|
||||
/-- Explain what we found out about the recursive calls (non-mutual case) -/
|
||||
def explainNonMutualFailure (varNames : Array Name) (rcs : Array RecCallCache) : MetaM Format := do
|
||||
let header := varNames.map (·.eraseMacroScopes.toString)
|
||||
let mut table : Array (Array String) := #[#[""] ++ header]
|
||||
for i in [:rcs.size], rc in rcs do
|
||||
let mut row := #[s!"{i+1}) {← rc.rcc.posString}"]
|
||||
for argIdx in [:varNames.size] do
|
||||
row := row.push (← rc.prettyEntry argIdx argIdx)
|
||||
table := table.push row
|
||||
|
||||
return formatTable table
|
||||
|
||||
/-- Explain what we found out about the recursive calls (mutual case) -/
|
||||
def explainMutualFailure (declNames : Array Name) (varNamess : Array (Array Name))
|
||||
(rcs : Array RecCallCache) : MetaM Format := do
|
||||
let mut r := Format.nil
|
||||
|
||||
for rc in rcs do
|
||||
let caller := rc.rcc.caller
|
||||
let callee := rc.rcc.callee
|
||||
r := r ++ f!"Call from {declNames[caller]!} to {declNames[callee]!} " ++
|
||||
f!"at {← rc.rcc.posString}:\n"
|
||||
|
||||
let header := varNamess[caller]!.map (·.eraseMacroScopes.toString)
|
||||
let mut table : Array (Array String) := #[#[""] ++ header]
|
||||
if caller = callee then
|
||||
-- For self-calls, only the diagonal is interesting, so put it into one row
|
||||
let mut row := #[""]
|
||||
for argIdx in [:varNamess[caller]!.size] do
|
||||
row := row.push (← rc.prettyEntry argIdx argIdx)
|
||||
table := table.push row
|
||||
else
|
||||
for argIdx in [:varNamess[callee]!.size] do
|
||||
let mut row := #[]
|
||||
row := row.push varNamess[callee]![argIdx]!.eraseMacroScopes.toString
|
||||
for paramIdx in [:varNamess[caller]!.size] do
|
||||
row := row.push (← rc.prettyEntry paramIdx argIdx)
|
||||
table := table.push row
|
||||
r := r ++ formatTable table ++ "\n"
|
||||
|
||||
return r
|
||||
|
||||
def explainFailure (declNames : Array Name) (varNamess : Array (Array Name))
|
||||
(rcs : Array RecCallCache) : MetaM Format := do
|
||||
let mut r : Format := "The arguments relate at each recursive call as follows:\n" ++
|
||||
"(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)\n"
|
||||
if declNames.size = 1 then
|
||||
r := r ++ (← explainNonMutualFailure varNamess[0]! rcs)
|
||||
else
|
||||
r := r ++ (← explainMutualFailure declNames varNamess rcs)
|
||||
return r
|
||||
|
||||
end Lean.Elab.WF.GuessLex
|
||||
|
||||
namespace Lean.Elab.WF
|
||||
|
|
@ -566,33 +665,32 @@ terminates. See the module doc string for a high-level overview.
|
|||
def guessLex (preDefs : Array PreDefinition) (unaryPreDef : PreDefinition)
|
||||
(fixedPrefixSize : Nat) (decrTactic? : Option Syntax) :
|
||||
MetaM TerminationWF := do
|
||||
try
|
||||
let varNamess ← preDefs.mapM (naryVarNames fixedPrefixSize ·)
|
||||
let arities := varNamess.map (·.size)
|
||||
trace[Elab.definition.wf] "varNames is: {varNamess}"
|
||||
let varNamess ← preDefs.mapM (naryVarNames fixedPrefixSize ·)
|
||||
let arities := varNamess.map (·.size)
|
||||
trace[Elab.definition.wf] "varNames is: {varNamess}"
|
||||
|
||||
let forbiddenArgs ← preDefs.mapM fun preDef =>
|
||||
getForbiddenByTrivialSizeOf fixedPrefixSize preDef
|
||||
let forbiddenArgs ← preDefs.mapM fun preDef =>
|
||||
getForbiddenByTrivialSizeOf fixedPrefixSize preDef
|
||||
|
||||
-- The list of measures, including the measures that order functions.
|
||||
-- The function ordering measures come last
|
||||
let measures ← generateMeasures forbiddenArgs arities
|
||||
-- The list of measures, including the measures that order functions.
|
||||
-- The function ordering measures come last
|
||||
let measures ← generateMeasures forbiddenArgs arities
|
||||
|
||||
-- If there is only one plausible measure, use that
|
||||
if let #[solution] := measures then
|
||||
return ← buildTermWF (preDefs.map (·.declName)) varNamess #[solution]
|
||||
-- If there is only one plausible measure, use that
|
||||
if let #[solution] := measures then
|
||||
return ← buildTermWF (preDefs.map (·.declName)) varNamess #[solution]
|
||||
|
||||
-- Collect all recursive calls and extract their context
|
||||
let recCalls ← collectRecCalls unaryPreDef fixedPrefixSize arities
|
||||
let rcs ← recCalls.mapM (RecCallCache.mk decrTactic? ·)
|
||||
let callMatrix := rcs.map (inspectCall ·)
|
||||
-- Collect all recursive calls and extract their context
|
||||
let recCalls ← collectRecCalls unaryPreDef fixedPrefixSize arities
|
||||
let rcs ← recCalls.mapM (RecCallCache.mk decrTactic? ·)
|
||||
let callMatrix := rcs.map (inspectCall ·)
|
||||
|
||||
match ← liftMetaM <| solve measures callMatrix with
|
||||
| .some solution => do
|
||||
let wf ← buildTermWF (preDefs.map (·.declName)) varNamess solution
|
||||
return wf
|
||||
| .none => throwError "Cannot find a decreasing lexicographic order"
|
||||
catch _ =>
|
||||
-- Hide all errors from guessing lexicographic orderings, as before
|
||||
-- Future work: explain the failure to the user, like Isabelle does
|
||||
throwError "failed to prove termination, use `termination_by` to specify a well-founded relation"
|
||||
match ← liftMetaM <| solve measures callMatrix with
|
||||
| .some solution => do
|
||||
let wf ← buildTermWF (preDefs.map (·.declName)) varNamess solution
|
||||
return wf
|
||||
| .none =>
|
||||
let explanation ← explainFailure (preDefs.map (·.declName)) varNamess rcs
|
||||
Lean.throwError <| "Could not find a decreasing measure.\n" ++
|
||||
explanation ++ "\n" ++
|
||||
"Please use `termination_by` to specify a decreasing measure."
|
||||
|
|
|
|||
|
|
@ -17,21 +17,117 @@ def nonTerminating2 : Nat → Nat → Nat
|
|||
| n, m => nonTerminating2 (.succ n) (.succ m)
|
||||
decreasing_by decreasing_tactic
|
||||
|
||||
def noArguments : Nat := noArguments
|
||||
|
||||
-- The GuessLex code does not like eta-contracted motives in `casesOn`.
|
||||
-- At the time of writing, the error message is swallowed
|
||||
-- When guessing the lexicographic order becomes more verbose this will improve.
|
||||
def noNonFixedArguments (n : Nat) : Nat := noNonFixedArguments n
|
||||
|
||||
def Array.sum (xs : Array Nat) : Nat := xs.foldl (init := 0) Nat.add
|
||||
|
||||
namespace InterestingMatrix
|
||||
def f : (n m l : Nat) → Nat
|
||||
| n+1, m+1, l+1 => #[
|
||||
f (n+1) (m+1) (l+1),
|
||||
f (n+1) (m-1) (l),
|
||||
f (n) (m+1) (l) ].sum
|
||||
| _, _, _ => 0
|
||||
decreasing_by decreasing_tactic
|
||||
end InterestingMatrix
|
||||
|
||||
namespace InterestingMatrixWithForbiddenArguments
|
||||
def f : (n m : Nat) → (h : True) → Nat → Nat
|
||||
| n+1, m+1, h, l+1 => #[
|
||||
f (n+1) (m+1) h (l+1),
|
||||
f (n+1) (m-1) h (l),
|
||||
f (n) (m+1) h (l) ].sum
|
||||
| _, _, _, _ => 0
|
||||
decreasing_by decreasing_tactic
|
||||
end InterestingMatrixWithForbiddenArguments
|
||||
|
||||
namespace InterestingMatrixWithNames
|
||||
-- Hopefully eventually lean will pick up names even with pattern match syntax
|
||||
def f (n m l : Nat) : Nat := match n, m, l with
|
||||
| n+1, m+1, l+1 => #[
|
||||
f (n+1) (m+1) (l+1),
|
||||
f (n+1) (m-1) (l),
|
||||
f (n) (m+1) (l) ].sum
|
||||
| _, _, _ => 0
|
||||
decreasing_by decreasing_tactic
|
||||
end InterestingMatrixWithNames
|
||||
|
||||
namespace Mutual
|
||||
mutual
|
||||
def f (fixed n m l : Nat) : Nat := match n, m, l with
|
||||
| n+1, m+1, l+1 => #[
|
||||
f fixed (n+1) (m+1) (l+1),
|
||||
f fixed (n+1) (m-1) (l),
|
||||
g fixed (n) (m+1) trivial (l)].sum
|
||||
| _, _, _ => 0
|
||||
|
||||
def g (fixed n m : Nat) (H : True) (l : Nat) : Nat := match n, m, l with
|
||||
| n+1, m+1, l+1 => #[
|
||||
g fixed (m+1) (n+1) H (l+1),
|
||||
g fixed (m+1) (n-1) H (l),
|
||||
h fixed (m) (n+1) ].sum
|
||||
| _, _, _ => 0
|
||||
|
||||
def h (fixed : Nat) : (n m : Nat) -> Nat
|
||||
| n+1, m+1 => #[
|
||||
f fixed (n+1) (m+1) (n+1),
|
||||
h fixed (n+1) (m-1),
|
||||
h fixed (n) (m+1) ].sum
|
||||
| _, _ => 0
|
||||
end
|
||||
end Mutual
|
||||
|
||||
|
||||
namespace DuplicatedCall
|
||||
|
||||
def dup (a : Nat) (b : Nat := a) := a + b
|
||||
|
||||
def f : (n m : Nat) → Nat
|
||||
| 0, m => m
|
||||
| n+1, m => dup (f (n+2) (m+1))
|
||||
|
||||
end DuplicatedCall
|
||||
|
||||
namespace TrickyCode
|
||||
|
||||
-- These tests run GuessLex on peculiar code that it once stumbled over, or might
|
||||
-- stumble over in the future.
|
||||
|
||||
-- The GuessLex code at some point did not like eta-contracted motives in `casesOn`.
|
||||
def FinPlus1 n := Fin (n + 1)
|
||||
def badCasesOn (n m : Nat) : Fin (n + 1) :=
|
||||
Nat.casesOn (motive := FinPlus1) n (⟨0,Nat.zero_lt_succ _⟩) (fun n => Fin.succ (badCasesOn n (.succ m)))
|
||||
-- termination_by badCasesOn n m => n
|
||||
decreasing_by decreasing_tactic
|
||||
-- termination_by badCasesOn n => n
|
||||
|
||||
|
||||
-- Like above, but now with a `casesOn` alternative with insufficient lambdas
|
||||
def Fin_succ_comp (f : (n : Nat) → Fin (n + 1)) : (n : Nat) → Fin (n + 2) := fun n => Fin.succ (f n)
|
||||
-- This actually also fails with an explicit termination_by, and could be fixed
|
||||
-- by eta-expanding the motive.
|
||||
-- TODO: Fix by using eta-expanding variant of lambdaTelescope, e.g.
|
||||
-- https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Going.20under.20exactly.20one.20lambda/near/404278529
|
||||
def badCasesOn2 (n m : Nat) : Fin (n + 1) :=
|
||||
Nat.casesOn (motive := fun n => Fin (n + 1)) n (⟨0,Nat.zero_lt_succ _⟩)
|
||||
(Fin_succ_comp (fun n => badCasesOn2 n (.succ m)))
|
||||
Nat.casesOn (motive := FinPlus1) n (⟨0,Nat.zero_lt_succ _⟩) (fun n => Fin.succ (badCasesOn2 n (.succ m)))
|
||||
termination_by badCasesOn2 n m => n
|
||||
decreasing_by decreasing_tactic
|
||||
-- termination_by badCasesOn2 n => n
|
||||
|
||||
-- The GuessLex code at does not like `casesOn` alternative with insufficient lambdas
|
||||
-- TODO: Fix by using eta-expanding variant of lambdaTelescope, e.g.
|
||||
-- https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Going.20under.20exactly.20one.20lambda/near/404278529
|
||||
def Fin_succ_comp (f : (n : Nat) → Fin (n + 1)) : (n : Nat) → Fin (n + 2) := fun n => Fin.succ (f n)
|
||||
def badCasesOn3 (n m : Nat) : Fin (n + 1) :=
|
||||
Nat.casesOn (motive := fun n => Fin (n + 1)) n (⟨0,Nat.zero_lt_succ _⟩)
|
||||
(Fin_succ_comp (fun n => badCasesOn3 n (.succ m)))
|
||||
-- termination_by badCasesOn3 n m => n
|
||||
decreasing_by decreasing_tactic
|
||||
|
||||
|
||||
-- Same test, explicit termination_by
|
||||
def badCasesOn4 (n m : Nat) : Fin (n + 1) :=
|
||||
Nat.casesOn (motive := fun n => Fin (n + 1)) n (⟨0,Nat.zero_lt_succ _⟩)
|
||||
(Fin_succ_comp (fun n => badCasesOn4 n (.succ m)))
|
||||
termination_by badCasesOn4 n m => n
|
||||
decreasing_by decreasing_tactic
|
||||
|
||||
end TrickyCode
|
||||
|
|
|
|||
|
|
@ -11,7 +11,140 @@ argument #2 was not used for structural recursion
|
|||
|
||||
structural recursion cannot be used
|
||||
|
||||
failed to prove termination, use `termination_by` to specify a well-founded relation
|
||||
guessLexFailures.lean:15:0-18:31: error: failed to prove termination, use `termination_by` to specify a well-founded relation
|
||||
guessLexFailures.lean:25:0-27:31: error: failed to prove termination, use `termination_by` to specify a well-founded relation
|
||||
guessLexFailures.lean:33:0-36:31: error: failed to prove termination, use `termination_by` to specify a well-founded relation
|
||||
Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
x1 x2
|
||||
1) 11:12-46 ? ?
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
guessLexFailures.lean:15:0-18:31: error: Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
x1 x2
|
||||
1) 17:12-47 ? ?
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
guessLexFailures.lean:20:4-20:15: error: fail to show termination for
|
||||
noArguments
|
||||
with errors
|
||||
structural recursion cannot be used
|
||||
|
||||
well-founded recursion cannot be used, 'noArguments' does not take any (non-fixed) arguments
|
||||
guessLexFailures.lean:22:4-22:23: error: fail to show termination for
|
||||
noNonFixedArguments
|
||||
with errors
|
||||
structural recursion cannot be used
|
||||
|
||||
well-founded recursion cannot be used, 'noNonFixedArguments' does not take any (non-fixed) arguments
|
||||
guessLexFailures.lean:27:0-33:31: error: Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
x1 x2 x3
|
||||
1) 29:6-25 = = =
|
||||
2) 30:6-23 = ? <
|
||||
3) 31:6-23 < _ _
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
guessLexFailures.lean:37:0-43:31: error: Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
x1 x2 x3 x4
|
||||
1) 39:6-27 = = _ =
|
||||
2) 40:6-25 = ? _ <
|
||||
3) 41:6-25 < _ _ _
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
guessLexFailures.lean:48:0-54:31: error: Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
n m l
|
||||
1) 50:6-25 = = =
|
||||
2) 51:6-23 = ? <
|
||||
3) 52:6-23 < _ _
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
guessLexFailures.lean:59:6-59:7: error: fail to show termination for
|
||||
Mutual.f
|
||||
Mutual.g
|
||||
Mutual.h
|
||||
with errors
|
||||
structural recursion does not handle mutually recursive functions
|
||||
|
||||
Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
Call from Mutual.f to Mutual.f at 61:8-33:
|
||||
n m l
|
||||
= = =
|
||||
Call from Mutual.f to Mutual.f at 62:8-31:
|
||||
n m l
|
||||
= ? <
|
||||
Call from Mutual.f to Mutual.g at 63:8-39:
|
||||
n m l
|
||||
n < _ ?
|
||||
m ? _ ?
|
||||
H _ _ _
|
||||
l ? _ <
|
||||
Call from Mutual.g to Mutual.g at 68:8-35:
|
||||
n m H l
|
||||
? _ _ =
|
||||
Call from Mutual.g to Mutual.g at 69:8-33:
|
||||
n m H l
|
||||
_ _ _ <
|
||||
Call from Mutual.g to Mutual.h at 70:8-27:
|
||||
n m H l
|
||||
x1 _ _ _ ?
|
||||
x2 _ _ _ ?
|
||||
Call from Mutual.h to Mutual.f at 75:8-33:
|
||||
x1 x2
|
||||
n _ _
|
||||
m _ _
|
||||
l _ _
|
||||
Call from Mutual.h to Mutual.h at 76:8-27:
|
||||
x1 x2
|
||||
_ _
|
||||
Call from Mutual.h to Mutual.h at 77:8-27:
|
||||
x1 x2
|
||||
_ _
|
||||
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
guessLexFailures.lean:89:19-89:32: error: fail to show termination for
|
||||
DuplicatedCall.f
|
||||
with errors
|
||||
argument #1 was not used for structural recursion
|
||||
failed to eliminate recursive application
|
||||
DuplicatedCall.f (n + 2) (m + 1)
|
||||
|
||||
argument #2 was not used for structural recursion
|
||||
failed to eliminate recursive application
|
||||
DuplicatedCall.f (n + 2) (m + 1)
|
||||
|
||||
structural recursion cannot be used
|
||||
|
||||
Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
x1 x2
|
||||
1) 89:19-32 ? ?
|
||||
2) 89:19-32 _ _
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
guessLexFailures.lean:100:0-103:31: error: Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
n m
|
||||
1) 101:83-105 ? ?
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
guessLexFailures.lean:113:14-113:31: error: failed to prove termination, possible solutions:
|
||||
- Use `have`-expressions to prove the remaining goals
|
||||
- Use `termination_by` to specify a different well-founded relation
|
||||
- Use `decreasing_by` to specify your own tactic for discharging this kind of goal
|
||||
n✝ m n : Nat
|
||||
⊢ n < n✝
|
||||
guessLexFailures.lean:119:0-123:31: error: Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
n m
|
||||
1) 121:31-54 ? ?
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
guessLexFailures.lean:131:14-131:31: error: failed to prove termination, possible solutions:
|
||||
- Use `have`-expressions to prove the remaining goals
|
||||
- Use `termination_by` to specify a different well-founded relation
|
||||
- Use `decreasing_by` to specify your own tactic for discharging this kind of goal
|
||||
m n✝ n : Nat
|
||||
⊢ n < Nat.succ n✝
|
||||
|
|
|
|||
|
|
@ -4,7 +4,17 @@ terminationFailure.lean:7:2-7:3: error: fail to show termination for
|
|||
with errors
|
||||
structural recursion does not handle mutually recursive functions
|
||||
|
||||
failed to prove termination, use `termination_by` to specify a well-founded relation
|
||||
Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
Call from f.g to f at 9:9-12:
|
||||
x1
|
||||
x =
|
||||
Call from f to f.g at 3:4-7:
|
||||
x
|
||||
x1 =
|
||||
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
f (x : Nat) : Nat
|
||||
f.g (a✝ : Nat) : Nat
|
||||
1
|
||||
|
|
|
|||
|
|
@ -11,4 +11,9 @@ argument #2 was not used for structural recursion
|
|||
|
||||
structural recursion cannot be used
|
||||
|
||||
failed to prove termination, use `termination_by` to specify a well-founded relation
|
||||
Could not find a decreasing measure.
|
||||
The arguments relate at each recursive call as follows:
|
||||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||||
x y
|
||||
1) 3:12-19 ? ?
|
||||
Please use `termination_by` to specify a decreasing measure.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue