// file: $isip/class/search/StackSearch/StackSearch.h
// version: $Id: StackSearch.h 9742 2004-08-20 20:43:15Z may $
//

// make sure definitions are only made once
//
#ifndef ISIP_STACK_SEARCH
#define ISIP_STACK_SEARCH

// isip include files:
//
#ifndef ISIP_PRIORITY_QUEUE
#include <PriorityQueue.h>
#endif

#ifndef ISIP_HYPOTHESIS
#include <Hypothesis.h>
#endif

#ifndef ISIP_CONTEXT_POOL
#include <ContextPool.h>
#endif

#ifndef ISIP_HISTORY_POOL
#include <HistoryPool.h>
#endif

#ifndef ISIP_HASH_KEY
#include <HashKey.h>
#endif

#ifndef ISIP_MATRIX_FLOAT
#include <MatrixFloat.h>
#endif

#ifndef ISIP_FRONTEND
#include <FrontEnd.h>
#endif

#ifndef ISIP_HIERARCHICAL_DIGRAPH
#include <HierarchicalDigraph.h>
#endif

// StackSearch:	A hierarchical, asynchronous, stack search engine.
//
// StackSearch can decode same hierarchical structure of graphs.
// Decoding algorithm follows the multistack approach described in:
//
//   Renals S., Hochberg. M.: Decoder Technology for Connectionist
//     Large Vocabulary Speech Recognition
// 
// 
class StackSearch {
  
  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:

  // define the class name
  //
  static const String CLASS_NAME;

  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------  

  static const String DEF_PARAM;
  static const String PARAM_DECODING_MODE;
  static const String PARAM_SCORE_NORMALIZATION;
  static const String PARAM_STACK_LEVEL;
  static const String PARAM_MAX_MIN_FILENAME;
  static const String PARAM_SIL_DUR_PENALTY;
  
  //----------------------------------------
  //
  // other important constants
  //
  //----------------------------------------  

  enum EVALUATION_MODE { FRAME_EVAL = 0, SEGMENT_EVAL,
			 DEF_EVALUATION_MODE = FRAME_EVAL };
  enum DECODING_MODE { GLOBAL_STACK = 0, MULTI_STACK, VITERBI,
		       DEF_DECODING_MODE = GLOBAL_STACK };
  enum SCORE_NORMALIZATION { NONE = 0, DURATION, NUM_OF_PHONES,
			     DEF_SCORE_NORMALIZATION = NONE };

  // define static NameMap objects for the enumerated values
  //
  static const NameMap EVALUATION_MODE_MAP;
  static const NameMap DECODING_MODE_MAP;
  static const NameMap SCORE_NORMALIZATION_MAP;

  // define the start frame index
  //
  static const long START_FRAME = -1;

  // define how many frames to decode
  //
  static const long ALL_FRAMES = -1;

  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  // default values
  //
  static const long MAX_NUM_LEVELS = 3;
  static const long MAX_NUM_FRAMES = 1000;
  static const long DEF_N_BEST = 1;
  static const long DEF_STACK_LEVEL = 0;
  static const long DEF_GLOB_STACK_CAPACITY = 100000;
  static const float DEF_SIL_DUR_PENALTY = 0;
  
  // default arguments to methods
  //
  static const long ALL_LEVELS = -1;
  
  //---------------------------------------
  //
  // error codes
  //
  //---------------------------------------

  static const long ERR = (long)90800;
  static const long ERR_LEVELS_NOT_LOADED = (long)90801;
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // type definition
  // 
  typedef GraphVertex<SearchNode> GVSnode;

  // evaluation mode
  //
  EVALUATION_MODE evaluation_mode_d;

  // decoding mode
  //
  DECODING_MODE decoding_mode_d;

  // score normalization
  //
  SCORE_NORMALIZATION score_normalization_d;
  boolean user_requested_no_score_normalization_d;

  // feature vectors
  //
  Vector<VectorFloat> features_d;

  // svm features
  //
  Vector<Vector<VectorFloat> > svm_features_d;

  // total number of frames to decode
  //
  Long num_frames_d;

  // number of best word hypotheses to find
  //
  Long n_best_d;

  // lever where to put the stack
  //
  Long stack_level_d;

  // current frame in the search
  //
  Long current_frame_d;

