Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
Try doing some basic maths questions in the Lean Theorem Prover. Functions, real numbers, equivalence relations and groups. Click on README.md and then on "Open in CoCalc with one click".
Project: Xena
Views: 18536License: APACHE
/- Copyright (c) 2018 Simon Hudon. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Simon Hudon, Scott Morrison -/ import tactic.interactive tactic.finish tactic.ext tactic.lift tactic.apply tactic.reassoc_axiom tactic.tfae tactic.elide tactic.ring_exp tactic.clear tactic.simp_rw example (m n p q : nat) (h : m + n = p) : true := begin have : m + n = q, { generalize_hyp h' : m + n = x at h, guard_hyp h' := m + n = x, guard_hyp h := x = p, guard_target m + n = q, admit }, have : m + n = q, { generalize_hyp h' : m + n = x at h ⊢, guard_hyp h' := m + n = x, guard_hyp h := x = p, guard_target x = q, admit }, trivial end example (α : Sort*) (L₁ L₂ L₃ : list α) (H : L₁ ++ L₂ = L₃) : true := begin have : L₁ ++ L₂ = L₂, { generalize_hyp h : L₁ ++ L₂ = L at H, induction L with hd tl ih, case list.nil { tactic.cleanup, change list.nil = L₃ at H, admit }, case list.cons { change list.cons hd tl = L₃ at H, admit } }, trivial end example (x y : ℕ) (p q : Prop) (h : x = y) (h' : p ↔ q) : true := begin symmetry' at h, guard_hyp' h := y = x, guard_hyp' h' := p ↔ q, symmetry' at *, guard_hyp' h := x = y, guard_hyp' h' := q ↔ p, trivial end section apply_rules example {a b c d e : nat} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 0 ≤ e) : a + c * e + a + c + 0 ≤ b + d * e + b + d + e := add_le_add (add_le_add (add_le_add (add_le_add h1 (mul_le_mul_of_nonneg_right h2 h3)) h1 ) h2) h3 example {a b c d e : nat} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 0 ≤ e) : a + c * e + a + c + 0 ≤ b + d * e + b + d + e := by apply_rules [add_le_add, mul_le_mul_of_nonneg_right] @[user_attribute] meta def mono_rules : user_attribute := { name := `mono_rules, descr := "lemmas usable to prove monotonicity" } attribute [mono_rules] add_le_add mul_le_mul_of_nonneg_right example {a b c d e : nat} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 0 ≤ e) : a + c * e + a + c + 0 ≤ b + d * e + b + d + e := by apply_rules [mono_rules] example {a b c d e : nat} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 0 ≤ e) : a + c * e + a + c + 0 ≤ b + d * e + b + d + e := by apply_rules mono_rules end apply_rules section h_generalize variables {α β γ φ ψ : Type} (f : α → α → α → φ → γ) (x y : α) (a b : β) (z : φ) (h₀ : β = α) (h₁ : β = α) (h₂ : φ = β) (hx : x == a) (hy : y == b) (hz : z == a) include f x y z a b hx hy hz example : f x y x z = f (eq.rec_on h₀ a) (cast h₀ b) (eq.mpr h₁.symm a) (eq.mpr h₂ a) := begin guard_hyp_nums 16, h_generalize hp : a == p with hh, guard_hyp_nums 19, guard_hyp' hh := β = α, guard_target f x y x z = f p (cast h₀ b) p (eq.mpr h₂ a), h_generalize hq : _ == q, guard_hyp_nums 21, guard_target f x y x z = f p q p (eq.mpr h₂ a), h_generalize _ : _ == r, guard_hyp_nums 23, guard_target f x y x z = f p q p r, casesm* [_ == _, _ = _], refl end end h_generalize section h_generalize variables {α β γ φ ψ : Type} (f : list α → list α → γ) (x : list α) (a : list β) (z : φ) (h₀ : β = α) (h₁ : list β = list α) (hx : x == a) include f x z a hx h₀ h₁ example : true := begin have : f x x = f (eq.rec_on h₀ a) (cast h₁ a), { guard_hyp_nums 11, h_generalize : a == p with _, guard_hyp_nums 13, guard_hyp' h := β = α, guard_target f x x = f p (cast h₁ a), h_generalize! : a == q , guard_hyp_nums 13, guard_target ∀ q, f x x = f p q, casesm* [_ == _, _ = _], success_if_fail { refl }, admit }, trivial end end h_generalize section tfae example (p q r s : Prop) (h₀ : p ↔ q) (h₁ : q ↔ r) (h₂ : r ↔ s) : p ↔ s := begin scc, end example (p' p q r r' s s' : Prop) (h₀ : p' → p) (h₀ : p → q) (h₁ : q → r) (h₁ : r' → r) (h₂ : r ↔ s) (h₂ : s → p) (h₂ : s → s') : p ↔ s := begin scc, end example (p' p q r r' s s' : Prop) (h₀ : p' → p) (h₀ : p → q) (h₁ : q → r) (h₁ : r' → r) (h₂ : r ↔ s) (h₂ : s → p) (h₂ : s → s') : p ↔ s := begin scc', assumption end example : tfae [true, ∀ n : ℕ, 0 ≤ n * n, true, true] := begin tfae_have : 3 → 1, { intro h, constructor }, tfae_have : 2 → 3, { intro h, constructor }, tfae_have : 2 ← 1, { intros h n, apply nat.zero_le }, tfae_have : 4 ↔ 2, { tauto }, tfae_finish, end example : tfae [] := begin tfae_finish, end variables P Q R : Prop example : tfae [P, Q, R] := begin have : P → Q := sorry, have : Q → R := sorry, have : R → P := sorry, --have : R → Q := sorry, -- uncommenting this makes the proof fail tfae_finish end example : tfae [P, Q, R] := begin have : P → Q := sorry, have : Q → R := sorry, have : R → P := sorry, have : R → Q := sorry, -- uncommenting this makes the proof fail tfae_finish end example : tfae [P, Q, R] := begin have : P ↔ Q := sorry, have : Q ↔ R := sorry, tfae_finish -- the success or failure of this tactic is nondeterministic! end example (p : unit → Prop) : tfae [p (), p ()] := begin tfae_have : 1 ↔ 2, from iff.rfl, tfae_finish end end tfae section clear_aux_decl example (n m : ℕ) (h₁ : n = m) (h₂ : ∃ a : ℕ, a = n ∧ a = m) : 2 * m = 2 * n := let ⟨a, ha⟩ := h₂ in begin clear_aux_decl, -- subst will fail without this line subst h₁ end example (x y : ℕ) (h₁ : ∃ n : ℕ, n * 1 = 2) (h₂ : 1 + 1 = 2 → x * 1 = y) : x = y := let ⟨n, hn⟩ := h₁ in begin clear_aux_decl, -- finish produces an error without this line finish end end clear_aux_decl section congr example (c : Prop → Prop → Prop → Prop) (x x' y z z' : Prop) (h₀ : x ↔ x') (h₁ : z ↔ z') : c x y z ↔ c x' y z' := begin congr', { guard_target x = x', ext, assumption }, { guard_target z = z', ext, assumption }, end end congr section convert_to example {a b c d : ℕ} (H : a = c) (H' : b = d) : a + b = d + c := by {convert_to c + d = _ using 2, from H, from H', rw[add_comm]} example {a b c d : ℕ} (H : a = c) (H' : b = d) : a + b = d + c := by {convert_to c + d = _ using 0, congr' 2, from H, from H', rw[add_comm]} example (a b c d e f g N : ℕ) : (a + b) + (c + d) + (e + f) + g ≤ a + d + e + f + c + g + b := by {ac_change a + d + e + f + c + g + b ≤ _, refl} end convert_to section swap example {α₁ α₂ α₃ : Type} : true := by {have : α₁, have : α₂, have : α₃, swap, swap, rotate, rotate, rotate, rotate 2, rotate 2, triv, recover} end swap section lift example (n m k x z u : ℤ) (hn : 0 < n) (hk : 0 ≤ k + n) (hu : 0 ≤ u) (h : k + n = 2 + x) : k + n = m + x := begin lift n to ℕ using le_of_lt hn, guard_target (k + ↑n = m + x), guard_hyp hn := (0 : ℤ) < ↑n, lift m to ℕ, guard_target (k + ↑n = ↑m + x), tactic.swap, guard_target (0 ≤ m), tactic.swap, tactic.num_goals >>= λ n, guard (n = 2), lift (k + n) to ℕ using hk with l hl, guard_hyp l := ℕ, guard_hyp hl := ↑l = k + ↑n, guard_target (↑l = ↑m + x), tactic.success_if_fail (tactic.get_local `hk), lift x to ℕ with y hy, guard_hyp y := ℕ, guard_hyp hy := ↑y = x, guard_target (↑l = ↑m + x), lift z to ℕ with w, guard_hyp w := ℕ, tactic.success_if_fail (tactic.get_local `z), lift u to ℕ using hu with u rfl hu, guard_hyp hu := (0 : ℤ) ≤ ↑u, all_goals { admit } end -- test lift of functions example (α : Type*) (f : α → ℤ) (hf : ∀ a, 0 ≤ f a) (hf' : ∀ a, f a < 1) (a : α) : 0 ≤ 2 * f a := begin lift f to α → ℕ using hf, guard_target ((0:ℤ) ≤ 2 * (λ i : α, (f i : ℤ)) a), guard_hyp hf' := ∀ a, ((λ i : α, (f i:ℤ)) a) < 1, trivial end instance can_lift_unit : can_lift unit unit := ⟨id, λ x, true, λ x _, ⟨x, rfl⟩⟩ /- test whether new instances of `can_lift` are added as simp lemmas -/ run_cmd do l ← can_lift_attr.get_cache, guard (`can_lift_unit ∈ l) /- test error messages -/ example (n : ℤ) (hn : 0 < n) : true := begin success_if_fail_with_msg {lift n to ℕ using hn} "lift tactic failed. The type of\n hn\nis 0 < n\nbut it is expected to be\n 0 ≤ n", success_if_fail_with_msg {lift (n : option ℤ) to ℕ} "Failed to find a lift from option ℤ to ℕ. Provide an instance of\n can_lift (option ℤ) ℕ", trivial end example (n : ℤ) : ℕ := begin success_if_fail_with_msg {lift n to ℕ} "lift tactic failed. Tactic is only applicable when the target is a proposition.", exact 0 end end lift private meta def get_exception_message (t : lean.parser unit) : lean.parser string | s := match t s with | result.success a s' := result.success "No exception" s | result.exception none pos s' := result.success "Exception no msg" s | result.exception (some msg) pos s' := result.success (msg ()).to_string s end @[user_command] meta def test_parser1_fail_cmd (_ : interactive.parse (lean.parser.tk "test_parser1")) : lean.parser unit := do let msg := "oh, no!", let t : lean.parser unit := tactic.fail msg, s ← get_exception_message t, if s = msg then tactic.skip else interaction_monad.fail "Message was corrupted while being passed through `lean.parser.of_tactic`" . -- Due to `lean.parser.of_tactic'` priority, the following *should not* fail with -- a VM check error, and instead catch the error gracefully and just -- run and succeed silently. test_parser1 section category_theory open category_theory variables {C : Type} [category.{1} C] example (X Y Z W : C) (x : X ⟶ Y) (y : Y ⟶ Z) (z z' : Z ⟶ W) (w : X ⟶ Z) (h : x ≫ y = w) (h' : y ≫ z = y ≫ z') : x ≫ y ≫ z = w ≫ z' := begin rw [h',reassoc_of h], end end category_theory section is_eta_expansion /- test the is_eta_expansion tactic -/ open function tactic structure my_equiv (α : Sort*) (β : Sort*) := (to_fun : α → β) (inv_fun : β → α) (left_inv : left_inverse inv_fun to_fun) (right_inv : right_inverse inv_fun to_fun) infix ` my≃ `:25 := my_equiv protected def my_rfl {α} : α my≃ α := ⟨id, λ x, x, λ x, rfl, λ x, rfl⟩ def eta_expansion_test : ℕ × ℕ := ((1,0).1,(1,0).2) run_cmd do e ← get_env, x ← e.get `eta_expansion_test, let v := (x.value.get_app_args).drop 2, let nms := [`prod.fst, `prod.snd], guard $ expr.is_eta_expansion_test (nms.zip v) = some `((1, 0)) def eta_expansion_test2 : ℕ my≃ ℕ := ⟨my_rfl.to_fun, my_rfl.inv_fun, λ x, rfl, λ x, rfl⟩ run_cmd do e ← get_env, x ← e.get `eta_expansion_test2, let v := (x.value.get_app_args).drop 2, projs ← e.structure_fields_full `my_equiv, b ← expr.is_eta_expansion_aux x.value (projs.zip v), guard $ b = some `(@my_rfl ℕ) run_cmd do e ← get_env, x1 ← e.get `eta_expansion_test, x2 ← e.get `eta_expansion_test2, b1 ← expr.is_eta_expansion x1.value, b2 ← expr.is_eta_expansion x2.value, guard $ b1 = some `((1, 0)) ∧ b2 = some `(@my_rfl ℕ) structure my_str (n : ℕ) := (x y : ℕ) def dummy : my_str 3 := ⟨3, 1, 1⟩ def wrong_param : my_str 2 := ⟨2, dummy.1, dummy.2⟩ def right_param : my_str 3 := ⟨3, dummy.1, dummy.2⟩ run_cmd do e ← get_env, x ← e.get `wrong_param, o ← x.value.is_eta_expansion, guard o.is_none, x ← e.get `right_param, o ← x.value.is_eta_expansion, guard $ o = some `(dummy) end is_eta_expansion section elide variables {x y z w : ℕ} variables (h : x + y + z ≤ w) (h' : x ≤ y + z + w) include h h' example : x + y + z ≤ w := begin elide 0 at h, elide 2 at h', guard_hyp h := @hidden _ (x + y + z ≤ w), guard_hyp h' := x ≤ @has_add.add (@hidden Type nat) (@hidden (has_add nat) nat.has_add) (@hidden ℕ (y + z)) (@hidden ℕ w), unelide at h, unelide at h', guard_hyp h' := x ≤ y + z + w, exact h, -- there was a universe problem in `elide`. `exact h` lets the kernel check -- the consistency of the universes end end elide section struct_eq @[ext] structure foo (α : Type*) := (x y : ℕ) (z : {z // z < x}) (k : α) (h : x < y) example {α : Type*} : Π (x y : foo α), x.x = y.x → x.y = y.y → x.z == y.z → x.k = y.k → x = y := foo.ext example {α : Type*} : Π (x y : foo α), x = y ↔ x.x = y.x ∧ x.y = y.y ∧ x.z == y.z ∧ x.k = y.k := foo.ext_iff example {α} (x y : foo α) (h : x = y) : y = x := begin ext, { guard_target' y.x = x.x, rw h }, { guard_target' y.y = x.y, rw h }, { guard_target' y.z == x.z, rw h }, { guard_target' y.k = x.k, rw h }, end end struct_eq section ring_exp example (a b : ℤ) (n : ℕ) : (a + b)^(n + 2) = (a^2 + 2 * a * b + b^2) * (a + b)^n := by ring_exp end ring_exp section clear' example {α} {β : α → Type} (a : α) (b : β a) : unit := begin success_if_fail { clear a b }, -- fails since `b` depends on `a` success_if_fail { clear' a }, -- fails since `b` depends on `a` clear' a b, guard_hyp_nums 2, exact () end example {α} {β : α → Type} (a : α) : β a → unit := begin success_if_fail { clear' a }, -- fails since the target depends on `a` exact λ _, () end end clear' section clear_dependent example {α} {β : α → Type} (a : α) (b : β a) : unit := begin success_if_fail { clear' a }, -- fails since `b` depends on `a` clear_dependent a, guard_hyp_nums 2, exact () end example {α} {β : α → Type} (a : α) : β a → unit := begin success_if_fail { clear_dependent a }, -- fails since the target depends on `a` exact λ _, () end end clear_dependent section simp_rw example {α β : Type} {f : α → β} {t : set β} : (∀ s, f '' s ⊆ t) = ∀ s : set α, ∀ x ∈ s, x ∈ f ⁻¹' t := by simp_rw [set.image_subset_iff, set.subset_def] end simp_rw