(* This program is free software; you can redistribute it and/or      *)
(* modify it under the terms of the GNU Lesser General Public License *)
(* as published by the Free Software Foundation; either version 2.1   *)
(* of the License, or (at your option) any later version.             *)
(*                                                                    *)
(* This program is distributed in the hope that it will be useful,    *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of     *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      *)
(* GNU General Public License for more details.                       *)
(*                                                                    *)
(* You should have received a copy of the GNU Lesser General Public   *)
(* License along with this program; if not, write to the Free         *)
(* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *)
(* 02110-1301 USA                                                     *)
(** %\subsection*{ support :  counting\_elements.v }%*)
Set Implicit Arguments.
Unset Strict Implicit.
From Algebra Require Export Diff.
From Algebra Require Export Singleton.
Require Export has_n_elements.
From Algebra Require Export Union.
Require Export const.
(** - Once we have has_n_elements, it would seem to be easy to define has_at_least_n_elements and has_at_most_n_elements. But one has to take a little care. We could not just say, e.g. [  Definition has_at_least_n_elements := ] [    [n:nat;A:Setoid](EXT m:nat | (le n m) /\ (has_n_elements m A)).  ] since the set may be infinite, and then there is no such m to be found.  - But we may adapt the definition of has_n_elements slightly. It said that we can make a sequence [v] of length [n] with all elements distinct---[(distinct v)]; covering the whole set---[(seq_set v)='(full v)]. Now we just drop this last requirement so we only need to point out a sequence of $n$ different elements:  %\label{hasatleastnelements}% *)
Definition has_at_least_n_elements (n : Nat) (A : Setoid) :=
exists v : seq n A, distinct v.
(** - Note that, contrarily, we may not just drop the other requirement to obtain  [Definition has_at_most_n_elements_wrong := [n:nat;A:Setoid](EXT v:(seq n A) | (full A)='(seq_set v)).]  since this doesn't work out well for empty sets: it has at most n elements for any n, but with this definition we'd need to exhibit an n-length sequence, which we can't do for $n>0$.*)
Definition has_at_most_n_elements (n : Nat) (A : Setoid) :=
exists m : nat, m <= n /\ has_n_elements m A.
intros.
red in |- *.
red in H.
inversion_clear H.
rename x into Bsize.
inversion_clear H2.
exists Bsize.
split.
generalize (eq_ind _ (fun n => Bsize <= n) H _ H1).
auto.
apply has_n_elements_comp with Bsize B; auto with algebra.
Qed.
intros.
rewrite <- H1.
red in |- *.
red in H.
inversion_clear H.
rename x into Bseq.
exists (Map_to_equal_subsets H0 Bseq).
red in |- *; intros; intro; red in H2; (apply (H2 i j); auto with algebra).
simpl in |- *.
red in |- *.
apply Trans with (subtype_elt (Bseq i)); auto with algebra.
apply Trans with (subtype_elt (Bseq j)); auto with algebra.
apply Trans with (subtype_elt (Map_to_equal_subsets H0 Bseq i));
auto with algebra.
apply Trans with (subtype_elt (Map_to_equal_subsets H0 Bseq j));
auto with algebra.
Qed.
intros.
inversion_clear H.
exists x.
inversion_clear H0; auto.
Qed.
intros.
exists n.
split; auto with arith.
Qed.
intros.
red in |- *; red in H.
inversion_clear H.
exists (Map_embed x).
fold (distinct (Map_embed x)) in |- *.
fold (distinct x) in H0.
apply Map_embed_preserves_distinct; auto with algebra.
Qed.
intros.
apply subset_has_at_least_n_elements with B; auto with algebra.
apply has_n_elements_then_has_at_least_n_elements; auto with algebra.
Qed.
intros.
inversion H.
set (B' := seq_set (Map_embed x)) in *.
assert (has_n_elements n B').
red in |- *.
exists (seq_set_seq (Map_embed x)).
split.
unfold B' in |- *.
simpl in |- *.
red in |- *; simpl in |- *.
split; intro; auto.
clear H3.
unfold subtype_image_equal in |- *.
simpl in |- *.
destruct x0.
simpl in subtype_prf.
rename subtype_elt into a.
inversion_clear subtype_prf.
exists x0.
simpl in |- *.
auto.
red in |- *.
intros.
simpl in |- *.
unfold subtype_image_equal in |- *.
simpl in |- *.
intro; (apply (H2 i j); auto with algebra).
assert (exists a : A, in_part a B' /\ ~ in_part a C).
apply has_extra_element with m n; auto with algebra.
assert (included B' B).
red in |- *.
intros a Ha.
simpl in Ha.
inversion_clear Ha.
apply in_part_comp_l with (subtype_elt (x x0)); auto with algebra.
inversion_clear H4.
rename x0 into a.
exists a.
inversion_clear H6.
split; auto.
Qed.
intros.
unfold has_at_least_n_elements in H.
unfold has_at_most_n_elements in |- *.
induction n.
exists 0; split; auto.
red in |- *.
exists (empty_seq A).
split.
simpl in |- *.
red in |- *.
intro a; split; simpl in |- *; auto.
intros _.
apply False_ind; auto with algebra.
apply H.
exists (const_seq 1 a).
intros; intro.
auto with algebra.
red in |- *.
intros.
auto with algebra.
case
(classic
(exists v : seq (S n) A,
(forall i j : fin (S n), ~ i =' j in _ -> ~ v i =' v j in _))).
intro; exists (S n).
split; auto.
red in |- *.
inversion_clear H0.
rename x into aa.
exists aa.
split; auto.
simpl in |- *; red in |- *; simpl in |- *.
intro a; split; auto; intros _.
apply NNPP; intro; apply H.
exists (a;; aa).
red in |- *.
destruct i; destruct j.
destruct index as [| n0];
[ destruct index0 as [| n0] | destruct index0 as [| n1] ].
simpl in |- *.
intuition.
simpl in |- *.
intros _.
intro; apply H0.
exists (Build_finiteT (lt_S_n n0 (S n) in_range_prf0)); auto with algebra.
simpl in |- *.
intros _.
intro; apply H0.
exists (Build_finiteT (lt_S_n n0 (S n) in_range_prf)).
apply Sym; auto with algebra.
simpl in |- *.
intro.
apply
(H1 (Build_finiteT (lt_S_n n0 (S n) in_range_prf))
(Build_finiteT (lt_S_n n1 (S n) in_range_prf0)));
auto with algebra.
intro.
generalize (IHn H0); intro p; inversion_clear p.
exists x.
inversion_clear H1; split; auto.
Qed.

Lemma has_n_elements_by_at_least_at_most :
forall (A : Setoid) (n : Nat),
has_at_least_n_elements n A ->
has_at_most_n_elements n A -> has_n_elements n A.