Stream: General

Topic: incorrect counterexamples?


view this post on Zulip Jared green (Aug 21 2024 at 17:18):

what do i do when quickcheck gives empty sets for predicates, as in

theorem any_filter_imp:  "(∀x. ¬s x ⟹ ¬t x) ⟹  list_ex t (filter s l) =  list_ex (λx. s x) l"
Auto Quickcheck found a counterexample:
  s = {a⇩1}
  t = {}
  x = a⇩1
  l = [a⇩1]
Evaluated terms:
  list_ex t (filter s l) = False
  list_ex s l = True

view this post on Zulip Jared green (Aug 21 2024 at 17:19):

for context, i have proven the same thing in lean.

view this post on Zulip Jared green (Aug 21 2024 at 17:24):

the lean proof looks like this:

import Init.Data.List
import Init.PropLemmas
import Mathlib.Algebra.BigOperators.Group.List
import Mathlib.Data.List.Dedup
import Mathlib.Data.List.Pairwise
import Mathlib.Data.List.Join
import Mathlib.Data.List.Basic
import Mathlib.Data.List.Defs
import Mathlib.Data.List.Infix
import Mathlib.Data.List.Lattice
import Mathlib.Data.List.Lemmas
import Mathlib.Data.Bool.AllAny
import Mathlib.Data.Bool.Basic
import Mathlib.Logic.Basic
import Batteries.Data.List.Lemmas
open Classical
theorem any_filter_imp (s t : a -> Bool): ( x : a, ¬ (s x) -> ¬ (t x)) ->  l : List a,l.any t <-> (l.filter s).any t :=
  by
  intro hst l
  simp
  induction' l with hd tl ht
  simp
  cases' Classical.em (s hd) with hsh hnsh
  simp
  rw [hsh]
  simp
  rw [ht]
  simp at hnsh
  have hnt : ¬ t hd := by {
    apply hst
    simp
    exact hnsh
  }
  simp
  simp at hnt
  rw [hnt]
  simp
  rw [ht]

view this post on Zulip Mathias Fleury (Aug 21 2024 at 17:41):

First, your question: quickcheck gives you the values where the function holds, where {} means nothing

view this post on Zulip Mathias Fleury (Aug 21 2024 at 17:43):

Second, there are two typos in your Isabelle expression:

- ∀x. ¬s x ⟹ ¬t x needs to be either ∀x. ¬s x ⟶ ¬t x (a HOL expression) or ⋀x. ¬s x ⟹ ¬t x(a pure expression). Your version means (∀x. ¬s x) ⟹ ¬t x as you can see with the color of the x (green = bound vs blue = free)

view this post on Zulip Mathias Fleury (Aug 21 2024 at 17:47):

view this post on Zulip Jared green (Aug 21 2024 at 18:24):

the = took priority?

view this post on Zulip Mathias Fleury (Aug 21 2024 at 18:28):

correct

view this post on Zulip Mathias Fleury (Aug 21 2024 at 18:28):

(it is stupid, but this choice was made too long to be changed)

view this post on Zulip Jared green (Aug 21 2024 at 18:29):

it does make a sort of sense

view this post on Zulip Mathias Fleury (Aug 21 2024 at 18:42):

Sort of, but it gets annoying for things like:
my_fancy_function x = ∃x. P x

view this post on Zulip Mathias Fleury (Aug 21 2024 at 18:43):

Jared green said:

the = took priority?

actually no, sorry

view this post on Zulip Mathias Fleury (Aug 21 2024 at 18:44):

(this is a different issue)

view this post on Zulip Mathias Fleury (Aug 21 2024 at 18:44):

The ∀ binds more than ⟹ sort of

view this post on Zulip Mathias Fleury (Aug 21 2024 at 18:45):

Your issue is in list_ex (λx. s x) l (there is a typo compared to the lean version)

view this post on Zulip Jared green (Aug 21 2024 at 18:50):

i now have

theorem any_filter_imp:  "(∀x. ¬s x ⟶ ¬t x) ⟹ ((∃x ∈ (set (filter s l)). t x) = (∃x ∈ (set l). t x))"

no 'counterexample' here.

view this post on Zulip Jared green (Aug 21 2024 at 19:00):

and for another:

datatype 'a normalizable =
  Atom 'a
| And "'a normalizable" "'a normalizable"
| Or "'a normalizable" "'a normalizable"
| Not "'a normalizable"


definition coherent :: "(bool × 'a normalizable) list list list ⇒ bool" where
  "coherent n = ( (n = []) ∨ (list_all (λg. (list_all (λs. ¬(s = []) ∧ (distinct (map (λx. snd x) s))) g) ∨ (g = []) ) n))"

