lean4-htt/tests/lean/run/mutual_coinduction.lean
Wojciech Rozowski 7f17970551
feat: generate (co)induction proof principles for mutually (co)inductive predicates (#9358)
This PR adds support for generating lattice-theoretic (co)induction
proof principles for predicates defined via `mutual` blocks using
`inductive_fixpoint`/`coinductive_fixpoint` constructs.

### Key Changes
- The order on product lattices (used to define fixpoints of mutual
blocks) is unfolded.
- Hypotheses in generated principles are curried.
- Conclusions are projected to focus only on the predicate of interest
(rather than being a conjunction of conclusions for all functions
defined in the `mutual` block.

### Example
Given:
```lean4
mutual
    def f : Prop :=
      g
    coinductive_fixpoint

    def g : Prop :=
      f
    coinductive_fixpoint
  end
```
The system now generates these coinduction principles:
```lean4
f.coinduct (pred_1 pred_2 : Prop) (hyp_1 : pred_1 → pred_2) (hyp_2 : pred_2 → pred_1) : pred_1 → f
```
and 
```lean4
g.coinduct (pred_1 pred_2 : Prop) (hyp_1 : pred_1 → pred_2) (hyp_2 : pred_2 → pred_1) : pred_2 → g
```

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2025-07-30 11:18:41 +00:00

103 lines
2.6 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

namespace MutualCoinduction
mutual
def f : Prop :=
g
coinductive_fixpoint
def g : Prop :=
f
coinductive_fixpoint
end
/--
info: MutualCoinduction.f.coinduct (pred_1 pred_2 : Prop) (hyp_1 : pred_1 → pred_2) (hyp_2 : pred_2 → pred_1) : pred_1 → f
-/
#guard_msgs in
#check MutualCoinduction.f.coinduct
/--
info: MutualCoinduction.g.coinduct (pred_1 pred_2 : Prop) (hyp_1 : pred_1 → pred_2) (hyp_2 : pred_2 → pred_1) : pred_2 → g
-/
#guard_msgs in
#check MutualCoinduction.g.coinduct
end MutualCoinduction
namespace MutualInduction
mutual
def f : Prop :=
g
inductive_fixpoint
def g : Prop :=
f
inductive_fixpoint
end
/--
info: MutualInduction.f.induct (pred_1 pred_2 : Prop) (hyp_1 : pred_2 → pred_1) (hyp_2 : pred_1 → pred_2) : f → pred_1
-/
#guard_msgs in
#check MutualInduction.f.induct
/--
info: MutualInduction.g.induct (pred_1 pred_2 : Prop) (hyp_1 : pred_2 → pred_1) (hyp_2 : pred_1 → pred_2) : g → pred_2
-/
#guard_msgs in
#check MutualInduction.g.induct
end MutualInduction
namespace MixedInductionCoinduction
mutual
def f : Prop :=
g → f
inductive_fixpoint
def g : Prop :=
f → g
coinductive_fixpoint
end
/--
info: MixedInductionCoinduction.f.induct (pred_1 pred_2 : Prop) (hyp_1 : (pred_2 → pred_1) → pred_1)
(hyp_2 : pred_2 → pred_1 → pred_2) : f → pred_1
-/
#guard_msgs in
#check f.induct
/--
info: MixedInductionCoinduction.g.coinduct (pred_1 pred_2 : Prop) (hyp_1 : (pred_2 → pred_1) → pred_1)
(hyp_2 : pred_2 → pred_1 → pred_2) : pred_2 → g
-/
#guard_msgs in
#check g.coinduct
end MixedInductionCoinduction
namespace DifferentPredicateTypes
mutual
def f (n : Nat) : Prop :=
g (n+1) (n+2)
coinductive_fixpoint
def g (n m : Nat): Prop :=
f (n + 2) g (m + 1) m
coinductive_fixpoint
end
/--
info: DifferentPredicateTypes.f.coinduct (pred_1 : Nat → Prop) (pred_2 : Nat → Nat → Prop)
(hyp_1 : ∀ (x : Nat), pred_1 x → pred_2 (x + 1) (x + 2))
(hyp_2 : ∀ (x x_1 : Nat), pred_2 x x_1 → pred_1 (x + 2) pred_2 (x_1 + 1) x_1) (x✝ : Nat) : pred_1 x✝ → f x✝
-/
#guard_msgs in
#check f.coinduct
/--
info: DifferentPredicateTypes.g.coinduct (pred_1 : Nat → Prop) (pred_2 : Nat → Nat → Prop)
(hyp_1 : ∀ (x : Nat), pred_1 x → pred_2 (x + 1) (x + 2))
(hyp_2 : ∀ (x x_1 : Nat), pred_2 x x_1 → pred_1 (x + 2) pred_2 (x_1 + 1) x_1) (x✝ x✝¹ : Nat) :
pred_2 x✝ x✝¹ → g x✝ x✝¹
-/
#guard_msgs in
#check g.coinduct
end DifferentPredicateTypes