-
Notifications
You must be signed in to change notification settings - Fork 632
feat: generate (co)induction proof principles for mutually (co)inductive predicates #9358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Mathlib CI status (docs):
|
Reference manual CI status:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
I’d expect that in many application, one does want the conclusions for all involved functions. If you only provide the projections, then the user has to do the proof multiple times.
I see that for partial_fixpoint
, I’m only generating the conjunction variant so far:
mutual
def a (n : Nat) : Nat := b (n + 1)
partial_fixpoint
def b (n : Nat) : Nat := a (n + 2)
partial_fixpoint
end
/--
info: a.fixpoint_induct (motive_1 motive_2 : (Nat → Nat) → Prop) (adm_1 : Lean.Order.admissible motive_1)
(adm_2 : Lean.Order.admissible motive_2) (h_1 : ∀ (b : Nat → Nat), motive_2 b → motive_1 fun n => b (n + 1))
(h_2 : ∀ (a : Nat → Nat), motive_1 a → motive_2 fun n => a (n + 2)) : motive_1 a ∧ motive_2 b
-/
#guard_msgs in
#check a.fixpoint_induct
For functional induction, I generate both:
mutual
def a (n : Nat) : Nat := b (n + 1)
decreasing_by sorry
def b (n : Nat) : Nat := a (n + 2)
decreasing_by sorry
end
/--
info: a.mutual_induct (motive1 motive2 : Nat → Prop) (case1 : ∀ (n : Nat), motive2 (n + 1) → motive1 n)
(case2 : ∀ (n : Nat), motive1 (n + 2) → motive2 n) : (∀ (n : Nat), motive1 n) ∧ ∀ (n : Nat), motive2 n
-/
#guard_msgs in
#check a.mutual_induct
/--
info: a.induct (motive1 motive2 : Nat → Prop) (case1 : ∀ (n : Nat), motive2 (n + 1) → motive1 n)
(case2 : ∀ (n : Nat), motive1 (n + 2) → motive2 n) (n : Nat) : motive1 n
-/
#guard_msgs in
#check a.induct
I wonder if we should do the latter in all cases. But it’s hard to decide without a real sizeable use-case yet.
In any case, adding the .mutual_induct
variant for (co)inductive predicates can be done later; no need to do it here.i
/-- Given a packed expression `t₁ ×' t₂ ×' t₃`, returns `#[t₁, t₂, t₃]` -/ | ||
def unpack (e : Expr) : MetaM (Array Expr) := do | ||
match e with | ||
| .const ``True _ => return #[] | ||
| .const ``PUnit _ => return #[] | ||
| _ => go e #[] | ||
where | ||
go (e : Expr) (acc : Array Expr) : MetaM (Array Expr) := do | ||
let .app (.app (.const ``PProd _) a) b := e | return acc.push e | ||
go b (acc.push a) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it’s possible, i.e. known at the call site, I’d prefer to pass in the expected number of components, so that the function doesn't run over if the last type itself happens to be a PProd
.
-- A joint approximation to the fixpoint | ||
let predVar ← PProdN.mk 0 predVars | ||
-- All motives get instantiated with the newly created variables | ||
let newMotives ← motives.mapM ( instantiateForall · #[predVar]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let newMotives ← motives.mapM ( instantiateForall · #[predVar]) | |
let newMotives ← motives.mapM (instantiateForall · #[predVar]) |
This PR adds support for generating lattice-theoretic (co)induction proof principles for predicates defined via
mutual
blocks usinginductive_fixpoint
/coinductive_fixpoint
constructs.Key Changes
mutual
block.Example
Given:
The system now generates these coinduction principles:
and