definition makeCoherent :: "(bool × 'a normalizable) list list list ⇒ (bool × 'a normalizable) list list list" where
  "makeCoherent n = map (λx. map remdups (filter (λy. (list_all2 (λa b. snd a = snd b ⟶ fst a = fst b) y y) ∧ ¬(y = [])) x)) n"

theorem coherency: "coherent (makeCoherent n)"

Auto Quickcheck found a counterexample:
n = [[[(True, Atom a⇩1), (False, Atom a⇩1)]]]

the lean code looks like this:

variable {α : Type}[h : DecidableEq α]
inductive normalizable α (pred : α -> Prop)
  where
  | atom : α -> (normalizable α pred)
  | And : (normalizable α pred) -> (normalizable α pred) -> normalizable α pred
  | Or : (normalizable α pred) -> (normalizable α pred) -> normalizable α pred
  | Not : normalizable α pred -> normalizable α pred
deriving DecidableEq

def coherent (n : List (List (List (Bool × normalizable α pred)))) : Prop :=
   g : List (List (Bool × normalizable α pred)), g  n ->
   s : List (Bool × normalizable α pred), s  g ->
  ( w : Bool × normalizable α pred, x : Bool × normalizable α pred, w  s  x  s ->
  w.snd == x.snd -> w.fst == x.fst)  s.Nodup

def makeCoherent (n : List (List (List (Bool × normalizable α pred)))) : List (List (List (Bool × normalizable α pred))) :=
  n.map
  (fun x => (x.filter
  (fun y => y.Pairwise
  (fun a b => a.snd = b.snd -> a.fst = b.fst))).map
  (fun y => y.dedup))

theorem coherency :  n : List (List (List (Bool × normalizable α pred))), coherent (makeCoherent n) :=
  by
  intro n g hg s hs
  unfold makeCoherent at hg
  obtain a, _, ha_transformed_to_g := List.mem_map.mp hg
  subst ha_transformed_to_g
  constructor
  intros w x hw heqw
  rw [List.mem_map] at hs
  obtain b, hb_in_filtered_a, hb_eq_s := hs
  subst hb_eq_s
  rw [List.mem_filter] at hb_in_filtered_a
  obtain hb_in_a, hb_pw := hb_in_filtered_a
  have hb_pairwise : b.Pairwise (fun c d => c.snd = d.snd  c.fst = d.fst) := by simpa using hb_pw
  have snd_eq : w.snd = x.snd := by simpa using heqw
  have hp :  c d, c  b  d  b  c.2 = d.2  c.1 = d.1 := by
    intro c d hc, hd
    refine List.Pairwise.forall_of_forall ?_ (by simp) hb_pairwise hc hd
    intro x y h1 h2
    exact (h1 (h2.symm)).symm
  obtain  hw_left, hw_right := hw
  simp
  apply hp
  constructor
  rw [ List.mem_dedup]
  exact hw_left
  rw [ List.mem_dedup]
  exact hw_right
  rw [beq_iff_eq] at heqw
  exact heqw
  simp [List.nodup_dedup] at hs
  obtain b, _, hb_eq_s := hs
  rw [ hb_eq_s]
  exact List.nodup_dedup b

view this post on Zulip Jared green (Aug 21 2024 at 19:32):

for that one the = does not take priority over the arrow

view this post on Zulip Mathias Fleury (Aug 21 2024 at 19:35):

At that point you should try to see where the issue comes from. You can ask quickcheck to evaluate the counterexample with

quickcheck[eval="makeCoherent n"]

This should help you find where the definitions are different

view this post on Zulip Mathias Fleury (Aug 21 2024 at 19:36):

nitpick is a bit nicer for that, because you put several terms:

  nitpick[eval="makeCoherent n""map (λx. map remdups (filter (λy. (list_all2 (λa b. snd a = snd b ⟶ fst a = fst b) y y) ∧ ¬(y = [])) x)) n"]

view this post on Zulip Mathias Fleury (Aug 21 2024 at 19:38):

Your list_all2 (λa b. snd a = snd b ⟶ fst a = fst b) y y looks suspicious because you are comparing the same elements each time, but I have no clue what you are trying to define here

view this post on Zulip Simon Roßkopf (Aug 21 2024 at 19:40):

I also think you misunderstood what list_all2 does. I think you need something like

Idea

or similar instead

view this post on Zulip Mathias Fleury (Aug 21 2024 at 19:40):

Damn Simon you were faster, but I wanted to put it in a spoiler environment

view this post on Zulip Yong Kiam (Aug 22 2024 at 05:36):

Mathias Fleury said:

The ∀ binds more than ⟹ sort of

I tried to introduce it like this once to someone and found that it bit me back

Perhaps it'd be better to say that ==> is meta-level so it's not possible to, e.g. have \forall ( ... ==> ...)


Last updated: Dec 21 2024 at 12:33 UTC