Zulip Chat Archive

Stream: mathlib4

Topic: FOL logic with unary predicates


Yury G. Kudryashov (May 25 2023 at 04:22):

Are there effective algorithms to prove statements in FOL if only one-variable predicates are involved? I tried to golf docs4#isPreconnected_closed_iff and after

  rw [IsPreconnected, compl_surjective.forall]
  refine forall_congr' fun u  compl_surjective.forall.trans <| forall_congr' fun v  ?_
  simp only [isOpen_compl_iff]
  refine forall_congr' fun hu  forall_congr' fun hv  ?_

I've got the goal

s  u  v  Set.Nonempty (s  u)  Set.Nonempty (s  v)  Set.Nonempty (s  (u  v)) 
    s  u  v  Set.Nonempty (s  u)  Set.Nonempty (s  v)  Set.Nonempty (s  (u  v))

This is a statement that is true for any three sets s, u, v. It would be nice to have a tactic that closes this goal automatically.

Yury G. Kudryashov (May 25 2023 at 04:25):

I guess, in this case one can reformulate each atom like s ⊆ u ∪ v as a statement about parts of the corresponding Venn diagram being (non)empty, then get a statement in propositional logic.

Mario Carneiro (May 25 2023 at 04:25):

there was a tactic along those lines

Yury G. Kudryashov (May 25 2023 at 04:26):

There was or there is?

Mario Carneiro (May 25 2023 at 04:26):

it was a zulip discussion

Mario Carneiro (May 25 2023 at 04:26):

I forget how far along it actually got, it did not land in mathlib

Mario Carneiro (May 25 2023 at 04:26):

the simple version is to introduce x, simp everything to propositional logic and call tauto

Yury G. Kudryashov (May 25 2023 at 04:27):

What do you mean by "introduce x"?

Mario Carneiro (May 25 2023 at 04:28):

well I guess your goal is more complicated because you have multiple existential quantifiers

Yury G. Kudryashov (May 25 2023 at 04:28):

  simp [subset_def, Set.Nonempty]
  tauto

Mario Carneiro (May 25 2023 at 04:28):

the version that was in the discussion only handled universal quantifiers IIRC

Mario Carneiro (May 25 2023 at 04:28):

for stuff like subset masquerading as implication

Yury G. Kudryashov (May 25 2023 at 04:29):

Leaves many goals like

case mp.inl.h.right.right
α : Type u
β : Type v
ι : Type ?u.23250
π : ι  Type ?u.23255
inst : TopologicalSpace α
s t u v s u v : Set α
hu : IsClosed u
hv : IsClosed v
em : (a : Prop)  Decidable a
h : ¬∀ (x : α), x  s  ¬x  u  ¬x  v
a⁴ :  (x : α), x  s  x  u  x  v
x¹ : α
a³ : x¹  s
a² : x¹  u
x : α
a¹ : x  s
a : x  v
 x¹  v

Yury G. Kudryashov (May 25 2023 at 04:29):

(deleted)

Mario Carneiro (May 25 2023 at 04:31):

yeah I think we need a FOL tactic to prove this

Mario Carneiro (May 25 2023 at 04:31):

if you instantiate the quantifiers manually it can probably be done with the existing tools

Yury G. Kudryashov (May 25 2023 at 04:34):

What means instantiate the quantifiers manually?

Mario Carneiro (May 25 2023 at 04:35):

have := a⁴ _ a¹; have := a⁴ _ a³; tauto

Mario Carneiro (May 25 2023 at 04:35):

something like that

Yury G. Kudryashov (May 25 2023 at 04:35):

(a) my goal is to avoid intervention; (b) those a^k only appear after the call to tauto.

Mario Carneiro (May 25 2023 at 04:36):

(a) yes I'm aware

Mario Carneiro (May 25 2023 at 04:36):

the tactic doesn't exist

Mario Carneiro (May 25 2023 at 04:36):

at least not until the likes of duper make it to mathlib

Yury G. Kudryashov (May 25 2023 at 04:36):

What is duper?

Yury G. Kudryashov (May 25 2023 at 04:37):

Should I open a github issue?

Mario Carneiro (May 25 2023 at 04:37):

https://github.com/leanprover-community/duper, WIP superposition prover in lean 4

Mario Carneiro (May 25 2023 at 04:38):

For FOL proving? This is a long standing issue, we've known about it since the beginning of lean 3

Yury G. Kudryashov (May 25 2023 at 04:38):

No README... Probably, a clear sign of "WIP"

Mario Carneiro (May 25 2023 at 04:39):

making a good FOL prover is really challenging, especially when you mix it with all the higher order stuff in lean

Yury G. Kudryashov (May 25 2023 at 04:40):

