(* File: model_utils.ml AIFAD - Automated Induction of Functions over Algebraic Datatypes Author: Markus Mottl email: markus.mottl@gmail.com WWW: http://www.ocaml.info Copyright (C) 2002 Austrian Research Institute for Artificial Intelligence Copyright (C) 2003- Markus Mottl This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *) (* $Id: model_utils.ml,v 1.43 2006/01/17 00:23:38 mottl Exp $ *) open Format open Utils open Algdt_types open Algdt_utils open Model_types open Typing (* General utility functions on models *) let dummy_model = Val dummy_fdsums let is_var_free = function VarFree _ -> true | _ -> false let is_var var_mod = var_mod = Var let rec count_vars_var_mod = function | VarStrct (_, subs) -> count_vars_var_mods subs | VarFree _ -> 0 | Var -> 1 and coll_count cnt var_mod = cnt + count_vars_var_mod var_mod and count_vars_var_mods var_mods = Array.fold_left coll_count 0 var_mods let coll_some cnt el = if el = None then cnt else cnt + 1 let count_some ar = Array.fold_left coll_some 0 ar let sum_of_var_mod = function | VarFree sum_mod -> sum_mod | _ -> failwith "Model_utils.sum_of_var_mod" let make_strct_var_mods cnstr var_mods = if array_forall is_var_free var_mods then VarFree (FDStrct (cnstr, Array.map sum_of_var_mod var_mods)) else VarStrct (cnstr, var_mods) let subst_fdsums var_mods fdsums = let ix_ref = ref 0 in let rec cnv = function | VarStrct (cnstr, sub_var_mods) -> FDStrct (cnstr, Array.map cnv sub_var_mods) | VarFree fdsum -> fdsum | Var -> let ix = !ix_ref in ix_ref := ix + 1; fdsums.(ix) in Array.map cnv var_mods let subst_var_mods outer_var_mods inner_var_mods = let ix_ref = ref 0 in let rec cnv = function | VarStrct (cnstr, sub_var_mods) -> make_strct_var_mods cnstr (Array.map cnv sub_var_mods) | VarFree _ as var_mod -> var_mod | Var -> let ix = !ix_ref in ix_ref := ix + 1; inner_var_mods.(ix) in Array.map cnv outer_var_mods let make_env init_vars = let env = Res.Array.sempty (1.5, 0.5, 4 * Array.length init_vars) in let add_var init_var = Res.Array.add_one env init_var in Array.iter add_var init_vars; env, add_var (* Apply a model to data *) let apply_model model fdsums = let env, add_var = make_env fdsums in let rec loop_mod = function | Val fdsums -> fdsums | Let (match_mod, var_mods) -> let tpl = loop_match_mod match_mod in let ix_ref = ref 0 in let rec loop = function | VarStrct (cnstr, var_mods) -> FDStrct (cnstr, Array.map loop var_mods) | VarFree fdsum -> fdsum | Var -> let ix = !ix_ref in incr ix_ref; tpl.(ix) in Array.map loop var_mods | MatchMod match_mod -> loop_match_mod match_mod and loop_match_mod = function | Shave (var_ix, cnstr, sh_mod, def_mod) -> (match Res.Array.get env var_ix with | FDStrct (var_cnstr, subs) when var_cnstr = cnstr -> Array.iter add_var subs; loop_mod sh_mod | FDAtom var_cnstr when var_cnstr = cnstr -> loop_mod sh_mod | _ -> loop_mod def_mod) | Split (var_ix, models) -> let cnstr = match Res.Array.get env var_ix with | FDStrct (cnstr, subs) -> Array.iter add_var subs; cnstr | FDAtom cnstr -> cnstr in loop_mod models.(cnstr) | PSplit (var_ix, maybe_models, def_mod) -> match Res.Array.get env var_ix with | FDStrct (cnstr, subs) -> (match maybe_models.(cnstr) with | Some model -> Array.iter add_var subs; loop_mod model | None -> loop_mod def_mod) | FDAtom cnstr -> match maybe_models.(cnstr) with | Some model -> loop_mod model | None -> loop_mod def_mod in loop_mod model (* Pretty-print model *) let coll_n_cnstrs n_cnstrs cnstrs = n_cnstrs + Array.length cnstrs let pp_model ppf t_prefix c_prefix dispec_info cispec_info model = let add_t_prefix = (^) t_prefix in let map_add_c_prefix = Array.map ((^) c_prefix) in let prefix_ispec_info ispec_info = { ispec_info with tp_tbl = Array.map add_t_prefix ispec_info.tp_tbl; cnstr_tbl = Array.map map_add_c_prefix ispec_info.cnstr_tbl; } in let module Spec = struct let dispec = dispec_info.ispec let cispec = cispec_info.ispec let dfspec, init_tps = if Array.fold_left coll_n_cnstrs 0 dispec_info.cnstr_tbl = 0 then empty_fspec, dummy_init_tps else flatten_ispec dispec_info.ispec let cfspec, _ = flatten_ispec cispec end in let module Deco = Deco_impl.Make (Spec) in let module DecoSpec = struct include Spec let dispec_info = prefix_ispec_info dispec_info let cispec_info = prefix_ispec_info cispec_info end in let module Model_pp = Model_pp_impl.Make (DecoSpec) in let dmodel, ddpat = Deco.decorate_model model in Model_pp.pp_dmodel std_formatter dmodel ddpat (* Print human-readable model to stdout *) let print_model t_prefix v_prefix dispec_info cispec_info model = set_margin 10000; set_max_indent 1000; pp_model std_formatter t_prefix v_prefix dispec_info cispec_info model; print_newline ()