10ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Ceres Solver - A fast non-linear least squares minimizer 20ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Copyright 2010, 2011, 2012 Google Inc. All rights reserved. 30ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// http://code.google.com/p/ceres-solver/ 40ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 50ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Redistribution and use in source and binary forms, with or without 60ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// modification, are permitted provided that the following conditions are met: 70ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 80ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Redistributions of source code must retain the above copyright notice, 90ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// this list of conditions and the following disclaimer. 100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Redistributions in binary form must reproduce the above copyright notice, 110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// this list of conditions and the following disclaimer in the documentation 120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// and/or other materials provided with the distribution. 130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Neither the name of Google Inc. nor the names of its contributors may be 140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// used to endorse or promote products derived from this software without 150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// specific prior written permission. 160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// POSSIBILITY OF SUCH DAMAGE. 280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Author: kushalav@google.com (Avanish Kushal) 300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// sameeragarwal@google.com (Sameer Agarwal) 310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 3279397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez// This include must come before any #ifndef check on Ceres compile options. 3379397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez#include "ceres/internal/port.h" 3479397c21138f54fcff6ec067b44b847f1f7e0e98Carlos Hernandez 351d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling#ifndef CERES_NO_SUITESPARSE 361d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling 370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/visibility.h" 380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <set> 400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <vector> 410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/block_structure.h" 420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/graph.h" 430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/internal/scoped_ptr.h" 440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "glog/logging.h" 450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "gtest/gtest.h" 460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace ceres { 480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace internal { 490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongclass VisibilityTest : public ::testing::Test { 510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}; 520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(VisibilityTest, SimpleMatrix) { 540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // A = [1 0 0 0 0 1 550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // 1 0 0 1 0 0 560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // 0 1 1 0 0 0 570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // 0 1 0 0 1 0] 580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong int num_cols = 6; 600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong int num_eliminate_blocks = 2; 610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CompressedRowBlockStructure bs; 620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Row 1 640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { 650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong bs.rows.push_back(CompressedRow()); 660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CompressedRow& row = bs.rows.back(); 670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.size = 2; 680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.position = 0; 690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.cells.push_back(Cell(0, 0)); 700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.cells.push_back(Cell(5, 0)); 710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Row 2 740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { 750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong bs.rows.push_back(CompressedRow()); 760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CompressedRow& row = bs.rows.back(); 770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.size = 2; 780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.position = 2; 790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.cells.push_back(Cell(0, 1)); 800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.cells.push_back(Cell(3, 1)); 810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Row 3 840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { 850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong bs.rows.push_back(CompressedRow()); 860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CompressedRow& row = bs.rows.back(); 870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.size = 2; 880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.position = 4; 890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.cells.push_back(Cell(1, 2)); 900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.cells.push_back(Cell(2, 2)); 910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Row 4 940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { 950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong bs.rows.push_back(CompressedRow()); 960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CompressedRow& row = bs.rows.back(); 970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.size = 2; 980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.position = 6; 990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.cells.push_back(Cell(1, 3)); 1000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.cells.push_back(Cell(4, 3)); 1010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong bs.cols.resize(num_cols); 1030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong vector< set<int> > visibility; 1050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ComputeVisibility(bs, num_eliminate_blocks, &visibility); 1060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ASSERT_EQ(visibility.size(), num_cols - num_eliminate_blocks); 1070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < visibility.size(); ++i) { 1080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ASSERT_EQ(visibility[i].size(), 1); 1090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong scoped_ptr<Graph<int> > graph(CreateSchurComplementGraph(visibility)); 1120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_EQ(graph->vertices().size(), visibility.size()); 1130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < visibility.size(); ++i) { 1140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_EQ(graph->VertexWeight(i), 1.0); 1150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < visibility.size(); ++i) { 1180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = i; j < visibility.size(); ++j) { 1190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double edge_weight = 0.0; 1200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if ((i == 1 && j == 3) || (i == 0 && j == 2) || (i == j)) { 1210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong edge_weight = 1.0; 1220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_EQ(graph->EdgeWeight(i, j), edge_weight) 1250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << "Edge: " << i << " " << j 1260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " weight: " << graph->EdgeWeight(i, j) 1270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " expected weight: " << edge_weight; 1280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 1310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(VisibilityTest, NoEBlocks) { 1340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // A = [1 0 0 0 0 0 1350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // 1 0 0 0 0 0 1360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // 0 1 0 0 0 0 1370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // 0 1 0 0 0 0] 1380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong int num_cols = 6; 1400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong int num_eliminate_blocks = 2; 1410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CompressedRowBlockStructure bs; 1420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Row 1 1440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { 1450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong bs.rows.push_back(CompressedRow()); 1460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CompressedRow& row = bs.rows.back(); 1470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.size = 2; 1480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.position = 0; 1490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.cells.push_back(Cell(0, 0)); 1500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Row 2 1530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { 1540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong bs.rows.push_back(CompressedRow()); 1550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CompressedRow& row = bs.rows.back(); 1560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.size = 2; 1570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.position = 2; 1580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.cells.push_back(Cell(0, 1)); 1590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Row 3 1620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { 1630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong bs.rows.push_back(CompressedRow()); 1640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CompressedRow& row = bs.rows.back(); 1650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.size = 2; 1660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.position = 4; 1670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.cells.push_back(Cell(1, 2)); 1680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Row 4 1710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { 1720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong bs.rows.push_back(CompressedRow()); 1730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CompressedRow& row = bs.rows.back(); 1740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.size = 2; 1750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.block.position = 6; 1760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong row.cells.push_back(Cell(1, 3)); 1770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong bs.cols.resize(num_cols); 1790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong vector<set<int> > visibility; 1810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ComputeVisibility(bs, num_eliminate_blocks, &visibility); 1820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ASSERT_EQ(visibility.size(), num_cols - num_eliminate_blocks); 1830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < visibility.size(); ++i) { 1840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ASSERT_EQ(visibility[i].size(), 0); 1850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong scoped_ptr<Graph<int> > graph(CreateSchurComplementGraph(visibility)); 1880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_EQ(graph->vertices().size(), visibility.size()); 1890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < visibility.size(); ++i) { 1900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_EQ(graph->VertexWeight(i), 1.0); 1910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < visibility.size(); ++i) { 1940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = i; j < visibility.size(); ++j) { 1950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double edge_weight = 0.0; 1960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (i == j) { 1970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong edge_weight = 1.0; 1980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_EQ(graph->EdgeWeight(i, j), edge_weight) 2000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << "Edge: " << i << " " << j 2010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " weight: " << graph->EdgeWeight(i, j) 2020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " expected weight: " << edge_weight; 2030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 2040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 2050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 2060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} // namespace internal 2080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} // namespace ceres 2091d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling 2101d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling#endif // CERES_NO_SUITESPARSE 211