(**
This file is part of the Elfic library

Copyright (C) Boldo, Clément, Faissole, Martin, Mayero

This library 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 3 of the License, or (at your option) any later version.

This library 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
COPYING file for more details.
*)

(** Countable iterations of operators on subsets (definitions and properties).

  Subsets of type U are represented by functions of type U -> Prop.

  Most identities can be found on Wikipedia:
  https://en.wikipedia.org/wiki/List_of_set_identities_and_relations

  All or parts of this file could use results on BigOps from MathComp. *)

From Coq Require Import Classical FunctionalExtensionality FinFun.
From Coq Require Import Arith Lia Even.

Require Import countable_sets nat_compl.
Require Import Subset Subset_finite.


Section Def0.

Context {U : Type}. (* Universe. *)

Variable A B : nat -> U -> Prop. (* Subset sequences. *)

Definition mix : nat -> U -> Prop :=
  fun n => if even_odd_dec n then A (Nat.div2 n) else B (Nat.div2 n).

End Def0.


Section Seq_Def.

Context {U : Type}. (* Universe. *)

Variable C : U -> Prop.
Variable A B : nat -> U -> Prop. (* Subset sequences. *)
Variable phi : nat -> nat * nat.

(** Binary and unary predicates on sequences of subsets. *)

Definition incl_seq : Prop :=
  forall n, incl (A n) (B n).

Definition same_seq : Prop :=
  forall n, same (A n) (B n).

(* Warning: incr actually means nondecreasing. *)
Definition incr_seq : Prop :=
  forall n, incl (A n) (A (S n)).

(* Warning: decr actually means nonincreasing. *)
Definition decr_seq : Prop :=
  forall n, incl (A (S n)) (A n).

Definition disj_seq : Prop :=
  forall n1 n2, n1 < n2 -> disj (A n1) (A n2).

Definition disj_seq_alt : Prop :=
  forall n1 n2 x, A n1 x -> A n2 x -> n1 = n2.

(** Unary and binary operations on sequences of subsets. *)

Definition compl_seq : nat -> U -> Prop :=
  fun n => compl (A n).

Definition x_inter_seq : nat -> U -> Prop :=
  fun n => inter (A (fst (phi n))) (B (snd (phi n))).

(** Reduce operations on sequences of subsets. *)

Definition union_seq : U -> Prop :=
  fun x => exists n, A n x.

Definition inter_seq : U -> Prop :=
  fun x => forall n, A n x.

(** Properties of sequences of subsets. *)

Definition partition_seq : Prop :=
  C = union_seq /\ disj_seq.

End Seq_Def.


Ltac subset_seq_unfold :=
  unfold incl_seq, same_seq, incr_seq, decr_seq, disj_seq, disj_seq_alt,
    compl_seq, x_inter_seq, union_seq, inter_seq.

Ltac subset_seq_full_unfold :=
  subset_seq_unfold; subset_finite_full_unfold.

Ltac subset_seq_auto :=
  subset_seq_unfold; try tauto; try easy.

Ltac subset_seq_full_auto :=
  subset_seq_unfold; subset_finite_full_auto.


Section Seq_Facts.

Context {U : Type}. (* Universe. *)

(** Extensionality of sequences of subsets. *)

Lemma subset_seq_ext :
  forall (A B : nat -> U -> Prop),
    same_seq A B -> A = B.
Proof.
intros A B H.
apply functional_extensionality; intros n.
apply subset_ext, H.
Qed.

Lemma subset_seq_ext_equiv :
  forall (A B : nat -> U -> Prop),
    A = B <-> incl_seq A B /\ incl_seq B A.
Proof.
intros; split.
intros H; split; now rewrite H.
intros [H1 H2]; apply subset_seq_ext; split; [apply H1 | apply H2].
Qed.

(** Facts about predicates on sequences of subsets. *)

(** Equivalent definitions from _finite version. *)

Lemma incl_seq_equiv_def :
  forall (A B : nat -> U -> Prop),
    incl_seq A B <-> forall N, incl_finite A B N.
Proof.
intros A B; split; intros H; try easy.
intros n; apply (H (S n)); lia.
Qed.

Lemma same_seq_equiv_def :
  forall (A B : nat -> U -> Prop),
    same_seq A B <-> forall N, same_finite A B N.
Proof.
intros A B; split; intros H; try easy.
intros n; apply (H (S n)); lia.
Qed.

Lemma incr_seq_equiv_def :
  forall (A : nat -> U -> Prop),
    incr_seq A <-> forall N, incr_finite A N.
Proof.
intros A; split; intros H; try easy.
intros n; apply (H (S (S n))); lia.
Qed.

Lemma decr_seq_equiv_def :
  forall (A : nat -> U -> Prop),
    decr_seq A <-> forall N, decr_finite A N.
Proof.
intros A; split; intros H; try easy.
intros n; apply (H (S (S n))); lia.
Qed.

Lemma disj_seq_equiv_def :
  forall (A : nat -> U -> Prop),
    disj_seq A <-> forall N, disj_finite A N.
Proof.
intros A; split; intros H.
intros N n1 n2 _ _ Hn; now apply H.
intros n1 n2 Hn; apply (H (S n2)); lia.
Qed.

Lemma disj_seq_alt_equiv_def :
  forall (A : nat -> U -> Prop),
    disj_seq_alt A <-> forall N, disj_finite_alt A N.
Proof.
intros A; split; intros H.
intros N n1 n2 x _ _ Hx1 Hx2; now apply (H n1 n2 x).
intros n1 n2 x Hx1 Hx2;
    case (lt_eq_lt_dec n1 n2); [intros [Hn | Hn] | intros Hn]; try easy.
apply (H (S n2) n1 n2 x); now try lia.
apply (H (S n1) n1 n2 x); now try lia.
Qed.

(** incl_seq is an order binary relation. *)

Lemma incl_seq_refl :
  forall (A B : nat -> U -> Prop),
    same_seq A B -> incl_seq A B.
Proof.
intros A B; rewrite same_seq_equiv_def, incl_seq_equiv_def.
intros H N; now apply incl_finite_refl.
Qed.

Lemma incl_seq_antisym :
  forall (A B : nat -> U -> Prop),
    incl_seq A B -> incl_seq B A -> same_seq A B.
