I'm using VST v1.7.
Has anyone ever proved that an int is equal as an array of characters? Something along those lines:
Definition int2uchars (i : int) : list Z :=
[
Int.unsigned (Int.and (Int.shru i (Int.repr 24)) (Int.repr 255));
Int.unsigned (Int.and (Int.shru i (Int.repr 16)) (Int.repr 255));
Int.unsigned (Int.and (Int.shru i (Int.repr 8)) (Int.repr 255));
Int.unsigned (Int.and (Int.shru i (Int.repr 0)) (Int.repr 255))
].
Lemma int2chararray :
forall (i : int) (v : val),
field_at Tsh tuint [] (Vint i) v
= data_block Tsh (int2uchars i) v.
Is there another solution than breaking the field_at abstraction to prove that?
Related
I'm trying to write a constraint in the from of the following (also attached):
sum([s,i], x[i,j,s,p] ) = sum([s,k], x[j,k,s,p] ) for all j in N\{0,n}, p in P
I already have all possible combinations of (i,j,s,p) stored in a set Xs and X0nswhich a vector of such 4-tuples.
Thus I tried to write it down as
#constraint( model, [p in P, jj in X0ns],
sum(x[(i, j, s, p)] for (i, j, s, p) in Xs if j == jj)
== sum(x[(j, k, s, p)] for (i, j, s, p) in Xs if j == jj)
This gives me an Error. On top of that I think this is not correct way of writing. Because I did not include a summation on S anywhere. Is it needed?
How can I build this kind of constraint?
Here is what I think that you mean (this is the exact implementation of your LaTeX equation).
Normally you should not have used tuples for array indexing.
m = Model();
S=1:3
N=1:4
K=1:4
P=1:5
#variable(m, x[N,N,S,P] >= 0);
#constraint(m, [j in N[2:end-1], p in P], sum(x[i,j,s,p] for i in N, s in S)
== sum(x[j,k,s,p] for k in K, s in S))
I'd like to prove this loop implementation of Euclidean division in Frama-C :
/*#
requires a >= 0 && 0 < b;
ensures \result == a / b;
*/
int euclid_div(const int a, const int b)
{
int q = 0;
int r = a;
/*#
loop invariant a == b*q+r && r>=0;
loop assigns q,r;
loop variant r;
*/
while (b <= r)
{
q++;
r -= b;
}
return q;
}
But the post condition fails to prove automatically (the loop invariant proved fine) :
Goal Post-condition:
Let x = r + (b * euclid_div_0).
Assume {
(* Pre-condition *)
Have: (0 < b) /\ (0 <= x).
(* Invariant *)
Have: 0 <= r.
(* Else *)
Have: r < b.
}
Prove: (x / b) = euclid_div_0.
--------------------------------------------------------------------------------
Prover Alt-Ergo: Unknown (250ms).
It does have all the hypotheses of Euclidean division, does anyone know why it cannot conclude ?
As indicated by Mohamed Iguernlala's answer, automated provers are not very comfortable with non-linear arithmetic. It is possible to do interactive proofs with WP, either directly within the GUI (see section 2.3 of WP Manual for more information), or by using coq (double click on the appropriate cell of the WP Goals tab of the GUI for launching coqide on the corresponding goal).
It is usually better to use coq on ACSL lemmas, as you can focus on the exact formula you want to prove manually, without being bothered by the logical model of the code you're trying to prove. Using this tactic, I've been able to prove your post-condition with the following intermediate lemma:
/*#
// WP's interactive prover select lemmas based on the predicate and
// function names which appear in it, but does not take arithmetic operators
// into account ðŸ˜. Hence the DIV definition.
logic integer DIV(integer a,integer b) = a / b ;
lemma div_rem:
\forall integer a,b,q,r; a >=0 ==> 0 < b ==> 0 <= r < b ==>
a == b*q+r ==> q == DIV(a, b);
*/
/*#
requires a >= 0 && 0 < b;
ensures \result == DIV(a, b);
*/
int euclid_div(const int a, const int b)
{
int q = 0;
int r = a;
/*#
loop invariant a == b*q+r;
loop invariant r>=0;
loop assigns q,r;
loop variant r;
*/
while (b <= r)
{
q++;
r -= b;
}
/*# assert 0<=r<b; */
/*# assert a == b*q+r; */
return q;
}
More precisely, the lemma itself is proved with the following Coq script:
intros a b q prod Hb Ha Hle Hge.
unfold L_DIV.
generalize (Cdiv_cases a b).
intros Hcdiv; destruct Hcdiv.
clear H0.
rewrite H; auto with zarith.
clear H.
symmetry; apply (Zdiv_unique a b q (a-prod)); auto with zarith.
unfold prod; simpl.
assert (b*q = q*b); auto with zarith.
While the post-condition only requires to instantiate the lemma with the appropriate arguments.
Because it's non-linear arithmetic, which is sometimes hard for automatic (SMT) solvers.
I re-written the goal in SMT2 format, and none of Alt-Ergo 2.2, CVC4 1.5 and Z3 4.6.0 is able to prove it:
(set-logic QF_NIA)
(declare-const i Int)
(declare-const i_1 Int)
(declare-const i_2 Int)
(assert (>= i_1 0))
(assert (> i_2 0))
(assert (>= i 0))
(assert (< i i_2))
; proved by alt-ergo 2.2 and z3 4.6.0 if these two asserts are uncommented
;(assert (<= i_1 10))
;(assert (<= i_2 10))
(assert
(not
(= i_1
(div
(+ i (* i_1 i_2))
i_2 )
)
)
)
(check-sat)
If you change your post-condition like this, it is proved by Alt-Ergo
ensures \exists int r ;
a == b * \result + r && 0 <= r && r < b;
Is there any way to use the decide equality tactic with mutually recursive types in Coq?
For example, if I've got something like this:
Inductive LTree : Set :=
| LNil
| LNode (x: LTree) (y: RTree)
with RTree : Set :=
| RNil
| RNode (x: Tree) (y: RTree).
Lemma eq_LTree : forall (x y : LTree), {x = y} + {x <> y}.
Proof.
decide equality; auto.
This leaves me with the goal:
y0: RTree
y1: RTree
{y0 = y1} + {y0 <> y1}
But I can't solve that until I've derived equality for RTree, which will have the same problem.
You can use decide equality in this case if you prove the two lemmas for LTrees and RTrees simultaneously:
Lemma eq_LTree : forall (x y : LTree), {x = y} + {x <> y}
with eq_RTree : forall (x y : RTree), {x = y} + {x <> y}.
Proof.
decide equality.
decide equality.
Qed.
Now I'm trying to prove a trivial array access procedure(file arr.c):
void set(int* arr, int key, int val)
{
arr[key] = val;
}
The file arr.c is translated to arr.v:
...
Definition f_set := {|
fn_return := tvoid;
fn_callconv := cc_default;
fn_params := ((_arr, (tptr tint)) :: (_key, tint) :: (_val, tint) :: nil);
fn_vars := nil;
fn_temps := nil;
fn_body :=
(Sassign
(Ederef
(Ebinop Oadd (Etempvar _arr (tptr tint)) (Etempvar _key tint)
(tptr tint)) tint) (Etempvar _val tint))
|}.
...
Here is the beginning of my proof (file verif_arr.v):
Require Import floyd.proofauto.
Require Import arr.
Local Open Scope logic.
Local Open Scope Z.
Inductive repr : Z -> val -> Prop :=
| mk_repr : forall z, z >= 0 -> z < Int.modulus -> repr z (Vint (Int.repr z)).
Function aPut (arr:Z -> val) (k:Z) (v:val) : Z -> val :=
fun (kk:Z) => if (Z.eq_dec k kk) then v else arr kk.
Definition set_spec :=
DECLARE _set
WITH sh : share, k : Z, arr : Z->val, vk : val, v : val, varr : val
PRE [_key OF tint, _val OF tint, _arr OF (tptr tint)]
PROP (0 <= k < 100; forall i, 0 <= i < 100 -> is_int (arr i);
writable_share sh; repr k vk)
LOCAL (`(eq vk) (eval_id _key);
`(eq varr) (eval_id _arr);
`(eq v) (eval_id _val);
`isptr (eval_id _arr))
SEP (`(array_at tint sh arr
0 100) (eval_id _arr))
POST [tvoid] `(array_at tint sh (aPut arr k v)
0 100 varr).
Definition Vprog : varspecs := nil.
Definition Gprog : funspecs := set_spec :: nil.
Lemma body_set: semax_body Vprog Gprog f_set set_spec.
Proof.
start_function.
name karg _key.
name arrarg _arr.
name valarg _val.
forward.
entailer!.
After the entailer!. tactic, I've got:
3 subgoals, subgoal 1 (ID 1261)
Espec : OracleKind
sh : share
k : Z
arr : Z -> val
H : 0 <= k < 100
H0 : forall i : Z, 0 <= i < 100 -> is_int (arr i)
H1 : writable_share sh
Delta := abbreviate : tycontext
MORE_COMMANDS := abbreviate : statement
Struct_env := abbreviate : type_id_env.type_id_env
karg : name _key
arrarg : name _arr
valarg : name _val
rho : environ
H2 : repr k (eval_id _key rho)
POSTCONDITION := abbreviate : ret_assert
H3 : isptr (eval_id _arr rho)
============================
offset_val (Int.repr (sizeof tint * 0)) (eval_id _arr rho) =
force_val (sem_add_pi tint (eval_id _arr rho) (eval_id _key rho))
subgoal 2 (ID 1266) is:
?890 = force_val (sem_cast_neutral (eval_id _val rho))
subgoal 3 (ID 1235) is:
semax Delta
(PROP ()
LOCAL (`(eq vk) (eval_id _key); `(eq varr) (eval_id _arr);
`(eq v) (eval_id _val); `isptr (eval_id _arr))
SEP (`(array_at tint sh (upd arr 0 ?890) 0 100) (eval_id _arr)))
(Sreturn None) POSTCONDITION
Now the questions:
In the specification set_spec there is a precondition '(array_at tint sh arr 0 100) (eval_id _arr) (here instead of ' should be backtick, which breaks the formatting). Why is this statement not present in the hypotheses list?
The first subgoal seems to me like it tryes to dereference 0 cell of the array (arr + 0), and it should be equal to a key-th cell (arr + key). That has nothing to do with the code or postcondition and certainly unprovable. What did go wrong here?
I use:
VST version:
Definition svn_rev := "6834P".
Definition release := "1.5".
Definition date := "2014-10-02".
CompCert version: 2.4
Coq version:
The Coq Proof Assistant, version 8.4pl3 (January 2014)
compiled on Jan 19 2014 23:14:16 with OCaml 4.01.0
Edit:
The last local ... part in the post condition turned out redundant.
First, the precondition '(array_at tint sh arr 0 100) (eval_id _arr) is actually present behind abbreviate in Delta hypothesis.
Second, it turned out, that entailer!. tactic is not safe, and can produce unprovable goals from eligible ones. In this case,
first I need to supply additional condition is_int v to be able to assign it to a cell of an "all ints" array. Seemingly VST can't deduce the type from CompCert annotations.
then instead of entailer!. I need to prove first all propositions on the right hand side separately, and then I can apply entailer to combine hypotheses.
Here are the correct spec, and proof:
Inductive repr : Z -> val -> Prop :=
| mk_repr : forall z, z >= 0 -> z < Int.modulus -> repr z (Vint (Int.repr z)).
Function aPut (arr:Z -> val) (k:Z) (v:val) : Z -> val :=
fun (kk:Z) => if (Z.eq_dec k kk) then v else arr kk.
Definition set_spec :=
DECLARE _set
WITH sh : share, k : Z, arr : Z->val, vk : val, v : val, varr : val
PRE [_key OF tint, _val OF tint, _arr OF (tptr tint)]
PROP (0 <= k < 100; forall i, 0 <= i < 100 -> is_int (arr i);
writable_share sh; repr k vk; is_int v)
LOCAL (`(eq vk) (eval_id _key);
`(eq varr) (eval_id _arr);
`(eq v) (eval_id _val);
`isptr (eval_id _arr))
SEP (`(array_at tint sh arr
0 100) (eval_id _arr))
POST [tvoid] `(array_at tint sh (aPut arr k v)
0 100 varr).
Definition Vprog : varspecs := nil.
Definition Gprog : funspecs := set_spec :: nil.
Lemma body_set: semax_body Vprog Gprog f_set set_spec.
Proof.
start_function.
name karg _key.
name arrarg _arr.
name valarg _val.
forward.
instantiate (1:=v).
instantiate (2:=k).
assert (offset_val (Int.repr (sizeof tint * k)) (eval_id _arr rho) =
force_val (sem_add_pi tint (eval_id _arr rho) (eval_id _key rho))).
inversion H2.
rewrite sem_add_pi_ptr.
unfold force_val.
apply f_equal2.
rewrite mul_repr.
auto.
auto.
assumption.
assert (eval_id _val rho = force_val (sem_cast_neutral (eval_id _val rho))).
apply is_int_e in H3.
destruct H3 as [n VtoN].
rewrite VtoN.
auto.
entailer.
forward.
Qed.
I am trying to merge two Maps, but there is no built in method for joining Collections. So how do you do it?
You can implement this using Map.fold and Map.add, since add is actually add/replace:
let map1 = Map.ofList [ 1, "one"; 2, "two"; 3, "three" ]
let map2 = Map.ofList [ 2, "two"; 3, "oranges"; 4, "four" ]
let newMap = Map.fold (fun acc key value -> Map.add key value acc) map1 map2
printfn "%A" newMap
Probably the reason merge isn't provided out of the box is that you need to deal with key conflicts. In this simple merge algorithm we simple take the key value pair from the second map, this may not be the behaviour you want.
An alternative way is this:
let merge (a : Map<'a, 'b>) (b : Map<'a, 'b>) (f : 'a -> 'b * 'b -> 'b) =
Map.fold (fun s k v ->
match Map.tryFind k s with
| Some v' -> Map.add k (f k (v, v')) s
| None -> Map.add k v s) a b
It lets you decide on what value you want if there is duplicate keys.
Example:
let a = Map([1,11;2,21;3,31;])
let b = Map([3,32; 4,41;5,51;6,61;])
merge a b (fun k (v, v') -> v + v');;
//Result
val it : Map<int,int> =
map [(1, 11); (2, 21); (3, 63); (4, 41); (5, 51); (6, 61)]
Notice that the key 3 is different.
Define the following function:
let join (p:Map<'a,'b>) (q:Map<'a,'b>) =
Map(Seq.concat [ (Map.toSeq p) ; (Map.toSeq q) ])
example:
let a = Map([1,11;2,21;3,31;])
let b = Map([3,32; 4,41;5,51;6,61;])
let c = join a b
and the result:
val c : Map<int,int> =
map [(1, 11); (2, 21); (3, 32); (4, 41); (5, 51); (6, 61)]
If you prefer using function composition you could define a join function like this:
let join (m1:Map<'a,'b>) (m2:Map<'a,'b>) =
Map.foldBack Map.add m2 m1
Given that m1 and m2 are Maps you would then use it like this:
m3 = join m1 m2
Some caveats:
Keys in m2 will overwrite those in m1
As others have noted it's faster to let the smaller map be the second argument as it will result in fewer insertions