Zulip Chat Archive

Stream: Is there code for X?

Topic: 2 is not a square


Heather Macbeth (Mar 15 2022 at 03:03):

What's the slick way to prove that 2 is not a square?

import data.nat.basic

example (m : ) : m ^ 2  2 := sorry

No luck with library_search (at least not with simple imports), omega, norm_num, ...

Scott Morrison (Mar 15 2022 at 03:42):

This is terrible. :-) I wanted to use interval_cases, but then couldn't find any of the lemmas I needed for that anyway...

import data.nat.basic
import tactic.interval_cases

lemma nat.le_self_mul_pos (n m : ) (h : 0 < m) : n  n * m :=
begin
  cases m, cases h,
  exact le_add_self,
end

lemma nat.le_self_pow (n k : ) (h : 0 < k) : n  n^k :=
begin
  cases n, { simp, },
  cases k with k, { cases h, },
  rw [pow_succ],
  apply nat.le_self_mul_pos,
  finish,
end

lemma nat.le_square (n : ) : n  n^2 := nat.le_self_pow _ _ zero_lt_two

example (m : ) : m ^ 2  2 :=
begin
  intro h,
  have : m  2 := (nat.le_square m).trans h.le,
  interval_cases m; cases h,
 end

Scott Morrison (Mar 15 2022 at 03:43):

Surely the first three lemmas already exist somewhere???

Heather Macbeth (Mar 15 2022 at 03:52):

I found

import tactic

example (m : ) : m ^ 2  2 :=
begin
  intros h,
  have : m  finset.range 3 := by simp; nlinarith,
  fin_cases this;
  norm_num at h,
end

which seems rather overkill.

Heather Macbeth (Mar 15 2022 at 03:53):

Ah, that's basically the same as yours, using overkill instead of proving a lemma nat.le_square, and using fin_cases instead of interval_cases.

Scott Morrison (Mar 15 2022 at 03:56):

Ah, yes, nlinarith+interval_cases is slightly nicer:

example (m : ) : m ^ 2  2 :=
begin
  intros h,
  have : m  2 := by nlinarith,
  interval_cases m; cases h,
end

Heather Macbeth (Mar 15 2022 at 03:57):

I think that's not embarrassing!

Scott Morrison (Mar 15 2022 at 04:03):

Yes! It's actually pretty good. The only problem with it is that I still don't have a good mental model of what nlinarith can and can't do, which makes it feel less "reproducible".

Scott Morrison (Mar 15 2022 at 04:04):

And I hope someone will explain whether the extra lemmas I had to write exist or not. If they don't exist I should add them.

Eric Rodriguez (Mar 15 2022 at 06:03):

import algebra.squarefree

example (m : ) : m ^ 2  2 :=
begin
  intro h,
  have : squarefree (m^2) := h.symm  (nat.prime_iff.mp nat.prime_two).squarefree,
  specialize this m 1, by rw [sq, mul_one]⟩,
  rw nat.is_unit_iff at this,
  norm_num [this] at h,
end

Heather Macbeth (Mar 15 2022 at 06:08):

In my opinion, this is better as a way of proving that 43 is not a square, but worse as a way of proving that 2 is not a square.

Junyan Xu (Mar 15 2022 at 06:22):

import data.nat.prime

example (m : ) : m ^ 2  2 :=
λ he, by { cases (nat.dvd_prime nat.prime_two).1
  (⟨m, by rw [ he, pow_two]⟩: m  2) with h; subst h; cases he }

Ruben Van de Velde (Mar 15 2022 at 06:45):

Maybe

example (r : ) : r ^ 2  2 :=
begin
  have : 1  2,
  { norm_num },
  apply monotone.ne_of_lt_of_lt_nat (nat.pow_left_strict_mono this).monotone 1; norm_num,
end

Ruben Van de Velde (Mar 15 2022 at 06:51):

I.e., no square lies between two consecutive squares

Ruben Van de Velde (Mar 15 2022 at 06:52):

(Credit to whoever proved that 2 is not a cube here on zulip a while ago)

Junyan Xu (Mar 15 2022 at 07:02):

I thought of this approach but couldn't find nat.pow_left_strict_mono; here's golfed solution:

import tactic
example (m : ) : m ^ 2  2 :=
by apply monotone.ne_of_lt_of_lt_nat (nat.pow_left_strict_mono _).monotone 1; norm_num

Ruben Van de Velde (Mar 15 2022 at 08:27):

Also, it's clearly a trivial consequence of docs#irrational_sqrt_two, but I feel like it would take some work to convince lean of that

Kevin Buzzard (Mar 15 2022 at 08:29):

Yeah we had all this out on the discord recently for sqrt(3) with Bhavik suggesting irrationality was a quick approach, but it never seemed to be quicker than the integral approaches

Ruben Van de Velde (Mar 15 2022 at 08:34):

example (m : ) : m ^ 2  2 :=
begin
  intro h,
  have qr : ((2 : ) : ) = 2, { norm_num },
  have := irrational_sqrt_two,
  rw [qr, irrational_sqrt_rat_iff] at this,
  apply this.1,
  have nq : ((2 : ) : ) = 2, { norm_num },
  rw [nq, h, sq m, nat.cast_mul, rat.sqrt_eq, abs_mul, abs_mul_self],
