(*  File: ds2_entropy.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: ds2_entropy.ml,v 1.10 2006/01/17 00:23:37 mottl Exp $ *)

open Utils
open Algdt_types
open Algdt_utils
open Entropy_utils

type split_info = var array

let rec vars_entropy_loop pre_histos pre_var_samples =
  let ixs_ref = ref [] in
  let n_vars_ref = ref 0 in
  let n_samples = Array.length pre_var_samples.(0) in
  for i = 0 to Array.length pre_histos - 1 do
    let histo = pre_histos.(i) in
    if not (histo_is_redundant histo n_samples) then (
      incr n_vars_ref;
      ixs_ref := i :: !ixs_ref)
  done;
  let n_vars = !n_vars_ref in
  if n_vars = 0 then 0.0
  else (
    let histos = Array.make n_vars [||] in
    let var_samples = Array.make n_vars [||] in
    let acti dst_ix src_ix =
      histos.(dst_ix) <- pre_histos.(src_ix);
      var_samples.(dst_ix) <- pre_var_samples.(src_ix) in
    list_iteri acti !ixs_ref;
    let n_vars_1 = n_vars - 1 in
    let histo = histos.(n_vars_1) in
    let samples = var_samples.(n_vars_1) in
    let e = calc_entropy histo n_samples in
    if n_vars_1 = 0 then e
    else (
      let make_histo ix = Array.make (Array.length histos.(ix)) 0 in
      let cnv_cnstr freq =
        Array.init n_vars_1 make_histo,
        Array.make_matrix n_vars_1 freq dummy_fdsum in
      let many_histos, many_var_samples = array_map2 cnv_cnstr histo in
      let many_sample_ixs = Array.make (Array.length histo) 0 in
      let n_vars_2 = n_vars_1 - 1 in
      let acti sample_ix sample =
        let cnstr = fdsum_cnstr sample in
        let dst_histos = many_histos.(cnstr) in
        let dst_var_samples = many_var_samples.(cnstr) in
        let dst_sample_ix = many_sample_ixs.(cnstr) in
        many_sample_ixs.(cnstr) <- dst_sample_ix + 1;
        for var_ix = 0 to n_vars_2 do
          let dst_sample = var_samples.(var_ix).(sample_ix) in
          dst_var_samples.(var_ix).(dst_sample_ix) <- dst_sample;
          let dst_cnstr = fdsum_cnstr dst_sample in
          let dst_histo = dst_histos.(var_ix) in
          dst_histo.(dst_cnstr) <- dst_histo.(dst_cnstr) + 1
        done in
      Array.iteri acti samples;
      let f_samples = float n_samples in
      let colli cnstr e new_histos =
        let new_var_samples = many_var_samples.(cnstr) in
        let f_sub_samples = float (Array.length new_var_samples.(0)) in
        let rest_e = vars_entropy_loop new_histos new_var_samples in
        e +. f_sub_samples /. f_samples *. rest_e in
      array_fold_lefti colli e many_histos))

let histo_samples_of_var var = var.histo, var.samples

let vars_entropy _ vars =
  let histos, var_samples = array_map2 histo_samples_of_var vars in
  vars_entropy_loop histos var_samples

let var_entropy _ var = calc_entropy var.histo (Array.length var.samples)

let calc_split_infos _ dvar cfspec cvars = split_vars dvar cfspec cvars
let calc_split_info_entropy = vars_entropy