Proof.
intros A B H1 H2.
assert (HH : A = B -> same_seq A B).
  intros H'; now rewrite H'.
now apply HH, subset_seq_ext_equiv.
Qed.

Lemma incl_seq_trans :
  forall (A B C : nat -> U -> Prop),
    incl_seq A B -> incl_seq B C -> incl_seq A C.
Proof.
intros A B C H1 H2 n x Hx; now apply H2, H1.
Qed.

(** same_seq is an equivalence binary relation. *)

(* Useless?
Lemma same_seq_refl :
  forall (A : nat -> U -> Prop),
    same_seq A A.
Proof.
easy.
Qed.*)

Lemma same_seq_sym :
  forall (A B : nat -> U -> Prop),
    same_seq A B -> same_seq B A.
Proof.
intros A B H n; apply same_sym, (H n).
Qed.

Lemma same_seq_trans :
  forall (A B C : nat -> U -> Prop),
    same_seq A B -> same_seq B C -> same_seq A C.
Proof.
intros A B C H1 H2 n; apply same_trans with (B n).
apply (H1 n).
apply (H2 n).
Qed.

(** Facts about incr_seq and decr_seq. *)

Lemma incr_seq_le :
  forall (A : nat -> U -> Prop) n1 n2,
    incr_seq A -> n1 <= n2 -> incl (A n1) (A n2).
Proof.
intros; apply incr_finite_le with (N := S n2); try lia.
now rewrite incr_seq_equiv_def in H.
Qed.

Lemma decr_seq_le :
  forall (A : nat -> U -> Prop) n1 n2,
    decr_seq A -> n1 <= n2 -> incl (A n2) (A n1).
Proof.
intros; apply decr_finite_le with (N := S n2); try lia.
now rewrite decr_seq_equiv_def in H.
Qed.

Lemma incr_finite_seq :
  forall (A : nat -> U -> Prop) N,
    incr_finite A N <-> incr_seq (extend A N).
Proof.
intros A N; unfold extend; split.
(* *)
intros H n x Hx.
destruct (lt_dec n (S N)) as [Hn1 | Hn1];
    destruct (lt_dec (S n) (S N)) as [Hn2 | Hn2]; [ | | lia | easy].
apply H in Hx; [easy | lia].
assert (Hn3 : N = n) by lia; now rewrite Hn3.
(* *)
intros H n Hn x Hx; specialize (H n x); simpl in H.
destruct (lt_dec n (S N)) as [Hn1 | Hn1]; [ | lia];
    destruct (lt_dec (S n) (S N)) as [Hn2 | Hn2]; [ | lia].
now apply H.
Qed.

Lemma decr_finite_seq :
  forall (A : nat -> U -> Prop) N,
    decr_finite A N <-> decr_seq (extend A N).
Proof.
intros A N; unfold extend; split.
(* *)
intros H n x Hx.
destruct (lt_dec n (S N)) as [Hn1 | Hn1];
    destruct (lt_dec (S n) (S N)) as [Hn2 | Hn2]; [ | | lia | easy].
apply H; [lia | easy].
assert (Hn3 : n = N) by lia; now rewrite Hn3.
(* *)
intros H n Hn x Hx; specialize (H n x); simpl in H.
destruct (lt_dec n (S N)) as [Hn1 | Hn1]; [ | lia];
    destruct (lt_dec (S n) (S N)) as [Hn2 | Hn2]; [ | lia].
now apply H.
Qed.

Lemma union_finite_id :
  forall (A : nat -> U -> Prop),
    incr_seq A -> union_finite A = A.
Proof.
intros A H; apply subset_seq_ext; intros N; now rewrite incr_union_finite.
Qed.

Lemma union_finite_id_rev :
  forall (A : nat -> U -> Prop),
    union_finite A = A -> incr_seq A.
Proof.
intros A H n x Hx; rewrite <- H; exists n; split; [lia | easy].
Qed.

Lemma union_finite_id_equiv :
  forall (A : nat -> U -> Prop),
    incr_seq A <-> union_finite A = A.
Proof.
intros; split; [apply union_finite_id | apply union_finite_id_rev].
Qed.

Lemma inter_finite_id :
  forall (A : nat -> U -> Prop),
    decr_seq A -> inter_finite A = A.
Proof.
intros A H; apply subset_seq_ext; intros N; now rewrite decr_inter_finite.
Qed.

Lemma inter_finite_id_rev :
  forall (A : nat -> U -> Prop),
    inter_finite A = A -> decr_seq A.
Proof.
intros A H n x Hx; rewrite <- H in Hx; apply Hx; lia.
Qed.

Lemma inter_finite_id_equiv :
  forall (A : nat -> U -> Prop),
    decr_seq A <-> inter_finite A = A.
Proof.
intros; split; [apply inter_finite_id | apply inter_finite_id_rev].
Qed.

Lemma incr_seq_union_finite :
  forall (A : nat -> U -> Prop),
    incr_seq (union_finite A).
Proof.
intros A N x [n [Hn Hx]]; exists n; split; [lia | easy].
Qed.

Lemma decr_seq_inter_finite :
  forall (A : nat -> U -> Prop),
    decr_seq (inter_finite A).
Proof.
intros A N x Hx n Hn; apply Hx; lia.
Qed.

Lemma incr_seq_union_compat_l :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    incr_seq A -> incr_seq (fun n => union B (A n)).
Proof.
intros A B H n x [Hx | Hx]; [now left | right; now apply H].
Qed.

Lemma incr_seq_union_compat_r :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    incr_seq A -> incr_seq (fun n => union (A n) B).
Proof.
intros A B H n x [Hx | Hx]; [left; now apply H | now right].
Qed.

Lemma incr_seq_inter_compat_l :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    incr_seq A -> incr_seq (fun n => inter B (A n)).
Proof.
intros A B H n x [Hx1 Hx2]; split; [easy | now apply H].
Qed.

Lemma incr_seq_inter_compat_r :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    incr_seq A -> incr_seq (fun n => inter (A n) B).
Proof.
intros A B H n x [Hx1 Hx2]; split; [now apply H | easy].
Qed.

Lemma incr_seq_diff_compat_l :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    incr_seq A -> decr_seq (fun n => diff B (A n)).
Proof.
intros A B H n x [Hx1 Hx2]; split; [easy | intros Hx3; now apply Hx2, H].
Qed.

