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

/* check_hmm_restriction.c --- check if Julius can handle the hmmdef */

/* $Id: check_hmm_restriction.c,v 1.4 2002/09/12 01:38:49 ri Exp $ */

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

#define GOOD 0
#define BAD 1

/*
 *
 * multi-path version has no restrictions on model transitions, except:
 *
 *   no arc to initial state
 *   no arc from final state
 *   should have at least one output state
 * 
 */

/* transition probability is not loganized yet */

/* check transition of t */
static int
trans_ok_p(t)
     HTK_HMM_Trans *t;
{
  int i;
  int tflag;
  int retflag = GOOD;

  /* no arc to initial state */
  tflag = GOOD;
  for (i=0;i<t->statenum;i++) {
    if (t->a[i][0] != (PROB)0.0) {
      tflag = BAD;
      break;
    }
  }
  if (tflag == BAD) {
    j_printerr("Error: transition to initial state not allowed\n");
    retflag = BAD;
  }
  /* no arc from final state */
  tflag = GOOD;
  for (i=0;i<t->statenum;i++) {
    if (t->a[t->statenum-1][i] != (PROB)0.0) {
      tflag = BAD;
      break;
    }
  }
  if (tflag == BAD) {
    j_printerr("Error: transition from final state not allowed\n");
    retflag = BAD;
  }
    
  return(retflag);
}

/* check HMM limitation (call trans_ok_p() above) */
boolean
check_hmm_limit(HTK_HMM_Data *dt)
{
  boolean return_flag = TRUE;

  /* check transitino restriction */
  if (trans_ok_p(dt->tr) == BAD) {
    j_printerr("Error: HMM \"%s\" has unsupported arc\n", dt->name);
    put_htk_trans(dt->tr);
    return_flag = FALSE;
  }
  /* should have at least one output state */
  if (dt->tr->statenum < 3) {
    j_printerr("Error: HMM \"%s\" has no output state (statenum=%d)\n", dt->name, dt->tr->statenum);
    return_flag = FALSE;
  }
  return(return_flag);
}

/* check all defined HMM */
boolean
check_all_hmm_limit(HTK_HMM_INFO *hmminfo)
{
  HTK_HMM_Data *dt;
  boolean return_flag = TRUE;

  for (dt = hmminfo->start; dt; dt = dt->next) {
    if (check_hmm_limit(dt) == FALSE) {
      return_flag = FALSE;
    }
  }
  return(return_flag);
}

boolean
is_context_free_model(HTK_HMM_Data *d)
{
  if (d->tr->a[0][d->tr->statenum-1] != LOG_ZERO) {
    return TRUE;
  }
  return FALSE;
}
