Zulip Chat Archive

Stream: new members

Topic: Simplification


Janitha (Feb 21 2025 at 05:32):

import Mathlib
open Nat

def h :   Int
  | 0 => 2
  | 1 => 1
  | 2 => 5
  | n + 2 => h (n + 1) + 2 * h n


def g (n : ) : Int := 2^n + (-1)^n

example (n : ) : h n = g n  h (n+1) = g (n+1) := by
  induction n with
  | zero =>
  constructor
  rfl
  rfl
  | succ k ih =>
  constructor
  apply ih.right
  calc
    h (k + 2) = h (k + 1) + 2 * h k := by {unfold h}
               _ = g (k + 1) + 2 * g k := by rw [ih.1, ih.2]
               _ = (2^(k + 1) + (-1)^(k + 1)) + 2 * (2^k + (-1)^k) := by rfl
               _ = 2^(k + 1) + (-1)^(k + 1) + 2 * 2^k + 2 * (-1)^k := by ring
               _ = 2^(k + 2) + (-1)^(k + 2) := by
                 simp only [pow_succ, pow_add, mul_comm]
                 ring


I get an error here: " h (k + 2) = h (k + 1) + 2 * h k := by {unfold h}" . How do I fix this proof?

Matt Diamond (Feb 21 2025 at 06:07):

the problem is that you've unnecessarily complicated things by explicitly defining the 2 case for h when it already follows from the rest of the definition

without that, rfl works just fine

import Mathlib
open Nat

def h :   Int
  | 0 => 2
  | 1 => 1
  | n + 2 => h (n + 1) + 2 * h n

def g (n : ) : Int := 2^n + (-1)^n

example (n : ) : h n = g n  h (n+1) = g (n+1) := by
  induction n with
  | zero =>
  constructor
  rfl
  rfl
  | succ k ih =>
  constructor
  apply ih.right
  calc
    h (k + 2) = h (k + 1) + 2 * h k := by rfl
               _ = g (k + 1) + 2 * g k := by rw [ih.1, ih.2]
               _ = (2^(k + 1) + (-1)^(k + 1)) + 2 * (2^k + (-1)^k) := by rfl
               _ = 2^(k + 1) + (-1)^(k + 1) + 2 * 2^k + 2 * (-1)^k := by ring
               _ = 2^(k + 2) + (-1)^(k + 2) := by
                 simp only [pow_succ, pow_add, mul_comm]
                 ring

Chris Wong (Feb 21 2025 at 06:15):

What Matt said, but also: You can simplify the proof using induction n using Nat.twoStepInduction

Chris Wong (Feb 21 2025 at 06:15):

docs#Nat.twoStepInduction

Chris Wong (Feb 21 2025 at 06:18):

induction n using h.induct might work too

Chris Wong (Feb 21 2025 at 06:28):

import Mathlib
open Nat

def h :   Int
  | 0 => 2
  | 1 => 1
  | n + 2 => h (n + 1) + 2 * h n

def g (n : ) : Int := 2^n + (-1)^n