Lemma incr_seq_diff_compat_r :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    incr_seq A -> incr_seq (fun n => diff (A n) B).
Proof.
intros A B H n x [Hx1 Hx2]; split; [now apply H | easy].
Qed.

Lemma decr_seq_union_compat_l :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    decr_seq A -> decr_seq (fun n => union B (A n)).
Proof.
intros A B H n x [Hx | Hx]; [now left | right; now apply H].
Qed.

Lemma decr_seq_union_compat_r :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    decr_seq A -> decr_seq (fun n => union (A n) B).
Proof.
intros A B H n x [Hx | Hx]; [left; now apply H | now right].
Qed.

Lemma decr_seq_inter_compat_l :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    decr_seq A -> decr_seq (fun n => inter B (A n)).
Proof.
intros A B H n x [Hx1 Hx2]; split; [easy | now apply H].
Qed.

Lemma decr_seq_inter_compat_r :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    decr_seq A -> decr_seq (fun n => inter (A n) B).
Proof.
intros A B H n x [Hx1 Hx2]; split; [now apply H | easy].
Qed.

Lemma decr_seq_diff_compat_l :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    decr_seq A -> incr_seq (fun n => diff B (A n)).
Proof.
intros A B H n x [Hx1 Hx2]; split; [easy | intros Hx3; now apply Hx2, H].
Qed.

Lemma decr_seq_diff_compat_r :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    decr_seq A -> decr_seq (fun n => diff (A n) B).
Proof.
intros A B H n x [Hx1 Hx2]; split; [now apply H | easy].
Qed.

(** Facts about disj_seq and disj_seq_alt. *)

Lemma disj_seq_equiv :
  forall (A : nat -> U -> Prop),
    disj_seq_alt A <-> disj_seq A.
Proof.
intros A; rewrite disj_seq_alt_equiv_def, disj_seq_equiv_def; split; intros H N.
now rewrite <- disj_finite_equiv.
now rewrite disj_finite_equiv.
Qed.

Lemma disj_finite_seq :
  forall (A : nat -> U -> Prop) N,
    disj_finite A N <-> disj_seq (trunc emptyset A N).
Proof.
intros A N; unfold trunc; split.
(* *)
intros H n1 n2 Hn x Hx1 Hx2.
destruct (lt_dec n1 (S N)) as [Hn1 | Hn1];
    destruct (lt_dec n2 (S N)) as [Hn2 | Hn2]; try easy.
now apply (H n1 n2 Hn1 Hn2 Hn x).
(* *)
intros H n1 n2 Hn1 Hn2 Hn x Hx1 Hx2; specialize (H n1 n2 Hn x); simpl in H.
destruct (lt_dec n1 (S N)) as [Hn1' | Hn1'];
    destruct (lt_dec n2 (S N)) as [Hn2' | Hn2']; try easy.
now apply H.
Qed.

Lemma disj_seq_inter_l :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    disj_seq A -> disj_seq (fun n => inter B (A n)).
Proof.
intros A B H; rewrite disj_seq_equiv_def in H; rewrite disj_seq_equiv_def.
intros; now apply disj_finite_inter_l.
Qed.

Lemma disj_seq_inter_r :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    disj_seq A -> disj_seq (fun n => inter (A n) B).
Proof.
intros A B H; rewrite disj_seq_equiv_def in H; rewrite disj_seq_equiv_def.
intros; now apply disj_finite_inter_r.
Qed.

Lemma disj_seq_alt_x_inter_seq :
  forall (A B : nat -> U -> Prop) (phi : nat -> nat * nat),
    disj_seq_alt A -> disj_seq_alt B -> Bijective phi ->
    disj_seq_alt (x_inter_seq A B phi).
Proof.
intros A B phi HA HB [psi [Hphi _]] p1 p2 x [HAx1 HBx1] [HAx2 HBx2].
rewrite <- (Hphi p1), <- (Hphi p2); f_equal; apply injective_projections.
now apply (HA _ _ x).
now apply (HB _ _ x).
Qed.

(** Facts about operations on sequences of subsets. *)

(** Facts about compl_seq. *)

Lemma compl_seq_invol :
  forall (A : nat -> U -> Prop),
    compl_seq (compl_seq A) = A.
Proof.
intros; apply subset_seq_ext.
intros n x; subset_seq_full_auto.
Qed.

Lemma compl_seq_shift :
  forall (A : nat -> U -> Prop) N,
    compl_seq (shift A N) = shift (compl_seq A) N.
Proof.
intros; apply subset_seq_ext; subset_seq_auto.
Qed.

Lemma incl_compl_seq :
  forall (A B : nat -> U -> Prop),
    incl_seq A B -> incl_seq (compl_seq B) (compl_seq A).
Proof.
subset_seq_unfold; intros; now apply incl_compl, H.
Qed.

Lemma incl_compl_seq_equiv :
  forall (A B : nat -> U -> Prop),
    incl_seq A B <-> incl_seq (compl_seq B) (compl_seq A).
Proof.
intros; split.
apply incl_compl_seq.
rewrite <- (compl_seq_invol A) at 2; rewrite <- (compl_seq_invol B) at 2.
apply incl_compl_seq.
Qed.

Lemma same_compl_seq :
  forall (A B : nat -> U -> Prop),
    same_seq A B -> same_seq (compl_seq A) (compl_seq B).
Proof.
intros A B H n; apply same_compl, H.
Qed.

Lemma same_compl_seq_equiv :
  forall (A B : nat -> U -> Prop),
    same_seq A B <-> same_seq (compl_seq A) (compl_seq B).
Proof.
intros; split.
apply same_compl_seq.
rewrite <- (compl_seq_invol A) at 2; rewrite <- (compl_seq_invol B) at 2.
apply same_compl_seq.
Qed.

Lemma incr_compl_seq :
  forall (A : nat -> U -> Prop),
    incr_seq (compl_seq A) <-> decr_seq A.
Proof.
intros; subset_seq_full_unfold; split; intros H n x Hx; intuition.
specialize (H n x); apply imply_to_or in H; destruct H as [H | H]; try easy.
now apply NNPP.
Qed.

Lemma decr_compl_seq :
  forall (A : nat -> U -> Prop),
    decr_seq (compl_seq A) <-> incr_seq A.
