Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

feat(data/[fin]set): add some more basic properties of (finite) sets#905

Closed
fpvandoorn wants to merge 1 commit intoleanprover-community:masterfrom
fpvandoorn:pr3
Closed

feat(data/[fin]set): add some more basic properties of (finite) sets#905
fpvandoorn wants to merge 1 commit intoleanprover-community:masterfrom
fpvandoorn:pr3

Conversation

@fpvandoorn
Copy link
Copy Markdown
Member

Part 2: (fin)sets

TO CONTRIBUTORS:

Make sure you have:

  • reviewed and applied the coding style: coding, naming
  • make sure definitions and lemmas are put in the right files
  • make sure definitions and lemmas are not redundant

If this PR is related to a discussion on Zulip, please include a link in the discussion.

For reviewers: code review check list

@fpvandoorn fpvandoorn requested a review from a team as a code owner April 8, 2019 19:07
@[simp] lemma coe_sdiff (s₁ s₂ : finset α) : ↑(s₁ \ s₂) = (↑s₁ \ ↑s₂ : set α) :=
set.ext $ λ _, mem_sdiff

lemma to_set_sdiff (s t : finset α) : (s \ t).to_set = s.to_set \ t.to_set :=
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a simp-lemma?

Copy link
Copy Markdown
Member Author

@fpvandoorn fpvandoorn Apr 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About finset-simp lemmas: I don't see a simp lemma rewriting s.to_set to (↑s : set _) or the other way around, so I'm not sure what the "canonical form" of this function is. If it's ↑s, then this simp lemma is superfluous (I don't know if that is a problem at all).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@digama0 Is there a general mathlib preference here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've never heard of s.to_set before this (and I wrote it). It's definitely written ↑s everywhere.

lemma compl_empty_iff {s : set α} : -s = ∅ ↔ s = univ :=
by { split, intro h, rw [←compl_compl s, h, compl_empty], intro h, rw [h, compl_univ] }

lemma compl_univ_iff {s : set α} : -s = ∅ ↔ s = univ :=
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is identical to the previous one. Which is not what you intended... I guess

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

He probably meant -s = empty iff s = univ. I think both of these should be @[simp]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name suggests: -s = univ ↔ s = ∅

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, copy-paste without actually changing the statement. Yes, Johannes wrote the statement I had in mind.

lemma compl_univ_iff {s : set α} : -s = ∅ ↔ s = univ :=
by { split, intro h, rw [←compl_compl s, h, compl_empty], intro h, rw [h, compl_univ] }

lemma nonempty_compl {s : set α} : s ≠ univ ↔ nonempty (-s : set α) :=
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the name, I would expect the sides of the iff to be swapped.

set.range (@subtype.val _ p) = {x | p x} :=
by rw ← set.image_univ; simp [-set.image_univ, val_image]

lemma range_val (s : set α) : range (subtype.val : s → α) = s :=
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simp-lemma?

Copy link
Copy Markdown
Collaborator

@avigad avigad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR looks good, but I'd like a bit of discussion on the nonempty question, because it will come up a lot in proofs.


@[simp] lemma coe_empty : ↑(∅ : finset α) = (∅ : set α) := rfl

lemma coe_nonempty_iff_ne_empty (s : finset α) : nonempty (↑s : set α) ↔ s ≠ ∅ :=
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is a general question: should the library favor nonempty (↑s : set α) or s ≠ ∅? The library should be consistent about using one or the other to state theorems. The second seems more natural and useful to me. If we go with that, then this should be a simplifier rule. If we go the other way, we should probably simplify the second to the first.

Either way, this lemma should be named nonempty_iff_ne_empty or nonempty_coe_iff_ne_empty. With the current name, it will be very hard to find using tab completion.

@ChrisHughes24 @jcommelin @johoelzl I am curious to hear your thoughts on this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the second looks nicer. Otoh, nonempty is a class, which might allow the type class system to take care of some proof obligations.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second looks more natural, but is less useful in practice. I noticed that in my proofs I preferred the nonempty, because I can immediately extract an element from that with cases. But I'm ok with using s ≠ ∅ as default since that is mathematically more accepted.

I used this name to be consistent with set.coe_nonempty_iff_ne_empty in set.basic. I would personally also name it nonempty_iff_ne_empty.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ability to uses cases with nonempty is compelling to me, so I am happy to make that the canonical idiom if nobody objects. In that case, we should try (at least over time) to state theorems that way, and also in set.

But I really do think it is better to have the name start with nonempty, also for the one in set.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The general mathlib preference is for the s ≠ ∅ idiom, although I can see the advantage of an inductive predicate so that you can use cases directly. It's still not that much better since you have to case twice; the additional coercion in the middle makes it less desirable since that makes it internally more complicated. I agree that we should use ne_empty and nonempty consistently to mean s ≠ ∅ and nonempty s respectively, though.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I think nonempty s reads quite naturally. I can't imagine many mathematicians stumbling over that... (-;


@[simp] lemma diff_self {s : set α} : s \ s = ∅ := ext $ by simp

lemma mem_diff_singleton_empty {s : set α} {t : set (set α)} :
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need this? This is essentially just a combination of mem_diff and mem_singleton_iff.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know. I definitely wanted it for my specific use-case, since I needed it multiple (10?) times. But maybe mathlib is not the place for "combined" facts like this. I will remove it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you needed it 10 times, I think it's legit to keep it. In my eyes >80% of formalisation libraries consist of little lemmas that are "essentially just a combination"... (not being sarcastic).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest generalizing to s \in t \ {a} <-> s \in t /\ s != a, assuming the situation with ne_zero vs nonempty is resolved.

lemma finite.coe_to_finset {α} {s : set α} (h : finite s) : ↑h.to_finset = s :=
by { ext, apply mem_to_finset }

lemma exists_finset_of_finite {s : set α} (h : finite s) : ∃(s' : finset α), s'.to_set = s :=
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should use coercion instead of to_set

λ x xs y ys h, H _ _ (hp x xs y ys h)

/- Disjoint sets and pairwise disjoint collections of sets -/
lemma disjoint_of_subset {s t s' t' : set α} (hst : s ∩ t = ∅) (hs : s' ⊆ s) (ht : t' ⊆ t) :
Copy link
Copy Markdown
Member

@digama0 digama0 Apr 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is already a definition of disjoint (and pairwise disjoint) in data.set.lattice, which is preferred over this one. Could you move / merge these lemmas?

@fpvandoorn
Copy link
Copy Markdown
Member Author

Superseded by #948

@fpvandoorn fpvandoorn closed this Apr 18, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants