chore: rename keywords for (co)inductive predicates and the names of their associated (co)induction principles

chore: rename `fixpoint_induct` to `induct` and `coinduct` for (co)inductive predicates
This commit is contained in:
Wojciech Rozowski 2025-06-23 16:02:11 +02:00 committed by Joachim Breitner
parent dd64678f07
commit 07c398e441
10 changed files with 124 additions and 107 deletions

View file

@ -184,25 +184,25 @@ def checkTerminationByHints (preDefs : Array PreDefinition) : CoreM Unit := do
let preDefsWithout := preDefs.filter (·.termination.terminationBy?.isNone)
let structural :=
preDefWith.termination.terminationBy? matches some {structural := true, ..}
-- Information whether the current one is partial, least or greatest
let partialFixpoint := preDefWith.termination.partialFixpoint?.any fun x => isPartial x.fixpointType
let leastFixpoint := preDefWith.termination.partialFixpoint?.any fun x => isLeast x.fixpointType
let greatestFixpoint := preDefWith.termination.partialFixpoint?.any fun x => isGreatest x.fixpointType
-- Information whether the current one is partial, inductive or coinductive
let partialFixpoint := preDefWith.termination.partialFixpoint?.any fun x => isPartialFixpoint x.fixpointType
let inductiveFixpoint := preDefWith.termination.partialFixpoint?.any fun x => isInductiveFixpoint x.fixpointType
let coinductiveFixpoint := preDefWith.termination.partialFixpoint?.any fun x => isCoinductiveFixpoint x.fixpointType
for preDef in preDefs do
-- if some has at termination by clause
if let .some termBy := preDef.termination.terminationBy? then
-- but something in the clique is partial/least/greatest, then we report error
-- but something in the clique is partial/inductive/coinductive, then we report error
if let .some partialFixpointStx := preDef.termination.partialFixpoint? then
match partialFixpointStx.fixpointType with
| .partialFixpoint => throwErrorAt partialFixpointStx.ref m!"conflicting annotations: this function cannot \
be both terminating and a partial fixpoint"
| .leastFixpoint => throwErrorAt partialFixpointStx.ref m!"conflicting annotations: this function cannot \
be both terminating and a least fixpoint"
| .greatestFixpoint => throwErrorAt partialFixpointStx.ref m!"conflicting annotations: this function cannot \
be both terminating and a greatest fixpoint"
| .inductiveFixpoint => throwErrorAt partialFixpointStx.ref m!"conflicting annotations: this function cannot \
be both terminating and an inductive fixpoint"
| .coinductiveFixpoint => throwErrorAt partialFixpointStx.ref m!"conflicting annotations: this function cannot \
be both terminating and a coinductive fixpoint"
-- if has no annotations
if !structural && !partialFixpoint && !leastFixpoint && !greatestFixpoint && !preDefsWithout.isEmpty then
if !structural && !partialFixpoint && !inductiveFixpoint && !coinductiveFixpoint && !preDefsWithout.isEmpty then
let m := MessageData.andList (preDefsWithout.toList.map (m!"{·.declName}"))
let doOrDoes := if preDefsWithout.size = 1 then "does" else "do"
logErrorAt termBy.ref m!"incomplete set of termination hints:\n\
@ -224,57 +224,57 @@ def checkTerminationByHints (preDefs : Array PreDefinition) : CoreM Unit := do
structurally recursive, so no explicit termination proof is needed."
-- If one is partial, but others are not
if partialFixpoint && !preDef.termination.partialFixpoint?.any fun x => isPartial x.fixpointType then
if partialFixpoint && !preDef.termination.partialFixpoint?.any fun x => isPartialFixpoint x.fixpointType then
throwErrorAt preDef.ref m!"Incompatible termination hint; this function is mutually \
recursive with {preDefWith.declName}, which is marked as \
`partial_fixpoint` so this one also needs to be marked \
`partial_fixpoint`."
-- If one is least, but others are not
if leastFixpoint && !preDef.termination.partialFixpoint?.any fun x => isLatticeTheoretic x.fixpointType then
if inductiveFixpoint && !preDef.termination.partialFixpoint?.any fun x => isLatticeTheoretic x.fixpointType then
throwErrorAt preDef.ref m!"Incompatible termination hint; this function is mutually \
recursive with {preDefWith.declName}, which is marked as
`least_fixpoint` so this one also needs to be marked \
`least_fixpoint` or `greatest_fixpoint`."
`inductive_fixpoint` so this one also needs to be marked \
`inductive_fixpoint` or `coinductive_fixpoint`."
-- If one is greatest, but others are not
if greatestFixpoint && !preDef.termination.partialFixpoint?.any fun x => isLatticeTheoretic x.fixpointType then
if coinductiveFixpoint && !preDef.termination.partialFixpoint?.any fun x => isLatticeTheoretic x.fixpointType then
throwErrorAt preDef.ref m!"Incompatible termination hint; this function is mutually \
recursive with {preDefWith.declName}, which is marked as \
`greatest_fixpoint` so this one also needs to be marked \
`least_fixpoint` or `greatest_fixpoint`."
`coinductive_fixpoint` so this one also needs to be marked \
`inductive_fixpoint` or `coinductive_fixpoint`."
-- checking for unnecessary `decreasing_by` clause
if preDef.termination.partialFixpoint?.any fun x => isPartial x.fixpointType then
if preDef.termination.partialFixpoint?.any fun x => isPartialFixpoint x.fixpointType then
if let .some decr := preDef.termination.decreasingBy? then
logErrorAt decr.ref m!"Invalid `decreasing_by`; this function is marked as \
partial_fixpoint, so no explicit termination proof is needed."
if preDef.termination.partialFixpoint?.any fun x => isLeast x.fixpointType then
if preDef.termination.partialFixpoint?.any fun x => isInductiveFixpoint x.fixpointType then
if let .some decr := preDef.termination.decreasingBy? then
logErrorAt decr.ref m!"Invalid `decreasing_by`; this function is marked as \
least_fixpoint, so no explicit termination proof is needed."
inductive_fixpoint, so no explicit termination proof is needed."
if preDef.termination.partialFixpoint?.any fun x => isLeast x.fixpointType then
if preDef.termination.partialFixpoint?.any fun x => isInductiveFixpoint x.fixpointType then
if let .some decr := preDef.termination.decreasingBy? then
logErrorAt decr.ref m!"Invalid `decreasing_by`; this function is marked as \
greatest_fixpoint, so no explicit termination proof is needed."
coinductive_fixpoint, so no explicit termination proof is needed."
-- if the selected one is not marked as partial fixpoint
if !partialFixpoint then
if let some stx := preDef.termination.partialFixpoint? then
if isPartial stx.fixpointType then
if isPartialFixpoint stx.fixpointType then
throwErrorAt stx.ref m!"Incompatible termination hint; this function is mutually \
recursive with {preDefWith.declName}, which is not also marked as \
`partial_fixpoint`, so this one cannot be either."
-- if the selected one is not marked as partial fixpoint
unless leastFixpoint || greatestFixpoint do
unless inductiveFixpoint || coinductiveFixpoint do
if let some stx := preDef.termination.partialFixpoint? then
if isLatticeTheoretic stx.fixpointType then
throwErrorAt stx.ref m!"Incompatible termination hint; this function is mutually \
recursive with {preDefWith.declName}, which is not also marked as \
`least_fixpoint` or `greatest_fixpoint`, so this one cannot be either."
`inductive_fixpoint` or `coinductive_fixpoint`, so this one cannot be either."
/--
Elaborates the `TerminationHint` in the clique to `TerminationMeasures`

