Library TLC.LibMin



Set Implicit Arguments.
From TLC Require Import LibTactics LibLogic LibReflect LibOperation
  LibRelation LibOrder LibEpsilon.
Generalizable Variables A.




Definition lower_bound A (le:binary A) (P:A->Prop) (x:A) :=
  forall y, P y -> le x y.


Definition min_element A (le:binary A) (P:A->Prop) (x:A) :=
  P x /\ lower_bound le P x.


Definition mmin `{Inhab A} (le:binary A) (P:A->Prop) :=
  epsilon (min_element le P).



Definition upper_bound A (le:binary A) (P:A->Prop) (x:A) :=
  forall y, P y -> le y x.


Definition max_element A (le:binary A) (P:A->Prop) (x:A) :=
  P x /\ upper_bound le P x.


Definition mmax `{Inhab A} (le:binary A) (P:A->Prop) :=
  epsilon (max_element le P).



Definition lub A (le:binary A) (P:A->Prop) (x:A) :=
  min_element le (upper_bound le P) x.


Definition glb A (le:binary A) (P:A->Prop) (x:A) :=
  max_element le (lower_bound le P) x.


Lemma upper_bound_inverse : forall A (le:binary A),
  upper_bound le = lower_bound (inverse le).
Proof using.
  extens. intros P x. unfolds lower_bound, upper_bound. iff*.
Qed.

Lemma max_element_inverse : forall A (le:binary A) (P:A->Prop) (x:A),
  max_element le P x = min_element (inverse le) P x.
Proof using.
  extens. unfold max_element, min_element. rewrite* upper_bound_inverse.
Qed.

Lemma mmax_inverse : forall `{Inhab A} (le:binary A) (P:A->Prop),
  mmax le P = mmin (inverse le) P.
Proof using.
  intros. applys epsilon_eq. intros x. rewrite* max_element_inverse.
Qed.



Definition bounded_has_minimal A (le:binary A) :=
  
  forall P,
  ex P ->
  ex (lower_bound le P) ->
  ex (min_element le P).


Lemma mmin_spec : forall `{Inhab A} (le:binary A) (P:A->Prop) m,
  m = mmin le P ->
  ex P ->
  ex (lower_bound le P) ->
  bounded_has_minimal le ->
  min_element le P m.
Proof using.
  intros. subst. unfold mmin. epsilon* m.
Qed.


From TLC Require Import LibNat.


Lemma increment_lower_bound_nat : forall (P : nat->Prop) x,
  lower_bound le P x ->
  ~ P x ->
  lower_bound le P (x + 1)%nat.
Proof using.
  introv hlo ?. intros y ?.
  destruct (eq_nat_dec x y).
    { subst. tauto. }
    { forwards: hlo; eauto. nat_math. }
Qed.

Lemma bounded_has_minimal_nat :
  @bounded_has_minimal nat le.
Proof using.
  intros P [ y ? ].
  cut (
    forall (k x : nat), (y + 1 - x)%nat = k ->
    lower_bound le P x ->
    exists z, min_element le P z
  ). { intros ? [ x ? ]. eauto. }
  induction k; introv ? hlo.
  { false. forwards: hlo; eauto. nat_math. }
  
  
  destruct (prop_inv (P x)).
    { exists x. split; eauto. }
    { eapply (IHk (x + 1)%nat). nat_math. eauto using increment_lower_bound_nat. }
Qed.

Hint Resolve bounded_has_minimal_nat : bounded_has_minimal.


Lemma admits_lower_bound_nat : forall (P : nat->Prop),
  ex (lower_bound le P).
Proof using.
  exists 0%nat. unfold lower_bound. nat_math.
Qed.

Hint Resolve admits_lower_bound_nat : admits_lower_bound.


Lemma bounded_has_maximal_nat :
  @bounded_has_minimal nat (inverse le).
Proof using.
  intros P [ y ? ] [ x h ].
  assert (y <= x).
    { forwards: h. eauto. eauto. }
  
  assert (self_inverse: forall i, i <= x -> (x - (x - i))%nat = i).
    intros. nat_math.
  forwards [ z [ ? hz ]]: (@bounded_has_minimal_nat (fun i => P (x - i)%nat)).
    { exists (x - y)%nat. rewrite self_inverse by eauto. eauto. }
    { eauto using admits_lower_bound_nat. }
  exists (x - z)%nat.
  clear dependent y.
  split; [ assumption | ].
  intros y ?.
  assert (y <= x).
    { forwards: h. eauto. eauto. }
  forwards: hz (x - y)%nat.
    { rewrite self_inverse by eauto. eauto. }
  unfold inverse. nat_math.
Qed.

Hint Resolve bounded_has_maximal_nat : bounded_has_minimal.

Lemma mmin_spec_nat:
  forall (P:nat->Prop) m,
  m = mmin le P ->
  ex P ->
  P m /\ (forall x, P x -> m <= x).
Proof using.
  introv E Q. applys (@mmin_spec _ _ _ P m E Q).
  applys admits_lower_bound_nat.
  applys bounded_has_minimal_nat.
Qed.



Definition MMin `{Inhab A} `{Le A} := mmin le.


Definition MMax `{Inhab A} `{Le A} := mmax le.