void ForwardBacktracker::forward_pass(uint start, uint end, uint seq_len, MDArray<eMISMASK> & mismask, bool multiply_by_parents) { // Set variables used in the forward algorithm uint slice_count = end - start; // Setup the forward array and the scales scales.clear(); scales.reserve(slice_count); forward.set_shape(vec(slice_count, hidden_node_size)); transition_matrices.clear(); transition_matrices.reserve(slice_count); // Fill out the forward array for(uint i=0, l=start; i < slice_count; i++, l++) { DiscreteNode *node; MDArray<double> *cpd; vector<Node*> *nodes; // For the first slice in the network if(l==0 || i==0) { // Get the appropriate hidden node if(l==0) { node = hd_0; cpd = cpd_0; } else { node = hd_1; cpd = cpd_1; } // Get the values of the parents of the hidden node // (and remove the value of the hidden node) vector<double> dpv; vector<uint> ipv; node->parentmap.get(l, dpv); dpv.pop_back(); toint(dpv, ipv); // Get the transition probability and store it in the forward array MDArray<double> *cpd_sliced = &cpd->get_view(ipv); forward.set(i, *cpd_sliced); // Store the transition matrix from a posible backtrack transition_matrices.push_back(cpd_sliced); } // For the remaining slices else { // Get the appropriate hidden node node = hd_1; // Get the values of the parents of the hidden node // (and remove the value of the hidden node) vector<double> dpv; vector<uint> ipv; node->parentmap.get(l, dpv); dpv.pop_back(); dpv.erase(dpv.begin()); toint(dpv, ipv); MDArray<double> *cpd_sliced = &cpd_1_swaped.get_view(ipv); // Store the transition matrix from a posible backtrack transition_matrices.push_back(cpd_sliced); // Multiply transitions probabilities P(HD_l = g | HD_{l-1} = h ) by the // forward values forward[i-1, g] and sum over node values of g // TODO: This can probably be done faster for(uint j=0; j < hidden_node_size; j++ ) { // Sum over the previous hidden value double sum = 0; for(uint k=0; k < hidden_node_size; k++ ) { sum += forward.get(i-1, k) * cpd_sliced->get(k, j); } forward.set(i, j, sum); } } // Multiply the forward value by the probability of the parents if(multiply_by_parents) { if(l==0) nodes = &nodes_0; else nodes = &nodes_1; for(vector<uint>::iterator parent=node->parents_1.begin(); parent < node->parents_1.end(); parent++) { double parent_likelihood = exp( (*nodes)[(*parent)]->get_slice_log_likelihood(l) ); forward.get_view(i).multiply_inplace(parent_likelihood); } } // Multiply the forward values by the probability of the observed children // Note that the value of the hidden node is preserved in prev_node_value for(vector<Node*>::iterator child=node->children_1.begin(); child < node->children_1.end(); child++) { if (mismask.get(l, (*child)->node_index) == MOCAPY_OBSERVED) { // Get the original value of the hidden node vector<double> dpv; node->parentmap.get(l, dpv); // Multiply the forward vector with the likelihood values of the child for(uint j=0; j < hidden_node_size; j++ ) { node->parentmap.set(l, j); forward.get(i,j) *= exp( (*child)->get_slice_log_likelihood(l) ); } // Restore the original value of the hidden node node->parentmap.set(l, dpv.back()); } } // If the is the end slice but not the end of the DBN, take the next hidden value into account if(l==end-1 && l!=seq_len-1) { // The next node can only be hd_1 vector<double> dpv; vector<uint> ipv; hd_1->parentmap.get(l+1, dpv); uint next_hidden_value = (uint)dpv.back(); dpv.pop_back(); dpv.erase(dpv.begin()); toint(dpv, ipv); MDArray<double> * cpd_1_sliced = &cpd_1_swaped.get_view(ipv); // Multiply the forward vector with the probability of the transition to the next hidden state for(uint j=0; j < hidden_node_size; j++ ) { forward.get(i,j) *= cpd_1_sliced->get(j, next_hidden_value); } } // Scale forward to be a probability distribution (this is // allowed according to BSA sec. 3.6 (p. 78) vector<double> *column_i = (&(&forward.get_view(i))->get_values()); double scale = 0; // Sum column i for(uint j=0; j < hidden_node_size; j++ ) {scale += (*column_i)[j];} // Normalise column i by it's sum bool observedNan=false; for(uint j=0; j < hidden_node_size; j++ ) { (*column_i)[j] /= scale; if (isnan((*column_i)[j])) observedNan = true; } if (observedNan) { for(uint j=0; j < hidden_node_size; j++ ) { (*column_i)[j] = 1.0/hidden_node_size; } } // Save the scale scales.push_back(scale); } }