Zulip Chat Archive

Stream: maths

Topic: Size of certain finset


Chris Birkbeck (Aug 10 2023 at 10:53):

Is there an easy way to prove the size of the following Finset:

def square (m : ) : Finset ( × ) :=
  ((Finset.Icc (-m) (m)) ×ˢ (Finset.Icc (-m) (m))).filter fun x =>
    max x.1.natAbs x.2.natAbs = m

theorem square_size (n : ) (h : 1  n) : Finset.card (square n) = 8 * n := --This is what I want to prove

I can do this by first doing a horrible case check to show this Finset is the same as :

def square2 (m : ) : Finset ( × ) :=
  ((Finset.Icc (-m) (m)) ×ˢ  {(m)}) 
  (Finset.Icc (-m ) (m)) ×ˢ {-(m)} 
  ({(m)} : Finset ) ×ˢ (Finset.Icc (-(m) + 1) (m-1)) 
  ({-(m)} : Finset ) ×ˢ (Finset.Icc (-(m) + 1) (m-1))

But I was hoping for something nicer.

Eric Wieser (Aug 10 2023 at 11:02):

Is showing it's the difference of Finset.Icc (-m, -m) (m, m) and Finset.Icc (-m + 1, -m + 1)(m - 1, m-1) any easier?

Chris Birkbeck (Aug 10 2023 at 11:07):

Hmm I can't immediately tell if that would be any easier

Alex J. Best (Aug 10 2023 at 17:13):

had a stab at these but gave up as its pretty horrible lol, also please #mwe next time with imports :wink:

import Mathlib.Order.LocallyFinite
import Mathlib.Data.Int.Interval
import Mathlib.Tactic
def square (m : ) : Finset ( × ) :=
  ((Finset.Icc (-m) (m)) ×ˢ (Finset.Icc (-m) (m))).filter fun x =>
    max x.1.natAbs x.2.natAbs = m
lemma square_eq (hm : 1  m) : square m =
    Finset.Icc (-m,-m) (m,m) \
    Finset.Icc (-(m-1),-(m-1)) (m-1,m-1) := by
  ext x1,x2
  simp [square, max_eq_iff]
  intros h1 h2 h3 h4
  rcases abs_cases x1 with su, hh | su, hh <;>
  rcases abs_cases x2 with su2, hh2 | su2, hh2 <;>
  simp [*] at *
  .
    aesop
    rw [or_iff_not_imp_left]
    specialize a (le_add_of_nonneg_of_le hh hm)
    aesop
    . specialize a (by sorry) (le_add_of_nonneg_of_le hh2 hm)
      linarith
    . linarith

theorem square_size (n : ) (h : 1  n) : Finset.card (square n) = 8 * n := --This is what I want to prove
by
  rw [square_eq]
  rw [Finset.card_sdiff]
  . rw [Prod.card_Icc]
    rw [Prod.card_Icc]
    simp only [gt_iff_lt, lt_neg_self_iff, Int.card_Icc, sub_neg_eq_add,
      neg_sub, sub_add_cancel,  sub_add, ge_iff_le]
    norm_cast
    simp only [Int.toNat_ofNat]
    have : (n - 1 + n) * (n - 1 + n)   (n + 1 + n) * (n + 1 + n)
    . apply mul_le_mul' <;>
        simp <;>
        linarith
    zify [h, this]
    ring
  . intro x h
    simp only [gt_iff_lt, Prod.mk_lt_mk, lt_neg_self_iff, le_neg_self_iff,
      Int.coe_nat_nonpos_iff, Prod.Icc_mk_mk,
      Finset.mem_product, Finset.mem_Icc] at *
    aesop <;>
    linarith

Eric Wieser (Aug 10 2023 at 17:30):

I thought an induction approach might be more pleasant, but ran into a deterministic timeout in simp only:

import Mathlib.Order.LocallyFinite
import Mathlib.Data.Int.Interval
import Mathlib.Tactic
def square (m : ) : Finset ( × ) :=
  ((Finset.Icc (-m) (m)) ×ˢ (Finset.Icc (-m) (m))).filter fun x =>
    max x.1.natAbs x.2.natAbs = m

