Open mehoggan opened 7 years ago
I guess you compiled only a 32-bit version of g2o, but trying to link a 64-bit target to it. This is from your log:
ld: symbol(s) not found for architecture x86_64
From the following:
mhoggan-C02S81PRG8WM:cmake-build-debug mhoggan$ file ./g2o-src/lib/libg2o_csparse_extension.dylib
./g2o-src/lib/libg2o_csparse_extension.dylib: Mach-O 64-bit dynamically linked shared library x86_64
I would assume that last comment to be incorrect.
Is the C++ standard being used by the compiler (i.e., the -std=c++xx
compile flag) consistent across the targets?
Outside of g2o there is only one other target, a target added using add_executable and it has -std=c++11 set in CXX_FLAGS. As seen in the following compiler line:
cd /Users/mhoggan/Development/bluenote/image_pose_adjustment/image_pose_adjustment/native/graph/cmake-build-debug/src && /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -I/usr/local/include -I/usr/local/include/eigen3 -I/Users/mhoggan/Development/bluenote/image_pose_adjustment/image_pose_adjustment/native/graph/cmake-build-debug/g2o-build -I/Users/mhoggan/Development/bluenote/image_pose_adjustment/image_pose_adjustment/native/graph/cmake-build-debug/g2o-src -I/Users/mhoggan/Development/bluenote/image_pose_adjustment/image_pose_adjustment/native/graph/cmake-build-debug/g2o-src/EXTERNAL/csparse -I/Users/mhoggan/Development/bluenote/image_pose_adjustment/image_pose_adjustment/native/graph/include -std=c++11 -Wall -Werror -O3 -DNDEBUG -o CMakeFiles/graph_optimization.dir/PoseJsonReader.cpp.o -c /Users/mhoggan/Development/bluenote/image_pose_adjustment/image_pose_adjustment/native/graph/src/PoseJsonReader.cpp
This is the line right before the executable goes to link against g2o.
Here is the CMakeLists.txt file used.
cmake_minimum_required(VERSION 3.2.2)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Werror")
set(EXE_NAME graph_optimization)
set(SOURCE_FILES )
add_executable(${EXE_NAME} "main.cpp"
"BundleRigidGraphOptimizer.cpp"
"FlexibleGraphOptimizer.cpp"
"LoopClosure.cpp"
"PoseJsonReader.cpp")
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost REQUIRED COMPONENTS filesystem system)
find_package(Eigen3 REQUIRED)
find_package(BLAS REQUIRED)
find_package(LAPACK REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${EIGEN3_INCLUDE_DIR})
include_directories(${G2O_INCLUDE_DIR})
include_directories("${CMAKE_SOURCE_DIR}/include")
include_directories("/usr/local/include")
link_directories("/usr/local/lib")
target_link_libraries(${EXE_NAME} ${Boost_LIBRARIES}
g2o_cli
g2o_core
g2o_interface
g2o_parser
g2o_solver_csparse
g2o_solver_dense
g2o_solver_pcg
g2o_stuff
g2o_types_icp
g2o_types_sba
g2o_types_sim3
g2o_types_slam2d
g2o_types_slam3d
g2o_csparse_extension
sparse
jsoncpp)
This only happens on a El Capitan OSx. But is a result of including linear_solver_csparse.h from a executable linking against g2o. This does not happen on debian jessie using g++ (Debian 4.9.2-10) 4.9.2.
Hi, I just figured out this problem, by adding this line in myCMakeLists.txt
file:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++ -lstdc++ -std=c++11")
Please note: This is a Fu*king typical problem on Clang
, and you can search the funning history with google:
The libstdC++ vs libC++ issue!
hope you guys work well, good luck.
Another issue you guys may face is:
fatal error: 'type_traits' file not found
and this is caused by using libstdc++, and libstdc++ does not support c++11 traits, in another word: this is a dead end on Mac..
One more thing: Just don't waste your time on this problem, don't try your hard time frustrating on this platform, install a VM and run a linux, then find other problems to hack on.
Unfortunately, moving off mac for developers is not an option. All developers in our office use macs for 95% of their local development. We deploy to production using docker containers created from local debian VM's.
Also I am now starting to see this error on debian Jessie. I will post my compilation errors in a bit.
uber@ford-ct-5:~/graph-optimization/debian$ cat /etc/*release* PRETTY_NAME="Debian GNU/Linux 8 (jessie)" NAME="Debian GNU/Linux" VERSION_ID="8" VERSION="8 (jessie)" ID=debian HOME_URL="http://www.debian.org/" SUPPORT_URL="http://www.debian.org/support" BUG_REPORT_URL="https://bugs.debian.org/" uber@ford-ct-5:~/graph-optimization/debian$ http://www.target.com/p/promark-photo-tripod/-/A-50626812^C uber@ford-ct-5:~/graph-optimization/debian$ /usr/bin/c++ --version c++ (Debian 4.9.2-10) 4.9.2 Copyright (C) 2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Here are the linker errors on Linux:
../lib/libgraph_optimization.so: undefined reference to
g2o::csparse_extension::cs_chol_workspace(cs_sparse const, cs_symbolic const, int, double)'
../lib/libgraph_optimization.so: undefined reference to g2o::csparse_extension::writeCs2Octave(char const*, cs_sparse const*, bool)' ../lib/libgraph_optimization.so: undefined reference to
g2o::csparse_extension::cs_cholsolsymb(cs_sparse const, double, cs_symbolic const, double, int*)'`
I am going to work on a patch since this is now blocking us from using your library.
For what its worth. When using/linking against the library in question from g2o and using the LinearSolverCSparse templated type. Explicit Template Instantiation (ETI) from a cpp file for linear_solver_csparse.h solves the problem. Below is the patch to apply to g2o if you are having the same problem. Because it uses ETI it is not a solution for everyone unless we new the set of all MatrixType(s) that would be used with the LinearSolverCSparse. This does appear to be a problem with certain tool chains. The patch below works on g++-4.9 in debian but was not tested in MacOSX. I would assume that it would work there since forcing the type to be compiled into the library insure the symbols are placed in the shared library.
From cc703029f3ca366906f05748171235303ace4336 Mon Sep 17 00:00:00 2001
From: Matthew Hoggan <mhoggan@uber.com>
Date: Fri, 28 Apr 2017 21:22:18 +0000
Subject: [PATCH] Explicit template instantiation.
---
g2o/solvers/csparse/CMakeLists.txt | 3 +-
g2o/solvers/csparse/linear_solver_csparse.cpp | 335 ++++++++++++++++++++++++++
g2o/solvers/csparse/linear_solver_csparse.h | 288 ++--------------------
3 files changed, 357 insertions(+), 269 deletions(-)
create mode 100644 g2o/solvers/csparse/linear_solver_csparse.cpp
diff --git a/g2o/solvers/csparse/CMakeLists.txt b/g2o/solvers/csparse/CMakeLists.txt
index 20728d1..9861be5 100644
--- a/g2o/solvers/csparse/CMakeLists.txt
+++ b/g2o/solvers/csparse/CMakeLists.txt
@@ -15,14 +15,13 @@ ENDIF()
ADD_LIBRARY(solver_csparse ${G2O_LIB_TYPE}
solver_csparse.cpp
- linear_solver_csparse.h
+ linear_solver_csparse.cpp
g2o_csparse_api.h
)
SET_TARGET_PROPERTIES(solver_csparse PROPERTIES OUTPUT_NAME ${LIB_PREFIX}solver_csparse)
TARGET_LINK_LIBRARIES(solver_csparse csparse_extension core)
-
INSTALL(TARGETS solver_csparse csparse_extension
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
diff --git a/g2o/solvers/csparse/linear_solver_csparse.cpp b/g2o/solvers/csparse/linear_solver_csparse.cpp
new file mode 100644
index 0000000..7266a27
--- /dev/null
+++ b/g2o/solvers/csparse/linear_solver_csparse.cpp
@@ -0,0 +1,335 @@
+// g2o - General Graph Optimization
+// Copyright (C) 2011 R. Kuemmerle, G. Grisetti, W. Burgard
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "g2o/solvers/csparse/linear_solver_csparse.h"
+
+#include "g2o/core/block_solver.h"
+
+#include <iostream>
+
+namespace g2o {
+
+CSparseExt::CSparseExt()
+{
+ nzmax = 0;
+ m = 0;
+ n = 0;
+ p = 0;
+ i = 0;
+ x = 0;
+ nz = 0;
+ columnsAllocated = 0;
+}
+
+CSparseExt::~CSparseExt()
+{
+ delete[] p;
+ delete[] i;
+ delete[] x;
+}
+
+template <typename MatrixType>
+LinearSolverCSparse<MatrixType>::LinearSolverCSparse() :
+ LinearSolverCCS<MatrixType>()
+{
+ _symbolicDecomposition = 0;
+ _csWorkspaceSize = -1;
+ _csWorkspace = 0;
+ _csIntWorkspace = 0;
+ _ccsA = new CSparseExt;
+ _blockOrdering = true;
+ _writeDebug = true;
+}
+
+template <typename MatrixType>
+LinearSolverCSparse<MatrixType>::~LinearSolverCSparse()
+{
+ if (_symbolicDecomposition) {
+ cs_sfree(_symbolicDecomposition);
+ _symbolicDecomposition = 0;
+ }
+ delete[] _csWorkspace; _csWorkspace = 0;
+ delete[] _csIntWorkspace; _csIntWorkspace = 0;
+ delete _ccsA;
+}
+
+template <typename MatrixType>
+bool LinearSolverCSparse<MatrixType>::init()
+{
+ if (_symbolicDecomposition) {
+ cs_sfree(_symbolicDecomposition);
+ _symbolicDecomposition = 0;
+ }
+ return true;
+}
+
+template <typename MatrixType>
+bool LinearSolverCSparse<MatrixType>::solve(const SparseBlockMatrix<MatrixType>& A, double* x, double* b)
+{
+ fillCSparse(A, _symbolicDecomposition != 0);
+ // perform symbolic cholesky once
+ if (_symbolicDecomposition == 0) {
+ computeSymbolicDecomposition(A);
+ }
+ // re-allocate the temporary workspace for cholesky
+ if (_csWorkspaceSize < _ccsA->n) {
+ _csWorkspaceSize = 2 * _ccsA->n;
+ delete[] _csWorkspace;
+ _csWorkspace = new double[_csWorkspaceSize];
+ delete[] _csIntWorkspace;
+ _csIntWorkspace = new int[2*_csWorkspaceSize];
+ }
+
+ double t=get_monotonic_time();
+ // _x = _b for calling csparse
+ if (x != b)
+ memcpy(x, b, _ccsA->n * sizeof(double));
+ int ok = csparse_extension::cs_cholsolsymb(_ccsA, x, _symbolicDecomposition, _csWorkspace, _csIntWorkspace);
+ if (! ok) {
+ if (_writeDebug) {
+ std::cerr << "Cholesky failure, writing debug.txt (Hessian loadable by Octave)" << std::endl;
+ csparse_extension::writeCs2Octave("debug.txt", _ccsA, true);
+ }
+ return false;
+ }
+
+ G2OBatchStatistics* globalStats = G2OBatchStatistics::globalStats();
+ if (globalStats){
+ globalStats->timeNumericDecomposition = get_monotonic_time() - t;
+ globalStats->choleskyNNZ = static_cast<size_t>(_symbolicDecomposition->lnz);
+ }
+
+ return ok != 0;
+}
+
+template <typename MatrixType>
+bool LinearSolverCSparse<MatrixType>::solveBlocks(double**& blocks, const SparseBlockMatrix<MatrixType>& A) {
+ fillCSparse(A, _symbolicDecomposition != 0);
+ // perform symbolic cholesky once
+ if (_symbolicDecomposition == 0) {
+ computeSymbolicDecomposition(A);
+ assert(_symbolicDecomposition && "Symbolic cholesky failed");
+ }
+ // re-allocate the temporary workspace for cholesky
+ if (_csWorkspaceSize < _ccsA->n) {
+ _csWorkspaceSize = 2 * _ccsA->n;
+ delete[] _csWorkspace;
+ _csWorkspace = new double[_csWorkspaceSize];
+ delete[] _csIntWorkspace;
+ _csIntWorkspace = new int[2*_csWorkspaceSize];
+ }
+
+ if (! blocks){
+ blocks=new double*[A.rows()];
+ double **block=blocks;
+ for (size_t i=0; i < A.rowBlockIndices().size(); ++i){
+ int dim = A.rowsOfBlock(i) * A.colsOfBlock(i);
+ *block = new double [dim];
+ block++;
+ }
+ }
+
+ int ok = 1;
+ csn* numericCholesky = csparse_extension::cs_chol_workspace(_ccsA, _symbolicDecomposition, _csIntWorkspace, _csWorkspace);
+ if (numericCholesky) {
+ MarginalCovarianceCholesky mcc;
+ mcc.setCholeskyFactor(_ccsA->n, numericCholesky->L->p, numericCholesky->L->i, numericCholesky->L->x, _symbolicDecomposition->pinv);
+ mcc.computeCovariance(blocks, A.rowBlockIndices());
+ cs_nfree(numericCholesky);
+ } else {
+ ok = 0;
+ std::cerr << "inverse fail (numeric decomposition)" << std::endl;
+ }
+
+ G2OBatchStatistics* globalStats = G2OBatchStatistics::globalStats();
+ if (globalStats){
+ globalStats->choleskyNNZ = static_cast<size_t>(_symbolicDecomposition->lnz);
+ }
+
+ return ok != 0;
+}
+
+template <typename MatrixType>
+bool LinearSolverCSparse<MatrixType>::solvePattern(SparseBlockMatrix<MatrixXD>& spinv, const std::vector<std::pair<int, int> >& blockIndices,
+ const SparseBlockMatrix<MatrixType>& A) {
+ fillCSparse(A, _symbolicDecomposition != 0);
+ // perform symbolic cholesky once
+ if (_symbolicDecomposition == 0) {
+ computeSymbolicDecomposition(A);
+ assert(_symbolicDecomposition && "Symbolic cholesky failed");
+ }
+ // re-allocate the temporary workspace for cholesky
+ if (_csWorkspaceSize < _ccsA->n) {
+ _csWorkspaceSize = 2 * _ccsA->n;
+ delete[] _csWorkspace;
+ _csWorkspace = new double[_csWorkspaceSize];
+ delete[] _csIntWorkspace;
+ _csIntWorkspace = new int[2*_csWorkspaceSize];
+ }
+
+
+ int ok = 1;
+ csn* numericCholesky = csparse_extension::cs_chol_workspace(_ccsA, _symbolicDecomposition, _csIntWorkspace, _csWorkspace);
+ if (numericCholesky) {
+ MarginalCovarianceCholesky mcc;
+ mcc.setCholeskyFactor(_ccsA->n, numericCholesky->L->p, numericCholesky->L->i, numericCholesky->L->x, _symbolicDecomposition->pinv);
+ mcc.computeCovariance(spinv, A.rowBlockIndices(), blockIndices);
+ cs_nfree(numericCholesky);
+ } else {
+ ok = 0;
+ std::cerr << "inverse fail (numeric decomposition)" << std::endl;
+ }
+
+ G2OBatchStatistics* globalStats = G2OBatchStatistics::globalStats();
+ if (globalStats){
+ globalStats->choleskyNNZ = static_cast<size_t>(_symbolicDecomposition->lnz);
+ }
+
+ return ok != 0;
+}
+
+//! do the AMD ordering on the blocks or on the scalar matrix
+template <typename MatrixType>
+bool LinearSolverCSparse<MatrixType>::blockOrdering() const { return _blockOrdering;}
+
+template <typename MatrixType>
+void LinearSolverCSparse<MatrixType>::setBlockOrdering(bool blockOrdering) { _blockOrdering = blockOrdering;}
+
+//! write a debug dump of the system matrix if it is not SPD in solve
+template <typename MatrixType>
+bool LinearSolverCSparse<MatrixType>::writeDebug() const { return _writeDebug;}
+
+template <typename MatrixType>
+void LinearSolverCSparse<MatrixType>::setWriteDebug(bool b) { _writeDebug = b;}
+
+template <typename MatrixType>
+void LinearSolverCSparse<MatrixType>::computeSymbolicDecomposition(const SparseBlockMatrix<MatrixType>& A)
+{
+ double t=get_monotonic_time();
+ if (! _blockOrdering) {
+ _symbolicDecomposition = cs_schol (1, _ccsA) ;
+ } else {
+ A.fillBlockStructure(_matrixStructure);
+
+ // prepare block structure for the CSparse call
+ cs auxBlock;
+ auxBlock.nzmax = _matrixStructure.nzMax();
+ auxBlock.m = auxBlock.n = _matrixStructure.n;
+ auxBlock.p = _matrixStructure.Ap;
+ auxBlock.i = _matrixStructure.Aii;
+ auxBlock.x = NULL; // no values
+ auxBlock.nz = -1; // CCS format
+
+ // AMD ordering on the block structure
+ const int& n = _ccsA->n;
+ int* P = cs_amd(1, &auxBlock);
+
+ // blow up the permutation to the scalar matrix
+ if (_scalarPermutation.size() == 0)
+ _scalarPermutation.resize(n);
+ if (_scalarPermutation.size() < n)
+ _scalarPermutation.resize(2*n);
+ size_t scalarIdx = 0;
+ for (int i = 0; i < _matrixStructure.n; ++i) {
+ const int& p = P[i];
+ int base = A.colBaseOfBlock(p);
+ int nCols = A.colsOfBlock(p);
+ for (int j = 0; j < nCols; ++j)
+ _scalarPermutation(scalarIdx++) = base++;
+ }
+ assert((int)scalarIdx == n);
+ cs_free(P);
+
+ // apply the scalar permutation to finish symbolic decomposition
+ _symbolicDecomposition = (css*) cs_calloc(1, sizeof(css)); /* allocate result S */
+ _symbolicDecomposition->pinv = cs_pinv(_scalarPermutation.data(), n);
+ cs* C = cs_symperm(_ccsA, _symbolicDecomposition->pinv, 0);
+ _symbolicDecomposition->parent = cs_etree(C, 0);
+ int* post = cs_post(_symbolicDecomposition->parent, n);
+ int* c = cs_counts(C, _symbolicDecomposition->parent, post, 0);
+ cs_free(post);
+ cs_spfree(C);
+ _symbolicDecomposition->cp = (int*) cs_malloc(n+1, sizeof(int));
+ _symbolicDecomposition->unz = _symbolicDecomposition->lnz = cs_cumsum(_symbolicDecomposition->cp, c, n);
+ cs_free(c);
+ if (_symbolicDecomposition->lnz < 0) {
+ cs_sfree(_symbolicDecomposition);
+ _symbolicDecomposition = 0;
+ }
+
+ }
+ G2OBatchStatistics* globalStats = G2OBatchStatistics::globalStats();
+ if (globalStats){
+ globalStats->timeSymbolicDecomposition = get_monotonic_time() - t;
+ }
+
+ /* std::cerr << "# Number of nonzeros in L: " << (int)_symbolicDecomposition->lnz << " by " */
+ /* << (_blockOrdering ? "block" : "scalar") << " AMD ordering " << std::endl; */
+}
+
+template <typename MatrixType>
+void LinearSolverCSparse<MatrixType>::fillCSparse(const SparseBlockMatrix<MatrixType>& A, bool onlyValues)
+{
+ if (! onlyValues)
+ this->initMatrixStructure(A);
+ int m = A.rows();
+ int n = A.cols();
+ assert(m > 0 && n > 0 && "Hessian has 0 rows/cols");
+
+ if (_ccsA->columnsAllocated < n) {
+ _ccsA->columnsAllocated = _ccsA->columnsAllocated == 0 ? n : 2 * n; // pre-allocate more space if re-allocating
+ delete[] _ccsA->p;
+ _ccsA->p = new int[_ccsA->columnsAllocated+1];
+ }
+
+ if (! onlyValues) {
+ int nzmax = A.nonZeros();
+ if (_ccsA->nzmax < nzmax) {
+ _ccsA->nzmax = _ccsA->nzmax == 0 ? nzmax : 2 * nzmax; // pre-allocate more space if re-allocating
+ delete[] _ccsA->x;
+ delete[] _ccsA->i;
+ _ccsA->i = new int[_ccsA->nzmax];
+ _ccsA->x = new double[_ccsA->nzmax];
+ }
+ }
+ _ccsA->m = m;
+ _ccsA->n = n;
+
+ if (onlyValues) {
+ this->_ccsMatrix->fillCCS(_ccsA->x, true);
+ } else {
+ int nz = this->_ccsMatrix->fillCCS(_ccsA->p, _ccsA->i, _ccsA->x, true); (void) nz;
+ assert(nz <= _ccsA->nzmax);
+ }
+ _ccsA->nz=-1; // tag as CCS formatted matrix
+}
+
+} // end namespace
+
+template class g2o::LinearSolverCSparse<g2o::BlockSolver<g2o::BlockSolverTraits<-1, -1>>::PoseMatrixType>;
+template class g2o::LinearSolverCSparse<Eigen::Matrix<double, 3, 3, 0, 3, 3>>;
+template class g2o::LinearSolverCSparse<Eigen::Matrix<double, 6, 6, 0, 6, 6>>;
+template class g2o::LinearSolverCSparse<Eigen::Matrix<double, 7, 7, 0, 7, 7>>;
diff --git a/g2o/solvers/csparse/linear_solver_csparse.h b/g2o/solvers/csparse/linear_solver_csparse.h
index 92b3498..869f5e8 100644
--- a/g2o/solvers/csparse/linear_solver_csparse.h
+++ b/g2o/solvers/csparse/linear_solver_csparse.h
@@ -44,193 +44,43 @@ namespace g2o {
*/
struct G2O_SOLVER_CSPARSE_API CSparseExt : public cs
{
- CSparseExt()
- {
- nzmax = 0;
- m = 0;
- n = 0;
- p = 0;
- i = 0;
- x = 0;
- nz = 0;
- columnsAllocated = 0;
- }
- ~CSparseExt()
- {
- delete[] p;
- delete[] i;
- delete[] x;
- }
+ CSparseExt();
+
+ ~CSparseExt();
+
int columnsAllocated;
};
/**
- * \brief linear solver which uses CSparse
+ * \brief linear solver which uses CSparse. Supported MatrixType(s)
+ * are listed in the .cpp for this templated type as explicit
+ * template instantiation.
*/
template <typename MatrixType>
class LinearSolverCSparse : public LinearSolverCCS<MatrixType>
{
public:
- LinearSolverCSparse() :
- LinearSolverCCS<MatrixType>()
- {
- _symbolicDecomposition = 0;
- _csWorkspaceSize = -1;
- _csWorkspace = 0;
- _csIntWorkspace = 0;
- _ccsA = new CSparseExt;
- _blockOrdering = true;
- _writeDebug = true;
- }
-
- virtual ~LinearSolverCSparse()
- {
- if (_symbolicDecomposition) {
- cs_sfree(_symbolicDecomposition);
- _symbolicDecomposition = 0;
- }
- delete[] _csWorkspace; _csWorkspace = 0;
- delete[] _csIntWorkspace; _csIntWorkspace = 0;
- delete _ccsA;
- }
-
- virtual bool init()
- {
- if (_symbolicDecomposition) {
- cs_sfree(_symbolicDecomposition);
- _symbolicDecomposition = 0;
- }
- return true;
- }
-
- bool solve(const SparseBlockMatrix<MatrixType>& A, double* x, double* b)
- {
- fillCSparse(A, _symbolicDecomposition != 0);
- // perform symbolic cholesky once
- if (_symbolicDecomposition == 0) {
- computeSymbolicDecomposition(A);
- }
- // re-allocate the temporary workspace for cholesky
- if (_csWorkspaceSize < _ccsA->n) {
- _csWorkspaceSize = 2 * _ccsA->n;
- delete[] _csWorkspace;
- _csWorkspace = new double[_csWorkspaceSize];
- delete[] _csIntWorkspace;
- _csIntWorkspace = new int[2*_csWorkspaceSize];
- }
-
- double t=get_monotonic_time();
- // _x = _b for calling csparse
- if (x != b)
- memcpy(x, b, _ccsA->n * sizeof(double));
- int ok = csparse_extension::cs_cholsolsymb(_ccsA, x, _symbolicDecomposition, _csWorkspace, _csIntWorkspace);
- if (! ok) {
- if (_writeDebug) {
- std::cerr << "Cholesky failure, writing debug.txt (Hessian loadable by Octave)" << std::endl;
- csparse_extension::writeCs2Octave("debug.txt", _ccsA, true);
- }
- return false;
- }
-
- G2OBatchStatistics* globalStats = G2OBatchStatistics::globalStats();
- if (globalStats){
- globalStats->timeNumericDecomposition = get_monotonic_time() - t;
- globalStats->choleskyNNZ = static_cast<size_t>(_symbolicDecomposition->lnz);
- }
-
- return ok != 0;
- }
-
- bool solveBlocks(double**& blocks, const SparseBlockMatrix<MatrixType>& A) {
- fillCSparse(A, _symbolicDecomposition != 0);
- // perform symbolic cholesky once
- if (_symbolicDecomposition == 0) {
- computeSymbolicDecomposition(A);
- assert(_symbolicDecomposition && "Symbolic cholesky failed");
- }
- // re-allocate the temporary workspace for cholesky
- if (_csWorkspaceSize < _ccsA->n) {
- _csWorkspaceSize = 2 * _ccsA->n;
- delete[] _csWorkspace;
- _csWorkspace = new double[_csWorkspaceSize];
- delete[] _csIntWorkspace;
- _csIntWorkspace = new int[2*_csWorkspaceSize];
- }
-
- if (! blocks){
- blocks=new double*[A.rows()];
- double **block=blocks;
- for (size_t i=0; i < A.rowBlockIndices().size(); ++i){
- int dim = A.rowsOfBlock(i) * A.colsOfBlock(i);
- *block = new double [dim];
- block++;
- }
- }
-
- int ok = 1;
- csn* numericCholesky = csparse_extension::cs_chol_workspace(_ccsA, _symbolicDecomposition, _csIntWorkspace, _csWorkspace);
- if (numericCholesky) {
- MarginalCovarianceCholesky mcc;
- mcc.setCholeskyFactor(_ccsA->n, numericCholesky->L->p, numericCholesky->L->i, numericCholesky->L->x, _symbolicDecomposition->pinv);
- mcc.computeCovariance(blocks, A.rowBlockIndices());
- cs_nfree(numericCholesky);
- } else {
- ok = 0;
- std::cerr << "inverse fail (numeric decomposition)" << std::endl;
- }
+ LinearSolverCSparse();
- G2OBatchStatistics* globalStats = G2OBatchStatistics::globalStats();
- if (globalStats){
- globalStats->choleskyNNZ = static_cast<size_t>(_symbolicDecomposition->lnz);
- }
+ virtual ~LinearSolverCSparse();
- return ok != 0;
- }
+ virtual bool init();
- virtual bool solvePattern(SparseBlockMatrix<MatrixXD>& spinv, const std::vector<std::pair<int, int> >& blockIndices, const SparseBlockMatrix<MatrixType>& A) {
- fillCSparse(A, _symbolicDecomposition != 0);
- // perform symbolic cholesky once
- if (_symbolicDecomposition == 0) {
- computeSymbolicDecomposition(A);
- assert(_symbolicDecomposition && "Symbolic cholesky failed");
- }
- // re-allocate the temporary workspace for cholesky
- if (_csWorkspaceSize < _ccsA->n) {
- _csWorkspaceSize = 2 * _ccsA->n;
- delete[] _csWorkspace;
- _csWorkspace = new double[_csWorkspaceSize];
- delete[] _csIntWorkspace;
- _csIntWorkspace = new int[2*_csWorkspaceSize];
- }
+ bool solve(const SparseBlockMatrix<MatrixType>& A, double* x, double* b);
+ bool solveBlocks(double**& blocks, const SparseBlockMatrix<MatrixType>& A);
- int ok = 1;
- csn* numericCholesky = csparse_extension::cs_chol_workspace(_ccsA, _symbolicDecomposition, _csIntWorkspace, _csWorkspace);
- if (numericCholesky) {
- MarginalCovarianceCholesky mcc;
- mcc.setCholeskyFactor(_ccsA->n, numericCholesky->L->p, numericCholesky->L->i, numericCholesky->L->x, _symbolicDecomposition->pinv);
- mcc.computeCovariance(spinv, A.rowBlockIndices(), blockIndices);
- cs_nfree(numericCholesky);
- } else {
- ok = 0;
- std::cerr << "inverse fail (numeric decomposition)" << std::endl;
- }
-
- G2OBatchStatistics* globalStats = G2OBatchStatistics::globalStats();
- if (globalStats){
- globalStats->choleskyNNZ = static_cast<size_t>(_symbolicDecomposition->lnz);
- }
-
- return ok != 0;
- }
+ virtual bool solvePattern(SparseBlockMatrix<MatrixXD>& spinv,
+ const std::vector<std::pair<int, int> >& blockIndices,
+ const SparseBlockMatrix<MatrixType>& A);
//! do the AMD ordering on the blocks or on the scalar matrix
- bool blockOrdering() const { return _blockOrdering;}
- void setBlockOrdering(bool blockOrdering) { _blockOrdering = blockOrdering;}
+ bool blockOrdering() const;
+ void setBlockOrdering(bool blockOrdering);
//! write a debug dump of the system matrix if it is not SPD in solve
- virtual bool writeDebug() const { return _writeDebug;}
- virtual void setWriteDebug(bool b) { _writeDebug = b;}
+ virtual bool writeDebug() const;
+ virtual void setWriteDebug(bool b);
protected:
css* _symbolicDecomposition;
@@ -243,105 +93,9 @@ class LinearSolverCSparse : public LinearSolverCCS<MatrixType>
VectorXI _scalarPermutation;
bool _writeDebug;
- void computeSymbolicDecomposition(const SparseBlockMatrix<MatrixType>& A)
- {
- double t=get_monotonic_time();
- if (! _blockOrdering) {
- _symbolicDecomposition = cs_schol (1, _ccsA) ;
- } else {
- A.fillBlockStructure(_matrixStructure);
-
- // prepare block structure for the CSparse call
- cs auxBlock;
- auxBlock.nzmax = _matrixStructure.nzMax();
- auxBlock.m = auxBlock.n = _matrixStructure.n;
- auxBlock.p = _matrixStructure.Ap;
- auxBlock.i = _matrixStructure.Aii;
- auxBlock.x = NULL; // no values
- auxBlock.nz = -1; // CCS format
-
- // AMD ordering on the block structure
- const int& n = _ccsA->n;
- int* P = cs_amd(1, &auxBlock);
-
- // blow up the permutation to the scalar matrix
- if (_scalarPermutation.size() == 0)
- _scalarPermutation.resize(n);
- if (_scalarPermutation.size() < n)
- _scalarPermutation.resize(2*n);
- size_t scalarIdx = 0;
- for (int i = 0; i < _matrixStructure.n; ++i) {
- const int& p = P[i];
- int base = A.colBaseOfBlock(p);
- int nCols = A.colsOfBlock(p);
- for (int j = 0; j < nCols; ++j)
- _scalarPermutation(scalarIdx++) = base++;
- }
- assert((int)scalarIdx == n);
- cs_free(P);
-
- // apply the scalar permutation to finish symbolic decomposition
- _symbolicDecomposition = (css*) cs_calloc(1, sizeof(css)); /* allocate result S */
- _symbolicDecomposition->pinv = cs_pinv(_scalarPermutation.data(), n);
- cs* C = cs_symperm(_ccsA, _symbolicDecomposition->pinv, 0);
- _symbolicDecomposition->parent = cs_etree(C, 0);
- int* post = cs_post(_symbolicDecomposition->parent, n);
- int* c = cs_counts(C, _symbolicDecomposition->parent, post, 0);
- cs_free(post);
- cs_spfree(C);
- _symbolicDecomposition->cp = (int*) cs_malloc(n+1, sizeof(int));
- _symbolicDecomposition->unz = _symbolicDecomposition->lnz = cs_cumsum(_symbolicDecomposition->cp, c, n);
- cs_free(c);
- if (_symbolicDecomposition->lnz < 0) {
- cs_sfree(_symbolicDecomposition);
- _symbolicDecomposition = 0;
- }
-
- }
- G2OBatchStatistics* globalStats = G2OBatchStatistics::globalStats();
- if (globalStats){
- globalStats->timeSymbolicDecomposition = get_monotonic_time() - t;
- }
-
- /* std::cerr << "# Number of nonzeros in L: " << (int)_symbolicDecomposition->lnz << " by " */
- /* << (_blockOrdering ? "block" : "scalar") << " AMD ordering " << std::endl; */
- }
-
- void fillCSparse(const SparseBlockMatrix<MatrixType>& A, bool onlyValues)
- {
- if (! onlyValues)
- this->initMatrixStructure(A);
- int m = A.rows();
- int n = A.cols();
- assert(m > 0 && n > 0 && "Hessian has 0 rows/cols");
-
- if (_ccsA->columnsAllocated < n) {
- _ccsA->columnsAllocated = _ccsA->columnsAllocated == 0 ? n : 2 * n; // pre-allocate more space if re-allocating
- delete[] _ccsA->p;
- _ccsA->p = new int[_ccsA->columnsAllocated+1];
- }
-
- if (! onlyValues) {
- int nzmax = A.nonZeros();
- if (_ccsA->nzmax < nzmax) {
- _ccsA->nzmax = _ccsA->nzmax == 0 ? nzmax : 2 * nzmax; // pre-allocate more space if re-allocating
- delete[] _ccsA->x;
- delete[] _ccsA->i;
- _ccsA->i = new int[_ccsA->nzmax];
- _ccsA->x = new double[_ccsA->nzmax];
- }
- }
- _ccsA->m = m;
- _ccsA->n = n;
+ void computeSymbolicDecomposition(const SparseBlockMatrix<MatrixType>& A);
- if (onlyValues) {
- this->_ccsMatrix->fillCCS(_ccsA->x, true);
- } else {
- int nz = this->_ccsMatrix->fillCCS(_ccsA->p, _ccsA->i, _ccsA->x, true); (void) nz;
- assert(nz <= _ccsA->nzmax);
- }
- _ccsA->nz=-1; // tag as CCS formatted matrix
- }
+ void fillCSparse(const SparseBlockMatrix<MatrixType>& A, bool onlyValues);
};
} // end namespace
--
2.1.4
Building my project using cmake in the following manner:
/Applications/CLion.app/Contents/bin/cmake/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=On -DCMAKE_BUILD_TYPE=Release -G "CodeBlocks - Unix Makefiles" /Users/mhoggan/Development/bluenote/image_pose_adjustment/image_pose_adjustment/native/graph
I get the following build error when my library goes to link against g2o.
However, the nm utility shows the symbols are present: