Zulip Chat Archive

Stream: new members

Topic: dec_trivial for zmod 8


Damiano Testa (May 13 2021 at 15:18):

Dear All,

I do not know anything about computability, but I would have thought that the lemma below should be provable "automatically". I do not mind if you change the set to something more "decidable", but I would like to get Lean to check for me that the sum of 4 numbers that are all either 0 or 1 can be divisible by 8 iff each of the numbers is 0.

I would prefer a solution that "teaches" me how to work with decidable. Something along the lines of "oh, you have to write this, to get a decidable instance on all props of this form...", ideally!

Thanks!

import data.zmod.basic

lemma zmod.sq_mod_eight_sum (a b c d : zmod 8)
  (h : a + b + c + d = 0) (se : ({a, b, c, d} : set (zmod 8))  {0, 1}) :
  a = 0  b = 0  c = 0  d = 0 :=
by dec_trivial!  --fails, since it does not have a decidable instance:
failed to synthesize type class instance for
 decidable
    ( (a b c d : zmod 8), a + b + c + d = 0  {a, b, c, d}  {0, 1}  a = 0  b = 0  c = 0  d = 0)

Yakov Pechersky (May 13 2021 at 15:39):

norm_fin and norm_num should help here, or they should be taught to understand zmod

Alex J. Best (May 13 2021 at 15:40):

Like you say, you just have to change set to something more decidable, in this case finset works. I'm not sure I can teach anything other than that finite sets are inherently more decidable than infinite!
You can see the instance used via

#check (by apply_instance : decidable ((({0} : finset (zmod 8))  {0}))

the analogous thing for set isn't found, however I think it is checking membership that makes the difference, compare

#check (by apply_instance : decidable (0  ({1,0} : finset (zmod 8))))

#check (by apply_instance : decidable (0  ({1,0} : set (zmod 8))))

curiously the second version works for singletons though

#check (by apply_instance : decidable (0  ({1} : set (zmod 8))))

Damiano Testa (May 13 2021 at 15:41):

Yakov, by norm_num says failed to simplify. norm_fin might require an import that I do not have...

Damiano Testa (May 13 2021 at 15:42):

Alex, thanks! This is already good! I will try to produce a finset instead of a set, then (or possibly try to stick with singletons :wink: ).

Yakov Pechersky (May 13 2021 at 15:44):

Here's what I mean

import data.zmod.basic
import tactic.norm_fin

lemma zmod.sq_mod_eight_sum (a b c d : fin 8)
  (h : a + b + c + d = 0) (se : ({a, b, c, d} : finset (fin 8))  {0, 1}) :
  a = 0  b = 0  c = 0  d = 0 :=
begin
  have :  (x : fin 8), x  ({a, b, c, d} : finset (fin 8))   x = 0  x = 1,
  { intros x hx,
    simpa using se hx },
  have ha := this a,
  have hb := this b,
  have hc := this c,
  have hd := this d,
  simp only [true_or, eq_self_iff_true, forall_true_left, or_true, finset.mem_insert,
    finset.mem_singleton] at ha hb hc hd,
  rcases ha with rfl|rfl;
  rcases hb with rfl|rfl;
  rcases hc with rfl|rfl;
  rcases hd with rfl|rfl,
  { simp }, -- the first goal is all zeros
  any_goals {
    contrapose! h,
    norm_num  } -- norm_num can figure out
end

Damiano Testa (May 13 2021 at 15:48):

Yakov, thanks a lot! I will take a close look at your solution, although it feels a little long, given what it is trying to prove!

Alternatively,

lemma zmod.sq_mod_eight_sum (a b c d : zmod 8)
  (h : a + b + c + d = 0) (se : ({a, b, c, d} : finset (zmod 8))  {0, 1}) :
  a = 0  b = 0  c = 0  d = 0 :=
by dec_trivial!

actually works, but is a little slow, I think!

Damiano Testa (May 13 2021 at 15:54):

Yakov, thanks a lot! I looked at your code and I understand better what is going on.

I have a follow up question: you used fin 8 instead of zmod 8 to be able to use norm_fin? (I had never seen norm_fin before.)

Johan Commelin (May 13 2021 at 16:25):

@Damiano Testa My guess is that dec_trivial! has to loop through (zmod 8)^4.

Johan Commelin (May 13 2021 at 16:26):

If you phrase it as a b c d : nat and add assumptions a <= 1 etc..., then there are only 2 ^ 4 options. That should be reasonably fast.

Johan Commelin (May 13 2021 at 16:26):

And from the nat-version to the zmod 8 version shouldn't be too much work either.

Damiano Testa (May 13 2021 at 16:28):

I see, thanks for the suggestion, Johan! There is also a further issue is that this was (partially) minimized: I really care about a, b, c, d being squares modulo 8, so they can also be 4 [in which case, they all are either 0 or 4, of course]. Still, it might be more efficient to use a <= 4 (but not 2 or 3), than what I was trying.

Thanks a lot!

Mario Carneiro (May 13 2021 at 18:11):

If you use \forall a b c d \in [0, 1, 4] it will only go through 3^4 options

Yakov Pechersky (May 13 2021 at 18:17):

@Mario Carneiro should norm_fin be extended to work on zmod automatically?

Damiano Testa (May 13 2021 at 18:18):

Mario, thanks for the comment! I think that I got it to work in 12secs. Honestly, I do not know if this is fast or slow! :upside_down:

Yakov Pechersky (May 13 2021 at 18:20):

That's pretty slow. You could help it along to instead phrase the proof as something about the cardinality of finset zmod bit0 k less than bit0 k, where the finset is a subset of 0, 1, k

Mario Carneiro (May 13 2021 at 18:25):

Yakov Pechersky said:

Mario Carneiro should norm_fin be extended to work on zmod automatically?

Sure, but like norm_num it's not intended for quantified statements like this example

Mario Carneiro (May 13 2021 at 18:26):

Also you can solve for d to make it only 3^3 options

Damiano Testa (May 13 2021 at 18:34):

Ok, I can see how these suggestions will cut down the number of computations. I am happy that such case bashes are rare in the kind of arguments that I usually think about!


Last updated: Dec 20 2023 at 11:08 UTC