-- import Mathlib.Algebra.Ring.Defs import BoundedArithmetic.DisplayedVariables import BoundedArithmetic.Complexity import BoundedArithmetic.IsEnum import BoundedArithmetic.IOPEN open FirstOrder Language BoundedFormula class IDelta0Model (num : Type*) extends IOPENModel num where delta0_induction {n1} {a} [IsEnum a] (phi : peano.BoundedFormula ((Vars1 n1) ⊕ a) 0) : phi.IsDelta0 -> (mkInductionSentence phi).Realize num namespace IDelta0Model universe u variable {M : Type*} [idelta0 : IDelta0Model M] -- Example 3.9 Theorems of IΔ0 open Formula BoundedFormula open BASICModel IOPENModel -- D1. x ≠ 0 → ∃ y ≤ x, x = y + 1 (Predecessor) -- proof: induction on x theorem pred_exists : ∀ {x : M}, x ≠ 0 → ∃ y ≤ x, x = y + 1 := by let ind1 : peano.Formula (Vars2 .y .x) := x =' (y + 1) let ind2 : peano.Formula (Vars1 .x) := (Formula.iBdEx' x (display2 .y ind1).flip) let ind := idelta0.delta0_induction $ display1 $ (x ≠' 0) ⟹ ind2 unfold ind2 ind1 at ind specialize ind (by rw [IsDelta0.display1] -- TODO: this lemma can't be in @[delta0_simps], -- as it creates a goal 'φ.IsOpen' - which might be not true! rw [IsDelta0.of_open.imp] · constructor · unfold Term.neq rw [IsDelta0.of_open.not] constructor; constructor; constructor constructor; constructor · constructor; rw [IsDelta0.flip]; rw [IsDelta0.display2]; constructor; constructor; constructor · unfold Term.neq rw [IsOpen.not] constructor; constructor ) simp_induction at ind apply ind ?base ?step <;> clear ind ind1 ind2 · simp only [IsEmpty.forall_iff] · intro a hind h exists a constructor · exact B8 · rfl theorem ex_of_bdEx {a} [LE a] {t} {P : a -> Prop} : (∃ x ≤ t, P x) -> ∃ x, P x := by intro h obtain ⟨x, ⟨hx1, hx2⟩⟩ := h exists x lemma zero_add : ∀ x : M, 0 + x = x := by intro x rw [idelta0.add_comm] exact B3 x instance : AddZeroClass M where zero_add := zero_add add_zero := B3 -- #check IOPENModel.zero_add open IOPENModel BASICModel -- D2. ∃ z, (x + z = y ∨ y + z = x) -- original proof: Induction on x. Base case: B2, O2. Induction step: B3, B4, D1 -- our proof is different theorem add_diff_exists : ∀ x y : M, ∃ z, x + z = y ∨ y + z = x := by let ind1 : peano.Formula (Vars3 .z .x .y) := ((x + z) =' y) ⊔ ((y + z) =' x) let ind2 : peano.Formula (Vars2 .x .y) := iBdEx' (x + y) (display3 .z ind1).flip let ind3 : peano.Formula (Vars1 .x ⊕ Vars1 .y) := display2 .x ind2 let ind := idelta0.delta0_induction ind3 unfold ind3 ind2 ind1 at ind specialize ind (by rw [IsDelta0.display2] constructor rw [IsDelta0.flip] rw [IsDelta0.display3] constructor · constructor · constructor; constructor; constructor · constructor; constructor · constructor; constructor; constructor ) simp_induction at ind intro x y apply ex_of_bdEx apply ind ?base ?step <;> clear ind1 ind2 ind3 ind · intro z exists z constructor · rw [zero_add z] exact le_refl z · rw [idelta0.add_comm] left rw [B3] · intro L hind R by_cases h_R_zero : R = 0 · exists (L + 1) constructor · exact B8 · right rw [h_R_zero] rw [idelta0.zero_add] · obtain ⟨pred_R, h_pred_R_le, h_pred_R_eq⟩ := pred_exists h_R_zero specialize hind pred_R obtain ⟨symdiff_pred, h_symdiff_pred_le, h_symdiff_pred_eq⟩ := hind exists symdiff_pred cases h_symdiff_pred_eq with | inl h_LR => constructor · rw [h_pred_R_eq, <- h_LR] conv => rhs; rw [idelta0.add_comm] rw [idelta0.add_assoc] lhs rw [idelta0.add_comm] rw [idelta0.add_assoc] apply B8 · left rw [h_pred_R_eq] rw [idelta0.add_assoc] conv => lhs; rhs; rw [idelta0.add_comm] rw [<- idelta0.add_assoc] congr | inr h_RL => constructor · rw [<- h_RL] conv => rhs; left; left; rw [idelta0.add_comm] conv => rhs; left; rw [idelta0.add_comm]; rw [<- idelta0.add_assoc]; left; rw [idelta0.add_comm] conv => rhs; rw [idelta0.add_assoc]; rw [idelta0.add_assoc] apply B8 · right rw [<- h_RL] rw [h_pred_R_eq] conv => lhs; rw [idelta0.add_assoc]; rhs; rw [idelta0.add_comm] rw [idelta0.add_assoc] -- D3. x ≤ y ↔ ∃ z, x + z = y theorem le_iff_exists_add : ∀ x y : M, x ≤ y ↔ ∃ z, x + z = y := by intro x y constructor · intro h_xy obtain ⟨diff, hdiff⟩ := add_diff_exists x y cases hdiff with | inl heq => exists diff | inr heq => exists 0 rw [B3] apply B7 · exact h_xy · rw [<- heq] apply B8 · intro h obtain ⟨z, hz⟩ := h rw [<- hz] apply B8 -- D4. (x ≤ y ∧ y ≤ z) → x ≤ z (Transitivity) theorem le_trans : ∀ {x y z : M}, x ≤ y -> y ≤ z -> x ≤ z := by intro x y z hxy hyz rw [le_iff_exists_add] at hxy hyz ⊢ obtain ⟨diff_x_y, hdiff_x_y⟩ := hxy obtain ⟨diff_y_z, hdiff_y_z⟩ := hyz exists (diff_x_y + diff_y_z) rw [<- idelta0.add_assoc] rw [hdiff_x_y] rw [hdiff_y_z] instance : Preorder M where le_refl := by apply @BASICModel.le_refl le_trans := by apply le_trans lt_iff_le_not_ge := by intro a b constructor · intro h constructor · exact h.1 · intro contr apply h.2 exact contr · intro h exact h -- D5. x ≤ y ∨ y ≤ x (Total order) theorem le_total : ∀ x y : M, x ≤ y ∨ y ≤ x := by intro x y obtain ⟨diff, hdiff⟩ := add_diff_exists x y cases hdiff with | inl h => left rw [le_iff_exists_add] exists diff | inr h => right rw [le_iff_exists_add] exists diff theorem add_rotate : ∀ {a b c : M}, a + b + c = b + c + a := by intro a b c rw [idelta0.add_assoc] rw [idelta0.add_comm] -- D6. x ≤ y ↔ x + z ≤ y + z theorem add_le_add_right : ∀ {x y z : M}, x ≤ y ↔ x + z ≤ y + z := by intro x y z constructor · intro hxy rw [le_iff_exists_add] at hxy ⊢ obtain ⟨diff, hdiff⟩ := hxy exists diff rw [<- add_rotate] rw [idelta0.add_comm] at ⊢ hdiff rw [hdiff] rw [idelta0.add_comm] · rw [le_iff_exists_add] rw [le_iff_exists_add] intro h obtain ⟨a, ha⟩ := h exists a apply add_cancel_right.mp conv at ha => rw [idelta0.add_assoc]; lhs; rhs; rw [idelta0.add_comm] rw [idelta0.add_assoc] exact ha theorem le_cancel_left : ∀ {x y z : M}, x <= y -> z + x <= z + y := by conv => rhs;rhs;rhs;rhs; rw[idelta0.add_comm]; rhs; rw[idelta0.add_comm] intro x y z h apply add_le_add_right.mp h -- D7. x ≤ y → x * z ≤ y * z theorem le_mul_right : ∀ {x y z : M}, x ≤ y → x * z ≤ y * z := by intro x y z hxy rw [le_iff_exists_add] at hxy ⊢ obtain ⟨diff, hdiff⟩ := hxy rw [<- hdiff] rw [idelta0.add_mul] exists (diff * z) -- D8. x ≤ y + 1 ↔ (x ≤ y ∨ x = y + 1) (Discreteness 1) theorem le_succ_iff : ∀ {x y : M}, x ≤ y + 1 ↔ (x ≤ y ∨ x = y + 1) := by intro x y constructor · intro hxy rw [le_iff_exists_add] at hxy obtain ⟨diff, hdiff⟩ := hxy by_cases h : diff = 0 · rw [h] at hdiff right rw [B3] at hdiff exact hdiff · obtain ⟨pred_diff, hpred_diff_le, hpred_diff_eq⟩ := pred_exists h left rw [hpred_diff_eq] at hdiff rw [<- idelta0.add_assoc] at hdiff rw [le_iff_exists_add] exists pred_diff apply B2 exact hdiff · intro h cases h with | inl h => rw [le_iff_exists_add] at h ⊢ rcases h with ⟨diff, hdiff⟩ refine ⟨diff + 1, ?_⟩ rw [<- idelta0.add_assoc] rw [hdiff] | inr h => rw [h] -- D4 used instance : PartialOrder M where le_refl := idelta0.le_refl le_trans := @idelta0.le_trans le_antisymm := by apply B7 instance : CanonicallyOrderedAdd M where exists_add_of_le := by intro a b hab have diff := idelta0.add_diff_exists a b obtain ⟨diff, hdiff⟩ := diff cases hdiff with | inl h => rw [<- h]; exists diff | inr h => exists 0 rw [B3] apply B7 · rw [<- h] apply B8 · exact hab le_self_add := by apply B8 noncomputable instance : LinearOrder M where le_refl := idelta0.le_refl le_trans := by apply le_trans le_antisymm := by apply B7 le_total := idelta0.le_total min_def := by simp only [implies_true] max_def := by exact fun a b ↦ rfl compare_eq_compareOfLessAndEq := by simp only [implies_true] toDecidableLE := by unfold DecidableLE DecidableRel intro a b if ha : a = 0 then apply Decidable.isTrue rw [ha] apply IOPENModel.zero_le b else if hb : b = 0 then apply Decidable.isFalse rw [hb] intro ha' apply ha exact (@nonpos_iff_eq_zero M).mp ha' else -- HERE, WE SHOULD TAKE PREDECESSOR OF -- BOTH AND RECURSE! exact Classical.propDecidable (a ≤ b) theorem le_of_eq : ∀ {x y : M}, x = y -> x ≤ y := by intro x y hxy rw [hxy] -- theorem lt_of_not_ge : -- ∀ {x y : M}, ¬ x <= y -> y < x := -- by -- intro x y h -- constructor -- · cases le_total x y with -- | inl x_le => -- contradiction -- | inr y_le => -- exact y_le -- · intro h_eq -- apply h -- apply le_of_eq -- apply Eq.symm -- exact h_eq theorem zero_if_sum_zero : ∀ {x y : M}, x + y = 0 -> x = 0 ∧ y = 0 := by intro x y h constructor · apply le_zero_eq have t := @B8 _ _ x y rw [h] at t exact t · apply le_zero_eq have t := @B8 _ _ y x rw [idelta0.add_comm] at t rw [h] at t exact t theorem lt_one_eq_zero : ∀ {x : M}, x < 1 -> x = 0 := by intro x hx rcases hx with ⟨h_x_le, h_x_neq⟩ rw [le_iff_exists_add] at h_x_le rcases h_x_le with ⟨diff, hdiff⟩ by_cases h : x = 0 · trivial · obtain ⟨pred, hp1, hp2⟩ := pred_exists h rw [hp2] at hdiff rw [idelta0.add_assoc] at hdiff conv at hdiff => lhs; rhs; rw [idelta0.add_comm] rw [<- idelta0.add_assoc] at hdiff conv at hdiff => rhs; rw [<- idelta0.zero_add 1] have hdiff := B2 _ _ hdiff have pred_zero := (zero_if_sum_zero hdiff).left rw [pred_zero, idelta0.zero_add] at hp2 exfalso apply h_x_neq rw [hp2] -- D9. x < y ↔ x + 1 ≤ y (Discreteness 2) -- recall: x < y means x ≤ y ∧ x ≠ y theorem lt_iff_succ_le : ∀ {x y : M}, (x < y) ↔ x + 1 ≤ y := by intro x y constructor · intro h rcases h with ⟨h1, h2⟩ rw [le_iff_exists_add] at h1 obtain ⟨diff, hdiff⟩ := h1 rw [<- hdiff] apply le_cancel_left by_contra not_one_le_diff apply h2 rw [<- hdiff] conv => lhs; rw [<- B3 x] have diff_lt_one := lt_of_not_ge not_one_le_diff rw [lt_one_eq_zero diff_lt_one] rw [@B3] rw [@B3] · rw [le_iff_exists_add] simp only [peano.instLTOfStructure, not_le] rw [le_iff_exists_add] intro h rcases h with ⟨diff, hdiff⟩ constructor · exists (1 + diff) rw [<- idelta0.add_assoc] exact hdiff · rw [<- hdiff] simp only [LT.lt] constructor · apply le_add_right apply le_add_right exact le_of_eq rfl · intro absurd have aux : x + 1 + diff = x := by have aux : x + 1 + diff >= x := by refine le_add_of_le_left ?_ exact le_self_add apply le_antisymm <;> assumption conv at aux => lhs; rw [idelta0.add_assoc] conv at aux => rhs; rw [<- B3 x] rw [add_cancel_left] at aux rw [idelta0.add_comm] at aux apply @B1 M exact aux theorem mul_eq_zero_iff_left : ∀ {x y : M}, x ≠ 0 -> (x * y = 0 ↔ y = 0) := by intro x y hx constructor · intro hxy rcases pred_exists hx with ⟨xp, _, hxp_eq⟩ rw [hxp_eq] at hxy rw [idelta0.add_mul] at hxy by_contra hy rcases pred_exists hy with ⟨yp, _, hyp_eq⟩ rw [hyp_eq] at hxy conv at hxy => lhs; rhs; rw [idelta0.mul_add] rw [idelta0.mul_one] at hxy rw [<- idelta0.add_assoc] at hxy apply B1 (num := M) exact hxy · intro hy rw [hy] apply B5 -- D10. x * z = y * z ∧ z ≠ 0 → x = y (Cancellation law for ·) theorem mul_cancel_right : ∀ x y z : M, (x * z = y * z ∧ z ≠ 0) → x = y := by let ind1 : peano.Formula (Vars3 .x .y .z) := ((x * z) =' (y * z) ⊓ (z ≠' 0)) ⟹ (x =' y) let ind := idelta0.delta0_induction $ display3 .x ind1 specialize ind (by rw [IsDelta0.display3] unfold ind1 constructor · apply IsDelta0.of_isQF apply IsQF.inf · constructor; constructor · apply IsQF.not; constructor; constructor · constructor; constructor; constructor ) unfold ind1 at ind simp_induction at ind apply ind ?base ?step <;> clear ind ind1 · intro y z hyz_z obtain ⟨hyz, hz⟩ := hyz_z by_cases hy : y = 0 · exact hy.symm · rcases pred_exists hy with ⟨yp, _, hyp_eq⟩ rcases pred_exists hz with ⟨zp, _, hzp_eq⟩ rw [hyp_eq, hzp_eq] at hyz rw [idelta0.mul_add] at hyz rw [idelta0.mul_one] at hyz rw [idelta0.zero_mul] at hyz rw [idelta0.zero_add] at hyz rw [idelta0.mul_add] at hyz rw [idelta0.mul_one] at hyz rw [<- idelta0.add_assoc] at hyz symm at hyz exfalso apply @B1 M exact hyz · intro y hind x z hass_hz obtain ⟨hass, hz⟩ := hass_hz -- hind tells us that we can right-cancel -- multiplication by `a_1` if the other factor at RHS is `a` -- right-cancel multiplication by `z` in `hass` have hx : x ≠ 0 := by by_contra hx rw [hx] at hass rw [idelta0.zero_mul] at hass rw [mul_eq_zero_iff_left] at hass apply hz exact hass apply @B1 M rcases pred_exists hx with ⟨xp, _, hxp_eq⟩ rw [hxp_eq] at hass rw [idelta0.add_mul] at hass rw [idelta0.add_mul] at hass rw [idelta0.one_mul] at hass rw [add_cancel_right] at hass specialize hind xp z rw [hxp_eq] rw [hind] constructor · exact hass · exact hz end IDelta0Model