summaryrefslogblamecommitdiff
path: root/abstract/abs_interp_dynpart.ml
blob: 28f92381c9ca3e50c8c6b1ce041e1575b7d2bab6 (plain) (tree)






















































































































































































































































































































































































                                                                                              
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 "@[<hov 4>(%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: @[<hov 4>[ %a ]@]@." id
              (print_list Formula_printer.print_expr " ∧ ") loc.def;
            (*Format.printf "F: %a@." Formula_printer.print_conslist loc.cl;*)
            Format.printf "    @[<hv 0>%a ∧@ %a@]@."
              ED.print (fst loc.v) ND.print (snd loc.v);
            Format.printf " -> @[<hov>[%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