Parcoursup / Calcul de l'ordre d'appel des candidats index
module Sum2d use int.Int use proofs.lib.pair.Pair use int.Sum function sum1d (f : pair -> int) (nj : int) : (int -> int) = fun i -> sum ( fun j -> f (mkp i j)) 0 nj function sum2d (f : pair -> int) (ni nj : int) : int = sum (sum1d f nj) 0 ni let function prec (p : pair) (nj : int) : pair = if p.j = 0 then (mkp (p.i -1) (nj-1)) else (mkp p.i (p.j-1)) let function succ (p : pair) (ni nj : int) : pair requires { pair_lt p (mkp (ni-1) nj) } = if p.j = (nj-1) then (mkp (p.i + 1) 0 ) else mkp p.i (p.j + 1) function minus (f g : pair -> int) : (pair -> int) = fun p -> (f p) - (g p) end module SumBasics use int.Int use int.Sum use proofs.lib.pair.Pair use export Sum2d let lemma sum2d_eq (f g : pair -> int) (ni nj : int) requires { forall p. 0 <= p.i < ni -> 0 <= p.j < nj -> f p = g p } ensures { sum2d f ni nj = sum2d g ni nj } = () let lemma sum_pos (f : int -> int) (n : int) requires { forall i. 0<= i < n -> f i >= 0 } ensures { sum f 0 n >= 0 } = () let lemma sum1d_pos (f : pair -> int) (nj : int) requires { forall p. f p >= 0 } ensures { forall i. sum1d f nj i >= 0 } = () let lemma sum2d_pos (f : pair -> int) (ni nj : int) requires { forall i j. f (mkp i j) >= 0 } ensures { sum2d f ni nj >= 0 } = sum1d_pos f nj; sum_pos (fun i -> sum1d f nj i) ni let lemma sum2d_small (f : pair -> int) requires { f (mkp 0 0) = 0 } ensures { sum2d f 1 1 = 0 } = assert { sum2d f 1 1 = f (mkp 0 0) } end module SumPath use int.Int use proofs.lib.pair.Pair use int.Sum use Sum2d let rec function sum_path (f : pair -> int) (ni nj : int) (pmin pmax: pair) requires { in_rect pmin ni nj } requires { in_rect pmax ni nj \/ (pmax.i = ni /\ pmax.j = 0) } requires { not pair_lt pmax pmin } variant { pmax.i, pmax.j } = if pair_eq pmin pmax then 0 else f (prec pmax nj) + sum_path f ni nj pmin (prec pmax nj) function projection (f : pair -> int) (i : int) : (int -> int) = fun j -> f (mkp i j) let lemma sum_proj (f : pair -> int) (i nj : int) ensures { sum (projection f i) 0 nj = (sum1d f nj) i } = () let rec lemma sum_path_carac_aux (f : pair -> int) (ni nj : int) (pmin pmax: pair) requires {in_rect pmin ni nj} requires {in_rect pmax ni nj \/ pair_eq pmax (mkp ni 0)} requires { not pair_lt pmax pmin } ensures { sum_path f ni nj pmin pmax = sum (sum1d f nj) pmin.i pmax.i - sum (projection f pmin.i) 0 pmin.j + sum (projection f pmax.i) 0 pmax.j } variant { pmax.i, pmax.j } = ( if not pair_eq pmin pmax then begin let sp = sum_path f ni nj pmin pmax in let pmax' = prec pmax nj in let sp' = sum_path f ni nj pmin pmax' in assert { sp = sp' + f pmax'}; if pmax'.i = pmax.i then begin sum_path_carac_aux f ni nj pmin pmax'; assert { sum (projection f pmax.i) 0 pmax.j = sum (projection f pmax'.i) 0 pmax'.j + f pmax' }; end else if pair_lt (mkp 0 0) pmax then begin assert { pmax.j = 0 }; assert { pmax'.i = pmax.i - 1 }; assert { sum (fun j -> f (mkp pmax'.i j)) 0 nj = sum (projection f pmax'.i) 0 nj}; let sl = sum (projection f pmin.i) 0 pmin.j in sum_path_carac_aux f ni nj pmin pmax'; sum_proj f pmax'.i nj; assert { sp' + f pmax' = sum (sum1d f nj) pmin.i pmax'.i - sl + sum (projection f pmax'.i) 0 pmax'.j + f pmax' = sum (sum1d f nj) pmin.i pmax'.i - sl + sum (projection f pmax'.i) 0 nj = sum (sum1d f nj) pmin.i pmax'.i - sl + (sum1d f nj) pmax'.i = sum (sum1d f nj) pmin.i pmax.i - sl }; end end ) let rec lemma sum_path_carac (f : pair -> int) (ni nj : int) requires { 1 <= ni } requires { 1 <= nj } ensures { sum2d f ni nj = sum_path f ni nj (mkp 0 0) (mkp ni 0) } = ( ) let rec lemma sum_path_split (f : pair -> int) (ni nj : int) (pmin pmid pmax: pair) requires { in_rect pmin ni nj } requires { in_rect pmid ni nj } requires { in_rect pmax ni nj \/ (pmax.i = ni /\ pmax.j = 0) } requires { not pair_lt pmax pmid } requires { not pair_lt pmid pmin } ensures { sum_path f ni nj pmin pmax = sum_path f ni nj pmin pmid + sum_path f ni nj pmid pmax } variant { pmax.i , pmax.j, ni - pmin.i, nj - pmin.j } = ( if (not pair_eq pmid pmax) && (not pair_eq pmin pmid) then begin assert { pair_lt pmid pmax }; assert { pair_lt pmin pmid }; let pmax' = (prec pmax nj) in sum_path_split f ni nj pmin pmid pmax'; assert { sum_path f ni nj pmin pmax = sum_path f ni nj pmin pmax' + f pmax'}; assert { sum_path f ni nj pmin pmax = sum_path f ni nj pmin pmid + sum_path f ni nj pmid pmax } end ) let lemma sum_path_split_pivot (f : pair -> int) (ni nj : int) (pmin pmid pmax: pair) requires { in_rect pmin ni nj } requires { in_rect pmid ni nj } requires { in_rect pmax ni nj \/ (pmax.i = ni /\ pmax.j = 0) } requires { not pair_lt pmid pmin } requires { pair_lt pmid pmax } ensures { let pmid' = (succ pmid ni nj) in sum_path f ni nj pmin pmax = sum_path f ni nj pmin pmid + f pmid + if pair_lt pmid' pmax then sum_path f ni nj pmid' pmax else 0 } = ( sum_path_split f ni nj pmin pmid pmax; if not (pmid.i = ni-1 && pmid.j = nj-1) then begin let pmid' = (succ pmid ni nj) in sum_path_split f ni nj pmid pmid' pmax; end ) let rec lemma sum_path_non_neg (f : pair -> int) (ni nj : int) (pmin pmax: pair) requires { in_rect pmin ni nj } requires { in_rect pmax ni nj \/ (pair_eq pmax (mkp ni 0) )} requires { not pair_lt pmax pmin } requires { forall p. in_rect p ni nj -> pair_lt p pmax -> not pair_lt p pmin -> f p >= 0 } ensures { sum_path f ni nj pmin pmax >= 0 } variant { pmax.i, pmax.j } = ( if pair_lt pmin pmax then begin let sp = sum_path f ni nj pmin pmax in let pmax' = prec pmax nj in let sp' = sum_path f ni nj pmin pmax' in assert { sp = sp' + f pmax'}; assert { in_rect pmax' ni nj }; assert { not pair_lt pmax' pmin }; assert { pair_lt pmax' pmax }; assert { f pmax' >= 0 }; sum_path_non_neg f ni nj pmin (prec pmax nj); assert { sp' >= 0 }; end ) let rec lemma sum_path_minus (f g : pair -> int) (ni nj : int) (pmin pmax: pair) requires { in_rect pmin ni nj } requires { in_rect pmax ni nj \/ (pair_eq pmax (mkp ni 0) )} requires { not pair_lt pmax pmin } ensures { sum_path (minus f g) ni nj pmin pmax = (sum_path f ni nj pmin pmax) - (sum_path g ni nj pmin pmax) } variant { pmax.i, pmax.j} =( if pair_lt pmin pmax then let pmax' = prec pmax nj in sum_path_minus f g ni nj pmin pmax' ) let rec lemma sum_path_lte (f g : pair -> int) (ni nj : int) (pmin pmax: pair) requires { in_rect pmin ni nj } requires { in_rect pmax ni nj \/ (pair_eq pmax (mkp ni 0) )} requires { forall p. in_rect p ni nj -> not pair_lt p pmin -> pair_lt p pmax -> f p <= g p } requires { not pair_lt pmax pmin } ensures { sum_path f ni nj pmin pmax <= sum_path g ni nj pmin pmax } = ( sum_path_non_neg (minus g f ) ni nj pmin pmax; assert { 0<= sum_path (minus g f ) ni nj pmin pmax }; sum_path_minus g f ni nj pmin pmax; ) let rec lemma sum_path_eq (f g : pair -> int) (ni nj : int) (pmin pmax: pair) requires { in_rect pmin ni nj } requires { in_rect pmax ni nj \/ (pair_eq pmax (mkp ni 0) )} requires { forall p. in_rect p ni nj -> not pair_lt p pmin -> pair_lt p pmax -> f p = g p } requires { not pair_lt pmax pmin } ensures { sum_path f ni nj pmin pmax = sum_path g ni nj pmin pmax } = ( sum_path_lte f g ni nj pmin pmax; sum_path_lte g f ni nj pmin pmax; ) end module Linearity use int.Int use proofs.lib.pair.Pair use int.Sum use Sum2d use SumPath as SP let lemma sum2d_minus (f g : pair -> int) (ni nj : int) requires { 1 <= ni /\ 1 <= nj } ensures { sum2d (minus f g) ni nj = (sum2d f ni nj) - (sum2d g ni nj) } = ( let pmin = mkp 0 0 in let pmax = mkp ni 0 in SP.sum_path_minus f g ni nj pmin pmax ) let lemma sum2d_split (f : pair -> int) (ni nj : int) (p0 p1 : pair) requires { in_rect p0 ni nj /\ in_rect p1 ni nj } requires { pair_lt p0 p1 } ensures { let pmin = mkp 0 0 in let pmax = mkp ni 0 in let p0' = succ p0 ni nj in let p1' = succ p1 ni nj in sum2d f ni nj = SP.sum_path f ni nj pmin p0 + f p0 + SP.sum_path f ni nj p0' p1 + f p1 + if pair_lt p1' pmax then SP.sum_path f ni nj p1' pmax else 0 } =( let pmin = mkp 0 0 in let pmax = mkp ni 0 in SP.sum_path_split_pivot f ni nj pmin p0 pmax; SP.sum_path_split_pivot f ni nj p0 p1 pmax; ) end module SemiLinearity use int.Int use proofs.lib.pair.Pair use int.Sum use Sum2d use SumPath as SP let lemma sum2d_pos (f : pair -> int) (ni nj : int) (p0 : pair) requires { forall p. in_rect p ni nj -> 0 <= f p } requires { in_rect p0 ni nj /\ 0 < f p0 } ensures { 0 < sum2d f ni nj } = ( let pmin = (mkp 0 0) in let pmax = (mkp ni 0) in SP.sum_path_non_neg f ni nj pmin p0; if pair_lt p0 (mkp (ni-1) (nj -1)) then begin let p0' = (succ p0 ni nj) in SP.sum_path_split_pivot f ni nj pmin p0 pmax; SP.sum_path_non_neg f ni nj p0' pmax; end ) let lemma sum2d_lte (f g : pair -> int) (ni nj : int) requires { 1 <= ni /\ 1 <= nj } requires { forall p. in_rect p ni nj -> f p <= g p } ensures { sum2d f ni nj <= sum2d g ni nj } = ( let pmin = (mkp 0 0) in let pmax = (mkp ni 0) in SP.sum_path_lte f g ni nj pmin pmax; ) let rec lemma sum2d_lt (f g : pair -> int) (ni nj : int) (p0 : pair) requires { forall p. in_rect p ni nj -> f p <= g p } requires { in_rect p0 ni nj /\ f p0 < g p0 } ensures { sum2d f ni nj < sum2d g ni nj } = ( sum2d_pos (minus g f ) ni nj p0 ) end module Permutation use proofs.lib.pair.Pair use Sum2d use int.Int use Linearity as L use SemiLinearity as S use SumPath as SP predicate is_involution (phi : pair -> pair ) (ni nj : int) = forall p. in_rect p ni nj -> (in_rect (phi p) ni nj /\ phi (phi p) = p) let function (@) (f : pair -> int) (phi : pair -> pair) = fun p -> f (phi p) let function transpose (p0 p1 : pair) : (pair -> pair) = fun p -> if pair_eq p p0 then p1 else if pair_eq p p1 then p0 else p let function compose (phi1 phi2 : pair -> pair) : (pair -> pair) = fun p -> phi1 (phi2 p) let lemma sum_transp (f f' : pair -> int) (p0 p1 : pair) (ni nj : int) requires { in_rect p0 ni nj } requires { in_rect p1 ni nj } requires { pair_lt p0 p1 } requires { f' = f @ transpose p0 p1 } ensures { sum2d f ni nj = sum2d f' ni nj } = ( let pmin = (mkp 0 0) in let pmax = (mkp ni 0) in let p0' = succ p0 ni nj in let p1' = succ p1 ni nj in assert { forall p. in_rect p ni nj /\ not pair_eq p p0 /\ not pair_eq p p1 -> f p = f' p }; SP.sum_path_eq f f' ni nj pmin p0; SP.sum_path_eq f f' ni nj p0' p1; if pair_lt p1' pmax then SP.sum_path_eq f f' ni nj p1' pmax; L.sum2d_split f ni nj p0 p1; L.sum2d_split f' ni nj p0 p1; assert { f p0 = f' p1 }; assert { f p1 = f' p0 }; assert { sum2d f ni nj = SP.sum_path f ni nj pmin p0 + f p0 + SP.sum_path f ni nj p0' p1 + f p1 + (if pair_lt p1' pmax then SP.sum_path f ni nj p1' pmax else 0) = SP.sum_path f' ni nj pmin p0 + f p0 + SP.sum_path f' ni nj p0' p1 + f p1 + (if pair_lt p1' pmax then SP.sum_path f' ni nj p1' pmax else 0) = SP.sum_path f' ni nj pmin p0 + f' p1 + SP.sum_path f' ni nj p0' p1 + f' p0 + (if pair_lt p1' pmax then SP.sum_path f' ni nj p1' pmax else 0) = SP.sum_path f' ni nj pmin p0 + f' p0 + SP.sum_path f' ni nj p0' p1 + f' p1 + (if pair_lt p1' pmax then SP.sum_path f' ni nj p1' pmax else 0) = sum2d f' ni nj } ) let function swap (phi : pair -> pair) (p0 : pair) : (pair -> pair) = compose phi (transpose p0 (phi p0)) let lemma invol_swap (phi : pair -> pair) (p0 : pair) (ni nj : int) requires { in_rect p0 ni nj } requires { is_involution phi ni nj } ensures { is_involution (swap phi p0) ni nj } = () let function umkp (p : pair) (ni nj: int) : int = (ni - p.i) * (nj+1) + (nj - p.j) let lemma mult_pos (i j: int) requires { i>= 0 && j >= 0 } ensures { i* j >= 0 } = () let lemma umkp_dec (p0 p1 : pair) (ni nj: int) requires { in_rect p0 ni nj \/ pair_eq p0 (mkp ni 0) } requires { in_rect p1 ni nj } requires { pair_lt p1 p0 } ensures { 0 <= umkp p0 ni nj < umkp p1 ni nj } =( assert { p0.i > p1.i \/ (p0.i = p1.i /\ p0.j > p1.j) }; if p0.i > p1.i then begin let a = (ni - p0.i + 1) in let b = (ni - p1.i) in let x = (nj+1) in assert { 0 <= a <= b }; assert { 0 <= x } ; mult_pos a x; assert { 0 <= a * x }; assert { a * x <= b * x }; assert { a *x = (ni - p0.i) * (nj+1) + (nj+1) }; assert { b *x = (ni - p1.i) * (nj+1) }; assert { 0 <= (ni - p0.i) * (nj+1) + (nj+1) <= (ni - p1.i) * (nj+1) }; assert { 0 <= (ni - p0.i) * (nj+1) + (nj - p0.j) < (ni - p1.i) * (nj+1) }; assert { 0 <= (ni - p0.i) * (nj+1) + (nj - p0.j) < (ni - p1.i) * (nj+1) + (nj - p1.j) }; end ) let rec function first_diff (phi : pair -> pair) (ni nj : int) (p0 : pair) : pair requires { p0 = mkp ni 0 \/ in_rect p0 ni nj } requires { forall p. in_rect p ni nj -> pair_lt p p0 -> phi p = p } ensures { forall p. in_rect p ni nj -> pair_lt p result -> phi p = p } ensures { result = mkp ni 0 \/ (in_rect result ni nj /\ phi result <> result) } variant { ni - p0.i, nj - p0.j } = ( if p0.i = ni && p0.j = 0 then p0 else if pair_neq p0 (phi p0) then p0 else if p0.j = nj-1 then first_diff phi ni nj (mkp (p0.i +1) 0) else first_diff phi ni nj (mkp p0.i (p0.j +1) ) ) let rec lemma sum_permut_aux (f : pair -> int) (g : pair -> pair) (ni nj: int) requires { is_involution g ni nj } ensures { sum2d f ni nj = sum2d ( f @ g ) ni nj } variant { umkp (first_diff g ni nj (mkp 0 0) ) ni nj } = ( if ni > 0 && nj > 0 then begin let fdg = first_diff g ni nj (mkp 0 0) in if pair_eq fdg (mkp ni 0) then begin assert { forall p. in_rect p ni nj -> f p = (f @ g) p }; S.sum2d_lte f (f@g) ni nj; assert { sum2d f ni nj <= sum2d ( f @ g ) ni nj }; S.sum2d_lte (f@g) f ni nj; assert { sum2d ( f @ g ) ni nj <= sum2d f ni nj } end else begin let fdg' = g fdg in assert { g fdg <> fdg }; assert { pair_lt fdg fdg' }; let h = swap g fdg in assert { forall p. in_rect p ni nj -> pair_lt p fdg -> h p = p }; assert { h fdg = fdg }; let fdh = first_diff h ni nj (mkp 0 0) in assert { pair_lt fdg fdh } ; umkp_dec fdh fdg ni nj; assert { umkp fdh ni nj < umkp fdg ni nj } ; sum_permut_aux f h ni nj; assert { let fg = (f @g) in let fh = (f @ h) in fh = fg @ (transpose fdg fdg') }; assert { sum2d ( f @ g ) ni nj = sum2d ( f @ h ) ni nj }; end end ) let lemma sum_permut (f : pair -> int) (g : pair -> pair) (ni nj : int) requires { 1 <= ni /\ 1 <= nj } requires { is_involution g ni nj } ensures { sum2d f ni nj = sum2d ( f @ g ) ni nj } = ( sum_permut_aux f g ni nj; assert { sum2d f ni nj = sum2d ( f @ g ) ni nj } ) end (* generated on Mon Dec 2 02:04:28 UTC 2024 from rev: *)
Generated by why3doc 1.7.2+git