example (n : ) : h n = g n := by
  induction n using h.induct with
  | case1 => rfl
  | case2 => rfl
  | case3 k ih' ih =>
    calc
      h (k + 2) = h (k + 1) + 2 * h k := by rfl
                _ = g (k + 1) + 2 * g k := by rw [ih, ih']
                _ = (2^(k + 1) + (-1)^(k + 1)) + 2 * (2^k + (-1)^k) := by rfl
                _ = 2^(k + 1) + (-1)^(k + 1) + 2 * 2^k + 2 * (-1)^k := by ring
                _ = 2^(k + 2) + (-1)^(k + 2) := by ring

Matt Diamond (Feb 21 2025 at 06:28):

nice

Chris Wong (Feb 21 2025 at 06:34):

Using the "functional induction" feature described here: https://lean-lang.org/blog/2024-5-17-functional-induction/

Janitha (Feb 21 2025 at 06:36):

Got it, Thanks Matt and Chris! Could you please tell me, what if I didn't have the case `| 0 => 2 for h but the other three cases

| 1 => 1
| 2 => 5
| n + 2 => h (n + 1) + 2 * h n

and the functions h and g were from positive integers to positive integers? The reason why I defined explicitly for zero was I kept getting an error. I thought I'd prove what was in my code and do something with the restrictions of h and g to positive integers.

Chris Wong (Feb 21 2025 at 08:35):

Then it would be a type error, because Lean functions must be defined for _every_ value in the domain

Chris Wong (Feb 21 2025 at 08:37):

There is docs#PNat for positive integers, but I still recommend defining it for zero, because though it's not part of the original problem, it does make the proof easier and more general

Chris Wong (Feb 21 2025 at 08:37):

You might like to read this to see why such "junk values" are good practice: https://xenaproject.wordpress.com/2020/07/05/division-by-zero-in-type-theory-a-faq/

Janitha (Feb 27 2025 at 05:04):

I'm stuck at the "sorry." Can someone help? What's a good strategy in general at such steps?

import Mathlib

set_option exponentiation.threshold 5000

example {f :   }

(h1 : f 1 = 1) (h2 :  n > 0, f (2 * n) = n * f n) : f (2 ^ 100) = 2 ^ 4950 := by

have h :  n : , f (2^n) = 2^((n-1) * n / 2) := by

intro n

induction n with

| zero =>
-- Base case: f(2^0) = f(1) = 1

rw [pow_zero]

exact h1

| succ n ih =>

calc

f (2 ^ (n + 1))

= f (2 * 2 ^ n) := by

rw [pow_succ, mul_comm]

_ = (2 ^ n) * f (2 ^ n) := by

apply h2

apply pow_pos

norm_num

_ = (2 ^ n) * (2 ^ ((n - 1) * n / 2)) := by

rw [ih]

_ = 2 ^ (n + ((n - 1) * n / 2)) := by

ring_nf

_ = 2 ^ (((n + 1 - 1) * (n + 1)) / 2) := by

sorry

exact h 100

Janitha (Feb 27 2025 at 05:34):

I'm having trouble filling the "sorry", please help.

import Mathlib

set_option exponentiation.threshold 5000

example {f : ℕ → ℕ}

(h1 : f 1 = 1) (h2 : ∀ n > 0, f (2 * n) = n * f n) : f (2 ^ 100) = 2 ^ 4950 := by

have h : ∀ n : ℕ, f (2^n) = 2^((n-1) * n / 2) := by

intro n

induction n with

| zero =>
-- Base case: f(2^0) = f(1) = 1

rw [pow_zero]

exact h1

| succ n ih =>

calc

f (2 ^ (n + 1))

= f (2 * 2 ^ n) := by

rw [pow_succ, mul_comm]

_ = (2 ^ n) * f (2 ^ n) := by

apply h2

apply pow_pos

norm_num

_ = (2 ^ n) * (2 ^ ((n - 1) * n / 2)) := by

rw [ih]

_ = 2 ^ (n + ((n - 1) * n / 2)) := by

ring_nf

_ = 2 ^ (((n + 1 - 1) * (n + 1)) / 2) := by

sorry

exact h 100

Sabbir Rahman (Feb 27 2025 at 06:11):

The problem is that Natural division is floor division in lean, so ring can't really work "across" natural divisions, you can try using theorems like add_mul_div_left which works with natrual division

Ruben Van de Velde (Feb 27 2025 at 06:42):

Please read #backticks and edit your message

Ruben Van de Velde (Feb 27 2025 at 06:51):

And can a maintainer merge this with https://leanprover.zulipchat.com/#narrow/channel/113489-new-members/topic/Simplification please, double posting wastes the time of people trying to help you

Bjørn Kjos-Hanssen (Feb 27 2025 at 07:00):

This works...

      congr
      symm
      nth_rewrite 1 [mul_comm]
      nth_rewrite 2 [mul_comm,add_comm]
      apply Nat.div_eq_of_eq_mul_right
      simp
      rw [mul_add]
      cases n with
      | zero => simp
      | succ n =>
        simp
        have : 2 * ((n + 1) * n / 2) = (n+1) * n := by
          nth_rewrite 1 [mul_comm]
          refine Nat.div_two_mul_two_of_even ?_
          refine Nat.even_mul.mpr ?_
          by_cases H : Even n
          · tauto
          · left
            exact Nat.even_add_one.mpr H
        linarith

Janitha (Feb 27 2025 at 07:22):

Hi Professor Bjorn. It worked. Thanks!

Notification Bot (Mar 01 2025 at 01:05):

15 messages were moved here from #lean4 > A proof by induction by Kim Morrison.


Last updated: May 02 2025 at 03:31 UTC