/* Copyright (c) 1991-2002 Doshita Lab. Speech Group, Kyoto University */
/* Copyright (c) 2000-2002 Speech and Acoustics Processing Lab., NAIST */
/*   All rights reserved   */

/* addlog.c --- addlog function */

/* $Id: addlog.c,v 1.3 2002/09/11 22:01:50 ri Exp $ */

#include <sent/stddefs.h>
#include <sent/hmm.h>

#define TBLSIZE 500000		/* table size (step determined by this) */
#define VRANGE 15               /* must be > - LOG_ADDMIN */
#define TMAG 33333.3333         /* TBLSIZE/VRANGE */

static LOGPROB tbl[TBLSIZE];    /* [0,1] */

/* make log table */
void
make_log_tbl()
{
  LOGPROB f;
  int i;

  j_printerr("Generating addlog table...");
  for (i=0;i<TBLSIZE;i++){
    f = - ((float)VRANGE * (float)i / (float)TBLSIZE);
    tbl[i] = log(1 + exp(f));
    /*if (i < 10 || i > TBLSIZE - 10) j_printf("%f: %d(%f)\n", f, i, tbl[i]);*/
  }
  j_printerr("%d kb...done\n",(TBLSIZE * sizeof(LOGPROB)) / 1024);
}

/* rapid computation of log(exp(x)+exp(y)) */
LOGPROB
addlog(LOGPROB x, LOGPROB y)
{
  /* return(log(exp(x)+exp(y))) */
  LOGPROB tmp;
  unsigned int idx;
  
  if (x < y) {
    if ((tmp = x - y) < LOG_ADDMIN) return y;
    else {
      idx = (unsigned int)((- tmp) * TMAG + 0.5);
      /* j_printf("%f == %f\n",tbl[idx],log(1 + exp(tmp))); */
      return (y + tbl[idx]);
    }
  } else {
    if ((tmp = y - x) < LOG_ADDMIN) return x;
    else {
      idx =(unsigned int)((- tmp) * TMAG + 0.5);
      /* j_printf("%f == %f\n",tbl[idx],log(1 + exp(tmp))); */
      return (x + tbl[idx]);
    }
  }
}

/* add all values a[0..n-1] */
LOGPROB
addlog_array(LOGPROB *a, int n)
{
  LOGPROB tmp;
  LOGPROB x,y;
  unsigned int idx;

  y = LOG_ZERO;
  for(n--; n >= 0; n--) {
    x = a[n];
    if (x > y) {
      tmp = x; x = y; y = tmp;
    }
    /* always y >= x */
    if ((tmp = x - y) < LOG_ADDMIN) continue;
    else {
      idx = (unsigned int)((- tmp) * TMAG + 0.5);
      y += tbl[idx];
    }
  }
  return(y);
}

#if 0  /* original function with no table lookup --- just for debug */
LOGPROB
addlog(LOGPROB x, LOGPROB y)
{
  /* return(log(exp(x)+exp(y))) */
  LOGPROB tmp;

  if (x < y) {
    if ((tmp = x - y) < LOG_ADDMIN) return y;
    else {
/*       j_printf("aa %f\n", tmp); */
      return (y + log(1 + exp(tmp)));
    }
  } else {
    if ((tmp = y - x) < LOG_ADDMIN) return x;
    else {
/*       j_printf("aa %f\n", tmp); */
      return( x + log(1 + exp(tmp)));
    }
  }
}
LOGPROB
addlog_array(LOGPROB *x, int n, LOGPROB max)
{
  LOGPROB tmp, y;
  int i;

  y = max;
  for(i=0;i<n;i++) {
    if ((tmp = x[i] - max) < LOG_ADDMIN) continue;
    y += log(1 + exp(tmp));
  }
  return(y);
}
#endif

/* return log10(exp10(x)+exp10(y)) */
LOGPROB
addlog10(LOGPROB x, LOGPROB y)
{
  return(addlog(x * LOGTEN, y * LOGTEN) / LOGTEN);
}