Do I understand correctly that FOL with unary predicates is doable, FOL with binary predicates is undecidable? Is it undecidable in practice or there is an algorithm that works for reasonably sized formulas provided that they're true?

Mario Carneiro (May 25 2023 at 04:41):

It's not undecidable in practice, but it is heuristic

Mario Carneiro (May 25 2023 at 04:41):

The success rate depends quite strongly on the complexity of the goal

Yury G. Kudryashov (May 25 2023 at 04:42):

BTW, are there any prover-independent solutions to this? Like an external tool or a C/C++ library that can take an input formula and give you a proof in some machine-readable format?

Mario Carneiro (May 25 2023 at 04:42):

Z3 (leo's project before lean) is an SMT solver (aka FOL plus theories like linear arithmetic)

Yury G. Kudryashov (May 25 2023 at 04:43):

Can we somehow call it (or another similar tool) from Lean 4?

Mario Carneiro (May 25 2023 at 04:43):

there are other SMT solvers as well like vampire (which had an open PR to mathlib for a long time)

Mario Carneiro (May 25 2023 at 04:44):

the other problem with calling such tools is that you often don't get a proof back, just an assertion "it's true"

Mario Carneiro (May 25 2023 at 04:44):

or at least not something which can be externally checked, much less reconstructed into a lean proof

Mario Carneiro (May 25 2023 at 04:45):

many of these properties disqualify them from being used in mathlib proofs

Yury G. Kudryashov (May 25 2023 at 04:46):

Of course, "it's true" is not enough.

Mario Carneiro (May 25 2023 at 04:46):

As for unary predicates... it's plausible to me that this fragment is decidable (at least, assuming the term language isn't too fancy), but I assume you want to include equality, and that's a binary predicate

Mario Carneiro (May 25 2023 at 04:46):

I'm not sure how useful that fragment is in practice

Yury G. Kudryashov (May 25 2023 at 04:46):

In this example I don't need equality.

Mario Carneiro (May 25 2023 at 04:47):

you are using a binary predicate though (actually, probably a 4-ary predicate since lean has implicits everywhere) so writing a tactic that knows what to ignore is quite a tricky part of this goal

Mario Carneiro (May 25 2023 at 04:48):

I think it would be more useful to just have a general FOL instantiation tactic rather than a decision procedure for unary predicate FOL

Yury G. Kudryashov (May 25 2023 at 04:49):

OK, I'll just leave the proof we had.

Mario Carneiro (May 25 2023 at 04:49):

I mean, in this case you can just instantiate all quantifiers at all ground terms and get a proof by propositional logic

Yury G. Kudryashov (May 25 2023 at 04:50):

There are many statements in Topology/Connected that are repeated for open and closed sets

Yury G. Kudryashov (May 25 2023 at 04:51):

And in most cases one can go from one statement to another by something I wrote in the first few lines: replace all open sets by their complements which are closed.

Mario Carneiro (May 25 2023 at 04:51):

the fact that your theorem is not quantified over u and v makes it a lot less obvious to me

Yury G. Kudryashov (May 25 2023 at 04:52):

It is quantified. The first 2 lines get rid of that.

Mario Carneiro (May 25 2023 at 04:53):

I mean that while

(\forall u v, s  u  v  Set.Nonempty (s  u)  Set.Nonempty (s  v)  Set.Nonempty (s  (u  v))) 
(\forall u v, s  u  v  Set.Nonempty (s  u)  Set.Nonempty (s  v)  Set.Nonempty (s  (u  v)))

looks obviously true to me,

(s  u  v  Set.Nonempty (s  u)  Set.Nonempty (s  v)  Set.Nonempty (s  (u  v))) 
(s  u  v  Set.Nonempty (s  u)  Set.Nonempty (s  v)  Set.Nonempty (s  (u  v)))

looks a lot harder and possibly false

Mario Carneiro (May 25 2023 at 04:54):

If you were to keep the quantifiers and substitute u |-> uᶜ and v |-> vᶜ then simp could probably do this proof

Yury G. Kudryashov (May 25 2023 at 04:55):

Let me try

Yury G. Kudryashov (May 25 2023 at 04:56):

  rw [IsPreconnected, compl_surjective.forall]
  refine forall_congr' fun u  compl_surjective.forall.trans ?_
  revert u
  simp [subset_def, Set.Nonempty]

fails

Mario Carneiro (May 25 2023 at 04:56):

what's the goal?

Mario Carneiro (May 25 2023 at 04:56):

you don't need to unfold subset_def or Set.Nonempty for this proof