Proof.
intros; now rewrite <- incr_compl_seq, compl_seq_invol.
Qed.

Lemma compl_seq_reg :
  forall (A B : nat -> U -> Prop),
    same_seq (compl_seq A) (compl_seq B) -> A = B.
Proof.
intros; now apply subset_seq_ext, same_compl_seq_equiv.
Qed.

(** Facts about x_inter_seq. *)

Lemma x_inter_seq_phi :
  forall (A B : nat -> U -> Prop) (phi1 phi2 : nat -> nat * nat),
    Bijective phi1 -> Bijective phi2 ->
    forall p1, exists p2,
      incl (x_inter_seq A B phi1 p1) (x_inter_seq A B phi2 p2).
Proof.
intros A B phi1 phi2 H1 [psi2 [_ H2]] p1.
exists (psi2 (phi1 p1)); intros x [Hx1 Hx2]; split; now rewrite H2.
Qed.

(** Facts about union_seq and inter_seq. *)

Lemma union_finite_seq :
  forall (A : nat -> U -> Prop) N,
    union_finite A N = union_seq (extend A N).
Proof.
intros A N; apply subset_ext; unfold extend; split.
(* *)
intros [n [Hn Hx]]; exists n.
now destruct (lt_dec n (S N)).
(* *)
intros [n Hx]; destruct (lt_dec n (S N)) as [Hn | Hn].
exists n; split; [lia | easy].
exists N; split; [lia | easy].
Qed.

Lemma union_finite_seq_alt :
  forall (A : nat -> U -> Prop) N,
    union_finite A N = union_seq (trunc emptyset A N).
Proof.
intros A N; apply subset_ext; unfold trunc; split.
intros [n [Hn1 Hx]]; exists n; now destruct (lt_dec n (S N)) as [Hn2 | Hn2].
intros [n Hx]; destruct (lt_dec n (S N)) as [Hn | Hn]; try easy.
exists n; split; [lia | easy].
Qed.

Lemma union_seq_finite :
  forall (A : nat -> U -> Prop),
    union_seq (union_finite A) = union_seq A.
Proof.
intros; apply subset_ext; split.
intros [N [n [_ Hx]]]; now exists n.
intros [n Hx]; exists (S n), n; split; [lia | easy].
Qed.

Lemma empty_union_seq :
  forall (A : nat -> U -> Prop),
    union_seq A = emptyset <-> forall n, A n = emptyset.
Proof.
intros A; rewrite <- empty_emptyset; split; intros H.
intros n; rewrite <- empty_emptyset; intros x Hx; apply (H x); now exists n.
intros x [n Hx]; specialize (H n); rewrite <- empty_emptyset in H; now apply (H x).
Qed.

Lemma union_seq_monot :
  forall (A B : nat -> U -> Prop),
    incl_seq A B ->
    incl (union_seq A) (union_seq B).
Proof.
intros A B H x [n Hx]; exists n; now apply H.
Qed.

Lemma union_seq_ub :
  forall (A : nat -> U -> Prop) n,
    incl (A n) (union_seq A).
Proof.
intros A n x Hx; now exists n.
Qed.

Lemma union_seq_full :
  forall (A : nat -> U -> Prop),
    (exists n, A n = fullset) ->
    union_seq A = fullset.
Proof.
intros A [n HAn].
apply subset_ext_equiv; split; try easy.
rewrite <- HAn; now apply union_seq_ub.
Qed.

Lemma union_seq_lub :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    (forall n, incl (A n) B) ->
    incl (union_seq A) B.
Proof.
intros A B H x [n Hx]; now apply (H n).
Qed.

Lemma incl_union_seq :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    incl (union_seq A) B ->
    forall n, incl (A n) B.
Proof.
intros A B H n x Hx; apply H; now exists n.
Qed.

Lemma union_seq_incl_compat :
  forall (A B : nat -> U -> Prop),
    (forall N, incl (union_finite A N) (union_finite B N)) ->
    incl (union_seq A) (union_seq B).
Proof.
intros A B H x [N Hx1]; specialize (H N x); destruct H as [n [Hn Hx2]].
apply (union_finite_ub _ N N); [lia | easy].
now apply (union_seq_ub _ n).
Qed.

Lemma union_seq_eq_compat :
  forall (A B : nat -> U -> Prop),
    (forall N, union_finite A N = union_finite B N) ->
    union_seq A = union_seq B.
Proof.
intros; apply subset_ext_equiv; split.
all: apply union_seq_incl_compat; intros N; now rewrite H.
Qed.

Lemma distrib_union_union_seq_l :
  forall (A : U -> Prop) (B : nat -> U -> Prop),
    union A (union_seq B) = union_seq (fun n => union A (B n)).
Proof.
intros A B; apply subset_ext; intros x; split.
intros [Hx | [n Hx]]; [exists 0; now left | exists n; now right].
intros [n [Hx | Hx]]; [now left | right; now exists n].
Qed.

Lemma distrib_union_union_seq_r :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    union (union_seq A) B = union_seq (fun n => union (A n) B).
Proof.
intros; rewrite union_comm, distrib_union_union_seq_l.
apply union_seq_eq_compat; intros.
rewrite <- distrib_union_union_finite_l, union_comm.
apply distrib_union_union_finite_r.
Qed.

Lemma distrib_inter_union_seq_l :
  forall (A : U -> Prop) (B : nat -> U -> Prop),
    inter A (union_seq B) = union_seq (fun n => inter A (B n)).
Proof.
intros A B; apply subset_ext; intros x; split.
intros [Hx1 [n Hx2]]; now exists n.
intros [n [Hx1 Hx2]]; split; [easy | now exists n].
Qed.

Lemma distrib_inter_union_seq_r :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    inter (union_seq A) B = union_seq (fun n => inter (A n) B).
Proof.
intros; rewrite inter_comm, distrib_inter_union_seq_l.
apply union_seq_eq_compat; intros.
rewrite <- distrib_inter_union_finite_l, inter_comm.
apply distrib_inter_union_finite_r.
Qed.

Lemma distrib_inter_union_seq :
  forall (A B : nat -> U -> Prop) (phi : nat -> nat * nat),
    Bijective phi ->
    inter (union_seq A) (union_seq B) =
    union_seq (x_inter_seq A B phi).
