/-! Johannes Hölzl pointed out that the `partial_fixpoint` machinery can be applied to `Prop` to define inductive or (when using the dual order) coinductive predicates. Without an induction principle this isn't so useful, though. -/ open Lean.Order instance : PartialOrder Prop where rel x y := y → x -- NB: Dual rel_refl := fun x => x rel_trans h₁ h₂ := fun x => h₁ (h₂ x) rel_antisymm h₁ h₂ := propext ⟨h₂, h₁⟩ instance : CCPO Prop where csup c := ∀ p, c p → p csup_spec := fun _ => ⟨fun h y hcy hx => h hx y hcy, fun h hx y hcy => h y hcy hx ⟩ @[partial_fixpoint_monotone] theorem monotone_exists {α} [PartialOrder α] {β} (f : α → β → Prop) (h : monotone f) : monotone (fun x => Exists (f x)) := fun x y hxy ⟨w, hw⟩ => ⟨w, monotone_apply w f h x y hxy hw⟩ @[partial_fixpoint_monotone] theorem monotone_and {α} [PartialOrder α] (f₁ : α → Prop) (f₂ : α → Prop) (h₁ : monotone f₁) (h₂ : monotone f₂) : monotone (fun x => f₁ x ∧ f₂ x) := fun x y hxy ⟨hfx₁, hfx₂⟩ => ⟨h₁ x y hxy hfx₁, h₂ x y hxy hfx₂⟩ def univ (n : Nat) : Prop := univ (n + 1) partial_fixpoint /- The following models a coinductive predicate defined as ``` coinductive infinite_chain step : α → Prop where | intro : ∀ y x, step x = some y → infinite_chain step y → infinite_chain step ``` -/ def infinite_chain {α} (step : α → Option α) (x : α) : Prop := ∃ y, step x = some y ∧ infinite_chain step y partial_fixpoint theorem infinite_chain.intro {α} (step : α → Option α) (y x : α) : step x = some y → infinite_chain step y → infinite_chain step x := by intros; unfold infinite_chain; simp [*] theorem infinite_chain.coinduct {α} (P : α → Prop) (step : α → Option α) (h : ∀ (x : α), P x → ∃ y, step x = some y ∧ P y) : ∀ x, P x → infinite_chain step x := by apply infinite_chain.fixpoint_induct step (motive := fun i => ∀ (x : α), P x → i x) case adm => clear h step apply admissible_pi intro a intro c hchain h hPa Q ⟨f, hcf, hfaQ⟩ subst Q apply h f hcf hPa case h => intro ic hPic x hPx obtain ⟨y, hstepx, h⟩ := h x hPx exact ⟨y, hstepx, hPic y h⟩ /-- Isabelle generates a stronger coinduction theorem from ``` coinductive infinite_chain :: "('a ⇒ 'a option) ⇒ 'a ⇒ bool" for step :: "'a ⇒ 'a option" where intro: "infinite_chain step x" if "step x = Some y" and "infinite_chain step y" ``` Note the occurrence of `infinite_chain` in the step: ``` Scratch.infinite_chain.coinduct: ?X ?x ⟹ (⋀x. ?X x ⟹ ∃xa y. x = xa ∧ ?step xa = Some y ∧ (?X y ∨ infinite_chain ?step y)) ⟹ infinite_chain ?step ?x ``` We can prove that from the one above. -/ theorem infinite_chain.coinduct_strong {α} (P : α → Prop) (step : α → Option α) (h : ∀ (x : α), P x → ∃ y, step x = some y ∧ (P y ∨ infinite_chain step y)) : ∀ x, P x → infinite_chain step x := by suffices ∀ x, (P x ∨ infinite_chain step x) → infinite_chain step x by intro x hPx exact this x (.inl hPx) apply infinite_chain.coinduct intro x hor cases hor next hPx => exact h _ hPx next hicx => unfold infinite_chain at hicx obtain ⟨y, hstepx, h⟩ := hicx exact ⟨y, hstepx, .inr h⟩