Parcoursup / Calcul de l'ordre d'appel des candidats index
module CalculOrdreAppelGroupe [@java:package:fr.parcoursup.whyml.ordreappel.algo] [@java:visibility:package] use ref.Ref use int.Int use seq.Seq use seq.Permut use mach.java.lang.Long use mach.java.lang.Integer use mach.java.lang.IndexOutOfBoundsException use mach.java.util.List as L use mach.java.util.UnmodifiableList as UL use proofs.lib.seq.Seq use proofs.ordre_appel.seq_voeux.SeqVoeux use proofs.ordre_appel.seq_voeux.SeqVoeuxTaux use proofs.ordre_appel.seq_voeux.SeqVoeuxGroupe use proofs.ordre_appel.seq_voeux.SeqVoeuxDistincts use proofs.ordre_appel.seq_voeux.SeqVoeuxEqUpToRangAppel use proofs.ordre_appel.specs.Invariants_Snoc use proofs.ordre_appel.invariants.iq0.IQ0_Lemmas use proofs.ordre_appel.specs.GroupeClassementValideProperties 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 fr.parcoursup.whyml.ordreappel.algo.enum_map.EnumMap use fr.parcoursup.whyml.ordreappel.algo.enum_map.AllDistincts use fr.parcoursup.whyml.ordreappel.algo.groupe_classement_valide.GroupeClassementValide use fr.parcoursup.whyml.exceptions.verification_exception.VerificationException use proofs.ordre_appel.eligibles.Eligibles use proofs.ordre_appel.eligibles.ValidEligibles use fr.parcoursup.whyml.ordreappel.algo.voeu_classe.PQueueVoeuxClasses as PQueue let function int_to_type_candidat [@java:visibility:private] (i : integer) : (r : type_candidat) requires { 1 <= i <= 4 } ensures { i = 1 -> r = BOURSIER_DU_SECTEUR } ensures { i = 2 -> r = BOURSIER_HORS_SECTEUR } ensures { i = 3 -> r = NON_BOURSIER_DU_SECTEUR } ensures { i = 4 -> r = NON_BOURSIER_HORS_SECTEUR } = if i = 1 then BOURSIER_DU_SECTEUR else if i = 2 then BOURSIER_HORS_SECTEUR else if i = 3 then NON_BOURSIER_DU_SECTEUR else begin assert { i = 4 }; NON_BOURSIER_HORS_SECTEUR end let ghost function type_candidat_to_int (tc : type_candidat) : (i : integer) ensures { 1 <= i <= 4 } ensures { int_to_type_candidat i = tc } = match tc with | BOURSIER_DU_SECTEUR -> 1 | BOURSIER_HORS_SECTEUR -> 2 | NON_BOURSIER_DU_SECTEUR -> 3 | NON_BOURSIER_HORS_SECTEUR -> 4 end let calcul_eligibles [@java:visibility:private] (cB cR : bool) (files_attente : EnumMap.t) : PQueue.t requires { [@expl:pre/files_attente not empty] not enummap_is_empty files_attente } requires { [@expl:pre/alld(files_attente)] enummap_all_distincts files_attente } requires { [@expl:pre/constraints ->remains] eligibles_constraints_imp_remain cB cR files_attente } ensures { eligibles_contains_eligible_heads cB cR files_attente result } ensures { valid_eligibles cB cR files_attente result } = let eligibles = PQueue.create () in for i = 1 to 4 do invariant { forall k : integer. 1 <= k < i <= 5 -> let t = int_to_type_candidat k in let q = get_queue files_attente t in q <> Seq.empty -> let v = Seq.get q 0 in est_eligible_p cB cR v -> Fset.mem v eligibles } invariant { forall v. (Fset.mem v eligibles) -> (enummap_v_is_head files_attente v /\ est_eligible_p cB cR v)} let t = int_to_type_candidat i in if EnumMap.queue_is_empty files_attente t then assert { Seq.(==) (get_queue files_attente t) Seq.empty } else let voe = EnumMap.peek files_attente t in if ((est_boursier voe || not cB) && (est_du_secteur voe || not cR)) then begin assert { est_eligible_p cB cR voe }; assert { enummap_v_is_head files_attente voe /\ est_eligible_p cB cR voe }; PQueue.add eligibles voe; end; done; assert { forall v. (enummap_v_is_head files_attente v /\ est_eligible_p cB cR v) -> (Fset.mem v eligibles) }; eligibles_conditions cB cR files_attente; eligibles let selectionner_meilleur_voeu [@java:visibility:private] (cB cR : bool) (nb_b nb_ds : integer) (tx_b tx_ds : Taux.t) (grp : UL.ulist VoeuClasse.t) (oa : L.list VoeuClasse.t) (files_attente : EnumMap.t) : (meilleur : VoeuClasse.t) requires { [@expl:grp ok] seq_groupe_ok grp } requires { [@expl:grp sorted] seq_rangs_sorted grp } requires { [@expl:InvAlgo] invariants_algo nb_b nb_ds tx_b tx_ds grp oa files_attente } requires { [@expl:files_attente not empty] not enummap_is_empty files_attente } requires { [@expl:cB implies constraint on tx_b] cB -> taux_b_contraignant tx_b oa nb_b } requires { [@expl:constraint on tx_b implies cB] taux_b_contraignant tx_b oa nb_b -> cB } requires { [@expl:cR implies constraint on tx_ds] cR -> taux_ds_contraignant tx_ds oa nb_ds } requires { [@expl:constraint on tx_ds implies cR] taux_ds_contraignant tx_ds oa nb_ds -> cR } ensures {[@expl:InvAlgo(oak.res)] invariants_algo nb_b nb_ds tx_b tx_ds grp (snoc oa meilleur) files_attente } = let eligibles = calcul_eligibles cB cR files_attente in let meilleur = if not PQueue.is_empty eligibles then let r = PQueue.peek eligibles in begin assert { enummap_v_is_head files_attente r }; assert { meilleur_eligible cB cR files_attente eligibles r }; r end else begin assert { cB \/ cR }; assert { (EnumMap.get_queue files_attente BOURSIER_DU_SECTEUR) == Seq.empty }; assert { not EnumMap.queue_is_empty files_attente BOURSIER_HORS_SECTEUR }; let r = EnumMap.peek files_attente BOURSIER_HORS_SECTEUR in assert { meilleur_eligible cB cR files_attente eligibles r }; r end in assert { meilleur_eligible cB cR files_attente eligibles meilleur }; let poll = EnumMap.pop files_attente (get_type_candidat meilleur) in assert { [@expl:meilleur is popped] poll = meilleur }; meilleur let contrainte_taux [@java:visibility:private] (x_total x_appeles nb_appeles : integer) (taux_x : Taux.t) : bool requires { [@expl:#x appeles <= #appeles] 0 <= x_appeles <= nb_appeles } requires { [@expl:#X appeles <= #x total] 0 <= x_appeles <= x_total } ensures { result = (x_appeles < x_total && x_appeles * 100 < taux_x * (1 + nb_appeles)) } = let x_appeles_long = Long.of_integer x_appeles in let nb_appeles_long = Long.of_integer nb_appeles in let taux_x_long = Long.of_integer taux_x.tx in x_appeles < x_total && x_appeles_long * 100 < taux_x_long * (1 + nb_appeles_long) let calcul_ordre_appel [@java:visibility:private] (g : GroupeClassementValide.t) : (oa: L.list VoeuClasse.t) ensures { Properties.ordre_appel_properties (nb_boursiers g) (nb_du_secteur g) (get_taux_min_boursiers g) (get_taux_min_du_secteur g) (get_ordre_pedagogique g) oa } ensures { permut_all g oa } = let ordre_pedago = get_ordre_pedagogique g in let ordre_appel : L.list VoeuClasse.t = L.empty () in let nb_voeux = GroupeClassementValide.get_nb_voeux_classes g in let tx_b = GroupeClassementValide.get_taux_min_boursiers g in let tx_r = GroupeClassementValide.get_taux_min_du_secteur g in let nb_appeles : ref integer = ref 0 in let nb_boursiers_appeles : ref integer = ref 0 in let nb_residents_appeles : ref integer = ref 0 in let files_attente : EnumMap.t = EnumMap.from_groupe ordre_pedago in let nb_boursiers_total : integer = EnumMap.get_nb_boursiers files_attente in let nb_residents_total : integer = EnumMap.get_nb_du_secteur files_attente in assert { nb_boursiers_total <= nb_voeux }; assert { nb_residents_total <= nb_voeux }; while L.size ordre_appel < nb_voeux do invariant { [@expl:InvAlgo] invariants_algo nb_boursiers_total nb_residents_total tx_b tx_r ordre_pedago ordre_appel files_attente } invariant { [@expl:#App] !nb_appeles = Seq.length ordre_appel } invariant { [@expl:#B App] !nb_boursiers_appeles = nb_boursiers ordre_appel } invariant { [@expl:#DS App] !nb_residents_appeles = nb_du_secteur ordre_appel } invariant { [@expl:#App bounds] !nb_appeles <= nb_voeux } invariant { [@expl:#B bounds] !nb_boursiers_appeles <= nb_boursiers_total && !nb_boursiers_appeles <= !nb_appeles } invariant { [@expl:#DS bounds] !nb_residents_appeles <= nb_residents_total && !nb_residents_appeles <= !nb_appeles } variant { nb_voeux - Seq.length ordre_appel } let contrainte_taux_boursier = contrainte_taux nb_boursiers_total !nb_boursiers_appeles !nb_appeles tx_b in let contrainte_taux_resident = contrainte_taux nb_residents_total !nb_residents_appeles !nb_appeles tx_r in let meilleur : VoeuClasse.t = selectionner_meilleur_voeu contrainte_taux_boursier contrainte_taux_resident nb_boursiers_total nb_residents_total tx_b tx_r ordre_pedago ordre_appel files_attente in assert { invariants_algo nb_boursiers_total nb_residents_total tx_b tx_r ordre_pedago (snoc ordre_appel meilleur) files_attente }; let _ = L.add ordre_appel meilleur in nb_appeles := !nb_appeles + 1; if est_boursier meilleur then nb_boursiers_appeles := !nb_boursiers_appeles + 1; if est_du_secteur meilleur then nb_residents_appeles := !nb_residents_appeles + 1; done; iq0_m_empty (UL.content ordre_pedago) (L.content ordre_appel) files_attente; ordre_appel let calculer_ordre_appel (grp : GroupeClassementValide.t) : (res : GroupeClassementValide.t) ensures { [@expl:res ok] groupe_ok res } ensures { [@expl:ra >= 1] seq_rangs_appel_ge_1 res } ensures { [@expl:ra uniques] seq_rangs_appel_uniques res } ensures { [@expl:grp = res (mod ra)] seq_voeu_permut_up_to_rang_appel grp res } ensures { [@expl:op(grp) = op(res) (mod ra)] seq_voeu_permut_up_to_rang_appel (get_ordre_pedagogique grp) (get_ordre_pedagogique res) } ensures { [@expl:specs res] ordre_appel_properties res } ensures { [@expl:c_gp_cod grp = res] c_gp_cod grp = c_gp_cod res } ensures { [@expl:|grp| = |res|] get_nb_voeux_classes grp = get_nb_voeux_classes res } ensures { [@expl:tx_b grp = res] get_taux_min_boursiers_pourcents grp = get_taux_min_boursiers_pourcents res } ensures { [@expl:tx_r grp = res] get_taux_min_du_secteur_pourcents grp = get_taux_min_du_secteur_pourcents res } ensures { ordre_appel_contiguous res } = try let tmp = calcul_ordre_appel grp in assert { seq_groupe_ok tmp }; let nb_v = L.size tmp in let oa = L.empty () in for i = 0 to nb_v - 1 do invariant { i = L.size oa } invariant { forall k. 0 <= k < i -> oa[k].rang_appel = (k+1) >=1 } invariant { seq_field_ge_x_loc oa get_rang_appel 1 i } invariant { forall k l. 0 <= k < l < i -> oa[k].rang_appel < oa[l].rang_appel } invariant { forall k. 0 <= k < i -> eq_up_to_rang_appel tmp[k] oa[k] } let v = L.get tmp i in let nv = set_rang_appel v (i+1) in alld_snoc nv (L.content oa); label H in let _ = L.add oa nv in assert { oa[i].rang_appel = (i+1) /\ oa = snoc (oa at H) nv }; assert { tmp[..i+1] = snoc tmp[..i] v /\ eq_up_to_rang_appel v nv /\ v = tmp[i] /\ nv = oa[i] }; done; assert { seq_field_ge_x_loc oa get_rang_appel 1 nb_v }; assert { [@expl:oa / ra >= 1] seq_rangs_appel_ge_1 oa }; assert { [@expl:tmp = oa (mod ra)] seq_voeu_eq_up_to_rang_appel tmp oa }; assert { forall k l. 0 <= k < l < nb_v -> oa[k].rang_appel < oa[l].rang_appel }; assert { [@expl:oa / sorted] seq_rangs_appel_sorted_loc oa nb_v }; assert { [@expl:oa / sorted] seq_rangs_appel_sorted oa }; assert { [@expl:oa / ra uniques] seq_rangs_appel_uniques oa }; assert { [@expl:oa / groupe ok oa] seq_groupe_ok oa }; assert { [@expl:alld(oa)] all_distincts oa }; let res = groupe_classement_valide_from_oa grp oa in assert { [@expl:op grp = op res (mod ra)] seq_voeu_eq_up_to_rang_appel (get_ordre_pedagogique grp) (get_ordre_pedagogique res) }; oap_up_to_rang_appel_groupe grp (L.content oa) res; res with VerificationException.E _ -> absurd | IndexOutOfBoundsException.E _ -> absurd end; end (* generated on Thu Nov 21 02:04:27 UTC 2024 from rev: *)
Generated by why3doc 1.7.2+git