Proof.
intros A B phi [psi [_ Hphi]]; apply subset_ext; intros x; split.
intros [[n1 Hx1] [n2 Hx2]]; exists (psi (n1, n2)); split; now rewrite Hphi.
intros [n [HAx HBx]]; split.
now exists (fst (phi n)).
now exists (snd (phi n)).
Qed.

Lemma incr_union_seq_shift :
  forall (A : nat -> U -> Prop),
    incr_seq A -> forall N, union_seq (shift A N) = union_seq A.
Proof.
intros A H N; apply subset_ext; split; intros [n Hx].
now exists (N + n).
case (le_lt_dec N n); intros Hn.
exists n; apply (incr_seq_le _ n (N + n)); now try lia.
exists 0; apply (incr_seq_le _ n (N + 0)); now try lia.
Qed.

Lemma decr_union_seq_shift :
  forall (A : nat -> U -> Prop),
    decr_seq A -> forall N, union_seq (shift A N) = A N.
Proof.
intros A H N; apply subset_ext; split.
intros [n Hx]; apply (decr_seq_le _ N (N + n)); now try lia.
intros Hx; exists 0; now rewrite shift_0_r.
Qed.

Lemma disj_union_seq_l :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    disj (union_seq A) B <-> forall n, disj (A n) B.
Proof.
intros A B; split.
intros H n x Hx1 Hx2; apply (H x); [now exists n | easy].
intros H x [n Hx1] Hx2; now apply (H n x).
Qed.

Lemma disj_union_seq_r :
  forall (A : U -> Prop) (B : nat -> U -> Prop),
    disj A (union_seq B) <-> forall n, disj A (B n).
Proof.
intros; rewrite disj_sym, disj_union_seq_l; split;
    intros H n; rewrite disj_sym; now apply H.
Qed.

Lemma inter_finite_seq :
  forall (A : nat -> U -> Prop) N,
    inter_finite A N = inter_seq (extend A N).
Proof.
intros A N; apply subset_ext; unfold extend; split.
intros Hx n; destruct (lt_dec n (S N)) as [Hn | Hn]; apply Hx; lia.
intros Hx n Hn; specialize (Hx n); simpl in Hx.
now destruct (lt_dec n (S N)).
Qed.

Lemma inter_finite_seq_alt :
  forall (A : nat -> U -> Prop) N,
    inter_finite A N = inter_seq (trunc fullset A N).
Proof.
intros A N; apply subset_ext; unfold trunc; split.
intros Hx n; now destruct (lt_dec n (S N)) as [Hn | Hn]; [apply Hx | ].
intros Hx n Hn1; specialize (Hx n); simpl in Hx.
now destruct (lt_dec n (S N)).
Qed.

Lemma inter_seq_finite :
  forall (A : nat -> U -> Prop),
    inter_seq (inter_finite A) = inter_seq A.
Proof.
intros; apply subset_ext; split.
intros H n; apply (H (S n) n); lia.
intros H N n _; apply H.
Qed.

Lemma full_inter_seq :
  forall (A : nat -> U -> Prop),
    inter_seq A = fullset <-> forall n, A n = fullset.
Proof.
intros A; rewrite <- full_fullset; split; intros H.
intros n; rewrite <- full_fullset; intros x; now apply (H x).
intros x n; specialize (H n); rewrite <- full_fullset in H; now apply (H x).
Qed.

Lemma inter_seq_monot :
  forall (A B : nat -> U -> Prop),
    incl_seq A B ->
    incl (inter_seq A) (inter_seq B).
Proof.
intros A B H x Hx n; apply H, Hx.
Qed.

Lemma inter_seq_empty :
  forall (A : nat -> U -> Prop),
    (exists n, A n = emptyset) ->
    inter_seq A = emptyset.
Proof.
intros A [n HAn].
apply subset_ext_equiv; split; try easy.
now rewrite <- HAn.
Qed.

Lemma inter_seq_glb :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    (forall n, incl B (A n)) ->
    incl B (inter_seq A).
Proof.
intros A B H x Hx n; now apply H.
Qed.

Lemma incl_inter_seq :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    incl B (inter_seq A) ->
    forall n, incl B (A n).
Proof.
intros A B H n x Hx; now apply H.
Qed.

Lemma inter_seq_incl_compat :
  forall (A B : nat -> U -> Prop),
    (forall N, incl (inter_finite A N) (inter_finite B N)) ->
    incl (inter_seq A) (inter_seq B).
Proof.
intros A B H x Hx N; specialize (H N x).
apply (inter_finite_lb _ N); try lia.
apply H; intros n Hn; apply Hx.
Qed.

Lemma inter_seq_eq_compat :
  forall (A B : nat -> U -> Prop),
    (forall N, inter_finite A N = inter_finite B N) ->
    inter_seq A = inter_seq B.
Proof.
intros; apply subset_ext_equiv; split.
all: apply inter_seq_incl_compat; intros N; now rewrite H.
Qed.

Lemma distrib_union_inter_seq_l :
  forall (A : U -> Prop) (B : nat -> U -> Prop),
    union A (inter_seq B) = inter_seq (fun n => union A (B n)).
Proof.
intros A B; apply subset_ext; intros x; split.
intros [Hx | Hx] n; [now left | right; apply Hx].
intros Hx1; case (classic (A x)); intros Hx2.
now left.
right; intros n; now destruct (Hx1 n).
Qed.

Lemma distrib_union_inter_seq_r :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    union (inter_seq A) B = inter_seq (fun n => union (A n) B).
Proof.
intros; rewrite union_comm, distrib_union_inter_seq_l.
apply inter_seq_eq_compat; intros.
rewrite <- distrib_union_inter_finite_l, union_comm.
apply distrib_union_inter_finite_r.
Qed.

Lemma distrib_inter_inter_seq_l :
  forall (A : U -> Prop) (B : nat -> U -> Prop),
    inter A (inter_seq B) = inter_seq (fun n => inter A (B n)).
Proof.
intros A B; apply subset_ext; intros x; split.
intros [Hx1 Hx2] n; split; [easy | apply Hx2].
intros Hx; split; [apply (Hx 0) | intros n; apply (Hx n)].
Qed.