  // search levels, sub-graphs are maintained at each SearchLevel 
  //
  HierarchicalDigraph* h_digraph_d;

  // vector that contains the location (index) of the nsymbol mapping
  //
  Vector<Long> nsymbol_mapping_d;

  // vector that contains the location (index) of the context mapping
  //
  Vector<Long> context_mapping_d;

  // maximal trace scores at each frame for all levels
  // used for beam pruning
  //
  MatrixFloat max_frame_scores_d;

  // maximal trace scores for stacks
  //
  VectorFloat max_stack_scores_d;

  // statistical model scores
  //
  MatrixFloat stat_model_scores_d;

  // vector that maps states to statistical model indices
  //
  Vector<Long> stat_model_mapping_d;

  // lists to keep track of traces during the search
  //
  Vector<DoubleLinkedList<Trace> > trace_lists_d;
  PriorityQueue<Trace> valid_hyps_d;
  DoubleLinkedList<Trace> term_hyps_d;

  // vector of hypothesis stacks
  // each stack contains word level hypothesess of one frame
  //
  Vector<
    HashTable<Trace, Stack<Hypothesis> >
    > stacks_d;

  // vector of hypothesis stacks
  // each stack contains word level hypothesess of one frame
  //
  PriorityQueue<Hypothesis> global_stack_d;

  // score of the best valid hypothesis found so far
  //
  float best_valid_score_d;
  Float sil_dur_penalty_d;

  // statistics
  //
  VectorLong num_eval_d;
  VectorLong num_avoided_eval_d;

  VectorLong num_traces_gen_d;
  VectorLong num_traces_vit_prun_d;
  VectorLong num_traces_beam_prun_d;

  // output file
  //
  Filename max_min_filename_d;

  // history and context pools
  //
  HistoryPool history_pool_d;
  ContextPool context_pool_d;
  
  // define a static debug level
  //
  static Integral::DEBUG debug_level_d;

  // define a static memory manager
  //
  static MemoryManager mgr_d;
  
  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:

  // method: name
  //
  static const String& name() {
    return CLASS_NAME;
  }
  static boolean diagnose(Integral::DEBUG debug_level);
  
  // debug methods:
  //  the setDebug method for this class is static because the debug_level is
  //  shared across all objects of this class
  //
  boolean debug(const unichar* message) const;

  // method: setDebug
  //
  static boolean setDebug(Integral::DEBUG debug_level) {
    debug_level_d = debug_level;
    return true;
  }

  // destructor/constructor(s)
  //
  ~StackSearch();
  StackSearch();
  StackSearch(const StackSearch& copy_search);
  
  // method: assign
  //
  boolean assign(const StackSearch& copy_search) {
    return Error::handle(name(), L"assign", Error::NOT_IMPLEM, __FILE__,
			 __LINE__);
  }

  // sofSize method
  //
  long sofSize() const;
  
  // read method
  //
  boolean read(Sof& sof, long tag, const String& cname = CLASS_NAME);

  // write method
  //
  boolean write(Sof& sof, long tag, const String& cname = CLASS_NAME) const;
  
  // method: readData
  //
  boolean readData(Sof& sof, const String& pname = DEF_PARAM,
		   long size = SofParser::FULL_OBJECT, boolean param = true,
                   boolean nested = false);
  
  // method: writeData
  //
  boolean writeData(Sof& sof, const String& pname = DEF_PARAM) const;

  // method: eq
  //
  boolean eq(const StackSearch& compare_search) const {
    return h_digraph_d->eq(*compare_search.h_digraph_d);
  }
  
  // method: new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }

  // method: new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }

  // method: delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }

  // method: setGrowSize
  //
  static boolean setGrowSize(long grow_size) {
    return mgr_d.setGrow(grow_size);
  }

  // clear method
  //
  boolean clear(Integral::CMODE ctype = Integral::DEF_CMODE);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods
  //
  //---------------------------------------------------------------------------

  // search level manipulation
  //
  boolean setNumLevels(long num_levels);

  // method: getNumLevels
  //
  long getNumLevels() const {
    return h_digraph_d->length();
  }

  // method: getSearchLevel
  //
  SearchLevel& getSearchLevel(long level) {
    return (*h_digraph_d)(level);
  }
  
  // method: getHDigraph
  //
  HierarchicalDigraph& getHDigraph() {
    return *h_digraph_d;
  }

