Parcoursup / Calcul de l'ordre d'appel des candidats index


module EnumMap
  [@java:package:fr.parcoursup.whyml.ordreappel.algo]
  [@java:visibility:package]

  use int.Int
  use seq.Seq
  use mach.java.lang.Integer
  use mach.java.lang.IndexOutOfBoundsException
  use mach.java.util.Queue as Q
  use mach.java.util.UnmodifiableList as UL
  use ref.Ref

  use proofs.lib.seq.Seq
  use proofs.ordre_appel.seq_voeux.SeqVoeux
  use proofs.ordre_appel.seq_voeux.SeqVoeuxDistincts
  use proofs.ordre_appel.seq_voeux.SeqVoeuxGroupe
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse_Props
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse

  type t = {
    bds : Q.queue VoeuClasse.t;
    bhs : Q.queue VoeuClasse.t;
    nbds : Q.queue VoeuClasse.t;
    nbhs : Q.queue VoeuClasse.t;
  } invariant { [@expl:map size is integer]
    0 <= Seq.length bds + Seq.length bhs + Seq.length nbds + Seq.length nbhs <= max_integer
  } invariant { [@expl: bds sorted]
    seq_rangs_sorted bds
  } invariant { [@expl: bds well-typed]
    boursiers_du_secteur_seulement bds
  } invariant { [@expl: nbds sorted]
    seq_rangs_sorted nbds
  } invariant { [@expl: nbds well-typed]
    non_boursiers_du_secteur_seulement nbds
  } invariant { [@expl: bhs sorted]
    seq_rangs_sorted bhs
  } invariant { [@expl: bhs well-typed]
    boursiers_hors_secteur_seulement bhs
  } invariant { [@expl: nbhs sorted]
    seq_rangs_sorted nbhs
  } invariant { [@expl: nbhs well-typed ]
    non_boursiers_hors_secteur_seulement nbhs
  } by {
    bds = Q.empty (); bhs = Q.empty (); nbds = Q.empty (); nbhs = Q.empty ();
  }

  let ghost function get_queue (self : t) (x: type_candidat) : (res : seq_voeu)
    ensures { seulement_type res x }
    ensures { seq_rangs_sorted res }
    ensures { match x with
    | BOURSIER_DU_SECTEUR -> res = Q.content self.bds
    | BOURSIER_HORS_SECTEUR -> res = Q.content self.bhs
    | NON_BOURSIER_DU_SECTEUR -> res = Q.content self.nbds
    | NON_BOURSIER_HORS_SECTEUR -> res = Q.content self.nbhs
    end }
  =
    match x with
    | BOURSIER_DU_SECTEUR -> Q.content self.bds
    | BOURSIER_HORS_SECTEUR -> Q.content self.bhs
    | NON_BOURSIER_DU_SECTEUR -> Q.content self.nbds
    | NON_BOURSIER_HORS_SECTEUR -> Q.content self.nbhs
    end

  let ghost function get_queue_of (self : t) (x : VoeuClasse.t) : (q : seq_voeu)
    ensures { forall v. seq_contains v q -> get_type_candidat v = get_type_candidat x }
  =
    let q = get_queue self (get_type_candidat x) in
    assert { seulement_type q (get_type_candidat x) };
    q

  predicate enummap_contains (self : t) (v : VoeuClasse.t) =
    match v.type_candidat with
    | BOURSIER_DU_SECTEUR -> seq_contains v self.bds
    | BOURSIER_HORS_SECTEUR -> seq_contains v self.bhs
    | NON_BOURSIER_DU_SECTEUR -> seq_contains v self.nbds
    | NON_BOURSIER_HORS_SECTEUR -> seq_contains v self.nbhs
    end

  predicate enummap_not_contains (self : t) (v : VoeuClasse.t) =
    match v.type_candidat with
    | BOURSIER_DU_SECTEUR -> not seq_contains v self.bds
    | BOURSIER_HORS_SECTEUR -> not seq_contains v self.bhs
    | NON_BOURSIER_DU_SECTEUR -> not seq_contains v self.nbds
    | NON_BOURSIER_HORS_SECTEUR -> not seq_contains v self.nbhs
    end

  let lemma enummap_not_contains_equiv (self : t) (v : VoeuClasse.t)
    ensures { enummap_not_contains self v <-> not enummap_contains self v }
  = ()

  predicate enummap_is_empty (self : t) =
    self.bds = Seq.empty /\ self.bhs = Seq.empty /\ self.nbds = Seq.empty /\ self.nbhs = Seq.empty

  predicate enummap_queue_is_empty (self : t) (x : type_candidat) =
    match x with
    | BOURSIER_DU_SECTEUR -> self.bds = Seq.empty
    | BOURSIER_HORS_SECTEUR -> self.bhs = Seq.empty
    | NON_BOURSIER_DU_SECTEUR -> self.nbds = Seq.empty
    | NON_BOURSIER_HORS_SECTEUR -> self.nbhs = Seq.empty
    end

  predicate enummap_is_peeked (self : t) (x : type_candidat) (v: VoeuClasse.t) =
    (not enummap_queue_is_empty self x) /\ (v = Seq.get (get_queue self x) 0)

  predicate enummap_v_is_head (self : t) (v : voeu) =
    enummap_is_peeked self (get_type_candidat v) v

  predicate enummap_equals_for_type (m1 m2 : t) (x : type_candidat) =
    match x with
    | BOURSIER_DU_SECTEUR -> m1.bds = m2.bds
    | BOURSIER_HORS_SECTEUR -> m1.bhs = m2.bhs
    | NON_BOURSIER_DU_SECTEUR -> m1.nbds = m2.nbds
    | NON_BOURSIER_HORS_SECTEUR -> m1.nbhs = m2.nbhs
    end

  predicate enummap_equals_except_for_type (m1 m2 : t) (x : type_candidat) =
    match x with
    | BOURSIER_DU_SECTEUR       -> m1.bhs = m2.bhs /\ m1.nbds = m2.nbds /\ m1.nbhs = m2.nbhs
    | BOURSIER_HORS_SECTEUR     -> m1.bds = m2.bds /\ m1.nbds = m2.nbds /\ m1.nbhs = m2.nbhs
    | NON_BOURSIER_DU_SECTEUR   -> m1.bds = m2.bds /\ m1.bhs = m2.bhs /\ m1.nbhs = m2.nbhs
    | NON_BOURSIER_HORS_SECTEUR -> m1.bds = m2.bds /\ m1.bhs = m2.bhs /\ m1.nbds = m2.nbds
    end

  predicate enummap_pop_v (om m : t) (v : VoeuClasse.t) =
    (enummap_equals_except_for_type om m (get_type_candidat v)) &&
    get_queue om (get_type_candidat v) == cons v (get_queue m (get_type_candidat v))

  let enummap [@java:constructor] () : t
    ensures { enummap_is_empty result }
  =
    { bds = Q.empty (); bhs = Q.empty (); nbds = Q.empty (); nbhs = Q.empty (); }

  let function get_nb_voeux_classes (self : t) : integer
    ensures { result = Seq.length self.bds + Seq.length self.bhs + Seq.length self.nbds + Seq.length self.nbhs }
  =
    Q.size self.bds + Q.size self.bhs + Q.size self.nbds + Q.size self.nbhs

  let function get_nb_boursiers (self : t) : integer
    ensures { result = Seq.length (self.bds) + Seq.length (self.bhs) }
  =
    Q.size self.bds + Q.size self.bhs

  let function get_nb_du_secteur (self : t) : integer
    ensures { result = Seq.length (self.bds) + Seq.length (self.nbds) }
  =
    Q.size self.bds + Q.size self.nbds

  let function queue_is_empty (self : t) (x : type_candidat) : bool
    ensures { result = enummap_queue_is_empty self x }
  =
    match x with
    | BOURSIER_DU_SECTEUR -> Q.is_empty self.bds
    | BOURSIER_HORS_SECTEUR -> Q.is_empty self.bhs
    | NON_BOURSIER_DU_SECTEUR -> Q.is_empty self.nbds
    | NON_BOURSIER_HORS_SECTEUR -> Q.is_empty self.nbhs
    end

  let function peek (self : t) (x : type_candidat) : VoeuClasse.t
    requires { [@expl:pre peek / queue no empty] not (queue_is_empty self x) }
    ensures { result = Seq.get (get_queue self x) 0 }
  =
    match x with
    | BOURSIER_DU_SECTEUR -> Q.peek self.bds
    | BOURSIER_HORS_SECTEUR -> Q.peek self.bhs
    | NON_BOURSIER_DU_SECTEUR -> Q.peek self.nbds
    | NON_BOURSIER_HORS_SECTEUR -> Q.peek self.nbhs
    end

  let put (self : t) (v : VoeuClasse.t) : unit
    requires { get_nb_voeux_classes self < max_integer }
    requires { [@expl:pre - v not in map m] not enummap_contains self v }
    requires { [@expl:pre - v is greater its destination queue]
      	       v_is_greater_than_seq (get_queue_of self v) v }
    ensures { get_queue self v.type_candidat == snoc (get_queue (old self) v.type_candidat) v }
    ensures { length (get_queue_of self v) = old (length (get_queue_of self v)) + 1 }
    ensures { forall y. y <> (get_type_candidat v) <-> enummap_equals_for_type self (old self) y }
    ensures { ((get_type_candidat v) <> BOURSIER_HORS_SECTEUR) <->
              enummap_equals_for_type self (old self) BOURSIER_HORS_SECTEUR }
    ensures { ((get_type_candidat v) <> BOURSIER_DU_SECTEUR) <->
       	      enummap_equals_for_type self (old self) BOURSIER_DU_SECTEUR }
    ensures { ((get_type_candidat v) <> NON_BOURSIER_HORS_SECTEUR) <->
       	      enummap_equals_for_type self (old self) NON_BOURSIER_HORS_SECTEUR }
    ensures { ((get_type_candidat v) <> NON_BOURSIER_DU_SECTEUR) <->
              enummap_equals_for_type self (old self) NON_BOURSIER_DU_SECTEUR }
    ensures { enummap_contains self v }
    ensures { seq_contains v (get_queue_of self v) }
    ensures { forall x. x <> v -> (enummap_contains (old self) x <-> enummap_contains self x) }
  =
    match get_type_candidat v with
    | BOURSIER_DU_SECTEUR -> Q.add self.bds v
    | BOURSIER_HORS_SECTEUR -> Q.add self.bhs v
    | NON_BOURSIER_DU_SECTEUR -> Q.add self.nbds v
    | NON_BOURSIER_HORS_SECTEUR -> Q.add self.nbhs v
    end

  let lemma enummap_same_types_in_queues (m : t)
    ensures { forall v. seq_contains v m.bds -> get_type_candidat v = BOURSIER_DU_SECTEUR }
    ensures { forall v. seq_contains v m.bhs -> get_type_candidat v = BOURSIER_HORS_SECTEUR }
    ensures { forall v. seq_contains v m.nbds -> get_type_candidat v = NON_BOURSIER_DU_SECTEUR }
    ensures { forall v. seq_contains v m.nbhs -> get_type_candidat v = NON_BOURSIER_HORS_SECTEUR }
    ensures { forall t: type_candidat. let q = get_queue m t in
                forall v vp. seq_contains v q -> seq_contains vp q -> get_type_candidat v = get_type_candidat vp }
  = ()

  let pop (self : t) (x: type_candidat) : (res : VoeuClasse.t)
    requires { [@expl:pre pop / queue not empty] not (queue_is_empty self x) }
    ensures { (get_queue self x) == (get_queue (old self) x)[1..] }
    ensures { res = (get_queue (old self) x)[0] }
    ensures { res = peek (old self) x }
    ensures { enummap_not_contains self res }
    ensures { forall v. v <> res -> (enummap_contains (old self) v -> enummap_contains self v) }
    ensures { voeu_lt_than_queue res (get_queue self x) }
    ensures { forall v. v <> res -> enummap_contains self v -> enummap_contains (old self) v }
    ensures { forall t. t <> get_type_candidat res -> enummap_equals_for_type self (old self) t }
    ensures { enummap_pop_v (old self) self res }
  =
    enummap_same_types_in_queues self;
    let res = match x with
    | BOURSIER_DU_SECTEUR -> Q.poll self.bds
    | BOURSIER_HORS_SECTEUR -> Q.poll self.bhs
    | NON_BOURSIER_DU_SECTEUR -> Q.poll self.nbds
    | NON_BOURSIER_HORS_SECTEUR -> Q.poll self.nbhs
    end in
    assert { type_candidat res = x };
    assert { (get_queue_of (old self) res) == cons res (get_queue_of self res) };
    assert { forall v. type_candidat v <> type_candidat res -> get_queue_of (old self) v == get_queue_of self v };
    assert { forall v. type_candidat v = type_candidat res -> v <> res ->
               seq_contains v (get_queue_of self res) -> seq_contains v (get_queue_of (old self) res) };
    res

  let lemma enummap_contains_lemma_1 (m : t) (v vv : VoeuClasse.t)
    requires { seq_contains vv (get_queue_of m v) }
    ensures { enummap_contains m vv }
  =
    assert { get_type_candidat v = get_type_candidat vv };
    match get_type_candidat v with
    | BOURSIER_DU_SECTEUR -> assert { seq_contains vv m.bds }
    | BOURSIER_HORS_SECTEUR -> assert { seq_contains vv m.bhs }
    | NON_BOURSIER_DU_SECTEUR -> assert { seq_contains vv m.nbds }
    | NON_BOURSIER_HORS_SECTEUR -> assert { seq_contains vv m.nbhs }
    end

  predicate enummap_in_grp (m : t) (grp : seq_voeu) =
    forall v. enummap_contains m v -> seq_contains v grp

  predicate grp_in_enummap (grp : seq_voeu) (m : t) =
    forall v. seq_contains v grp -> enummap_contains m v

  predicate enummap_eq_grp (m : t) (grp : seq_voeu) =
    forall v. enummap_contains m v <-> seq_contains v grp

  predicate enummap_all_distincts (m : t) =
     forall x y. enummap_contains m x -> enummap_contains m y -> x <> y -> voeu_distinct x y

  let lemma enummap_eq_grp_lemma (g : seq_voeu) (m : t)
    requires { seq_rangs_sorted g }
    requires { forall v. enummap_contains m v -> seq_contains v g }
    requires { forall v. seq_contains v g -> enummap_contains m v }
    ensures { enummap_all_distincts m }
  =
    let lemma aux (x y : VoeuClasse.t)
      requires { enummap_contains m x }
      requires { enummap_contains m y }
      requires { x <> y }
      ensures { voeu_distinct x y }
    =
      if get_rang x = get_rang y then
      begin
        assert { all_distincts g };
        absurd;
      end
    in
      ()

  let from_groupe (grp : UL.ulist VoeuClasse.t) : t
    requires { [@expl:g is ok] seq_groupe_ok grp }
    requires { [@expl:g is sorted] seq_rangs_sorted grp }
    requires { [@expl:g size is integer] 0 <= Seq.length grp <= Integer.max_integer }

    ensures { get_nb_voeux_classes result = Seq.length grp }
    ensures { get_nb_boursiers result = nb_boursiers grp }
    ensures { get_nb_du_secteur result = nb_du_secteur grp }
    ensures { forall v. enummap_contains result v -> seq_contains v grp }
    ensures { forall v. seq_contains v grp -> enummap_contains result v }
    ensures { enummap_eq_grp result grp }
    ensures { enummap_all_distincts result }
    ensures { [@expl:IQ0-1/3] seq_contains_seq grp Seq.empty }
    ensures { [@expl:IQ0-2/3] enummap_in_grp result grp }
    ensures { [@expl:IQ0-3/3] forall i. 0 <= i < length grp -> seq_contains grp[i] Seq.empty \/ enummap_contains result grp[i] }
  =
    let ghost nb_b : ref integer = ref 0 in
    let ghost nb_r : ref integer = ref 0 in

    let res = enummap () in
    let nb_v = UL.size grp in
    for i = 0 to nb_v -1 do
      invariant { get_nb_voeux_classes res = i }
      invariant { [@expl:#R.grp] nb_du_secteur_r grp 0 i = !nb_r }
      invariant { [@expl:#B.grp] nb_boursiers_r grp 0 i = !nb_b }
      invariant { [@expl:#B.res] get_nb_boursiers res = nb_boursiers_r grp 0 i  }
      invariant { [@expl:#R.res] get_nb_du_secteur res = nb_du_secteur_r grp 0 i }
      invariant { [@expl:res in grp] forall v. enummap_contains res v -> seq_contains v grp[..i] }
      invariant { [@expl:grp in res] forall j. 0 <= j < i -> enummap_contains res grp[j] }

      assert { [@expl:v > q] forall j. i <= j < nb_v -> forall v. enummap_contains res v ->  voeu_lt v grp[j] };
      try
        let v = UL.get grp i in
        ghost begin
          if est_boursier v then begin
            nb_b := !nb_b + 1;
          end;
          if est_du_secteur v then
            nb_r := !nb_r + 1;
        end;

        label H in
        assert { forall vv. enummap_contains res vv -> seq_contains vv grp[..i] };
        assert { forall vv. enummap_contains res vv -> voeu_lt vv v };
        assert { forall vv. seq_contains vv (get_queue_of res v) -> enummap_contains res vv };

        put res v;

        assert { grp[..i+1] == snoc grp[..i] v };
  (*
        assert { forall x. enummap_contains res x -> x = v -> seq_contains x grp[..i+1] };
        assert { forall x. x <> v -> (enummap_contains (res at H) x -> enummap_contains res x) };
        assert { forall vp. vp <> v -> enummap_contains res vp -> enummap_contains (res at H) vp ->
                  seq_contains vp grp[..i+1] }
  *)
      with
        IndexOutOfBoundsException.E _ -> absurd
      end
    done;
    res
end

module EnumMap_Props
  use int.Int
  use seq.Seq
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse
  use EnumMap

  predicate enummap_est_boursier (m : EnumMap.t) (v : VoeuClasse.t) =
     enummap_contains m v && est_boursier v

  predicate enummap_est_du_secteur (m : EnumMap.t) (v : VoeuClasse.t) =
     enummap_contains m v && est_du_secteur v

  predicate enummap_remains_boursiers (m : EnumMap.t) =
    EnumMap.get_nb_boursiers m > 0

  predicate enummap_remains_du_secteur (m : EnumMap.t) =
    EnumMap.get_nb_du_secteur m > 0

  let lemma enummap_remains_boursiers_equiv (m : EnumMap.t)
    ensures { enummap_remains_boursiers m <->  (not (m.bds == empty)  || (not m.bhs == empty)) }
  =
    ()

  let lemma enummap_remains_du_secteur_equiv (m : EnumMap.t)
    ensures { enummap_remains_du_secteur m <-> (m.bds <> empty  || m.nbds <> empty) }
  =
    ()
end

module EnumMap_Lemmas
  use int.Int
  use seq.Seq
  use mach.java.lang.Integer
  use EnumMap
  use EnumMap_Props
  use proofs.lib.seq.Seq
  use proofs.ordre_appel.seq_voeux.SeqVoeux
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse_Props

  let lemma enummap_equals_for_type_imply_queue_eq (m1 m2 : EnumMap.t) (x : type_candidat)
    requires { enummap_equals_for_type m1 m2 x }
    ensures { (get_queue m1 x) = (get_queue m2 x) }
  =
    ()

  let lemma enummap_non_empty (m : EnumMap.t)
    requires { EnumMap.get_nb_voeux_classes m > 0 }
    ensures { exists v. enummap_contains m v }
  = assert { m.bds <> empty || m.bhs <> empty || m.nbds <> empty || m.nbhs <> empty };
    assert { m.bds <> empty -> exists v. seq_contains v m.bds };
    assert { m.bhs <> empty -> exists v. seq_contains v m.bhs };
    assert { m.nbds <> empty -> exists v. seq_contains v m.nbds };
    assert { m.nbhs <> empty -> exists v. seq_contains v m.nbhs }

  let lemma enummap_pop_imply_size_decrease (om m : EnumMap.t) (v : VoeuClasse.t)
    requires { enummap_pop_v om m v }
    ensures { EnumMap.get_nb_voeux_classes om = EnumMap.get_nb_voeux_classes m + 1 }
  = ()

  let lemma enummap_pop_imply_included (om m : EnumMap.t)
    requires { exists v : VoeuClasse.t. enummap_pop_v om m v }
    ensures { forall v. enummap_contains m v -> enummap_contains om v }
  =
    let lemma enummap_pop_imply_included_aux (v : VoeuClasse.t) (vv :VoeuClasse.t)
      requires { enummap_pop_v om m v }
      requires { enummap_contains m vv }
      ensures { enummap_contains om vv }
    = let q = get_queue om (get_type_candidat v) in
      assert { q == cons v q[1..] };
      assert { get_type_candidat v = get_type_candidat vv -> v <> vv -> seq_contains vv q[1..] };
      assert { get_type_candidat v = get_type_candidat vv -> v <> vv -> seq_contains vv q } in
    ()

  let lemma enummap_pop_v_imply_not_in_m (om m : EnumMap.t) (v : VoeuClasse.t)
    requires { enummap_pop_v om m v }
    ensures { enummap_contains om v }
    ensures { not enummap_contains m v }
  = ()

  let lemma enummap_pop_v_all_eq_except_v (om m : EnumMap.t) (v vv : VoeuClasse.t)
      requires { enummap_pop_v om m v }
      requires { enummap_contains om vv }
      requires { v <> vv }
      ensures { enummap_contains m vv }
    =
      assert { get_type_candidat v = get_type_candidat vv -> v <> vv ->
                seq_contains vv (get_queue m (get_type_candidat v)) }

  let lemma enummap_in_grp_included (m1 m2 : EnumMap.t) (grp : seq_voeu)
     requires { forall v. enummap_contains m1 v -> enummap_contains m2 v }
     requires { enummap_in_grp m2 grp}
     ensures { enummap_in_grp m1 grp}
  =  ()

  let lemma enummap_contains_equiv_seq_contains_q (m : EnumMap.t) (v : VoeuClasse.t)
    ensures { enummap_contains m v -> seq_contains v (get_queue_of m v) }
    ensures { seq_contains v (get_queue_of m v) -> enummap_contains m v }
  = ()

  let lemma enummap_non_empty_imply_exists_head (m : EnumMap.t) : (v : VoeuClasse.t)
    requires { not enummap_is_empty m }
    ensures { enummap_v_is_head m v }
  =
    let t = any type_candidat ensures { get_queue m result <> empty } in
    (get_queue m t)[0]

  let lemma enummap_non_empty_du_secteur (m : EnumMap.t) : (v : VoeuClasse.t)
    requires { enummap_remains_du_secteur m }
    ensures { enummap_v_is_head m v }
    ensures { est_du_secteur v }
  =
    let t = any (t : type_candidat) ensures { type_est_du_secteur t /\ get_queue m t <> empty } in
    (get_queue m t)[0]

  let lemma enummap_non_empty_boursier (m : EnumMap.t) : (v : VoeuClasse.t)
    requires { enummap_remains_boursiers m }
    ensures { enummap_v_is_head m v }
    ensures { est_boursier v }
  =
    let t = any (t : type_candidat) ensures { type_est_boursier t /\ get_queue m t <> empty } in
    (get_queue m t)[0]

  let lemma enummap_head_is_lt_its_queue (m : EnumMap.t) (v h : VoeuClasse.t)
    requires { enummap_v_is_head m h }
    requires { seq_contains v (get_queue m (type_candidat h)) }
    ensures {  v <> h -> voeu_lt h v }
  =
    ()

  let lemma enummap_poped_head_saved (om m : EnumMap.t) (x v h : VoeuClasse.t)
    requires { enummap_pop_v om m x }
    requires { get_type_candidat x <> get_type_candidat v }
    requires { get_type_candidat h = get_type_candidat v }
    requires { enummap_v_is_head om h }
    ensures { enummap_v_is_head m h }
    ensures { seq_contains v (EnumMap.get_queue om (get_type_candidat v)) -> seq_contains v (EnumMap.get_queue m (get_type_candidat h)) }
  =
    ()

end

module AllDistincts
  use int.Int
  use proofs.lib.seq.Seq
  use proofs.ordre_appel.seq_voeux.SeqVoeux
  use proofs.ordre_appel.seq_voeux.SeqVoeuxDistincts
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse_Props
  use EnumMap

  predicate enummap_all_distincts (m : EnumMap.t) =
     forall x y. enummap_contains m x -> enummap_contains m y -> x <> y ->
       voeu_distinct x y

  predicate enummap_seq_distincts (m : EnumMap.t) (s : seq_voeu) =
    forall x, y. enummap_contains m x -> seq_contains y s -> voeu_distinct x y

  predicate enummap_seq_all_distincts (s : seq_voeu) (m : EnumMap.t) =
      all_distincts s && enummap_all_distincts m && enummap_seq_distincts m s

end

(* generated on Mon Dec  2 02:04:28 UTC 2024 from rev:  *)

Generated by why3doc 1.7.2+git