Lemma distrib_inter_inter_seq_r :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    inter (inter_seq A) B = inter_seq (fun n => inter (A n) B).
Proof.
intros; rewrite inter_comm, distrib_inter_inter_seq_l.
apply inter_seq_eq_compat; intros.
rewrite <- distrib_inter_inter_finite_l, inter_comm.
apply distrib_inter_inter_finite_r.
Qed.

(*
Lemma distrib_inter_seq_union_seq :
  forall (A : nat -> nat -> U -> Prop) (phi : R -> nat -> nat),
    Bijective_pow phi ->
    inter_seq (fun n => union_seq (fun m => A n m)) =
    union_any (fun (x : R) => inter_seq (fun n => A n (phi x n))).
Proof.
Aglopted.

Lemma distrib_union_seq_inter_seq :
  forall (A : nat -> nat -> U -> Prop) (phi : R -> nat -> nat),
    Bijective_pow phi ->
    union_seq (fun n => inter_seq (fun m => A n m)) =
    inter_any (fun (x : R) => union_seq (fun n => A n (phi x n))).
Proof.
Aglopted.
*)

Lemma incr_inter_seq_shift :
  forall (A : nat -> U -> Prop),
    incr_seq A -> forall N, inter_seq (shift A N) = A N.
Proof.
intros A H N; apply subset_ext; split; intros Hx.
rewrite <- (Nat.add_0_r N); apply (Hx 0).
intros n; apply (incr_seq_le _ N (N + n)); now try lia.
Qed.

Lemma decr_inter_seq_shift :
  forall (A : nat -> U -> Prop),
    decr_seq A -> forall N, inter_seq (shift A N) = inter_seq A.
Proof.
intros A H N; apply subset_ext; split; intros Hx n.
case (le_lt_dec N n); intros Hn.
replace n with (N + (n - N)); try lia; apply (Hx (n - N)).
apply (decr_seq_le _ n (N + 0)); [easy | lia | ]; apply (Hx 0).
apply (Hx (N + n)).
Qed.

Lemma incl_inter_union_seq :
  forall (A : nat -> U -> Prop),
    incl (inter_seq A) (union_seq A).
Proof.
intros A x Hx; exists 0; apply (Hx 0).
Qed.

