bool BlockSolver<Traits>::updateStructure(const std::vector<HyperGraph::Vertex*>& vset, const HyperGraph::EdgeSet& edges) { for (std::vector<HyperGraph::Vertex*>::const_iterator vit = vset.begin(); vit != vset.end(); ++vit) { OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*vit); int dim = v->dimension(); if (! v->marginalized()){ v->setColInHessian(_sizePoses); _sizePoses+=dim; _Hpp->rowBlockIndices().push_back(_sizePoses); _Hpp->colBlockIndices().push_back(_sizePoses); _Hpp->blockCols().push_back(typename SparseBlockMatrix<PoseMatrixType>::IntBlockMap()); ++_numPoses; int ind = v->hessianIndex(); PoseMatrixType* m = _Hpp->block(ind, ind, true); v->mapHessianMemory(m->data()); } else { std::cerr << "updateStructure(): Schur not supported" << std::endl; abort(); } } resizeVector(_sizePoses + _sizeLandmarks); for (HyperGraph::EdgeSet::const_iterator it = edges.begin(); it != edges.end(); ++it) { OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it); for (size_t viIdx = 0; viIdx < e->vertices().size(); ++viIdx) { OptimizableGraph::Vertex* v1 = (OptimizableGraph::Vertex*) e->vertex(viIdx); int ind1 = v1->hessianIndex(); int indexV1Bak = ind1; if (ind1 == -1) continue; for (size_t vjIdx = viIdx + 1; vjIdx < e->vertices().size(); ++vjIdx) { OptimizableGraph::Vertex* v2 = (OptimizableGraph::Vertex*) e->vertex(vjIdx); int ind2 = v2->hessianIndex(); if (ind2 == -1) continue; ind1 = indexV1Bak; bool transposedBlock = ind1 > ind2; if (transposedBlock) // make sure, we allocate the upper triangular block std::swap(ind1, ind2); if (! v1->marginalized() && !v2->marginalized()) { PoseMatrixType* m = _Hpp->block(ind1, ind2, true); e->mapHessianMemory(m->data(), viIdx, vjIdx, transposedBlock); } else { std::cerr << __PRETTY_FUNCTION__ << ": not supported" << std::endl; } } } } return true; }
void SparseOptimizer::computeInitialGuess(EstimatePropagatorCost& costFunction) { OptimizableGraph::VertexSet emptySet; std::set<Vertex*> backupVertices; HyperGraph::VertexSet fixedVertices; // these are the root nodes where to start the initialization for (EdgeContainer::iterator it = _activeEdges.begin(); it != _activeEdges.end(); ++it) { OptimizableGraph::Edge* e = *it; for (size_t i = 0; i < e->vertices().size(); ++i) { OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(e->vertex(i)); if (!v) continue; if (v->fixed()) fixedVertices.insert(v); else { // check for having a prior which is able to fully initialize a vertex for (EdgeSet::const_iterator vedgeIt = v->edges().begin(); vedgeIt != v->edges().end(); ++vedgeIt) { OptimizableGraph::Edge* vedge = static_cast<OptimizableGraph::Edge*>(*vedgeIt); if (vedge->vertices().size() == 1 && vedge->initialEstimatePossible(emptySet, v) > 0.) { //cerr << "Initialize with prior for " << v->id() << endl; vedge->initialEstimate(emptySet, v); fixedVertices.insert(v); } } } if (v->hessianIndex() == -1) { std::set<Vertex*>::const_iterator foundIt = backupVertices.find(v); if (foundIt == backupVertices.end()) { v->push(); backupVertices.insert(v); } } } } EstimatePropagator estimatePropagator(this); estimatePropagator.propagate(fixedVertices, costFunction); // restoring the vertices that should not be initialized for (std::set<Vertex*>::iterator it = backupVertices.begin(); it != backupVertices.end(); ++it) { Vertex* v = *it; v->pop(); } if (verbose()) { computeActiveErrors(); cerr << "iteration= -1\t chi2= " << activeChi2() << "\t time= 0.0" << "\t cumTime= 0.0" << "\t (using initial guess from " << costFunction.name() << ")" << endl; } }
void MainWindow::setRobustKernel() { SparseOptimizer* optimizer = viewer->graph; bool robustKernel = cbRobustKernel->isChecked(); double huberWidth = leKernelWidth->text().toDouble(); //odometry edges are those whose node ids differ by 1 bool onlyLoop = cbOnlyLoop->isChecked(); if (robustKernel) { QString strRobustKernel = coRobustKernel->currentText(); AbstractRobustKernelCreator* creator = RobustKernelFactory::instance()->creator(strRobustKernel.toStdString()); if (! creator) { cerr << strRobustKernel.toStdString() << " is not a valid robust kernel" << endl; return; } for (SparseOptimizer::EdgeSet::const_iterator it = optimizer->edges().begin(); it != optimizer->edges().end(); ++it) { OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it); if (onlyLoop) { if (e->vertices().size() >= 2 && std::abs(e->vertex(0)->id() - e->vertex(1)->id()) != 1) { e->setRobustKernel(creator->construct()); e->robustKernel()->setDelta(huberWidth); } } else { e->setRobustKernel(creator->construct()); e->robustKernel()->setDelta(huberWidth); } } } else { for (SparseOptimizer::EdgeSet::const_iterator it = optimizer->edges().begin(); it != optimizer->edges().end(); ++it) { OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it); e->setRobustKernel(0); } } }
bool SparseOptimizer::gaugeFreedom() { if (vertices().empty()) return false; int maxDim=0; for (HyperGraph::VertexIDMap::iterator it=vertices().begin(); it!=vertices().end(); ++it){ OptimizableGraph::Vertex* v=static_cast<OptimizableGraph::Vertex*>(it->second); maxDim = std::max(maxDim,v->dimension()); } for (HyperGraph::VertexIDMap::iterator it=vertices().begin(); it!=vertices().end(); ++it){ OptimizableGraph::Vertex* v=static_cast<OptimizableGraph::Vertex*>(it->second); if (v->dimension() == maxDim) { // test for fixed vertex if (v->fixed()) { return false; } // test for full dimension prior for (HyperGraph::EdgeSet::const_iterator eit = v->edges().begin(); eit != v->edges().end(); ++eit) { OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*eit); if (e->vertices().size() == 1 && e->dimension() == maxDim) return false; } } } return true; }
bool BlockSolver<Traits>::buildSystem() { // clear b vector # ifdef G2O_OPENMP # pragma omp parallel for default (shared) if (_optimizer->indexMapping().size() > 1000) # endif for (int i = 0; i < static_cast<int>(_optimizer->indexMapping().size()); ++i) { OptimizableGraph::Vertex* v=_optimizer->indexMapping()[i]; assert(v); v->clearQuadraticForm(); } _Hpp->clear(); if (_doSchur) { _Hll->clear(); _Hpl->clear(); } // resetting the terms for the pairwise constraints // built up the current system by storing the Hessian blocks in the edges and vertices # ifndef G2O_OPENMP // no threading, we do not need to copy the workspace JacobianWorkspace& jacobianWorkspace = _optimizer->jacobianWorkspace(); # else // if running with threads need to produce copies of the workspace for each thread JacobianWorkspace jacobianWorkspace = _optimizer->jacobianWorkspace(); # pragma omp parallel for default (shared) firstprivate(jacobianWorkspace) if (_optimizer->activeEdges().size() > 100) # endif for (int k = 0; k < static_cast<int>(_optimizer->activeEdges().size()); ++k) { OptimizableGraph::Edge* e = _optimizer->activeEdges()[k]; e->linearizeOplus(jacobianWorkspace); // jacobian of the nodes' oplus (manifold) e->constructQuadraticForm(); # ifndef NDEBUG for (size_t i = 0; i < e->vertices().size(); ++i) { const OptimizableGraph::Vertex* v = static_cast<const OptimizableGraph::Vertex*>(e->vertex(i)); if (! v->fixed()) { bool hasANan = arrayHasNaN(jacobianWorkspace.workspaceForVertex(i), e->dimension() * v->dimension()); if (hasANan) { std::cerr << "buildSystem(): NaN within Jacobian for edge " << e << " for vertex " << i << std::endl; break; } } } # endif } // flush the current system in a sparse block matrix # ifdef G2O_OPENMP # pragma omp parallel for default (shared) if (_optimizer->indexMapping().size() > 1000) # endif for (int i = 0; i < static_cast<int>(_optimizer->indexMapping().size()); ++i) { OptimizableGraph::Vertex* v=_optimizer->indexMapping()[i]; int iBase = v->colInHessian(); if (v->marginalized()) iBase+=_sizePoses; v->copyB(_b+iBase); } return 0; }
int SparseOptimizerIncremental::optimize(int iterations, bool online) { (void) iterations; // we only do one iteration anyhow OptimizationAlgorithm* solver = _algorithm; solver->init(online); int cjIterations=0; bool ok=true; if (! online || batchStep) { //cerr << "performing batch step" << endl; if (! online) { ok = _underlyingSolver->buildStructure(); if (! ok) { cerr << __PRETTY_FUNCTION__ << ": Failure while building CCS structure" << endl; return 0; } } // copy over the updated estimate as new linearization point if (slamDimension == 3) { for (size_t i = 0; i < indexMapping().size(); ++i) { OnlineVertexSE2* v = static_cast<OnlineVertexSE2*>(indexMapping()[i]); v->setEstimate(v->updatedEstimate); } } else if (slamDimension == 6) { for (size_t i = 0; i < indexMapping().size(); ++i) { OnlineVertexSE3* v= static_cast<OnlineVertexSE3*>(indexMapping()[i]); v->setEstimate(v->updatedEstimate); } } SparseOptimizer::computeActiveErrors(); SparseOptimizer::linearizeSystem(); _underlyingSolver->buildSystem(); int numBlocksRequired = _ivMap.size(); if (_cmember.size() < numBlocksRequired) { _cmember.resize(2 * numBlocksRequired); } memset(_cmember.data(), 0, numBlocksRequired * sizeof(int)); if (_ivMap.size() > 100) { for (size_t i = _ivMap.size() - 20; i < _ivMap.size(); ++i) { const HyperGraph::EdgeSet& eset = _ivMap[i]->edges(); for (HyperGraph::EdgeSet::const_iterator it = eset.begin(); it != eset.end(); ++it) { OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it); OptimizableGraph::Vertex* v1 = static_cast<OptimizableGraph::Vertex*>(e->vertices()[0]); OptimizableGraph::Vertex* v2 = static_cast<OptimizableGraph::Vertex*>(e->vertices()[1]); if (v1->hessianIndex() >= 0) _cmember(v1->hessianIndex()) = 1; if (v2->hessianIndex() >= 0) _cmember(v2->hessianIndex()) = 1; } } } ok = _underlyingSolver->solve(); // get the current cholesky factor along with the permutation _L = _solverInterface->L(); if (_perm.size() < (int)_L->n) _perm.resize(2*_L->n); int* p = (int*)_L->Perm; for (size_t i = 0; i < _L->n; ++i) _perm[p[i]] = i; } else { // update the b vector for (HyperGraph::VertexSet::iterator it = _touchedVertices.begin(); it != _touchedVertices.end(); ++it) { OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it); int iBase = v->colInHessian(); v->copyB(_underlyingSolver->b() + iBase); } _solverInterface->solve(_underlyingSolver->x(), _underlyingSolver->b()); } update(_underlyingSolver->x()); ++cjIterations; if (verbose()){ computeActiveErrors(); cerr << "nodes = " << vertices().size() << "\t edges= " << _activeEdges.size() << "\t chi2= " << FIXED(activeChi2()) << endl; } if (vizWithGnuplot) gnuplotVisualization(); if (! ok) return 0; return 1; }
bool SparseOptimizerIncremental::updateInitialization(HyperGraph::VertexSet& vset, HyperGraph::EdgeSet& eset) { if (batchStep) { return SparseOptimizerOnline::updateInitialization(vset, eset); } for (HyperGraph::VertexSet::iterator it = vset.begin(); it != vset.end(); ++it) { OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it); v->clearQuadraticForm(); // be sure that b is zero for this vertex } // get the touched vertices _touchedVertices.clear(); for (HyperGraph::EdgeSet::iterator it = eset.begin(); it != eset.end(); ++it) { OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it); OptimizableGraph::Vertex* v1 = static_cast<OptimizableGraph::Vertex*>(e->vertices()[0]); OptimizableGraph::Vertex* v2 = static_cast<OptimizableGraph::Vertex*>(e->vertices()[1]); if (! v1->fixed()) _touchedVertices.insert(v1); if (! v2->fixed()) _touchedVertices.insert(v2); } //cerr << PVAR(_touchedVertices.size()) << endl; // updating the internal structures std::vector<HyperGraph::Vertex*> newVertices; newVertices.reserve(vset.size()); _activeVertices.reserve(_activeVertices.size() + vset.size()); _activeEdges.reserve(_activeEdges.size() + eset.size()); for (HyperGraph::EdgeSet::iterator it = eset.begin(); it != eset.end(); ++it) _activeEdges.push_back(static_cast<OptimizableGraph::Edge*>(*it)); //cerr << "updating internal done." << endl; // update the index mapping size_t next = _ivMap.size(); for (HyperGraph::VertexSet::iterator it = vset.begin(); it != vset.end(); ++it) { OptimizableGraph::Vertex* v=static_cast<OptimizableGraph::Vertex*>(*it); if (! v->fixed()){ if (! v->marginalized()){ v->setHessianIndex(next); _ivMap.push_back(v); newVertices.push_back(v); _activeVertices.push_back(v); next++; } else // not supported right now abort(); } else { v->setHessianIndex(-1); } } //cerr << "updating index mapping done." << endl; // backup the tempindex and prepare sorting structure VertexBackup backupIdx[_touchedVertices.size()]; memset(backupIdx, 0, sizeof(VertexBackup) * _touchedVertices.size()); int idx = 0; for (HyperGraph::VertexSet::iterator it = _touchedVertices.begin(); it != _touchedVertices.end(); ++it) { OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it); backupIdx[idx].hessianIndex = v->hessianIndex(); backupIdx[idx].vertex = v; backupIdx[idx].hessianData = v->hessianData(); ++idx; } sort(backupIdx, backupIdx + _touchedVertices.size()); // sort according to the hessianIndex which is the same order as used later by the optimizer for (int i = 0; i < idx; ++i) { backupIdx[i].vertex->setHessianIndex(i); } //cerr << "backup tempindex done." << endl; // building the structure of the update _updateMat.clear(true); // get rid of the old matrix structure _updateMat.rowBlockIndices().clear(); _updateMat.colBlockIndices().clear(); _updateMat.blockCols().clear(); // placing the current stuff in _updateMat MatrixXd* lastBlock = 0; int sizePoses = 0; for (int i = 0; i < idx; ++i) { OptimizableGraph::Vertex* v = backupIdx[i].vertex; int dim = v->dimension(); sizePoses+=dim; _updateMat.rowBlockIndices().push_back(sizePoses); _updateMat.colBlockIndices().push_back(sizePoses); _updateMat.blockCols().push_back(SparseBlockMatrix<MatrixXd>::IntBlockMap()); int ind = v->hessianIndex(); //cerr << PVAR(ind) << endl; if (ind >= 0) { MatrixXd* m = _updateMat.block(ind, ind, true); v->mapHessianMemory(m->data()); lastBlock = m; } } lastBlock->diagonal().array() += 1e-6; // HACK to get Eigen value > 0 for (HyperGraph::EdgeSet::const_iterator it = eset.begin(); it != eset.end(); ++it) { OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it); OptimizableGraph::Vertex* v1 = (OptimizableGraph::Vertex*) e->vertices()[0]; OptimizableGraph::Vertex* v2 = (OptimizableGraph::Vertex*) e->vertices()[1]; int ind1 = v1->hessianIndex(); if (ind1 == -1) continue; int ind2 = v2->hessianIndex(); if (ind2 == -1) continue; bool transposedBlock = ind1 > ind2; if (transposedBlock) // make sure, we allocate the upper triangular block swap(ind1, ind2); MatrixXd* m = _updateMat.block(ind1, ind2, true); e->mapHessianMemory(m->data(), 0, 1, transposedBlock); } // build the system into _updateMat for (HyperGraph::EdgeSet::iterator it = eset.begin(); it != eset.end(); ++it) { OptimizableGraph::Edge * e = static_cast<OptimizableGraph::Edge*>(*it); e->computeError(); } for (HyperGraph::EdgeSet::iterator it = eset.begin(); it != eset.end(); ++it) { OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it); e->linearizeOplus(); } for (HyperGraph::EdgeSet::iterator it = eset.begin(); it != eset.end(); ++it) { OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it); e->constructQuadraticForm(); } // restore the original data for the vertex for (int i = 0; i < idx; ++i) { backupIdx[i].vertex->setHessianIndex(backupIdx[i].hessianIndex); if (backupIdx[i].hessianData) backupIdx[i].vertex->mapHessianMemory(backupIdx[i].hessianData); } // update the structure of the real block matrix bool solverStatus = _algorithm->updateStructure(newVertices, eset); bool updateStatus = computeCholeskyUpdate(); if (! updateStatus) { cerr << "Error while computing update" << endl; } cholmod_sparse* updateAsSparseFactor = cholmod_factor_to_sparse(_cholmodFactor, &_cholmodCommon); // convert CCS update by permuting back to the permutation of L if (updateAsSparseFactor->nzmax > _permutedUpdate->nzmax) { //cerr << "realloc _permutedUpdate" << endl; cholmod_reallocate_triplet(updateAsSparseFactor->nzmax, _permutedUpdate, &_cholmodCommon); } _permutedUpdate->nnz = 0; _permutedUpdate->nrow = _permutedUpdate->ncol = _L->n; { int* Ap = (int*)updateAsSparseFactor->p; int* Ai = (int*)updateAsSparseFactor->i; double* Ax = (double*)updateAsSparseFactor->x; int* Bj = (int*)_permutedUpdate->j; int* Bi = (int*)_permutedUpdate->i; double* Bx = (double*)_permutedUpdate->x; for (size_t c = 0; c < updateAsSparseFactor->ncol; ++c) { const int& rbeg = Ap[c]; const int& rend = Ap[c+1]; int cc = c / slamDimension; int coff = c % slamDimension; const int& cbase = backupIdx[cc].vertex->colInHessian(); const int& ccol = _perm(cbase + coff); for (int j = rbeg; j < rend; j++) { const int& r = Ai[j]; const double& val = Ax[j]; int rr = r / slamDimension; int roff = r % slamDimension; const int& rbase = backupIdx[rr].vertex->colInHessian(); int row = _perm(rbase + roff); int col = ccol; if (col > row) // lower triangular entry swap(col, row); Bi[_permutedUpdate->nnz] = row; Bj[_permutedUpdate->nnz] = col; Bx[_permutedUpdate->nnz] = val; ++_permutedUpdate->nnz; } } } cholmod_free_sparse(&updateAsSparseFactor, &_cholmodCommon); #if 0 cholmod_sparse* updatePermuted = cholmod_triplet_to_sparse(_permutedUpdate, _permutedUpdate->nnz, &_cholmodCommon); //writeCCSMatrix("update-permuted.txt", updatePermuted->nrow, updatePermuted->ncol, (int*)updatePermuted->p, (int*)updatePermuted->i, (double*)updatePermuted->x, false); _solverInterface->choleskyUpdate(updatePermuted); cholmod_free_sparse(&updatePermuted, &_cholmodCommon); #else convertTripletUpdateToSparse(); _solverInterface->choleskyUpdate(_permutedUpdateAsSparse); #endif return solverStatus; }
void computeSimpleStars(StarSet& stars, SparseOptimizer* optimizer, EdgeLabeler* labeler, EdgeCreator* creator, OptimizableGraph::Vertex* gauge_, std::string edgeTag, std::string vertexTag, int level, int step, int backboneIterations, int starIterations, double rejectionThreshold, bool debug){ cerr << "preforming the tree actions" << endl; HyperDijkstra d(optimizer); // compute a spanning tree based on the types of edges and vertices in the pool EdgeTypesCostFunction f(edgeTag, vertexTag, level); d.shortestPaths(gauge_, &f, std::numeric_limits< double >::max(), 1e-6, false, std::numeric_limits< double >::max()/2); HyperDijkstra::computeTree(d.adjacencyMap()); // constructs the stars on the backbone BackBoneTreeAction bact(optimizer, vertexTag, level, step); bact.init(); cerr << "free edges size " << bact.freeEdges().size() << endl; // perform breadth-first visit of the visit tree and create the stars on the backbone d.visitAdjacencyMap(d.adjacencyMap(),&bact,true); stars.clear(); for (VertexStarMultimap::iterator it=bact.vertexStarMultiMap().begin(); it!=bact.vertexStarMultiMap().end(); it++){ stars.insert(it->second); } cerr << "stars.size: " << stars.size() << endl; cerr << "size: " << bact.vertexStarMultiMap().size() << endl; // for each star // for all vertices in the backbone, select all edges leading/leaving from that vertex // that are contained in freeEdges. // mark the corresponding "open" vertices and add them to a multimap (vertex->star) // select a gauge in the backbone // push all vertices on the backbone // compute an initial guess on the backbone // one round of optimization backbone // lock all vertices in the backbone // push all "open" vertices // for each open vertex, // compute an initial guess given the backbone // do some rounds of solveDirect // if (fail) // - remove the vertex and the edges in that vertex from the star // - make the structures consistent // pop all "open" vertices // pop all "vertices" in the backbone // unfix the vertices in the backbone int starNum=0; for (StarSet::iterator it=stars.begin(); it!=stars.end(); it++){ Star* s =*it; HyperGraph::VertexSet backboneVertices = s->_lowLevelVertices; HyperGraph::EdgeSet backboneEdges = s->_lowLevelEdges; if (backboneEdges.empty()) continue; // cerr << "optimizing backbone" << endl; // one of these should be the gauge, to be simple we select the fisrt one in the backbone OptimizableGraph::VertexSet gauge; gauge.insert(*backboneVertices.begin()); s->gauge()=gauge; s->optimizer()->push(backboneVertices); s->optimizer()->setFixed(gauge,true); s->optimizer()->initializeOptimization(backboneEdges); s->optimizer()->computeInitialGuess(); s->optimizer()->optimize(backboneIterations); s->optimizer()->setFixed(backboneVertices, true); // cerr << "assignind edges.vertices not in bbone" << endl; HyperGraph::EdgeSet otherEdges; HyperGraph::VertexSet otherVertices; std::multimap<HyperGraph::Vertex*, HyperGraph::Edge*> vemap; for (HyperGraph::VertexSet::iterator bit=backboneVertices.begin(); bit!=backboneVertices.end(); bit++){ HyperGraph::Vertex* v=*bit; for (HyperGraph::EdgeSet::iterator eit=v->edges().begin(); eit!=v->edges().end(); eit++){ OptimizableGraph::Edge* e = (OptimizableGraph::Edge*) *eit; HyperGraph::EdgeSet::iterator feit=bact.freeEdges().find(e); if (feit!=bact.freeEdges().end()){ // edge is admissible otherEdges.insert(e); bact.freeEdges().erase(feit); for (size_t i=0; i<e->vertices().size(); i++){ OptimizableGraph::Vertex* ve= (OptimizableGraph::Vertex*)e->vertices()[i]; if (backboneVertices.find(ve)==backboneVertices.end()){ otherVertices.insert(ve); vemap.insert(make_pair(ve,e)); } } } } } // RAINER TODO maybe need a better solution than dynamic casting here?? OptimizationAlgorithmWithHessian* solverWithHessian = dynamic_cast<OptimizationAlgorithmWithHessian*>(s->optimizer()->solver()); if (solverWithHessian) { s->optimizer()->push(otherVertices); // cerr << "optimizing vertices out of bbone" << endl; // cerr << "push" << endl; // cerr << "init" << endl; s->optimizer()->initializeOptimization(otherEdges); // cerr << "guess" << endl; s->optimizer()->computeInitialGuess(); // cerr << "solver init" << endl; s->optimizer()->solver()->init(); // cerr << "structure" << endl; if (!solverWithHessian->buildLinearStructure()) cerr << "FATAL: failure while building linear structure" << endl; // cerr << "errors" << endl; s->optimizer()->computeActiveErrors(); // cerr << "system" << endl; solverWithHessian->updateLinearSystem(); // cerr << "directSolove" << endl; } else { cerr << "FATAL: hierarchical thing cannot be used with a solver that does not support the system structure construction" << endl; } // // then optimize the vertices one at a time to check if a solution is good for (HyperGraph::VertexSet::iterator vit=otherVertices.begin(); vit!=otherVertices.end(); vit++){ OptimizableGraph::Vertex* v=(OptimizableGraph::Vertex*)(*vit); v->solveDirect(); // cerr << " " << d; // if a solution is found, add a vertex and all the edges in //othervertices that are pointing to that edge to the star s->_lowLevelVertices.insert(v); for (HyperGraph::EdgeSet::iterator eit=v->edges().begin(); eit!=v->edges().end(); eit++){ OptimizableGraph::Edge* e = (OptimizableGraph::Edge*) *eit; if (otherEdges.find(e)!=otherEdges.end()) s->_lowLevelEdges.insert(e); } } //cerr << endl; // relax the backbone and optimize it all // cerr << "relax bbone" << endl; s->optimizer()->setFixed(backboneVertices, false); //cerr << "fox gauge bbone" << endl; s->optimizer()->setFixed(s->gauge(),true); //cerr << "opt init" << endl; s->optimizer()->initializeOptimization(s->_lowLevelEdges); optimizer->computeActiveErrors(); double initialChi = optimizer->activeChi2(); int starOptResult = s->optimizer()->optimize(starIterations); //cerr << starOptResult << "(" << starIterations << ") " << endl; double finalchi=-1.; cerr << "computing star: " << starNum << endl; int vKept=0, vDropped=0; if (!starIterations || starOptResult > 0 ){ optimizer->computeActiveErrors(); finalchi = optimizer->activeChi2(); #if 1 s->optimizer()->computeActiveErrors(); // cerr << "system" << endl; if (solverWithHessian) solverWithHessian->updateLinearSystem(); HyperGraph::EdgeSet prunedStarEdges = backboneEdges; HyperGraph::VertexSet prunedStarVertices = backboneVertices; for (HyperGraph::VertexSet::iterator vit=otherVertices.begin(); vit!=otherVertices.end(); vit++){ //discard the vertices whose error is too big OptimizableGraph::Vertex* v=(OptimizableGraph::Vertex*)(*vit); MatrixXd h(v->dimension(), v->dimension()); for (int i=0; i<v->dimension(); i++){ for (int j=0; j<v->dimension(); j++) h(i,j)=v->hessian(i,j); } EigenSolver<Eigen::MatrixXd> esolver; esolver.compute(h); VectorXcd ev= esolver.eigenvalues(); double emin = std::numeric_limits<double>::max(); double emax = -std::numeric_limits<double>::max(); for (int i=0; i<ev.size(); i++){ emin = ev(i).real()>emin ? emin : ev(i).real(); emax = ev(i).real()<emax ? emax : ev(i).real(); } double d=emin/emax; // cerr << " " << d; if (d>rejectionThreshold){ // if a solution is found, add a vertex and all the edges in //othervertices that are pointing to that edge to the star prunedStarVertices.insert(v); for (HyperGraph::EdgeSet::iterator eit=v->edges().begin(); eit!=v->edges().end(); eit++){ OptimizableGraph::Edge* e = (OptimizableGraph::Edge*) *eit; if (otherEdges.find(e)!=otherEdges.end()) prunedStarEdges.insert(e); } //cerr << "K( " << v->id() << "," << d << ")" ; vKept ++; } else { vDropped++; //cerr << "R( " << v->id() << "," << d << ")" ; } } s->_lowLevelEdges=prunedStarEdges; s->_lowLevelVertices=prunedStarVertices; #endif //cerr << "addHedges" << endl; //now add to the star the hierarchical edges std::vector<OptimizableGraph::Vertex*> vertices(2); vertices[0]= (OptimizableGraph::Vertex*) *s->_gauge.begin(); for (HyperGraph::VertexSet::iterator vit=s->_lowLevelVertices.begin(); vit!=s->_lowLevelVertices.end(); vit++){ OptimizableGraph::Vertex* v=(OptimizableGraph::Vertex*)*vit; vertices[1]=v; if (v==vertices[0]) continue; OptimizableGraph::Edge* e=creator->createEdge(vertices); //rr << "creating edge" << e << Factory::instance()->tag(vertices[0]) << "->" << Factory::instance()->tag(v) <endl; if (e) { e->setLevel(level+1); optimizer->addEdge(e); s->_starEdges.insert(e); } else { cerr << "HERE" << endl; cerr << "FATAL, cannot create edge" << endl; } } } cerr << " gauge: " << (*s->_gauge.begin())->id() << " kept: " << vKept << " dropped: " << vDropped << " edges:" << s->_lowLevelEdges.size() << " hedges" << s->_starEdges.size() << " initial chi " << initialChi << " final chi " << finalchi << endl; if (debug) { char starLowName[100]; sprintf(starLowName, "star-%04d-low.g2o", starNum); ofstream starLowStream(starLowName); optimizer->saveSubset(starLowStream, s->_lowLevelEdges); } bool labelOk=false; if (!starIterations || starOptResult > 0) labelOk = s->labelStarEdges(0, labeler); if (labelOk) { if (debug) { char starHighName[100]; sprintf(starHighName, "star-%04d-high.g2o", starNum); ofstream starHighStream(starHighName); optimizer->saveSubset(starHighStream, s->_starEdges); } } else { cerr << "FAILURE: " << starOptResult << endl; } starNum++; //label each hierarchical edge s->optimizer()->pop(otherVertices); s->optimizer()->pop(backboneVertices); s->optimizer()->setFixed(s->gauge(),false); } StarSet stars2; // now erase the stars that have 0 edges. They r useless for (StarSet::iterator it=stars.begin(); it!=stars.end(); it++){ Star* s=*it; if (s->lowLevelEdges().size()==0) { delete s; } else stars2.insert(s); } stars=stars2; }
bool SparseOptimizer::initializeOptimization (HyperGraph::VertexSet& vset, int level) { // Recorre todos los vertices introducidos en el optimizador. // Para cada vertice 'V' obtiene los edges de los que forma parte. // Para cada uno de esos edges, se mira si todos sus vertices estan en el // optimizador. Si lo estan, el edge se aniade a _activeEdges. // Si el vertice 'V' tiene algun edge con todos los demas vertices en el // optimizador, se aniade 'V' a _activeVertices // Al final se asignan unos indices internos para los vertices: // -1: vertices fijos // 0..n: vertices no fijos y NO marginalizables // n+1..m: vertices no fijos y marginalizables clearIndexMapping(); _activeVertices.clear(); _activeVertices.reserve(vset.size()); _activeEdges.clear(); set<Edge*> auxEdgeSet; // temporary structure to avoid duplicates for (HyperGraph::VertexSet::iterator it = vset.begin(); it != vset.end(); it++) { OptimizableGraph::Vertex* v= (OptimizableGraph::Vertex*) *it; const OptimizableGraph::EdgeSet& vEdges=v->edges(); // count if there are edges in that level. If not remove from the pool int levelEdges=0; for (OptimizableGraph::EdgeSet::const_iterator it = vEdges.begin(); it != vEdges.end(); it++) { OptimizableGraph::Edge* e = reinterpret_cast<OptimizableGraph::Edge*>(*it); if (level < 0 || e->level() == level) { bool allVerticesOK = true; for (vector<HyperGraph::Vertex*>::const_iterator vit = e->vertices().begin(); vit != e->vertices().end(); ++vit) { if (vset.find(*vit) == vset.end()) { allVerticesOK = false; break; } } if (allVerticesOK) { auxEdgeSet.insert(reinterpret_cast<OptimizableGraph::Edge*>(*it)); levelEdges++; } } } if (levelEdges) _activeVertices.push_back(v); } _activeEdges.reserve(auxEdgeSet.size()); for (set<Edge*>::iterator it = auxEdgeSet.begin(); it != auxEdgeSet.end(); ++it) _activeEdges.push_back(*it); sortVectorContainers(); return buildIndexMapping(_activeVertices); }
bool BlockSolver<Traits>::buildStructure(bool zeroBlocks) { assert(_optimizer); size_t sparseDim = 0; _numPoses=0; _numLandmarks=0; _sizePoses=0; _sizeLandmarks=0; int* blockPoseIndices = new int[_optimizer->indexMapping().size()]; int* blockLandmarkIndices = new int[_optimizer->indexMapping().size()]; for (size_t i = 0; i < _optimizer->indexMapping().size(); ++i) { OptimizableGraph::Vertex* v = _optimizer->indexMapping()[i]; int dim = v->dimension(); if (! v->marginalized()){ v->setColInHessian(_sizePoses); _sizePoses+=dim; blockPoseIndices[_numPoses]=_sizePoses; ++_numPoses; } else { v->setColInHessian(_sizeLandmarks); _sizeLandmarks+=dim; blockLandmarkIndices[_numLandmarks]=_sizeLandmarks; ++_numLandmarks; } sparseDim += dim; } resize(blockPoseIndices, _numPoses, blockLandmarkIndices, _numLandmarks, sparseDim); delete[] blockLandmarkIndices; delete[] blockPoseIndices; // allocate the diagonal on Hpp and Hll int poseIdx = 0; int landmarkIdx = 0; for (size_t i = 0; i < _optimizer->indexMapping().size(); ++i) { OptimizableGraph::Vertex* v = _optimizer->indexMapping()[i]; if (! v->marginalized()){ //assert(poseIdx == v->hessianIndex()); PoseMatrixType* m = _Hpp->block(poseIdx, poseIdx, true); if (zeroBlocks) m->setZero(); v->mapHessianMemory(m->data()); ++poseIdx; } else { LandmarkMatrixType* m = _Hll->block(landmarkIdx, landmarkIdx, true); if (zeroBlocks) m->setZero(); v->mapHessianMemory(m->data()); ++landmarkIdx; } } assert(poseIdx == _numPoses && landmarkIdx == _numLandmarks); // temporary structures for building the pattern of the Schur complement SparseBlockMatrixHashMap<PoseMatrixType>* schurMatrixLookup = 0; if (_doSchur) { schurMatrixLookup = new SparseBlockMatrixHashMap<PoseMatrixType>(_Hschur->rowBlockIndices(), _Hschur->colBlockIndices()); schurMatrixLookup->blockCols().resize(_Hschur->blockCols().size()); } // here we assume that the landmark indices start after the pose ones // create the structure in Hpp, Hll and in Hpl for (SparseOptimizer::EdgeContainer::const_iterator it=_optimizer->activeEdges().begin(); it!=_optimizer->activeEdges().end(); ++it){ OptimizableGraph::Edge* e = *it; for (size_t viIdx = 0; viIdx < e->vertices().size(); ++viIdx) { OptimizableGraph::Vertex* v1 = (OptimizableGraph::Vertex*) e->vertex(viIdx); int ind1 = v1->hessianIndex(); if (ind1 == -1) continue; int indexV1Bak = ind1; for (size_t vjIdx = viIdx + 1; vjIdx < e->vertices().size(); ++vjIdx) { OptimizableGraph::Vertex* v2 = (OptimizableGraph::Vertex*) e->vertex(vjIdx); int ind2 = v2->hessianIndex(); if (ind2 == -1) continue; ind1 = indexV1Bak; bool transposedBlock = ind1 > ind2; if (transposedBlock){ // make sure, we allocate the upper triangle block std::swap(ind1, ind2); } if (! v1->marginalized() && !v2->marginalized()){ PoseMatrixType* m = _Hpp->block(ind1, ind2, true); if (zeroBlocks) m->setZero(); e->mapHessianMemory(m->data(), viIdx, vjIdx, transposedBlock); if (_Hschur) {// assume this is only needed in case we solve with the schur complement schurMatrixLookup->addBlock(ind1, ind2); } } else if (v1->marginalized() && v2->marginalized()){ // RAINER hmm.... should we ever reach this here???? LandmarkMatrixType* m = _Hll->block(ind1-_numPoses, ind2-_numPoses, true); if (zeroBlocks) m->setZero(); e->mapHessianMemory(m->data(), viIdx, vjIdx, false); } else { if (v1->marginalized()){ PoseLandmarkMatrixType* m = _Hpl->block(v2->hessianIndex(),v1->hessianIndex()-_numPoses, true); if (zeroBlocks) m->setZero(); e->mapHessianMemory(m->data(), viIdx, vjIdx, true); // transpose the block before writing to it } else { PoseLandmarkMatrixType* m = _Hpl->block(v1->hessianIndex(),v2->hessianIndex()-_numPoses, true); if (zeroBlocks) m->setZero(); e->mapHessianMemory(m->data(), viIdx, vjIdx, false); // directly the block } } } } } if (! _doSchur) return true; _DInvSchur->diagonal().resize(landmarkIdx); _Hpl->fillSparseBlockMatrixCCS(*_HplCCS); for (size_t i = 0; i < _optimizer->indexMapping().size(); ++i) { OptimizableGraph::Vertex* v = _optimizer->indexMapping()[i]; if (v->marginalized()){ const HyperGraph::EdgeSet& vedges=v->edges(); for (HyperGraph::EdgeSet::const_iterator it1=vedges.begin(); it1!=vedges.end(); ++it1){ for (size_t i=0; i<(*it1)->vertices().size(); ++i) { OptimizableGraph::Vertex* v1= (OptimizableGraph::Vertex*) (*it1)->vertex(i); if (v1->hessianIndex()==-1 || v1==v) continue; for (HyperGraph::EdgeSet::const_iterator it2=vedges.begin(); it2!=vedges.end(); ++it2){ for (size_t j=0; j<(*it2)->vertices().size(); ++j) { OptimizableGraph::Vertex* v2= (OptimizableGraph::Vertex*) (*it2)->vertex(j); if (v2->hessianIndex()==-1 || v2==v) continue; int i1=v1->hessianIndex(); int i2=v2->hessianIndex(); if (i1<=i2) { schurMatrixLookup->addBlock(i1, i2); } } } } } } } _Hschur->takePatternFromHash(*schurMatrixLookup); delete schurMatrixLookup; _Hschur->fillSparseBlockMatrixCCSTransposed(*_HschurTransposedCCS); return true; }
void EstimatePropagator::propagate(OptimizableGraph::VertexSet& vset, const EstimatePropagator::PropagateCost& cost, const EstimatePropagator::PropagateAction& action, double maxDistance, double maxEdgeCost) { reset(); PriorityQueue frontier; for (OptimizableGraph::VertexSet::iterator vit=vset.begin(); vit!=vset.end(); ++vit){ OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*vit); AdjacencyMap::iterator it = _adjacencyMap.find(v); assert(it != _adjacencyMap.end()); it->second._distance = 0.; it->second._parent.clear(); it->second._frontierLevel = 0; frontier.push(&it->second); } while(! frontier.empty()){ AdjacencyMapEntry* entry = frontier.pop(); OptimizableGraph::Vertex* u = entry->child(); double uDistance = entry->distance(); //cerr << "uDistance " << uDistance << endl; // initialize the vertex if (entry->_frontierLevel > 0) { action(entry->edge(), entry->parent(), u); } /* std::pair< OptimizableGraph::VertexSet::iterator, bool> insertResult = */ _visited.insert(u); OptimizableGraph::EdgeSet::iterator et = u->edges().begin(); while (et != u->edges().end()){ OptimizableGraph::Edge* edge = static_cast<OptimizableGraph::Edge*>(*et); ++et; int maxFrontier = -1; OptimizableGraph::VertexSet initializedVertices; for (size_t i = 0; i < edge->vertices().size(); ++i) { OptimizableGraph::Vertex* z = static_cast<OptimizableGraph::Vertex*>(edge->vertex(i)); AdjacencyMap::iterator ot = _adjacencyMap.find(z); if (ot->second._distance != numeric_limits<double>::max()) { initializedVertices.insert(z); maxFrontier = (max)(maxFrontier, ot->second._frontierLevel); } } assert(maxFrontier >= 0); for (size_t i = 0; i < edge->vertices().size(); ++i) { OptimizableGraph::Vertex* z = static_cast<OptimizableGraph::Vertex*>(edge->vertex(i)); if (z == u) continue; size_t wasInitialized = initializedVertices.erase(z); double edgeDistance = cost(edge, initializedVertices, z); if (edgeDistance > 0. && edgeDistance != std::numeric_limits<double>::max() && edgeDistance < maxEdgeCost) { double zDistance = uDistance + edgeDistance; //cerr << z->id() << " " << zDistance << endl; AdjacencyMap::iterator ot = _adjacencyMap.find(z); assert(ot!=_adjacencyMap.end()); if (zDistance < ot->second.distance() && zDistance < maxDistance){ //if (ot->second.inQueue) //cerr << "Updating" << endl; ot->second._distance = zDistance; ot->second._parent = initializedVertices; ot->second._edge = edge; ot->second._frontierLevel = maxFrontier + 1; frontier.push(&ot->second); } } if (wasInitialized > 0) initializedVertices.insert(z); } } } // writing debug information like cost for reaching each vertex and the parent used to initialize #ifdef DEBUG_ESTIMATE_PROPAGATOR cerr << "Writing cost.dat" << endl; ofstream costStream("cost.dat"); for (AdjacencyMap::const_iterator it = _adjacencyMap.begin(); it != _adjacencyMap.end(); ++it) { HyperGraph::Vertex* u = it->second.child(); costStream << "vertex " << u->id() << " cost " << it->second._distance << endl; } cerr << "Writing init.dat" << endl; ofstream initStream("init.dat"); vector<AdjacencyMapEntry*> frontierLevels; for (AdjacencyMap::iterator it = _adjacencyMap.begin(); it != _adjacencyMap.end(); ++it) { if (it->second._frontierLevel > 0) frontierLevels.push_back(&it->second); } sort(frontierLevels.begin(), frontierLevels.end(), FrontierLevelCmp()); for (vector<AdjacencyMapEntry*>::const_iterator it = frontierLevels.begin(); it != frontierLevels.end(); ++it) { AdjacencyMapEntry* entry = *it; OptimizableGraph::Vertex* to = entry->child(); initStream << "calling init level = " << entry->_frontierLevel << "\t ("; for (OptimizableGraph::VertexSet::iterator pit = entry->parent().begin(); pit != entry->parent().end(); ++pit) { initStream << " " << (*pit)->id(); } initStream << " ) -> " << to->id() << endl; } #endif }
bool saveGnuplot(const std::string& gnudump, const HyperGraph::VertexSet& vertices, const HyperGraph::EdgeSet& edges) { // seek for an action whose name is writeGnuplot in the library HyperGraphElementAction* saveGnuplot = HyperGraphActionLibrary::instance()->actionByName("writeGnuplot"); if (! saveGnuplot ){ cerr << __PRETTY_FUNCTION__ << ": no action \"writeGnuplot\" registered" << endl; return false; } WriteGnuplotAction::Parameters params; int maxDim = -1; int minDim = numeric_limits<int>::max(); for (HyperGraph::VertexSet::const_iterator it = vertices.begin(); it != vertices.end(); ++it){ OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it); int vdim = v->dimension(); maxDim = (std::max)(vdim, maxDim); minDim = (std::min)(vdim, minDim); } string extension = getFileExtension(gnudump); if (extension.size() == 0) extension = "dat"; string baseFilename = getPureFilename(gnudump); // check for odometry edges bool hasOdomEdge = false; bool hasLandmarkEdge = false; for (HyperGraph::EdgeSet::const_iterator it = edges.begin(); it != edges.end(); ++it) { OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it); if (e->vertices().size() == 2) { if (edgeAllVertsSameDim(e, maxDim)) hasOdomEdge = true; else hasLandmarkEdge = true; } if (hasOdomEdge && hasLandmarkEdge) break; } bool fileStatus = true; if (hasOdomEdge) { string odomFilename = baseFilename + "_odom_edges." + extension; cerr << "# saving " << odomFilename << " ... "; ofstream fout(odomFilename.c_str()); if (! fout) { cerr << "Unable to open file" << endl; return false; } params.os = &fout; // writing odometry edges for (HyperGraph::EdgeSet::const_iterator it = edges.begin(); it != edges.end(); ++it) { OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it); if (e->vertices().size() != 2 || ! edgeAllVertsSameDim(e, maxDim)) continue; (*saveGnuplot)(e, ¶ms); } cerr << "done." << endl; } if (hasLandmarkEdge) { string filename = baseFilename + "_landmarks_edges." + extension; cerr << "# saving " << filename << " ... "; ofstream fout(filename.c_str()); if (! fout) { cerr << "Unable to open file" << endl; return false; } params.os = &fout; // writing landmark edges for (HyperGraph::EdgeSet::const_iterator it = edges.begin(); it != edges.end(); ++it) { OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it); if (e->vertices().size() != 2 || edgeAllVertsSameDim(e, maxDim)) continue; (*saveGnuplot)(e, ¶ms); } cerr << "done." << endl; } if (1) { string filename = baseFilename + "_edges." + extension; cerr << "# saving " << filename << " ... "; ofstream fout(filename.c_str()); if (! fout) { cerr << "Unable to open file" << endl; return false; } params.os = &fout; // writing all edges for (HyperGraph::EdgeSet::const_iterator it = edges.begin(); it != edges.end(); ++it) { OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it); (*saveGnuplot)(e, ¶ms); } cerr << "done." << endl; } if (1) { string filename = baseFilename + "_vertices." + extension; cerr << "# saving " << filename << " ... "; ofstream fout(filename.c_str()); if (! fout) { cerr << "Unable to open file" << endl; return false; } params.os = &fout; for (HyperGraph::VertexSet::const_iterator it = vertices.begin(); it != vertices.end(); ++it){ OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it); (*saveGnuplot)(v, ¶ms); } cerr << "done." << endl; } return fileStatus; }