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


module SeqVoeux
  use int.Int
  use seq.Seq
  use proofs.lib.seq.Seq
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse_Props
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse

  type voeu = VoeuClasse.t
  type seq_voeu = seq voeu

  function nb_boursiers (s : seq_voeu) : int = seq_numof est_boursier s

  function nb_boursiers_r (s : seq_voeu) (a b : int): int = seq_numof_r est_boursier s a b

  lemma nb_boursiers_positive:
    forall s. nb_boursiers s >= 0

  let lemma nb_boursiers_next (s : seq_voeu) (a b : int)
    requires { 0 <= a <= b < length s }
    requires { est_boursier s[b] }
    ensures { nb_boursiers_r s a (b+1) = (nb_boursiers_r s a b) + 1 }
  = ()

  function nb_residents (s : seq_voeu) : int = seq_numof est_du_secteur s

  function nb_du_secteur (s : seq_voeu) : int = seq_numof est_du_secteur s

  function nb_du_secteur_r (s : seq_voeu) (a b : int): int = seq_numof_r est_du_secteur s a b

  lemma nb_du_secteur_positive:
    forall s. nb_du_secteur s >= 0

  let lemma nb_du_secteur_next (s: seq_voeu) (a b : int)
    requires { 0 <= a <=  b < length s }
    requires { est_du_secteur s[b] }
    ensures { nb_du_secteur_r s a (b + 1) = (nb_du_secteur_r s a b) + 1 }
  =
    ()

  predicate est_boursier_du_secteur (v : voeu) =
    v.type_candidat = BOURSIER_DU_SECTEUR

  function nb_bour_res (s: seq_voeu) : int = seq_numof est_boursier_du_secteur s

  function contient (v : voeu) (s: seq_voeu) : bool = seq_contains v s

  predicate boursiers_du_secteur_seulement (s : seq_voeu) =
    seq_forall est_boursier_du_secteur s

  predicate est_boursier_hors_secteur (v : voeu) =
    v.type_candidat = BOURSIER_HORS_SECTEUR

  predicate boursiers_hors_secteur_seulement (s : seq_voeu) =
    seq_forall est_boursier_hors_secteur s

  predicate est_non_boursier_du_secteur (v : voeu) =
    v.type_candidat = NON_BOURSIER_DU_SECTEUR

  predicate non_boursiers_du_secteur_seulement (s : seq_voeu) =
    seq_forall est_non_boursier_du_secteur s

  predicate est_non_boursier_hors_secteur (v : voeu) =
    v.type_candidat = NON_BOURSIER_HORS_SECTEUR

  predicate non_boursiers_hors_secteur_seulement (s : seq_voeu) =
    seq_forall est_non_boursier_hors_secteur s

  predicate du_secteur_seulement (s : seq_voeu) =
    seq_forall est_du_secteur s

  predicate est_hors_secteur (v : voeu) =
    not est_du_secteur v

  predicate hors_secteur_seulement (s : seq_voeu) =
    seq_forall est_hors_secteur s

  let lemma hors_secteur_seulement_snoc (s : seq_voeu) (v: voeu)
    requires { hors_secteur_seulement s }
    requires { est_hors_secteur v }
    ensures { hors_secteur_seulement (snoc s v) }
  = ()

  predicate boursiers_seulement (s : seq_voeu) =
    seq_forall est_boursier s

  predicate est_non_boursier (v : voeu) =
    not (est_boursier v)

  predicate non_boursiers_seulement (s : seq_voeu) =
    seq_forall est_non_boursier s

  let rec lemma carac_non_bour_seulement (s : seq_voeu)
      ensures { non_boursiers_seulement s -> nb_boursiers s = 0 }
      ensures { nb_boursiers s = 0 -> non_boursiers_seulement s }
      variant { length s }
  = if length s > 0 then
    begin
      carac_non_bour_seulement s[1..];
      assert { non_boursiers_seulement s -> est_non_boursier s[0] };
      assert { nb_boursiers s = 0 -> est_non_boursier s[0] };
    end

  let lemma non_boursiers_seulement_snoc (s : seq_voeu) (x : voeu)
    requires { non_boursiers_seulement s }
    requires { not est_boursier x }
    ensures { non_boursiers_seulement (snoc s x) }
  = ()

  let lemma  non_boursiers_seulement_after_i_snoc (s : seq_voeu) (v : voeu) (i : int)
    requires { 0 <= i <= length s }
    requires {  non_boursiers_seulement s[i..] }
    requires { est_non_boursier v }
    ensures { non_boursiers_seulement (snoc s v)[i..] }
  = ()

  let lemma non_boursiers_seulement_after_i (s : seq_voeu) (i k : int)
    requires { 0 <= i <= k < length s }
    requires { non_boursiers_seulement s[i..] }
    ensures { est_non_boursier s[k] }
  =
    assert { s[k] = s[i..][k-i] }

  let lemma non_boursiers_seulement_suffix_i (s : seq_voeu) (i : int)
    requires { 0 <= i <= length s }
    requires { non_boursiers_seulement s[i..] }
    ensures { forall k. i <= k <= length s -> non_boursiers_seulement s[k..] }
  =
    ()

  predicate seulement_type (s : seq_voeu) (t : type_candidat) =
    match t with
    | BOURSIER_DU_SECTEUR -> boursiers_du_secteur_seulement s
    | BOURSIER_HORS_SECTEUR -> boursiers_hors_secteur_seulement s
    | NON_BOURSIER_DU_SECTEUR -> non_boursiers_du_secteur_seulement s
    | NON_BOURSIER_HORS_SECTEUR -> non_boursiers_hors_secteur_seulement s
    end

  let lemma seulement_type_equiv_type (s : seq_voeu) (t : type_candidat)
    ensures { seulement_type s t <-> forall v. seq_contains v s -> get_type_candidat v = t }
  = ()

  let rec lemma seulement_type_snoc (s : seq_voeu) (v : voeu)
    requires { seulement_type s (get_type_candidat v)}
    ensures { seulement_type (snoc s v) (get_type_candidat v) }
    variant { length s }
  =
    if length s = 0 then
      assert { seulement_type (cons v Seq.empty) (get_type_candidat v) }
    else begin
      assert { seulement_type s (get_type_candidat v) };
      seulement_type_snoc s[1..] v
    end

  predicate remains_boursiers (s : seq_voeu) (total_b : int) =
    0 <= nb_boursiers s < total_b

  let lemma remains_boursiers_snoc (s : seq_voeu) (v: voeu) (total_b : int)
    requires { remains_boursiers (snoc s v) total_b }
    ensures { remains_boursiers s total_b }
  = ()

  let lemma remains_boursiers_prefix (s : seq_voeu) (total_b : int)
    requires { remains_boursiers s total_b }
    ensures { forall k. 0 <= k <= length s -> remains_boursiers s[..k] total_b }
  = ()

  let lemma not_remains_boursiers_snoc (s : seq_voeu) (v: voeu) (total_b : int)
    requires { not remains_boursiers s total_b }
    ensures { not remains_boursiers (snoc s v) total_b }
  = ()

  predicate remains_du_secteur (s : seq_voeu) (total_ds : int) =
    0 <= nb_du_secteur s < total_ds

  let lemma remains_du_secteur_prefix (s : seq_voeu) (total_ds : int)
    requires { remains_du_secteur s total_ds }
    ensures { forall k. 0 <= k <= length s ->
    	      remains_du_secteur s[..k] total_ds }
  = ()

  let lemma nb_du_secteur_app (s1 s2 s3 : seq_voeu)
    requires { s1 == s2 ++ s3 }
    ensures { nb_du_secteur (s1) = nb_du_secteur s2 + nb_du_secteur s3 }
  = ()

  let lemma remains_du_secteur_prefix_loc (s : seq_voeu) (total_ds : int)
      	    			      (i : int)
    requires { 0 <= i <= length s }
    requires { remains_du_secteur s[..i] total_ds }
    ensures { forall k. 0 <= k <= i ->
    	      remains_du_secteur s[..k] total_ds }
  = for k = 0 to i do
      invariant { forall j. 0 <= j < k -> remains_du_secteur s[..j] total_ds }
      nb_du_secteur_app s[..i] s[..k] s[k..i] ;
      assert { nb_du_secteur s[..k] <= nb_du_secteur s[..i] }
    done

  predicate voeu_lt_than_queue (v : voeu) (q : seq_voeu) =
    forall k. 0 <= k < length q -> voeu_lt v q[k]

  predicate voeu_lt_than_typed_in_queue (v : voeu) (s : seq_voeu)
  	    				(t : type_candidat) =
    forall j. 0 <= j < length s -> s[j].type_candidat = t -> voeu_lt v s[j]

  predicate v_is_greater_than_seq (s : seq_voeu) (v : voeu) =
    forall i. 0 <= i < length s -> voeu_lt s[i] v

  let lemma voeu_lt_than_queue_trans (v v': voeu) (q : seq_voeu)
    requires { voeu_lt_than_queue v q }
    requires { voeu_lt v' v }
    ensures { voeu_lt_than_queue v' q }
  = ()

  let lemma voeu_lt_than_queue_cons (v v': voeu) (q : seq_voeu)
    requires { voeu_lt_than_queue v' q }
    requires { voeu_lt v v' }
    ensures { voeu_lt_than_queue v (cons v' q) }
  = ()

  let lemma voeu_lt_than_last_typed_in_queue (s : seq_voeu) (t : type_candidat)
    requires { length s > 0 }
    requires { forall i. 0 <= i < length s - 1 ->
               voeu_lt_than_typed_in_queue s[i] s[i+1..] t }
    ensures { s[length s -1].type_candidat = t ->
  	      forall i. 0 <= i < length s - 1 -> voeu_lt s[i] s[length s -1] }
  =
    let k = length s - 1 in
    let x = s[k] in

    if voeu_has_type x t then
    begin
      for i = 0 to k - 1 do
        invariant { forall j. 0 <= j < i -> voeu_lt s[j] x }
	      assert { s[i+1..][k - i - 1] = x };
      done
    end

  let lemma voeu_lt_than_queue_suffix (s : seq_voeu) (z : VoeuClasse.t)
    requires { voeu_lt_than_queue z s }
    requires { length s > 0 }
    ensures { voeu_lt_than_queue z s[1..] }
  = ()
end

module SeqVoeuxTaux
  use int.Int
  use seq.Seq
  use fr.parcoursup.whyml.ordreappel.algo.taux.Taux
  use SeqVoeux

  type taux = Taux.t

  (*
   * Le predicat 'taux_ok' exprime le fait que le nombre de candidats 'nb'
   * d'un type considéré sur le nombre 'total' de candidats est supérieur au
   * 'taux' spécifié. Donc lorsque 'taux' est ok si 'nb' / 'total' >= 'taux'.
   * Le taux étant exprimé par un entier de [0, 100] l'inéquation devient
   * 'nb' / 'total' >= 'taux / 100 c'est-à-dire:
   *)
  predicate taux_ok (taux : taux) (nb: int) (total: int)
    = 100 * nb >= taux * total

  (*
   * Si 'taux_x' est la taux minimum de candidats de type 'x' souhaité. 's' est
   * une liste de candidats, 'count' une fonction de comptage du nombre de 'x'
   * dans 's' et 'total_x' le nombre maximum de candidats existants. 'total_x'
   * n'est pas nécessairement la longueur de 's'.
   *
   * 'taux_x_contraignant' exprime le fait que si on ajoute un nouveau candidat
   * qui n'est pas de type 'x' à 's' (alors qu'il reste des candidats 'x')
   * alors 'taux_x' n'est pas respecté.
   *)
  predicate taux_x_contraignant (taux_x : taux) (s : seq_voeu) (count : seq_voeu -> int) (total_x : int) =
   let nb_x = count s in
     nb_x < total_x && 100 * nb_x < taux_x * (1 + length s)

  (* Spécialisation du taux contraignant pour les boursiers *)
  predicate taux_b_contraignant (taux_b : taux) (s : seq_voeu) (total_b : int) =
    taux_x_contraignant taux_b s nb_boursiers total_b

  (* Spécialisation du taux contraignant pour les residents *)
  predicate taux_ds_contraignant (taux_ds : taux) (s : seq_voeu) (total_ds : int) =
    taux_x_contraignant taux_ds s nb_du_secteur total_ds

  (*
   * Le taux de boursiers et de residents sont en conflit si ils sont tous
   * les deux contraignants.
   *)
  predicate conflit_taux (s : seq_voeu) (taux_b : taux) (total_b : int) (taux_ds : taux) (total_ds : int) =
    taux_b_contraignant taux_b s total_b &&
    taux_ds_contraignant taux_ds s total_ds

  predicate seq_respecte_taux (tx : taux) (s : seq_voeu) (count : seq_voeu -> int) =
    taux_ok tx (count s) (length s)

  predicate seq_respecte_taux_b (tb : taux) (s : seq_voeu) =
    taux_ok tb (nb_boursiers s) (length s)

  predicate seq_respecte_taux_ds (tds : taux) (s : seq_voeu) =
    taux_ok tds (nb_du_secteur s) (length s)

  let lemma seq_respecte_taux_snoc (tx : taux) (s : seq_voeu) (count : seq_voeu -> int) (v : voeu) (k : int)
    requires { 0 <= k <= length s }
    requires { seq_respecte_taux tx (snoc s v)[..k] count }
    ensures { seq_respecte_taux tx s[..k] count }
  = ()

  let lemma seq_respecte_taux_app (s1 s2 : seq_voeu) (taux : taux)
    ensures { (seq_respecte_taux_b taux s1 && seq_respecte_taux_b taux s2) -> seq_respecte_taux_b taux (s1 ++ s2) }
    ensures { (seq_respecte_taux_ds taux s1 && seq_respecte_taux_ds taux s2) -> seq_respecte_taux_ds taux (s1 ++ s2) }
  = ()
end

module SeqVoeuxTauxMinore
  use int.Int
  use seq.Seq
  use seq.FreeMonoid
  use SeqVoeux
  use SeqVoeuxTaux
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse

  (*
   * Le taux minoré est le plus petit des taux taux_r et 1-taux_b' où
   * taux_b' = 1/(1+(1-taux_b)).
   * Il est respecté si au moins un des deux est respecté. Pour taux_b',
   * on utilise l'inégalité:
   * (200 - taux_b)*(nb_ds) >= (100 - tau_b) * total_ds
   *)
  predicate taux_ds_minore_ok (taux_b taux_ds : taux) (nb_ds total : int) =
    taux_ok taux_ds nb_ds total \/
    (200 - taux_b)*(nb_ds) >= (100 - taux_b) * total

  predicate seq_respecte_taux_ds_minore (taux_b taux_ds : taux) (s : seq_voeu) =
    taux_ds_minore_ok taux_b taux_ds (nb_du_secteur s) (length s)

  let lemma seq_respecte_taux_ds_minore_snoc (taux_b taux_ds : taux)
      	    				     (s : seq_voeu) (x : voeu)
    requires { seq_respecte_taux_ds_minore taux_b taux_ds s }
    requires { est_du_secteur x }
    ensures { seq_respecte_taux_ds_minore taux_b taux_ds (snoc s x) }
  = ()

  let lemma seq_respecte_taux_ds_minore_p1 (s : seq_voeu)
      	    				   (taux_b taux_ds : taux)
    requires { seq_respecte_taux_ds_minore taux_b taux_ds s }
    requires { not taux_ok taux_ds (nb_du_secteur s) (length s) }
    ensures { (200 - taux_b)*((nb_du_secteur s)) >= (100 - taux_b) * (length s) }
  = ()

  let lemma seq_respecte_taux_ds_minore_app (s1 s2 : seq_voeu)
      	    				    (taux_b taux_ds : taux)
    ensures { (seq_respecte_taux_ds_minore taux_b taux_ds s1 &&
    	       seq_respecte_taux_ds_minore taux_b taux_ds s2) ->
    	       seq_respecte_taux_ds_minore taux_b taux_ds (s1 ++ s2) }
  = ()

end

module SeqVoeuxDistincts
  use int.Int
  use seq.Seq
  use SeqVoeux
  use mach.java.lang.Integer
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse_Props
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse

  clone export proofs.lib.distincts.Distincts
  	with type t=voeu, predicate distinct=VoeuClasse_Props.voeu_distinct

  let lemma alld_imp_distinct_ranks (s : seq_voeu)
    requires { all_distincts s }
    ensures { forall i j. 0 <= i < length s -> 0 <= j < length s -> i <> j ->
	             get_rang s[i] <> get_rang s[j] }
  =
    for i = 0 to length s -1 do
      invariant { forall j. 0 <= j < i -> forall k. 0 <= k < i -> k <> j -> get_rang s[k] <> get_rang s[j] }
      for j = 0 to length s - 1 do
        invariant { forall k. 0 <= k < j -> k <> i -> get_rang s[k] <> get_rang s[i] }
        if i <> j then begin
          alld_inst s i j;
          assert { get_rang s[i] <> get_rang s[j] } ;
        end
      done
    done;
    assert { forall i j. 0 <= i < length s -> 0 <= j < length s -> i <> j ->
	           voeu_distinct s[i] s[j] };
    ()
end

module SortedSeqVoeux
  use SeqVoeux
  use seq.Seq
  use proofs.lib.seq.Seq
  use int.Int
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse_Props
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse

  predicate sorted (s : seq_voeu) =
    seq_forall_two voeu_lt s

  predicate seq_all_lt (s1 s2 : seq_voeu) =
    forall i j: int. 0 <= i < length s1 /\ 0 <= j < length s2
    	   -> voeu_lt s1[i] s2[j]

  let lemma sorted_cons (v : voeu) (s : seq_voeu)
   ensures { (seq_forall (voeu_lt v) s /\ sorted s) <-> sorted (cons v s) }
  = ()

  let lemma sorted_append (s1 s2: seq_voeu)
    ensures { (sorted s1 /\ sorted s2 /\ seq_all_lt s1 s2) <-> sorted (s1 ++ s2) }
  = ()

  let lemma sorted_snoc (v : voeu) (s : seq_voeu)
    ensures { (seq_forall (fun v' -> voeu_lt v' v) s /\ sorted s) <-> sorted (snoc s v) }
  = ()

  let lemma sorted_pop (v : voeu) (s : seq_voeu)
    requires { sorted (cons v s) }
    ensures { not seq_contains v s }
  = ()

end

module NbBoursiers
  use int.Int
  use seq.Seq
  use int.NumOf
  use proofs.lib.seq.Seq
  use SeqVoeux
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse_Props
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse

  function nombre_non_boursiers (s: seq_voeu) : int = seq_numof est_non_boursier s

  let lemma nb_snoc (p : voeu -> bool) (d : seq_voeu) (k : int)
    requires { 0 < k <= length d }
    ensures { seq_numof p d[k-1..k] = if p d[k-1] then 1 else 0 }
    ensures { seq_numof p d[..k] = seq_numof p d[..k-1] +  seq_numof p d[k-1..k] }
    ensures { p d[k-1] -> seq_numof p d[..k] = seq_numof p d[..k-1] +  1 }
    ensures { not (p d[k-1]) -> seq_numof p d[..k] = seq_numof p d[..k-1]  }
  =
    assert { d[..k] == d[..k-1] ++ d[k-1..k] }

  let lemma nb_snoc2 (p : voeu -> bool) (s s' : seq_voeu) (l: int)
    requires { 0 < l <= length s = length s' }
    requires { seq_numof p s[..l-1] = seq_numof p s'[..l-1] }
    requires { p s[l-1] <-> p s'[l-1] }
    ensures { seq_numof p s[..l] = seq_numof p s'[..l] }
  = ()

  let lemma nb_boursiers_snoc (d : seq_voeu) (k : int)
    requires { 0 < k <= length d }
    ensures { nb_boursiers d[k-1..k] = if est_boursier d[k-1] then 1 else 0 }
    ensures { nb_boursiers d[..k]
              = nb_boursiers d[..k-1] +  nb_boursiers d[k-1..k] }
    ensures { est_boursier d[k-1]
              -> nb_boursiers d[..k] = nb_boursiers d[..k-1] +  1 }
    ensures { est_non_boursier d[k-1]
              -> nb_boursiers d[..k] = nb_boursiers d[..k-1]  }
  = nb_snoc est_boursier d k

  let lemma nb_boursiers_eq_snoc (s s' : seq_voeu) (l: int)
    requires { 0 < l <= length s = length s' }
    requires { nb_boursiers s[..l-1] = nb_boursiers s'[..l-1] }
    requires { est_boursier s[l-1] <-> est_boursier s'[l-1] }
    ensures { nb_boursiers s[..l] = nb_boursiers s'[..l] }
  = nb_snoc2 est_boursier s s' l

  (* Invariant 2: si deux candidats sont de même type alors ils sont dans le 
     même ordre dans l'ordre d'appel *)

  let lemma nb_boursiers_pos_implique_existe (s : seq_voeu)
    requires { nb_boursiers s > 0 }
    ensures { exists k. (0 <= k < length s /\ est_boursier s[k]) }
  = ()

  let lemma nb_non_boursiers_snoc (d : seq_voeu) (k : int)
    requires { 0 < k <= length d }
    ensures { nombre_non_boursiers d[k-1..k] =
    	      if est_non_boursier d[k-1] then 1 else 0 }
    ensures { nombre_non_boursiers d[..k] =
              nombre_non_boursiers d[..k-1] + nombre_non_boursiers d[k-1..k] }
    ensures { est_non_boursier d[k-1] ->
              nombre_non_boursiers d[..k] = nombre_non_boursiers d[..k-1] + 1 }
    ensures { est_boursier d[k-1] ->
              nombre_non_boursiers d[..k] = nombre_non_boursiers d[..k-1]  }
  = nb_snoc est_non_boursier d k

  let lemma nombre_non_boursiers_snoc2 (s s' : seq_voeu) (l: int)
    requires { 0 < l <= length s = length s' }
    requires { nombre_non_boursiers s[..l-1] = nombre_non_boursiers s'[..l-1] }
    requires { est_non_boursier s[l-1] <-> est_non_boursier s'[l-1] }
    ensures { nombre_non_boursiers s[..l] = nombre_non_boursiers s'[..l] }
  = nb_snoc2 est_non_boursier s s' l

  let rec lemma nb_boursiers_part (s : seq_voeu) (i : int)
    requires { 0 < i <= length s }
    ensures { i = nb_boursiers s[..i] + nombre_non_boursiers s[..i] }
    variant { i }
  =
    if i > 1 then
      nb_boursiers_part s[..i-1] (i-1)

end

module SeqVoeuxInversions
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse_Props

  clone export proofs.lib.inversions.Inversions with type t = VoeuClasse.t, predicate lt = voeu_lt
end

module SeqVoeuxGroupe
  use int.Int
  use seq.Seq
  use seq.Distinct
  use seq.Permut
  use mach.java.lang.Integer
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse
  use proofs.lib.seq.Seq
  use SeqVoeux

  predicate seq_field_uniques_loc (s : seq_voeu) (field : VoeuClasse.t -> integer) (k : int) =
    forall i j. 0 <= i < k -> 0 <= j < k -> i <> j -> field s[i] <> field s[j]

  predicate seq_field_ge_x_loc (s : seq_voeu) (field : VoeuClasse.t -> integer) (x : int) (k : int) =
    forall i. 0 <= i < k -> field s[i] >= x

  predicate seq_field_sorted_loc (s : seq_voeu) (field : VoeuClasse.t -> integer) (k : int) =
    forall i j. 0 <= i < j < k -> field s[i] < field s[j]

  predicate seq_rangs_uniques_loc (s : seq_voeu) (k : int) =
    seq_field_uniques_loc s get_rang k

  predicate seq_rangs_ge_1_loc (s : seq_voeu) (k : int) =
    seq_field_ge_x_loc s get_rang 1 k

  predicate seq_rangs_sorted_loc (s : seq_voeu) (k : int) =
    seq_field_sorted_loc s get_rang k

  predicate seq_rangs_appel_uniques_loc (s : seq_voeu) (k : int) =
    seq_field_uniques_loc s get_rang_appel k

  let lemma seq_rangs_appel_uniques_loc_equiv (s : seq_voeu) (k : int)
    requires { seq_rangs_appel_uniques_loc s k }
    ensures { forall i j. 0 <= i < k -> 0 <= j < k -> i <> j -> s[i].rang_appel <> s[j].rang_appel }
  =
    ()

  predicate seq_rangs_appel_ge_1_loc (s : seq_voeu) (k : int) =
    seq_field_ge_x_loc s get_rang_appel 1 k

  predicate seq_rangs_appel_sorted_loc (s : seq_voeu) (k : int) =
    seq_field_sorted_loc s get_rang_appel k

  predicate seq_g_cn_cod_uniques_loc (s : seq_voeu) (k : int) =
    seq_field_uniques_loc s get_g_cn_cod k

  predicate seq_g_cn_cod_ge_0_loc (s : seq_voeu) (k : int) =
    seq_field_ge_x_loc s get_g_cn_cod 0 k

  predicate seq_field_uniques (s : seq_voeu) (field : VoeuClasse.t -> integer) =
    seq_field_uniques_loc s field (length s)

  predicate seq_field_sorted (s : seq_voeu) (field : VoeuClasse.t -> integer) =
    seq_field_sorted_loc s field (length s)

  predicate seq_rangs_uniques (s : seq_voeu) =
    seq_rangs_uniques_loc s (length s)

  predicate seq_rangs_ge_1 (s : seq_voeu) =
    seq_rangs_ge_1_loc s (length s)

  predicate seq_rangs_sorted (s : seq_voeu) =
    seq_rangs_sorted_loc s (length s)

  predicate seq_rangs_appel_uniques (s : seq_voeu) =
    seq_rangs_appel_uniques_loc s (length s)

  predicate seq_rangs_appel_ge_1 (s : seq_voeu) =
    seq_rangs_appel_ge_1_loc s (length s)

  predicate seq_rangs_appel_contiguous (s : seq_voeu) =
    forall i. 0 <= i < length s -> get_rang_appel s[i] = i + 1

  predicate seq_rangs_appel_sorted (s : seq_voeu) =
    seq_rangs_appel_sorted_loc s (length s)

  predicate seq_g_cn_cod_uniques (s : seq_voeu) =
    seq_g_cn_cod_uniques_loc s (length s)

  predicate seq_g_cn_cod_ge_0 (s : seq_voeu) =
    seq_g_cn_cod_ge_0_loc s (length s)

  predicate seq_groupe_ok (g : seq_voeu) =
       distinct g
    /\ Seq.length g < Integer.max_integer
    /\ seq_rangs_uniques g
    /\ seq_rangs_ge_1 g
    /\ seq_rangs_appel_uniques g
    /\ seq_rangs_appel_ge_1 g
    /\ seq_g_cn_cod_ge_0 g
    /\ seq_g_cn_cod_uniques g

  let lemma seq_field_sorted_cons (v : VoeuClasse.t) (s : seq_voeu) (field : VoeuClasse.t -> integer)
    requires { seq_field_sorted s field }
    requires { forall x. seq_contains x s -> field v < field x }
    ensures { seq_field_sorted (cons v s) field }
  =
    ()

  let lemma seq_field_sorted_append (s1 s2: seq_voeu) (field : VoeuClasse.t -> integer)
    requires { seq_field_sorted s1 field }
    requires { seq_field_sorted s2 field }
    requires { forall v1 v2. seq_contains v1 s1 -> seq_contains v2 s2 -> field v1 < field v2 }
    ensures { seq_field_sorted (s1 ++ s2) field }
  =
    ()

  let lemma seq_field_sorted_snoc (v : voeu) (s : seq_voeu) (field : VoeuClasse.t -> integer)
    requires { seq_field_sorted s field }
    requires { forall x. seq_contains x s -> field x < field v }
    ensures { seq_field_sorted (snoc s v) field }
  =
    ()

  let lemma seq_rangs_sorted_snoc (v : voeu) (s : seq_voeu)
    requires { seq_rangs_sorted s }
    requires { v_is_greater_than_seq s v  }
    ensures { seq_rangs_sorted (snoc s v) }
  =
    assert { forall x. seq_contains x s -> get_rang x < get_rang v }

  let lemma seq_field_sorted_pop (v : voeu) (s : seq_voeu) (field : VoeuClasse.t -> integer)
    requires { seq_field_sorted (cons v s) field }
    ensures { not seq_contains v s }
  =
    assert { forall x. seq_contains x s -> field v < field x }

  let lemma seq_rangs_sorted_pop (v : voeu) (s : seq_voeu)
    requires { seq_rangs_sorted (cons v s) }
    ensures { not seq_contains v s }
    ensures { voeu_lt_than_queue v s }
  =
    ()

  let lemma seq_rangs_sorted_suffix_prefix (s: seq_voeu) (i : int)
    requires { 0 <= i < length s }
    requires { seq_rangs_sorted s }
    ensures { seq_rangs_sorted s[..i] }
    ensures { seq_rangs_sorted s[i..] }
  =
    ()

  let lemma seq_rangs_sorted_shift (s: seq_voeu) (i j : int)
    requires { 0 <= i <= j < length s }
    requires { seq_rangs_sorted s }
    ensures { forall v. seq_contains v s[..i] -> get_rang v < get_rang s[j] }
  =
    ()

  let lemma seq_field_uniques_imp_distinct (s : seq_voeu) (field : VoeuClasse.t -> integer)
    requires { seq_field_uniques_loc s field (length s) }
    ensures { seq_distinct s }
  =
    for i = 0 to length s -1 do
      invariant { forall j k. 0 <= j < i -> 0 <= k < i -> k <> j -> s[j] <> s[k] }
      for j = 0 to length s - 1 do
        invariant { forall k. 0 <= k < j -> k <> i -> s[k] <> s[i] }
        if j = i then continue;
        assert { s[j] = s[i] -> field s[j] = field s[i] };
      done
    done

  let lemma seq_rangs_sorted_imp_distinct (s : seq_voeu)
    requires { seq_rangs_sorted s }
    ensures { seq_distinct s }
  =
    assert { seq_rangs_uniques s }

  let lemma seq_rangs_appel_sorted_imp_distinct (s : seq_voeu)
    requires { seq_rangs_appel_sorted s }
    ensures { seq_distinct s }
  =
    assert { seq_rangs_appel_uniques s }

  let rec lemma seq_rangs_appel_sorted_permut (s1 s2 : seq_voeu)
    requires { seq_rangs_appel_sorted s1 }
    requires { permut_all s1 s2 }
    requires { seq_rangs_appel_sorted s2 }
    ensures { s1 == s2 }
    variant { length s1 }
  =
    if length s1 = 0 then return;
    let j = any (j : int) ensures { 0 <= j < length s2 && s2[j] = s1[0] } in
    if j <> 0 then
    begin
      let i = any (i : int) ensures { 0 <= i < j < length s1 && s1[i] = s2[0] } in
      assert { get_rang_appel s1[i] = get_rang_appel s2[0] < get_rang_appel s2[j] = get_rang_appel s1[0] };
      absurd;
    end;
    seq_rangs_appel_sorted_permut s1[1..] s2[1..]

  let lemma seq_field_uniques_permut (s1 s2 : seq_voeu) (field : VoeuClasse.t -> integer)
    requires { permut_all s1 s2 }
    requires { seq_field_uniques s1 field }
    ensures { seq_field_uniques s2 field }
  =
    ()

  let lemma list_voeu_classe_groupe_ok (g1 g2 : seq_voeu)
    requires { seq_groupe_ok g1 }
    requires { permut_all g1 g2 }
    ensures { seq_groupe_ok g2 }
  =
    assert { seq_rangs_uniques g2 };
    assert { seq_rangs_ge_1 g2 };
    assert { seq_g_cn_cod_ge_0 g2 };
    assert { seq_g_cn_cod_uniques g2 };

  use SeqVoeuxDistincts

  let lemma seq_rangs_uniques_imp_distinct (s : seq_voeu)
    requires { seq_rangs_uniques s }
    ensures { all_distincts s }
  =
    ()
end

module SeqVoeuxEqUpToRangAppel
  use int.Int
  use seq.Seq
  use seq.Distinct
  use seq.Permut
  use proofs.lib.seq.Seq
  use fr.parcoursup.whyml.ordreappel.algo.taux.Taux
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse
  use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.VoeuClasse_Props
  use SeqVoeuxGroupe
  use SeqVoeuxTaux
  use SeqVoeux

  predicate seq_voeu_eq_up_to_rang_appel (s1 s2 : seq_voeu) =
    length s1 = length s2 &&
    forall i. 0 <= i < length s1 -> voeux_classes_eq_up_to_rang_appel s1[i] s2[i]

  let lemma seq_voeu_eq_up_to_rang_appel_groupe_ok (s1 s2 : seq_voeu)
    requires { seq_voeu_eq_up_to_rang_appel s1 s2 }
    requires { seq_groupe_ok s1 }
    requires { seq_rangs_appel_uniques s2 }
    requires { seq_rangs_appel_ge_1 s2 }
    ensures { seq_groupe_ok s2 }
  =
    assert { seq_rangs_uniques s2 };
    assert { seq_rangs_ge_1 s2 };
    assert { seq_g_cn_cod_ge_0 s2 };
    assert { seq_g_cn_cod_uniques s2 }

  let lemma seq_voeu_eq_up_to_rang_appel_props1 (s1 s2 : seq_voeu)
    requires { seq_voeu_eq_up_to_rang_appel s1 s2 }
    ensures { forall k. 0 <= k <= length s1 -> nb_boursiers s1[..k] = nb_boursiers s2[..k] }
    ensures { nb_boursiers s1 = nb_boursiers s2 }
  =
    seq_numof_eq_prefix s1 s2 est_boursier;
    seq_numof_equiv s1 s2 est_boursier

  let lemma seq_voeu_eq_up_to_rang_appel_props2 (s1 s2 : seq_voeu)
    requires { seq_voeu_eq_up_to_rang_appel s1 s2 }
    ensures { forall k. 0 <= k <= length s1 -> nb_du_secteur s1[..k] = nb_du_secteur s2[..k] }
    ensures { nb_du_secteur s1 = nb_du_secteur s2 }
  =
    seq_numof_eq_prefix s1 s2 est_du_secteur;
    seq_numof_equiv s1 s2 est_du_secteur

  let lemma seq_voeu_eq_up_to_rang_appel_props3 (tx : Taux.t) (s1 s2 : seq_voeu)
    requires { seq_voeu_eq_up_to_rang_appel s1 s2 }
    ensures { forall k. 0 <= k <= length s1 -> seq_respecte_taux_b tx s1[..k] = seq_respecte_taux_b tx s2[..k] }
  =
    seq_voeu_eq_up_to_rang_appel_props1 s1 s2;
    assert { forall k. 0 <= k <= length s1 -> nb_boursiers s1[..k] = nb_boursiers s2[..k] };
    assert { forall k. 0 <= k <= length s1 -> taux_ok tx (nb_boursiers s1[..k]) k = taux_ok tx (nb_boursiers s2[..k]) k }

 let lemma seq_voeu_eq_up_to_rang_appel_props4 (tx : Taux.t) (s1 s2 : seq_voeu)
    requires { seq_voeu_eq_up_to_rang_appel s1 s2 }
    ensures { forall k. 0 <= k <= length s1 -> seq_respecte_taux_ds tx s1[..k] = seq_respecte_taux_ds tx s2[..k] }
  =
    seq_voeu_eq_up_to_rang_appel_props2 s1 s2

 let lemma seq_voeu_eq_up_to_rang_appel_props5  (s1 s2 : seq_voeu)
    requires { seq_voeu_eq_up_to_rang_appel s1 s2 }
    ensures { forall k. 0 <= k < length s1 -> non_boursiers_seulement s1[k..] = non_boursiers_seulement s2[k..] }
  =
    seq_forall_eq_suffix s1 s2 est_non_boursier

 let lemma seq_voeu_eq_up_to_rang_appel_props6 (s1 s2 : seq_voeu)
    requires { seq_voeu_eq_up_to_rang_appel s1 s2 }
    ensures { forall k. 0 <= k < length s1 -> hors_secteur_seulement s1[k..] = hors_secteur_seulement s2[k..] }
  =
    seq_forall_eq_suffix s1 s2 est_hors_secteur

  predicate seq_voeu_permut_up_to_rang_appel (s1 s2 : seq_voeu) =
    exists s1p. permut_all s1 s1p && seq_voeu_eq_up_to_rang_appel s1p s2

  let lemma seq_voeu_rangs_sorted_eq_up_to_rang_appel (op1 oa op2 : seq_voeu)
    requires { [@expl:op1 sorted] seq_rangs_sorted op1 }
    requires { [@expl:op1 = oa (mod ra)] seq_voeu_permut_up_to_rang_appel op1 oa }
    requires { [@expl:oa permut op2] permut_all oa op2 }
    requires { [@expl:op1 sorted] seq_rangs_sorted op2 }
    ensures { [@expl:op1 = op2 (mod ra)] seq_voeu_eq_up_to_rang_appel op1 op2 }
  =
    let lemma aux1 (i : int) : (k : int)
      requires { 0 <= i < length op2 }
      ensures { 0 <= k < length op1 }
      ensures { voeux_classes_eq_up_to_rang_appel op1[k] op2[i] }
    =
      let j = any (j : int) ensures { 0 <= j < length oa && oa[j] = op2[i] } in
      let op1p = any (op1p : seq_voeu) ensures { permut_all op1 op1p && seq_voeu_eq_up_to_rang_appel op1p oa } in
      let k = any (k : int) ensures { 0 <= k < length op1 && op1[k] = op1p[j] } in
      k
    in
    let lemma aux2 (k : int) : (i : int)
      requires { 0 <= k < length op1 }
      ensures { 0 <= i < length op2 }
      ensures { voeux_classes_eq_up_to_rang_appel op1[k] op2[i] }
    =
      let op1p = any (op1p : seq_voeu) ensures { permut_all op1 op1p && seq_voeu_eq_up_to_rang_appel op1p oa } in
      let j = any (j : int) ensures { 0 <= j < length op1 && op1[k] = op1p[j] } in
      let i = any (i : int) ensures { 0 <= i < length oa && oa[j] = op2[i] } in
      i
    in
    for i = 0 to length op1 - 1 do
      invariant { forall k. 0 <= k < i -> voeux_classes_eq_up_to_rang_appel op1[k] op2[k] }
      let k = aux1 i in
      assert { voeux_classes_eq_up_to_rang_appel op1[k] op2[i] };

      if k = i then
        continue;

      if k < i then
        assert { voeux_classes_eq_up_to_rang_appel op1[k] op2[k] }
      else if i < k then begin
        let j = aux2 i in
        assert { j = i };
      end;
      absurd
    done

end

(* generated on Thu Nov 21 02:04:27 UTC 2024 from rev:  *)

Generated by why3doc 1.7.2+git