29                                     bool input, 
bool *is_new) {
    30   typedef unordered_map<Cindex, int32, CindexHasher> map_type;
    33       std::pair<Cindex, int32>(cindex, new_index));
    34   if (p.second == 
true) {  
    44     return p.first->second;
    48   typedef unordered_map<Cindex, int32, CindexHasher> map_type;
    58                                 const std::vector<bool> &keep) {
    60   KALDI_ASSERT(keep.size() == old_num_cindex_ids - start_cindex_id);
    63   int32 count_before_renumbering = old_num_cindex_ids - start_cindex_id;
    64   std::vector<int32> old2new(count_before_renumbering, -1), new2old;
    65   new2old.reserve(old_num_cindex_ids);
    66   for (
int32 j = 0; 
j < count_before_renumbering; 
j++) {
    68       old2new[
j] = new2old.size() + start_cindex_id;
    69       new2old.push_back(j + start_cindex_id);
    74   int32 count_after_renumbering = new2old.size(),
    75       new_num_cindex_ids = start_cindex_id + count_after_renumbering;
    76   if (count_after_renumbering == count_before_renumbering) {
    82   for (
int32 old_cindex_id = start_cindex_id;
    83        old_cindex_id < old_num_cindex_ids; old_cindex_id++) {
    84     int32 new_cindex_id = old2new[old_cindex_id - start_cindex_id];
    86     if (new_cindex_id == -1) {
    88     } 
else if (new_cindex_id != old_cindex_id) {
    93   std::vector<int32> temp;
    94   for (
int32 c = start_cindex_id; c < new_num_cindex_ids; c++) {
    95     int32 d = new2old[c - start_cindex_id];
   101     const std::vector<int32> &src_dependencies =
   103     std::vector<int32>::const_iterator
   104         iter = src_dependencies.begin(), end = src_dependencies.end();
   106     for (; iter != end; ++iter) {
   107       int32 old_dep = *iter;
   108       if (old_dep < start_cindex_id) {
   111         int32 new_dep = old2new[old_dep - start_cindex_id];
   115           KALDI_ERR << 
"Dependency on nonexistent cindex-id";
   120   cindexes.resize(new_num_cindex_ids);
   121   is_input.resize(new_num_cindex_ids);
   126                                             int32 cindex_id)
 const {
   127   KALDI_ASSERT(static_cast<size_t>(cindex_id) < graph_->cindexes.size());
   128   const Cindex &cindex = graph_->cindexes[cindex_id];
   129   const std::string &node_name = nnet_.GetNodeName(cindex.first);
   130   os << node_name << 
'(' << cindex.second.n << 
", " << cindex.second.t
   131      << 
", " << cindex.second.x << 
')';
   135     int32 first_cindex_id)
 const {
   136   int32 max_lines_print = 100;
   137   std::deque<int32> cindexes_to_explain;
   138   std::vector<bool> added_to_queue(graph_->cindexes.size(), 
false);
   139   cindexes_to_explain.push_back(first_cindex_id);
   140   added_to_queue[first_cindex_id] = 
true;
   141   KALDI_ASSERT(graph_->cindexes.size() == graph_->dependencies.size());
   142   std::ostringstream os;
   144   PrintCindexId(os, first_cindex_id);
   145   os << 
" is not computable for the following reason: ***\n";
   146   for (
int32 num_lines_printed = 0;
   147        num_lines_printed < max_lines_print && !cindexes_to_explain.empty();
   148        num_lines_printed++) {
   149     int32 cindex_id = cindexes_to_explain.front();
   150     cindexes_to_explain.pop_front();
   151     KALDI_ASSERT(static_cast<size_t>(cindex_id) < graph_->cindexes.size());
   152     PrintCindexId(os, cindex_id);
   153     os << 
" is " << cindex_info_[cindex_id].computable << 
", dependencies: ";
   154     const std::vector<int32> 
dependencies = graph_->dependencies[cindex_id];
   155     std::vector<int32>::const_iterator iter = dependencies.begin(),
   156         end = dependencies.end();
   157     for (; iter != end; iter++) {
   158       int32 dep_cindex_id = *iter;
   159       PrintCindexId(os, dep_cindex_id);
   160       const CindexInfo &dep_info = cindex_info_[dep_cindex_id];
   162       if (dep_info.
computable != kComputable && !added_to_queue[dep_cindex_id]) {
   163         added_to_queue[dep_cindex_id] = 
true;
   164         cindexes_to_explain.push_back(dep_cindex_id);
   177                              const std::vector<std::string> &node_names) {
   178   int32 max_cindexes_per_line = 50, max_dependencies = 5,
   181   std::vector<std::pair<Cindex, std::vector<Cindex> > > pairs;
   182   pairs.reserve(num_cindexes);
   183   for (
int32 cindex_id = 0; cindex_id < num_cindexes; cindex_id++) {
   185     std::vector<Cindex> deps(size);
   186     for (
size_t i = 0; 
i < size; 
i++)
   188     std::sort(deps.begin(), deps.end());
   189     pairs.push_back(std::pair<
Cindex, std::vector<Cindex> >(
cindexes[cindex_id],
   192   std::sort(pairs.begin(), pairs.end());
   194   for (
int32 i = 0; 
i < num_cindexes; 
i++) {
   195     if (pairs[
i].first.first != pairs[cur_start].first.first) {
   199     if (
i - cur_start < max_cindexes_per_line) {
   206         for (
int32 j = 0; 
j < pairs[
i].second.size(); 
j++) {
   207           if (
j < max_dependencies) {
   209             if (j + 1 < pairs[
i].second.size())
   211           } 
else if (
j == max_dependencies) {
   217     } 
else if (
i - cur_start == max_cindexes_per_line) {
   231                         cindex_id == cindex_info_.size());
   232   depend_on_this_.push_back(std::vector<int32>());
   256   for (
int32 i = 0; 
i < request_->inputs.size(); 
i++) {
   257     int32 n = nnet_.GetNodeIndex(request_->inputs[
i].name);
   259       KALDI_ERR << 
"Network has no input with name "   260                 << request_->inputs[
i].name;
   261     NodeType t = nnet_.GetNode(n).node_type;
   263                  "Inputs to graph only allowed for Input and Component nodes.");
   265     for (
int32 j = 0; 
j < request_->inputs[
i].indexes.size(); 
j++) {
   266       Cindex cindex(n, request_->inputs[
i].indexes[
j]);
   268       int32 cindex_id = graph_->GetCindexId(cindex, is_input, &is_new);
   269       KALDI_ASSERT(is_new && 
"Input index seems to be listed more than once");
   270       AddCindexId(cindex_id);
   271       cindex_info_.back().computable = kComputable;
   275   KALDI_ASSERT(num_added > 0 && 
"AddInputToGraph: nothing to add.");
   280   for (
int32 i = 0; 
i < request_->outputs.size(); 
i++) {
   281     int32 n = nnet_.GetNodeIndex(request_->outputs[
i].name);
   283       KALDI_ERR << 
"Network has no output with name "   284                 << request_->outputs[
i].name;
   285     for (
int32 j = 0; 
j < request_->outputs[
i].indexes.size(); 
j++) {
   286       Cindex cindex(n, request_->outputs[
i].indexes[
j]);
   288       int32 cindex_id = graph_->GetCindexId(cindex, is_input, &is_new);
   289       KALDI_ASSERT(is_new && 
"Output index seems to be listed more than once");
   290       AddCindexId(cindex_id);
   291       cindex_info_.back().usable_count = 1;
   292       cindex_info_.back().queued = 
true;
   293       next_queue_.push_back(cindex_id);
   297   if (num_added == 0) {
   298     KALDI_ERR << 
"Cannot process computation request with no outputs";
   300   current_distance_ = 0;
   302   current_queue_.swap(next_queue_);
   306   auto iter = cindex_info_.begin(),
   307       end = cindex_info_.end();
   308   for (
int32 cindex_id = 0; iter != end; ++iter, ++cindex_id) {
   309     if (iter->computable != kComputable) {
   310       int32 network_node = graph_->cindexes[cindex_id].first;
   311       if (nnet_.IsOutputNode(network_node))
   327     default: os << 
"[invalid enum value]"; 
break;
   335   std::vector<int32> outputs_not_computable;
   336   int32 num_outputs_total = 0;
   338   std::vector<Cindex>::const_iterator iter = graph_->cindexes.begin(),
   339       end = graph_->cindexes.end();
   340   for (
int32 cindex_id = 0; iter != end; ++iter,++cindex_id) {
   341     int32 network_node = iter->first;
   342     if (nnet_.IsOutputNode(network_node)) {
   344       if (cindex_info_[cindex_id].computable != kComputable)
   345         outputs_not_computable.push_back(cindex_id);
   349                "You called this function when everything was computable.");
   350   int32 num_print = 10, num_not_computable = outputs_not_computable.size();
   351   KALDI_LOG << num_not_computable << 
" output cindexes out of "   352             << num_outputs_total << 
" were not computable.";
   353   std::ostringstream os;
   355   KALDI_LOG << 
"Computation request was: " << os.str();
   356   if (num_not_computable > num_print)
   357     KALDI_LOG << 
"Printing the reasons for " << num_print << 
" of these.";
   358   for (
int32 i = 0; 
i < num_not_computable && 
i < num_print; 
i++)
   359     ExplainWhyNotComputable(outputs_not_computable[
i]);
   368   const CindexInfo &info = cindex_info_[cindex_id];
   375     graph_->dependencies[cindex_id].clear();
   379   const Cindex &cindex = graph_->cindexes[cindex_id];
   380   int32 node_id = cindex.first;
   381   const Index &index = cindex.second;
   384   std::vector<int32> &
dependencies = graph_->dependencies[cindex_id];
   385   std::sort(dependencies.begin(), dependencies.end());
   386   std::vector<int32> used_cindex_ids;
   391       bool dont_care = 
false;  
   392       CindexSet cindex_set(*graph_, cindex_info_, dont_care);
   393       std::vector<Cindex> used_cindexes;
   394       bool ans = desc.
IsComputable(index, cindex_set, &used_cindexes);
   399       size_t size = used_cindexes.size();
   400       used_cindex_ids.resize(size);
   401       for (
size_t i = 0; 
i < size; 
i++) {
   402         int32 dep_cindex_id = graph_->GetCindexId(used_cindexes[
i]);
   404         used_cindex_ids[
i] = dep_cindex_id;
   413       bool dont_care = 
false;  
   417       IndexSet index_set(*graph_, cindex_info_, node_id - 1, dont_care);
   418       std::vector<Index> used_indexes;
   419       bool ans = c->
IsComputable(request_->misc_info, index, index_set,
   425       size_t size = used_indexes.size();
   426       used_cindex_ids.resize(size);
   427       for (
size_t i = 0; 
i < size; 
i++) {
   428         Cindex dep_cindex(node_id - 1, used_indexes[
i]);
   429         int32 dep_cindex_id = graph_->GetCindexId(dep_cindex);
   431         used_cindex_ids[
i] = dep_cindex_id;
   453   dependencies.swap(used_cindex_ids);
   459     nnet_(nnet), request_(NULL), graph_(graph),
   460     current_distance_(-1) {
   462                "ComputationGraphBuilder initialized with nonempty graph.");
   469     KALDI_ERR << 
"You are calling things in the wrong order: should be "   470               << 
"Compute(), Prune(), Compute, Prune(), ...";
   477   int32 max_distance = 10000;
   482       Check(cur_segment_start);
   488     KALDI_ERR << 
"Loop detected while building computation graph (bad "   489               << 
"network topology?)";
   492     Check(cur_segment_start);
   498   for (
int32 cindex_id = start_cindex_id; cindex_id < num_cindex_ids;
   499        cindex_id += 1 + 
RandInt(0, num_cindex_ids / 100)) {
   502       int32 size = depend_on_this.size();
   503       std::sort(depend_on_this.begin(), depend_on_this.end());
   505       for (
size_t j = 0; 
j < size; 
j++) {
   506         int32 other_cindex_id = depend_on_this[
j];
   515       int32 size = dependencies.size();
   516       std::sort(dependencies.begin(), dependencies.end());
   518       for (
size_t j = 0; 
j < size; 
j++) {
   519         int32 dep_cindex_id = dependencies[
j];
   520         if (dep_cindex_id >= start_cindex_id) {
   534       int32 size = depend_on_this.size();
   535       for (
size_t j = 0; 
j < size; 
j++) {
   536         int32 other_cindex_id = depend_on_this[
j];
   539           usable_count_recomputed++;
   550         KALDI_ERR << 
"Mismatch in computable status";
   555     if (
RandInt(0, cindex_id) == 0) {
   579   for (
int32 cindex_id = start_cindex_id;
   580        cindex_id < num_cindex_ids; cindex_id++)
   586   std::vector<bool> required;
   589   std::vector<bool> keep(num_cindex_ids - start_cindex_id, 
false);
   590   for (
int32 c = start_cindex_id; c < num_cindex_ids; c++) {
   593                    "You are calling Prune when not everything is computable.");
   594       keep[c - start_cindex_id] = 
true;
   612   for (
int32 i = start_cindex_id; 
i < new_num_cindex_ids; 
i++) {
   633   int32 node_index = cindex.first;
   634   const Index &index = cindex.second;
   637   std::vector<Cindex> input_cindexes;
   650       std::vector<Index> input_indexes;
   653       input_cindexes.resize(input_indexes.size());
   654       for (
size_t i = 0; 
i < input_indexes.size(); 
i++) {
   655         input_cindexes[
i].first = node_index  - 1;  
   656         input_cindexes[
i].second = input_indexes[
i];
   661       input_cindexes.resize(1);
   671   int32 num_dependencies = input_cindexes.size();
   683   this_dep.resize(num_dependencies);
   684   for (
size_t i = 0; 
i < num_dependencies; 
i++) {
   685     bool is_input = 
false, is_new;
   688     this_dep[
i] = dep_cindex_id;
   699   std::vector<int32>::const_iterator iter = this_dep.begin(),
   700       end = this_dep.end();
   711   for (; iter != end; ++iter) {
   712     int32 dep_cindex_id = *iter;
   723   int32 node_id = cindex.first;
   724   const Index &index = cindex.second;
   749       const int32 input_node_id = node_id - 1;
   770       if (input_cindex_id != -1)
   788     std::vector<std::vector<bool> > *computable)
 const {
   790                "You need to call this after Compute()!");
   792                "You need to call this before Prune()!");
   800     std::vector<bool> &this_vec = (*computable)[
i];
   801     this_vec.resize(size);
   802     for (
size_t j = 0; 
j < size; 
j++) {
   832     std::vector<int32>::const_iterator iter = 
depend_on_this_[cindex_id].begin(),
   834     for (; iter != end; ++iter) {
   835       int32 other_cindex_id = *iter;
   847       std::vector<int32>::const_iterator
   850       for (; iter != end; ++iter) {
   851         int32 dep_cindex_id = *iter;
   863     std::vector<int32>::const_iterator
   866     for (; iter != end; ++iter) {
   867       int32 dep_cindex_id = *iter;
   885     std::vector<int32>::const_iterator
   888     for (; iter != end; ++iter) {
   889       int32 dep_cindex_id = *iter;
   919     int32 start_cindex_id,
   920     std::vector<bool> *required)
 const {
   926   required->resize(num_cindex_ids - start_cindex_id, 
false);
   933   std::vector<int32> queue;
   934   for (
int32 c = start_cindex_id; c < num_cindex_ids; c++) {
   937     if (is_output_node[node_id]) {
   938       (*required)[c - start_cindex_id] = 
true;
   942   while (!queue.empty()) {
   943     int32 c = queue.back();
   946     std::vector<int32>::const_iterator iter = dependencies.begin(),
   947         end = dependencies.end();
   948     for (; iter != end; ++iter) {
   950       if (d >= start_cindex_id && !(*required)[d - start_cindex_id]){
   951         (*required)[d - start_cindex_id] = 
true;
   958   for (
int32 c = start_cindex_id; c < num_cindex_ids; c++)
   966 namespace computation_graph {
   978       KALDI_ERR << 
"Network has no output with name "   982       bool is_input = 
false, is_new;
   984       KALDI_ASSERT(is_new && 
"Output index seems to be listed more than once");
   988   KALDI_ASSERT(num_added > 0 && 
"AddOutputToGraph: nothing to add.");
  1001       KALDI_ERR << 
"Network has no input with name "  1005                  "Inputs to graph only allowed for Input and Component nodes.");
  1009       bool is_input = 
true, is_new;
  1011       KALDI_ASSERT(is_new && 
"Input index seems to be listed more than once");
  1015   KALDI_ASSERT(num_added > 0 && 
"AddInputToGraph: nothing to add.");
  1030     const std::vector<int32> &cindex_id_to_segment_and_epoch,
  1031     std::vector<std::vector<int32> > *dependencies_subset) {
  1033   KALDI_ASSERT(cindex_id_to_segment_and_epoch.size() == num_cindex_ids);
  1034   dependencies_subset->resize(num_cindex_ids);
  1035   for (
int32 cindex_id = 0; cindex_id < num_cindex_ids; cindex_id++) {
  1036     int32 phase_index = cindex_id_to_segment_and_epoch[cindex_id];
  1037     const std::vector<int32> &dependencies = graph.
dependencies[cindex_id];
  1038     std::vector<int32> &dep_subset = (*dependencies_subset)[cindex_id];
  1039     int32 num_dep = dependencies.size();
  1040     for (
int32 i = 0; 
i < num_dep; 
i++) {
  1042       if (cindex_id_to_segment_and_epoch[d] == phase_index)
  1043         dep_subset.push_back(d);
  1085     std::vector<int32> *cindex_id_to_segment_and_epoch,
  1086     std::vector<std::vector<std::vector<int32 > > > *epochs_per_segment,
  1087     std::vector<bool> *epoch_is_trivial) {
  1092   std::vector<int32> node_to_epoch;
  1095     std::ostringstream os;
  1097     KALDI_VLOG(6) << 
"node_to_epoch: " << os.str();
  1103   for (
int32 i = 0; 
i < node_to_epoch.size(); 
i++)
  1106       num_cindex_ids = graph.
cindexes.size(),
  1108       num_epoch_indexes = 1 + *std::max_element(node_to_epoch.begin(),
  1109                                                 node_to_epoch.end());
  1112   epochs_per_segment->clear();
  1113   epochs_per_segment->resize(num_segments);
  1118   std::vector<int32> epoch_to_num_nodes(num_epoch_indexes, 0);
  1119   for (
int32 n = 0; 
n < num_nodes; 
n++)
  1120     epoch_to_num_nodes[node_to_epoch[
n]]++;
  1122   epoch_is_trivial->resize(num_epoch_indexes);
  1123   for (
int32 o = 0; o < num_epoch_indexes; o++) {
  1125     (*epoch_is_trivial)[o] = (epoch_to_num_nodes[o] <= 1);
  1127   cindex_id_to_segment_and_epoch->resize(num_cindex_ids);
  1129   int32 cur_segment_start = 0, cur_segment_end;
  1130   for (
int32 segment = 0; segment < num_segments; segment++) {
  1132     std::vector<std::vector<int32> > &epochs = (*epochs_per_segment)[segment];
  1133     epochs.resize(num_epoch_indexes);
  1135     for (
int32 cindex_id = cur_segment_start;
  1136          cindex_id < cur_segment_end; cindex_id++) {
  1138           epoch_index = (graph.
is_input[cindex_id] ? 0 :
  1139                          node_to_epoch[node_index]);
  1140       (*cindex_id_to_segment_and_epoch)[cindex_id] =
  1141           epoch_index + segment * num_epoch_indexes;
  1142       epochs[epoch_index].push_back(cindex_id);
  1144     cur_segment_start = cur_segment_end;
  1155   using namespace computation_graph;
  1163   std::vector<int32> queue(graph->
cindexes.size());
  1167   while (!queue.empty()) {
  1168     int32 cindex_id = queue.back();
  1170     if (static_cast<int32>(graph->
dependencies.size()) <= cindex_id)
  1179     const Index &index = cindex.second;
  1182     std::vector<Cindex> input_cindexes;
  1195         std::vector<Index> input_indexes;
  1203         input_cindexes.resize(input_indexes.size());
  1204         for (
size_t i = 0; 
i < input_indexes.size(); 
i++) {
  1205           input_cindexes[
i].first = n - 1;  
  1206           input_cindexes[
i].second = input_indexes[
i];
  1211         input_cindexes.resize(1);
  1219     std::vector<int32> &this_dep = graph->
dependencies[cindex_id];
  1221     int32 num_dependencies = input_cindexes.size();
  1222     this_dep.resize(num_dependencies);
  1223     for (
size_t i = 0; 
i < num_dependencies; 
i++) {
  1224       bool is_input = 
false, is_new;
  1227       this_dep[
i] = dep_cindex_id;
  1229         queue.push_back(dep_cindex_id);
  1240   std::vector<std::vector<int32> >::const_iterator iter = vec.begin(),
  1242   for (; iter != end; ++iter)
  1243     ans += iter->size();
  1249   for (
size_t i = 0; 
i < vec.size(); 
i++)
  1310     const std::vector<int32> &this_epoch,
  1311     const std::vector<std::vector<int32> > &dependencies_subset,
  1312     const std::vector<std::vector<int32> > &depend_on_subset,
  1313     bool epoch_is_trivial,
  1314     std::vector<int32> *phase_indexes,
  1315     std::vector<std::vector<int32> > *phases) {
  1316   std::vector<int32> this_phase, next_phase_candidates;
  1318   if (this_epoch.empty())
  1321   if (epoch_is_trivial) { 
  1322     this_phase = this_epoch;
  1327     std::vector<int32>::const_iterator iter = this_epoch.begin(),
  1328         end = this_epoch.end();
  1329     for (; iter != end; ++iter) {
  1330       int32 cindex_id = *iter;
  1331       if (dependencies_subset[cindex_id].empty())
  1332         this_phase.push_back(cindex_id);
  1338                "Trying to process computation with cycles");
  1340   while (!this_phase.empty()) {
  1343     phases->resize(phases->size() + 1);
  1344     phases->back().swap(this_phase);
  1351     if (epoch_is_trivial)
  1354     int32 cur_phase_index = phases->size() - 1;
  1359     next_phase_candidates.clear();
  1360     std::vector<int32>::const_iterator this_phase_iter = phases->back().begin(),
  1361         this_phase_end = phases->back().end();
  1363     for (; this_phase_iter != this_phase_end; ++this_phase_iter) {
  1364       int32 c = *this_phase_iter;  
  1365       (*phase_indexes)[c] = cur_phase_index;
  1366       std::vector<int32>::const_iterator iter = depend_on_subset[c].begin(),
  1367           end = depend_on_subset[c].end();
  1368       for (; iter != end; ++iter) {
  1370         next_phase_candidates.push_back(d);
  1376     this_phase.reserve(next_phase_candidates.size());
  1379     std::vector<int32>::const_iterator iter = next_phase_candidates.begin(),
  1380         end = next_phase_candidates.end();
  1381     for (; iter != end; ++iter) {
  1383       std::vector<int32>::const_iterator
  1384           dep_iter = dependencies_subset[c].begin(),
  1385           dep_end = dependencies_subset[c].end();
  1386       for (; dep_iter != dep_end; ++dep_iter) {
  1388         if ((*phase_indexes)[d] < 0)  
  1391       if (dep_iter == dep_end) {
  1393         this_phase.push_back(c);
  1396     if (!next_phase_candidates.empty() && this_phase.empty())  {
  1399       KALDI_ERR << 
"Your model has a type of recurrence that cannot be computed. "  1400                 << 
"E.g. if x[t] depends on both x[t+1] and x[t-1]... no order "  1401                 << 
"of computation will work.";
  1409     std::vector<std::vector<std::vector<int32> > > *phases_per_segment) {
  1410   using namespace computation_graph;
  1413   std::vector<int32> cindex_id_to_segment_and_epoch;
  1414   std::vector<std::vector<std::vector<int32 > > > epochs_per_segment;
  1415   std::vector<bool> epoch_is_trivial;
  1417                    &epochs_per_segment, &epoch_is_trivial);
  1426   std::vector<std::vector<int32> > dependencies_subset;
  1428                             &dependencies_subset);
  1430   { std::vector<int32> temp; temp.swap(cindex_id_to_segment_and_epoch);  }
  1435   std::vector<std::vector<int32> > depend_on_subset;
  1438   int32 num_epoch_indexes = epoch_is_trivial.size(),
  1442   std::vector<int32> phase_indexes(num_cindex_ids, -1);
  1444   phases_per_segment->clear();
  1445   phases_per_segment->resize(num_segments);
  1447   for (
int32 segment = 0; segment < num_segments; segment++) {
  1448     phases_per_segment->reserve(50);  
  1450     for (
int32 epoch = 0; epoch < num_epoch_indexes; epoch++)
  1452                                        epochs_per_segment[segment][epoch],
  1453                                        dependencies_subset,
  1455                                        epoch_is_trivial[epoch],
  1457                                        &((*phases_per_segment)[segment]));
  1467     graph_(graph), info_(NULL) { }
  1470                      const std::vector<ComputationGraphBuilder::CindexInfo> &info,
  1471                      bool treat_unknown_as_computable):
  1478   if (cindex_id == -1) {
  1481     if (
info_ == NULL) {
  1485           c = (*info_)[cindex_id].computable;
  1494                    const std::vector<ComputationGraphBuilder::CindexInfo> &info,
  1496                    bool treat_unknown_as_computable):
  1502   if (cindex_id == -1) {
  1518     std::vector<std::vector<int32> > *steps,
  1519     std::vector<std::pair<int32, int32> > *locations):
  1520     nnet_(nnet), 
graph_(graph), steps_(steps), locations_(locations) {
  1526   locations_->reserve(num_cindexes + num_cindexes / 10);
  1527   locations_->resize(num_cindexes, std::pair<int32,int32>(-1, -1));
  1532     const std::vector<std::vector<int32> > &phases) {
  1533   int32 this_num_phases = phases.size();
  1534   for (
int32 i = 0; 
i < this_num_phases; 
i++) {
  1535     std::vector<std::vector<Cindex> > sub_phases;
  1537     for (
size_t j = 0; 
j < sub_phases.size(); 
j++) {
  1546     const std::vector<Cindex> &sub_phase) {
  1547   int32 io_node = sub_phase[0].first;
  1554   const std::vector<IoSpecification> &inputs_or_outputs =
  1556   int32 io_index = -1;
  1557   for (
size_t i = 0; 
i < inputs_or_outputs.size(); 
i++)
  1558     if (inputs_or_outputs[
i].name == node_name)
  1561   const std::vector<Index> &io_indexes = inputs_or_outputs[io_index].indexes;
  1562   std::vector<Cindex> io_cindexes(io_indexes.size());
  1563   for (
size_t i = 0, size = io_cindexes.size(); 
i < size; 
i++) {
  1564     io_cindexes[
i].first = io_node;
  1565     io_cindexes[
i].second = io_indexes[
i];
  1576   for (
size_t i = 0; 
i < sub_phase.size(); 
i += 10) {
  1577     const Cindex &cindex = sub_phase[
i];
  1584                                         bool add_if_absent) {
  1592   steps_->push_back(std::vector<int32>());
  1593   std::vector<int32> &step = 
steps_->back();  
  1594   step.resize(cindexes.size());
  1595   size_t row_index = 0;
  1596   std::vector<Cindex>::const_iterator iter = cindexes.begin(),
  1597       end = cindexes.end();
  1598   std::vector<int32>::iterator out_iter = step.begin();
  1599   std::pair<int32, int32> *locations = &((*locations_)[0]);
  1600   if (!add_if_absent) {
  1604     for (; iter != end; ++iter, ++out_iter, ++row_index) {
  1606       *out_iter = cindex_id;
  1607       locations[cindex_id].first = step_index;
  1608       locations[cindex_id].second = row_index;
  1611     for (; iter != end; ++iter, ++out_iter, ++row_index) {
  1612       bool is_input = 
false;  
  1619       *out_iter = cindex_id;
  1622         locations_->resize(cindex_id + 1, std::pair<int32, int32>(-1, -1));
  1625         locations = &((*locations_)[0]);  
  1627         locations[cindex_id].first = step_index;
  1628         locations[cindex_id].second = row_index;
  1638   steps_->push_back(std::vector<int32>());
  1639   steps_->back().swap(*cindex_ids);
  1640   std::vector<int32>::const_iterator iter = 
steps_->back().begin(),
  1641       end = 
steps_->back().end();
  1642   int32 row_index = 0;
  1643   std::pair<int32,int32> *locations = &((*locations_)[0]);
  1645   for (; iter != end; ++iter, ++row_index) {
  1646     int32 cindex_id = *iter;
  1647     KALDI_ASSERT(static_cast<size_t>(cindex_id) < num_cindexes);
  1648     locations[cindex_id].first = step_index;
  1649     locations[cindex_id].second = row_index;
  1656     const std::vector<int32> &cindex_ids,
  1657     std::vector<Cindex> *cindexes)
 const {
  1658   cindexes->resize(cindex_ids.size());
  1660   std::vector<int32>::const_iterator iter = cindex_ids.begin(),
  1661       end = cindex_ids.end();
  1662   std::vector<Cindex>::iterator out_iter = cindexes->begin();
  1663   for (; iter != end; ++iter, ++out_iter) {
  1664     int32 cindex_id = *iter;
  1665     KALDI_ASSERT(static_cast<size_t>(cindex_id) < num_cindexes);
  1672     const std::vector<Cindex> &cindexes,
  1673     std::vector<int32> *cindex_ids)
 const {
  1674   cindex_ids->resize(cindexes.size());
  1675   std::vector<Cindex>::const_iterator iter = cindexes.begin(),
  1676       end = cindexes.end();
  1677   std::vector<int32>::iterator out_iter = cindex_ids->begin();
  1678   for (; iter != end; ++iter, ++out_iter) {
  1681     *out_iter = cindex_id;
  1688     const std::vector<Cindex> &cindexes,
  1689     std::vector<Index> *indexes) {
  1690   indexes->resize(cindexes.size());
  1691   std::vector<Cindex>::const_iterator iter = cindexes.begin(),
  1692       end = cindexes.end();
  1693   std::vector<Index>::iterator out_iter = indexes->begin();
  1694   for (; iter != end; ++iter, ++out_iter)
  1695     *out_iter = iter->second;
  1700     const std::vector<Index> &indexes,
  1702     std::vector<Cindex> *cindexes) {
  1704   cindexes->resize(indexes.size());
  1705   std::vector<Index>::const_iterator iter = indexes.begin(),
  1706       end = indexes.end();
  1707   std::vector<Cindex>::iterator out_iter = cindexes->begin();
  1708   for (; iter != end; ++iter, ++out_iter) {
  1709     out_iter->first = node_index;
  1710     out_iter->second = *iter;
  1718     const std::vector<Cindex> &step) {
  1720   int32 component_node_index = step.front().first;
  1721   int32 component_input_index = component_node_index - 1;
  1730     std::vector<Cindex> input_step(step.size());
  1731     input_step.resize(step.size());
  1732     std::vector<Cindex>::iterator iter = input_step.begin(),
  1733         end = input_step.end();
  1734     std::vector<Cindex>::const_iterator src = step.begin();
  1735     for (; iter != end; ++iter,++src) {
  1736       iter->first = component_input_index;
  1737       iter->second = src->second;
  1742     std::vector<int32> step_cindex_ids;
  1745     unordered_set<int32> input_cindex_ids;
  1746     std::vector<int32>::iterator iter = step_cindex_ids.begin(),
  1747         end = step_cindex_ids.end();
  1748     for (; iter != end; ++iter) {
  1751       std::vector<int32>::const_iterator dep_iter = dependencies.begin(),
  1752           dep_end = dependencies.end();
  1753       for (; dep_iter != dep_end; ++dep_iter) {
  1755         input_cindex_ids.insert(d);
  1759     std::vector<Cindex> input_step;
  1760     input_step.reserve(input_cindex_ids.size());
  1761     unordered_set<int32>::iterator set_iter = input_cindex_ids.begin(),
  1762         set_end = input_cindex_ids.end();
  1763     for (; set_iter != set_end; ++set_iter) {
  1764       int32 c = *set_iter;
  1769     std::sort(input_step.begin(), input_step.end());
  1772       std::vector<Index> indexes, input_indexes;
  1777       size_t orig_size = indexes.size() + input_indexes.size();
  1783       bool added_padding = (orig_size != indexes.size() + input_indexes.size());
  1787       std::vector<Cindex> reordered_step;
  1792       AddStep(input_step, added_padding);
  1793       AddStep(reordered_step, added_padding);
  1807     const std::vector<int32> &cindex_ids,
  1808     std::vector<std::pair<int32, int32> > *locations)
 const {
  1809   locations->resize(cindex_ids.size());
  1810   std::vector<int32>::const_iterator iter = cindex_ids.begin(),
  1811       end = cindex_ids.end();
  1812   std::vector<std::pair<int32, int32> >::iterator out_iter =
  1815   std::pair<int32, int32> *locations_ptr = &((*locations_)[0]);
  1817   for (; iter != end; ++iter, ++out_iter) {
  1818     int32 cindex_id = *iter;
  1819     KALDI_ASSERT(static_cast<size_t>(cindex_id) < num_cindexes);
  1820     int32 step = locations_ptr[cindex_id].first,
  1821         row = locations_ptr[cindex_id].second;
  1823     out_iter->first = step;
  1824     out_iter->second = row;
  1829     const std::vector<Cindex> &sub_phase) {
  1830   int32 dim_range_node = sub_phase[0].first;
  1838   std::vector<Cindex> input_cindexes(sub_phase);
  1839   for (std::vector<Cindex>::iterator iter = input_cindexes.begin(),
  1840            end = input_cindexes.end(); iter != end; ++iter)
  1841     iter->first = input_node_index;
  1842   std::vector<int32> input_cindex_ids;
  1844   std::vector<std::pair<int32, int32> > locations;
  1849   std::unordered_set<int32> source_step_indexes;
  1851   std::vector<std::pair<int32, int32> >::const_iterator
  1852       locations_iter = locations.begin(),
  1853       locations_end = locations.end();
  1857   int32 cur_source_step_index = -1;
  1858   for (; locations_iter != locations_end; ++locations_iter) {
  1859     int32 source_step_index = locations_iter->first;
  1860     if (source_step_index != cur_source_step_index) {
  1861       cur_source_step_index = source_step_index;
  1862       source_step_indexes.insert(cur_source_step_index);
  1866   std::unordered_set<int32>::const_iterator
  1867       source_step_iter = source_step_indexes.begin(),
  1868       source_step_end = source_step_indexes.end();
  1870   for (; source_step_iter != source_step_end; ++source_step_iter) {
  1871     int32 source_step_index = *source_step_iter;
  1872     std::pair<int32, int32> p(source_step_index, dim_range_node);
  1879     const std::vector<int32> &source_step = (*steps_)[source_step_index];
  1881     std::vector<Cindex> cindexes;
  1883     std::vector<Cindex>::iterator iter = cindexes.begin(),
  1884         end = cindexes.end();
  1885     for (; iter != end; ++iter)
  1886       iter->first = dim_range_node;
  1887     bool add_if_absent = 
true;
  1892     AddStep(cindexes, add_if_absent);
  1898     const std::vector<Cindex> &sub_phase) {
  1900   int32 node_index = sub_phase[0].first;
  1925   for (
int32 c = 0; c < num_cindexes; c++) {
  1926     int32 step = (*locations_)[c].first,
  1927         row = (*locations_)[c].second;
  1928     if (!(step >= 0 && row >= 0 && (*
steps_)[step][row] == c)) {
  1936         KALDI_ERR << 
"Error in computing computation steps (likely code error)";
  1944     const std::vector<int32> &phase,
  1945     std::vector<std::vector<Cindex> > *sub_phases)
 const {
  1946   std::vector<Cindex> phase_cindexes;
  1949   std::sort(phase_cindexes.begin(), phase_cindexes.end());
  1952   std::vector<size_t> segment_begins;
  1953   int32 cur_node_index = -1;
  1954   size_t size = phase_cindexes.size();
  1955   for (
size_t i = 0; 
i < size; 
i++) {
  1956     if (phase_cindexes[
i].first != cur_node_index) {
  1957       cur_node_index = phase_cindexes[
i].first;
  1958       segment_begins.push_back(
i);
  1961   size_t num_sub_phases = segment_begins.size();
  1962   segment_begins.push_back(size);
  1963   sub_phases->clear();
  1964   sub_phases->resize(num_sub_phases);
  1965   for (
size_t i = 0; 
i < num_sub_phases; 
i++) {
  1966     size_t this_begin = segment_begins[
i],
  1967         this_end = segment_begins[
i+1];
  1968     (*sub_phases)[
i].insert((*sub_phases)[
i].end(),
  1969                             phase_cindexes.begin() + this_begin,
  1970                             phase_cindexes.begin() + this_end);
 virtual bool IsComputable(const MiscComputationInfo &misc_info, const Index &output_index, const IndexSet &input_index_set, std::vector< Index > *used_inputs) const
This function only does something interesting for non-simple Components, and it exists to make it pos...
 
void ConvertToLocations(const std::vector< int32 > &cindex_ids, std::vector< std::pair< int32, int32 > > *locations) const
 
void GetDependencies(const Index &index, std::vector< Cindex > *used_inputs) const
This function exists to enable us to manage optional dependencies, i.e. 
 
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
 
ComputationGraph * graph_
 
ComputationStepsComputer(const Nnet &nnet, ComputationGraph *graph, std::vector< std::vector< int32 > > *steps, std::vector< std::pair< int32, int32 > > *locations)
Constructor. 
 
void UpdateComputableInfo(int32 cindex_id)
 
void ExplainWhyNotComputable(int32 cindex_id) const
 
static void ComputeEpochInfo(const Nnet &nnet, const ComputationGraph &graph, std::vector< int32 > *cindex_id_to_segment_and_epoch, std::vector< std::vector< std::vector< int32 > > > *epochs_per_segment, std::vector< bool > *epoch_is_trivial)
This function computes certain information about "epochs" of cindex_ids. 
 
const std::string & GetNodeName(int32 node_index) const
returns individual node name. 
 
MiscComputationInfo misc_info
misc_info is for extensibility to things that don't easily fit into the framework. 
 
ComputationGraph * graph_
 
Abstract base-class for neural-net components. 
 
void PrintCindex(std::ostream &os, const Cindex &cindex, const std::vector< std::string > &node_names)
 
int32 GetVerboseLevel()
Get verbosity level, usually set via command line '–verbose=' switch. 
 
bool treat_unknown_as_computable_
 
void GetComputableInfo(std::vector< std::vector< bool > > *computable) const
 
An abstract representation of a set of Indexes. 
 
void ConvertToCindexIds(const std::vector< Cindex > &cindexes, std::vector< int32 > *cindex_ids) const
 
void PrintCindexId(std::ostream &os, int32 cindex_id) const
 
std::vector< std::pair< int32, int32 > > * locations_
locations_ is a map from cindex_id to the pair of indexes into steps_ where that cindex_id resides...
 
virtual void GetInputIndexes(const MiscComputationInfo &misc_info, const Index &output_index, std::vector< Index > *desired_indexes) const
This function only does something interesting for non-simple Components. 
 
bool IsInputNode(int32 node) const
Returns true if this is an output node, meaning that it is of type kInput. 
 
void Check(int32 start_cindex_id) const
 
const std::vector< ComputationGraphBuilder::CindexInfo > * info_
 
std::ostream & operator<<(std::ostream &ostream, const Index &index)
 
void ProcessDimRangeSubPhase(const std::vector< Cindex > &sub_phase)
 
bool treat_unknown_as_computable_
 
std::vector< IoSpecification > inputs
 
void SplitIntoSubPhases(const std::vector< int32 > &phase, std::vector< std::vector< Cindex > > *sub_phase) const
 
bool operator()(const Cindex &cindex) const
Parenthesis operator; returns true if this cindex exists in the set. 
 
int32 RoundUpToNearestPowerOfTwo(int32 n)
 
bool IsComponentNode(int32 node) const
Returns true if this is a component node, meaning that it is of type kComponent. 
 
void SortAndUniq(std::vector< T > *vec)
Sorts and uniq's (removes duplicates) from a vector. 
 
void AddCindexId(int32 cindex_id)
 
void IncrementUsableCount(int32 cindex_id)
 
static void ConvertToIndexes(const std::vector< Cindex > &cindexes, std::vector< Index > *indexes)
 
void AddInputToGraph(const ComputationRequest &request, const Nnet &nnet, ComputationGraph *graph)
 
void ComputeComputationGraph(const Nnet &nnet, const ComputationRequest &request, ComputationGraph *graph)
 
struct Index is intended to represent the various indexes by which we number the rows of the matrices...
 
void ComputeGraphTranspose(const std::vector< std::vector< int32 > > &graph, std::vector< std::vector< int32 > > *graph_transpose)
Outputs a graph in which the order of arcs is reversed. 
 
void ComputeRequiredArray(int32 start_cindex_id, std::vector< bool > *required) const
 
bool operator()(const Index &index) const
Returns true if this Index exists in the set. 
 
const ComputationGraph & graph_
 
std::pair< int32, Index > Cindex
 
void AddOutputToGraph(const ComputationRequest &request, const Nnet &nnet, ComputationGraph *graph)
 
std::vector< Cindex > cindexes
The mapping of cindex_id to Cindex. 
 
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node. 
 
void ConvertToCindexes(const std::vector< int32 > &cindex_ids, std::vector< Cindex > *cindexes) const
 
static int32 SumVectorSizes(const std::vector< std::vector< int32 > > &vec)
 
std::vector< std::vector< int32 > > dependencies
dependencies[cindex_id] gives you the list of other cindex_ids that this particular cindex_id directl...
 
int32 GetCindexId(const Cindex &cindex, bool is_input, bool *is_new)
Maps a Cindex to an integer cindex_id. 
 
bool IsOutputNode(int32 node) const
Returns true if this is an output node, meaning that it is of type kDescriptor and is not directly fo...
 
void Check() const
This is only to be called after you have called ComputeForSegment for all the segments. 
 
unordered_map< Cindex, int32, CindexHasher > cindex_to_cindex_id_
Maps each Cindex to an integer cindex_id: reverse mapping of "cindexes". 
 
void ComputeComputationPhases(const Nnet &nnet, const ComputationGraph &graph, std::vector< std::vector< std::vector< int32 > > > *phases_per_segment)
This function divides a computation into 'phases', where a 'phase' is a collection of cindexes which ...
 
virtual int32 Properties() const =0
Return bitmask of the component's properties. 
 
void PruneDependencies(int32 cindex_id)
 
virtual void ReorderIndexes(std::vector< Index > *input_indexes, std::vector< Index > *output_indexes) const
This function only does something interesting for non-simple Components. 
 
IndexSet(const ComputationGraph &graph, const std::vector< ComputationGraphBuilder::CindexInfo > &info, int32 node_id, bool treat_unknown_as_computable)
This constructor creates the set of all Indexes x such that a Cindex (node_id, x) which is computable...
 
std::vector< CindexInfo > cindex_info_
 
std::vector< bool > is_input
For each Cindex this tells us whether it was provided as an input to the network. ...
 
std::vector< std::vector< int32 > > depend_on_this_
 
std::vector< int32 > segment_ends
This variable is only of particular interest in a 'multi-segment' computation, which is used while cr...
 
bool AllOutputsAreComputable() const
 
void ComputeNnetComputationEpochs(const Nnet &nnet, std::vector< int32 > *node_to_epoch)
This function computes the order in which we need to compute each node in the graph, where each node-index n maps to an epoch-index t = 0, 1, ... 
 
std::vector< std::vector< int32 > > * steps_
steps_ is a pointer to an output that's passed in in the constructor. 
 
#define KALDI_PARANOID_ASSERT(cond)
 
void Compute(const ComputationRequest &request)
 
void PrintIntegerVector(std::ostream &os, const std::vector< int32 > &ints)
 
void Renumber(int32 start_cindex_id, const std::vector< bool > &keep)
This function renumbers the cindex-ids (but only those with index c >= start_cindex_id,. 
 
std::vector< int32 > current_queue_
 
bool IsComputable(const Index &ind, const CindexSet &cindex_set, std::vector< Cindex > *used_inputs) const
Has the same purpose and interface as the IsComputable function of the SumDescriptor function...
 
NetworkNode is used to represent, three types of thing: either an input of the network (which pretty ...
 
Component * GetComponent(int32 c)
Return component indexed c. Not a copy; not owned by caller. 
 
This file contains a few functions that treat the neural net as a graph on nodes: e...
 
ComputableInfo computable
 
void ProcessComponentStep(const std::vector< Cindex > &step)
 
void ComputeForSegment(const ComputationRequest &request, const std::vector< std::vector< int32 > > &phases)
You call this once for each segment, in order (note: for normal, non-online computations, there is only one segment). 
 
std::unordered_set< std::pair< int32, int32 >, PairHasher< int32 > > dim_range_nodes_
dim_range_nodes_ is used when allocating steps for nodes of type kDimRangeNode. 
 
std::vector< Index > indexes
 
ComputableInfo ComputeComputableInfo(int32 cindex_id) const
 
static void ComputeComputationPhasesForEpoch(const Nnet &nnet, const ComputationGraph &graph, const std::vector< int32 > &this_epoch, const std::vector< std::vector< int32 > > &dependencies_subset, const std::vector< std::vector< int32 > > &depend_on_subset, bool epoch_is_trivial, std::vector< int32 > *phase_indexes, std::vector< std::vector< int32 > > *phases)
 
const std::vector< ComputationGraphBuilder::CindexInfo > & info_
 
#define KALDI_ASSERT(cond)
 
std::vector< IoSpecification > outputs
 
void ProcessInputOrOutputStep(const ComputationRequest &request, bool is_output, const std::vector< Cindex > &sub_phase)
 
const ComputationGraph & graph_
 
ComputationGraphBuilder(const Nnet &nnet, ComputationGraph *graph)
 
void AddDependencies(int32 cindex_id)
 
union kaldi::nnet3::NetworkNode::@15 u
 
void Print(std::ostream &os, const std::vector< std::string > &node_names)
This function, useful for debugging/visualization purposes, prints out a summary of the computation g...
 
int32 GetNodeIndex(const std::string &node_name) const
returns index associated with this node name, or -1 if no such index. 
 
void ExplainWhyAllOutputsNotComputable() const
 
bool IsSortedAndUniq(const std::vector< T > &vec)
Returns true if the vector is sorted and contains each element only once. 
 
void DecrementUsableCount(int32 cindex_id)
 
int32 AddStep(const std::vector< Cindex > &cindexes, bool add_if_absent=false)
 
static void ComputeDependenciesSubset(const ComputationGraph &graph, const std::vector< int32 > &cindex_id_to_segment_and_epoch, std::vector< std::vector< int32 > > *dependencies_subset)
This function outputs to dependencies_subset[c], for each cindex_id c, the subset of elements d of gr...
 
const ComputationRequest * request_
 
bool IsDimRangeNode(int32 node) const
Returns true if this is a dim-range node, meaning that it is of type kDimRange. 
 
The first step in compilation is to turn the ComputationSpecification into a ComputationGraph, where for each Cindex we have a list of other Cindexes that it depends on. 
 
CindexSet(const ComputationGraph &graph)
with this constructor, represents the set of all Cindexes that exist in the graph. 
 
int32 RandInt(int32 min_val, int32 max_val, struct RandomState *state)
 
bool IsComponentInputNode(int32 node) const
Returns true if this is component-input node, i.e. 
 
void ProcessSubPhase(const ComputationRequest &request, const std::vector< Cindex > &sub_phase)
 
std::vector< int32 > next_queue_