(** De Morgan's laws. *)

Lemma compl_union_seq :
  forall (A : nat -> U -> Prop),
    compl (union_seq A) = inter_seq (compl_seq A).
Proof.
intros; apply subset_ext; split.
intros H n Hx; apply H; now exists n.
intros H [n Hx]; now apply (H n).
Qed.

Lemma compl_inter_seq :
  forall (A : nat -> U -> Prop),
    compl (inter_seq A) = union_seq (compl_seq A).
Proof.
intros; apply compl_reg; rewrite compl_union_seq.
now rewrite compl_invol, compl_seq_invol.
Qed.

Lemma compl_seq_union_seq :
  forall (A : nat -> U -> Prop)
      (f : (nat -> U -> Prop) -> nat -> nat -> U -> Prop),
    (forall (A : nat -> U -> Prop) N,
      compl_seq (f A N) = f (compl_seq A) N) ->
    compl_seq (fun n => union_seq (f A n)) =
      (fun n => inter_seq (f (compl_seq A) n)).
Proof.
intros A f Hf; apply subset_seq_ext; intros n x; unfold compl_seq.
now rewrite compl_union_seq, Hf.
Qed.

Lemma compl_seq_inter_seq :
  forall (A : nat -> U -> Prop)
      (f : (nat -> U -> Prop) -> nat -> nat -> U -> Prop),
    (forall (A : nat -> U -> Prop) N,
      compl_seq (f A N) = f (compl_seq A) N) ->
    compl_seq (fun n => inter_seq (f A n)) =
      (fun n => union_seq (f (compl_seq A) n)).
Proof.
intros A f Hf; apply subset_seq_ext; intros n x; unfold compl_seq.
now rewrite compl_inter_seq, Hf.
Qed.

(** ``Distributivity'' of diff. *)

Lemma diff_union_seq_l :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    diff (union_seq A) B = union_seq (fun n => diff (A n) B).
Proof.
intros; now rewrite diff_equiv_def_inter, distrib_inter_union_seq_r.
Qed.

Lemma diff_union_seq_r :
  forall (A : U -> Prop) (B : nat -> U -> Prop),
    diff A (union_seq B) = inter_seq (fun n => diff A (B n)).
Proof.
intros; now rewrite diff_equiv_def_inter, compl_union_seq, distrib_inter_inter_seq_l.
Qed.

Lemma diff_inter_seq_l :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    diff (inter_seq A) B = inter_seq (fun n => diff (A n) B).
Proof.
intros; now rewrite diff_equiv_def_inter, distrib_inter_inter_seq_r.
Qed.

Lemma diff_inter_seq_r :
  forall (A : U -> Prop) (B : nat -> U -> Prop),
    diff A (inter_seq B) = union_seq (fun n => diff A (B n)).
Proof.
intros; now rewrite diff_equiv_def_inter, compl_inter_seq, distrib_inter_union_seq_l.
Qed.

(** Facts about partition_seq. *)

Lemma partition_seq_inter_l :
  forall (A C : U -> Prop) (B : nat -> U -> Prop),
    partition_seq A B ->
    partition_seq (inter C A) (fun n => inter C (B n)).
Proof.
intros A C B [H1 H2]; split.
rewrite H1; apply distrib_inter_union_seq_l.
now apply disj_seq_inter_l.
Qed.

Lemma partition_seq_inter_r :
  forall (A C : U -> Prop) (B : nat -> U -> Prop),
    partition_seq A B ->
    partition_seq (inter A C) (fun n => inter (B n) C).
Proof.
intros A C B [H1 H2]; split.
rewrite H1; apply distrib_inter_union_seq_r.
now apply disj_seq_inter_r.
Qed.

Lemma partition_seq_inter :
  forall (A B : U -> Prop) (A' B' : nat -> U -> Prop) (phi : nat -> nat * nat),
    partition_seq A A' -> partition_seq B B' -> Bijective phi ->
    partition_seq (inter A B) (x_inter_seq A' B' phi).
Proof.
intros A B A' B' phi [HA1 HA2] [HB1 HB2] Hphi; split.
rewrite HA1, HB1; now apply distrib_inter_union_seq.
apply disj_seq_equiv, disj_seq_alt_x_inter_seq; now try apply disj_seq_equiv.
Qed.

End Seq_Facts.


Section Limit_Def.

Context {U : Type}. (* Universe. *)

Variable A : nat -> U -> Prop. (* Subset sequence. *)

Definition liminf : U -> Prop :=
  union_seq (fun n => inter_seq (shift A n)).

Definition limsup : U -> Prop :=
  inter_seq (fun n => union_seq (shift A n)).

(* Useful?
Definition ex_lim : Prop :=
  same liminf limsup.*)

Definition is_lim (B : U -> Prop) : Prop :=
  same B liminf /\ same B limsup.

End Limit_Def.


Ltac subset_lim_unfold :=
  unfold liminf, limsup.

Ltac subset_lim_full_unfold :=
  subset_lim_unfold; subset_seq_full_unfold.

Ltac subset_lim_auto :=
  subset_lim_unfold; try tauto; try easy.

Ltac subset_lim_full_auto :=
  subset_lim_unfold; subset_seq_full_auto.


Section Limit_Facts.

Context {U : Type}. (* Universe. *)

Lemma liminf_ext :
  forall (A B : nat -> U -> Prop),
    same_seq A B -> liminf A = liminf B.
Proof.
intros A B H; apply subset_seq_ext in H; now rewrite H.
Qed.

Lemma limsup_ext :
  forall (A B : nat -> U -> Prop),
    same_seq A B -> limsup A = limsup B.
Proof.
intros A B H; apply subset_seq_ext in H; now rewrite H.
Qed.

Lemma liminf_shift :
  forall (A : nat -> U -> Prop) N,
    liminf (shift A N) = liminf A.
Proof.
intros A N1; apply subset_ext; split; intros [N2 Hx].
rewrite shift_add in Hx; now exists (N1 + N2).
exists N2; intros n; rewrite shift_add, plus_comm.
specialize (Hx (N1 + n)); now rewrite shift_assoc in Hx.
Qed.

Lemma limsup_shift :
  forall (A : nat -> U -> Prop) N,
    limsup (shift A N) = limsup A.
Proof.
intros A N1; apply subset_ext; subset_lim_unfold; split; intros Hx N2.
specialize (Hx N2); destruct Hx as [n Hx];
    exists (N1 + n); now rewrite shift_assoc, plus_comm, <- shift_add.
specialize (Hx (N1 + N2)); now rewrite shift_add.
Qed.

Lemma incl_liminf_limsup :
  forall (A : nat -> U -> Prop),
    incl (liminf A) (limsup A).
Proof.
intros A x [n H] p; exists n.
unfold shift; rewrite plus_comm; apply H.
Qed.

Lemma compl_liminf :
  forall (A : nat -> U -> Prop),
    compl (liminf A) = limsup (compl_seq A).
Proof.
intros; subset_lim_unfold; rewrite compl_union_seq; f_equal.
apply compl_seq_inter_seq, compl_seq_shift.
Qed.

Lemma compl_limsup :
  forall (A : nat -> U -> Prop),
    compl (limsup A) = liminf (compl_seq A).
Proof.
intros; subset_lim_unfold; rewrite compl_inter_seq; f_equal.
apply compl_seq_union_seq, compl_seq_shift.
Qed.

Lemma is_lim_unique :
  forall (A : nat -> U -> Prop) (B1 B2 : U -> Prop),
    is_lim A B1 -> is_lim A B2 -> B1 = B2.
Proof.
intros A B1 B2 [H1 _] [H2 _]; apply same_sym in H2; apply subset_ext.
now apply same_trans with (liminf A).
Qed.

Lemma is_lim_ext :
  forall (A1 A2 : nat -> U -> Prop) (B1 B2 : U -> Prop),
    same_seq A1 A2 -> is_lim A1 B1 -> is_lim A2 B2 -> B1 = B2.
Proof.
intros A1 A2 B1 B2 HA H1 H2.
apply subset_seq_ext in HA; rewrite HA in H1; now apply (is_lim_unique A2).
Qed.

Lemma is_lim_shift :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    is_lim A B -> forall N, is_lim (shift A N) B.
Proof.
intros A B [H1 H2] N; split.
now rewrite liminf_shift.
now rewrite limsup_shift.
Qed.

Lemma is_lim_compl :
  forall (A : nat -> U -> Prop) (B : U -> Prop),
    is_lim (compl_seq A) (compl B) <-> is_lim A B.
Proof.
intros A B; unfold is_lim.
rewrite <- compl_liminf, <- compl_limsup.
now do 2 rewrite same_compl_equiv.
Qed.

Lemma lim_incr_seq :
  forall (A : nat -> U -> Prop),
    incr_seq A -> is_lim A (union_seq A).
Proof.
intros A H; do 2 split.
intros [n Hx]; exists n; intros p; apply (incr_seq_le A n); now try lia.
intros [n Hx]; exists n; rewrite <- (Nat.add_0_r n); apply (Hx 0).
intros [n Hx] N; exists n; apply (incr_seq_le A n); now try lia.
intros Hx; destruct (Hx 0) as [n Hx']; exists n; now rewrite <- (Nat.add_0_l n).
Qed.

Lemma lim_decr_seq :
  forall (A : nat -> U -> Prop),
    decr_seq A -> is_lim A (inter_seq A).
Proof.
intros A.
rewrite <- (compl_seq_invol A), decr_compl_seq, <- compl_union_seq, is_lim_compl.
apply lim_incr_seq.
Qed.

Lemma union_seq_lim :
  forall (A : nat -> U -> Prop),
    is_lim (union_finite A) (union_seq A).
Proof.
intros; rewrite <- union_seq_finite.
apply lim_incr_seq, incr_seq_union_finite.
Qed.

Lemma inter_seq_lim :
  forall (A : nat -> U -> Prop),
    is_lim (inter_finite A) (inter_seq A).
Proof.
intros; rewrite <- inter_seq_finite.
apply lim_decr_seq, decr_seq_inter_finite.
Qed.

Lemma liminf_equiv_def :
  forall (A : nat -> U -> Prop),
    is_lim (fun n => inter_seq (shift A n)) (liminf A).
Proof.
intros; apply lim_incr_seq; unfold shift; intros n x Hx p.
rewrite Nat.add_succ_comm; apply (Hx (S p)).
Qed.

Lemma limsup_equiv_def :
  forall (A : nat -> U -> Prop),
    is_lim (fun n => union_seq (shift A n)) (limsup A).
Proof.
intros; apply lim_decr_seq; unfold shift; intros n x [p Hx].
rewrite Nat.add_succ_comm in Hx; now exists (S p).
Qed.

End Limit_Facts.


Section FU_DU_Def.

Context {U : Type}. (* Universe. *)

Variable A : nat -> U -> Prop. (* Subset sequence. *)

(** FU = finite union.
 It makes any subset sequence a nondecreasing sequence,
 while keeping the partial unions. *)

Definition FU : nat -> U -> Prop := union_finite A.

(** DU = disjoint union.
 It makes any subset sequence a pairwise disjoint sequence,
 while keeping the partial unions. *)

Definition DU : nat -> U -> Prop :=
  fun N => match N with
           | 0 => A 0
           | S N => diff (A (S N)) (FU N) end.

End FU_DU_Def.


Section FU_Facts.

(** Properties of finite union. *)

Context {U : Type}. (* Universe. *)

Lemma FU_0 :
  forall (A : nat -> U -> Prop),
    FU A 0 = A 0.
Proof.
exact union_finite_0.
Qed.

Lemma FU_S :
  forall (A : nat -> U -> Prop) N,
    FU A (S N) = union (FU A N) (A (S N)).
Proof.
exact union_finite_S.
Qed.

Lemma FU_id :
  forall (A : nat -> U -> Prop),
    incr_seq A <-> FU A = A.
Proof.
exact union_finite_id_equiv.
Qed.

Lemma FU_lim :
  forall (A : nat -> U -> Prop),
    is_lim (FU A) (union_seq A).
Proof.
exact union_seq_lim.
Qed.

Lemma FU_incr_seq :
  forall (A : nat -> U -> Prop),
    incr_seq (FU A).
Proof.
exact incr_seq_union_finite.
Qed.

Lemma FU_union_finite :
  forall (A : nat -> U -> Prop) N,
    union_finite (FU A) N = union_finite A N.
Proof.
exact union_finite_idem.
Qed.

Lemma FU_union_seq :
  forall (A : nat -> U -> Prop),
    union_seq (FU A) = union_seq A.
Proof.
exact union_seq_finite.
Qed.

Lemma FU_disj_l :
  forall (A : nat -> U -> Prop) (B : U -> Prop) N,
    disj (FU A N) B <-> (forall n, n < S N -> disj (A n) B).
Proof.
exact disj_union_finite_l.
Qed.

Lemma FU_disj_r :
  forall (A : U -> Prop) (B : nat -> U -> Prop) N,
    disj A (union_finite B N) <-> (forall n, n < S N -> disj A (B n)).
Proof.
exact disj_union_finite_r.
Qed.

End FU_Facts.


Section DU_Facts.

(** Properties of disjoint union. *)

Context {U : Type}. (* Universe. *)

Lemma DU_incl_seq_l :
  forall (A : nat -> U -> Prop),
    incl_seq (DU A) A.
Proof.
intros A n x; destruct n; [easy | now intros [H _]].
Qed.

Lemma DU_union_finite_incl :
  forall (A : nat -> U -> Prop),
    incl_seq (union_finite (DU A)) (union_finite A).
Proof.
intros; rewrite incl_seq_equiv_def; intros N1 N2 HN2.
apply union_finite_monot; intros n Hn; apply DU_incl_seq_l.
Qed.

Lemma DU_union_finite_incl_rev :
  forall (A : nat -> U -> Prop),
    incl_seq (union_finite A) (union_finite (DU A)).
Proof.
assert (H : forall (A B : U -> Prop) x, A x \/ B x -> A x \/ B x /\ ~ A x)
    by (intros; tauto).
intros A N x; induction N; intros [n [Hn Hx]].
rewrite lt_1 in Hn; rewrite Hn in Hx; now rewrite union_finite_0.
rewrite union_finite_S.
destruct H
    with (A := union_finite A N)
         (B := A (S N)) (x := x) as [H' | H'].
  case (le_lt_eq_dec n (S N)); try lia; clear Hn; intros Hn.
  left; exists n; split; [lia | easy].
  right; now rewrite Hn in Hx.
left; now apply IHN.
now right.
Qed.

Lemma DU_union_finite :
  forall (A : nat -> U -> Prop),
    union_finite (DU A) = union_finite A.
Proof.
intros; apply subset_seq_ext_equiv; split.
apply DU_union_finite_incl.
apply DU_union_finite_incl_rev.
Qed.

Lemma DU_equiv_def :
  forall (A : nat -> U -> Prop) N,
    DU A (S N) = diff (A (S N)) (union_finite (DU A) N).
Proof.
intros; now rewrite DU_union_finite.
Qed.

Lemma DU_union_seq :
  forall (A : nat -> U -> Prop),
    union_seq (DU A) = union_seq A.
Proof.
intros; apply union_seq_eq_compat.
intros; now rewrite DU_union_finite.
Qed.

Lemma DU_disj_finite :
  forall (A : nat -> U -> Prop) N,
    disj_finite (DU A) N.
Proof.
intros A N n1 n2 Hn1 Hn2 Hn x Hx1 Hx2.
destruct n1, n2; try lia; simpl in Hx2; destruct Hx2 as [Hx2 Hx2']; apply Hx2'.
apply (union_finite_ub _ _ 0); [lia | easy].
apply DU_incl_seq_l in Hx1; now exists (S n1).
Qed.

Lemma DU_disj_finite_alt :
  forall (A : nat -> U -> Prop) N,
    disj_finite_alt (DU A) N.
Proof.
intros; apply disj_finite_equiv, DU_disj_finite.
Qed.

Lemma DU_disj_seq :
  forall (A : nat -> U -> Prop),
    disj_seq (DU A).
Proof.
intros; rewrite disj_seq_equiv_def; apply DU_disj_finite.
Qed.

Lemma DU_disj_seq_alt :
  forall (A : nat -> U -> Prop),
    disj_seq_alt (DU A).
Proof.
intros; apply disj_seq_equiv, DU_disj_seq.
Qed.

End DU_Facts.