// file: $isip/class/search/HierarchicalSearch/hsrch_11.cc // // isip include files // #include "HierarchicalSearch.h" // method: addHypothesisPath // // arguments: // Trace*& new_trace: (input) new input trace // Trace*& old_trace: (input) old input trace // GraphArc*& arc: (input) graph transition arc // int32 level_num: (input) current level number // // return: logical error status // // this method add an trace to the hypothesis path // bool8 HierarchicalSearch::addHypothesisPath(Trace*& new_trace_a, Trace*& old_trace_a, GraphArc*& arc_a, int32 level_num_a) { // declare local variables // Context* symbol = (Context*)NULL; Trace* existing_trace = (Trace*)NULL; SearchNode* search_node = (SearchNode*)NULL; GraphVertex* v = (GraphVertex*)NULL; // retrieve the transition scores for the corresponding transition // float32 weight = arc_a->getWeight(); // retrieve the symbol penalty and transition scale for this level // float32 tr_scale = getSearchLevel(level_num_a).getTrScale(); float32 symbol_penalty = getSearchLevel(level_num_a).getSymbolPenalty(); // retrieve the symbol, search node and central vertex for this trace // if (((symbol = new_trace_a->getSymbol()) == (Context*)NULL) || ((v = symbol->getCentralVertex()) == (GraphVertex*)NULL) || ((search_node = v->getItem()) == (SearchNode*)NULL)) { return false; } // add the transition score and symbol insertion penalty (when applicable) // int32 symbol_id = search_node->getSymbolId(); if (!getSearchLevel(level_num_a).isDummySymbol(symbol_id) && !getSearchLevel(level_num_a).isSPenaltyExcludeSymbol(symbol_id)) { new_trace_a->setScore(new_trace_a->getScore() + (weight * tr_scale) + symbol_penalty); } else { new_trace_a->setScore(new_trace_a->getScore() + (weight * tr_scale)); } // add any posterior score such as n-symbol probabilities // if (getSearchLevel(level_num_a).useNSymbol()) { if (!getSearchLevel(level_num_a).useRescore() && !getSearchLevel(level_num_a).isDummySymbol(symbol_id) && !getSearchLevel(level_num_a).isNSymbolExcludeSymbol(symbol_id) && !v->isStart() && !v->isTerm()) { shiftNSymbol(new_trace_a, level_num_a, v); float32 posterior_score = getPosteriorScore(new_trace_a->getNSymbol(), level_num_a); new_trace_a->setScore(new_trace_a->getScore() + posterior_score); new_trace_a->setLMScore(posterior_score); } } // when we are in acoustic rescoring mode we need to read the language // model probabilities directly from the symbol graph // if (getSearchLevel(level_num_a).useRescore()) { // retrieve the lm score and the lm scale factor // float32 lm_score = arc_a->getLanguageWeight(); float32 lm_scale = symbol_graph_d.getScale(); // add the scaled lm score and symbol insertion penalty // new_trace_a->setScore(new_trace_a->getScore() + (lm_scale * lm_score)); if (getSearchLevel(level_num_a).useAcousticScore()) { // retrieve the ac score and the ac scale factor // float32 ac_score = arc_a->getAcousticWeight(); float32 ac_scale = getSearchLevel(level_num_a).getAcousticScale(); new_trace_a->setScore(new_trace_a->getScore() + (ac_score / ac_scale)); } } // apply viterbi pruning at this level if we are not applying nsymbol // probabilities and we are not generating symbol graphs // if (!getSearchLevel(level_num_a).useSymbolGraph() && !getSearchLevel(level_num_a).useNSymbol()) { // add the trace to the search node's trace list // if (search_node->addTrace(new_trace_a, current_frame_d, existing_trace)) { // update the maximal trace score for the beam pruning // float32 trace_score = new_trace_a->getScore(); if( getSearchLevel(level_num_a).useBeam() && (trace_score > max_trace_scores_d(level_num_a))) { max_trace_scores_d(level_num_a) = trace_score; } // set the backpointer // new_trace_a->setBackPointer(old_trace_a); // add the trace to the next level's trace list // trace_lists_d(level_num_a).insertLast(new_trace_a); // print debugging information // if (debug_level_d >= Integral::DETAILED) { printNewPath(new_trace_a, old_trace_a); } // insert the trace in the trellis (optional) // if (search_mode_d == TRAIN) { if (!insertNewPath(old_trace_a, new_trace_a, weight)) { return Error::handle(name(), L"addHypothesisPath", Error::ARG, __FILE__, __LINE__); } } } // delete the trace since there is existing trace with the same history // else { // print debugging information // if (debug_level_d >= Integral::DETAILED) { printDeletedPath(new_trace_a, old_trace_a); } // discard the new trace // delete new_trace_a; new_trace_a = (Trace*)NULL; // insert the trace in the trellis (optional) // if (search_mode_d == TRAIN) { if (existing_trace != (Trace*)NULL) { if (!insertOldPath(old_trace_a, existing_trace, weight)) { return Error::handle(name(), L"addHypothesisPath", Error::ARG, __FILE__, __LINE__); } } else { return Error::handle(name(), L"addHypothesisPath", Error::ARG, __FILE__, __LINE__); } } } } // propagate the path without pruning at all other levels // else { // update the maximal trace score for the beam pruning // float32 trace_score = new_trace_a->getScore(); if( getSearchLevel(level_num_a).useBeam() && (trace_score > max_trace_scores_d(level_num_a))) { max_trace_scores_d(level_num_a) = trace_score; } // set the backpointer // new_trace_a->setBackPointer(old_trace_a); // add the trace to the next level's trace list // trace_lists_d(level_num_a).insertLast(new_trace_a); // print debugging information // if (debug_level_d >= Integral::DETAILED) { printNewPath(new_trace_a, old_trace_a); } // insert the trace in the trellis (optional) // if (search_mode_d == TRAIN) { if (!insertNewPath(old_trace_a, new_trace_a, weight)) { return Error::handle(name(), L"addHypothesisPath", Error::ARG, __FILE__, __LINE__); } } } // exit gracefully // return true; } // method: addHypothesisPath // // arguments: // Instance*& new_instance: (input) new input instance // Instance*& old_instance: (input) old input instance // int32 level_num: (input) current level number // int32 weight_a: (input) transition score // // return: logical error status // // this method add an instance to the hypothesis path // bool8 HierarchicalSearch::addHypothesisPath(Instance*& new_instance_a, Instance*& old_instance_a, int32 level_num_a, float32 weight_a) { // declare local variables // Context* symbol = (Context*)NULL; Instance* existing_instance = (Instance*)NULL; SearchNode* search_node = (SearchNode*)NULL; GraphVertex* v = (GraphVertex*)NULL; // retrieve the symbol penalty and transition scale for this level // float32 tr_scale = getSearchLevel(level_num_a).getTrScale(); float32 symbol_penalty = getSearchLevel(level_num_a).getSymbolPenalty(); // retrieve the symbol, search node and central vertex for this instance // if ((symbol = new_instance_a->getSymbol()) == (Context*)NULL) { return false; } if ((v = symbol->getCentralVertex()) == (GraphVertex*)NULL) { return false; } if ((search_node = v->getItem()) == (SearchNode*)NULL) { return false; } // add the transition score and symbol insertion penalty (when applicable) // int32 symbol_id = search_node->getSymbolId(); if (!getSearchLevel(level_num_a).isDummySymbol(symbol_id) && !getSearchLevel(level_num_a).isSPenaltyExcludeSymbol(symbol_id)) { new_instance_a->setScore(new_instance_a->getScore() + (weight_a * tr_scale) + symbol_penalty); } else { new_instance_a->setScore(new_instance_a->getScore() + (weight_a * tr_scale)); } // add any posterior score such as n-symbol probabilities // if (getSearchLevel(level_num_a).useNSymbol()) { if (!getSearchLevel(level_num_a).isDummySymbol(symbol_id) && !getSearchLevel(level_num_a).isNSymbolExcludeSymbol(symbol_id) && !v->isStart() && !v->isTerm()) { shiftNSymbol(new_instance_a, level_num_a, v); float32 posterior_score = getPosteriorScore(new_instance_a->getNSymbol(), level_num_a); new_instance_a->setScore(new_instance_a->getScore() + posterior_score); } } // add the instance to the search node's instance list // if (search_node->addInstance(new_instance_a, current_frame_d, existing_instance)) { // update the maximal instance score for the beam pruning // float32 instance_score = new_instance_a->getScore(); if( getSearchLevel(level_num_a).useBeam() && (instance_score > max_instance_scores_d(level_num_a))) { max_instance_scores_d(level_num_a) = instance_score; } // set the backpointer // new_instance_a->setBackPointer(old_instance_a); // add the instance to the next level's instance list // instance_lists_d(level_num_a).insertLast(new_instance_a); // print debugging information // if (debug_level_d >= Integral::DETAILED) { printNewPath(new_instance_a, old_instance_a); } // insert the instance in the trellis // if (search_mode_d == TRAIN) { if (!insertNewPath(old_instance_a, new_instance_a, weight_a)) { return Error::handle(name(), L"addHypothesisPath", Error::ARG, __FILE__, __LINE__); } } } else { // print debugging information // if (debug_level_d >= Integral::DETAILED) { printDeletedPath(new_instance_a, old_instance_a); } // delete the instance since there is existing instance - same history // delete new_instance_a; new_instance_a = (Instance*)NULL; if (search_mode_d == TRAIN) { if (existing_instance != (Instance*)NULL) { if (!insertOldPath(old_instance_a, existing_instance, weight_a)) { return Error::handle(name(), L"addHypothesisPath", Error::ARG, __FILE__, __LINE__); } } else { return Error::handle(name(), L"addHypothesisPath", Error::ARG, __FILE__, __LINE__); } } } // exit gracefully // return true; } // method: insertNewPath // // arguments: // Trace* parent: (input) source trace // Trace* child: (input) destination trace // float32 weight: (input) transition probability // // return: logical error status // // method adds a new path to the trellis // bool8 HierarchicalSearch::insertNewPath(Trace* parent_a, Trace* child_a, float32 weight_a) { // declare local variables // BiGraphVertex* ptr = (BiGraphVertex*)NULL; BiGraphVertex* src = (BiGraphVertex*)NULL; BiGraphVertex* dst = (BiGraphVertex*)NULL; // make sure that neither the parent nor the child traces are null // if ((parent_a == (Trace*)NULL) || (child_a == (Trace*)NULL)) { return false; } // retrieve the refernece pointer // ptr = parent_a->getReference(); // check to see if the parent trace exists in the map // if (ptr != (BiGraphVertex*)NULL) { // get the parent and child vertices // src = ptr; dst = insertTrace(child_a); // add a transition in the trellis from the parent to the child // if (src != trellis_d.getTerm()) { trellis_d.insertArc(src, dst, false, weight_a); } } else { // get the parent and child vertices // src = insertTrace(parent_a); dst = insertTrace(child_a); // add a transition in the trellis from the parent to the child // if (src != trellis_d.getTerm()) { trellis_d.insertArc(src, dst, false, weight_a); } } // print debugging information // if (debug_level_d >= Integral::DETAILED) { GraphVertex* src_vertex = src->getItem()->getReference()->getCentralVertex(); GraphVertex* dst_vertex = dst->getItem()->getReference()->getCentralVertex(); int32 src_frame = src->getItem()->getFrame(); int32 dst_frame = dst->getItem()->getFrame(); SearchSymbol src_sym; if (src_vertex->isStart()) { src_sym.assign(L"_START_"); } else if (src_vertex->isTerm()) { src_sym.assign(L"_TERM_"); } else { src->getItem()->getReference()->print(src_sym); } SearchSymbol dst_sym; if (dst_vertex->isStart()) { dst_sym.assign(L"_START_"); } else if (dst_vertex->isTerm()) { dst_sym.assign(L"_TERM_"); } else { dst->getItem()->getReference()->print(dst_sym); } String val; String output(L"\n-> source: "); output.concat(src_vertex); output.concat(L", destination: "); output.concat(dst_vertex); output.concat(L"\n ["); output.concat(src_sym); output.concat(L"], frame: "); val.assign((int32)src_frame); output.concat(val); output.concat(L" -> ["); output.concat(dst_sym); output.concat(L"], frame: "); val.assign((int32)dst_frame); output.concat(val); Console::put(output); } // exit gracefully // return true; } // method: insertNewPath // // arguments: // Instance* parent: (input) source instance // Instance* child: (input) destination instance // float32 weight: (input) transition probability // // return: logical error status // // method adds a new path to the trellis // bool8 HierarchicalSearch::insertNewPath(Instance* parent_a,Instance* child_a, float32 weight_a) { // declare local variables // BiGraphVertex* ptr = (BiGraphVertex*)NULL; BiGraphVertex* src = (BiGraphVertex*)NULL; BiGraphVertex* dst = (BiGraphVertex*)NULL; // make sure that the child instances is not null // if (child_a == (Instance*)NULL) { return false; } // when the parent is null we are at the begining of the utterance // if (parent_a == (Instance*)NULL) { // get the parent and child vertices // src = trellis_d.getStart(); dst = insertInstance(child_a); // add a transition in the trellis from the parent to the child // if (src != trellis_d.getTerm()) { trellis_d.insertArc(src, dst, false, 0); } return true; } // retrieve the refernece pointer // ptr = parent_a->getReference(); // check to see if the parent trace exists in the map // if (ptr != (BiGraphVertex*)NULL) { // get the parent and child vertices // src = ptr; dst = insertInstance(child_a); // add a transition in the trellis from the parent to the child // if (src != trellis_d.getTerm()) { trellis_d.insertArc(src, dst, false, weight_a); } } else { // get the parent and child vertices // src = insertInstance(parent_a); dst = insertInstance(child_a); // add a transition in the trellis from the parent to the child // if (src != trellis_d.getTerm()) { trellis_d.insertArc(src, dst, false, weight_a); } } // print debugging information // if (debug_level_d >= Integral::DETAILED) { GraphVertex* src_vertex = src->getItem()->getReference()->getCentralVertex(); GraphVertex* dst_vertex = dst->getItem()->getReference()->getCentralVertex(); int32 src_frame = src->getItem()->getFrame(); int32 dst_frame = dst->getItem()->getFrame(); SearchSymbol src_sym; if (src_vertex->isStart()) { src_sym.assign(L"_START_"); } else if (src_vertex->isTerm()) { src_sym.assign(L"_TERM_"); } else { src->getItem()->getReference()->print(src_sym); } SearchSymbol dst_sym; if (dst_vertex->isStart()) { dst_sym.assign(L"_START_"); } else if (dst_vertex->isTerm()) { dst_sym.assign(L"_TERM_"); } else { dst->getItem()->getReference()->print(dst_sym); } String val; String output(L"\n-> source: "); output.concat(src_vertex); output.concat(L", destination: "); output.concat(dst_vertex); output.concat(L"\n ["); output.concat(src_sym); output.concat(L"], frame: "); val.assign((int32)src_frame); output.concat(val); output.concat(L" -> ["); output.concat(dst_sym); output.concat(L"], frame: "); val.assign((int32)dst_frame); output.concat(val); Console::put(output); } // exit gracefully // return true; } // method: insertOldPath // // arguments: // Trace* parent: (input) source trace // Trace* child: (input) destination trace // float32 weight: (input) transition probability // // return: logical error status // // method adds a new path to the trellis // bool8 HierarchicalSearch::insertOldPath(Trace* parent_a, Trace* child_a, float32 weight_a) { // declare local variables // BiGraphVertex* ptr = (BiGraphVertex*)NULL; BiGraphVertex* src = (BiGraphVertex*)NULL; BiGraphVertex* dst = (BiGraphVertex*)NULL; // make sure that neither the parent nor the child traces are null // if ((parent_a == (Trace*)NULL) || (child_a == (Trace*)NULL)) { return false; } // check to see if the parent trace exists in the map // ptr = parent_a->getReference(); if (ptr != (BiGraphVertex*)NULL) { src = ptr; } // check to see if the child trace exists in the map // ptr = child_a->getReference(); if (ptr != (BiGraphVertex*)NULL) { dst = ptr; } // add a transition in the trellis from the parent to the child // if ((src != (BiGraphVertex*)NULL) && (dst != (BiGraphVertex*)NULL)) { trellis_d.insertArc(src, dst, false, weight_a); // print debugging information // if (debug_level_d >= Integral::DETAILED) { GraphVertex* src_vertex = src->getItem()->getReference()->getCentralVertex(); GraphVertex* dst_vertex = dst->getItem()->getReference()->getCentralVertex(); int32 src_frame = src->getItem()->getFrame(); int32 dst_frame = dst->getItem()->getFrame(); SearchSymbol src_sym; if (src_vertex->isStart()) { src_sym.assign(L"_START_"); } else if (src_vertex->isTerm()) { src_sym.assign(L"_TERM_"); } else { src->getItem()->getReference()->print(src_sym); } SearchSymbol dst_sym; if (dst_vertex->isStart()) { dst_sym.assign(L"_START_"); } else if (dst_vertex->isTerm()) { dst_sym.assign(L"_TERM_"); } else { dst->getItem()->getReference()->print(dst_sym); } String val; String output(L"\n-> source: "); output.concat(src_vertex); output.concat(L", destination: "); output.concat(dst_vertex); output.concat(L"\n ["); output.concat(src_sym); output.concat(L"], frame: "); val.assign((int32)src_frame); output.concat(val); output.concat(L" -> ["); output.concat(dst_sym); output.concat(L"], frame: "); val.assign((int32)dst_frame); output.concat(val); Console::put(output); } } // exit gracefully // return true; } // method: insertOldPath // // arguments: // Instance* parent: (input) source instance // Instance* child: (input) destination instance // float32 weight: (input) transition probability // // return: logical error status // // method adds a new path to the trellis // bool8 HierarchicalSearch::insertOldPath(Instance* parent_a, Instance* child_a, float32 weight_a) { // declare local variables // BiGraphVertex* ptr = (BiGraphVertex*)NULL; BiGraphVertex* src = (BiGraphVertex*)NULL; BiGraphVertex* dst = (BiGraphVertex*)NULL; // make sure that neither the parent nor the child instances are null // if ((parent_a == (Instance*)NULL) || (child_a == (Instance*)NULL)) { return false; } // check to see if the parent instance exists in the map // ptr = parent_a->getReference(); if (ptr != (BiGraphVertex*)NULL) { src = ptr; } // check to see if the child instance exists in the map // ptr = child_a->getReference(); if (ptr != (BiGraphVertex*)NULL) { dst = ptr; } // add a transition in the trellis from the parent to the child // if ((src != (BiGraphVertex*)NULL) && (dst != (BiGraphVertex*)NULL)) { trellis_d.insertArc(src, dst, false, weight_a); // print debugging information // if (debug_level_d >= Integral::DETAILED) { GraphVertex* src_vertex = src->getItem()->getReference()->getCentralVertex(); GraphVertex* dst_vertex = dst->getItem()->getReference()->getCentralVertex(); int32 src_frame = src->getItem()->getFrame(); int32 dst_frame = dst->getItem()->getFrame(); SearchSymbol src_sym; if (src_vertex->isStart()) { src_sym.assign(L"_START_"); } else if (src_vertex->isTerm()) { src_sym.assign(L"_TERM_"); } else { src->getItem()->getReference()->print(src_sym); } SearchSymbol dst_sym; if (dst_vertex->isStart()) { dst_sym.assign(L"_START_"); } else if (dst_vertex->isTerm()) { dst_sym.assign(L"_TERM_"); } else { dst->getItem()->getReference()->print(dst_sym); } String val; String output(L"\n-> source: "); output.concat(src_vertex); output.concat(L", destination: "); output.concat(dst_vertex); output.concat(L"\n ["); output.concat(src_sym); output.concat(L"], frame: "); val.assign((int32)src_frame); output.concat(val); output.concat(L" -> ["); output.concat(dst_sym); output.concat(L"], frame: "); val.assign((int32)dst_frame); output.concat(val); Console::put(output); } } // exit gracefully // return true; } // method: insertTrace // // arguments: // Trace* trace: (input) trace to be added to the trellis // // return: train node vertex // // insert the trace into the trellis // BiGraphVertex* HierarchicalSearch::insertTrace(Trace* trace_a) { // declare local variables // TrainNode train_node; BiGraphVertex* vertex = (BiGraphVertex*)NULL; // initialize the time stamp (t) // if (trace_a != (Trace*)NULL) { train_node.setFrame((int32)trace_a->getFrame()); } // initialize the forward/backward probabilities at time (t) // train_node.setAlpha(Integral::DB_LOG_MIN_VALUE); train_node.setBeta(Integral::DB_LOG_MIN_VALUE); // initialize the reference pointers at time (t) // if (trace_a != (Trace*)NULL) { train_node.setReference(trace_a->getSymbol()); } // initialize the statistical model at time (t) // if (trace_a != (Trace*)NULL) { train_node.setStatisticalModel(trace_a->getSymbol()->getCentralVertex()-> getItem()->getStatisticalModel()); } // insert the node in the trellis and return the graph vertex // vertex = trellis_d.insertVertex(&train_node); // initialize the reference pointers for the trace // if (trace_a != (Trace*)NULL) { trace_a->setReference(vertex); } // return the inserted vertex // return vertex; } // method: insertInstance // // arguments: // Instance* instance: (input) instance to be added to the trellis // // return: train node vertex // // insert the instance into the trellis // BiGraphVertex* HierarchicalSearch::insertInstance(Instance* instance_a) { // declare local variables // TrainNode train_node; BiGraphVertex* vertex = (BiGraphVertex*)NULL; // initialize the time stamp (t) // if (instance_a != (Instance*)NULL) { train_node.setFrame((int32)instance_a->getFrame()); } // initialize the forward/backward probabilities at time (t) // train_node.setAlpha(Integral::DB_LOG_MIN_VALUE); train_node.setBeta(Integral::DB_LOG_MIN_VALUE); // initialize the reference pointer at time (t) // if (instance_a != (Instance*)NULL) { train_node.setReference(instance_a->getSymbol()); } // initialize the statistical model at time (t) // if (instance_a != (Instance*)NULL) { train_node.setStatisticalModel(instance_a->getSymbol()-> getCentralVertex()-> getItem()->getStatisticalModel()); } // insert the node in the trellis and return the graph vertex // vertex = trellis_d.insertVertex(&train_node); // initialize the reference pointers for the instance // if (instance_a != (Instance*)NULL) { instance_a->setReference(vertex); } // return the inserted vertex // return vertex; } // method: computeForwardBackward // // arguments: // Vector data: (output) feature vectors // float32 beta_threshold: (input) beta pruning threshold // // return: logical error status // // traverse the trellis and compute the state occupancies // BiGraph* HierarchicalSearch::computeForwardBackward(Vector& data_a, float32 beta_threshold_a) { // setup the initial conditions for the forward backward algorithm // initializeForwardBackward(); // traverse the trellis backwards and compute the backward probability // computeBackward(data_a, beta_threshold_a); // traverse the trellis backwards and compute the forward probability // computeForward(data_a); // return the trellis // return &trellis_d; } // method: initializeForwardBackward // // arguments: none // // return: logical error status // // this method setup the initial conditions for the forward backward algorithm // bool8 HierarchicalSearch::initializeForwardBackward() { // declare local variables // BiGraphVertex* vertex = (BiGraphVertex*)NULL; // get the start node of the trellis // vertex = trellis_d.getStart(); if (vertex != (BiGraphVertex*)NULL) { vertex->getItem()->setAlpha(0); } // get the term node of the trellis // vertex = trellis_d.getTerm(); if (vertex != (BiGraphVertex*)NULL) { vertex->getItem()->setBeta(0); } // exit gracefully // return true; } // method: computeForward // // arguments: // Vector data: (output) feature vectors // // return: logical error status // // this method computes the forward probability of the network // bool8 HierarchicalSearch::computeForward(Vector& data_a) { // iterate over all valid traces in the hypotheses list // BiGraphVertex* child = (BiGraphVertex*)NULL; BiGraphVertex* vertex = (BiGraphVertex*)NULL; DoubleLinkedList > active_list(DstrBase::USER); // add the term vertex to the active list // active_list.insertLast(trellis_d.getStart()); // loop until the active list is empty // while (!active_list.isEmpty()) { // remove the first element from the list // active_list.removeFirst(vertex); // compute the backward probability of the vertex // computeAlpha(data_a, vertex); // insert the children of the vertex on the list // for (bool8 more = vertex->gotoFirstChild(); more; more = vertex->gotoNextChild()) { child = vertex->getCurrChild()->getVertex(); if (child != (BiGraphVertex*)NULL) { if ((child->getItem() != (TrainNode*)NULL) && !child->getItem()->isAlphaValid()) { active_list.insertLast(child); child->getItem()->setAlphaValid(true); } } } } // clear the list before exiting // active_list.clear(); // exit gracefully // return true; } // method: computeBackward // // arguments: // Vector data: (input) feature vectors // float32 beta_threshold: (input) beta threshold // // return: logical error status // // this method computes the backward probability of the network // bool8 HierarchicalSearch::computeBackward(Vector& data_a, float32 beta_threshold_a) { // iterate over all valid traces in the hypotheses list // int32 timestamp = 0; float32 beta_value = 0.0; BiGraphVertex* parent = (BiGraphVertex*)NULL; BiGraphVertex* vertex = (BiGraphVertex*)NULL; VectorFloat beta_bound; DoubleLinkedList > active_list(DstrBase::USER); int32 num_frames = data_a.length(); int32 num_models = getSearchLevel(getNumLevels() - 1).getStatisticalModels().length(); float32** model_cache = new float32*[num_frames]; for (int32 i=0; i < num_frames; i++) { model_cache[i] = new float32[num_models]; for (int32 j=0; j < num_models; j++) { model_cache[i][j] = Integral::DB_LOG_MIN_VALUE; } } // set the length and initialize the beta bound // beta_bound.setLength(data_a.length()); beta_bound.assign(Integral::DB_LOG_MIN_VALUE); // first pass determines the maximum beta score for each time frame // // add the term vertex to the active list // active_list.insertLast(trellis_d.getTerm()); // loop until the active list is empty // while (!active_list.isEmpty()) { // remove the first element from the list // active_list.removeFirst(vertex); // compute the backward probability of the vertex // computeBeta(data_a, vertex, model_cache); // set the maximum beta value for the time frame if applicable // if (vertex->getItem() != (TrainNode*)NULL) { vertex->getItem()->setBetaValid(false); timestamp = vertex->getItem()->getFrame(); if ((timestamp >= 0) && (timestamp < data_a.length())) { beta_value = vertex->getItem()->getBeta(); if (beta_bound(timestamp) < beta_value) { beta_bound(timestamp) = beta_value; } } } // insert the parents of the vertex on the list // for (bool8 more = vertex->gotoFirstParent(); more; more = vertex->gotoNextParent()) { parent = vertex->getCurrParent()->getVertex(); if (parent != (BiGraphVertex*)NULL) { if ((parent->getItem() != (TrainNode*)NULL) && !parent->getItem()->isBetaValid()) { active_list.insertLast(parent); parent->getItem()->setBetaValid(true); } } } } // second pass applies beta pruning using the maximum beta score // // add the term vertex to the active list // active_list.insertLast(trellis_d.getTerm()); // loop until the active list is empty // while (!active_list.isEmpty()) { // remove the first element from the list // active_list.removeFirst(vertex); // set the maximum beta value for the time frame if applicable // if (vertex->getItem() != (TrainNode*)NULL) { timestamp = vertex->getItem()->getFrame(); if ((timestamp >= 0) && (timestamp < data_a.length())) { beta_value = vertex->getItem()->getBeta(); if ((beta_bound(timestamp) - beta_value) > beta_threshold_a) { vertex->getItem()->setValidNode(false); vertex->getItem()->setBeta(Integral::DB_LOG_MIN_VALUE); } } } // insert the parents of the vertex on the list // for (bool8 more = vertex->gotoFirstParent(); more; more = vertex->gotoNextParent()) { parent = vertex->getCurrParent()->getVertex(); if (parent != (BiGraphVertex*)NULL) { if ((parent->getItem() != (TrainNode*)NULL) && !parent->getItem()->isBetaValid()) { active_list.insertLast(parent); parent->getItem()->setBetaValid(true); } } } } // clear the data structures before exiting // active_list.clear(); // free memory // for (int32 i=0; i < num_frames; i++) { delete [] model_cache[i]; model_cache[i] = (float32*)NULL; } delete [] model_cache; model_cache = (float32**)NULL; // exit gracefully // return true; } // method: computeAlpha // // arguments: // Vector data: (output) feature vectors // BiGraphVertex& vertex: (input) trace whose back pointers we need // to recursively visit // float32 weight: (input) weight of the arc from the current trace to the next // // [1] L. Rabiner, B. H. Juang, "Fundamentals of Speech Recognition", Prentice // Hall P T R, New Jersey, 1993, pp. 337-338, ISBN 0-13-015157-2 // // 1. Initialization: // // Alpha(1)[i] = pi(i) * b(1) 1 <= i <= N // pi(i) = initial probability for state i // // 2. Induction: // // Alpha(t + 1)[j] = aij * b(t + 1)[j] * Alpha (t)[i] // i = [1, ..., N] // b = model evaluation for state j at time t + 1 // a = state transition between i at time t and j at time t + 1 // // return: logical error status // // computes the forward probability // bool8 HierarchicalSearch::computeAlpha(Vector& data_a, BiGraphVertex* vertex_a) { // declare local variables // float64 tmp_accum = 0.0; float64 accumulator = 0.0; bool8 accum_valid = false; TrainNode* prev_node = (TrainNode*)NULL; TrainNode* train_node = (TrainNode*)NULL; // get the state to be evaluated // train_node = vertex_a->getItem(); // make sure the state is not null // if (train_node == (TrainNode*)NULL) { return true; } // loop over all states at the previous time frame // accumulator = Integral::DB_LOG_MIN_VALUE; for (bool8 more = vertex_a->gotoFirstParent(); more; more = vertex_a->gotoNextParent()) { // get the train node associate with the state at the previous time frame // prev_node = vertex_a->getCurrParent()->getVertex()->getItem(); // make sure that this node contributes to the alpha probability // if ((prev_node == (TrainNode*)NULL) || !prev_node->getValidNode()) { continue; } // compute the forward probability // tmp_accum = prev_node->getAlpha() + vertex_a->getCurrParent()->getWeight(); // accumulate the backward probability over different states // accum_valid = true; accumulator = Integral::logAddLog(accumulator, tmp_accum); } // when the current state does not have a valid statistical model // propagate the forward probabilities through // if (!train_node->getValidModel()) { if (accum_valid) { train_node->setAlpha(accumulator); } } // when the current state does have a valid statistical model propagate // the forward probabilities through after model evaluation // else { if (accum_valid) { accumulator += train_node->getScore(); train_node->setAlpha(accumulator); } } // exit gracefully // return true; } // method: computeBeta // // arguments: // Vector data: (output) feature vectors // BiGraphVertex& vertex: (input) trace whose back pointers we need // to recursively visit // float32** model_cache: (input) model cache // // [1] L. Rabiner, B. H. Juang, "Fundamentals of Speech Recognition", Prentice // Hall P T R, New Jersey, 1993, pp. 337-338, ISBN 0-13-015157-2 // // 1. Initialization: // // Beta(T)[i] = 1 1 <= i <= N // // 2. Induction: // // Beta(t)[i] = aij * b(t + 1)[j] * Beta (t + 1)[j] // j = [1, ..., N] // b = model evaluation for state j at time t + 1 // a = state transition between i at time t and j at time t + 1 // // return: logical error status // // computes the backward probability // bool8 HierarchicalSearch::computeBeta(Vector& data_a, BiGraphVertex* vertex_a, float32** model_cache_a) { // declare local variables // float64 tmp_accum = 0.0; float64 accumulator = 0.0; bool8 accum_valid = false; TrainNode* next_node = (TrainNode*)NULL; TrainNode* train_node = (TrainNode*)NULL; SearchNode* search_node = (SearchNode*)NULL; Context* reference_symbol = (Context*)NULL; GraphVertex* reference_vertex = (GraphVertex*)NULL; // get the trace associated with the state // train_node = vertex_a->getItem(); // make sure the state is not null // if (train_node == (TrainNode*)NULL) { return true; } // loop over all states at next time frame // accumulator = Integral::DB_LOG_MIN_VALUE; for (bool8 more = vertex_a->gotoFirstChild(); more; more = vertex_a->gotoNextChild()) { // get the train node associate with the state at the next time frame // next_node = vertex_a->getCurrChild()->getVertex()->getItem(); // make sure that this node contributes to the beta probability // if ((next_node == (TrainNode*)NULL) || !next_node->getValidNode()) { continue; } // compute the backward probability // float32 score = 0.0; int32 frame = next_node->getFrame(); reference_vertex = (GraphVertex*)NULL; if ((reference_symbol = next_node->getReference()) != (Context*)NULL) { reference_vertex = reference_symbol->getCentralVertex(); } if ((reference_vertex != (GraphVertex*)NULL) && ((search_node = reference_vertex->getItem()) != (SearchNode*)NULL)) { if ((frame > -1) && (frame < data_a.length())) { StatisticalModel* stat_model = search_node->getStatisticalModel(); if (stat_model != (StatisticalModel*)NULL) { int32 model_index = search_node->getModelId(); if (model_cache_a[frame][model_index] != Integral::DB_LOG_MIN_VALUE) { score = model_cache_a[frame][model_index]; } else { score = stat_model->getLogLikelihood(data_a(frame)); model_cache_a[frame][model_index] = score; } } } } // update the score // next_node->setScore(score); tmp_accum = next_node->getBeta() + vertex_a->getCurrChild()->getWeight() + score; // accumulate the backward probability over different states // accum_valid = true; accumulator = Integral::logAddLog(accumulator, tmp_accum); } // mark the train node so that is used in the accumulate/update phase // train_node->setValidNode(true); // have we accumulated any statistics? // if (accum_valid) { train_node->setBeta(accumulator); } // exit gracefully // return true; } // method: traverseTraceLevels // // arguments: none // // return: logical error status // // do a single-step traversal of the hypotheses at each level // bool8 HierarchicalSearch::traverseTraceLevels() { // define local variables // bool8 status = false; // make sure we have some paths left to traverse // if (!pathsRemainTrace()) { return false; } // propagate traces forward until they are all ready to be evaluated // status = (propagateTraces() || status); // now we evaluate all traces that are in the lowest level and move // them forward one arc. viterbi pruning takes place at this level // as does beam pruning. // status = (evaluateTraceModels() || status); // exit gracefully // return status; } // method: traverseInstanceLevels // // arguments: none // // return: logical error status // // do a single-step traversal of the hypotheses at each level // bool8 HierarchicalSearch::traverseInstanceLevels() { // define local variables // bool8 status = false; // make sure we have some paths left to traverse // if (!pathsRemainInstance()) { return false; } // propagate instances forward until they are all ready to be evaluated // status = (propagateInstances() || status); // now we evaluate all instances that are in the lowest level and move // them forward one arc. viterbi pruning takes place at this level // as does beam pruning. // status = (evaluateInstanceModels() || status); // exit gracefully // return status; } // method: propagateInstances // // arguments: none // // return: logical error status // // move instances through the hierarchy until all active instances are ready // to be evaluated // bool8 HierarchicalSearch::propagateInstances() { // define local variables // int32 level_num = 0; bool8 status = true; int32 num_levels = getNumLevels(); // clear the hypothesis list since we are generating new hypotheses for this // frame // clearValidHypsInstance(); // move all traces forward in the search space. we do this by // pushing traces up and down in the hierarchy until they all rest // in a state that is ready to be evaluated. if there is an infinite // "skip" loop in the search graph then this process will go into an // infinite loop. an infinite skip loop is of the form: // A -> B && B -> A. // this infinite loop structure may be masked by the fact that it // extends over multiple search levels. // // when we exit the while loop below, all traces should be in the lowest // level and should be ready for evaluation. // while ((getActiveInstances() != getActiveInstances(num_levels - 1)) || status) { // status indicates whether any movement in the traces happened // status = false; for (level_num = (int32)initial_level_d; level_num < num_levels; level_num++) { if (getSearchLevel(level_num).useBeam()) { max_instance_scores_d(level_num) = Trace::INACTIVE_SCORE; } } // work from the bottom up until we reach a point where all traces // are ready to descend again // for (level_num = num_levels - 1; level_num >= (int32)initial_level_d; level_num--) { if (debug_level_d >= Integral::DETAILED) { String output; output.assign(L"propagating instances up from level: "); output.concat(level_num); output.concat(L" in frame: "); output.concat(current_frame_d); Console::put(output); } status = (propagateInstancesUp(level_num) || status); } // propagate traces down the hierarchy, carrying out viterbi pruning // for (level_num = (int32)initial_level_d; level_num < num_levels - 1; level_num++) { // beam pruning // if (getSearchLevel(level_num).useBeam()) { if (debug_level_d >= Integral::DETAILED) { Console::put(L"\nbeam pruning after propagation instance up"); } beamPruneInstance(level_num); } // instance pruning // if (getSearchLevel(level_num).useInstance()) { if (debug_level_d >= Integral::DETAILED) { Console::put(L"\ninstance pruning after propagation instances up"); } instancePruneInstance(level_num); } if (debug_level_d >= Integral::DETAILED) { String output; output.assign(L"propagating instances down from level: "); output.concat(level_num); output.concat(L" in frame: "); output.concat(current_frame_d); Console::put(output); } status = (propagateInstancesDown(level_num) || status); } } // print debugging information // if (debug_level_d >= Integral::ALL) { String val; val.assign(L"old frame:"); val.concat(current_frame_d); val.concat(L" instances left:"); val.concat(getActiveInstances(num_levels - 1)); Console::put(val); } // exit gracefully // return true; } // method: propagateTraces // // arguments: none // // return: logical error status // // move traces through the hierarchy until all active traces are ready to be // evaluated // bool8 HierarchicalSearch::propagateTraces() { // define local variables // int32 level_num = 0; bool8 status = true; int32 num_levels = getNumLevels(); String out; // clear the hypothesis list since we are generating new hypotheses for this // frame // clearValidHypsTrace(); // move all traces forward in the search space. we do this by // pushing traces up and down in the hierarchy until they all rest // in a state that is ready to be evaluated. if there is an infinite // "skip" loop in the search graph then this process will go into an // infinite loop. an infinite skip loop is of the form: // A -> B && B -> A. // this infinite loop structure may be masked by the fact that it // extends over multiple search levels. // // when we exit the while loop below, all traces should be in the lowest // level and should be ready for evaluation. // while ((getActiveTraces() != getActiveTraces(num_levels - 1)) || status) { // status indicates whether any movement in the traces happened // status = false; for (level_num = (int32)initial_level_d; level_num < num_levels; level_num++) { if (getSearchLevel(level_num).useBeam()) { max_trace_scores_d(level_num) = Trace::INACTIVE_SCORE; } } // work from the bottom up until we reach a point where all traces // are ready to descend again. this segment takes care of // posterior scores such as nsymbol probabilities and applies // pruning (beam and instance) at each level. // for (level_num = num_levels - 1; level_num >= (int32)initial_level_d; level_num--) { if (debug_level_d >= Integral::DETAILED) { String output; output.assign(L"propagating traces up from level: "); output.concat(level_num); output.concat(L" in frame: "); output.concat(current_frame_d); Console::put(output); } // propagate up // status = (propagateTracesUp(level_num) || status); } // propagate traces down the hierarchy, carrying out viterbi pruning // as we go. // for (level_num = (int32)initial_level_d; level_num < num_levels - 1; level_num++) { // beam pruning // if (getSearchLevel(level_num).useBeam()) { if (debug_level_d >= Integral::DETAILED) { Console::put(L"\nbeam pruning after propagation trace up"); } beamPruneTrace(level_num); } // instance pruning // if (getSearchLevel(level_num).useInstance()) { if (debug_level_d >= Integral::DETAILED) { Console::put(L"\ninstance pruning after propagation trace up"); } instancePruneTrace(level_num); } if (debug_level_d >= Integral::DETAILED) { String output; output.assign(L"propagating traces down from level: "); output.concat(level_num); output.concat(L" in frame: "); output.concat(current_frame_d); Console::put(output); } // propagate down // status = (propagateTracesDown(level_num) || status); } } // exit gracefully // return true; } // method: evaluateInstanceModels // // arguments: (none) // // return: logical error status. // // evaluate all statistical models // bool8 HierarchicalSearch::evaluateInstanceModels() { // define local variables // String out; String val; int32 level_num = getNumLevels() - 1; bool8 end_loop = false; SearchSymbol item; Instance* curr_instance = (Instance*)NULL; Instance* next_instance = (Instance*)NULL; GraphVertex* curr_vert = (GraphVertex*)NULL; DiGraph* parent_graph = (DiGraph*)NULL; BiGraphVertex* vertex = (BiGraphVertex*)NULL; // output the frame information // if (debug_level_d >= Integral::DETAILED) { out.assign(L"\n-> evaluating data in frame: "); val.assign((uint64)current_frame_d); out.concat(val); Console::put(out); } // when we are NOT in context generation mode - // evaluate each instance at the lowest level of the hierarchy // if (!context_generation_mode_d && (search_mode_d != TRAIN)) { // if the beam pruning is required at this level // initialize the maximal instance score // if(getSearchLevel(level_num).useBeam()) { max_instance_scores_d(level_num) = Instance::INACTIVE_SCORE; } // loop over all active instances and score them // for (bool8 more_instances = instance_lists_d(level_num).gotoFirst(); more_instances; more_instances = instance_lists_d(level_num).gotoNext()) { // get the current vertex in the search graph // curr_instance = instance_lists_d(level_num).getCurr(); curr_vert = curr_instance->getSymbol()->getCentralVertex(); // evaluate the statistical model // float32 model_score = curr_vert->getItem()->evaluateData(features_d, (int32)current_frame_d); float32 new_score = curr_instance->getScore() + model_score; curr_instance->setScore(new_score); if (search_mode_d == TRAIN) { // update the trained node in the trellis // vertex = curr_instance->getReference(); if (vertex == (BiGraphVertex*)NULL) { return Error::handle(name(), L"evaluateTraceModels", Error::ARG, __FILE__, __LINE__); } vertex->getItem()->setScore(model_score); } // update the maximal instance score for the beam pruning // if(getSearchLevel(level_num).useBeam() && (new_score > max_instance_scores_d(level_num))) { max_instance_scores_d(level_num) = new_score; } } // beam pruning at this level // if (getSearchLevel(getNumLevels() - 1).useBeam()) { if (debug_level_d >= Integral::DETAILED) { Console::put(L"\nbeam pruning after the model evaluation"); } beamPruneInstance(getNumLevels() - 1); } // instance pruning at this level // if (getSearchLevel(getNumLevels() - 1).useInstance()) { if (debug_level_d >= Integral::DETAILED) { Console::put(L"\ninstance pruning after the model evaluation"); } instancePruneInstance(getNumLevels() - 1); } } // update current frame // - instances generated later will correspond to the next frame // current_frame_d += 1 ; // print debugging information // if (debug_level_d >= Integral::DETAILED) { out.assign(L"\n-> time changed to: "); out.concat(current_frame_d); Console::put(out); } // we mark the current end of the list so we only propagate those instances // forward that were just evaluated // instance_lists_d(level_num).gotoLast(); instance_lists_d(level_num).setMark(); instance_lists_d(level_num).gotoFirst(); // print debugging information // if (debug_level_d >= Integral::DETAILED) { Console::put(L"\npropagating instances forward after the model evaluation"); } // loop until we have propagated all evaluated instances forward // end_loop = instance_lists_d(level_num).isEmpty(); while (!end_loop) { end_loop = instance_lists_d(level_num).isMarkedElement(); // get the current vertex in the search graph // curr_instance = instance_lists_d(level_num).getCurr(); curr_vert = curr_instance->getSymbol()->getLastVertex(); parent_graph = curr_vert->getParentGraph(); // when we are in context generation mode - // we do not need to evaluate the states at the lowest level // if (context_generation_mode_d) { // create a new instance // next_instance = new Instance(*curr_instance); next_instance->setFrame((uint32)current_frame_d); // update the history with the next node at this level // Context term_context; term_context.assignAndAdvance((uint64)parent_graph->getTerm()); next_instance->setSymbol(context_pool_d.get(term_context)); // set the backpointer // next_instance->setBackPointer(curr_instance); // add the instance to this level's instance list // instance_lists_d(level_num).insertLast(next_instance); if (debug_level_d >= Integral::DETAILED) { printNewPath(next_instance, curr_instance); } // bump the current instance off of the instance list // instance_lists_d(level_num).removeFirst(curr_instance); if (curr_instance->getRefCount() < 1) { Instance::deleteInstance(curr_instance, true); } instance_lists_d(level_num).gotoFirst(); // evaluate the next instance in the list // continue; } // if this instance is inactive, then delete it // if (!curr_instance->isActive()) { // bump the current instance off of the instance list // if (debug_level_d >= Integral::ALL) { Console::put(L" not active"); } instance_lists_d(level_num).removeFirst(curr_instance); Instance::deleteInstance(curr_instance, true); } // else, extend paths and apply viterbi pruning // else { // extend all paths from that vertex and apply viterbi pruning // for (bool8 more_paths = curr_vert->gotoFirst(); more_paths; more_paths = curr_vert->gotoNext()) { // create a new instance // next_instance = new Instance(*curr_instance); next_instance->setFrame((uint32)current_frame_d); // update the history with the next node at this level // GraphArc* tmp_arc = curr_vert->getCurr(); next_instance->setSymbol(context_pool_d.shiftAndAllocate(next_instance->getSymbol(), tmp_arc->getVertex())); // add the instance to the search node's instance list // if (!addHypothesisPath(next_instance, curr_instance, level_num, tmp_arc->getWeight())) { return Error::handle(name(), L"evaluateInstanceModels", Error::ARG, __FILE__, __LINE__); } } // bump the current instance off of the instance list // instance_lists_d(level_num).removeFirst(curr_instance); if (curr_instance->getRefCount() < 1) { Instance::deleteInstance(curr_instance, true); } instance_lists_d(level_num).gotoFirst(); } // end if the instance is active } // end while (!end_loop) // exit gracefully // return true; } // method: evaluateTraceModels // // arguments: (none) // // return: logical error status. // // evaluate all statistical models // bool8 HierarchicalSearch::evaluateTraceModels() { // define local variables // String out; String val; int32 level_num = getNumLevels() - 1; bool8 end_loop = false; Trace* curr_trace = (Trace*)NULL; Trace* next_trace = (Trace*)NULL; GraphVertex* curr_vert = (GraphVertex*)NULL; SearchSymbol item; BiGraphVertex* vertex = (BiGraphVertex*)NULL; // output the frame information // if (debug_level_d >= Integral::DETAILED) { out.assign(L"\n-> evaluating data in frame: "); val.assign((uint64)current_frame_d); out.concat(val); Console::put(out); } // add for word-internal context generation // when we are NOT in context generation mode - // evaluate each instance at the lowest level of the hierarchy // if (!context_generation_mode_d && (search_mode_d != TRAIN)) { // if the beam pruning is required at this level // initialize the maximal trace score // if(getSearchLevel(level_num).useBeam()) { max_trace_scores_d(level_num) = Trace::INACTIVE_SCORE; } // loop over all active traces and score them // for (bool8 more_traces = trace_lists_d(level_num).gotoFirst(); more_traces; more_traces = trace_lists_d(level_num).gotoNext()) { // get the current vertex in the search graph // curr_trace = trace_lists_d(level_num).getCurr(); curr_vert = curr_trace->getSymbol()->getCentralVertex(); // evaluate the statistical model // float32 model_score = curr_vert->getItem()->evaluateData(features_d, (int32)current_frame_d); float32 new_score = curr_trace->getScore() + model_score; curr_trace->setScore(new_score); if (search_mode_d == TRAIN) { // update the trained node in the trellis // vertex = curr_trace->getReference(); if (vertex == (BiGraphVertex*)NULL) { return Error::handle(name(), L"evaluateTraceModels", Error::ARG, __FILE__, __LINE__); } vertex->getItem()->setScore(model_score); } // update the maximal trace score for the beam pruning // if(getSearchLevel(level_num).useBeam() && (new_score > max_trace_scores_d(level_num))) { max_trace_scores_d(level_num) = new_score; } } // beam pruning at this level // if (getSearchLevel(getNumLevels() - 1).useBeam()) { if (debug_level_d >= Integral::DETAILED) { Console::put(L"\nbeam pruning after the model evaluation"); } beamPruneTrace(getNumLevels() - 1); } // instance pruning at this level // if (getSearchLevel(getNumLevels() - 1).useInstance()) { if (debug_level_d >= Integral::DETAILED) { Console::put(L"\ninstance pruning after the model evaluation"); } instancePruneTrace(getNumLevels() - 1); } } // end of non-context-generation mode // update current frame // - traces generated later will correspond to the next frame // current_frame_d += 1 ; if (debug_level_d >= Integral::DETAILED) { out.assign(L"\n-> time changed to: "); out.concat(current_frame_d); Console::put(out); } // we mark the current end of the list so we only propagate those traces // forward that were just evaluated // trace_lists_d(level_num).gotoLast(); trace_lists_d(level_num).setMark(); trace_lists_d(level_num).gotoFirst(); if (debug_level_d >= Integral::DETAILED) { Console::put(L"\npropagating traces forward after the model evaluation"); } // loop until we have propagated all evaluated traces forward // end_loop = (trace_lists_d(level_num).length() < 1); while (!end_loop) { end_loop = trace_lists_d(level_num).isMarkedElement(); // get the current vertex in the search graph // curr_trace = trace_lists_d(level_num).getCurr(); curr_vert = curr_trace->getSymbol()->getLastVertex(); // add for word-internal context generation // we do not need to evaluate the states at the lowest level // if (context_generation_mode_d) { // get parent graph // DiGraph* parent_graph = curr_vert->getParentGraph(); // create a new trace // next_trace = new Trace(*curr_trace); next_trace->setFrame((uint32)current_frame_d); // update the history with the next node at this level // next_trace->getSymbol()->assignAndAdvance((uint64)parent_graph->getTerm()); // set the backpointer // next_trace->setBackPointer(curr_trace); // add the trace to this level's trace list // trace_lists_d(level_num).insertLast(next_trace); if (debug_level_d >= Integral::DETAILED) { printNewPath(next_trace, curr_trace); } // bump the current trace off of the trace list // trace_lists_d(level_num).removeFirst(curr_trace); if (curr_trace->getRefCount() < 1) { Trace::deleteTrace(curr_trace, true); } trace_lists_d(level_num).gotoFirst(); // evaluate the next trace in the list // continue; } // if this trace is inactive, then delete it // if (!curr_trace->isActive()) { // bump the current trace off of the trace list // if (debug_level_d >= Integral::ALL) { Console::put(L" not active"); } trace_lists_d(level_num).removeFirst(curr_trace); Trace::deleteTrace(curr_trace, true); } // else, extend paths and apply viterbi pruning // else { // extend all paths from that vertex and apply viterbi pruning // for (bool8 more_paths = curr_vert->gotoFirst(); more_paths; more_paths = curr_vert->gotoNext()) { // create a new trace // next_trace = new Trace(*curr_trace); next_trace->setFrame((uint32)current_frame_d); // has the context been previously generated? if so reuse the context, // if not generate a new context and add it to the context pool // GraphArc* tmp_arc = curr_vert->getCurr(); next_trace->setSymbol(context_pool_d.shiftAndAllocate(next_trace->getSymbol(), tmp_arc->getVertex())); // add the trace to the search node's trace list // if (!addHypothesisPath(next_trace, curr_trace, tmp_arc, level_num)) { return Error::handle(name(), L"evaluateTraceModels", Error::ARG, __FILE__, __LINE__); } } // bump the current trace off of the trace list // trace_lists_d(level_num).removeFirst(curr_trace); if (curr_trace->getRefCount() < 1) { Trace::deleteTrace(curr_trace, true); } trace_lists_d(level_num).gotoFirst(); } // end if the trace is active } // end while (!end_loop) // exit gracefully // return true; } // method: propagateInstancesUp // // arguments: // int32 level_num: (input) the level for which we will propagate instances // // return: logical error status // // propagate all instances up the hierarchy. only instances at the end of a // each subgraph are considered // bool8 HierarchicalSearch::propagateInstancesUp(int32 level_num_a) { // define local variables // bool8 status = false; bool8 end_loop = false; Context* tmp_context = (Context*)NULL; Instance* curr_instance = (Instance*)NULL; Instance* tmp_instance = (Instance*)NULL; Instance* next_instance = (Instance*)NULL; GraphVertex* curr_vert = (GraphVertex*)NULL; // make sure there is at least one instance to propagate // if (instance_lists_d(level_num_a).length() < 1) { return false; } // loop over all current instances and create the next level's instances. // all new instances will go at the end of the list so we set the mark to // tell us when to stop propagating // instance_lists_d(level_num_a).gotoLast(); instance_lists_d(level_num_a).setMark(); instance_lists_d(level_num_a).gotoFirst(); while (!end_loop) { // loop until we reached the marked element // end_loop = instance_lists_d(level_num_a).isMarkedElement(); // get the current first instance from the list // instance_lists_d(level_num_a).removeFirst(curr_instance); // if the instance is inactive then delete it and its backpath if necessary // if (!curr_instance->isActive()) { Instance::deleteInstance(curr_instance, true); } // else, extend paths and update scores // else { // get the current vertex in the search graph // curr_vert = curr_instance->getSymbol()->getCentralVertex(); // if this vertex is a terminal vertex then ascend and create the traces // at the higher level // if (curr_vert->isTerm()) { // set the status to true since we are propagating a instance // status = true; // if we are at the top level then put the instance into the valid // hypothesis list // if (level_num_a == (int32)initial_level_d) { instance_valid_hyps_d.insertLast(curr_instance); } // else move up one level and create the next set of instances // else { // create a new instance, // next_instance = new Instance(*curr_instance); next_instance->setFrame((uint32)current_frame_d); next_instance->setBackPointer(curr_instance); // decrement the history of the instance // next_instance->setHistory(history_pool_d.popAndAllocate(next_instance->getHistory(), tmp_context)); // the context must exist in the context pool in this case // next_instance->setSymbol(context_pool_d.get(*tmp_context)); // print the debuging information // if (debug_level_d >= Integral::DETAILED) { printNewPath(next_instance, curr_instance); } // insert the instance into the trellis // if (search_mode_d == TRAIN) { if (!insertNewPath(curr_instance, next_instance, 0)) { return Error::handle(name(), L"propagateInstancesUp", Error::ARG, __FILE__, __LINE__); } } if (isTerminal(next_instance, level_num_a - 1)) { // create a temporary instance // tmp_instance = new Instance(*next_instance); tmp_instance->setFrame((uint32)current_frame_d); tmp_instance->setBackPointer(next_instance); // create a context with a terminal as the central context // Context term_context; term_context.assignAndAdvance((uint64)(*h_digraph_d)((int64)initial_level_d).getSubGraph(0).getTerm()); tmp_instance->setSymbolStack(history_pool_d.pushAndAllocate(tmp_instance->getSymbolStack(), tmp_instance->getSymbol())); tmp_instance->setSymbol(context_pool_d.get(term_context)); // add the instance to this level's instance list // instance_lists_d(level_num_a - 1).insertLast(tmp_instance); // print the debuging information // if (debug_level_d >= Integral::DETAILED) { printNewPath(tmp_instance, next_instance); } // insert the insatnce into the trellis // if (search_mode_d == TRAIN) { if (!insertNewPath(next_instance, tmp_instance, 0)) { return Error::handle(name(), L"propagateInstancesUp", Error::ARG, __FILE__, __LINE__); } } } // extend the current context // else { if (!extendRightContexts(next_instance, level_num_a - 1)) { return Error::handle(name(), L"propagateInstancesUp", Error::ARG, __FILE__, __LINE__); } } // delete next_instance if no instances propagated from it // have survived // if (next_instance->getRefCount() < 1) { Instance::deleteInstance(next_instance, false); } } // bump the current instance off of the instance list // if (curr_instance->getRefCount() < 1) { // if this is at top level, we can not delete them since they // are also referenced by the valid_hyps // if (level_num_a != (int32)initial_level_d) { Instance::deleteInstance(curr_instance, true); } } instance_lists_d(level_num_a).gotoFirst(); } // when the instance is NOT at the end of the current subgraph we keep // it at this level for now it gets propagated forwards during the // evaluateInstanceModels function // else { // update the maximal instance score for the beam pruning // float32 instance_score = curr_instance->getScore(); if(getSearchLevel(level_num_a).useBeam() && (instance_score > max_instance_scores_d(level_num_a)) ) { max_instance_scores_d(level_num_a) = instance_score; } // keep the instance on this level // instance_lists_d(level_num_a).insertLast(curr_instance); instance_lists_d(level_num_a).gotoFirst(); } } } // exit gracefully // return status; } // method: propagateTracesUp // // arguments: // int32 level_num: (input) the level for which we will propagate traces // // return: logical error status. if no propagations were made then return false // // propagate all traces up. only traces at the end of a subgraph are considered // bool8 HierarchicalSearch::propagateTracesUp(int32 level_num_a) { // define local variables // bool8 status = false; bool8 end_loop = false; Trace* curr_trace = (Trace*)NULL; Trace* tmp_trace = (Trace*)NULL; Trace* next_trace = (Trace*)NULL; Context* tmp_context = (Context*)NULL; GraphVertex* curr_vert = (GraphVertex*)NULL; GraphVertex* tmp_vert = (GraphVertex*)NULL; Context* symbol = (Context*)NULL; Trace* existing_trace = (Trace*)NULL; SingleLinkedList trace_list(DstrBase::USER); // make sure there is at least one trace to propagate // if (trace_lists_d(level_num_a).length() < 1) { return false; } // loop over all current traces and create the next level's traces. all new // traces will go at the end of the list so we set the mark to tell us when // to stop propagating // trace_lists_d(level_num_a).gotoLast(); trace_lists_d(level_num_a).setMark(); trace_lists_d(level_num_a).gotoFirst(); while (!end_loop) { // loop until we reached the marked element // end_loop = trace_lists_d(level_num_a).isMarkedElement(); // get the current first trace from the list // trace_lists_d(level_num_a).removeFirst(curr_trace); // if the trace is inactive then delete it and its backpath if necessary // if (!curr_trace->isActive()) { Trace::deleteTrace(curr_trace, true); } // else, extend paths and update scores // else { // get the current vertex in the search graph // curr_vert = curr_trace->getSymbol()->getCentralVertex(); // if this vertex is a terminal vertex then ascend and create the traces // at the higher level // if (curr_vert->isTerm()) { // set the status to true since we are propagating a trace // status = true; // if we are at the top level then put the trace into the valid // hypothesis list // if (level_num_a == (int32)initial_level_d) { // insert the trace into the valid hypothesis list // trace_valid_hyps_d.insertLast(curr_trace); } // else move up one level and create the next set of traces // else { // create a new trace, // next_trace = new Trace(*curr_trace); next_trace->setFrame((uint32)current_frame_d); // decrement the history of the new trace // next_trace->setHistory(history_pool_d.popAndAllocate(next_trace->getHistory(), tmp_context)); // the context must exist in the context pool in this case // next_trace->setSymbol(context_pool_d.get(*tmp_context)); // set the backpointer // next_trace->setBackPointer(curr_trace); // insert the trace into the trellis // if (search_mode_d == TRAIN) { if (!insertNewPath(curr_trace, next_trace, 0)) { return Error::handle(name(), L"propagateTracesUp", Error::ARG, __FILE__, __LINE__); } } // propagate all paths we can move to from this higher level trace // (ISIP_BUG: this will only work for monophones and triphones) // tmp_vert = next_trace->getSymbol()->getLastVertex(); if (tmp_vert->isTerm()) { // create a temporary trace // tmp_trace = new Trace(*next_trace); tmp_trace->setFrame((uint32)current_frame_d); // shift the history and set the backpointer // tmp_trace->setSymbol(context_pool_d.shiftAndAllocate(tmp_trace->getSymbol(), tmp_vert)); // set the backpointer // tmp_trace->setBackPointer(next_trace); // add the trace to the temporary list // trace_list.insertLast(tmp_trace); // print the debuging information // if (debug_level_d >= Integral::DETAILED) { printNewPath(tmp_trace, next_trace); } // insert the trace into the trellis // if (search_mode_d == TRAIN) { if (!insertNewPath(next_trace, tmp_trace, 0)) { return Error::handle(name(), L"propagateTracesUp", Error::ARG, __FILE__, __LINE__); } } } // vertex to propagate from is not terminal // else { // are we applying nsymbol probabilities at this level? // if (getSearchLevel(level_num_a - 1).useSymbolGraph() || getSearchLevel(level_num_a - 1).useNSymbol()) { // error checking // if ((symbol = next_trace->getSymbol()) == (Context*)NULL) { return Error::handle(name(), L"propagateTracesUp", Error::ARG, __FILE__, __LINE__); } SearchNode* search_node = symbol->getCentralVertex()->getItem(); // add the trace to the search node's trace list // int32 index = (int32)nsymbol_indices_d(level_num_a - 1); int32 order = getSearchLevel(level_num_a - 1).getNSymbolOrder(); existing_trace = (Trace*)NULL; if (search_node->mergeTrace(next_trace, current_frame_d, existing_trace, index, order)) { if (debug_level_d >= Integral::DETAILED) { printNewPath(next_trace, curr_trace); } if (getSearchLevel(level_num_a - 1).useSymbolGraph()) { // generate the symbol graph at this level // SymbolGraphNode* new_symbol_node = (SymbolGraphNode*)NULL; SymbolGraphNode* old_symbol_node = (SymbolGraphNode*)NULL; GraphVertex* nv = (GraphVertex*)NULL; nv = next_trace->getSymbol()->getCentralVertex(); int32 symbol_id = nv->getItem()->getSymbolId(); if (!getSearchLevel(level_num_a - 1).isDummySymbol(symbol_id) && !nv->isStart() && !nv->isTerm()) { SearchSymbol symbol_str; nv->getItem()->getSymbol(symbol_str); // transfer the old symbol graph node // old_symbol_node = curr_trace->getSymbolNode(); if (old_symbol_node == (SymbolGraphNode*)NULL) { old_symbol_node = symbol_graph_d.getStart(); old_symbol_node->setFrameIndex((int32)0); old_symbol_node->setParentGraph(&symbol_graph_d); } // when the next trace gets added to the search node // if (existing_trace == (Trace*)NULL) { new_symbol_node = symbol_graph_d.insertNode((uint32)current_frame_d, symbol_str); next_trace->setSymbolNode(new_symbol_node); if (debug_level_d >= Integral::DETAILED) { String new_str; new_symbol_node->getSymbol(new_str); String output(L"\n-> creating node: "); output.concat(new_symbol_node); output.concat(L" ["); output.concat(new_str); output.concat(L"], frame: "); output.concat(new_symbol_node->getFrameIndex()); output.concat(L", associated trace: "); output.concat(next_trace); Console::put(output); } } // when the new trace replaces the existing in the search node // else { new_symbol_node = existing_trace->getSymbolNode(); next_trace->setSymbolNode(new_symbol_node); if (debug_level_d >= Integral::DETAILED) { String new_str; new_symbol_node->getSymbol(new_str); String output(L"\n-> transferring node: "); output.concat(new_symbol_node); output.concat(L" ["); output.concat(new_str); output.concat(L"], frame: "); output.concat(new_symbol_node->getFrameIndex()); output.concat(L", from trace: "); output.concat(existing_trace); output.concat(L", to trace: "); output.concat(next_trace); Console::put(output); } } // insert the old symbol graph node into the current nodes history // float32 ac_score = curr_trace->getScore(); float32 lm_score = curr_trace->getLMScore(); int32 history_paths = getSearchLevel(level_num_a - 1).getHistoryPaths(); new_symbol_node->insertPrevNode(old_symbol_node, ac_score, history_paths, lm_score); } } // add the trace to the temporary list // trace_list.insertLast(next_trace); } // conflict in add the trace to the search nodes list // else { // print debugging information // if (debug_level_d >= Integral::DETAILED) { printDeletedPath(next_trace, curr_trace); } if (getSearchLevel(level_num_a - 1).useSymbolGraph()) { // generate the symbol graph at this level // SymbolGraphNode* new_symbol_node = (SymbolGraphNode*)NULL; SymbolGraphNode* old_symbol_node = (SymbolGraphNode*)NULL; GraphVertex* nv = (GraphVertex*)NULL; nv = next_trace->getSymbol()->getCentralVertex(); int32 symbol_id = nv->getItem()->getSymbolId(); if (!getSearchLevel(level_num_a - 1).isDummySymbol(symbol_id) && !nv->isStart() && !nv->isTerm()) { // when the new trace has a worse score that the existing trace // new_symbol_node = existing_trace->getSymbolNode(); // insert the old symbol graph node into the current nodes history // old_symbol_node = curr_trace->getSymbolNode(); float32 ac_score = curr_trace->getScore(); float32 lm_score = curr_trace->getLMScore(); int32 history_paths = getSearchLevel(level_num_a - 1).getHistoryPaths(); new_symbol_node->insertPrevNode(old_symbol_node, ac_score, history_paths, lm_score); } } // discard the new trace // delete next_trace; next_trace = (Trace*)NULL; } } // propagate the traces forward when no nsymbol probabilities // are being applied at this level // else { if (debug_level_d >= Integral::DETAILED) { printNewPath(next_trace, curr_trace); } // add the trace to the temporary list // trace_list.insertLast(next_trace); } } } // bump the current trace off of the trace list // if (curr_trace->getRefCount() < 1) { // if this is at top level, we can not delete them since they // are also referenced by the valid_hyps // if (level_num_a != (int32)initial_level_d) { Trace::deleteTrace(curr_trace, true); } } trace_lists_d(level_num_a).gotoFirst(); } // if this trace is not at the end of a subgraph then keep it on this // level // else { float32 curr_score = curr_trace->getScore(); // update the maximal trace score for the beam pruning // if(getSearchLevel(level_num_a).useBeam() && (curr_score > max_trace_scores_d(level_num_a)) ) { max_trace_scores_d(level_num_a) = curr_score; } // keep the trace on this level // trace_lists_d(level_num_a).insertLast(curr_trace); trace_lists_d(level_num_a).gotoFirst(); } } } // propagate the traces forward // while (!trace_list.isEmpty()) { // retrieve the current trace and its central vertex // (ISIP_BUG: this will only work for monophones and triphones) // trace_list.removeLast(curr_trace); curr_vert = curr_trace->getSymbol()->getLastVertex(); // when the central vertex is a terminal // if (curr_vert->isTerm()) { // insert the traces in the higher level's trace list // trace_lists_d(level_num_a - 1).insertLast(curr_trace); } else { // generate traces to all next vertices // for (bool8 more_paths = curr_vert->gotoFirst(); more_paths; more_paths = curr_vert->gotoNext()) { // create a new trace, we store the extra trace so we // can later view the scores as they are added. this can // be changed later for efficiency // next_trace = new Trace(*curr_trace); next_trace->setFrame((uint32)current_frame_d); // has the context been previously generated? // if so reuse the context, // if not generate a new context and add it to the context pool // GraphArc* tmp_arc = curr_vert->getCurr(); next_trace->setSymbol(context_pool_d.shiftAndAllocate(next_trace->getSymbol(), tmp_arc->getVertex())); // add the trace to the search node's trace list // if (!addHypothesisPath(next_trace, curr_trace, tmp_arc, level_num_a - 1)) { return Error::handle(name(), L"propagateTracesUp", Error::ARG, __FILE__, __LINE__); } } // delete curr_trace if no traces propagated from it have survived // if (curr_trace->getRefCount() < 1) { Trace::deleteTrace(curr_trace, true); } } } // exit gracefully // return status; } // method: propagateInstancesDown // // arguments: // int32 level_num: (input) the level for which we will propagate instances // // return: logical error status // // propagate all instances down the hierarchy. any instances that are at the // end of a subgraph are discarded // bool8 HierarchicalSearch::propagateInstancesDown(int32 level_num_a) { // define local variables // Instance* curr_instance = (Instance*)NULL; Instance* tmp_instance = (Instance*)NULL; GraphVertex* curr_vert = (GraphVertex*)NULL; GraphVertex* start_vertex = (GraphVertex*)NULL; SearchSymbol item; bool8 status = false; // make sure there is at least one instance to propagate // if (instance_lists_d(level_num_a).length() < 1) { return false; } // switch on whether we are at the lowest level or not // // if we are not at the lowest level, push instances down the hierarchy - // there should be no instances left at this level when we are done // instance_lists_d(level_num_a).gotoFirst(); if (level_num_a != getNumLevels() - 1) { // loop over all current instances and create the next level's instances // while (!instance_lists_d(level_num_a).isEmpty()) { // get the current vertex in the search graph // instance_lists_d(level_num_a).removeFirst(curr_instance); // delete this instance if it is now inactive // if (!curr_instance->isActive()) { // bump the current instance off of the instance list and delete it // and its backpath if necessary // Instance::deleteInstance(curr_instance, true); } // if it is active then propagate it // else { // get the current history and its central vertex // Context curr_context(*curr_instance->getSymbol()); curr_vert = curr_context.getCentralVertex(); // print debugging information // if (debug_level_d >= Integral::ALL) { curr_context.print(); } // if this vertex has a subgraph then descend and create the instances // at the next level // if (!curr_vert->isStart() && !curr_vert->isTerm()) { // we are propagating paths so set status to true // status = true; // retrieve the current and lower levels // SearchLevel& sl_curr = getSearchLevel(level_num_a); SearchLevel& sl_lower = getSearchLevel(level_num_a + 1); // determine the symbol id corresponding to the central context // int32 symbol_id = curr_context.getCentralVertex()->getItem()->getSymbolId(); // when we are in context generation mode - // if we require context for this level then we save the context // Ulong* subgr_ind = (Ulong*)NULL; Context* tmp_context = (Context*)NULL; if (context_generation_mode_d && ((int32)context_level_d == level_num_a) && !getSearchLevel(level_num_a).isContextLessSymbol(symbol_id)) { String context; curr_context.print(context); // append the context to the sdb // Ulong tmp_value; if (!context_hash_d.containsKey(context)) { context_list_d.concat(context); context_hash_d.insert(context, &tmp_value); } } // when we are in context generation mode - // determine the subgraph index for the current context // if (context_generation_mode_d && ((int32)context_level_d == level_num_a)) { Context new_context(1); GraphVertex* central_vertex = curr_context.getCentralVertex(); // initialize central vertex of the context // new_context.assignAndAdvance((uint64)central_vertex); // convert context of vertices to search symbol indices // new_context.convert(tmp_context); // get the index corresponding to the current context // subgr_ind = sl_curr.getSubGraphIndex(*tmp_context); if (subgr_ind == (Ulong*)NULL) { String context; new_context.print(context); String output(L"No subgraph found for context "); output.concat(context); output.concat(L" at level "); output.concat(level_num_a); Console::put(output); return Error::handle(name(), L"propagateInstancesDown", Error::ARG, __FILE__, __LINE__); } if (tmp_context != (Context*)NULL) { delete tmp_context; } } // when we are NOT in context generation mode - // determine the subgraph index for the current context iff // the current symbol does not have context (context-less) // else if (getSearchLevel(level_num_a).isContextLessSymbol(symbol_id) && !context_generation_mode_d) { // generate the new context // int32 left_context_length = getSearchLevel(level_num_a).getLeftContext(); int32 right_context_length = getSearchLevel(level_num_a).getRightContext(); int32 central_pos = right_context_length + 1; int32 total_context_length = left_context_length + central_pos; // error checking // if (getSearchLevel(level_num_a).getLeftContext() != getSearchLevel(level_num_a).getRightContext()) { return Error::handle(name(), L"propagateInstancesDown - left and right context lengths must be the same", Error::ARG, __FILE__, __LINE__); } // initialize the left context // Context new_context(total_context_length, central_pos); GraphVertex* central_vertex = curr_context.getCentralVertex(); DiGraph* parent_graph = central_vertex->getParentGraph(); // initialize left vertices of the context // for (int32 i = 0; i < left_context_length; i++) { new_context.assignAndAdvance((uint64)parent_graph->getStart()); } // initialize central vertex of the context // new_context.assignAndAdvance((uint64)central_vertex); // initialize right vertices of the context // for (int32 i = 0; i < right_context_length; i++) { new_context.assignAndAdvance((uint64)parent_graph->getTerm()); } // convert context of vertices to search symbol indices // new_context.convert(tmp_context); // get the index corresponding to the current context // subgr_ind = sl_curr.getSubGraphIndex(*tmp_context); if (subgr_ind == (Ulong*)NULL) { String context; new_context.print(context); String output(L"No subgraph found for context "); output.concat(context); output.concat(L" at level "); output.concat(level_num_a); Console::put(output); return Error::handle(name(), L"propagateInstancesDown", Error::ARG, __FILE__, __LINE__); } if (tmp_context != (Context*)NULL) { delete tmp_context; } } // when we are NOT in context generation mode - // determine the subgraph index for the current context // else { // convert context of vertices to search symbol indices // curr_context.convert(tmp_context); // get the index corresponding to the current context // subgr_ind = sl_curr.getSubGraphIndex(*tmp_context); if (subgr_ind == (Ulong*)NULL) { String context; curr_context.print(context); String output(L"No subgraph found for context "); output.concat(context); output.concat(L" at level "); output.concat(level_num_a); Console::put(output); return Error::handle(name(), L"propagateInstancesDown", Error::ARG, __FILE__, __LINE__); } if (tmp_context != (Context*)NULL) { delete tmp_context; } } // get the subgraph start vertex // start_vertex = (sl_lower.getSubGraph((int32)*subgr_ind)).getStart(); // when the next (lower) level has existing context we can simply // extend that context - this is necessary for cross-word // if ((curr_instance->hasNextLevelContext()) && ((level_num_a + 1) != (getNumLevels() - 1))) { // generate a instance from the current vertex to the start vertex // of its corresponding subgraph at the lower level // descend(curr_instance); tmp_instance = new Instance(*curr_instance); tmp_instance->setFrame((uint32)current_frame_d); ascend(curr_instance); // set the backpointer // tmp_instance->setBackPointer(curr_instance); // set the start vertex context // Context* start_context = context_pool_d.initAndAllocate(); start_context = context_pool_d.shiftAndAllocate(start_context, start_vertex); Context* prev_symbol = tmp_instance->getSymbol(); tmp_instance->setSymbol(start_context); // print the debuging information // if (debug_level_d >= Integral::DETAILED) { printNewPath(tmp_instance, curr_instance); } // insert the trace into the trellis // if (search_mode_d == TRAIN) { if (!insertNewPath(curr_instance, tmp_instance, 0)) { return Error::handle(name(), L"propagateTracesUp", Error::ARG, __FILE__, __LINE__); } } // extend the current context // if (!extendRightContexts(tmp_instance, level_num_a + 1, prev_symbol)) { return Error::handle(name(), L"propagateInstancesUp", Error::ARG, __FILE__, __LINE__); } } // when the next (lower) level does not have any previously generated // context we need to start fresh and generate the initial context // else { // determine the context length for the next level // int32 central_pos = getSearchLevel(level_num_a + 1).getRightContext() + 1; int32 left_context_length = getSearchLevel(level_num_a + 1).getLeftContext(); int32 total_context_length = left_context_length + central_pos; // error checking // if (getSearchLevel(level_num_a + 1).getLeftContext() != getSearchLevel(level_num_a + 1).getRightContext()) { return Error::handle(name(), L"propagateInstancesDown - left and right context lengths must be the same", Error::ARG, __FILE__, __LINE__); } // has the context been previously generated? // if so reuse the context, // if not generate a new context and add it to the context pool // Context left_context(total_context_length, central_pos); for (int32 i = 0; i < central_pos; i++) { left_context.assignAndAdvance((uint64)start_vertex); } // generate a instance from the current vertex to the start vertex // of its corresponding subgraph at the lower level // tmp_instance = new Instance(*curr_instance); tmp_instance->setFrame((uint32)current_frame_d); // set the backpointer // tmp_instance->setBackPointer(curr_instance); // set the start vertex context // Context* start_context = context_pool_d.initAndAllocate(); start_context = context_pool_d.shiftAndAllocate(start_context, start_vertex); tmp_instance->setSymbol(start_context); // print the debuging information // if (debug_level_d >= Integral::DETAILED) { printNewPath(tmp_instance, curr_instance); } // insert the trace into the trellis // if (search_mode_d == TRAIN) { if (!insertNewPath(curr_instance, tmp_instance, 0)) { return Error::handle(name(), L"propagateTracesUp", Error::ARG, __FILE__, __LINE__); } } // has the history been previously generated? // if so reuse the history, // if not generate a new history and add it to the history pool // tmp_instance->setHistory(history_pool_d.pushAndAllocate(tmp_instance->getHistory(), curr_instance->getSymbol())); // loop over all paths in the subgraph and create new // instances in the next level // Context* symbol = context_pool_d.get(left_context); for (bool8 more_paths = start_vertex->gotoFirst(); more_paths; more_paths = start_vertex->gotoNext()) { // initialize central vertex of the context // GraphArc* tmp_arc = start_vertex->getCurr(); GraphVertex* target_vertex = tmp_arc->getVertex(); Context* left_center_context = context_pool_d.shiftAndAllocate(symbol, target_vertex); // output the debugging information // if (debug_level_d >= Integral::ALL) { left_center_context->print(); } // generate list of all possible right contexts // int32 right_context_length = sl_lower.getRightContext(); if (!initializeRightContexts(tmp_instance, *left_center_context, level_num_a + 1, tmp_arc->getWeight(), right_context_length)) { return Error::handle(name(), L"propagateInstancesDown", Error::ARG, __FILE__, __LINE__); } } } // bump the current instance off of the instance list // if (tmp_instance == (Instance*)NULL) { if (curr_instance->getRefCount() < 1) { Instance::deleteInstance(curr_instance, true); } } else { if (tmp_instance->getRefCount() < 1) { Instance::deleteInstance(tmp_instance, true); } } instance_lists_d(level_num_a).gotoFirst(); } // else if there is no subgraph for this node, we extend the search // along this level. this is a special case for the sentence start // search node. usually all nodes that we can propogate down will // either have a subgraph or it will be a terminal search node. // else { bool8 more_paths = curr_vert->gotoFirst(); if (more_paths) { status = true; } // extend the current context // if (!extendRightContexts(curr_instance, level_num_a)) { return Error::handle(name(), L"propagateInstancesUp", Error::ARG, __FILE__, __LINE__); } // bump the current instance off of the instance list // if (curr_instance->getRefCount() < 1) { Instance::deleteInstance(curr_instance, true); } instance_lists_d(level_num_a).gotoFirst(); } } } } // exit gracefully // return status; } // method: propagateTracesDown // // arguments: // int32 level_num: (input) the level for which we will propagate traces // // return: logical error status. if no propagations were made then return false // // propagate all traces down. any traces that are at the end of a subgraph are // discarded. // bool8 HierarchicalSearch::propagateTracesDown(int32 level_num_a) { // define local variables // SearchSymbol item; Trace* tmp_trace = (Trace*)NULL; Trace* curr_trace = (Trace*)NULL; Trace* next_trace = (Trace*)NULL; GraphVertex* curr_vert = (GraphVertex*)NULL; GraphVertex* tmp_vert = (GraphVertex*)NULL; DoubleLinkedList score_list(DstrBase::USER); DoubleLinkedList right_context_list(DstrBase::USER); bool8 status = false; // make sure there is at least one trace to propagate // if (trace_lists_d(level_num_a).length() < 1) { return false; } // switch on whether we are at the lowest level or not // // if we are not at the lowest level, push traces down the hierarchy - // there should be no traces left at this level when we are done // trace_lists_d(level_num_a).gotoFirst(); if (level_num_a != getNumLevels() - 1) { // loop over all current traces and create the next level's traces // while (!trace_lists_d(level_num_a).isEmpty()) { // get the current vertex in the search graph // trace_lists_d(level_num_a).removeFirst(curr_trace); // delete this trace if it is now inactive // if (!curr_trace->isActive()) { // bump the current trace off of the trace list and delete it // and its backpath if necessary // Trace::deleteTrace(curr_trace, true); } // if it is active then propagate it // else { // get the current history and its central vertex // Context* curr_context = curr_trace->getSymbol(); curr_vert = curr_context->getCentralVertex(); // if this vertex has a subgraph then descend and create the traces // at the next level // int32 symbol_id = curr_vert->getItem()->getSymbolId(); if (!curr_vert->isStart() && !curr_vert->isTerm() && !getSearchLevel(level_num_a).isDummySymbol(symbol_id)) { // we are propagating paths so set status to true // status = true; // acces the subgraph's start vertex // SearchLevel& sl_curr = getSearchLevel(level_num_a); SearchLevel& sl_lower = getSearchLevel(level_num_a + 1); // convert context vertices to search symbol indices // we need to do it before hashing in getSubGraphIndex // Ulong* subgr_ind = (Ulong*)NULL; Context* tmp_context = (Context*)NULL; Context* swap_context = curr_context; Context copy_context(*curr_context); // print the original context // if (debug_level_d >= Integral::DETAILED) { // debug information // String context; curr_context->print(context); String output(L"curr_context org:"); output.concat(context); Console::put(output); } // deal with the context less symbols // if (true ){ // map all context less symbols to their central context only // int32 left_order = getSearchLevel(level_num_a).getLeftContext(); int32 right_order = getSearchLevel(level_num_a).getRightContext(); // determine the symbol id corresponding to the central context // int32 curr_id = copy_context.getCentralVertex()->getItem()->getSymbolId(); bool8 context_less = getSearchLevel(level_num_a).isContextLessSymbol(curr_id); // set the left context // int32 index2 = 0; GraphVertex* curr_vertex = NULL; // replace the left context as necessary // for (int j=0; j < left_order; j++) { curr_vertex = (GraphVertex*) (uint32)copy_context(index2); curr_id = curr_vertex->getItem()->getSymbolId(); // replace this symbol id as the no left context // if (context_less || getSearchLevel(level_num_a).isContextLessSymbol(curr_id)){ copy_context(index2).assign((uint64)curr_vertex-> getParentGraph()->getStart()); } index2++; } // never change the central symbol // index2++; // set the right context // for (int j=0; j < right_order; j++) { curr_vertex = (GraphVertex*) (uint32)copy_context(index2); curr_id = curr_vertex->getItem()->getSymbolId(); // replace this symbol id as the no left context // if (context_less || getSearchLevel(level_num_a).isContextLessSymbol(curr_id)){ copy_context(index2).assign((uint64)curr_vertex-> getParentGraph()->getTerm()); } index2++; } // set curr context // curr_context = ©_context; } if (debug_level_d >= Integral::DETAILED) { // debug information // String context; curr_context->print(context); String output(L"curr_context new:"); output.concat(context); Console::put(output); } // add for word-internal context generation // when we are in context generation mode - // if we require context for this level then we save the context // if (context_generation_mode_d && ((int32)context_level_d == level_num_a)) { String context; curr_context->print(context); // append the context to the sdb // Ulong tmp_value; if (!context_hash_d.containsKey(context)) { context_list_d.concat(context); context_hash_d.insert(context, &tmp_value); } } // when we are in context generation mode - // determine the subgraph index for the current context // if (context_generation_mode_d && ((int32)context_level_d == level_num_a)) { Context new_context(1); GraphVertex* central_vertex = curr_context->getCentralVertex(); // initialize central vertex of the context // new_context.assignAndAdvance((uint64)central_vertex); // convert context of vertices to search symbol indices // new_context.convert(tmp_context); // get the index corresponding to the current context // subgr_ind = sl_curr.getSubGraphIndex(*tmp_context); } else { curr_context->convert(tmp_context); subgr_ind = sl_curr.getSubGraphIndex(*tmp_context); } // set curr context back // curr_context = swap_context; swap_context = NULL; // check with the sub graph id // if (subgr_ind == (Ulong*)NULL) { // throw an error message and exit // String out(L"propagateTracesDown - no subgraph for context: "); curr_context->debug(L"undefined context"); curr_trace->getSymbol()->print(); Console::put(out); return Error::handle(name(), L"propagateTracesDown", Error::ARG, __FILE__, __LINE__); } if (tmp_context != (Context*)NULL) { delete tmp_context; } if (debug_level_d >= Integral::DETAILED) { // debug information // String context; curr_context->print(context); String output(L"curr_context "); output.concat(context); output.concat(L" at level "); output.concat(level_num_a); Console::put(output); subgr_ind->debug(L"subgr_ind:"); } // get the subgraph start vertex // tmp_vert = (sl_lower.getSubGraph((int32)*subgr_ind)).getStart(); // generate a trace from the current vertex to the start vertex // of its corresponding subgraph at the lower level // tmp_trace = new Trace(*curr_trace); tmp_trace->setFrame((uint32)current_frame_d); // determine the context length for the next level // int32 central_pos = getSearchLevel(level_num_a + 1).getRightContext() + 1; int32 left_context_length = getSearchLevel(level_num_a + 1).getLeftContext(); int32 total_context_length = left_context_length + central_pos; // error checking // if (getSearchLevel(level_num_a + 1).getLeftContext() != getSearchLevel(level_num_a + 1).getRightContext()) { return Error::handle(name(), L"propagateTracesDown - left and right context lengths must be the same", Error::ARG, __FILE__, __LINE__); } // has the history been previously generated? // if so reuse the history, // if not generate a new history and add it to the history pool // tmp_trace->setHistory(history_pool_d.pushAndAllocate(tmp_trace->getHistory(), curr_trace->getSymbol())); // has the context been previously generated? // if so reuse the context, // if not generate a new context and add it to the context pool // Context left_context(total_context_length, central_pos); for (int32 i = 0; i < central_pos; i++) { left_context.assignAndAdvance((uint64)tmp_vert); } // set the start vertex context // Context* start_context = context_pool_d.initAndAllocate(); start_context = context_pool_d.shiftAndAllocate(start_context, tmp_vert); tmp_trace->setSymbol(start_context); // set the backpointer // tmp_trace->setBackPointer(curr_trace); // print the debuging information // if (debug_level_d >= Integral::DETAILED) { printNewPath(tmp_trace, curr_trace); } // insert the trace into the trellis // if (search_mode_d == TRAIN) { if (!insertNewPath(curr_trace, tmp_trace, 0)) { return Error::handle(name(), L"propagateTracesUp", Error::ARG, __FILE__, __LINE__); } } // loop over all paths in the subgraph and create new traces in the // next level // Context* symbol = context_pool_d.get(left_context); for (bool8 more_paths = tmp_vert->gotoFirst(); more_paths; more_paths = tmp_vert->gotoNext()) { // initialize central vertex of the context // GraphArc* tmp_arc = tmp_vert->getCurr(); GraphVertex* target_vertex = tmp_arc->getVertex(); Context* left_center_context = context_pool_d.shiftAndAllocate(symbol, target_vertex); // output the debugging information // if (debug_level_d >= Integral::ALL) { left_center_context->print(); } // generate list of all possible right contexts // int32 depth = getSearchLevel(level_num_a + 1).getRightContext(); score_list.setAllocationMode(DstrBase::USER); right_context_list.setAllocationMode(DstrBase::USER); generateRightContexts(right_context_list, score_list, left_center_context, depth, level_num_a + 1); // output the debugging information // if (debug_level_d >= Integral::ALL) { String output(L"Generated contexts for depth"); output.concat(depth); Console::put(output); int32 num = 0; for (bool8 more_items = right_context_list.gotoFirst(); more_items; more_items = right_context_list.gotoNext()) { num++; String out(L" "); out.concat(num); out.concat(L":"); String cont; right_context_list.getCurr()->print(); out.concat(cont); Console::put(out); } } // generate a new trace for each right context // for (bool8 more_items = (right_context_list.gotoFirst() && score_list.gotoFirst()); more_items; more_items = (right_context_list.gotoNext() && score_list.gotoNext())) { // create a new trace // next_trace = new Trace(*tmp_trace); next_trace->setFrame((uint32)current_frame_d); // factor in the symbol internal transition scores // float32 posterior_score = (float32)(*score_list.getCurr()); next_trace->setScore(next_trace->getScore() + posterior_score); // has the context been previously generated? // if so reuse the context, // if not generate a new context and add it to the context pool // next_trace->setSymbol(right_context_list.getCurr()); // add the trace to the search node's trace list. // if (!addHypothesisPath(next_trace, tmp_trace, tmp_arc, level_num_a + 1)) { return Error::handle(name(), L"propagateTracesDown", Error::ARG, __FILE__, __LINE__); } } // free allocated memory // right_context_list.clear(); score_list.setAllocationMode(DstrBase::SYSTEM); score_list.clear(); } // bump the current trace off of the trace list // if (tmp_trace->getRefCount() < 1) { Trace::deleteTrace(tmp_trace, true); } trace_lists_d(level_num_a).gotoFirst(); } // else if there is no subgraph for this node, we extend the search // along this level. for now, we don't allow a level to completely // skip sub-levels so if we get to the end of the graph at this level // we simply stop // else { bool8 more_paths = curr_vert->gotoFirst(); if (more_paths) { status = true; } for ( ; more_paths; more_paths = curr_vert->gotoNext()) { // create a new trace // next_trace = new Trace(*curr_trace); next_trace->setFrame((uint32)current_frame_d); // update the history with the next node at this level // GraphArc* tmp_arc = curr_vert->getCurr(); next_trace->setSymbol(context_pool_d.shiftAndAllocate(curr_trace->getSymbol(), tmp_arc->getVertex())); // add the trace to the search node's trace list to make sure we // propagate it before exiting // if (!addHypothesisPath(next_trace, curr_trace, tmp_arc, level_num_a)) { return Error::handle(name(), L"propagateTracesDown", Error::ARG, __FILE__, __LINE__); } } // bump the current trace off of the trace list // if (curr_trace->getRefCount() < 1) { Trace::deleteTrace(curr_trace, true); } trace_lists_d(level_num_a).gotoFirst(); } } } } // exit gracefully // return status; } // method: beamPruneTrace // // arguments: // int32 level_num: (input) the level for which we will propagate traces // // return: logical error status. // bool8 HierarchicalSearch::beamPruneTrace(int32 level_num_a) { // define local variables // Trace* curr_trace = (Trace*)NULL; float32 threshold = max_trace_scores_d(level_num_a) - (*h_digraph_d)(level_num_a).getBeamThreshold(); float32 curr_score; int32 pruned_traces = 0; int32 orig_length = trace_lists_d(level_num_a).length(); // loop over all active traces at this level // bool8 more_traces = trace_lists_d(level_num_a).gotoFirst(); while (more_traces) { curr_trace = trace_lists_d(level_num_a).getCurr(); curr_score = curr_trace->getScore(); if (curr_score > max_trace_scores_d(level_num_a)) { return Error::handle(name(), L"beamPruneTrace - bad maximal score", Error::ARG, __FILE__, __LINE__); } // prune the traces with too low score // if (curr_score < threshold) { if (debug_level_d >= Integral::ALL) { String output(L"score is smaller than threshold: "); output.concat(curr_score); output.concat(L", trace:" ); output.concat(curr_trace); Console::put(output); } if (trace_lists_d(level_num_a).isLast()) { more_traces = false; } // bump the current trace off of the trace list // trace_lists_d(level_num_a).remove(); if (curr_trace->getRefCount() < 1) { Trace::deleteTrace(curr_trace, true); } pruned_traces++; } else { if (debug_level_d >= Integral::ALL) { String output(L"score is not smaller than threshold: "); output.concat(curr_score); output.concat(L", trace:" ); output.concat(curr_trace); Console::put(output); } more_traces = trace_lists_d(level_num_a).gotoNext(); } } if (debug_level_d >= Integral::DETAILED) { String output(L"frame: "); output.concat(current_frame_d); output.concat(L", level: "); output.concat(level_num_a); output.concat(L", original traces: "); output.concat(orig_length); output.concat(L", pruned traces: "); output.concat(pruned_traces); output.concat(L", current traces: "); output.concat(trace_lists_d(level_num_a).length()); output.concat(L", threshold: "); output.concat(threshold); output.concat(L", max trace score: "); output.concat(max_trace_scores_d(level_num_a)); output.concat(L"\n"); Console::put(output); } // exit gracefully // return true; } // method: beamPruneInstance // // arguments: // int32 level_num: (input) the level for which we will propagate traces // // return: logical error status. // bool8 HierarchicalSearch::beamPruneInstance(int32 level_num_a) { // define local variables // Instance* curr_instance = (Instance*)NULL; float32 threshold = max_instance_scores_d(level_num_a) - (*h_digraph_d)(level_num_a).getBeamThreshold(); float32 curr_score; int32 pruned_instances = 0; int32 orig_length = instance_lists_d(level_num_a).length(); // loop over all active instances at this level // bool8 more_instances = instance_lists_d(level_num_a).gotoFirst(); while (more_instances) { curr_instance = instance_lists_d(level_num_a).getCurr(); curr_score = curr_instance->getScore(); if (curr_score > max_instance_scores_d(level_num_a)) { return Error::handle(name(), L"beamPruneInstance - bad maximal score", Error::ARG, __FILE__, __LINE__); } // prune the instances with too low score // if (curr_score < threshold) { if (debug_level_d >= Integral::ALL) { String output(L"score is smaller than threshold: "); output.concat(curr_score); output.concat(L", instance:" ); output.concat(curr_instance); Console::put(output); } if (instance_lists_d(level_num_a).isLast()) { more_instances = false; } // bump the current instance off of the instance list // instance_lists_d(level_num_a).remove(); if (curr_instance->getRefCount() < 1) { Instance::deleteInstance(curr_instance, true); } pruned_instances++; } else { if (debug_level_d >= Integral::ALL) { String output(L"score is not smaller than threshold: "); output.concat(curr_score); output.concat(L", instance:" ); output.concat(curr_instance); Console::put(output); } more_instances = instance_lists_d(level_num_a).gotoNext(); } } if (debug_level_d >= Integral::DETAILED) { String output(L"frame: "); output.concat(current_frame_d); output.concat(L", level: "); output.concat(level_num_a); output.concat(L", original instances: "); output.concat(orig_length); output.concat(L", pruned instances: "); output.concat(pruned_instances); output.concat(L", current instances: "); output.concat(instance_lists_d(level_num_a).length()); output.concat(L", threshold: "); output.concat(threshold); output.concat(L", max instance score: "); output.concat(max_instance_scores_d(level_num_a)); output.concat(L"\n"); Console::put(output); } // exit gracefully // return true; } // method: instancePruneInstance // // arguments: // int32 level_num: (input) the level for which we will propagate traces // // return: logical error status. // bool8 HierarchicalSearch::instancePruneInstance(int32 level_num_a) { // define local variables // Instance* curr_instance = (Instance*)NULL; float32 curr_score = 0.0; int32 pruned_instances = 0; float32 instance_threshold = -0.5e10; int32 num_instances = instance_lists_d(level_num_a).length(); int32 instance_limit = (*h_digraph_d)(level_num_a).getInstanceThreshold(); if ((num_instances > instance_limit) && (instance_limit > 0)) { // sort all the instances by score in descending order // instance_lists_d(level_num_a).sort(Integral::DESCENDING, DstrBase::RAND_QUICK); // get the score at the cut-off instance // instance_lists_d(level_num_a).gotoPosition(instance_limit); curr_instance = instance_lists_d(level_num_a).getCurr(); instance_threshold = curr_instance->getScore(); } // loop over all active instances at this level // bool8 more_instances = instance_lists_d(level_num_a).gotoFirst(); while (more_instances) { curr_instance = instance_lists_d(level_num_a).getCurr(); curr_score = curr_instance->getScore(); // prune away the instance if it is below the threshold // if ((instance_threshold > 0.0) && (instance_threshold > curr_score)) { if (debug_level_d >= Integral::ALL) { String output(L"score is smaller than threshold: "); output.concat(curr_score); output.concat(L", instance:" ); output.concat(curr_instance); Console::put(output); } if (instance_lists_d(level_num_a).isLast()) { more_instances = false; } // bump the current instance off of the instance list // instance_lists_d(level_num_a).remove(); if (curr_instance->getRefCount() < 1) { Instance::deleteInstance(curr_instance, true); } pruned_instances++; } else { if (debug_level_d >= Integral::ALL) { String output(L"score is not smaller than threshold: "); output.concat(curr_score); output.concat(L", instance:" ); output.concat(curr_instance); Console::put(output); } more_instances = instance_lists_d(level_num_a).gotoNext(); } } if (debug_level_d >= Integral::DETAILED) { String output(L"frame: "); output.concat(current_frame_d); output.concat(L", level: "); output.concat(level_num_a); output.concat(L", original instances: "); output.concat(num_instances); output.concat(L", pruned instances: "); output.concat(pruned_instances); output.concat(L", current instances: "); output.concat(instance_lists_d(level_num_a).length()); output.concat(L", threshold: "); output.concat(instance_threshold); output.concat(L"\n"); Console::put(output); } // exit gracefully // return true; } // method: instancePruneTrace // // arguments: // int32 level_num: (input) the level for which we will propagate traces // // return: logical error status. // bool8 HierarchicalSearch::instancePruneTrace(int32 level_num_a) { // define local variables // Trace* curr_trace = (Trace*)NULL; float32 curr_score = 0.0; int32 pruned_traces = 0; float32 trace_threshold = -0.5e10; int32 num_traces = trace_lists_d(level_num_a).length(); int32 trace_limit = (*h_digraph_d)(level_num_a).getInstanceThreshold(); if ((num_traces > trace_limit) && (trace_limit > 0)) { // sort all the traces by score in descending order // trace_lists_d(level_num_a).sort(Integral::DESCENDING, DstrBase::RAND_QUICK); // get the score at the cut-off trace // trace_lists_d(level_num_a).gotoPosition(trace_limit); curr_trace = trace_lists_d(level_num_a).getCurr(); trace_threshold = curr_trace->getScore(); } // loop over all active traces at this level // bool8 more_traces = trace_lists_d(level_num_a).gotoFirst(); while (more_traces) { curr_trace = trace_lists_d(level_num_a).getCurr(); curr_score = curr_trace->getScore(); // prune away the trace if it is below the threshold // if ((trace_threshold > 0.0) && (trace_threshold > curr_score)) { if (debug_level_d >= Integral::ALL) { String output(L"score is smaller than threshold: "); output.concat(curr_score); output.concat(L", trace:" ); output.concat(curr_trace); Console::put(output); } if (trace_lists_d(level_num_a).isLast()) { more_traces = false; } // bump the current trace off of the trace list // trace_lists_d(level_num_a).remove(); if (curr_trace->getRefCount() < 1) { Trace::deleteTrace(curr_trace, true); } pruned_traces++; } else { if (debug_level_d >= Integral::ALL) { String output(L"score is not smaller than threshold: "); output.concat(curr_score); output.concat(L", trace:" ); output.concat(curr_trace); Console::put(output); } more_traces = trace_lists_d(level_num_a).gotoNext(); } } if (debug_level_d >= Integral::DETAILED) { String output(L"frame: "); output.concat(current_frame_d); output.concat(L", level: "); output.concat(level_num_a); output.concat(L", original traces: "); output.concat(num_traces); output.concat(L", pruned traces: "); output.concat(pruned_traces); output.concat(L", current traces: "); output.concat(trace_lists_d(level_num_a).length()); output.concat(L", threshold: "); output.concat(trace_threshold); output.concat(L"\n"); Console::put(output); } // exit gracefully // return true; }