Zulip Chat Archive

Stream: general

Topic: intersections


Patrick Massot (Jul 03 2018 at 15:56):

Do we have a better way to do

example {α : Type*} (a b c : set α) : a  b  (a  c) = a  b  c :=
by ext x ; split ; finish

Patrick Massot (Jul 03 2018 at 15:56):

Of course I'm not asking for the magic sequence of rewrite, I want Lean to figure it out.

Sean Leather (Jul 04 2018 at 06:43):

It would be nice if there was. I run into something similar with conjunction (e.g. a ∧ b ∧ (a ∧ c) = a ∧ b ∧ c) all the time.

Simon Hudon (Jul 04 2018 at 07:00):

does cc help?

Patrick Massot (Jul 04 2018 at 08:50):

no

Patrick Massot (Jul 04 2018 at 13:05):

A related question is: can anyone bring https://leanprover.github.io/programming_in_lean/#09_Writing_Automation.html up to date with current Lean?

Reid Barton (Jul 04 2018 at 14:01):

@Sean Leather for a ∧ b ∧ (a ∧ c) ↔ a ∧ b ∧ c, tauto works.

Sean Leather (Jul 04 2018 at 14:03):

Yeah, that may be true for that example. But I've run into others where tauto didn't work.

Reid Barton (Jul 04 2018 at 14:04):

Yes, tauto is good at failing frustratingly close to the goal

Sean Leather (Jul 04 2018 at 14:04):

true:exclamation:

Simon Hudon (Jul 04 2018 at 15:04):

Yes, tauto is good at failing frustratingly close to the goal

Excellent, that's what I wrote it for

Simon Hudon (Jul 04 2018 at 15:05):

But seriously, any examples of what it can't handle?

Reid Barton (Jul 04 2018 at 15:17):

as alluded to above, example (p : Prop) : p ∧ true ↔ p := by tauto

Reid Barton (Jul 04 2018 at 15:17):

Somewhat less trivially, I often find it gets stuck needing to prove a = b when b = a is available as a hypothesis

Simon Hudon (Jul 04 2018 at 15:23):

The latter should be getting better. @Scott Morrison recently submitted a patch to consider the symmetry of relations in solve_by_elim which tauto uses.

Simon Hudon (Jul 04 2018 at 15:24):

As for the first, true is probably the culprit. That's an easy fix, I can submit a PR right away

Simon Hudon (Jul 04 2018 at 15:25):

While I'm at it, I'll also take care of false in the assumptions.

Simon Hudon (Jul 04 2018 at 15:39):

Done: https://github.com/leanprover/mathlib/pull/175

Patrick Massot (Jul 04 2018 at 15:41):

Simon, what is the relation between this tauto and https://leanprover.github.io/programming_in_lean/#09_Writing_Automation.html Would you be able to update the later?

Simon Hudon (Jul 04 2018 at 15:49):

I haven't looked closely but that should be doable.

Simon Hudon (Jul 04 2018 at 15:50):

I'll take a look

Simon Hudon (Jul 04 2018 at 15:54):

By the way, don't despair, I haven't forgotten your request for tutorials

Simon Hudon (Jul 04 2018 at 15:55):

I'm preparing a talk about Lean tactics that I'll give at the DeepSpec summer school. That should be the seed for a useful tutorial

Patrick Massot (Jul 04 2018 at 15:56):

Nice!

Simon Hudon (Jul 04 2018 at 15:56):

I think I'll present the transportable problem that @Kevin Buzzard brought in a few months ago

Kevin Buzzard (Jul 04 2018 at 16:22):

+1 from me -- as I've probably said 100 times, this is something which mathematicians do subconsciously.

Johan Commelin (Jul 04 2018 at 16:54):

(And that is subconsciously, with big fat capital letters :wink:)

Sean Leather (Jul 05 2018 at 06:09):

Reid:

Somewhat less trivially, I often find it gets stuck needing to prove a = b when b = a is available as a hypothesis

Same here! That's the main reason I gave up on using tauto.