lemma square_eq (n : ) : square n.succ =
    Finset.Icc ((-n.succ,-n.succ) :  × ) (n.succ,n.succ) \
    Finset.Icc (-(n),-(n)) (n,n) := by
  induction n with
  | zero =>
    simp only  -- this causes it to hang
    sorry
  | succ n ih =>
    sorry

Alex J. Best (Aug 10 2023 at 17:31):

If only we still had omega :sad:

Eric Rodriguez (Aug 10 2023 at 18:26):

oh E_2, i'll have a stab in a couple seconds

Eric Rodriguez (Aug 10 2023 at 18:37):

rfl proves the zero step

Eric Rodriguez (Aug 10 2023 at 18:37):

but I'm not too sure how this is an inductive approach

Eric Rodriguez (Aug 10 2023 at 18:38):

as in, I don't really see an obvious induction argument for this

Eric Wieser (Aug 10 2023 at 18:38):

I hit the timeout before thinking about it

Eric Wieser (Aug 10 2023 at 18:39):

But I would guess a more viable aproach is to show that (square n.succ).disjUnion (Finset.Icc (-(n),-(n)) (n,n)) sorry = Finset.Icc ((-n.succ,-n.succ) : ℤ × ℤ) (n.succ,n.succ)

Eric Wieser (Aug 10 2023 at 18:39):

Which should also make it easier to get the cardinality at the end

Eric Rodriguez (Aug 10 2023 at 19:38):

def square (m : ) : Finset ( × ) :=
  ((Finset.Icc (-m) (m)) ×ˢ (Finset.Icc (-m) (m))).filter fun x =>
    max x.1.natAbs x.2.natAbs = m

lemma square_eq (n : ) : square (n + 1) =
  (((Finset.Icc (-(n + 1) : ) (n + 1)).map ⟨(·, ((n + 1) : )), fun a b h  by sorry⟩).disjUnion
    ((Finset.Icc (-(n + 1) : ) (n + 1)).map ⟨(·, (-(n + 1) : )), fun a b h  by sorry⟩)
  (Finset.disjoint_iff_ne.mpr <| fun a ha b hb  by simp only [Finset.mem_map] at ha hb; obtain k, -, rfl := ha; obtain m, -, rfl := hb; linarith)) 
  (((Finset.Icc (-(n + 1) : ) (n + 1)).map ⟨(((n + 1) : ), ·), fun a b h  by sorry⟩).disjUnion
    ((Finset.Icc (-(n + 1) : ) (n + 1)).map ⟨((-(n + 1) : ), ·), fun a b h  by sorry⟩)
    (Finset.disjoint_iff_ne.mpr <| fun a ha b hb  by simp only [Finset.mem_map] at ha hb; obtain k, -, rfl := ha; obtain m, -, rfl := hb; linarith)) := by
  apply le_antisymm
  · intro a h
    sorry
  · intro a h
    sorry


theorem Finset.card_union [DecidableEq α] {s t : Finset α} : (s  t).card = s.card + t.card - (s  t).card :=
eq_tsub_of_add_eq (card_union_add_card_inter s t)

example (m : ) : (square $ m + 1).card = 8 * (m + 1) := by
  rw [square_eq, Finset.card_union]
  have : Int.toNat (m + 1 + 1 - (-1 + -↑m)) = (2 * (m + 1) + 1)
  · ring_nf
    rfl
  simp only [Finset.card_map, Finset.card_disjUnion, neg_add_rev, gt_iff_lt, lt_add_neg_iff_add_lt, Int.card_Icc, ge_iff_le, this]
  apply Nat.sub_eq_of_eq_add
  have : 2 * (m + 1) + 1 + (2 * (m + 1) + 1) + (2 * (m + 1) + 1 + (2 * (m + 1) + 1)) = 8 * (m + 1) + 4
  · ring
  rw [this, add_right_inj]
  sorry

Eric Rodriguez (Aug 10 2023 at 19:38):

I think this is a good approach

Eric Rodriguez (Aug 10 2023 at 19:38):

the sorrys in the definition of square_eq are by aesop, I just removed them for speed

Eric Rodriguez (Aug 10 2023 at 19:38):