end

Kevin Buzzard (Mar 15 2022 at 08:39):

Yeah exactly

Yury G. Kudryashov (Mar 16 2022 at 06:07):

example (k : ) : k ^ 2  2 :=
begin
  refine mt (λ h, _) irrational_sqrt_two,
  use k,
  rw [rat.cast_coe_nat,  sq_eq_sq,  nat.cast_pow, h, nat.cast_two, real.sq_sqrt],
  exacts [zero_le_two, k.cast_nonneg, real.sqrt_nonneg 2]
end

Kyle Miller (Mar 16 2022 at 06:14):

This seems like a good codegolf.stackexchange.com question

Kyle Miller (Mar 16 2022 at 06:34):

Here's a "rational root theorem" solution:

import data.nat.basic
import tactic

example (k : ) : k ^ 2  2 :=
begin
  intro h,
  have : k  2,
  { rw [h, sq],
    exact dvd.intro k rfl, },
  have : k  2 := nat.le_of_dvd two_pos this,
  interval_cases k; norm_num at h,
end

Is there a good way to turn k ∣ 2 into k = 1 ∨ k = 2 by computing divisors?

Junyan Xu (Mar 16 2022 at 06:44):

same idea as https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/2.20is.20not.20a.20square/near/275333827 where I used 2 a prime

Scott Morrison (Mar 16 2022 at 06:47):

@Kyle Miller:

example (k : ) (h : k  2) : k = 1  k = 2 :=
begin
  have : k  nat.divisors 2, { simp [h] },
  fin_cases this; simp,
end

Johan Commelin (Mar 16 2022 at 06:47):

Sounds like we need dvd_cases

Scott Morrison (Mar 16 2022 at 06:48):

(Warning, the performance scales very badly for larger values of 2!)

Kyle Miller (Mar 16 2022 at 06:49):

I got 43 to work this way:

import data.nat.basic
import number_theory.divisors
import tactic

lemma nat.mem_divisors_of_dvd {n m : } (h : m  0) (hd : n  m) : n  m.divisors :=
by simp [*]

example (k : ) : k ^ 2  43 :=
begin
  intro h,
  have : k  nat.divisors 43,
  { apply nat.mem_divisors_of_dvd (by norm_num : 43  0),
    rw [h, sq],
    exact dvd.intro k rfl, },
  have hd : nat.divisors 43 = {1, 43} := dec_trivial,
  simp only [hd, finset.mem_insert, finset.mem_singleton] at this,
  obtain rfl|rfl := this; norm_num at h,
end

Kyle Miller (Mar 16 2022 at 06:50):

Proving that it's way too general to prove 2 is not a square :smile:

Johan Commelin (Mar 16 2022 at 06:57):

@Scott Morrison But with a bit of norm_num, a dvd_cases should be able to be performant, right?

Kyle Miller (Mar 16 2022 at 07:00):

I was thinking about how it could be implemented similarly to the interval_cases PR I haven't finished yet. (My course's final exam was today, so I should have time to get back to that!)

Mario Carneiro (Mar 16 2022 at 07:08):

What are the rules of the game here? Are lemmas allowed?

import tactic.norm_num

theorem is_not_square (n a : ) (h₁ : n ^ 2 < a) (h₂ : a < (n+1)^2) (k) : k^2  a :=
begin
  rintro rfl,
  simp [pow_two,  nat.mul_self_lt_mul_self_iff] at *,
  cases not_le_of_gt h₂ h₁
end

example :  k, k ^ 2  2 := is_not_square 1 _ (by norm_num) (by norm_num)
example :  k, k ^ 2  43 := is_not_square 6 _ (by norm_num) (by norm_num)

Junyan Xu (Mar 16 2022 at 07:18):

theorem is_not_square (n a : ) (h₁ : n ^ 2 < a) (h₂ : a < (n+1)^2) (k) : k^2  a :=
by apply monotone.ne_of_lt_of_lt_nat (nat.pow_left_strict_mono (by norm_num : 1  2)).monotone n h₁ h₂

https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/2.20is.20not.20a.20square/near/275334964

Scott Morrison (Mar 16 2022 at 07:23):

I guess we should add support for nat.sqrt to norm_num so one doesn't even need to compute the constants:

example :  k, k ^ 2  43 := is_not_square (nat.sqrt 43) _ (by norm_num) (by norm_num)

Mario Carneiro (Mar 16 2022 at 07:23):

I'm already writing it

Kevin Buzzard (Mar 16 2022 at 07:41):

Just to say that two weeks ago this came up on the discord but with sqrt(3) and in particular it does happen "in the wild".

Mario Carneiro (Mar 16 2022 at 08:02):

On #12735:

import data.nat.sqrt_norm_num

theorem is_not_square {n : } (h : (nat.sqrt n)^2 < n) (k) : k^2  n :=
by { rintro rfl, simpa [nat.sqrt_eq'] using h }

example :  k, k ^ 2  2 := is_not_square (by norm_num)
example :  k, k ^ 2  43 := is_not_square (by norm_num)

Last updated: Dec 20 2023 at 11:08 UTC