Simon:

The latter should be getting better. Scott Morrison recently submitted a patch to consider the symmetry of relations in solve_by_elim which tauto uses.

Cool. I'll have to try it out again.

Simon Hudon (Jul 05 2018 at 06:30):

Also, Mario merged my PR today. The one thing tauto doesn't do well still is proving disjunction. I didn't want to do back tracking out of fear that it would get slow but maybe I should do it anyway

Patrick Massot (Jul 05 2018 at 15:37):

Here is what I can currently do on this topic:

variables {α : Type*} (a b c : set α) (x : α)

example : a  b  c = c  b  a :=
by simp_inter


example : a  b  a = a  b :=
by simp_inter

example : a  b  (a  c) = a  b  c :=
by simp_inter

example (x  a  b  c) : x  b :=
by simp_inter

example (x  a  b  c) : x  b  a :=
by simp_inter

example (h : x  a) (h' : x  b) (h'' : x  c) : x  b  a :=
by simp_inter

example : x  a   x  b   x  c  x  b  a :=
by simp_inter

Patrick Massot (Jul 05 2018 at 15:38):

This is based on the destruct_conjunctions tactic from PIL and then poor's man tactic writing

Patrick Massot (Jul 05 2018 at 15:38):

open tactic monad expr
/-- Recursively destructs all hypotheses that are conjunctions. From programming in Lean. -/
meta def destruct_conjunctions : tactic unit :=
repeat (do
  l  local_context,
  first $ l.map (λ h, do
    ht  infer_type h >>= whnf,
    match ht with
    | `(and %%a %%b) := do
      n  get_unused_name `h none,
      mk_mapp ``and.left [none, none, some h] >>= assertv n a,
      n  get_unused_name `h none,
      mk_mapp ``and.right [none, none, some h] >>= assertv n b,
      clear h
    | _ := failed
    end))

/-- Simplify proving intersection and conjunctions goals -/
meta def simp_inter : tactic unit :=
`[  destruct_conjunctions,
    try { ext } ; try { split } ; try { intros }; destruct_conjunctions,
    all_goals { repeat { split } ; assumption }]

Patrick Massot (Jul 05 2018 at 15:38):

Any cleaner and more general way to do this is welcome :wink:

Patrick Massot (Jul 05 2018 at 15:39):

Note that all examples below should really be solved by the general purpose come_on tactic.

Simon Hudon (Jul 05 2018 at 15:40):

Haha! Have you tried tauto since Mario merged my PR yesterday?

Patrick Massot (Jul 05 2018 at 15:49):

No. I thought you only changed stuff is true or false appears explicitly.

Patrick Massot (Jul 05 2018 at 15:49):

I'm upgrading

Simon Hudon (Jul 05 2018 at 15:51):

In your case, it should already work, you're right

Simon Hudon (Jul 05 2018 at 15:51):

but recently, there's been added support for symmetric relations and true and false appearing in formulas

Patrick Massot (Jul 05 2018 at 15:57):

tauto solves none of my examples

Patrick Massot (Jul 05 2018 at 15:57):

even with updated mathlib

Simon Hudon (Jul 05 2018 at 15:59):

and with ext; tauto?

Patrick Massot (Jul 05 2018 at 16:01):

no luck

Patrick Massot (Jul 05 2018 at 16:01):

you can try my examples, they depend on nothing else but mathlib

Simon Hudon (Jul 05 2018 at 16:06):

Ok got it

Simon Hudon (Jul 05 2018 at 16:06):

first import data.set.basic. That's where set extensionality is declared

Simon Hudon (Jul 05 2018 at 16:07):

Next:

example : a  b  c = c  b  a :=
by ext; dsimp; tauto


example : a  b  a = a  b :=
by ext; dsimp; tauto

example : a  b  (a  c) = a  b  c :=
by ext; dsimp; tauto

example (x  a  b  c) : x  b :=
by dsimp at *; tauto

example (x  a  b  c) : x  b  a :=
by dsimp at *; tauto

example (h : x  a) (h' : x  b) (h'' : x  c) : x  b  a :=
by dsimp at *; tauto

example : x  a   x  b   x  c  x  b  a :=
by dsimp at *; tauto

Simon Hudon (Jul 05 2018 at 16:07):

Unfortunately, you need to unfold set notation for tauto to work

Simon Hudon (Jul 05 2018 at 16:09):

And I'm not sure that adding dsimp to tauto would be a good idea.

Simon Hudon (Jul 05 2018 at 16:11):

What I could do is match on hypotheses and goal using definitional equality instead of pattern matching

Simon Hudon (Jul 05 2018 at 16:12):

Then the first proof would become:

by ext; tauto

I'm wondering if that would make auto slower. Maybe we could enable this feature with tauto!

Simon Hudon (Jul 05 2018 at 16:13):

(In French, that would sound like you're insulting someone, with the exclamation mark)

Simon Hudon (Jul 05 2018 at 16:27):

@Mario Carneiro I managed to add support for disjunction but it requires tactic.interactive to import logic.basic. I think the creation of tactic.cache would fix that situation. Should I submit that change in a separate PR? (separate from the traversable PR) If you need more time to review the traversable PR, I think that would be a good way to move forward

Patrick Massot (Jul 05 2018 at 17:04):

It does look like one could define

meta def come_one : tactic unit := `[try { ext ; dsimp at *; tauto}, try { dsimp at *; tauto}]

or something like this. It looks much better, thanks!

Simon Hudon (Jul 05 2018 at 17:07):

:) At your service

Simon Hudon (Jul 05 2018 at 17:08):

I would advise you to call it COME_ON. And you may want to add three exclamation marks, to communicate impatience ;-)

Simon Hudon (Jul 05 2018 at 17:09):

Consider:

meta def COME_ON (x y z : parse (tk "!")) : tactic unit := ...

Patrick Massot (Jul 05 2018 at 20:13):

The version is used currently is at https://github.com/PatrickMassot/lean-differential-topology/blob/master/src/tactic/easy.lean It passes both the tests I had for simp_inter and the tauto tests from mathlib.

Patrick Massot (Jul 05 2018 at 20:18):

Oh, it doesn't work in my real use case :(

Patrick Massot (Jul 05 2018 at 20:18):

failed to prove recursive application is decreasing, well founded relation

Reid Barton (Jul 05 2018 at 20:23):

Do you have a _let_match or similar in the tactic state?

Patrick Massot (Jul 05 2018 at 20:24):

I don't know what is similar to _let_match since I have no idea what it means

Patrick Massot (Jul 05 2018 at 20:26):

The full error is:

failed to prove recursive application is decreasing, well founded relation
  @has_well_founded.r
    (Σ' (a : @smooth_compatible X _inst_1 φ ψ) (a : @smooth_compatible X _inst_1 ψ φ),
       @smooth_compatible X _inst_1 ψ χ)
    (@has_well_founded_of_has_sizeof
       (Σ' (a : @smooth_compatible X _inst_1 φ ψ) (a : @smooth_compatible X _inst_1 ψ φ),
          @smooth_compatible X _inst_1 ψ χ)
       (default_has_sizeof
          (Σ' (a : @smooth_compatible X _inst_1 φ ψ) (a : @smooth_compatible X _inst_1 ψ φ),
             @smooth_compatible X _inst_1 ψ χ)))
Possible solutions:
  - Use 'using_well_founded' keyword in the end of your definition to specify tactics for synthesizing well founded relations and decreasing proofs.
  - The default decreasing tactic uses the 'assumption' tactic, thus hints (aka local proofs) can be provided using 'have'-expressions.
The nested exception contains the failure state for the decreasing tactic.
nested exception message:
invalid apply tactic, failed to unify
  0 < 0
with
  ?m_1 < ?m_1 + ?m_2
state:
X : Type,
_inst_1 : inhabited X,
φ ψ χ : chart X,
open_triple_intersection :
  (Σ' (a : smooth_compatible φ ψ) (a : smooth_compatible ψ φ), smooth_compatible ψ χ) 
  is_open (φ '' (φ.domain  ψ.domain  χ.domain)),
op_φ_ψ : is_open_intersection φ ψ,
smooth_φ_ψ : is_smooth_transition φ ψ,
op_ψ_φ : is_open_intersection ψ φ,
smooth_ψ_φ : is_smooth_transition ψ φ,
op_ψ_χ : is_open_intersection ψ χ,
smooth_ψ_χ : is_smooth_transition ψ χ,
x : X,
a : smooth_compatible φ ψ,
a : smooth_compatible ψ φ,
a : smooth_compatible ψ χ
 0 < 0

Patrick Massot (Jul 05 2018 at 20:28):

Replacing meta def easy : tactic unit := `[try { ext } , try { dsimp at * }, all_goals { tauto }] by meta def easy : tactic unit := `[try { ext } , try { dsimp }, all_goals { tauto }] make it work in this case but fail in others. Somehow the try is not enough to prevent the error.

Simon Hudon (Jul 05 2018 at 20:36):

Well-foundedness is only checked at the end of the proof I believe which means that it won't make individual tactics fail.

Simon Hudon (Jul 05 2018 at 20:37):

You may just need to add a have : _ < _, from _ expression to state and prove that some quantity decreases in your recursive function

Patrick Massot (Jul 05 2018 at 20:37):

I don't have any recursive function

Patrick Massot (Jul 05 2018 at 20:38):

I have no idea what Lean is talking about

Simon Hudon (Jul 05 2018 at 20:38):

Can you show the goal prior to calling the tactic? There might be a way of saying "I'm not trying to bring in the curse of recursion"

Patrick Massot (Jul 05 2018 at 20:39):

X : Type,
_inst_1 : inhabited X,
φ ψ χ : chart X,
open_triple_intersection :
  smooth_compatible φ ψ 
  smooth_compatible ψ φ  smooth_compatible ψ χ  is_open (φ '' (φ.domain  ψ.domain  χ.domain)),
op_φ_ψ : is_open_intersection φ ψ,
smooth_φ_ψ : is_smooth_transition φ ψ,
op_ψ_φ : is_open_intersection ψ φ,
smooth_ψ_φ : is_smooth_transition ψ φ,
op_ψ_χ : is_open_intersection ψ χ,
smooth_ψ_χ : is_smooth_transition ψ χ,
op : is_open (ψ '' (ψ.domain  φ.domain  χ.domain)),
this : ψ '' (ψ.domain  φ.domain  χ.domain)  ψ '' (ψ.domain  φ.domain),
op : is_open (transition ψ φ '' (ψ '' (ψ.domain  φ.domain  χ.domain))),
h :
  transition ψ φ '' (ψ '' (ψ.domain  φ.domain  χ.domain)) =
    φ '' (ψ.domain  φ.domain  χ.domain)
 ψ.domain  φ.domain  χ.domain = φ.domain  ψ.domain  χ.domain

Simon Hudon (Jul 05 2018 at 20:40):

Is the lemma that you're trying to prove open_triple_intersection? If so, try clear open_triple_intersection before calling the tactic.

Patrick Massot (Jul 05 2018 at 20:40):

Note that ext, dsimp, tauto works here, but I want a tactic which also works when you need to dsimp something from context

Patrick Massot (Jul 05 2018 at 20:41):

Indeed, this is what I'm proving

Patrick Massot (Jul 05 2018 at 20:41):

and clearing this works

Patrick Massot (Jul 05 2018 at 20:41):

WTF?

Patrick Massot (Jul 05 2018 at 20:42):

Is it because I have pattern matching?

Patrick Massot (Jul 05 2018 at 20:42):

https://github.com/PatrickMassot/lean-differential-topology/blob/master/src/manifold.lean#L185

Patrick Massot (Jul 05 2018 at 20:43):

Indeed

Patrick Massot (Jul 05 2018 at 20:43):

If I remove the matching and start with

  intros h h' h'',
  rcases h with op_φ_ψ, smooth_φ_ψ,
  rcases h' with op_ψ_φ, smooth_ψ_φ,
  rcases h'' with op_ψ_χ, smooth_ψ_χ,

Then easy works

Patrick Massot (Jul 05 2018 at 20:44):

Do you understand what happens?

Patrick Massot (Jul 05 2018 at 20:45):

@Mario Carneiro We really need a hybrid of intros and rcases that would allow writing intros ⟨op_φ_ψ, smooth_φ_ψ⟩ ⟨op_ψ_φ, smooth_ψ_φ⟩ ⟨op_ψ_χ, smooth_ψ_χ⟩

Patrick Massot (Jul 05 2018 at 20:45):

instead of the four lines of the previous code block

Simon Hudon (Jul 05 2018 at 20:46):

The situation is that pattern matching and recursion are rooted in the same machinery

Simon Hudon (Jul 05 2018 at 20:47):

When you pattern match, Lean gives you the opportunity to make a recursive call. It gives you more than you need and once you're done with the proof, it checks whether you introduced recursion / induction and makes sure that it's well-founded

Simon Hudon (Jul 05 2018 at 20:47):

Tactics don't see the difference between assumptions that are in fact a recursive call and the rest

Patrick Massot (Jul 05 2018 at 20:56):

Thanks

Patrick Massot (Jul 05 2018 at 20:56):

I'll forget about matching and patiently wait for rintros to land in mathlib.

Patrick Massot (Jul 05 2018 at 20:57):

And I'll go sleeping.

Simon Hudon (Jul 05 2018 at 21:06):

You could do something like clear_rec that you call after pattern matching

Mario Carneiro (Jul 06 2018 at 05:36):

I managed to add support for disjunction but it requires tactic.interactive to import logic.basic. I think the creation of tactic.cache would fix that situation. Should I submit that change in a separate PR? (separate from the traversable PR) If you need more time to review the traversable PR, I think that would be a good way to move forward

@Simon Hudon I think this is a good idea. Splitting up the different unrelated parts will make it easier to merge things

Simon Hudon (Jul 06 2018 at 05:39):

Nice, I hadn't thought of it that way but we'll kill two birds with one stone. I can pull a few more PRs from traversable

Simon Hudon (Jul 06 2018 at 05:48):

What's your opinion about using lemmas in tactics that require predicates to be decidable? Would you just let it fail if some predicate is not decidable or would you silently use prop_decidable?

Mario Carneiro (Jul 06 2018 at 05:52):

Depends on the use case. I think by_cases will fail, but adding prop_decidable as a local instance fixes this, so this seems sufficiently flexible

Simon Hudon (Jul 06 2018 at 05:59):

That's straightforward. With tauto, decidable constraints can come from a lot of different sources and become relevant without obvious reasons

Mario Carneiro (Jul 06 2018 at 06:10):

It would be nice if the tactic reports the decidability problem in the error, that way the user can decide what to do about it

Simon Hudon (Jul 06 2018 at 06:14):

That's true. Unfortunately, tauto can keep going for a while once it has failed to find a decidable instance

Simon Hudon (Jul 06 2018 at 06:21):

I'm thinking that tauto! could add prop_decidable as a local instance right from the start. Then when you're not sure why tauto failed, you can try that and move on.

Mario Carneiro (Jul 06 2018 at 07:38):

I'll forget about matching and patiently wait for rintros to land in mathlib.

Your wish is my command...

Simon Hudon (Jul 06 2018 at 07:40):

@Mario Carneiro Tag, you're it! https://github.com/leanprover/mathlib/pull/178

Patrick Massot (Jul 06 2018 at 07:42):

I love that! My next wish is you answer my Wednesday email :wink:

Patrick Massot (Jul 06 2018 at 07:42):

And I'm sure this rintro tactic will soon be all over the place.

Simon Hudon (Jul 06 2018 at 07:43):

What is this rintro thing?


Last updated: Dec 20 2023 at 11:08 UTC