void BaseMultiEdge<D, E>::constructQuadraticForm() { const InformationType& omega = _information; Matrix<double, D, 1> omega_r = - omega * _error; for (size_t i = 0; i < _vertices.size(); ++i) { OptimizableGraph::Vertex* from = static_cast<OptimizableGraph::Vertex*>(_vertices[i]); bool istatus = !(from->fixed()); if (istatus) { const MatrixXd& A = _jacobianOplus[i]; MatrixXd AtO = A.transpose() * omega; int fromDim = from->dimension(); Map<MatrixXd> fromMap(from->hessianData(), fromDim, fromDim); Map<VectorXd> fromB(from->bData(), fromDim); // ii block in the hessian #ifdef G2O_OPENMP from->lockQuadraticForm(); #endif fromMap.noalias() += AtO * A; fromB.noalias() += A.transpose() * omega_r; // compute the off-diagonal blocks ij for all j for (size_t j = i+1; j < _vertices.size(); ++j) { OptimizableGraph::Vertex* to = static_cast<OptimizableGraph::Vertex*>(_vertices[j]); #ifdef G2O_OPENMP to->lockQuadraticForm(); #endif bool jstatus = !(to->fixed()); if (jstatus) { const MatrixXd& B = _jacobianOplus[j]; int idx = computeUpperTriangleIndex(i, j); assert(idx < (int)_hessian.size()); HessianHelper& hhelper = _hessian[idx]; if (hhelper.transposed) { // we have to write to the block as transposed hhelper.matrix.noalias() += B.transpose() * AtO.transpose(); } else { hhelper.matrix.noalias() += AtO * B; } } #ifdef G2O_OPENMP to->unlockQuadraticForm(); #endif } #ifdef G2O_OPENMP from->unlockQuadraticForm(); #endif } } }
void BaseMultiEdge<D, E>::linearizeOplus() { #ifdef G2O_OPENMP for (size_t i = 0; i < _vertices.size(); ++i) { OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(_vertices[i]); v->lockQuadraticForm(); } #endif const double delta = 1e-9; const double scalar = 1.0 / (2*delta); ErrorVector errorBak; ErrorVector errorBeforeNumeric = _error; for (size_t i = 0; i < _vertices.size(); ++i) { //Xi - estimate the jacobian numerically OptimizableGraph::Vertex* vi = static_cast<OptimizableGraph::Vertex*>(_vertices[i]); if (vi->fixed()) continue; const int vi_dim = vi->dimension(); #ifdef _MSC_VER double* add_vi = new double[vi_dim]; #else double add_vi[vi_dim]; #endif std::fill(add_vi, add_vi + vi_dim, 0.0); if (_jacobianOplus[i].rows() != _dimension || _jacobianOplus[i].cols() != vi_dim) _jacobianOplus[i].resize(_dimension, vi_dim); // add small step along the unit vector in each dimension for (int d = 0; d < vi_dim; ++d) { vi->push(); add_vi[d] = delta; vi->oplus(add_vi); computeError(); errorBak = _error; vi->pop(); vi->push(); add_vi[d] = -delta; vi->oplus(add_vi); computeError(); errorBak -= _error; vi->pop(); add_vi[d] = 0.0; _jacobianOplus[i].col(d) = scalar * errorBak; } // end dimension #ifdef _MSC_VER delete[] add_vi; #endif } _error = errorBeforeNumeric; #ifdef G2O_OPENMP for (int i = (int)(_vertices.size()) - 1; i >= 0; --i) { OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(_vertices[i]); v->unlockQuadraticForm(); } #endif }