...
  View open merge request
Commits (23)
......@@ -2,3 +2,6 @@ Config/config.hh
*.orig
*.rej
.project
*.swp
.DS_Store
/build*/
This diff is collapsed.
......@@ -316,6 +316,7 @@ solve(NProblemInterface* _problem,
try
{
GRBEnv env = GRBEnv();
applyEnvParams(&env);
GRBModel model = GRBModel(env);
auto vars = allocate_variables(_problem, _discrete_constraints, model);
......@@ -375,8 +376,10 @@ solve_two_phase(NProblemInterface* _problem, //
try
{
GRBEnv env = GRBEnv();
applyEnvParams(&env);
GRBModel model = GRBModel(env);
auto vars = allocate_variables(_problem, _discrete_constraints, model);
set_start(_problem, model, vars, start_solution_output_path_);
setup_constraints(_problem, _constraints, model, vars);
......@@ -444,8 +447,10 @@ solve(NProblemInterface* _problem,
//----------------------------------------------
GRBEnv env = GRBEnv();
applyEnvParams(&env);
GRBModel model = GRBModel(env);
auto vars = allocate_variables(_problem, _discrete_constraints, model);
set_start(_problem, model, vars, start_solution_output_path_);
setup_constraints(_problem, _constraints, model, vars);
......@@ -771,6 +776,7 @@ solve(NProblemInterface* _problem,
//----------------------------------------------
GRBEnv env = GRBEnv();
applyEnvParams(&env);
GRBModel model = GRBModel(env);
//----------------------------------------------
......@@ -874,7 +880,13 @@ void
GUROBISolver::
set_solution_input_path(const std::string &_solution_input_path)
{
solution_input_path_ = _solution_input_path;
solution_input_path_ = _solution_input_path;
}
void GUROBISolver::applyEnvParams(GRBEnv *env)
{
env->set(GRB_DoubleParam_Heuristics, grb_Heuristics_);
env->set(GRB_IntParam_MIPFocus, grb_MIPFocus_);
}
......
......@@ -24,6 +24,7 @@
//== FORWARDDECLARATIONS ======================================================
class GRBEnv;
//== NAMESPACES ===============================================================
......@@ -119,6 +120,8 @@ public:
void set_problem_env_output_path ( const std::string &_problem_env_output_path);
void set_solution_input_path ( const std::string &_solution_input_path);
void set_GRB_MIPFocus(int val) { grb_MIPFocus_ = val;}
void set_GRB_Heuristics(double val) { grb_Heuristics_ = val;}
protected:
private:
......@@ -129,6 +132,11 @@ private:
std::string start_solution_output_path_;
std::string problem_env_output_path_;
std::string solution_input_path_;
// gurobi env parameters, set to their gurobi defaults:
void applyEnvParams(GRBEnv *env);
int grb_MIPFocus_ = 0; // https://www.gurobi.com/documentation/8.1/refman/mipfocus.html
double grb_Heuristics_ = 0.05 ; // https://www.gurobi.com/documentation/8.1/refman/heuristics.html
};
......
......@@ -72,8 +72,8 @@ CholmodSolver::~CholmodSolver()
//-----------------------------------------------------------------------------
bool CholmodSolver::calc_system( const std::vector<int>& _colptr,
const std::vector<int>& _rowind,
bool CholmodSolver::calc_system( const std::vector<SuiteSparseInt>& _colptr,
const std::vector<SuiteSparseInt>& _rowind,
const std::vector<double>& _values)
{
if(show_timings_) sw_.start();
......@@ -98,7 +98,7 @@ bool CholmodSolver::calc_system( const std::vector<int>& _colptr,
// matA.stype = -1;
matA.stype = 1;
matA.itype = CHOLMOD_INT;
matA.itype = SuiteSparseITYPE;
matA.xtype = CHOLMOD_REAL;
matA.dtype = CHOLMOD_DOUBLE;
matA.sorted = 1;
......@@ -154,11 +154,11 @@ bool CholmodSolver::calc_system( const std::vector<int>& _colptr,
//-----------------------------------------------------------------------------
bool CholmodSolver::calc_system_prepare_pattern( const std::vector<int>& _colptr,
const std::vector<int>& _rowind,
bool CholmodSolver::calc_system_prepare_pattern( const std::vector<SuiteSparseInt>& _colptr,
const std::vector<SuiteSparseInt>& _rowind,
const std::vector<double>& _values,
const std::vector<int>& _colptr2,
const std::vector<int>& _rowind2,
const std::vector<SuiteSparseInt>& _colptr2,
const std::vector<SuiteSparseInt>& _rowind2,
const std::vector<double>& _values2 )
{
if(show_timings_) sw_.start();
......@@ -179,12 +179,12 @@ bool CholmodSolver::calc_system_prepare_pattern( const std::vector<int>& _col
matA.p = &colptr_[0];
matA.i = &rowind_[0];
matA.x = &values_[0];
matA.nz = 0;
matA.z = 0;
matA.nz = nullptr;
matA.z = nullptr;
// matA.stype = -1;
matA.stype = 1;
matA.itype = CHOLMOD_INT;
matA.itype = SuiteSparseITYPE;
matA.xtype = CHOLMOD_REAL;
matA.dtype = CHOLMOD_DOUBLE;
matA.sorted = 1;
......@@ -197,15 +197,15 @@ bool CholmodSolver::calc_system_prepare_pattern( const std::vector<int>& _col
matA_pattern.ncol = n;
matA_pattern.nzmax = _values2.size();
matA_pattern.p = (int*)(&_colptr2[0]);
matA_pattern.i = (int*)(&_rowind2[0]);
matA_pattern.x = (double*)(&_values2[0]);
matA_pattern.nz = 0;
matA_pattern.z = 0;
matA_pattern.p = (void*)(&_colptr2[0]);
matA_pattern.i = (void*)(&_rowind2[0]);
matA_pattern.x = (void*)(&_values2[0]);
matA_pattern.nz = nullptr;
matA_pattern.z = nullptr;
// matA_pattern.stype = -1;
matA_pattern.stype = 1;
matA_pattern.itype = CHOLMOD_INT;
matA_pattern.itype = SuiteSparseITYPE;
matA_pattern.xtype = CHOLMOD_REAL;
matA_pattern.dtype = CHOLMOD_DOUBLE;
matA_pattern.sorted = 1;
......@@ -221,7 +221,7 @@ bool CholmodSolver::calc_system_prepare_pattern( const std::vector<int>& _col
// compute permutation based on full pattern
std::vector<int> perm(matA_pattern.nrow);
std::vector<SuiteSparseInt> perm(matA_pattern.nrow);
// cholmod_metis(&matA_pattern, 0, 0, 0, perm.data(), mp_cholmodCommon) ;
cholmod_amd(&matA_pattern, 0, 0, perm.data(), mp_cholmodCommon) ;
......@@ -272,8 +272,8 @@ bool CholmodSolver::calc_system_prepare_pattern( const std::vector<int>& _col
//-----------------------------------------------------------------------------
bool CholmodSolver::update_system( const std::vector<int>& _colptr,
const std::vector<int>& _rowind,
bool CholmodSolver::update_system( const std::vector<SuiteSparseInt>& _colptr,
const std::vector<SuiteSparseInt>& _rowind,
const std::vector<double>& _values )
{
if( !mp_L )
......@@ -298,7 +298,7 @@ bool CholmodSolver::update_system( const std::vector<int>& _colptr,
// matA.stype = -1;
matA.stype = 1;
matA.itype = CHOLMOD_INT;
matA.itype = SuiteSparseITYPE;
matA.xtype = CHOLMOD_REAL;
matA.dtype = CHOLMOD_DOUBLE;
matA.sorted = 1;
......@@ -318,8 +318,8 @@ bool CholmodSolver::update_system( const std::vector<int>& _colptr,
//-----------------------------------------------------------------------------
bool CholmodSolver::update_downdate_factor( const std::vector<int>& _colptr,
const std::vector<int>& _rowind,
bool CholmodSolver::update_downdate_factor( const std::vector<SuiteSparseInt>& _colptr,
const std::vector<SuiteSparseInt>& _rowind,
const std::vector<double>& _values,
const bool _upd)
{
......@@ -344,14 +344,14 @@ bool CholmodSolver::update_downdate_factor( const std::vector<int>& _colptr,
matA.z = 0;
matA.stype = 0;
matA.itype = CHOLMOD_INT;
matA.itype = SuiteSparseITYPE;
matA.xtype = CHOLMOD_REAL;
matA.dtype = CHOLMOD_DOUBLE;
matA.sorted = 1;
matA.packed = 1;
// get permuted matrix
cholmod_sparse* matAp = cholmod_submatrix ( &matA, (int*)mp_L->Perm, mp_L->n, 0, -1, true, true, mp_cholmodCommon);
cholmod_sparse* matAp = cholmod_submatrix ( &matA, (SuiteSparseInt*)mp_L->Perm, mp_L->n, 0, -1, true, true, mp_cholmodCommon);
if(show_timings_)
{
std::cerr << " Cholmod conversion Timing: " << sw_.stop()/1000.0 << "s\n";
......@@ -417,9 +417,14 @@ bool CholmodSolver::solve( double * _x, double * _b)
//-----------------------------------------------------------------------------
int CholmodSolver::dimension()
size_t CholmodSolver::dimension()
{
return std::max(int(0), (int)(colptr_.size()-1));
size_t s = colptr_.size();
if (s == 0) {
return 0;
} else {
return s - 1;
}
}
//-----------------------------------------------------------------------------
......
......@@ -52,6 +52,31 @@
// typedef struct cholmod_factor_struct cholmod_factor;
#ifndef USE_CHOLMOD_LONG_MODE
# define USE_CHOLMOD_LONG_MODE 0
#endif
#if USE_CHOLMOD_LONG_MODE
# define SuiteSparseInt SuiteSparse_long
# define SuiteSparseITYPE CHOLMOD_LONG
# define cholmod_amd cholmod_l_amd
# define cholmod_analyze cholmod_l_analyze
# define cholmod_analyze_p cholmod_l_analyze_p
# define cholmod_factorize cholmod_l_factorize
# define cholmod_finish cholmod_l_finish
# define cholmod_free_sparse cholmod_l_free_sparse
# define cholmod_free_dense cholmod_l_free_dense
# define cholmod_free_factor cholmod_l_free_factor
# define cholmod_metis cholmod_l_metis
# define cholmod_solve cholmod_l_solve
# define cholmod_start cholmod_l_start
# define cholmod_submatrix cholmod_l_submatrix
# define cholmod_updown cholmod_l_updown
#else
# define SuiteSparseInt int
# define SuiteSparseITYPE CHOLMOD_INT
#endif
//== NAMESPACES ===============================================================
namespace COMISO {
......@@ -65,15 +90,15 @@ public:
CholmodSolver();
~CholmodSolver();
bool calc_system( const std::vector<int>& _colptr,
const std::vector<int>& _rowind,
bool calc_system( const std::vector<SuiteSparseInt>& _colptr,
const std::vector<SuiteSparseInt>& _rowind,
const std::vector<double>& _values );
bool calc_system_prepare_pattern( const std::vector<int>& _colptr,
const std::vector<int>& _rowind,
bool calc_system_prepare_pattern( const std::vector<SuiteSparseInt>& _colptr,
const std::vector<SuiteSparseInt>& _rowind,
const std::vector<double>& _values,
const std::vector<int>& _colptr2,
const std::vector<int>& _rowind2,
const std::vector<SuiteSparseInt>& _colptr2,
const std::vector<SuiteSparseInt>& _rowind2,
const std::vector<double>& _values2 );
......@@ -88,8 +113,8 @@ public:
bool calc_system_eigen_prepare_pattern( const Eigen_MatrixT& _mat, const Eigen_MatrixT& _mat_pattern);
bool update_system( const std::vector<int>& _colptr,
const std::vector<int>& _rowind,
bool update_system( const std::vector<SuiteSparseInt>& _colptr,
const std::vector<SuiteSparseInt>& _rowind,
const std::vector<double>& _values );
......@@ -100,8 +125,8 @@ public:
bool update_system_eigen( const Eigen_MatrixT& _mat);
bool update_downdate_factor( const std::vector<int>& _colptr,
const std::vector<int>& _rowind,
bool update_downdate_factor( const std::vector<SuiteSparseInt>& _colptr,
const std::vector<SuiteSparseInt>& _rowind,
const std::vector<double>& _values,
const bool _upd);
......@@ -115,7 +140,7 @@ public:
bool& show_timings();
int dimension();
size_t dimension();
private:
......@@ -124,8 +149,8 @@ private:
cholmod_factor * mp_L;
std::vector<double> values_;
std::vector<int> colptr_;
std::vector<int> rowind_;
std::vector<SuiteSparseInt> colptr_;
std::vector<SuiteSparseInt> rowind_;
bool show_timings_;
Base::StopWatch sw_;
......
......@@ -42,8 +42,8 @@ namespace COMISO {
template< class GMM_MatrixT>
bool CholmodSolver::calc_system_gmm( const GMM_MatrixT& _mat)
{
// std::vector<int> colptr;
// std::vector<int> rowind;
// std::vector<SuiteSparseInt> colptr;
// std::vector<SuiteSparseInt> rowind;
// std::vector<double> values;
......@@ -71,8 +71,8 @@ bool CholmodSolver::calc_system_gmm( const GMM_MatrixT& _mat)
template< class GMM_MatrixT>
bool CholmodSolver::update_system_gmm( const GMM_MatrixT& _mat)
{
// std::vector<int> colptr;
// std::vector<int> rowind;
// std::vector<SuiteSparseInt> colptr;
// std::vector<SuiteSparseInt> rowind;
// std::vector<double> values;
COMISO_GMM::get_ccs_symmetric_data( _mat,
......@@ -126,8 +126,8 @@ bool CholmodSolver::calc_system_eigen_prepare_pattern( const Eigen_MatrixT& _mat
#endif
std::vector<double> values2;
std::vector<int> colptr2;
std::vector<int> rowind2;
std::vector<SuiteSparseInt> colptr2;
std::vector<SuiteSparseInt> rowind2;
#if COMISO_EIGEN3_AVAILABLE
COMISO_EIGEN::get_ccs_symmetric_data( _mat_pattern,
......
......@@ -260,6 +260,17 @@ public:
/// Set noise-level (how much std output is given) 0 basically none, 1 important stuff (warning/timing, is default), 2+ not so important
void set_noisy( int _noisy) { noisy_ = _noisy;}
/// Support changing the RHS of the constraint system in resolve(). Enabled by default.
/// If this is needed, it must be enabled for the initial solve, not just before the resolve!
/// Warning: This can impose substantial memory overhead for large sparse constraint systems.
void set_support_constraint_rhs_resolve( bool _val) {
support_constraint_rhs_resolve_ = _val;
if (!_val) {
// Disabling support means we don't need the content of D_ anymore.
this->rhs_update_table_.D_ = {};
}
}
// Get/Set whether the constraint reordering is used (default true)
bool& use_constraint_reordering() { return miso_.use_constraint_reordering(); }
......@@ -361,6 +372,9 @@ private:
int noisy_;
bool do_gcd_;
// User-configurable, whether to store information for constraint-rhs resolve:
bool support_constraint_rhs_resolve_ = true;
// --------------- Update by Marcel to enable efficient re-solve with changed rhs ----------------------
// Store for symbolic elimination information for rhs
class rhsUpdateTable {
......
......@@ -222,8 +222,10 @@ ConstrainedSolver::solve(
gmm::size_type ncols = gmm::mat_ncols(_A);
gmm::size_type ncons = gmm::mat_nrows(_constraints);
DEB_out_if(_show_timings, 1, "Initital dimension: " << nrows << " x " << ncols
DEB_out_if(_show_timings, 1, "Initial dimension: " << nrows << " x " << ncols
<< " (nnz: " << gmm::nnz(_A) << ")"
<< ", number of constraints: " << ncons
<< " (nnz: " << gmm::nnz(_constraints) << ")"
<< " use reordering: " << use_constraint_reordering() << "\n")
// StopWatch for Timings
......@@ -249,9 +251,11 @@ ConstrainedSolver::solve(
double time_eliminate = sw.stop() / 1000.0;
/// TODO: temporary disable this since it was causing performance issues
//DEB_out_if( _show_timings, 2,
// "Eliminated dimension: " << Acsc.nr << " x " << Acsc.nc
// << "\n#nonzeros: " << gmm::nnz(Acsc) << "\n");
DEB_out_if( _show_timings, 2,
"Eliminated dimension: " << Acsc.nr << " x " << Acsc.nc
<< "\n#nonzeros: " << gmm::nnz(Acsc) << "\n");
DEB_out_if( _show_timings, 2, "constraint nnz: " << gmm::nnz(_constraints) << "\n")
DEB_out_if( _show_timings, 2, "rhs_update_table.D_ nnz: " << gmm::nnz(rhs_update_table_.D_) << "\n")
sw.start();
miso_.solve(Acsc, _x, _rhs, _idx_to_round);
......@@ -342,6 +346,10 @@ ConstrainedSolver::resolve(
// apply stored updates and eliminations to exchanged rhs
if (_constraint_rhs)
{
if (!support_constraint_rhs_resolve_) {
std::cerr << "ERROR: ConstrainedSolver::resolve: resolve() with modified constraint_rhs requested, but support is disabled." << std::endl;
return;
}
// apply linear transformation of Gaussian elimination
rhs_update_table_.cur_constraint_rhs_.resize(gmm::mat_nrows(rhs_update_table_.D_));
gmm::mult(rhs_update_table_.D_, *_constraint_rhs, rhs_update_table_.cur_constraint_rhs_);
......@@ -395,9 +403,11 @@ ConstrainedSolver::make_constraints_independent(
DEB_enter_func;
// setup linear transformation for rhs, start with identity
gmm::size_type nr = gmm::mat_nrows(_constraints);
gmm::resize(rhs_update_table_.D_, nr, nr);
gmm::clear(rhs_update_table_.D_);
for (gmm::size_type i = 0; i < nr; ++i) rhs_update_table_.D_(i, i) = 1.0;
if (support_constraint_rhs_resolve_) {
gmm::resize(rhs_update_table_.D_, nr, nr);
gmm::clear(rhs_update_table_.D_);
for (gmm::size_type i = 0; i < nr; ++i) rhs_update_table_.D_(i, i) = 1.0;
}
// Base::StopWatch sw;
// number of variables
......@@ -556,9 +566,11 @@ ConstrainedSolver::make_constraints_independent(
_constraints(c_it.index(), elim_j) = 0;
constraints_c(c_it.index(), elim_j) = 0;
if (support_constraint_rhs_resolve_) {
// update linear transition of rhs
gmm::add(gmm::scaled(gmm::mat_row(rhs_update_table_.D_, i), val),
gmm::mat_row(rhs_update_table_.D_, c_it.index()));
gmm::add(gmm::scaled(gmm::mat_row(rhs_update_table_.D_, i), val),
gmm::mat_row(rhs_update_table_.D_, c_it.index()));
}
}
}
}
......@@ -579,11 +591,13 @@ ConstrainedSolver::make_constraints_independent_reordering(
DEB_enter_func;
// setup linear transformation for rhs, start with identity
gmm::size_type nr = gmm::mat_nrows(_constraints);
gmm::resize(rhs_update_table_.D_, nr, nr);
gmm::clear(rhs_update_table_.D_);
if (support_constraint_rhs_resolve_) {
gmm::resize(rhs_update_table_.D_, nr, nr);
gmm::clear(rhs_update_table_.D_);
for (gmm::size_type i = 0; i < nr; ++i)
rhs_update_table_.D_(i, i) = 1.0;
for (gmm::size_type i = 0; i < nr; ++i)
rhs_update_table_.D_(i, i) = 1.0;
}
// Base::StopWatch sw;
// number of variables
......@@ -773,9 +787,11 @@ ConstrainedSolver::make_constraints_independent_reordering(
queue.update(static_cast<int>(cur_idx),
static_cast<int>(cur_nnz));
// update linear transition of rhs
gmm::add(gmm::scaled(gmm::mat_row(rhs_update_table_.D_, i), val),
gmm::mat_row(rhs_update_table_.D_, c_it.index()));
if (support_constraint_rhs_resolve_) {
// update linear transition of rhs
gmm::add(gmm::scaled(gmm::mat_row(rhs_update_table_.D_, i), val),
gmm::mat_row(rhs_update_table_.D_, c_it.index()));
}
}
}
}
......@@ -789,7 +805,7 @@ ConstrainedSolver::make_constraints_independent_reordering(
RMatrixT c_tmp(gmm::mat_nrows(_constraints), gmm::mat_ncols(_constraints));
gmm::copy(_constraints, c_tmp);
RowMatrix d_tmp(gmm::mat_nrows(rhs_update_table_.D_), gmm::mat_ncols(rhs_update_table_.D_));
gmm::copy(rhs_update_table_.D_, d_tmp);
rhs_update_table_.D_.swap(d_tmp);
// std::vector<int> elim_temp2(_c_elim);
// std::sort(elim_temp2.begin(), elim_temp2.end());
......@@ -801,7 +817,9 @@ ConstrainedSolver::make_constraints_independent_reordering(
for (unsigned int i = 0; i < nr; ++i)
{
gmm::copy(gmm::mat_row(c_tmp, row_ordering[i]), gmm::mat_row(_constraints, i));
gmm::copy(gmm::mat_row(d_tmp, row_ordering[i]), gmm::mat_row(rhs_update_table_.D_, i));
if (support_constraint_rhs_resolve_) {
gmm::mat_row(d_tmp, row_ordering[i]).swap(gmm::mat_row(rhs_update_table_.D_, i));
}
_c_elim[i] = elim_temp[row_ordering[i]];
}
......
This diff is collapsed.
include(CMakeFindDependencyMacro)
if(NOT TARGET CoMISo::CoMISo)
include("${CMAKE_CURENT_LIST_DIR}/CoMISoTargets.cmake")
endif()
# Add the targets file
include("${CMAKE_CURRENT_LIST_DIR}/CoMISoTargets.cmake")
# - Try to find GUROBI
# GUROBI_BASE - The libraries needed to use Gurobi
# Once done this will define
# GUROBI_FOUND - System has Gurobi
# GUROBI_INCLUDE_DIRS - The Gurobi include directories
# GUROBI_LIBRARIES - The libraries needed to use Gurobi
set (GUROBI_ENABLE OFF CACHE BOOL "Enable gurobi?")
if ( GUROBI_ENABLE )
set (GUROBI_BASE "c:" CACHE PATH "Base path of your gurobi installation")
if (GUROBI_INCLUDE_DIR)
# in cache already
set(GUROBI_FOUND TRUE)
set(GUROBI_INCLUDE_DIRS "${GUROBI_INCLUDE_DIR}" )
set(GUROBI_LIBRARIES "${GUROBI_CXX_LIBRARY};${GUROBI_LIBRARY}" )
else (GUROBI_INCLUDE_DIR)
find_path(GUROBI_INCLUDE_DIR
NAMES gurobi_c++.h
PATHS "$ENV{GUROBI_HOME}/include"
"/Library/gurobi502/mac64/include"
"/Library/gurobi562/mac64/include"
"C:\\libs\\gurobi502\\include"
"C:\\libs\\gurobi562\\include"
"${GUROBI_BASE}/include"
)
find_library( GUROBI_LIBRARY
NAMES gurobi
gurobi60
gurobi56
gurobi55
gurobi51
gurobi50
gurobi46
gurobi45
PATHS "$ENV{GUROBI_HOME}/lib"
"/Library/gurobi562/mac64/lib"
"/Library/gurobi502/mac64/lib"
"C:\\libs\\gurobi562\\lib"
"C:\\libs\\gurobi502\\lib"
"${GUROBI_BASE}/lib"
)
if ( CMAKE_GENERATOR MATCHES "^Visual Studio 12.*Win64" )
SET(GUROBI_LIB_NAME "gurobi_c++md2013")
endif()
find_library( GUROBI_CXX_LIBRARY
NAMES gurobi_c++
${GUROBI_LIB_NAME}
PATHS "$ENV{GUROBI_HOME}/lib"
"/Library/gurobi562/mac64/lib"
"/Library/gurobi502/mac64/lib"
"C:\\libs\\gurobi562\\lib"
"C:\\libs\\gurobi502\\lib"
"${GUROBI_BASE}/lib"
)
# Binary dir for DLLs
find_path(GUROBI_BIN_DIR
NAMES "gurobi60.dll"
PATHS "${GUROBI_INCLUDE_DIR}/../bin"
"${GUROBI_BASE}/bin"
DOC "Directory containing the GUROBI DLLs"
)
set(GUROBI_INCLUDE_DIRS "${GUROBI_INCLUDE_DIR}" )
set(GUROBI_LIBRARIES "${GUROBI_CXX_LIBRARY};${GUROBI_LIBRARY}" )
# use c++ headers as default
# set(GUROBI_COMPILER_FLAGS "-DIL_STD" CACHE STRING "Gurobi Compiler Flags")
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBCPLEX_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(GUROBI DEFAULT_MSG
GUROBI_CXX_LIBRARY GUROBI_LIBRARY GUROBI_INCLUDE_DIR)
mark_as_advanced(GUROBI_INCLUDE_DIR GUROBI_LIBRARY GUROBI_CXX_LIBRARY GUROBI_BIN_DIR )
endif(GUROBI_INCLUDE_DIR)
endif()
\ No newline at end of file
# Once done this will define
# Gurobi_FOUND - System has Gurobi
# Targets:
# Gurobi::GurobiC - only the C interface
# Gurobi::GurobiCXX - C and C++ interface
find_path(GUROBI_HOME
NAMES include/gurobi_c++.h
PATHS
$ENV{GUROBI_HOME}
"/opt/gurobi/linux64/"
)
find_path(GUROBI_INCLUDE_DIR
NAMES gurobi_c++.h
HINTS
"${GUROBI_HOME}/include"
)
mark_as_advanced(GUROBI_INCLUDE_DIR)
set(GUROBI_BIN_DIR "${GUROBI_HOME}/bin")
set(GUROBI_LIB_DIR "${GUROBI_HOME}/lib")
if (WIN32)
file(GLOB GUROBI_LIBRARY_LIST
RELATIVE ${GUROBI_BIN_DIR}
${GUROBI_BIN_DIR}/gurobi*.dll
)
else()
file(GLOB GUROBI_LIBRARY_LIST
RELATIVE ${GUROBI_LIB_DIR}
${GUROBI_LIB_DIR}/libgurobi*.so
)
endif()
# Ignore libgurobiXY_light.so, libgurobi.so (without version):
string(REGEX MATCHALL
"gurobi([0-9]+)\\..*"
GUROBI_LIBRARY_LIST
"${GUROBI_LIBRARY_LIST}"
)
string(REGEX REPLACE
".*gurobi([0-9]+)\\..*"
"\\1"
GUROBI_LIBRARY_VERSIONS
"${GUROBI_LIBRARY_LIST}")
list(LENGTH GUROBI_LIBRARY_VERSIONS GUROBI_NUMVER)
#message("GUROBI LIB VERSIONS: ${GUROBI_LIBRARY_VERSIONS}")
if (GUROBI_NUMVER EQUAL 0)
message(STATUS "Found no Gurobi library version, GUROBI_HOME = ${GUROBI_HOME}.")
elseif (GUROBI_NUMVER EQUAL 1)
list(GET GUROBI_LIBRARY_VERSIONS 0 GUROBI_LIBRARY_VERSION)
else()
# none or more than one versioned library -let's try without suffix,
# maybe the user added a symlink to the desired library
message(STATUS "Found more than one Gurobi library version (${GUROBI_LIBRARY_VERSIONS}), trying without suffix. Set GUROBI_LIBRARY if you want to pick a certain one.")
set(GUROBI_LIBRARY_VERSION "")
endif()
if (WIN32)
find_library(GUROBI_LIBRARY
NAMES "gurobi${GUROBI_LIBRARY_VERSION}"
PATHS
${GUROBI_BIN_DIR}
)
find_library(GUROBI_IMPLIB
NAMES "gurobi${GUROBI_LIBRARY_VERSION}"
PATHS
${GUROBI_LIB_DIR}
)
mark_as_advanced(GUROBI_IMPLIB)
else ()
find_library(GUROBI_LIBRARY
NAMES "gurobi${GUROBI_LIBRARY_VERSION}"
PATHS
${GUROBI_LIB_DIR}
)
endif()
mark_as_advanced(GUROBI_LIBRARY)
if(GUROBI_LIBRARY AND NOT TARGET Gurobi::GurobiC)
add_library(Gurobi::GurobiC SHARED IMPORTED)
target_include_directories(Gurobi::GurobiC INTERFACE ${GUROBI_INCLUDE_DIR})
set_target_properties(Gurobi::GurobiC PROPERTIES IMPORTED_LOCATION ${GUROBI_LIBRARY})
if (GUROBI_IMPLIB)
set_target_properties(Gurobi::GurobiC PROPERTIES IMPORTED_IMPLIB ${GUROBI_IMPLIB})
endif()
endif()
# Gurobi ships with some compiled versions of its C++ library for specific
# compilers, however it also comes with the source code. We will compile
# the source code outselves -- this is much safer, as it guarantees the same
# compiler version and flags.
# (Note: doing this is motivated by actual sometimes-subtle ABI compatibility bugs)
find_path(GUROBI_SRC_DIR NAMES "Model.h" PATHS "${GUROBI_HOME}/src/cpp/")
mark_as_advanced(GUROBI_SRC_DIR)
file(GLOB GUROBI_CXX_SRC CONFIGURE_DEPENDS ${GUROBI_SRC_DIR}/*.cpp)
if(TARGET Gurobi::GurobiC AND GUROBI_CXX_SRC AND NOT TARGET Gurobi::GurobiCXX)
add_library(GurobiCXX STATIC EXCLUDE_FROM_ALL ${GUROBI_CXX_SRC})
add_library(Gurobi::GurobiCXX ALIAS GurobiCXX)
if(MSVC)
target_compile_definitions(GurobiCXX PRIVATE "WIN64")
endif()
target_include_directories(GurobiCXX PUBLIC ${GUROBI_INCLUDE_DIR})
target_link_libraries(GurobiCXX PUBLIC Gurobi::GurobiC)
# We need to be able to link this into a shared library:
set_target_properties(GurobiCXX PROPERTIES POSITION_INDEPENDENT_CODE ON)
endif()
# legacy support:
set(GUROBI_INCLUDE_DIRS "${GUROBI_INCLUDE_DIR}")
set(GUROBI_LIBRARIES Gurobi::GurobiC Gurobi::GurobiCXX)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Gurobi DEFAULT_MSG GUROBI_LIBRARY GUROBI_INCLUDE_DIR GUROBI_SRC_DIR)