diff options
author | Alex Auvolat <alex.auvolat@ansys.com> | 2014-06-26 16:57:10 +0200 |
---|---|---|
committer | Alex Auvolat <alex.auvolat@ansys.com> | 2014-06-26 16:57:10 +0200 |
commit | f3d89408ebb44f77f257b2cb51a4bdd74b9268d0 (patch) | |
tree | adc4b2505f907ea031c0a8d082b077702d8f49eb | |
parent | dcdcedf42c8c3a3041c0fcda6a5a3362777672f5 (diff) | |
download | scade-analyzer-f3d89408ebb44f77f257b2cb51a4bdd74b9268d0.tar.gz scade-analyzer-f3d89408ebb44f77f257b2cb51a4bdd74b9268d0.zip |
Many things, sorry for the mess.
- Implement two new enumeration domains (they don't bring us much) :
multi valuation for variables ;
multi valuation for variables and pairs of variables (not really sure it works)
- Make it so that the number of init/time variables is reduced
(do not create new init/time variables on node instanciation, only
inside activate blocks and automaton states)
- Some work on EDD (it is currently broken and does not compile)
-rw-r--r-- | abstract/abs_interp_edd.ml | 186 | ||||
-rw-r--r-- | abstract/enum_domain.ml | 343 | ||||
-rw-r--r-- | abstract/transform.ml | 229 | ||||
-rw-r--r-- | frontend/typing.ml | 53 | ||||
-rw-r--r-- | main.ml | 10 |
5 files changed, 615 insertions, 206 deletions
diff --git a/abstract/abs_interp_edd.ml b/abstract/abs_interp_edd.ml index 3ff91a6..4f2ad81 100644 --- a/abstract/abs_interp_edd.ml +++ b/abstract/abs_interp_edd.ml @@ -11,8 +11,6 @@ module I (ND : NUMERICAL_ENVIRONMENT_DOMAIN) : sig val do_prog : cmdline_opt -> rooted_prog -> unit - val test : unit -> unit - end = struct @@ -31,10 +29,11 @@ end = struct ev_order : (id, int) Hashtbl.t; } - type edd = + type edd_node = | DBot | DVal of int | DChoice of id * (item * edd) list + and edd = int * edd_node type edd_v = { ve : varenv; @@ -43,40 +42,66 @@ end = struct (* add here eventual annotations *) } + (* + Utility functions for memoization + + memo : (((int * 'a) -> (int * 'b)) -> 'a -> 'b) -> (int * 'a) -> (int * 'b) + memo2 : (((int * 'a) -> (int * 'b) -> (int * 'c)) -> 'a -> 'b -> 'c) -> (int * 'a) -> (int * 'b) -> (int * 'c) + *) + let memo f = + let n = ref 0 in + let memo = Hashtbl.create 12 in + let rec ff (id, v) = + try Hashtbl.find memo id + with Not_found -> + let r = f ff v in + incr n; + Hashtbl.add memo id (n, r); + n, r + in ff + let memo2 f = + let n = ref 0 in + let memo = Hashtbl.create 12 in + let rec ff (id1, v1) (id2, v2) = + try Hashtbl.find memo (id1, id2) + with Not_found -> + let r = f ff v1 v2 in + incr n; + Hashtbl.add memo (id1, id2) (n, r); + n, r + in ff (* edd_print : Format.formatter -> edd_v -> unit *) let edd_print fmt v = - let ids = Hashtbl.create 12 in - let n = ref 0 in - let rec mkid = function - | DChoice(_, l) as x -> - if not (Hashtbl.mem ids x) then begin - incr n; Hashtbl.add ids x !n; - List.iter (fun (_, x) -> mkid x) l + let c_nodes = Hashtbl.create 12 in + let rec add = function + | n, (DChoice(_, l) as x) -> + if not (Hashtbl.mem c_nodes n) then begin + Hashtbl.add c_nodes n x; + List.iter (fun (_, y) -> add y) l end | _ -> () - in mkid v.root; + in add v.root; + let print_n fmt = function - | DBot -> Format.fprintf fmt "⊥"; - | DVal i -> Format.fprintf fmt "v%d" i; - | DChoice _ as x -> Format.fprintf fmt "n%d" (Hashtbl.find ids x) + | (_, DBot) -> Format.fprintf fmt "⊥"; + | (_, DVal i) -> Format.fprintf fmt "v%d" i; + | (n, DChoice _) -> Format.fprintf fmt "n%d" n in Format.fprintf fmt "Root: %a@." print_n v.root; - for id = 1 to !n do - let c = ref None in - Hashtbl.iter (fun u i -> if i = id then c := Some u) ids; - let x = match !c with | Some x -> x | None -> assert false in - match x with + + Hashtbl.iter + (fun id x -> match x with | DChoice (var, l) -> let p fmt (c, l) = Format.fprintf fmt "%s → %a" c print_n l in Format.fprintf fmt "n%d: %a ? @[<hov>%a@]@." id Formula_printer.print_id var (print_list p ", ") l - | _ -> assert false - done; + | _ -> assert false) + c_nodes; Hashtbl.iter (fun id v -> Format.fprintf fmt "v%d: %a@." id ND.print v) v.leaves @@ -86,7 +111,7 @@ end = struct (* edd_bot : varenv -> edd_v *) - let edd_bot ve = { ve; root = DBot; leaves = Hashtbl.create 1 } + let edd_bot ve = { ve; root = (0, DBot); leaves = Hashtbl.create 1 } (* edd_top : evar list -> nvar list -> edd_v @@ -94,7 +119,7 @@ end = struct let edd_top ve = let leaves = Hashtbl.create 1 in Hashtbl.add leaves 0 (ND.top ve.nvars); - { ve; root = DVal 0; leaves } + { ve; root = (1, DVal 0); leaves } (* edd_of_cons : varenv -> enum_cons -> edd_v @@ -105,23 +130,27 @@ end = struct let leaves = Hashtbl.create 1 in Hashtbl.add leaves 0 (ND.top ve.nvars); + let bot, top = (0, DBot), (1, DVal 0) in + let root = match r with | EItem x -> - DChoice(vid, - List.map (fun v -> if op v x then v, DVal 0 else v, DBot) - (List.assoc vid ve.evars)) + 2, DChoice(vid, + List.map (fun v -> if op v x then v, bot else v, top) + (List.assoc vid ve.evars)) | EIdent vid2 -> let a, b = if Hashtbl.find ve.ev_order vid < Hashtbl.find ve.ev_order vid2 then vid, vid2 else vid2, vid in + let n = ref 2 in let nb x = - DChoice(b, - List.map (fun v -> if op v x then v, DVal 0 else v, DBot) - (List.assoc b ve.evars)) + incr n; + !n, DChoice(b, + List.map (fun v -> if op v x then v, top else v, bot) + (List.assoc b ve.evars)) in - DChoice(a, List.map (fun x -> x, nb x) (List.assoc a ve.evars)) + 2, DChoice(a, List.map (fun x -> x, nb x) (List.assoc a ve.evars)) in { ve; root; leaves } @@ -131,10 +160,9 @@ end = struct let edd_join a b = let ve = a.ve in - let leaves = Hashtbl.copy a.leaves in - let n = ref 0 in - Hashtbl.iter (fun i _ -> if i > !n then n := i) leaves; + let leaves = Hashtbl.create 12 in + let n = ref 0 in let get_leaf x = let id = ref None in Hashtbl.iter (fun i v -> if ND.eq v x then id := Some i) leaves; @@ -147,61 +175,47 @@ end = struct end in - let memo_bcopy = Hashtbl.create 12 in - let rec bcopy nb = - try Hashtbl.find memo_bcopy nb - with Not_found -> let r = - match nb with - | DBot -> DBot - | DVal i -> get_leaf (Hashtbl.find b.leaves i) - | DChoice (v, x) -> - DChoice(v, List.map (fun (c, n) -> c, bcopy n) x) - in Hashtbl.add memo_bcopy nb r; r - in - let memo = Hashtbl.create 12 in - let rec f (na, nb) = - try Hashtbl.find memo (na, nb) - with Not_found -> let r = - let dq v l = - let _, x0 = List.hd l in - if List.exists (fun (_, x) -> x <> x0) l - then DChoice(v, l) - else x0 + let f f_rec na nb = + let dq v l = + let _, (i, x0) = List.hd l in + if List.exists (fun (_, (j, x)) -> j <> i || x <> x0) l + then DChoice(v, l) + else x0 + in + match na, nb with + | DBot, DBot -> DBot + | DBot, DVal i -> get_leaf (Hashtbl.find b.leaves i) + | x, DBot -> x + + | DChoice(va, la), DChoice(vb, lb) when va = vb -> + let kl = List.map2 + (fun (ta, ba) (tb, bb) -> assert (ta = tb); + ta, f (ba, bb)) + la lb in - match na, nb with - | DBot, x -> bcopy x - | x, DBot -> x - - | DChoice(va, la), DChoice(vb, lb) when va = vb -> - let kl = List.map2 - (fun (ta, ba) (tb, bb) -> assert (ta = tb); - ta, f (ba, bb)) - la lb - in - dq va kl - | DChoice(va, la), DChoice(vb, lb) -> - let v, kl = - if Hashtbl.find ve.ev_order va < Hashtbl.find ve.ev_order vb then - va, List.map (fun (k, ca) -> k, f (ca, nb)) la - else - vb, List.map (fun (k, cb) -> k, f (na, cb)) lb - in - dq v kl - - | DChoice(va, la), _ -> - let kl = List.map (fun (k, ca) -> k, f (ca, nb)) la in - dq va kl - | _, DChoice(vb, lb) -> - let kl = List.map (fun (k, cb) -> k, f (na, cb)) lb in - dq vb kl - - | DVal u, DVal v -> - let x = ND.join (Hashtbl.find a.leaves u) (Hashtbl.find b.leaves v) in - get_leaf x - in Hashtbl.add memo (na, nb) r; r + dq va kl + | DChoice(va, la), DChoice(vb, lb) -> + let v, kl = + if Hashtbl.find ve.ev_order va < Hashtbl.find ve.ev_order vb then + va, List.map (fun (k, ca) -> k, f (ca, nb)) la + else + vb, List.map (fun (k, cb) -> k, f (na, cb)) lb + in + dq v kl + + | DChoice(va, la), _ -> + let kl = List.map (fun (k, ca) -> k, f (ca, nb)) la in + dq va kl + | _, DChoice(vb, lb) -> + let kl = List.map (fun (k, cb) -> k, f (na, cb)) lb in + dq vb kl + + | DVal u, DVal v -> + let x = ND.join (Hashtbl.find a.leaves u) (Hashtbl.find b.leaves v) in + get_leaf x in - { leaves; ve; root = f (a.root, b.root) } + { leaves; ve; root = memo2 f a.root b.root } (* edd_meet : edd_v -> edd_v -> edd_v @@ -342,6 +356,7 @@ end = struct in f (a.root, b.root) + (* let test () = let ve = { evars = ["x", ["tt"; "ff"]; "y", ["tt"; "ff"]; "z", ["tt"; "ff"]]; @@ -358,6 +373,7 @@ end = struct Format.printf "x = y && y != z : @[%a@]@." edd_print w; let t = edd_join u v in Format.printf "x = y || y != z : @[%a@]@." edd_print t + *) (* ****************************** diff --git a/abstract/enum_domain.ml b/abstract/enum_domain.ml index c8b4ec5..2353049 100644 --- a/abstract/enum_domain.ml +++ b/abstract/enum_domain.ml @@ -34,6 +34,9 @@ module type ENUM_ENVIRONMENT_DOMAIN = sig end +(* + Simple domain : one valuation for each variable, or T +*) module Valuation : ENUM_ENVIRONMENT_DOMAIN = struct type item = string @@ -142,3 +145,343 @@ module Valuation : ENUM_ENVIRONMENT_DOMAIN = struct Format.fprintf fmt " }@]" end + + +(* + Less simple domain : a set of possible values for each variable, or T +*) + +module MultiValuation : ENUM_ENVIRONMENT_DOMAIN = struct + type item = string + + type t = { + vars : (id * item list) list; + value : item list VarMap.t; + } + + let sort = List.sort Pervasives.compare + let uniq x = uniq_sorted (sort x) + + let top vars = { vars; value = VarMap.empty } + + let vars x = x.vars + + let forgetvar x id = + { x with value = VarMap.remove id x.value } + let project x id = + try VarMap.find id x.value + with Not_found -> List.assoc id x.vars + + let join x1 x2 = + let v = VarMap.merge + (fun _ a b -> match a, b with + | Some a, Some b -> Some (uniq (a@b)) + | _ -> None) + x1.value x2.value in + { x1 with value = v } + let meet x1 x2 = + let v = VarMap.merge + (fun _ a b -> match a, b with + | Some a, None | None, Some a -> Some a + | Some a, Some b -> + begin match List.filter (fun x -> List.mem x b) a with + | [] -> raise Bot | l -> Some l end + | _ -> None) + x1.value x2.value in + { x1 with value = v } + + let subset a b = + VarMap.for_all + (fun id v -> + try let v2 = VarMap.find id b.value in + List.for_all (fun x -> List.mem x v2) v + with Not_found -> true) + a.value + let eq a b = subset a b && subset b a + + let apply_cons x (op, id, e) = + let op = match op with | E_EQ -> (=) | E_NE -> (<>) in + + match e with + | EItem s -> + let pv = project x id in + begin match List.filter (op s) pv with + | [] -> [] + | vals -> [{ x with value = VarMap.add id vals x.value }] + end + | EIdent id2 -> + let v1 = project x id in + let v2 = project x id2 in + List.fold_left + (fun l v1 -> + let v2 = List.filter (op v1) v2 in + let x = { x with value = VarMap.add id [v1] x.value } in + match v2 with + | [] -> l + | _ -> { x with value = VarMap.add id2 v2 x.value }::l) + [] v1 + + let assign x idl = + let v = List.fold_left + (fun v (id, id2) -> + try VarMap.add id (VarMap.find id2 x.value) v + with Not_found -> VarMap.remove id v ) + x.value idl + in { x with value = v } + + + let print fmt x = + let b = List.map (fun (x, y) -> y, x) (VarMap.bindings x.value) in + let s = List.sort Pervasives.compare b in + let rec bl = function + | [] -> [] + | (v, id)::q -> + let v = sort v in + if v <> sort (List.assoc id x.vars) then + match bl q with + | (vv, ids)::q when vv = v -> (v, id::ids)::q + | r -> (v, [id])::r + else + bl q + in + let sbl = bl s in + Format.fprintf fmt "@[<v 2>{ "; + List.iteri + (fun j (v, ids) -> + if j > 0 then Format.fprintf fmt "@ "; + Format.fprintf fmt "@[<hov 4>"; + List.iteri + (fun i id -> + if i > 0 then Format.fprintf fmt ",@ "; + Format.fprintf fmt "%a" Formula_printer.print_id id) + ids; + match v with + | [v0] -> Format.fprintf fmt " ≡ %s@]" v0 + | l -> Format.fprintf fmt " ∊ @[<hov>{ %a }@]@]" (print_list Format.pp_print_string ", ") l) + sbl; + Format.fprintf fmt " }@]" + +end + + +(* + Complicated domain : a set of values for each variables, plus some + constraints on couples of variables + (eg. (x, y) in [ tt, tt ; ff, ff ] +*) + +module MultiValuationCCons : ENUM_ENVIRONMENT_DOMAIN = struct + + module VarC = struct + type t = id * id + let compare = Pervasives.compare + end + module VarCMap = Mapext.Make(VarC) + + type item = string + + type t = { + vars : (id * item list) list; + value : item list VarMap.t; + + (* in ccond (x, y) -> l, must have x < y (textual order on identifiers) -> unicity *) + ccons : (item * item) list VarCMap.t; + } + + let sort = List.sort Pervasives.compare + let uniq x = uniq_sorted (sort x) + let list_inter x y = List.filter (fun k -> List.mem k y) x + + let all_couples l1 l2 = + List.flatten + (List.map (fun x -> List.map (fun y -> x, y) l2) l1) + + let top vars = { vars; value = VarMap.empty; ccons = VarCMap.empty } + + let vars x = x.vars + + let forgetvar x id = + (* TODO : try to find a substitution variable so that some contraints can be propagated. + this is important so that cycle passing can be done correctly ! *) + { x with + value = VarMap.remove id x.value; + ccons = VarCMap.filter (fun (a, b) _ -> a <> id && b <> id) x.ccons } + + let project x id = + try VarMap.find id x.value + with Not_found -> List.assoc id x.vars + + let project2 x id1 id2 = + try + let id1', id2' = ord_couple (id1, id2) in + if id1' = id1 then + VarCMap.find (id1, id2) x.ccons + else + List.map (fun (a, b) -> b, a) (VarCMap.find (id1', id2') x.ccons) + with _ -> + let v1, v2 = project x id1, project x id2 in + all_couples v1 v2 + + let strict x = + let rec f x = + (* + - if (x, y) in [ a, b1 ; a, b2 ; ... ; a, bn ], + replace this by x = a and y in { b1, ..., bn } + - filter (x, y) in [ ... ] with x in specified itv, y in specified itv + *) + let usefull, vv, cc = + VarCMap.fold + (fun (x, y) l (usefull, vv, cc) -> + let p1, p2 = uniq (List.map fst l), uniq (List.map snd l) in + let p1 = try list_inter p1 (VarMap.find x vv) with _ -> p1 in + let p2 = try list_inter p2 (VarMap.find y vv) with _ -> p2 in + + if p1 = [] || p2 = [] then raise Bot; + let vv = VarMap.add x p1 (VarMap.add y p2 vv) in + + if List.length p1 = 1 || List.length p2 = 1 + then + true, vv, cc + else + match List.filter (fun (u, v) -> List.mem u p1 && List.mem v p2) l with + | [] -> raise Bot + | l2 -> List.length l2 < List.length l, vv, VarCMap.add (x, y) l2 cc) + x.ccons (false, x.value, VarCMap.empty) in + + let x = { x with value = vv; ccons = cc } in + if usefull then f x else x + in + f x + + let join x1 x2 = + let v = VarMap.merge + (fun _ a b -> match a, b with + | Some a, Some b -> Some (uniq (a@b)) + | _ -> None) + x1.value x2.value in + let x = { x1 with value = v } in + + let cc = VarCMap.merge + (fun (id1, id2) l1 l2 -> + let v1, v2 = project x1 id1, project x id2 in + let ac = all_couples v1 v2 in + let c = List.filter + (fun q -> + (match l1 with Some l -> List.mem q l | _ -> true) || + (match l2 with Some l -> List.mem q l | _ -> true)) + ac in + if List.length c < List.length ac then Some c else None) + x1.ccons x2.ccons in + + strict { x with ccons = cc } + + let meet x1 x2 = + let v = VarMap.merge + (fun _ a b -> match a, b with + | Some a, None | None, Some a -> Some a + | Some a, Some b -> + begin match list_inter a b with + | [] -> raise Bot | l -> Some l end + | _ -> None) + x1.value x2.value in + let x = { x1 with value = v } in + + let cc = VarCMap.merge + (fun (id1, id2) l1 l2 -> + let v1, v2 = project x id1, project x id2 in + let ac = all_couples v1 v2 in + let c1 = match l1 with Some l -> list_inter l ac | None -> ac in + let c2 = match l2 with Some l -> list_inter l ac | None -> ac in + match list_inter c1 c2 with + | [] -> raise Bot + | l -> if List.length l < List.length ac then Some l else None) + x1.ccons x2.ccons in + + strict { x with ccons = cc } + + let subset a b = + VarMap.for_all + (fun id v -> + let vs = project a id in + List.for_all (fun c -> List.mem c vs) v) + b.value + && + VarCMap.for_all + (fun (id1, id2) l -> + let l2 = project2 a id1 id2 in + List.for_all (fun c -> List.mem c l) l2) + b.ccons + let eq a b = + subset a b && subset b a + + let apply_cons x (op, id, e) = + let op = match op with | E_EQ -> (=) | E_NE -> (<>) in + + match e with + | EItem s -> + let pv = project x id in + begin match List.filter (op s) pv with + | [] -> [] + | vals -> try [strict { x with value = VarMap.add id vals x.value }] with Bot -> [] + end + | EIdent id2 -> + let id, id2 = ord_couple (id, id2) in + let c = project2 x id id2 in + let ok_c = List.filter (fun (a, b) -> op a b) c in + try + [match uniq (List.map fst ok_c), uniq (List.map snd ok_c) with + | [], _ | _, [] -> raise Bot + | [a], q -> strict { x with value = VarMap.add id [a] (VarMap.add id2 q x.value) } + | q, [b] -> strict { x with value = VarMap.add id q (VarMap.add id2 [b] x.value) } + | _ -> strict { x with ccons = VarCMap.add (id, id2) ok_c x.ccons} + ] + with Bot -> [] + + let assign x idl = + let x2 = List.fold_left (fun x (v, _) -> forgetvar x v) x idl in + let v = List.fold_left + (fun v (id, id2) -> + try VarMap.add id (VarMap.find id2 x.value) v + with Not_found -> v) + x2.value idl in + let c = VarCMap.fold + (fun (v1, v2) l c -> + let v1' = try List.assoc v1 idl with _ -> v1 in + let v2' = try List.assoc v2 idl with _ -> v2 in + VarCMap.add (v1', v2') l c) + x.ccons x2.ccons in + strict { x with value = v; ccons = c } + + + let print fmt x = + let b = List.map (fun (x, y) -> y, x) (VarMap.bindings x.value) in + let s = List.sort Pervasives.compare b in + let rec bl = function + | [] -> [] + | (v, id)::q -> + let v = sort v in + if v <> sort (List.assoc id x.vars) then + match bl q with + | (vv, ids)::q when vv = v -> (v, id::ids)::q + | r -> (v, [id])::r + else + bl q + in + let sbl = bl s in + Format.fprintf fmt "@[<v 2>{ "; + List.iteri + (fun j (v, ids) -> + if j > 0 then Format.fprintf fmt "@ "; + Format.fprintf fmt "@[<hov 4>"; + List.iteri + (fun i id -> + if i > 0 then Format.fprintf fmt ",@ "; + Format.fprintf fmt "%a" Formula_printer.print_id id) + ids; + match v with + | [v0] -> Format.fprintf fmt " ≡ %s@]" v0 + | l -> Format.fprintf fmt " ∊ @[<hov>{ %a }@]@]" (print_list Format.pp_print_string ", ") l) + sbl; + Format.fprintf fmt " }@]" + +end diff --git a/abstract/transform.ml b/abstract/transform.ml index b9c173d..4a13e18 100644 --- a/abstract/transform.ml +++ b/abstract/transform.ml @@ -26,8 +26,8 @@ type ne_expr = (* f_of_neexpr : transform_data -> (string, string) -> (ne_expr list -> bool_expr) -> expr -> bool_expr *) -let rec f_of_neexpr td (node, prefix) where expr = - let sub = f_of_neexpr td (node, prefix) in +let rec f_of_neexpr td (node, prefix, clock_scope) where expr = + let sub = f_of_neexpr td (node, prefix, clock_scope) in let le = loc_error (snd expr) in match fst expr with (* ident *) @@ -71,24 +71,27 @@ let rec f_of_neexpr td (node, prefix) where expr = | TEnum _ -> EE(EIdent x)) typ) | AST_arrow(a, b) -> - if td.rp.init_scope (node^"/") + if td.rp.init_scope clock_scope then f_or - (f_and (f_e_eq (EIdent (node^"/"^prefix^"init")) (EItem bool_true)) + (f_and (f_e_eq (EIdent (clock_scope^"init")) (EItem bool_true)) (sub where a)) - (f_and (f_e_eq (EIdent (node^"/"^prefix^"init")) (EItem bool_false)) + (f_and (f_e_eq (EIdent (clock_scope^"init")) (EItem bool_false)) (sub where b)) - else + else if not (td.rp.no_time_scope clock_scope) + then f_or - (f_and (BRel(AST_EQ, NIdent(node^"/"^prefix^"time"), NIntConst 0)) + (f_and (BRel(AST_EQ, NIdent(clock_scope^"time"), NIntConst 0)) (sub where a)) - (f_and (BRel(AST_GE, NIdent(node^"/"^prefix^"time"), NIntConst 1)) + (f_and (BRel(AST_GE, NIdent(clock_scope^"time"), NIntConst 1)) (sub where b)) + else + f_or (sub where a) (sub where b) (* other *) | AST_if(c, a, b) -> f_or - (f_and (f_of_expr td (node, prefix) c) (sub where a)) - (f_and (BNot(f_of_expr td (node, prefix) c)) (sub where b)) + (f_and (f_of_expr td (node, prefix, clock_scope) c) (sub where a)) + (f_and (BNot(f_of_expr td (node, prefix, clock_scope) c)) (sub where b)) | AST_instance ((f, _), args, nid) -> let (n, _) = find_node_decl td.rp.p f in where @@ -107,8 +110,9 @@ let rec f_of_neexpr td (node, prefix) where expr = (* boolean values treated as enumerated types *) | _ when type_expr td.rp node expr = [bool_type] -> f_or - (f_and (f_of_expr td (node, prefix) expr) (where [EE (EItem bool_true)])) - (f_and (f_of_expr td (node, prefix) (AST_not(expr), snd expr)) + (f_and (f_of_expr td (node, prefix, clock_scope) expr) + (where [EE (EItem bool_true)])) + (f_and (f_of_expr td (node, prefix, clock_scope) (AST_not(expr), snd expr)) (where [EE (EItem bool_false)])) | _ -> le type_error "Expected numerical/enumerated value" @@ -120,8 +124,8 @@ let rec f_of_neexpr td (node, prefix) where expr = f_of_bexpr : transform_data -> (string, string) -> (bool_expr -> bool_expr) -> expr -> bool_expr *) -and f_of_bexpr td (node, prefix) where expr = - let sub = f_of_bexpr td (node, prefix) in +and f_of_bexpr td (node, prefix, clock_scope) where expr = + let sub = f_of_bexpr td (node, prefix, clock_scope) in match fst expr with | AST_bool_const b -> where (BConst b) | AST_binary_bool(AST_AND, a, b) -> f_and (sub where a) (sub where b) @@ -129,7 +133,7 @@ and f_of_bexpr td (node, prefix) where expr = | AST_not(a) -> BNot(sub where a) | AST_binary_rel(rel, a, b) -> where - (f_of_neexpr td (node, prefix) + (f_of_neexpr td (node, prefix, clock_scope) (function | [NE x; NE y] -> BRel(rel, x, y) | [EE x; EE y] -> @@ -142,11 +146,22 @@ and f_of_bexpr td (node, prefix) where expr = (AST_tuple [a; b], snd expr)) (* Temporal *) | AST_arrow(a, b) -> + if td.rp.init_scope clock_scope + then f_or - (f_and (BRel(AST_EQ, NIdent(node^"/"^prefix^"time"), NIntConst 0)) + (f_and (f_e_eq (EIdent (clock_scope^"init")) (EItem bool_true)) (sub where a)) - (f_and (BRel(AST_GE, NIdent(node^"/"^prefix^"time"), NIntConst 1)) + (f_and (f_e_eq (EIdent (clock_scope^"init")) (EItem bool_false)) (sub where b)) + else if not (td.rp.no_time_scope clock_scope) + then + f_or + (f_and (BRel(AST_EQ, NIdent(clock_scope^"time"), NIntConst 0)) + (sub where a)) + (f_and (BRel(AST_GE, NIdent(clock_scope^"time"), NIntConst 1)) + (sub where b)) + else + f_or (sub where a) (sub where b) (* Enumerations... *) | _ when type_expr td.rp node expr = [bool_type] -> let ff = function @@ -156,23 +171,53 @@ and f_of_bexpr td (node, prefix) where expr = (f_and (f_e_eq x (EItem bool_false)) (where (BConst false))) | _ -> assert false in - f_of_neexpr td (node, prefix) ff expr + f_of_neexpr td (node, prefix, clock_scope) ff expr | _ -> type_error "Expected boolean value." -and f_of_expr td (node, prefix) expr = - f_of_bexpr td (node, prefix) (fun x -> x) expr +and f_of_expr td (node, prefix, clock_scope) expr = + f_of_bexpr td (node, prefix, clock_scope) (fun x -> x) expr (* Translate program into one big formula *) -let rec f_of_scope active td (node, prefix, eqs) assume_guarantees = + +let clock_scope_here (node, prefix, _) = + node^"/"^prefix + +let gen_clock td (node, prefix, _) active = + let clock_scope = node^"/"^prefix in + let clock_eq = + if active then + f_and + (if not (td.rp.no_time_scope clock_scope) + then BRel(AST_EQ, NIdent("N"^clock_scope^"time"), + NBinary(AST_PLUS, NIntConst 1, NIdent(clock_scope^"time"))) + else BConst true) + (if td.rp.init_scope clock_scope + then f_e_eq (EIdent("N"^clock_scope^"init")) (EItem bool_false) + else BConst true) + else + f_and + (if not (td.rp.no_time_scope clock_scope) + then BRel(AST_EQ, + NIdent("N"^clock_scope^"time"), + NIdent(clock_scope^"time")) + else BConst true) + (if td.rp.init_scope clock_scope + then f_e_eq (EIdent("N"^clock_scope^"init")) + (EIdent (clock_scope^"init")) + else BConst true) + in + clock_scope, clock_eq + +let rec f_of_scope active td (node, prefix, eqs) clock_scope assume_guarantees = let expr_eq e = let instance_eq (_, id, eqs, args) = - let eq = f_of_scope active td (node^"/"^id, "", eqs) assume_guarantees in + let eq = f_of_scope active td (node^"/"^id, "", eqs) clock_scope assume_guarantees in if active then let arg_eq ((_,argname,_), expr) = - f_of_neexpr td (node, prefix) (function + f_of_neexpr td (node, prefix, clock_scope) (function | [NE v] -> BRel(AST_EQ, NIdent(node^"/"^id^"/"^argname), v) | [EE v] -> f_e_eq (EIdent(node^"/"^id^"/"^argname)) v | _ -> invalid_arity "in argument") @@ -186,7 +231,7 @@ let rec f_of_scope active td (node, prefix, eqs) assume_guarantees = let pre_expr (id, expr) = let id = node^"/"^id in if active then - f_of_neexpr td (node, prefix) (fun elist -> + f_of_neexpr td (node, prefix, clock_scope) (fun elist -> list_fold_op f_and (List.mapi (fun i v -> let x = ("N"^id^"."^(string_of_int i)) in @@ -222,7 +267,7 @@ let rec f_of_scope active td (node, prefix, eqs) assume_guarantees = in f_and_list rels in - f_of_neexpr td (node, prefix) apply_f e + f_of_neexpr td (node, prefix, clock_scope) apply_f e else BConst true in @@ -230,7 +275,7 @@ let rec f_of_scope active td (node, prefix, eqs) assume_guarantees = | AST_assume (_, e) -> let assume_eq = if active then - f_of_expr td (node, prefix) e + f_of_expr td (node, prefix, clock_scope) e else BConst true in @@ -239,13 +284,13 @@ let rec f_of_scope active td (node, prefix, eqs) assume_guarantees = let gn = node^"/g_"^id in let guarantee_eq = if active && assume_guarantees then - f_and (f_of_expr td (node, prefix) e) + f_and (f_of_expr td (node, prefix, clock_scope) e) (BEnumCons(E_EQ, gn, EItem bool_true)) else f_or - (f_and (f_of_expr td (node, prefix) e) + (f_and (f_of_expr td (node, prefix, clock_scope) e) (BEnumCons(E_EQ, gn, EItem bool_true))) - (f_and (BNot (f_of_expr td (node, prefix) e)) + (f_and (BNot (f_of_expr td (node, prefix, clock_scope) e)) (BEnumCons(E_EQ, gn, EItem bool_false))) in f_and (expr_eq e) guarantee_eq @@ -258,16 +303,20 @@ let rec f_of_scope active td (node, prefix, eqs) assume_guarantees = in let rec do_tree_act = function | AST_activate_body b -> - f_of_scope true td (node, b.act_id^".", b.body) assume_guarantees + let b_scope = node, b.act_id^".", b.body in + let clock_scope, clock_eq = gen_clock td b_scope true in + f_and clock_eq (f_of_scope true td b_scope clock_scope assume_guarantees) | AST_activate_if(c, a, b) -> f_or - (f_and (f_of_expr td (node, prefix) c) + (f_and (f_of_expr td (node, prefix, clock_scope) c) (f_and (do_tree_act a) (do_tree_inact b))) - (f_and (BNot(f_of_expr td (node, prefix) c)) + (f_and (BNot(f_of_expr td (node, prefix, clock_scope) c)) (f_and (do_tree_act b) (do_tree_inact a))) and do_tree_inact = function | AST_activate_body b -> - f_of_scope false td (node, b.act_id^".", b.body) assume_guarantees + let b_scope = node, b.act_id^".", b.body in + let clock_scope, clock_eq = gen_clock td b_scope false in + f_and clock_eq (f_of_scope false td b_scope clock_scope assume_guarantees) | AST_activate_if(_, a, b) -> f_and (do_tree_inact a) (do_tree_inact b) in @@ -276,24 +325,27 @@ let rec f_of_scope active td (node, prefix, eqs) assume_guarantees = let stv = node^"/"^aid^".state" in let nstv = "N"^node^"/"^aid^".state" in let st_eq_inact (st, _) = - f_and - (f_of_scope false td - (node, aid^"."^st.st_name^".", st.body) assume_guarantees) - (f_and_list (List.map (fun (c, _, _) -> expr_eq c) st.until)) + let st_scope = node, aid^"."^st.st_name^".", st.body in + let clock_scope, clock_eq = gen_clock td st_scope false in + f_and clock_eq + (f_and + (f_of_scope false td st_scope clock_scope assume_guarantees) + (f_and_list (List.map (fun (c, _, _) -> expr_eq c) st.until))) in if active then let st_eq_act (st, l) = let act_eq = - let st_eq = f_of_scope true td - (node, aid^"."^st.st_name^".", st.body) assume_guarantees in + let st_scope = node, aid^"."^st.st_name^".", st.body in + let clock_scope, clock_eq = gen_clock td st_scope true in + let st_eq = f_and clock_eq (f_of_scope true td st_scope clock_scope assume_guarantees) in let rec aux = function | [] -> BEnumCons(E_EQ, nstv, EItem st.st_name) | (c, (target, l), rst)::q -> if rst then loc_error l error "Resetting transitions not supported."; f_or - (f_and (f_of_expr td (node, prefix) c) + (f_and (f_of_expr td (node, prefix, clock_scope) c) (BEnumCons(E_EQ, nstv, EItem target))) - (f_and (BNot (f_of_expr td (node, prefix) c)) (aux q)) + (f_and (BNot (f_of_expr td (node, prefix, clock_scope) c)) (aux q)) in f_and st_eq (aux st.until) in f_or @@ -305,31 +357,7 @@ let rec f_of_scope active td (node, prefix, eqs) assume_guarantees = else f_and_list (List.map st_eq_inact states) in - let time_incr_eq = - if active then - f_and - (if not (td.rp.no_time_scope (node^"/")) - then BRel(AST_EQ, NIdent("N"^node^"/"^prefix^"time"), - NBinary(AST_PLUS, NIntConst 1, NIdent(node^"/"^prefix^"time"))) - else BConst true) - (if td.rp.init_scope (node^"/") - then f_e_eq (EIdent("N"^node^"/"^prefix^"init")) (EItem bool_false) - else BConst true) - else - f_and - (if not (td.rp.no_time_scope (node^"/")) - then BRel(AST_EQ, - NIdent("N"^node^"/"^prefix^"time"), - NIdent(node^"/"^prefix^"time")) - else BConst true) - (if td.rp.init_scope (node^"/") - then f_e_eq (EIdent("N"^node^"/"^prefix^"init")) - (EIdent (node^"/"^prefix^"init")) - else BConst true) - in - List.fold_left f_and - time_incr_eq - (List.map do_eq eqs) + f_and_list (List.map do_eq eqs) and f_of_prog rp assume_guarantees = let td = { @@ -337,15 +365,34 @@ and f_of_prog rp assume_guarantees = consts = I.consts rp; } in - f_of_scope true td td.rp.root_scope assume_guarantees + let clock_scope, clock_eq = gen_clock td rp.root_scope true in + + f_and clock_eq (f_of_scope true td td.rp.root_scope clock_scope assume_guarantees) (* Translate init state into a formula *) -let rec init_f_of_scope rp (node, prefix, eqs) = +let gen_clock_init rp (node, prefix, _) = + let clock_scope = node^"/"^prefix in + let time_eq = + f_and + (if not (rp.no_time_scope clock_scope) + then + BRel(AST_EQ, + NIdent(clock_scope^"time"), + NIntConst 0) + else BConst true) + (if rp.init_scope clock_scope + then + f_e_eq (EIdent(clock_scope^"init")) (EItem bool_true) + else BConst true) + in + clock_scope, time_eq + +let rec init_f_of_scope rp (node, prefix, eqs) clock_scope = let expr_eq e = let instance_eq (_, id, eqs, args) = - init_f_of_scope rp (node^"/"^id, "", eqs) + init_f_of_scope rp (node^"/"^id, "", eqs) clock_scope in List.fold_left (fun x i -> f_and (instance_eq i) x) (BConst true) (extract_instances rp.p e) @@ -356,7 +403,9 @@ let rec init_f_of_scope rp (node, prefix, eqs) = | AST_activate (b, _) -> let rec cond_eq = function | AST_activate_body b -> - init_f_of_scope rp (node, b.act_id^".", b.body) + let bscope = (node, b.act_id^".", b.body) in + let clock_scope, clock_eq = gen_clock_init rp bscope in + f_and clock_eq (init_f_of_scope rp bscope clock_scope) | AST_activate_if(c, a, b) -> f_and (expr_eq c) (f_and (cond_eq a) (cond_eq b)) @@ -367,37 +416,27 @@ let rec init_f_of_scope rp (node, prefix, eqs) = let init_eq = BEnumCons(E_EQ, node^"/"^aid^".state", EItem st.st_name) in let state_eq (st, _) = let sc_f = - init_f_of_scope rp (node, aid^"."^st.st_name^".", st.body) + let st_scope = (node, aid^"."^st.st_name^".", st.body) in + let clock_scope, clock_eq = gen_clock_init rp st_scope in + f_and clock_eq (init_f_of_scope rp st_scope clock_scope) in List.fold_left (fun f (c, _, _) -> f_and f (expr_eq c)) sc_f st.until in List.fold_left f_and init_eq (List.map state_eq states) in - let time_eq = - f_and - (if not (rp.no_time_scope (node^"/")) - then - BRel(AST_EQ, - NIdent(node^"/"^prefix^"time"), - NIntConst 0) - else BConst true) - (if rp.init_scope (node^"/") - then - f_e_eq (EIdent(node^"/"^prefix^"init")) (EItem bool_true) - else BConst true) - in - List.fold_left f_and time_eq (List.map do_eq eqs) + f_and_list (List.map do_eq eqs) and init_f_of_prog rp = - init_f_of_scope rp rp.root_scope + let clock_scope, clock_eq = gen_clock_init rp rp.root_scope in + f_and clock_eq (init_f_of_scope rp rp.root_scope clock_scope) (* Get expressions for guarantee violation *) -let rec g_of_scope td (node, prefix, eqs) cond = +let rec g_of_scope td (node, prefix, eqs) clock_scope cond = let expr_g e = let instance_g (_, id, eqs, args) = - g_of_scope td (node^"/"^id, "", eqs) cond + g_of_scope td (node^"/"^id, "", eqs) clock_scope cond in List.fold_left (fun x i -> (instance_g i) @ x) [] (extract_instances td.rp.p e) @@ -406,21 +445,23 @@ let rec g_of_scope td (node, prefix, eqs) cond = | AST_assign(_, e) | AST_assume(_, e) -> expr_g e | AST_guarantee((id, _), e) -> - (id, f_and cond (f_of_expr td (node, prefix) (AST_not(e), snd e))) + (id, f_and cond (f_of_expr td (node, prefix, clock_scope) (AST_not(e), snd e))) :: (expr_g e) | AST_activate (b, _) -> let rec cond_g cond = function | AST_activate_body b -> - g_of_scope td (node, b.act_id^".", b.body) cond + let bscope = node, b.act_id^".", b.body in + g_of_scope td bscope (clock_scope_here bscope) cond | AST_activate_if(c, a, b) -> - (cond_g (f_and cond (f_of_expr td (node, prefix) c)) a) @ - (cond_g (f_and cond (f_of_expr td (node, prefix) (AST_not(c), snd c))) b) @ + (cond_g (f_and cond (f_of_expr td (node, prefix, clock_scope) c)) a) @ + (cond_g (f_and cond (f_of_expr td (node, prefix, clock_scope) (AST_not(c), snd c))) b) @ (expr_g c) in cond_g cond b | AST_automaton (aid, states, _) -> let st_g (st, _) = - g_of_scope td (node, aid^"."^st.st_name^".", st.body) + let stscope = (node, aid^"."^st.st_name^".", st.body) in + g_of_scope td stscope (clock_scope_here stscope) (f_and cond (BEnumCons(E_EQ, node^"/"^aid^".state", EItem st.st_name))) in List.flatten (List.map st_g states) @@ -433,4 +474,4 @@ and guarantees_of_prog rp = consts = I.consts rp; } in - g_of_scope td rp.root_scope (BConst true) + g_of_scope td rp.root_scope "" (BConst true) diff --git a/frontend/typing.ml b/frontend/typing.ml index 0f19b93..167caea 100644 --- a/frontend/typing.ml +++ b/frontend/typing.ml @@ -117,7 +117,26 @@ let node_vars p f nid = vars_in_node nid (decls_of_node n) (* - extract_all_vars : prog -> scope -> var list + clock_vars : rooted_prog -> scope -> var list +*) +let clock_vars rp (node, prefix, _) = + let v = + if not (rp.no_time_scope (node^"/")) + then + [ + false, node^"/"^prefix^"time", TInt; + false, "N"^node^"/"^prefix^"time", TInt] + else [] in + let v = + if rp.init_scope (node^"/") + then + (false, node^"/"^prefix^"init", bool_type):: + (false, "N"^node^"/"^prefix^"init", bool_type)::v + else v in + v + +(* + extract_all_vars : rooted_prog -> scope -> var list Extracts all variables with names given according to naming convention used here and in transform.ml : @@ -154,10 +173,9 @@ let rec extract_all_vars rp (node, prefix, eqs) n_vars = let rec do_branch = function | AST_activate_body b -> let bvars = vars_in_node node b.act_locals in - bvars @ - extract_all_vars rp - (node, b.act_id^".", b.body) - (bvars@n_vars) + let b_scope = node, b.act_id^".", b.body in + bvars @ clock_vars rp b_scope @ + extract_all_vars rp b_scope (bvars@n_vars) | AST_activate_if(c, a, b) -> vars_of_expr c @ do_branch a @ do_branch b in do_branch b @@ -167,11 +185,10 @@ let rec extract_all_vars rp (node, prefix, eqs) n_vars = List.flatten (List.map (fun (e, _, _) -> vars_of_expr e) st.until) in + let st_scope = (node, aid^"."^st.st_name^".", st.body) in let svars = vars_in_node node st.st_locals in - svars @ tvars @ - extract_all_vars rp - (node, aid^"."^st.st_name^".", st.body) - (tvars@n_vars) + svars @ tvars @ clock_vars rp st_scope @ + extract_all_vars rp st_scope (tvars@n_vars) in let st_ids = List.map (fun (st, _) -> st.st_name) states in (false, node^"/"^aid^".state", TEnum st_ids):: @@ -179,18 +196,6 @@ let rec extract_all_vars rp (node, prefix, eqs) n_vars = (List.flatten (List.map do_state states)) in let v = List.flatten (List.map vars_of_eq eqs) in - let v = - if not (rp.no_time_scope (node^"/")) - then - (false, node^"/"^prefix^"time", TInt):: - (false, "N"^node^"/"^prefix^"time", TInt)::v - else v in - let v = - if rp.init_scope (node^"/") - then - (false, node^"/"^prefix^"init", bool_type):: - (false, "N"^node^"/"^prefix^"init", bool_type)::v - else v in v @@ -208,7 +213,6 @@ let root_prog p root no_time_scope init_scope = (extract_const_decls p) in - let root_vars = vars_in_node "" (decls_of_node root_node) in let rp = { p; root_scope; root_node; @@ -219,6 +223,9 @@ let root_prog p root no_time_scope init_scope = const_vars; all_vars = [] } in - { rp with all_vars = root_vars @ extract_all_vars rp root_scope root_vars } + let root_vars = vars_in_node "" (decls_of_node root_node) in + let root_clock_vars = clock_vars rp root_scope in + + { rp with all_vars = root_clock_vars @ root_vars @ extract_all_vars rp root_scope root_vars } @@ -9,10 +9,12 @@ module Interpret = Interpret.I module ItvND = Nonrelational.ND(Intervals_domain.VD) -module AI_Itv = Abs_interp.I(Enum_domain.Valuation)(ItvND) -module AI_Rel = Abs_interp.I(Enum_domain.Valuation)(Apron_domain.ND) +module AI_Itv = Abs_interp.I(Enum_domain.MultiValuationCCons)(ItvND) +module AI_Rel = Abs_interp.I(Enum_domain.MultiValuationCCons)(Apron_domain.ND) +(* module AI_Itv_EDD = Abs_interp_edd.I(ItvND) +*) (* command line options *) let dump = ref false @@ -82,8 +84,6 @@ let do_test_interpret prog verbose = let () = Arg.parse options (fun f -> ifile := f) usage; - AI_Itv_EDD.test (); - if !ifile = "" then begin Format.eprintf "No input file...@."; exit 1 @@ -117,7 +117,9 @@ let () = if !ai_itv then AI_Itv.do_prog opt rp; if !ai_rel then AI_Rel.do_prog opt rp; + (* if !ai_itv_edd then AI_Itv_EDD.do_prog opt rp; + *) end; if !vtest then do_test_interpret prog true |