open Ast open Ast_util open Formula open Typing open Cmdline open Util open Num_domain open Enum_domain open Varenv module I (ED : ENUM_ENVIRONMENT_DOMAIN) (ND : NUMERICAL_ENVIRONMENT_DOMAIN) : sig val do_prog : cmdline_opt -> rooted_prog -> unit end = struct type abs_v = ED.t * ND.t type location = { id : int; def : bool_expr list; (* conjunction of formula *) def_cl : conslist; is_init : bool; f : bool_expr; cl : conslist; (* For chaotic iteration fixpoint *) mutable star : bool; mutable in_c : int; mutable v : abs_v; mutable out_t : int list; mutable in_t : int list; } type env = { rp : rooted_prog; opt : cmdline_opt; ve : varenv; (* program expressions *) f : bool_expr; guarantees : (id * bool_expr) list; (* data *) loc : (int, location) Hashtbl.t; counter : int ref; } (* ************************** ABSTRACT VALUES ************************** *) (* top : env -> abs_v bottom : env -> abs_v *) let top e = (ED.top e.ve.evars, ND.top e.ve.nvars) let bottom e = (ED.top e.ve.evars, ND.bottom e.ve.nvars) let is_bot (e, n) = ND.is_bot n let print_v fmt (enum, num) = if is_bot (enum, num) then Format.fprintf fmt "⊥" else Format.fprintf fmt "@[(%a,@ %a)@]" ED.print enum ND.print num (* join : abs_v -> abs_v -> abs_v meet : abs_v -> abs_v -> abs_v *) let join (e1, n1) (e2, n2) = if is_bot (e1, n1) then (e2, n2) else if is_bot (e2, n2) then (e1, n1) else (ED.join e1 e2, ND.join n1 n2) let meet (e1, n1) (e2, n2) = if is_bot (e1, n1) then ED.vtop e1, ND.vbottom n1 else if is_bot (e2, n2) then ED.vtop e2, ND.vbottom n2 else try (ED.meet e1 e2 , ND.meet n1 n2) with Bot -> e1, ND.vbottom n1 (* apply_cl : abs_v -> conslist -> abs_v *) let rec apply_cl (enum, num) (ec, nc, r) = try begin match r with | CLTrue -> (ED.apply_cl enum ec, ND.apply_cl num nc) | CLFalse -> (enum, ND.vbottom num) | CLAnd(a, b) -> let enum, num = apply_cl (enum, num) (ec, nc, a) in let enum, num = apply_cl (enum, num) ([], nc, b) in enum, num | CLOr((eca, nca, ra), (ecb, ncb, rb)) -> let a = apply_cl (enum, num) (ec@eca, nc@nca, ra) in let b = apply_cl (enum, num) (ec@ecb, nc@ncb, rb) in join a b end with Bot -> ED.vtop enum, ND.vbottom num (* *************************** INTERPRET *************************** *) (* init_env : cmdline_opt -> rooted_prog -> env *) let init_env opt rp = let f = Transform.f_of_prog_incl_init rp false in let f = simplify_k (get_root_true f) f in Format.printf "Complete formula:@.%a@.@." Formula_printer.print_expr f; let facts = get_root_true f in let f, rp, _ = List.fold_left (fun (f, (rp : rooted_prog), repls) eq -> match eq with | BEnumCons(E_EQ, a, EIdent b) when a.[0] <> 'L' && b.[0] <> 'L' -> let a = try List.assoc a repls with Not_found -> a in let b = try List.assoc b repls with Not_found -> b in if a = b then f, rp, repls else begin let keep, repl = if String.length a <= String.length b then a, b else b, a in Format.printf "Replacing %s with %s@." repl keep; let f = formula_replace_evars [repl, keep; "L"^repl, "L"^keep] f in let rp = { rp with all_vars = List.filter (fun (_, id, _) -> id <> repl) rp.all_vars } in let repls = (repl, keep):: (List.map (fun (r, k) -> r, if k = repl then keep else k) repls) in f, rp, repls end | _ -> f, rp, repls) (f, rp, []) facts in let f = simplify_k (get_root_true f) f in Format.printf "Complete formula after simpl:@.%a@.@." Formula_printer.print_expr f; let guarantees = Transform.guarantees_of_prog rp in Format.printf "Guarantees:@."; List.iter (fun (id, f) -> Format.printf " %s: %a@." id Formula_printer.print_expr f) guarantees; Format.printf "@."; let ve = mk_varenv rp f (conslist_of_f f) in let env = { rp; opt; ve; f; guarantees; loc = Hashtbl.create 2; counter = ref 2; } in (* add initial disjunction : L/must_reset = tt, L/must_reset ≠ tt *) let rstc = [BEnumCons(E_EQ, "L/must_reset", EItem bool_true)] in let rstf = simplify_k rstc f in let rstf = simplify_k (get_root_true rstf) rstf in let nrstc = [BEnumCons(E_NE, "L/must_reset", EItem bool_true)] in let nrstf = simplify_k nrstc f in let nrstf = simplify_k (get_root_true nrstf) nrstf in Hashtbl.add env.loc 0 { id = 0; def = rstc; def_cl = conslist_of_f (f_and_list rstc); is_init = true; f = rstf; cl = conslist_of_f rstf; star = false; in_c = 0; v = (ED.top ve.evars, ND.bottom ve.nvars); out_t = []; in_t = []; }; Hashtbl.add env.loc 1 { id = 1; def = nrstc; def_cl = conslist_of_f (f_and_list nrstc); is_init = false; f = nrstf; cl = conslist_of_f nrstf; star = false; in_c = 0; v = (ED.top ve.evars, ND.bottom ve.nvars); out_t = []; in_t = []; }; env (* pass_cycle : env -> edd_v -> edd_v unpass_cycle : env -> edd_v -> edd_v set_target_case : env -> edd_v -> bool_expr -> edd_v cycle : env -> edd_v -> conslist -> edd_v *) let pass_cycle env (enum, num) = let assign_e, assign_n = List.fold_left (fun (ae, an) (a, b, t) -> match t with | TEnum _ -> (a, b)::ae, an | TInt | TReal -> ae, (a, NIdent b)::an) ([], []) env.cycle in let enum = ED.assign enum assign_e in let num = ND.assign num assign_n in let ef, nf = List.fold_left (fun (ef, nf) (var, t) -> match t with | TEnum _ -> var::ef, nf | TReal | TInt -> ef, var::nf) ([], []) env.forget in (ED.forgetvars enum ef, List.fold_left ND.forgetvar num nf) let unpass_cycle env (enum, num) = let assign_e, assign_n = List.fold_left (fun (ae, an) (a, b, t) -> match t with | TEnum _ -> (b, a)::ae, an | TInt | TReal -> ae, (b, NIdent a)::an) ([], []) env.ve.cycle in let enum = ED.assign enum assign_e in let num = ND.assign num assign_n in let ef, nf = List.fold_left (fun (ef, nf) (var, t) -> match t with | TEnum _ -> var::ef, nf | TReal | TInt -> ef, var::nf) ([], []) env.ve.forget_inv in (ED.forgetvars enum ef, List.fold_left ND.forgetvar num nf) let set_target_case e v cl = let tgt = (unpass_cycle e (apply_cl (top e) cl)) in (*Format.printf "Target %a = %a@." Formula_printer.print_conslist cl print_v tgt;*) meet v tgt (* chaotic_iter : env -> unit Fills the values of loc[*].v, and updates out_t and in_t *) let chaotic_iter e = let delta = ref [] in (* Fill up initial states *) Hashtbl.iter (fun q loc -> loc.out_t <- []; loc.in_t <- []; if loc.is_init then begin loc.v <- apply_cl (top e) loc.cl; delta := q::!delta end else loc.v <- bottom e) e.loc; (* Iterate *) let it_counter = ref 0 in while !delta <> [] do let s = List.hd !delta in let loc = Hashtbl.find e.loc s in incr it_counter; Format.printf "@.Iteration %d: q%d@." !it_counter s; let start = loc.v in let f i = (*Format.printf "I: %a@." print_v i;*) let i' = set_target_case e i loc.def_cl in (*Format.printf "I': %a@." print_v i';*) let j = join start (apply_cl (apply_cl (pass_cycle e.ve i') loc.def_cl) loc.cl) in (*Format.printf "J: %a@." print_v j;*) j in let rec iter n (i_enum, i_num) = let fi_enum, fi_num = f (i_enum, i_num) in let j_enum, j_num = if ND.is_bot fi_num then i_enum, i_num else if n < e.opt.widen_delay then ED.join i_enum fi_enum, ND.join i_num fi_num else ED.join i_enum fi_enum, ND.widen i_num fi_num in if ED.eq j_enum i_enum && ND.eq j_num i_num then (i_enum, i_num) else iter (n+1) (j_enum, j_num) in let y = iter 0 start in let z = fix (fun (a, b) (c, d) -> ED.eq a c && ND.eq b d) f y in Format.printf "Fixpoint: %a@." print_v z; loc.v <- z; Hashtbl.iter (fun t loc2 -> let u = pass_cycle e.ve z in let v = apply_cl u loc2.def_cl in let w = apply_cl v loc2.cl in (*Format.printf "u: %a@.v: %a@. w: %a@." print_v u print_v v print_v w;*) let r_enum, r_num = w in if not (is_bot (r_enum, r_num)) then begin Format.printf "%d -> %d with:@. %a@." s t print_v (r_enum, r_num); if not (List.mem s loc2.in_t) then loc2.in_t <- s::loc2.in_t; if not (List.mem t loc.out_t) then loc.out_t <- t::loc.out_t; let enum, num = loc2.v in let enum2, num2 = join (enum, num) (r_enum, r_num) in if not (ED.subset enum2 enum) || not (ND.subset num2 num) then begin loc2.v <- (enum2, num2); if not (List.mem t !delta) then delta := t::!delta end end) e.loc; delta := List.filter ((<>) s) !delta; done let print_locs e = Hashtbl.iter (fun id loc -> Format.printf "@."; Format.printf "q%d: @[[ %a ]@]@." id (print_list Formula_printer.print_expr " ∧ ") loc.def; (*Format.printf "F: %a@." Formula_printer.print_conslist loc.cl;*) Format.printf " @[%a ∧@ %a@]@." ED.print (fst loc.v) ND.print (snd loc.v); Format.printf " -> @[[%a]@]@." (print_list (fun fmt i -> Format.fprintf fmt "q%d" i) ", ") loc.out_t; ) e.loc let do_prog opt rp = let e = init_env opt rp in Format.printf "@.Initializing.@."; chaotic_iter e; print_locs e end