the sorrys in that theorem just follow by boring ass case bashing

Eric Rodriguez (Aug 10 2023 at 19:39):

and the last sorry is that the corners have size 4, the expression looks really ugly but it's probably fairly simple with judicious use of simp

Eric Rodriguez (Aug 10 2023 at 20:09):

(stuff looks a lot better with set_option pp.proofs.withType false)

Bhavik Mehta (Aug 10 2023 at 22:03):

import Mathlib.Order.LocallyFinite
import Mathlib.Data.Int.Interval
import Mathlib.Tactic
import Mathlib.Data.Finset.Basic

def square (m : ) : Finset ( × ) :=
  ((Finset.Icc (-m) (m)) ×ˢ (Finset.Icc (-m) (m))).filter fun x =>
    max x.1.natAbs x.2.natAbs = m

-- a re-definition in simp-normal form
lemma square_eq (m : ) :
  square m = ((Finset.Icc (-m) (m)) ×ˢ (Finset.Icc (-m) (m))).filter fun x => max |x.1| |x.2| = m :=
  by simp [square]

open Finset

lemma mem_square_aux {m : } {i} : i  Icc (-m) m ×ˢ Icc (-m) m  max |i.1| |i.2|  m :=
  by simp [abs_le]

lemma square_disj {n : } : Disjoint (square (n+1)) (Icc (-n) n ×ˢ Icc (-n) n) := by
  rw [square_eq]
  simp only [Finset.disjoint_left, mem_filter, mem_square_aux]
  intros x y
  simp_all

-- copied from the nat version, probably it already exists somewhere?
lemma Int.le_add_one_iff {m n : } : m  n + 1  m  n  m = n + 1 :=
  fun h =>
    match eq_or_lt_of_le h with
    | Or.inl h => Or.inr h
    | Or.inr h => Or.inl <| lt_add_one_iff.1 h,
    Or.rec (fun h => le_trans h <| le.intro 1 rfl) le_of_eq

lemma square_union {n : } :
    square (n+1)  Icc (-n) n ×ˢ Icc (-n) n = Icc (-(n+1)) (n+1) ×ˢ Icc (-(n+1)) (n+1) := by
  ext x
  rw [mem_union, square_eq, mem_filter, mem_square_aux, mem_square_aux,
    and_iff_right_of_imp le_of_eq, Int.le_add_one_iff, or_comm]

lemma square_disjunion (n : ) :
  (square (n+1)).disjUnion (Icc (-n) n ×ˢ Icc (-n) n) square_disj =
    Icc (-(n+1)) (n+1) ×ˢ Icc (-(n+1)) (n+1) :=
  by rw [disjUnion_eq_union, square_union]

theorem square_size (n : ) : Finset.card (square (n + 1)) = 8 * (n + 1) := by
  have : (((square (n+1)).disjUnion (Icc (-n : ) n ×ˢ Icc (-n : ) n) square_disj).card : ) =
    (Icc (-(n+1 : )) (n+1) ×ˢ Icc (-(n+1 : )) (n+1)).card
  · rw [square_disjunion]
  rw [card_disjUnion, card_product, Nat.cast_add, Nat.cast_mul, card_product, Nat.cast_mul,
    Int.card_Icc, Int.card_Icc, Int.toNat_sub_of_le, Int.toNat_sub_of_le,
    eq_sub_iff_add_eq] at this
  · rw [Nat.cast_inj (R := ), this, Nat.cast_mul, Nat.cast_ofNat, Nat.cast_add_one]
    ring_nf
  · linarith
  · linarith

using Erics' ideas, but without the case bashing

Chris Birkbeck (Aug 10 2023 at 22:12):

Oh amazing, thank you! I was out and missed all the discussion, but I'll definitely profit from the results :)

Bhavik Mehta (Aug 10 2023 at 22:17):

The key ideas are to use Eric W's idea of showing the disjoint union, and then expressing everything in terms of max |x| |y| makes the case-work a lot simpler

Chris Birkbeck (Aug 10 2023 at 22:18):

Yes, I hadn't thought about showing the disjoint union. That's a really nice way to do it


Last updated: Dec 20 2023 at 11:08 UTC