Skip to content
Snippets Groups Projects
Select Git revision
  • e5a735d5beec2abb008793b94173cfa25aab2b13
  • master default protected
  • home_exam
3 results

main_locate.rs

Blame
  • Forked from Per Lindgren / D7050E
    Source project has a limited visibility.
    destruct.ml 9.39 KiB
    (********************************************************************)
    (*                                                                  *)
    (*  The Why3 Verification Platform   /   The Why3 Development Team  *)
    (*  Copyright 2010-2018   --   Inria - CNRS - Paris-Sud University  *)
    (*                                                                  *)
    (*  This software is distributed under the terms of the GNU Lesser  *)
    (*  General Public License version 2.1, with the special exception  *)
    (*  on linking described in file LICENSE.                           *)
    (*                                                                  *)
    (********************************************************************)
    
    open Term
    open Decl
    open Args_wrapper
    open Generic_arg_trans_utils
    
    (** This file contains transformations with arguments that eliminates logic
        connectors (instantiate, destruct, destruct_alg). *)
    
    (** Explanation *)
    
    (* Explanation for destruct premises *)
    let destruct_expl = "destruct premise"
    
    let is_lsymbol t =
      match t.t_node with
      | Tapp (_, []) -> true
      | _ -> false
    
    let create_constant ty =
      let fresh_name = Ident.id_fresh "x" in
      let ls = create_lsymbol fresh_name [] (Some ty) in
      (ls, create_param_decl ls)
    
    let rec return_list list_types type_subst =
      match list_types with
      | [] -> []
      | hd :: tl ->
          create_constant (Ty.ty_inst type_subst hd) :: return_list tl type_subst
    
    let my_ls_app_inst ls ty =
      match ls.ls_value, ty with
        | Some _, None -> raise (PredicateSymbolExpected ls)
        | None, Some _ -> raise (FunctionSymbolExpected ls)
        | Some vty, Some ty -> Ty.ty_match Ty.Mtv.empty vty ty
        | None, None -> Ty.Mtv.empty
    
    let rec build_decls cls x =
      match cls with
      | [] -> []
      | (cs, _) :: tl ->
          let type_subst = my_ls_app_inst cs x.t_ty in
          let l = return_list cs.ls_args type_subst in
          let teqx =
            (t_app cs (List.map (fun x -> t_app_infer (fst x) []) l) x.t_ty) in
          let ht = t_equ x teqx in
          let h = Decl.create_prsymbol (gen_ident "h") in
          let new_hyp = Decl.create_prop_decl Decl.Paxiom h ht in
          ((List.map snd l) @ [new_hyp]) :: build_decls tl x
    
    (* Enumerate all constants of a term *)
    let rec compounds_of acc (t: term) =
      match t.t_node with
      | Tapp (ls, _) -> Term.t_fold compounds_of (Term.Sls.add ls acc) t
      | _ -> Term.t_fold compounds_of acc t
    
    (* This tactic acts on a term of algebraic type. It introduces one
       new goal per constructor of the type and introduce corresponding
       variables. It also introduce the equality between the term and
       its destruction in the context.
       When replace is set to true, a susbtitution is done when x is an lsymbol.
     *)
    let destruct_alg replace (x: term) : Task.task Trans.tlist =
      let ty = x.t_ty in
      (* We list all the constants used in x so that we know the first place in the
         task where we can introduce hypothesis about the destruction of x. *)
      let ls_of_x = ref (compounds_of Term.Sls.empty x) in
      let defined = ref false in
      let r = ref [] in
      match ty with
      | None -> raise (Cannot_infer_type "destruct")
      | Some ty ->
        begin
          match ty.Ty.ty_node with
          | Ty.Tyvar _       -> raise (Cannot_infer_type "destruct")
          | Ty.Tyapp (ts, _) ->
            let trans = Trans.decl_l (fun d ->
              match d.d_node with
              (* TODO not necessary to check this first: this can be optimized *)
              | _ when (not !defined) && Term.Sls.is_empty !ls_of_x ->
                  if !r = [] then
                    [[d]]
                  else
                    begin
                      defined := true;
                      List.map (fun x -> x @ [d]) !r
                    end
              | Dlogic dls          ->
                  ls_of_x :=
                    List.fold_left
                      (fun acc (ls, _) -> Term.Sls.remove ls acc)
                      !ls_of_x dls;
                  [[d]]
              | Dparam ls ->
                  ls_of_x := Term.Sls.remove ls !ls_of_x;
                  [[d]]
              | Dind (_, ils)       ->
                  ls_of_x :=
                    List.fold_left
                      (fun acc (ls, _) -> Term.Sls.remove ls acc)
                      !ls_of_x ils;
                  [[d]]
              | Ddata dls           ->
                  (try
                    (let cls = List.assoc ts dls in
                    r := build_decls cls x;
                    [[d]]
                    )
                  with Not_found -> [[d]])
              | Dprop (Pgoal, _, _) ->
                  [[d]]
              | _ -> [[d]]) None
            in
            if replace && is_lsymbol x then
              Trans.compose_l trans (Trans.singleton (Subst.subst [x]))
            else
              trans
        end
    
    (* Destruct the head term of an hypothesis if it is either
       conjunction, disjunction or exists *)
    let destruct pr : Task.task Trans.tlist =
      let new_decl = ref None in
      (* This transformation destructs the hypothesis pr. In case pr is an
         implication H : A -> B, the destruction creates two task (one with H
         removed and one with H : B). It also fills new_decl with A.
         The next transformation replace the first goal with A. *)
      let tr_decl =
        Trans.decl_l (fun d ->
        match d.d_node with
        | Dprop (Paxiom, dpr, ht) when Ident.id_equal dpr.pr_name pr.pr_name ->
          begin
            match ht.t_node with
            | Tbinop (Tand, t1, t2) ->
              let new_pr1 = create_prsymbol (Ident.id_clone dpr.pr_name) in
              let new_decl1 = create_prop_decl Paxiom new_pr1 t1 in
              let new_pr2 = create_prsymbol (Ident.id_clone dpr.pr_name) in
              let new_decl2 = create_prop_decl Paxiom new_pr2 t2 in
              [[new_decl1;new_decl2]]
            | Tbinop (Tor, t1, t2) ->
              let new_pr1 = create_prsymbol (Ident.id_clone dpr.pr_name) in
              let new_decl1 = create_prop_decl Paxiom new_pr1 t1 in
              let new_pr2 = create_prsymbol (Ident.id_clone dpr.pr_name) in
              let new_decl2 = create_prop_decl Paxiom new_pr2 t2 in
              [[new_decl1];[new_decl2]]
            | Tbinop (Timplies, t1, t2) ->
              begin
                let new_pr2 = create_prsymbol (Ident.id_clone dpr.pr_name) in
                let new_decl2 = create_prop_decl Paxiom new_pr2 t2 in
                new_decl := Some t1;
                (* Creates a task with hypothesis removes (need to prove t1) and one
                   with hypothesis replaced by t2 (needs to prove current goal).
                   Example: "false -> false" *)
                [] :: [[new_decl2]]
              end
            | Tquant (Texists, tb) ->
              begin
                let (vsl, tr, te) = Term.t_open_quant tb in
                match vsl with
                | x :: tl ->
                    let ls = create_lsymbol (Ident.id_clone x.vs_name) [] (Some x.vs_ty) in
                    let tx = fs_app ls [] x.vs_ty in
                    let x_decl = create_param_decl ls in
                    (try
                      let part_t = t_subst_single x tx te in
                      let new_t = t_quant_close Texists tl tr part_t in
                      let new_pr = create_prsymbol (Ident.id_clone dpr.pr_name) in
                      let new_decl = create_prop_decl Paxiom new_pr new_t in
                      [[d; x_decl; new_decl]]
                    with
                    | Ty.TypeMismatch (ty1, ty2) ->
                        raise (Arg_trans_type ("destruct_exists", ty1, ty2)))
                | [] -> raise (Arg_trans ("destruct_exists"))
              end
            | _ -> raise (Arg_trans ("destruct"))
          end
        | _ -> [[d]]) None in
      Trans.store (fun task ->
        let goal, task = Task.task_separate_goal task in
        let new_tasks = Trans.apply tr_decl task in
        match !new_decl with
        | None ->
          (* Normal destruct case (not implication): add goal back to tasks *)
          List.map (fun task -> Task.add_tdecl task goal) new_tasks
        | Some new_decl ->
          match new_tasks with
          (* Destruct case for an implication. The first goal should be new_decl,
             the second one is unchanged. *)
          | first_task :: second_task :: [] ->
              let pr = create_prsymbol (gen_ident "G") in
              let new_goal = create_goal ~expl:destruct_expl pr new_decl in
              let first_goal = Task.add_decl first_task new_goal in
              let second_goal = Task.add_tdecl second_task goal in
              first_goal :: second_goal :: []
          | _ -> assert false)
    
    (* from task [delta, name:forall x.A |- G,
         build the task [delta,name:forall x.A,name':A[x -> t]] |- G] *)
    let instantiate (pr: Decl.prsymbol) lt =
      let r = ref [] in
      Trans.decl
        (fun d ->
          match d.d_node with
          | Dprop (pk, dpr, ht) when Ident.id_equal dpr.pr_name pr.pr_name ->
              let t_subst = subst_forall_list ht lt in
              let new_pr = create_prsymbol (gen_ident "Hinst") in
              let new_decl = create_prop_decl pk new_pr t_subst in
              r := [new_decl];
              [d]
          | Dprop (Pgoal, _, _) -> !r @ [d]
          | _ -> [d]) None
    
    let () = wrap_and_register
        ~desc:"instantiate <prop> <term list> generates a new hypothesis with quantified variables of prop replaced with terms"
        "instantiate"
        (Tprsymbol (Ttermlist Ttrans)) instantiate
    
    let () = wrap_and_register ~desc:"destruct <name> destructs the head logic constructor of hypothesis name (/\\, \\/, -> or <->).\nTo destruct a literal of algebraic type, use destruct_alg."
        "destruct" (Tprsymbol Ttrans_l) destruct
    
    let () = wrap_and_register ~desc:"destruct <name> destructs as an algebraic type"
        "destruct_alg" (Tterm Ttrans_l) (destruct_alg false)
    
    let () = wrap_and_register ~desc:"destruct <name> destructs as an algebraic type and substitute the definition if an lsymbol was provided"
        "destruct_alg_subst" (Tterm Ttrans_l) (destruct_alg true)