double MapOptimizer::compute_relentropy_cpu (MatrixXf & dH) const { const MatrixXf & H = m_conditional; const MatrixSf & P = dom_flow.joint; MatrixXf HP(H.rows(), H.cols()); MatrixXf HPt(H.rows(), H.cols()); #pragma omp parallel sections { #pragma omp section HP.noalias() = H * P; #pragma omp section HPt.noalias() = H * P.transpose(); } MatrixXf HPH = HP * H.transpose(); const float sum_P = m_dom_flow_sum; const float sum_Q = m_cod_flow_sum; const float dQ_scale = sum_P / sum_Q; const MatrixSf & Q = cod_flow.joint; MatrixSf & dQ = m_temp_dQ; double relentropy = 0; for (int i = 0; i < Q.outerSize(); ++i) { for (MatrixSf::InnerIterator iter(Q,i); iter; ++iter) { const float Q_yy = iter.value(); const float HPH_yy = HPH(iter.row(), iter.col()); const float dQ_yy = dQ_scale * Q_yy / HPH_yy; relentropy += Q_yy * log(dQ_yy); dQ.coeffRef(iter.row(), iter.col()) = dQ_yy; } } relentropy /= sum_Q; ASSERT_LE(0, relentropy); MatrixXf dH2(H.rows(), H.cols()); #pragma omp parallel sections { #pragma omp section dH.noalias() = dQ.transpose() * HP; #pragma omp section dH2.noalias() = dQ * HPt; } dH += dH2; return relentropy; }