Yury G. Kudryashov (May 25 2023 at 04:56):

  (u : Set α),
    ( (x : Set α),
        IsClosed u 
          IsClosed x 
            ( (x_1 : α), x_1  s  ¬x_1  u  ¬x_1  x) 
               (x_1 : α), x_1  s  ¬x_1  u   (x_2 : α), x_2  s  ¬x_2  x   x_3, x_3  s  ¬x_3  u  ¬x_3  x) 
       (t' : Set α),
        IsClosed u 
          IsClosed t' 
            ( (x : α), x  s  x  u  x  t') 
               (x : α), x  s  x  u   (x : α), x  s  x  t'   x, x  s  x  u  x  t'

Mario Carneiro (May 25 2023 at 04:57):

I guess I don't understand what the original goal was and how you want to prove it

Yury G. Kudryashov (May 25 2023 at 04:58):

Here is the original proof from mathlib4:

  by
      rintro h t t' ht ht' htt' x, xs, xt y, ys, yt'
      rw [ not_disjoint_iff_nonempty_inter,  subset_compl_iff_disjoint_right, compl_inter]
      intro h'
      have xt' : x  t' := (h' xs).resolve_left (absurd xt)
      have yt : y  t := (h' ys).resolve_right (absurd yt')
      have := h _ _ ht.isOpen_compl ht'.isOpen_compl h' y, ys, yt x, xs, xt'
      rw [ compl_union] at this
      exact this.ne_empty htt'.disjoint_compl_right.inter_eq,
    by
      rintro h u v hu hv huv x, xs, xu y, ys, yv
      rw [ not_disjoint_iff_nonempty_inter,  subset_compl_iff_disjoint_right, compl_inter]
      intro h'
      have xv : x  v := (h' xs).elim (absurd xu) id
      have yu : y  u := (h' ys).elim id (absurd yv)
      have := h _ _ hu.isClosed_compl hv.isClosed_compl h' y, ys, yu x, xs, xv
      rw [ compl_union] at this
      exact this.ne_empty huv.disjoint_compl_right.inter_eq

Mario Carneiro (May 25 2023 at 04:59):

ah yeah that can be golfed

Mario Carneiro (May 25 2023 at 04:59):

and your replacement?

Yury G. Kudryashov (May 25 2023 at 04:59):

The problem is that while the formulas are equivalent (in FOL, after the cleanup I made), it is not "obvious": the terms in the implications do not correspond to each other.

Yury G. Kudryashov (May 25 2023 at 05:01):

The replacement I tried to write starts with

  rw [IsPreconnected, compl_surjective.forall]
  refine forall_congr' fun u  compl_surjective.forall.trans ?_
  simp only [isOpen_compl_iff]

and leaves a goal that is true in FOL.

Yury G. Kudryashov (May 25 2023 at 05:01):

(at least if you unfold definitions of subset and nonempty)

Mario Carneiro (May 25 2023 at 05:01):

what happened to t and t'?

Mario Carneiro (May 25 2023 at 05:01):

from the original theorem

Yury G. Kudryashov (May 25 2023 at 05:02):

I used compl_surjective.forall.trans _ to unify sets in LHS and RHS.

Yury G. Kudryashov (May 25 2023 at 05:03):

As you can see, the original proof calls h with the complements of the available sets.

Yury G. Kudryashov (May 25 2023 at 05:18):

Anyway, this is a low priority question (at least, for me and now). Sorry for taking so much of your time.

Yury G. Kudryashov (May 25 2023 at 05:18):

I mean, there is no theorem I can't prove without it, it's only about hiding technical details of some proofs.

Mario Carneiro (May 25 2023 at 05:43):

Here's my golf of the proof:

  rw [IsPreconnected, compl_surjective.forall]
  let P u u' := s  u  u'  (s  u).Nonempty  (s  u').Nonempty  (s  (u  u')).Nonempty
  suffices  {u u'}, P u u'  P (u) (u') by
    refine forall_congr' fun u  compl_surjective.forall.trans ?_
    simp only [isOpen_compl_iff]
    constructor <;> exact fun H v hu hv  by simpa using this (H v hu hv)
  simp only [ not_disjoint_iff_nonempty_inter,  subset_compl_iff_disjoint_right, compl_inter,
    compl_compl] at *
  refine fun h huv hu hv huv'  h huv' ?_ ?_ huv
  · exact fun h'  hv fun x hx  (huv' hx).resolve_left (h' hx)
  · exact fun h'  hu fun x hx  (huv' hx).resolve_right (h' hx)

Mario Carneiro (May 25 2023 at 05:46):

it could be golfed a bit more with the lemma a ⊆ b ∪ c → a ⊆ bᶜ → a ⊆ c (i.e. resolve_left for subsets)

Yury G. Kudryashov (May 25 2023 at 06:22):

Thanks!


Last updated: Dec 20 2023 at 11:08 UTC