View file

@ -53,14 +53,13 @@ def CCPOProdProjs (n : Nat) (inst : Expr) : Array Expr := Id.run do
Unfolds an appropriate `PartialOrder` instance on predicates to quantifications and implications.
I.e. `ImplicationOrder.instPartialOrder.rel P Q` becomes
`∀ x y, P x y → Q x y`.
In the premise of the Park induction principle (`lfp_le_of_le_monotone`) we use a monotone map defining the predicate in the eta expanded form. In such a case, besides desugaring the predicate, we need to perform a weak head reduction.
The optional parameter `reduceConclusion` (false by default) indicates whether we need to perform this reduction.
-/
def unfoldPredRel (predType : Expr) (body : Expr) (fixpointType : PartialFixpointType) (reduceConclusion : Bool := false) : MetaM Expr := do
match fixpointType with
| .partialFixpoint => throwError "Trying to apply lattice induction to a non-lattice fixpoint. Please report this issue."
| .leastFixpoint | .greatestFixpoint =>
| .inductiveFixpoint | .coinductiveFixpoint =>
unless body.isAppOfArity ``PartialOrder.rel 4 do
throwError "{body} is not an application of partial order"
let lhsTypes ← forallTelescope predType fun ts _ => ts.mapM inferType
@ -68,15 +67,15 @@ def unfoldPredRel (predType : Expr) (body : Expr) (fixpointType : PartialFixpoin
let bodyArgs := body.getAppArgs
withLocalDeclsDND (names.zip lhsTypes) fun exprs => do
let mut applied := match fixpointType with
| .leastFixpoint => (bodyArgs[2]!, bodyArgs[3]!)
| .greatestFixpoint => (bodyArgs[3]!, bodyArgs[2]!)
| .inductiveFixpoint => (bodyArgs[2]!, bodyArgs[3]!)
| .coinductiveFixpoint => (bodyArgs[3]!, bodyArgs[2]!)
| .partialFixpoint => panic! "Cannot apply lattice induction to a non-lattice fixpoint"
for e in exprs do
applied := (mkApp applied.1 e, mkApp applied.2 e)
if reduceConclusion then
match fixpointType with
| .leastFixpoint => applied := ((←whnf applied.1), applied.2)
| .greatestFixpoint => applied := (applied.1, (←whnf applied.2))
| .inductiveFixpoint => applied := ((←whnf applied.1), applied.2)
| .coinductiveFixpoint => applied := (applied.1, (←whnf applied.2))
| .partialFixpoint => throwError "Cannot apply lattice induction to a non-lattice fixpoint"
mkForallFVars exprs (←mkArrow applied.1 applied.2)
@ -93,8 +92,18 @@ private def numberNames (n : Nat) (base : String) : Array Name :=
.ofFn (n := n) fun ⟨i, _⟩ =>
if n == 1 then .mkSimple base else .mkSimple s!"{base}_{i+1}"
def deriveInduction (name : Name) : MetaM Unit :=
let inductName := name ++ `fixpoint_induct
def getInductionPrinciplePostfix (name : Name) : MetaM Name := do
let some eqnInfo := eqnInfoExt.find? (← getEnv) name | throwError "{name} is not defined by partial_fixpoint, inductive_fixpoint, nor coinductive_fixpoint"
let idx := eqnInfo.declNames.idxOf name
let some res := eqnInfo.fixpointType[idx]? | throwError "Cannot get fixpoint type for {name}"
match res with
| .partialFixpoint => return `fixpoint_induct
| .inductiveFixpoint => return `induct
| .coinductiveFixpoint => return `coinduct
def deriveInduction (name : Name) : MetaM Unit := do
let postFix ← getInductionPrinciplePostfix name
let inductName := name ++ postFix
realizeConst name inductName do
trace[Elab.definition.partialFixpoint] "Called deriveInduction for {inductName}"
prependError m!"Cannot derive fixpoint induction principle (please report this issue)" do
@ -250,7 +259,17 @@ def isInductName (env : Environment) (name : Name) : Bool := Id.run do
match s with
| "fixpoint_induct" =>
if let some eqnInfo := eqnInfoExt.find? env p then
return p == eqnInfo.declNames[0]!
return p == eqnInfo.declNames[0]! && isPartialFixpoint (eqnInfo.fixpointType[0]!)
return false
| "coinduct" =>
if let some eqnInfo := eqnInfoExt.find? env p then
let idx := eqnInfo.declNames.idxOf p
return isCoinductiveFixpoint eqnInfo.fixpointType[idx]!
return false
| "induct" =>
if let some eqnInfo := eqnInfoExt.find? env p then
let idx := eqnInfo.declNames.idxOf p
return isInductiveFixpoint eqnInfo.fixpointType[idx]!
return false
| _ => return false

View file

@ -75,7 +75,7 @@ private def mkMonoPProd : (hmono₁ hmono₂ : Expr × Expr) → MetaM (Expr ×
return (← inferType hmonoProof, hmonoProof)
def partialFixpoint (preDefs : Array PreDefinition) : TermElabM Unit := do
-- We expect all functions in the clique to have `partial_fixpoint` or `greatest_fixpoint` syntax
-- We expect all functions in the clique to have `partial_fixpoint`, `inductive_fixpoint` or `coinductive_fixpoint` syntax
let hints := preDefs.filterMap (·.termination.partialFixpoint?)
assert! preDefs.size = hints.size
-- We check if any fixpoints were defined lattice-theoretically
@ -90,13 +90,13 @@ def partialFixpoint (preDefs : Array PreDefinition) : TermElabM Unit := do
let type ← instantiateForall preDef.type xs
let inst ←
match hints[i]!.fixpointType with
| .greatestFixpoint =>
| .coinductiveFixpoint =>
unless type.isProp do
throwError "`greatest_fixpoint` can be only used to define predicates"
throwError "`coinductive_fixpoint` can be only used to define predicates"
pure (mkConst ``ReverseImplicationOrder.instCompleteLattice)
| .leastFixpoint =>
| .inductiveFixpoint =>
unless type.isProp do
throwError "`least_fixpoint` can be only used to define predicates"
throwError "`inductive_fixpoint` can be only used to define predicates"
pure (mkConst ``ImplicationOrder.instCompleteLattice)
| .partialFixpoint => try
synthInstance (← mkAppM ``CCPO #[type])

View file

@ -35,11 +35,11 @@ structure DecreasingBy where
inductive PartialFixpointType where
| partialFixpoint
| greatestFixpoint
| leastFixpoint
| coinductiveFixpoint
| inductiveFixpoint
deriving Inhabited
/-- A single `partial_fixpoint`, `greatest_fixpoint` or `least_fixpoint` clause -/
/-- A single `partial_fixpoint`, `inductive_fixpoint` or `coinductive_fixpoint` clause -/
structure PartialFixpoint where
ref : Syntax
term? : Option Term
@ -69,20 +69,20 @@ structure TerminationHints where
extraParams : Nat
deriving Inhabited
def isLeast : PartialFixpointType → Bool
| .leastFixpoint => true
def isInductiveFixpoint : PartialFixpointType → Bool
| .inductiveFixpoint => true
| _ => false
def isGreatest : PartialFixpointType → Bool
| .greatestFixpoint => true
def isCoinductiveFixpoint : PartialFixpointType → Bool
| .coinductiveFixpoint => true
| _ => false
def isPartial : PartialFixpointType → Bool
def isPartialFixpoint : PartialFixpointType → Bool
| .partialFixpoint => true
| _ => false
def isLatticeTheoretic (p : PartialFixpointType ) : Bool :=
isLeast p isGreatest p
def isLatticeTheoretic (p : PartialFixpointType) : Bool :=
isInductiveFixpoint p isCoinductiveFixpoint p
def TerminationHints.none : TerminationHints := ⟨.missing, .none, .none, .none, .none, 0⟩
@ -99,8 +99,8 @@ def TerminationHints.ensureNone (hints : TerminationHints) (reason : String) : C
| .none, .none, .none, .some partialFixpoint =>
match partialFixpoint.fixpointType with
| .partialFixpoint => logWarningAt partialFixpoint.ref m!"unused `partial_fixpoint`, function is {reason}"
| .greatestFixpoint => logWarningAt partialFixpoint.ref m!"unused `greatest_fixpoint`, function is {reason}"
| .leastFixpoint => logWarningAt partialFixpoint.ref m!"unused `least_fixpoint`, function is {reason}"
| .coinductiveFixpoint => logWarningAt partialFixpoint.ref m!"unused `coinductive_fixpoint`, function is {reason}"
| .inductiveFixpoint => logWarningAt partialFixpoint.ref m!"unused `inductive_fixpoint`, function is {reason}"
| _, _, _, _=>
logWarningAt hints.ref m!"unused termination hints, function is {reason}"
@ -160,14 +160,14 @@ def elabTerminationHints {m} [Monad m] [MonadError m] (stx : TSyntax ``suffix) :
pure (some {ref := t, structural := s.isSome, vars := #[], body})
| `(terminationBy?|termination_by?) => pure none
| `(partialFixpoint|partial_fixpoint $[monotonicity $_]?) => pure none
| `(greatestFixpoint|greatest_fixpoint $[monotonicity $_]?) => pure none
| `(leastFixpoint|least_fixpoint $[monotonicity $_]?) => pure none
| `(coinductiveFixpoint|coinductive_fixpoint $[monotonicity $_]?) => pure none
| `(inductiveFixpoint|inductive_fixpoint $[monotonicity $_]?) => pure none
| _ => throwErrorAt t "unexpected `termination_by` syntax"
else pure none
let partialFixpoint? : Option PartialFixpoint ← if let some t := t? then match t with
| `(partialFixpoint|partial_fixpoint $[monotonicity $term?]?) => pure (some {ref := t, term?, fixpointType := .partialFixpoint})
| `(greatestFixpoint|greatest_fixpoint $[monotonicity $term?]?) => pure (some {ref := t, term?, fixpointType := .greatestFixpoint})
| `(leastFixpoint|least_fixpoint $[monotonicity $term?]?) => pure (some {ref := t, term?, fixpointType := .leastFixpoint})
| `(coinductiveFixpoint|coinductive_fixpoint $[monotonicity $term?]?) => pure (some {ref := t, term?, fixpointType := .coinductiveFixpoint})
| `(inductiveFixpoint|inductive_fixpoint $[monotonicity $term?]?) => pure (some {ref := t, term?, fixpointType := .inductiveFixpoint})
| _ => pure none
else pure none
let decreasingBy? ← d?.mapM fun d => match d with

View file

@ -802,9 +802,9 @@ The coinductive predicate is defined as the greatest fixed point of a monotone f
By default, monotonicity is verified automatically. However, users can provide custom proofs
of monotonicity if needed.
-/
def greatestFixpoint := leading_parser
def coinductiveFixpoint := leading_parser
withPosition (
"greatest_fixpoint" >>
"coinductive_fixpoint" >>
optional (checkColGt "indentation" >> nonReservedSymbol "monotonicity " >>
checkColGt "indented monotonicity proof" >> termParser))
@ -819,9 +819,9 @@ The inductive predicate is defined as the least fixed point of a monotone functi
By default, monotonicity is verified automatically. However, users can provide custom proofs
of monotonicity if needed.
-/
def leastFixpoint := leading_parser
def inductiveFixpoint := leading_parser
withPosition (
"least_fixpoint" >>
"inductive_fixpoint" >>
optional (checkColGt "indentation" >> nonReservedSymbol "monotonicity " >>
checkColGt "indented monotonicity proof" >> termParser))
@ -841,7 +841,7 @@ Forces the use of well-founded recursion and is hence incompatible with
Termination hints are `termination_by` and `decreasing_by`, in that order.
-/
@[builtin_doc] def suffix := leading_parser
optional (ppDedent ppLine >> (terminationBy? <|> terminationBy <|> partialFixpoint <|> greatestFixpoint <|> leastFixpoint)) >> optional decreasingBy
optional (ppDedent ppLine >> (terminationBy? <|> terminationBy <|> partialFixpoint <|> coinductiveFixpoint <|> inductiveFixpoint)) >> optional decreasingBy
end Termination
namespace Term

View file

@ -1,27 +1,25 @@
-- Coinductive predicate definition
def infseq {α} (R : αα → Prop) : α → Prop :=
λ x : α => ∃ y, R x y ∧ infseq R y
greatest_fixpoint
coinductive_fixpoint
-- Application of the rewrite rule
def infseq_fixpoint {α} (R : αα → Prop) (x : α) :
infseq R x = ∃ y, R x y ∧ infseq R y := by
rw [infseq]
#check infseq.coinduct
-- The associated coinduction principle
theorem infseq.coind {α} (h : α → Prop) (R : αα → Prop)
(prem : ∀ (x : α), h x → ∃ y, R x y ∧ h y) : ∀ x, h x → infseq R x := by
apply infseq.fixpoint_induct
exact prem
/--
info: infseq.fixpoint_induct.{u_1} {α : Sort u_1} (R : αα → Prop) (x : α → Prop)
(y : ∀ (x_1 : α), x x_1 → ∃ y, R x_1 y ∧ x y) (x✝ : α) : x x✝ → infseq R x✝
info: infseq.coinduct.{u_1} {α : Sort u_1} (R : αα → Prop) (x : α → Prop) (y : ∀ (x_1 : α), x x_1 → ∃ y, R x_1 y ∧ x y)
(x✝ : α) : x x✝ → infseq R x✝
-/
#guard_msgs in #check infseq.fixpoint_induct
#guard_msgs in #check infseq.coinduct
-- Simple proof by coinduction
theorem cycle_infseq {R : αα → Prop} (x : α) : R x x → infseq R x := by
apply @infseq.fixpoint_induct α R (λ m => R m m)
apply @infseq.coinduct α R (λ m => R m m)
intro x _
apply Exists.intro x
trivial
@ -34,13 +32,13 @@ inductive star (R : αα → Prop) : αα → Prop where
-- Inductive predicate, as a least fixpoint
def star_ind (tr : αα → Prop) (q₁ q₂ : α) : Prop :=
∃ (z : α), q₁ = q₂ (tr q₁ z ∧ star_ind tr z q₂)
least_fixpoint
inductive_fixpoint
/--
info: star_ind.fixpoint_induct.{u_1} {α : Sort u_1} (tr : αα → Prop) (q₂ : α) (x : α → Prop)
info: star_ind.induct.{u_1} {α : Sort u_1} (tr : αα → Prop) (q₂ : α) (x : α → Prop)
(y : ∀ (x_1 : α), (∃ z, x_1 = q₂ tr x_1 z ∧ x z) → x x_1) (x✝ : α) : (fun q₁ => star_ind tr q₁ q₂) x✝ → x x✝
-/
#guard_msgs in #check star_ind.fixpoint_induct
#guard_msgs in #check star_ind.induct
-- From one you can prove the other
theorem star_implies_star' (R : αα → Prop) : ∀ a b : α, star R a b → star_ind R a b := by
@ -109,7 +107,7 @@ def all_seq_inf (R : αα → Prop) (x : α) : Prop :=
∀ y : α, star R x y → ∃ z, R y z
def infseq_if_all_seq_inf (R : αα → Prop) : ∀ x, all_seq_inf R x → infseq R x := by
apply infseq.fixpoint_induct
apply infseq.coinduct
intro x H
unfold all_seq_inf at H
have H' := H x (by simp [star.star_refl])
@ -132,7 +130,7 @@ theorem infseq_coinduction_principle_2:
∀ (a : α), x a → infseq R a := by
intro X
intro h₁ a rel
apply @infseq.fixpoint_induct _ _ (fun a => ∃ b, star R a b ∧ X b)
apply @infseq.coinduct _ _ (fun a => ∃ b, star R a b ∧ X b)
case x =>
apply Exists.elim (h₁ a rel)
intro a' ⟨h₁, h₂⟩
@ -164,10 +162,10 @@ def language_equivalent (automaton : DFA Q A) (q₁ q₂ : Q) : Prop :=
let ⟨o₁, t₁⟩ := automaton q₁
let ⟨o₂, t₂⟩ := automaton q₂
o₁ = o₂ ∧ (∀ a : A, language_equivalent automaton (t₁ a) (t₂ a))
greatest_fixpoint
coinductive_fixpoint
/--
info: language_equivalent.fixpoint_induct {Q A : Type} (automaton : DFA Q A) (x : Q → Q → Prop)
info: language_equivalent.coinduct {Q A : Type} (automaton : DFA Q A) (x : Q → Q → Prop)
(y :
∀ (x_1 x_2 : Q),
x x_1 x_2 →
@ -175,17 +173,17 @@ info: language_equivalent.fixpoint_induct {Q A : Type} (automaton : DFA Q A) (x
(x✝ x✝¹ : Q) : x x✝ x✝¹ → language_equivalent automaton x✝ x✝¹
-/
#guard_msgs in
#check language_equivalent.fixpoint_induct
#check language_equivalent.coinduct
namespace mixed1
mutual
def tick : Prop :=
¬tock
greatest_fixpoint
coinductive_fixpoint
def tock : Prop :=
¬tick
least_fixpoint
inductive_fixpoint
end
end mixed1
@ -193,11 +191,11 @@ namespace mixed2
mutual
def tick : Prop :=
¬tock
greatest_fixpoint
inductive_fixpoint
def tock : Prop :=
¬tick
least_fixpoint
coinductive_fixpoint
end
end mixed2
@ -205,11 +203,11 @@ namespace mixed3
mutual
def tick : Prop :=
tock → tick
greatest_fixpoint
coinductive_fixpoint
def tock : Prop :=
tick → tock
least_fixpoint
inductive_fixpoint
end
end mixed3
@ -217,10 +215,10 @@ namespace mixed4
mutual
def tick : Prop :=
tock → tick
least_fixpoint
inductive_fixpoint
def tock : Prop :=
tick → tock
greatest_fixpoint
coinductive_fixpoint
end
end mixed4

View file

@ -1,36 +1,36 @@
/-!
This file contains tests for typical mistakes one might do when using `least_fixpoint`/`greatest_fixpoint`/`partial_fixpoint` machinery, that is:
- Try to use `greatest_fixpoint`/`least_fixpoint` to define functions instead of predicates
- Apply `greatest_fixpoint`/`least_fixpoint` to non-recursive functions
- Mix `partial_fixpoint` with `greatest_fixpoint`/`least_fixpoint` in the same clique
This file contains tests for typical mistakes one might do when using `inductive_fixpoint`/`coinductive_fixpoint`/`partial_fixpoint` machinery, that is:
- Try to use `coinductive_fixpoint`/`inductive_fixpoint` to define functions instead of predicates
- Apply `coinductive_fixpoint`/`inductive_fixpoint` to non-recursive functions
- Mix `partial_fixpoint` with `coinductive_fixpoint`/`inductive_fixpoint` in the same clique
-/
/--
error: `greatest_fixpoint` can be only used to define predicates
error: `coinductive_fixpoint` can be only used to define predicates
-/
#guard_msgs in
def f (x : Nat) : Nat :=
f (x + 1)
greatest_fixpoint
coinductive_fixpoint
/--
error: `least_fixpoint` can be only used to define predicates
error: `inductive_fixpoint` can be only used to define predicates
-/
#guard_msgs in
def g (x : Nat) : Nat :=
g (x + 1)
least_fixpoint
inductive_fixpoint
/--
warning: unused `greatest_fixpoint`, function is not recursive
warning: unused `coinductive_fixpoint`, function is not recursive
-/
#guard_msgs in
def h (x : Nat) : Prop := x > 42
greatest_fixpoint
coinductive_fixpoint
/--
warning: unused `least_fixpoint`, function is not recursive
warning: unused `inductive_fixpoint`, function is not recursive
-/
#guard_msgs in
def h' (x : Nat) : Prop := x > 42
least_fixpoint
inductive_fixpoint

View file

@ -10,7 +10,7 @@ def asimp_const : Aexp -> Aexp
@[simp]
def optimal' (a : Aexp) : Prop :=
optimal' a ∧ True
least_fixpoint
inductive_fixpoint
/-- info: Try this: simp_all only [asimp_const, reduceCtorEq] -/
#guard_msgs in

View file

@ -131,20 +131,20 @@ mutual
partial_fixpoint
def g (x : Nat) : Prop := f (x + 1)
least_fixpoint
inductive_fixpoint
end
end Test6
namespace Test7
/--
error: Incompatible termination hint; this function is mutually recursive with Test7.f, which is marked as `greatest_fixpoint` so this one also needs to be marked `least_fixpoint` or `greatest_fixpoint`.
error: Incompatible termination hint; this function is mutually recursive with Test7.f, which is marked as `coinductive_fixpoint` so this one also needs to be marked `inductive_fixpoint` or `coinductive_fixpoint`.
-/
#guard_msgs in
mutual
def f (x : Nat) : Prop :=
g (x + 1)
greatest_fixpoint
coinductive_fixpoint
def g (x : Nat) : Prop :=
f (x + 1)
@ -170,7 +170,7 @@ end Test8
namespace Test9
/--
error: Incompatible termination hint; this function is mutually recursive with Test9.f, which is not also marked as `least_fixpoint` or `greatest_fixpoint`, so this one cannot be either.
error: Incompatible termination hint; this function is mutually recursive with Test9.f, which is not also marked as `inductive_fixpoint` or `coinductive_fixpoint`, so this one cannot be either.
-/
#guard_msgs in
mutual
@ -180,19 +180,19 @@ mutual
def g (x : Nat) : Prop :=
f (x + 1)
least_fixpoint
inductive_fixpoint
end
end Test9
namespace Test10
/--
error: Incompatible termination hint; this function is mutually recursive with Test10.f, which is marked as `greatest_fixpoint` so this one also needs to be marked `least_fixpoint` or `greatest_fixpoint`.
error: Incompatible termination hint; this function is mutually recursive with Test10.f, which is marked as `coinductive_fixpoint` so this one also needs to be marked `inductive_fixpoint` or `coinductive_fixpoint`.
-/
#guard_msgs in
mutual
def f (x : Nat) : Prop :=
g (x + 1)
greatest_fixpoint
coinductive_fixpoint
def g (x : Nat) : Prop :=
f (x + 1)

View file

@ -5,11 +5,11 @@ Tests that `partial_fixpoint` is not picking up the partial order structure on P
-- This works as `` is monotone in its arguments with respect to the (`ImplicationOrder`/`ReverseImplicationOrder` on `Prop`.
def f (x : Nat) : Prop :=
f (x + 1) f ( x + 2)
greatest_fixpoint
coinductive_fixpoint
def f' (x : Nat) : Prop :=
f' (x + 1) f' ( x + 2)
least_fixpoint
inductive_fixpoint
/--
error: Could not prove 'f''' to be monotone in its recursive calls: