(* Formalizing and Proving Theorems in Coq --- Homework 3, part c. curated by Tobias Kappé, May 2022. There are no exercises in this file; it just serves to demonstrate some applications of the lia tactic. *) Require Import Coq.micromega.Lia. Lemma add_zero_right (n: nat): n + 0 = n . Proof. lia. Qed. Lemma add_zero_left (n: nat): 0 + n = n . Proof. lia. Qed. Lemma add_succ (n m: nat): S n + m = n + S m . Proof. lia. Qed. Lemma add_commute (n m: nat): n + m = m + n . Proof. lia. Qed. Lemma add_associate (n m k: nat): (n + m) + k = n + (m + k) . Proof. lia. Qed. Lemma add_associate_more (n m k l: nat): ((n + m) + k) + l = n + (m + (k + l)) . Proof. lia. Qed. Lemma add_exchange (p q r s: nat): (p + q) + (r + s) = (p + r) + (q + s) . Proof. lia. Qed. Lemma mul_zero (n: nat): 0 * n = 0 . Proof. lia. Qed. Lemma mul_succ (n m: nat): S n * m = m + n * m . Proof. lia. Qed. Lemma mul_commute (n m: nat): n * m = m * n . Proof. lia. Qed. Fixpoint sum_odd (n: nat): nat := match n with | 0 => 0 | S n' => S (sum_odd n' + 2 * n') end . Lemma sum_odd_is_square (n: nat): sum_odd n = n * n . Proof. induction n; simpl. - auto. - lia. Qed. Lemma mul_distribute_right (n m k: nat): (n + m) * k = n * k + m * k . Proof. lia. Qed. Fixpoint accumulate (n: nat): nat := match n with | 0 => 0 | S n' => n + (accumulate n') end . Lemma gauss_correct (n: nat): 2 * (accumulate n) = n * (S n) . Proof. induction n; simpl. - auto. - lia. Qed. Fixpoint fib (n: nat): nat := match n with | 0 => 0 | S n' => match n' with | 0 => 1 | S n'' => fib n' + fib n'' end end . Lemma fib_plus_two (n: nat): fib (S (S n)) = fib n + fib (S n) . Proof. simpl. lia. Qed. Lemma fib_multiply (n m: nat): fib (n + S m) = fib (S n) * fib (S m) + fib n * fib m . Proof. revert n. induction m; intros. - simpl fib at 3. simpl fib at 4. Search (_ * 1). rewrite PeanoNat.Nat.mul_1_r. Search (_ * 0). rewrite PeanoNat.Nat.mul_0_r. Search (_ + 0). rewrite PeanoNat.Nat.add_0_r. f_equal. lia. - rewrite <- add_succ, IHm. repeat rewrite fib_plus_two. lia. Qed. Lemma less_than_equal_trans (n m k: nat): n <= m -> m <= k -> n <= k . Proof. lia. Qed. Lemma less_than_equal_shift (n m: nat): n <= m -> S n <= S m . Proof. lia. Qed. Lemma less_than_equal_zero (n: nat): n <= 0 -> n = 0 . Proof. lia. Qed. Lemma less_than_equal_succ (n m: nat): n <= S m -> n = S m \/ n <= m . Proof. lia. Qed. Lemma less_than_equal_mono_add_left (n m k: nat): n <= m -> n + k <= m + k . Proof. lia. Qed. Lemma less_than_equal_mono_add (n m k l: nat): n <= m -> k <= l -> n + k <= m + l . Proof. lia. Qed. Lemma less_than_equal_mono_mul (n m k: nat): n <= m -> n * k <= m * k . Proof. Fail lia. Admitted. Fixpoint lucas (n: nat): nat := match n with | 0 => 2 | S n' => match n' with | 0 => 1 | S n'' => (lucas n') + (lucas n'') end end . Lemma lucas_plus_two (n: nat): lucas (S (S n)) = lucas n + lucas (S n) . Proof. simpl. lia. Qed. Definition holds_up_to (P: nat -> Prop) (n: nat) := forall (m: nat), m <= n -> P m . Lemma strong_induction (P: nat -> Prop) (HBase: P 0) (HStep: forall (n: nat), holds_up_to P n -> P (S n)) (n: nat) : P n . Proof. enough (forall m, m <= n -> P m); auto. induction n; intros. - now rewrite less_than_equal_zero. - destruct (less_than_equal_succ m n); auto. subst. apply HStep. unfold holds_up_to. apply IHn. Qed. Lemma pair_induction (P: nat -> Prop) (HBaseZero: P 0) (HBaseOne: P 1) (HStep: forall (n: nat), P n -> P (S n) -> P (S (S n))) (n: nat) : P n . Proof. induction n using strong_induction; auto. unfold holds_up_to in H. destruct n; auto. Qed. Lemma lucas_vs_fibonnaci (n: nat): lucas (S n) = (fib n) + (fib (S (S n))) . Proof. induction n using pair_induction; auto. rewrite lucas_plus_two. rewrite IHn, IHn0. repeat rewrite fib_plus_two. lia. Qed.