(* File: factor.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: factor.ml,v 1.7 2006/01/17 00:23:37 mottl Exp $ *) open Utils open Algdt_types open Algdt_utils open Model_types open Model_utils (* Factorization of models *) type factor = | FactorNone | FactorVal of model | FactorLet of models * var_mods let not_match_mod = function MatchMod _ -> false | _ -> true let make_var_free fdsum = VarFree fdsum let get_n_tpl models = match models.(0) with | Val fdsums -> Array.length fdsums | Let (_, var_mods) -> Array.length var_mods | _ -> assert false (* impossible *) let get_cnstr_strct models tpl_ix subs_ar = match models.(0) with | Val fdsums -> (match fdsums.(tpl_ix) with | FDAtom cnstr -> cnstr, false | FDStrct (cnstr, subs) -> subs_ar.(0) <- Array.map make_var_free subs; cnstr, true) | Let (_, var_mods) -> (match var_mods.(tpl_ix) with | VarStrct (cnstr, subs) -> subs_ar.(0) <- subs; cnstr, true | VarFree (FDAtom cnstr) -> cnstr, false | VarFree (FDStrct (cnstr, subs)) -> subs_ar.(0) <- Array.map make_var_free subs; cnstr, true | Var -> raise Exit) | _ -> assert false (* impossible *) let get_sub_cnstr_strct subs_ar tsubs = match tsubs.(0) with | VarStrct (cnstr, subs) -> subs_ar.(0) <- subs; cnstr, true | VarFree (FDAtom cnstr) -> cnstr, false | VarFree (FDStrct (cnstr, subs)) -> subs_ar.(0) <- Array.map make_var_free subs; cnstr, true | Var -> raise Exit let cpy_subs subs_ar model_ix last_cnstr = function | VarStrct (cnstr, subs) when cnstr = last_cnstr -> subs_ar.(model_ix) <- subs | VarFree (FDStrct (cnstr, subs)) when cnstr = last_cnstr -> subs_ar.(model_ix) <- Array.map make_var_free subs | _ -> raise Exit let chk_atom last_cnstr = function | VarFree (FDAtom cnstr) when cnstr = last_cnstr -> () | _ -> raise Exit let rec factorize_subs n_models_1 same_ref n_sub_same_ref subs_ar last_cnstr = let tsubs = transpose_matrix subs_ar in let n_tsubs = Array.length tsubs in let factorized_subs = Array.make n_tsubs Var in for ix = n_tsubs - 1 downto 0 do let tsub = tsubs.(ix) in try let last_sub_cnstr, is_sub_strct = get_sub_cnstr_strct subs_ar tsub in let factorized = if is_sub_strct then ( for model_ix = 1 to n_models_1 do cpy_subs subs_ar model_ix last_sub_cnstr tsub.(model_ix) done; factorize_subs n_models_1 same_ref n_sub_same_ref subs_ar last_sub_cnstr) else ( for model_ix = 1 to n_models_1 do chk_atom last_sub_cnstr tsub.(model_ix) done; VarFree (FDAtom last_sub_cnstr)) in factorized_subs.(ix) <- factorized with Exit -> same_ref := Right tsub :: !same_ref; incr n_sub_same_ref done; make_strct_var_mods last_cnstr factorized_subs let factorize_no_match models = let n_models = Array.length models in let n_models_1 = n_models - 1 in let subs_ar = Array.make n_models [||] in let same_ref = ref [] in let factorized_ref = ref [] in let n_factorized_ref = ref 0 in let n_vars_ref = ref 0 in let n_sub_same_ref = ref 0 in let n_tpl = get_n_tpl models in for tpl_ix = n_tpl - 1 downto 0 do try let last_cnstr, is_strct = get_cnstr_strct models tpl_ix subs_ar in let factorized = if is_strct then ( for model_ix = 1 to n_models_1 do match models.(model_ix) with | Val fdsums -> (match fdsums.(tpl_ix) with | FDStrct (cnstr, subs) when cnstr = last_cnstr -> subs_ar.(model_ix) <- Array.map make_var_free subs | _ -> raise Exit) | Let (_, var_mods) -> cpy_subs subs_ar model_ix last_cnstr var_mods.(tpl_ix) | _ -> assert false (* impossible *) done; factorize_subs n_models_1 same_ref n_sub_same_ref subs_ar last_cnstr) else ( for model_ix = 1 to n_models_1 do match models.(model_ix) with | Val fdsums -> if fdsum_cnstr fdsums.(tpl_ix) <> last_cnstr then raise Exit | Let (_, var_mods) -> chk_atom last_cnstr var_mods.(tpl_ix) | _ -> assert false (* impossible *) done; VarFree (FDAtom last_cnstr)) in factorized_ref := factorized :: !factorized_ref; incr n_factorized_ref with Exit -> factorized_ref := Var :: !factorized_ref; incr n_vars_ref; same_ref := Left tpl_ix :: !same_ref done; let n_factorized = !n_factorized_ref in if n_factorized = 0 then FactorNone else let n_sub_same = !n_sub_same_ref in if n_factorized = n_tpl && n_sub_same = 0 then let fdsums = array_map_of_nlist sum_of_var_mod n_factorized !factorized_ref in FactorVal (Val fdsums) else ( let same = !same_ref in let n_vars = !n_vars_ref in let n_new_tpl = n_vars + n_sub_same in let cnvi model_ix = function | Val fdsums -> let new_fdsums = Array.make n_new_tpl dummy_fdsum in let acti ix = function | Left tpl_ix -> new_fdsums.(ix) <- fdsums.(tpl_ix) | Right tsub -> match tsub.(model_ix) with | VarFree fdsum -> new_fdsums.(ix) <- fdsum | _ -> assert false (* impossible *) in list_iteri acti same; Val new_fdsums | Let (match_mod, var_mods) -> let new_var_mods = Array.make n_new_tpl Var in let acti ix = function | Left tpl_ix -> new_var_mods.(ix) <- var_mods.(tpl_ix) | Right tsub -> new_var_mods.(ix) <- tsub.(model_ix) in list_iteri acti same; if array_forall is_var new_var_mods then MatchMod match_mod else Let (match_mod, new_var_mods) | _ -> assert false (* impossible *) in let new_models = Array.mapi cnvi models in let n_new_var_mods = n_factorized + n_vars in FactorLet (new_models, array_of_nlist n_new_var_mods !factorized_ref)) let factorize_models models = if array_forall not_match_mod models then factorize_no_match models else FactorNone