  // method: setHDigraph
  //
  boolean setHDigraph(HierarchicalDigraph& h_digraph) {
    h_digraph_d = &h_digraph;
    return true;
  }
  
  // search initialization methods
  //
  boolean initSizes(long total_num_frames);
  boolean initializeLinearDecoder();

  // stack decoding methods
  //
  boolean decode(Vector<FrontEnd>& vector_fe,
		 long num_frames = ALL_FRAMES);
  boolean decode(Vector<VectorFloat>& features,
		 long num_frames = ALL_FRAMES);

  // hypothesis methods
  //
  boolean getHypotheses(String& output_hyp, long level, double& total_score,
			long& num_frames, DoubleLinkedList<Trace>& trace_path,
			String* word_hyp = NULL);

  // method: setDecodingMode
  //
  boolean setDecodingMode(DECODING_MODE decoding_mode) {
    decoding_mode_d = decoding_mode;
    return true;
  }

  // method: getDecodingMode
  //
  DECODING_MODE getDecodingMode() {
    return decoding_mode_d;
  }

  // method: setStackLevel
  //
  boolean setStackLevel(long level) {
    stack_level_d = level;
    return true;
  }

  // method: getStackLevel
  //
  long getStackLevel() {
    return stack_level_d;
  }

  // method: getScoreNormalization
  //
  SCORE_NORMALIZATION getScoreNormalization() {
    return score_normalization_d;
  }

  // method: setScoreNormalization
  //
  boolean setScoreNormalization(SCORE_NORMALIZATION arg) {
    score_normalization_d = arg;
    if (arg == NONE) {
      user_requested_no_score_normalization_d = true;
    }
    return true;
  }
  
  // method: setSilDurPenalty
  //
  boolean setSilDurPenalty(float arg) {
    sil_dur_penalty_d = arg;
    return true;
  }
  
  // method: getSilDurPenalty
  //
  float getSilDurPenalty() {
    return sil_dur_penalty_d;
  }
  
  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:
  
  // search initialization methods
  //
  boolean clearTraceStorage();
  boolean clearSearchNodesTraceLists();
  boolean clearValidHypsTrace();
  boolean clearTermHypsTrace();

  // search traversal methods
  //
  boolean traverseTraceLevels();
  boolean pathsRemainTrace();

  // trace propagation methods
  //
  boolean propagateTraces(DoubleLinkedList<Trace>* pickup_list = NULL,
			  long pickup_level = -1);
  boolean propagateTracesDown(long level_num_a,
		      DoubleLinkedList<Trace>* pickup_list = NULL,
		      long pickup_level = -1);
  boolean propagateTracesUp(long level_num_a,
			    DoubleLinkedList<Trace>* pickup_list = NULL,
			    long pickup_level = -1);
  boolean evaluateTraceModels(DoubleLinkedList<Trace>* pickup_list = NULL,
			      long pickup_level = -1);

  // trace bookkeeping methods
  //
  long getActiveTraces(long search_level = ALL_LEVELS);

  // debugging methods
  //
  boolean printNewPath(Trace* new_trace, Trace* old_trace);
  boolean printDeletedPath(Trace* new_trace, Trace* old_trace);  

  // pruning method
  //
  boolean beamPruneTrace(long level_num);

  // context related methods
  //
  boolean generateRightContexts(DoubleLinkedList<Context>& context_list,
				Context* initial_context,
				long depth);
  boolean generateInitialTraces();  

  // method extending hypothesis by one word
  //
  boolean extend(DoubleLinkedList<Trace>& hlist, 
		 long start_frame);

  boolean getTraces(DoubleLinkedList<Trace>& trace_list, long level);
  boolean setTraces(DoubleLinkedList<Trace>& trace_list, long level);

  // stack decoding core method
  //
  boolean decode();

  // method: setFrame
  //
  boolean setFrame(long frame) {
    current_frame_d = frame;
    return true;
  }

  // method to determine evaluation mode (FRAME, SEGMENT)
  //
  boolean determineEvaluationMode();

  // method to normalize features
  //
  boolean normalizeFeatures();
  
  // method to transform skip models
  //
  boolean transformSkipModels();

  // method to add skip transitions
  //
  boolean addSkipArcs(GraphVertex<SearchNode>* vertex_a,
		      const long level_ind_a);
};

// end of include file
//
#endif
