// file: $isip/class/search/HierarchicalSearch/hsrch_14.cc
// version: $Id: hsrch_15.cc 9340 2003-11-12 15:38:03Z alphonso $
//

// isip include files
//
#include "HierarchicalSearch.h"

// method: applyNSymbolScore
//
// arguments:
//  Instance* instance_a: (input) current instances
//  long     level_num_a: (input) the search level
//
// return: logical error status
//
// this method apply a n-symbol score to current instance
//
boolean HierarchicalSearch::applyNSymbolScore(Instance*& curr_instance_a,
					      long level_num_a){
  // local variable
  //
  Context* curr_context = (Context*)NULL;
  GraphVertex<SearchNode>* curr_vertex = (GraphVertex<SearchNode>*)NULL;
  
  // add the N-symbol score
  //
  if (!getSearchLevel(level_num_a).useNSymbol() ){

    // exit gracefully
    //
    return false;
  }

  // get current n-symbol
  //
  curr_context = curr_instance_a->getSymbol();

  if (curr_context == (Context*)NULL) {
    return Error::handle(name(), L"applyNSymbolScore", Error::ARG, __FILE__, __LINE__);
  }

  // retrieve the current vertex
  //
  curr_vertex = curr_context->getCentralVertex();
  
  if (curr_vertex == (GraphVertex<SearchNode>*)NULL) {

    // exit gracefully
    //
    return false;
  }
  
  else if (curr_vertex->isTerm() || curr_vertex->isStart()) {

    // exit gracefully
    //
    return false;
  }

  else if (curr_vertex->getItem()->isDummyNode()) {
    
    // exit gracefully
    //
    return false;
  }
  
  // can't apply lower level n-symbol probabilities
  //
  else if (curr_vertex->getItem()->
	   getSearchLevel()->getLevelIndex() >  level_num_a) {
    
    // exit gracefully
    //
    return false;
  }

  // apply the n-symbol probability at the same level
  // the nsymbol probability becomes the fact now.
  //
  else if (curr_vertex->getItem()->
	   getSearchLevel()->getLevelIndex() ==  level_num_a) {

    float posterior_score = 0.0;
    
    // add any posterior score such as n-symbol probabilities
    //
    if (!getSearchLevel(level_num_a).useRescore()) {

      // compute the n-symbol probability
      //
      shiftNSymbol(curr_instance_a, level_num_a, curr_vertex);
      
      posterior_score =
	getPosteriorScore(curr_instance_a->getNSymbol(), level_num_a);
      curr_instance_a->setLMScore(posterior_score);      
    }

    // when we are in acoustic rescoring mode we need to read the language
    // model probabilities directly from the symbol graph
    //
    else {

      float lm_score = curr_instance_a->getLMScore();
      float lm_scale = symbol_graph_d.getScale();
      posterior_score = lm_scale * lm_score;
    }
    
    // add the n-symbol probability
    //
    addInstanceScore(curr_instance_a, posterior_score, level_num_a, false);
  }

  // apply n-symbol probability to a higher level
  //
  else if (curr_context->getCentralVertex()->getItem()->
	   getSearchLevel()->getLevelIndex() <  level_num_a) {

    // for the next step
    //
    return false;
  }
  
  // exit gracefully
  //
  return true;

}

// method: addInstanceScore
//
// arguments:
//  Instance*& instance_a: (input) the endpoint of the new arc
//  float     score_a: (input) the score to be added
//  long     level_num_a: (input) the search level
//  boolean  weight_score_a: (input) this is a weight score or not
//
// return: logical error status
//
// add score to a instance, lm_scale and tr_scale will be used here
//
boolean HierarchicalSearch::addInstanceScore(Instance*& curr_instance_a,
					     float score_a,
					     long level_num_a,
					     boolean weight_score_a) {
  // local variable
  //
  float tr_scale = 1.0;
  float score = 0.0;
  
  // add the score from weight
  //
  if (weight_score_a){

    // get the score
    //
    score = curr_instance_a->getScore();

    // add the weight
    //
    score += score_a*tr_scale;
    curr_instance_a->setScore(score);
    
  }
  // add the N-symbol score
  //
  else if ( getSearchLevel(level_num_a).useNSymbol() ){
    
    // get the score
    //
    score = curr_instance_a->getScore();
    score += score_a;
    
    // set pre score
    //
    curr_instance_a->setScore(score);
  }
  
  return true;

}

/*
codes for next step - spread language model score
  
// method: getMaxScore
//
// arguments:
//  long     level_num_a: (input) the search level
//
// return: logical error status
//
// print an arc created in the hypothesis space
//
boolean HierarchicalSearch::getMaxScore(long& level_num_a,
					NGramModel& nsymbol_model_a,
					VectorLong& symbol_index_a,
					GraphVertex<SearchNode>*&
					start_vertex_a,
					float score_a,
					boolean recursive_a){
  
  // local variable
  //
  float max_score = (float)Integral::MIN_LOG_VALUE;
  Context* tmp_context = (Context*)NULL;
  Context* curr_context = (Context*)NULL;
  VectorLong symbol_indices;
  GraphVertex<SearchNode> succ_vert =  GraphVertex<SearchNode>* NULL;
  GraphArc<SearchNode> succ_vert =  GraphArc<SearchNode>* NULL;
  
  // need to avoid search for the same score
  //
  if ( (curr_instance_a->getPreNSymbolScore() != 0) &&
       (start_vertex_a->length() <= 1) && !recursive_a ) {

    score_a = 0;
    
    // exit, don't need to change the n-symbol score
    //
    return false;
    
  }

  // set the initial value
  //
  score_a = max_score;
  
  // loop throught all successors
  //
  for ( more_arcs = start_vertex_a->gotoFirst(); more_arcs;
	  more_arcs = start_vertex_a->gotoNext() ) {

    // get current arc
    //
    curr_arc = start_vertex_a->getCurr();
    
    // get the successor
    //
    succ_vertex = curr_arc->getVertex();
    SearchNode* succ_node = (LexicalNode*)succ_vertex->getItem();
    
    // if it is a NULL node
    //
    if (succ_node == (LexicalNode*)NULL){
      return Error::handle(name(), L"getMaxScore: invalid lexical tree node",
			   Error::NULL_ARG, __FILE__,
			   __LINE__);
    }
    else if ( succ_vertex->isStart() || succ_vertex->isTerm() ){
      
      return Error::handle(name(), L"getMaxScore: invalid lexical tree node",
			   Error::NULL_ARG, __FILE__,
			   __LINE__);
    }
    // if in the middle of the tree
    //
    else if ( succ_node->isDummyNode() ||
	      succ_node->getSearchLevel()->getLevelIndex() != level_num_a ){
      
      // call this function recursively
      //
      getMaxScore(level_num_a,
		  nsymbol_model_a,
		  symbol_index_a,
		  succ_vertex,
		  score_a,
		  true);
      
    }
    // if we reach the word we needed
    //
    else if (	succ_node->getSearchLevel()->getLevelIndex() == level_num_a ){

      // get this symbol's Id
      //
      long last_index = symbol_indices_a.length() - 1;
      symbol_indices_a(last_index) = succ_node->getSymbolId();
      
      // get the n-symbol probability
      //
      max_score = nsymbol_model_a.getScore(symbol_indices_a);

      // change the score
      //
      score_a = score_a >= max_score ? score_a : max_score;
    }
    else {
      
      // not implemented yet
      //
      return Error::handle(name(), L"getMaxScore: incorrect node",
			   Error::NOT_IMPLEM, __FILE__,
			   __LINE__);
    }
  }
  
  // exit gracefully
  //
  return true;
  
}

*/


