diff --git a/src/plugins/wp/Cint.mli b/src/plugins/wp/Cint.mli index e889cc7d28636556e4bd95d472db3dbdd01da4f6..72a7467a5a38115973b22c0770461db1f062f5e2 100644 --- a/src/plugins/wp/Cint.mli +++ b/src/plugins/wp/Cint.mli @@ -90,4 +90,5 @@ val is_cint_simplifier: simplifier val mask_simplifier: simplifier +(* under approximation: [is_positive_or_null e] ==> [e] >= 0 *) val is_positive_or_null: term -> bool diff --git a/src/plugins/wp/TacSequence.ml b/src/plugins/wp/TacSequence.ml index 3671cd67b73db65cf679ea358e3a6b56640dba10..ab689630267f2bfc69790deb410b7399075391ad 100644 --- a/src/plugins/wp/TacSequence.ml +++ b/src/plugins/wp/TacSequence.ml @@ -53,36 +53,59 @@ class sequence = ~descr:"Unroll repeat-sequence operator" ~params:[pmode] - method select _feedback (s : Tactical.selection) = + method select feedback (s : Tactical.selection) = let value = Tactical.selected s in match F.repr value with | Fun(f,[a;n]) when f == Vlist.f_repeat -> let result = F.typeof value in let at = Tactical.at s in - Tactical.Applicable - begin - match self#get_field vmode with - | `Sum -> - let ns = sum n in - let pos = F.p_all positive ns in - let cat = concat ~result (List.map (repeat ~result a) ns) in - Tactical.condition "Positive" pos @@ - Tactical.rewrite ?at [ "Unroll" , pos , value , cat ] - | `Left -> - let p = F.e_add n F.e_minus_one in - let unroll = concat ~result [a ; repeat ~result a p] in + begin + match self#get_field vmode with + | `Sum -> + (* n1>=0 && n2>=0 && ... |- (a *^ (n1 + n2 + ...)) -+-> ((a *^ n1) ^ (a *^ n2) ^ ...) *) + begin + match sum n with + | [ s ] -> + feedback#set_descr + "Cannot unroll with selected option, '%a' is not a sum" + F.pp_term s ; + Tactical.Not_configured + | ns -> + (* NB. the term is rewriten in itself when the initial term is not a sum *) + let pos = F.p_all positive ns in + let cat = + concat ~result (List.map (repeat ~result a) ns) in + feedback#set_descr + "Unroll repeat-sequence: unroll sum" ; + Tactical.Applicable ( + Tactical.condition "Positive" pos @@ + Tactical.rewrite ?at [ "Unroll" , pos , value , cat ]) + end + | `Left -> + (* n<=0 |- (a *^ n) -+-> [] *) + (* n-1>=0 |- (a *^ n) -+-> (a ^ (a *^ (n-1))) *) + let p = F.e_add n F.e_minus_one in + let unroll = concat ~result [a ; repeat ~result a p] in + feedback#set_descr + "Unroll repeat-sequence: unroll first element" ; + Tactical.Applicable( Tactical.rewrite ?at [ "Nil", negative n , value , concat ~result [] ; "Unroll", positive p , value , unroll ; - ] - | `Right -> - let p = F.e_add n F.e_minus_one in - let unroll = concat ~result [repeat ~result a p ; a] in + ]) + | `Right -> + (* n<=0 |- (a *^ n) -+-> [] *) + (* n-1>=0 |- (a *^ n) -+-> ((a *^ (n-1)) ^ a) *) + let p = F.e_add n F.e_minus_one in + let unroll = concat ~result [repeat ~result a p ; a] in + feedback#set_descr + "Unroll repeat-sequence: unroll last element" ; + Tactical.Applicable( Tactical.rewrite ?at [ "Nil", negative n , value , concat ~result [] ; "Unroll", positive p , value , unroll ; - ] - end + ]) + end | _ -> Not_applicable end diff --git a/src/plugins/wp/Vlist.ml b/src/plugins/wp/Vlist.ml index c46c6b226aef8d634e93f6df32fbecff73698184..76423f7fee8de99ce2a543a5d264bc5c18128ed5 100644 --- a/src/plugins/wp/Vlist.ml +++ b/src/plugins/wp/Vlist.ml @@ -23,6 +23,9 @@ (* -------------------------------------------------------------------------- *) (* --- VList Builtins --- *) (* -------------------------------------------------------------------------- *) +let dkey = Wp_parameters.register_category "sequence" +let debug fmt = Wp_parameters.debug ~dkey fmt +let debugN level fmt = Wp_parameters.debug ~level ~dkey fmt open Lang open Lang.F @@ -113,39 +116,75 @@ let () = add_builtin "\\repeat" [A;Z] f_repeat ; end +let category e = + match F.repr e with + | Qed.Logic.Fun (f,_) when Fun.equal f f_nil -> "Nil" + | Qed.Logic.Fun (f,_) when Fun.equal f f_cons -> "Cons" + | Qed.Logic.Fun (f,_) when Fun.equal f f_nth -> "Nth" + | Qed.Logic.Fun (f,_) when Fun.equal f f_length -> "Length" + | Qed.Logic.Fun (f,_) when Fun.equal f f_concat -> "Concat" + | Qed.Logic.Fun (f,_) when Fun.equal f f_repeat -> "Repeat" + | _ -> "_" + +let rec pp_pattern fmt e = + match F.repr e with + | Qed.Logic.Fun (f, args) when Fun.equal f f_nil || + Fun.equal f f_cons || + Fun.equal f f_nth || + Fun.equal f f_length || + Fun.equal f f_concat || + Fun.equal f f_repeat -> Format.fprintf fmt "(%s %a)" (category e) (Format.pp_print_list ~pp_sep:(fun fmt () -> Format.pp_print_string fmt " ") pp_pattern) args + | _ -> Format.pp_print_string fmt "_" + (*--- Smart Constructors ---*) -let is_nil e = +let is_nil e = (* under-approximation of e==[] *) match F.repr e with | Qed.Logic.Fun (f,_) -> Fun.equal f f_nil | _ -> false + let v_nil t = F.e_fun ~result:t f_nil [] let v_elt e = F.e_fun f_elt [e] let v_concat es tau = F.e_fun f_concat es ~result:tau let v_length l = F.e_fun f_length [l] -let v_repeat s n = F.e_fun f_repeat [s;n] +let v_repeat s n tau = F.e_fun f_repeat [s;n] ~result:tau (* -------------------------------------------------------------------------- *) (* --- Rewriters --- *) (* -------------------------------------------------------------------------- *) -let rewrite_cons a w tau = v_concat [v_elt a ; w] (vlist_get_tau tau) +let rewrite_cons a w tau = (* a::w == [a]^w *) + v_concat [v_elt a ; w] (vlist_get_tau tau) let rewrite_length e = match F.repr e with - | L.Fun( nil , [] ) when nil == f_nil -> F.e_zero - | L.Fun( elt , [_] ) when elt == f_elt -> F.e_one - | L.Fun( concat , es ) when concat == f_concat -> + | L.Fun( nil , [] ) when nil == f_nil -> F.e_zero (* \length([]) == 0 *) + | L.Fun( elt , [_] ) when elt == f_elt -> F.e_one (* \length([x]) == 1 *) + | L.Fun( concat , es ) when concat == f_concat -> (* \length(\concat(...,x_i,...)) == \sum(...,\length(x_i),...) *) F.e_sum (List.map v_length es) - | L.Fun( repeat , [ u ; n ] ) when repeat == f_repeat && - Cint.is_positive_or_null n -> - F.e_mul (v_length u) n + | L.Fun( repeat , [ u ; n ] ) when repeat == f_repeat -> + (* \length(u ^* n) == if 0<=n then n * \length(u) else 0 *) + F.e_if (F.e_leq e_zero n) (F.e_mul n (v_length u)) e_zero + | _ -> + (* NB. do not considers \Cons because they are removed *) + raise Not_found + +let match_natural k = + match F.repr k with + | L.Kint z -> + let k = try Integer.to_int_exn z with Z.Overflow -> raise Not_found in + if 0 <= k then k else raise Not_found | _ -> raise Not_found +(* Why3 definition: [\nth(e,k)] is undefined for [k<0 || k>=\length(e)]. + So, the list cannot be destructured when the length is unknown *) let rec get_nth k e = match F.repr e with | L.Fun( concat , list ) when concat == f_concat -> get_nth_list k list - | L.Fun( elt , [x] ) when elt == f_elt && k = 0 -> x + | L.Fun( elt , [x] ) when elt == f_elt -> + get_nth_elt k x (fun _ -> raise Not_found) + | L.Fun( repeat , [x;n] ) when repeat == f_repeat -> + get_nth_repeat k x n (fun _ -> raise Not_found) | _ -> raise Not_found and get_nth_list k = function @@ -153,37 +192,78 @@ and get_nth_list k = function begin match F.repr head with | L.Fun( elt , [x] ) when elt == f_elt -> - if k = 0 then x else get_nth_list (k-1) tail + get_nth_elt k x (fun k -> get_nth_list k tail) + | L.Fun( repeat , [x;n] ) when repeat == f_repeat -> + get_nth_repeat k x n (fun k -> get_nth_list k tail) | _ -> raise Not_found end | [] -> raise Not_found +and get_nth_elt k x f = + if k = 0 then x else (f (k-1)) + +and get_nth_repeat k x n f = + let n = match_natural n in + if n = 0 then raise Not_found ; + let m = match_natural (rewrite_length x) in + if m = 0 then raise Not_found ; + let en = Integer.of_int n in + let em = Integer.of_int m in + let ek = Integer.of_int k in + if Integer.(ge ek (mul en em)) then f (k -(n*m)) + else get_nth (k mod m) x + let rewrite_nth s k = - match F.repr k with - | L.Kint z -> - let k = try Integer.to_int_exn z with Z.Overflow -> raise Not_found in - if 0 <= k then get_nth k s else raise Not_found - | _ -> raise Not_found + get_nth (match_natural k) s let rewrite_repeat s n = - if F.equal n e_zero then v_nil (F.typeof s) else - if F.equal n e_one then s else - if is_nil s then s else + if F.decide (F.e_leq n e_zero) then (* n <=0 ==> (s *^ n) == [] *) + v_nil (F.typeof s) + else if F.equal n e_one then (* (s *^ 1) == s *) + s + else if is_nil s then (* ([] *^ n) == [] ; even if [n] is negative *) + s + else match F.repr s with - | L.Fun( repeat , [s0 ; n0] ) + | L.Fun( repeat , [s0 ; n0] ) (* n0>=0 && n>=0 ==> ((s0 *^ n0) *^ n) == (s0 *^ (n0 * n)) *) when (repeat == f_repeat) && (Cint.is_positive_or_null n) && - (Cint.is_positive_or_null n0) -> v_repeat s0 (F.e_mul n0 n) + (Cint.is_positive_or_null n0) -> v_repeat s0 (F.e_mul n0 n) (F.typeof s) | _ -> raise Not_found let rec leftmost a ms = match F.repr a with | L.Fun( concat , e :: es ) when concat == f_concat -> leftmost e (es@ms) - | L.Fun( repeat , [ u ; n ] ) when repeat == f_repeat && Cint.is_positive_or_null n -> - leftmost u (v_repeat u (F.e_sub n F.e_one) :: ms) + | L.Fun( repeat , [ u ; n ] ) when repeat == f_repeat -> begin + match (* tries to perform some rolling that do not depend on [n] *) + (match ms with + | b::ms -> + let b,ms = leftmost b ms in + let u,us = leftmost u [] in + if F.decide (F.e_eq u b) then + (* u=b ==> ((u^us)*^n) ^ b ^ ms == u ^ (us^b)*^n) ^ ms *) + Some (u, v_repeat (v_concat (us@[b]) (F.typeof a)) n (F.typeof a) :: ms) + else None + | _ -> None) with + | Some res -> res + | None -> + if F.decide (F.e_lt F.e_zero n) then + (* 0<n ==> (u*^n) ^ ms == u ^ (u*^(n-1)) ^ ms *) + leftmost u (v_repeat u (F.e_sub n F.e_one) (F.typeof a) :: ms) + else a , ms + end | _ -> a , ms +(* [leftmost a] returns [s,xs] such that [a = s ^ x1 ^ ... ^ xn] *) +let leftmost a = + let r = leftmost a [] in + debugN 2 "Vlist.leftmost %a@ = %a (form: %s) ^ ... (%d more)@." + Lang.F.pp_term a + Lang.F.pp_term (fst r) (category (fst r)) + (List.length (snd r)) ; + r + let rec rightmost ms a = match F.repr a with | L.Fun( concat , es ) when concat == f_concat -> @@ -191,72 +271,182 @@ let rec rightmost ms a = | [] -> ms , a | e::es -> rightmost (ms @ List.rev es) e end - | L.Fun( repeat , [ u ; n ] ) when repeat == f_repeat && Cint.is_positive_or_null n -> - rightmost (ms @ [v_repeat u (F.e_sub n F.e_one)]) u + | L.Fun( repeat , [ u ; n ] ) when repeat == f_repeat -> begin + match (* tries to perform some rolling that do not depend on [n] *) + (match List.rev ms with + | b::ms -> + let ms,b = rightmost (List.rev ms) b in + let us,u = rightmost [] u in + if F.decide (F.e_eq u b) then + (* u=b ==> (ms ^ b ^ (us^u)*^n) == ms ^ (b^us)*^n) ^ u *) + Some (ms @ [ v_repeat (v_concat (b::us) (F.typeof a)) n (F.typeof a)], u) + else None + | _ -> None) with + | Some res -> res + | None -> + if F.decide (F.e_lt F.e_zero n) then + (* 0<n ==> ms ^ (u*^n) == ms ^ (u*^(n-1)) ^ u *) + rightmost (ms @ [v_repeat u (F.e_sub n F.e_one) (F.typeof a)]) u + else ms , a + end | _ -> ms , a +(* [rightmost a] returns [s,xs] such that [a = x1 ^ ... ^ xn ^ s] *) +let rightmost a = + let r = rightmost [] a in + debugN 2 "Vlist.rightmost %a@ = (%d more) ... ^ %a (form: %s)@." + Lang.F.pp_term a + (List.length (fst r)) + Lang.F.pp_term (snd r) (category (snd r)); + r + let leftmost_eq a b = - let a , u = leftmost a [] in - let b , v = leftmost b [] in + let a , u = leftmost a in + let b , v = leftmost b in if u <> [] || v <> [] then match F.is_equal a b with - | L.Yes -> F.p_equal (v_concat u (F.typeof a)) (v_concat v (F.typeof a)) - | L.No -> F.p_false - | L.Maybe -> raise Not_found + | L.Yes -> + (* s ^ u1 ^ ... = s ^ v1 ^ ... <=> u1 ^ ... = v1 ^ ... *) + F.p_equal (v_concat u (F.typeof a)) (v_concat v (F.typeof a)) + | L.No when F.decide (F.e_eq (v_length a) (v_length b)) -> + (* a <> b && \length(a)=\length(b) ==> a ^ u1 ^ ... <> b ^ v1 ^ ... *) + F.p_false + | _ -> raise Not_found else raise Not_found let rightmost_eq a b = - let u , a = rightmost [] a in - let v , b = rightmost [] b in + let u , a = rightmost a in + let v , b = rightmost b in if u <> [] || v <> [] then match F.is_equal a b with - | L.Yes -> F.p_equal (v_concat u (F.typeof a)) (v_concat v (F.typeof a)) - | L.No -> F.p_false - | L.Maybe -> raise Not_found + | L.Yes -> + (* u1 ^ ... ^ s = v1 ^ ... ^ s <=> u1 ^ ... = v1 ^ ... *) + F.p_equal (v_concat u (F.typeof a)) (v_concat v (F.typeof a)) + | L.No when F.decide (F.e_eq (v_length a) (v_length b)) -> + (* a <> b && \length(a)=\length(b) ==> u1 ^ ... ^ a <> v1 ^ ... ^ b *) + F.p_false + | _ -> raise Not_found else raise Not_found -let p_is_nil a = F.p_equal a (v_nil (F.typeof a)) -let rewrite_is_nil a = +let rewrite_is_nil ~nil a = + let p_is_nil a = F.p_equal nil a in match F.repr a with - | L.Fun(concat,es) when concat == f_concat -> F.p_all p_is_nil es - | L.Fun(elt,[_]) when elt == f_elt -> F.p_false - | L.Fun(repeat,[u;n]) when repeat == f_repeat -> - F.p_or (F.p_leq n F.e_zero) (p_is_nil u) + | L.Fun(concat,es) when concat == f_concat -> + (* \concat (s1,...,sn)==[] <==> (s1==[] && ... && sn==[]) *) + F.p_all p_is_nil es + | L.Fun(elt,[_]) when elt == f_elt -> F.p_false (* [x]==[] <==> false *) + | L.Fun(repeat,[s;n]) when repeat == f_repeat -> + (* (s *^ n)==[] <==> (s==[] || n<=0) *) + F.p_or (F.p_leq n F.e_zero) (p_is_nil s) + | _ -> + raise Not_found + +(* Ensures xs to be a sub-sequence of ys, otherwise raise Not_found + In such a case, (concat xs = concat ys) <==> (forall r in result, r = nil) *) +let rec subsequence xs ys = + match xs , ys with + | [],ys -> ys + | x::rxs, y::rys -> + if (F.decide (e_eq x y)) then subsequence rxs rys else y :: subsequence xs rys | _ -> raise Not_found let elements a = match F.repr a with - | L.Fun( nil , [] ) when nil == f_nil -> [] - | L.Fun( concat , es ) when concat == f_concat -> es - | _ -> [a] - -(* [omit rs x ys]: if ys = u.x.v returns (rs+u,v) with r in reverse order *) - -let rec omit rs x = function - | [] -> raise Not_found - | y::ys -> if x == y then rs,ys else omit (y::rs) x ys - -let rec subsequence xs rs ys = - match xs with - | [] -> List.rev_append rs ys - | x::xs -> - let rs,ys = omit rs x ys in - subsequence xs rs ys + | L.Fun(concat,es) when concat == f_concat -> true, es + | _ -> false, [ a ] + +(* Ensures that [a] or [b] is a sub-sequence of the other, otherwise [raise Not_found] + In such a case, (concat xs = concat ys) <==> (forall r in result, r = nil) *) +let subsequence a b = + let destruct_a, xs = elements a in + let destruct_b, ys = elements b in + if not (destruct_a || destruct_b) then raise Not_found; + let shortest,xs,ys = if List.length xs <= List.length ys then a,xs,ys else b,ys,xs in + let es = subsequence xs ys in + (* xs=ys <==> forall s in es ; s = nil *) + let nil = v_nil (F.typeof shortest) in + (* [s] are elements of [ys] (the longest sequence) and [nil] has the same type than the [shortest] sequence *) + let p_is_nil s = F.p_equal nil s in + F.p_all p_is_nil es + +let repeat_eq a x n b y m = + let e_eq_x_y = F.e_eq x y in + let e_eq_n_m = F.e_eq n m in + if F.decide e_eq_x_y then + (* s *^ n == s *^ m <==> ( n=m || (s *^ n == [] && s *^ m == []) ) *) + let nil_a = v_nil (F.typeof a) in + let nil_b = v_nil (F.typeof b) in + F.p_or (Lang.F.p_bool e_eq_n_m) + (F.p_and (F.p_equal a nil_b) (F.p_equal nil_a b)) + else if F.decide e_eq_n_m then + (* x *^ n == y *^ n <==> ( x == y || n<=0 ) *) + F.p_or (F.p_leq n e_zero) (Lang.F.p_bool e_eq_x_y) + else if F.decide (e_eq (v_length x) (v_length y)) then + (* \length(x)=\length(y) ==> ( x *^ n == y *^ m <==> ( m == n && x == y) || (x *^ n == [] && y *^ m == [] ) *) + let nil_a = v_nil (F.typeof a) in + let nil_b = v_nil (F.typeof b) in + F.p_or (F.p_and (F.p_bool e_eq_n_m) (Lang.F.p_bool e_eq_x_y)) + (F.p_and (F.p_equal a nil_b) (F.p_equal nil_a b)) + else raise Not_found + +let rewrite_eq_sequence a b = + debug "Vlist.rewrite_eq_sequence: tries to rewrite %a@ = %a@.- left pattern: %a@.- right pattern: %a@." + Lang.F.pp_term a Lang.F.pp_term b + pp_pattern a pp_pattern b; + match F.repr a , F.repr b with + | L.Fun(nil,[]) , _ when nil == f_nil -> rewrite_is_nil ~nil:a b + | _ , L.Fun(nil,[]) when nil == f_nil -> rewrite_is_nil ~nil:b a + | _ -> try + match F.repr a , F.repr b with + | L.Fun(repeat_a, [x;n]), L.Fun(repeat_b, [y;m]) + when repeat_a == f_repeat && + repeat_b == f_repeat -> + repeat_eq a x n b y m + | _ -> + try leftmost_eq a b with Not_found -> + try rightmost_eq a b with Not_found -> + subsequence a b + with Not_found -> + if F.decide (F.e_neq (v_length a) (v_length b)) then + F.p_false + else raise Not_found + +let rewrite_eq_length a b = + match F.repr a , F.repr b with + | L.Fun(length_a,[_]), L.Fun(length_b,[_]) when length_a == f_length && + length_b == f_length -> + (* N.B. cannot be simplified by the next patterns *) + raise Not_found + | _, L.Fun(length,[_]) when length == f_length && + F.decide (e_lt a e_zero) -> + (* a < 0 ==> ( a=\length(b) <=> false ) *) + F.p_false + | L.Fun(length,[_]), _ when length == f_length && + F.decide (e_lt b e_zero) -> + (* b < 0 ==> ( \length(a)<=b <=> false ) *) + F.p_false + | _ -> raise Not_found -let rewrite_eq a b = +let rewrite_leq_length a b = match F.repr a , F.repr b with - | L.Fun(nil,[]) , _ when nil == f_nil -> rewrite_is_nil b - | _ , L.Fun(nil,[]) when nil == f_nil -> rewrite_is_nil a - | _ -> - try leftmost_eq a b with Not_found -> - try rightmost_eq a b with Not_found -> - let xs = elements a in - let ys = elements b in - if List.length xs < List.length ys - then F.p_all p_is_nil (subsequence xs [] ys) - else F.p_all p_is_nil (subsequence ys [] xs) + | L.Fun(length_a,[_]), L.Fun(length_b,[_]) when length_a == f_length && + length_b == f_length -> + (* N.B. cannot be simplified by the next patterns *) + raise Not_found + | L.Fun(length,[_]), _ when length == f_length && + F.decide (e_lt b e_zero) -> + (* b < 0 ==> ( \length(a)<=b <=> false ) *) + F.e_false + (* N.B. the next rule does not allow to split on the sign of \length(a) with TIP + | _, L.Fun(length,[_]) when length == f_length && + F.decide (e_leq a e_zero) -> + (* a <= 0 ==> ( a<=\length(b) <=> true ) *) + F.e_true + *) + | _ -> raise Not_found + (* All Simplifications *) @@ -267,8 +457,11 @@ let () = F.set_builtin_2' f_cons rewrite_cons ; F.set_builtin_2 f_repeat rewrite_repeat ; F.set_builtin_1 f_length rewrite_length ; - F.set_builtin_eqp f_repeat rewrite_eq ; - F.set_builtin_eqp f_nil rewrite_eq ; + F.set_builtin_leq f_length rewrite_leq_length ; + F.set_builtin_eqp f_length rewrite_eq_length ; + F.set_builtin_eqp f_concat rewrite_eq_sequence ; + F.set_builtin_eqp f_repeat rewrite_eq_sequence ; + F.set_builtin_eqp f_nil rewrite_eq_sequence ; end (* -------------------------------------------------------------------------- *) diff --git a/src/plugins/wp/tests/wp_plugin/nth.i b/src/plugins/wp/tests/wp_plugin/nth.i index 3e5a1d4e75d247e894c07d6e09395a0d3c7bdf92..0e444d63fe1e9d5f689f657eea8a81b7188fce9c 100644 --- a/src/plugins/wp/tests/wp_plugin/nth.i +++ b/src/plugins/wp/tests/wp_plugin/nth.i @@ -3,8 +3,85 @@ */ /*@ - axiomatic Nth { + axiomatic Def { + logic integer f(integer a); + logic integer N; + logic integer M; + logic \list<integer> S; + logic \list<integer> A; + logic \list<integer> B; + logic \list<integer> C; + + logic \list<integer> empty = \Nil; + predicate IsEmpty(\list<integer> s) = s == empty; + + predicate P(\list<integer> s) reads \nothing; + + } +*/ + +/*@ + axiomatic MkRepeat { + + check lemma negative_repeat: ok: P( A *^ 0 ) <==> P( S *^ (-1) ) ; + check lemma repeat_nil: ok: P( A *^ 0 ) <==> P( (S *^ 0) *^ N ); + check lemma repeat_one: ok: P( S *^ 1 ) <==> P( S ); + check lemma repeat_repeated: ok: P( (S *^ ((N&1)) *^ (M&2)) ) <==> P( S *^ ((N&1) * (M&2)) ); + + } +*/ + +/*@ + axiomatic Equality { + + check lemma constructor_elt: ok: [| 1 |] != [| 2 |] ; + + check lemma not_nil_elt: ok: ([| 1 |] ^ A) != A ; + + + check lemma repeat1: ko: (S *^ N) == (S *^ M) + <==> ( N == M || ( ((S *^ N) ^ A) == A && ((S *^ M) ^ A) == A ) ) ; + + check lemma repeat2: ok: ( ((S *^ N) ^ S) *^ M ) == ( ( S ^ (S *^ N)) *^ M ) ; + + check lemma left_shift_repeat1: ok: ( ((S ^ A ^ B) *^ N) ^ S ^ A ) == (S ^ C) + <==> ( ( (A ^ B ^ S) *^ N) ^ A ) == ( C); + check lemma left_unfold_repeat1: ok: ( ((S ^ A ^ B) *^ 3) ^ A ^ S ) == (S ^ C) + <==> ( A ^ B ^ ((S ^ A ^ B) *^ 2) ^ A ^ S ) == ( C); + + check lemma right_shift_repeat1: ko: ( A ^ S ^ ((B ^ A ^ S) *^ N) ) == (C ^ S) + <==> ( A ^ ((S ^ B ^ A ) *^ N) ) == (C ); + check lemma right_unfold_repeat1: ko: ( S ^ A ^ ((B ^ A ^ S) *^ 3) ) == (C ^ S) + <==> ( S ^ A ^ ((B ^ A ^ S) *^ 2) ^ B ^ A) == (C ); + + + check lemma left_shift_repeat2: ok: ( ((S ^ A ^ B) *^ N) ^ S ^ A ^ C) == (S ^ A) + <==> ( (C ^ S) == S && (N<=0 || (A ^ B ^ S ^ S) == S) ); + check lemma left_unfold_repeat2: ok: ( ((S ^ A ^ B) *^ 3) ^ C) == (S ^ A) + <==> (A ^ A ^ B ^ C ^ S) == A ; + + check lemma right_shift_repeat2: ko: ( C ^ A ^ S ^ ((B ^ A ^ S) *^ N) ) == (A ^ S) + <==> ( (C ^ S) == S && (N<=0 || (A ^ B ^ S ^ S) == S) ); + check lemma right_unfold_repeat2: ko: ( C ^ ((B ^ A ^ S) *^ 3) ) == (A ^ S) + <==> (A ^ B ^ C ^ S ^ S) == S ; + + + check lemma subsequence1: ko: ( A ^ (S *^ N) ^ B ^ S ^ C ) == ( (S *^ N) ^ S ) + <==> ( A ^ B ^ C ^ C ) == C ; + + } +*/ + +/*@ + axiomatic Nth { + + check lemma nth_repeat_undefined_1: ko: \nth ( [| f(0), f(1), f(2), f(3) |] *^ 3, 12 ) == f(0); + + check lemma nth_repeat_1: ok: \nth ( [| f(0), f(1), f(2), f(3) |] *^ 3, 0 ) == f(0); + check lemma nth_repeat_2: ok: \nth ( [| f(0), f(1), f(2), f(3) |] *^ 3, 11 ) == f(3); + check lemma nth_repeat_3: ok: \nth ( ([| f(0), f(1), f(2), f(3) |] *^ 3) ^ [| f(12) |] , 12 ) == f(12); + check lemma nth_repeat_4: ok: \nth ( ([| f(0), f(1), f(2), f(3) |] *^ 3) ^ [| f(12),f(13),f(14)|] ^ S, 13 ) == f(13); lemma access_16_16: ok: \forall integer k ; 0 <= k < 16 ==> @@ -15,12 +92,12 @@ \forall integer k ; 0 <= k < 4 ==> f(k)==\nth([| f(0), f(1), f(2), f(3) |], k); - lemma eq_repeat_concat_3: ok: - \forall \list<integer> x ; (x *^ 3) == (x ^ x ^ x) ; + lemma eq_repeat_concat_3: ok: (S *^ 3) == (S ^ S ^ S) ; lemma access_repeat_concat_3: ok: lack: - \forall \list<integer> x ; - \forall integer k ; 0 <= k < 3*\length(x) ==> \nth(x *^ 3, k) == \nth(x ^ x ^ x, k) ; + \forall integer k ; 0 <= k < 3*\length(S) ==> \nth(S *^ 3, k) == \nth(S ^ S ^ S, k) ; } + + */ diff --git a/src/plugins/wp/tests/wp_plugin/oracle/nth.res.oracle b/src/plugins/wp/tests/wp_plugin/oracle/nth.res.oracle index 908af494da9eac274fa2f4293aa6379dc9accb7c..c93629cbb62d4b5fa92e4144cc23d6e0c1089cf1 100644 --- a/src/plugins/wp/tests/wp_plugin/oracle/nth.res.oracle +++ b/src/plugins/wp/tests/wp_plugin/oracle/nth.res.oracle @@ -1,6 +1,97 @@ # frama-c -wp [...] [kernel] Parsing nth.i (no preprocessing) [wp] Running WP plugin... +------------------------------------------------------------ + Axiomatic 'Equality' +------------------------------------------------------------ + +Lemma constructor_elt: +Prove: true + +------------------------------------------------------------ + +Lemma left_shift_repeat1: +Prove: true + +------------------------------------------------------------ + +Lemma left_shift_repeat2: +Prove: true + +------------------------------------------------------------ + +Lemma left_unfold_repeat1: +Prove: true + +------------------------------------------------------------ + +Lemma left_unfold_repeat2: +Prove: true + +------------------------------------------------------------ + +Lemma not_nil_elt: +Prove: true + +------------------------------------------------------------ + +Lemma repeat1: +Prove: true + +------------------------------------------------------------ + +Lemma repeat2: +Prove: true + +------------------------------------------------------------ + +Lemma right_shift_repeat1: +Prove: true + +------------------------------------------------------------ + +Lemma right_shift_repeat2: +Prove: true + +------------------------------------------------------------ + +Lemma right_unfold_repeat1: +Prove: true + +------------------------------------------------------------ + +Lemma right_unfold_repeat2: +Prove: true + +------------------------------------------------------------ + +Lemma subsequence1: +Prove: true + +------------------------------------------------------------ +------------------------------------------------------------ + Axiomatic 'MkRepeat' +------------------------------------------------------------ + +Lemma negative_repeat: +Prove: true + +------------------------------------------------------------ + +Lemma repeat_nil: +Prove: true + +------------------------------------------------------------ + +Lemma repeat_one: +Prove: true + +------------------------------------------------------------ + +Lemma repeat_repeated: +Prove: true + +------------------------------------------------------------ ------------------------------------------------------------ Axiomatic 'Nth' ------------------------------------------------------------ @@ -27,8 +118,8 @@ Prove: (0<=k_0) -> (k_0<=3) Lemma access_repeat_concat_3: Assume: 'eq_repeat_concat_3' 'access_4_4' 'access_16_16' -Prove: (0<=k_0) -> (k_0<(3*(length x_0))) - -> ((nth (concat x_0 x_0 x_0) k_0)=(nth (repeat x_0 3) k_0)) +Prove: (0<=k_0) -> (k_0<(3*(length L_S))) + -> ((nth (concat L_S L_S L_S) k_0)=(nth (repeat L_S 3) k_0)) ------------------------------------------------------------ @@ -37,3 +128,31 @@ Assume: 'access_4_4' 'access_16_16' Prove: true ------------------------------------------------------------ + +Lemma nth_repeat_1: +Prove: true + +------------------------------------------------------------ + +Lemma nth_repeat_2: +Prove: true + +------------------------------------------------------------ + +Lemma nth_repeat_3: +Prove: true + +------------------------------------------------------------ + +Lemma nth_repeat_4: +Prove: true + +------------------------------------------------------------ + +Lemma nth_repeat_undefined_1: +Prove: let x_0 = (L_f 0) in + (nth + (repeat (concat (elt x_0) (elt (L_f 1)) (elt (L_f 2)) (elt (L_f 3))) + 3) 12)=x_0 + +------------------------------------------------------------ diff --git a/src/plugins/wp/tests/wp_plugin/oracle/sequence.res.oracle b/src/plugins/wp/tests/wp_plugin/oracle/sequence.res.oracle index eaf6561ef18ecbc197623780c17af09faa1eb1ba..fedcdb66fb660ab5c85989b6c35ce166281fa5ba 100644 --- a/src/plugins/wp/tests/wp_plugin/oracle/sequence.res.oracle +++ b/src/plugins/wp/tests/wp_plugin/oracle/sequence.res.oracle @@ -34,7 +34,7 @@ Assume { (* Call 'f' *) Have: L_call_obs(call_seq_3) = a_1. } -Prove: nth(a_1, 1 + length(a)) = z. +Prove: nth(a_1, 1 + i) = z. ------------------------------------------------------------ @@ -181,30 +181,7 @@ Prove: true. ------------------------------------------------------------ Goal Post-condition for 'g_called' 'ok,u1' in 'loops': -Let a = ([ y ] *^ i). -Assume { - Type: is_sint32(i) /\ is_sint32(n) /\ is_sint32(x) /\ is_sint32(y) /\ - is_sint32(z). - (* Heap *) - Type: is_sint32(call_seq_0). - (* Pre-condition *) - Have: L_call_obs(call_seq_0) = nil. - (* Pre-condition for 'g_called' *) - Have: 0 < n. - (* Call 'f' *) - Have: L_call_obs(call_seq_1) = [ x ]. - (* Invariant 'ok,id_min' *) - Have: 0 <= i. - (* Invariant 'ok,id_max' *) - Have: i <= n. - (* Invariant 'ok,inv' *) - Have: L_call_obs(call_seq_2) = [ x ] ^ a. - (* Else *) - Have: n <= i. - (* Call 'f' *) - Have: L_call_obs(call_seq_3) = [ x ] ^ a ^ [ z ]. -} -Prove: length(a) = i. +Prove: true. ------------------------------------------------------------ @@ -240,7 +217,7 @@ Assume { (* Call 'f' *) Have: L_call_obs(call_seq_3) = [ x ] ^ a ^ [ z ]. } -Prove: length(a) = 0. +Prove: i = 0. ------------------------------------------------------------ diff --git a/src/plugins/wp/tests/wp_plugin/oracle_qualif/nth.res.oracle b/src/plugins/wp/tests/wp_plugin/oracle_qualif/nth.res.oracle index 68fe97d6e4fa3fa66f330d8a0def5a8eab97d2f6..d276407bd64584ec645b8c0a7af2e28af3fb306d 100644 --- a/src/plugins/wp/tests/wp_plugin/oracle_qualif/nth.res.oracle +++ b/src/plugins/wp/tests/wp_plugin/oracle_qualif/nth.res.oracle @@ -1,15 +1,39 @@ # frama-c -wp [...] [kernel] Parsing nth.i (no preprocessing) [wp] Running WP plugin... -[wp] 4 goals scheduled +[wp] 26 goals scheduled [wp] [Alt-Ergo] Goal typed_lemma_access_16_16_ok : Valid [wp] [Alt-Ergo] Goal typed_lemma_access_4_4_ok : Valid -[wp] [Alt-Ergo] Goal typed_lemma_access_repeat_concat_3_ok_lack : Unsuccess +[wp] [Alt-Ergo] Goal typed_lemma_access_repeat_concat_3_ok_lack : Valid +[wp] [Qed] Goal typed_check_lemma_constructor_elt_ok : Valid [wp] [Qed] Goal typed_lemma_eq_repeat_concat_3_ok : Valid -[wp] Proved goals: 3 / 4 - Qed: 1 - Alt-Ergo: 2 (unsuccess: 1) +[wp] [Qed] Goal typed_check_lemma_left_shift_repeat1_ok : Valid +[wp] [Qed] Goal typed_check_lemma_left_shift_repeat2_ok : Valid +[wp] [Qed] Goal typed_check_lemma_left_unfold_repeat1_ok : Valid +[wp] [Qed] Goal typed_check_lemma_left_unfold_repeat2_ok : Valid +[wp] [Qed] Goal typed_check_lemma_negative_repeat_ok : Valid +[wp] [Qed] Goal typed_check_lemma_not_nil_elt_ok : Valid +[wp] [Qed] Goal typed_check_lemma_nth_repeat_1_ok : Valid +[wp] [Qed] Goal typed_check_lemma_nth_repeat_2_ok : Valid +[wp] [Qed] Goal typed_check_lemma_nth_repeat_3_ok : Valid +[wp] [Qed] Goal typed_check_lemma_nth_repeat_4_ok : Valid +[wp] [Alt-Ergo] Goal typed_check_lemma_nth_repeat_undefined_1_ko : Unsuccess +[wp] [Qed] Goal typed_check_lemma_repeat1_ko : Valid +[wp] [Qed] Goal typed_check_lemma_repeat2_ok : Valid +[wp] [Qed] Goal typed_check_lemma_repeat_nil_ok : Valid +[wp] [Qed] Goal typed_check_lemma_repeat_one_ok : Valid +[wp] [Qed] Goal typed_check_lemma_repeat_repeated_ok : Valid +[wp] [Qed] Goal typed_check_lemma_right_shift_repeat1_ko : Valid +[wp] [Qed] Goal typed_check_lemma_right_shift_repeat2_ko : Valid +[wp] [Qed] Goal typed_check_lemma_right_unfold_repeat1_ko : Valid +[wp] [Qed] Goal typed_check_lemma_right_unfold_repeat2_ko : Valid +[wp] [Qed] Goal typed_check_lemma_subsequence1_ko : Valid +[wp] Proved goals: 25 / 26 + Qed: 22 + Alt-Ergo: 3 (unsuccess: 1) ------------------------------------------------------------ Axiomatics WP Alt-Ergo Total Success - Axiomatic Nth 1 2 4 75.0% + Axiomatic Equality 13 - 13 100% + Axiomatic MkRepeat 4 - 4 100% + Axiomatic Nth 5 3 9 88.9% ------------------------------------------------------------ diff --git a/src/plugins/wp/tests/wp_plugin/oracle_qualif/sequence.0.res.oracle b/src/plugins/wp/tests/wp_plugin/oracle_qualif/sequence.0.res.oracle index 08751dc1962e76436108d5c150fb46acbffc110b..7602867d0780d45feb0ba2978880f36079220b2c 100644 --- a/src/plugins/wp/tests/wp_plugin/oracle_qualif/sequence.0.res.oracle +++ b/src/plugins/wp/tests/wp_plugin/oracle_qualif/sequence.0.res.oracle @@ -38,16 +38,16 @@ [wp] [Qed] Goal typed_caveat_loops_assigns_normal_part1 : Valid [wp] [Qed] Goal typed_caveat_loops_assigns_normal_part2 : Valid [wp] [Qed] Goal typed_caveat_loops_assigns_normal_part3 : Valid -[wp] [Alt-Ergo] Goal typed_caveat_loops_g_called_ensures_ok_u1 : Valid +[wp] [Qed] Goal typed_caveat_loops_g_called_ensures_ok_u1 : Valid [wp] [Qed] Goal typed_caveat_loops_g_called_ensures_ok_u2 : Valid [wp] [Alt-Ergo] Goal typed_caveat_loops_g_not_called_ensures_ok_v1 : Valid [wp] [Alt-Ergo] Goal typed_caveat_loops_g_not_called_ensures_ok_v2 : Valid [wp] Proved goals: 39 / 39 - Qed: 25 - Alt-Ergo: 14 + Qed: 26 + Alt-Ergo: 13 ------------------------------------------------------------ Functions WP Alt-Ergo Total Success no_calls 5 5 10 100% sequence 8 2 10 100% - loops 12 7 19 100% + loops 13 6 19 100% ------------------------------------------------------------ diff --git a/src/plugins/wp/tests/wp_plugin/oracle_qualif/sequence.1.res.oracle b/src/plugins/wp/tests/wp_plugin/oracle_qualif/sequence.1.res.oracle index d2806020044b634a1c493759069ee6fe5ebee4ee..fb728b9fa94a45d92d1f3cf5d409d84160adeadd 100644 --- a/src/plugins/wp/tests/wp_plugin/oracle_qualif/sequence.1.res.oracle +++ b/src/plugins/wp/tests/wp_plugin/oracle_qualif/sequence.1.res.oracle @@ -33,16 +33,16 @@ [wp] [Qed] Goal typed_caveat_loops_assigns_normal_part1 : Valid [wp] [Qed] Goal typed_caveat_loops_assigns_normal_part2 : Valid [wp] [Qed] Goal typed_caveat_loops_assigns_normal_part3 : Valid -[wp] [Alt-Ergo] Goal typed_caveat_loops_g_called_ensures_ok_u1 : Valid +[wp] [Qed] Goal typed_caveat_loops_g_called_ensures_ok_u1 : Valid [wp] [Qed] Goal typed_caveat_loops_g_called_ensures_ok_u2 : Valid [wp] [Alt-Ergo] Goal typed_caveat_loops_g_not_called_ensures_ok_v1 : Valid [wp] [Alt-Ergo] Goal typed_caveat_loops_g_not_called_ensures_ok_v2 : Valid [wp] Proved goals: 34 / 34 - Qed: 22 - Alt-Ergo: 12 + Qed: 23 + Alt-Ergo: 11 ------------------------------------------------------------ Functions WP Alt-Ergo Total Success no_calls 2 3 5 100% sequence 8 2 10 100% - loops 12 7 19 100% + loops 13 6 19 100% ------------------------------------------------------------