diff --git a/CoMISo/CMakeLists.txt b/CoMISo/CMakeLists.txt index bd50db448c720837151723aad366155a1a84ab3a..647c0c443cb4c16e162dc603633684a2c217a7e3 100644 --- a/CoMISo/CMakeLists.txt +++ b/CoMISo/CMakeLists.txt @@ -202,6 +202,9 @@ if (CPLEX_FOUND ) # list( APPEND COMISO_LINK_DIRECTORIES ${CPLEX_LIBRARY_DIR} ) # list( APPEND COMISO_LINK_DIRECTORIES ${CPLEX_CONCERT_LIBRARY_DIR} ) list( APPEND COMISO_LINK_LIBRARIES ${CPLEX_LIBRARIES} ) + + #enable c++ support + add_definitions(-DIL_STD) else () message (STATUS "CPLEX not found!") set (COMISO_ARPACK_CONFIG_FILE_SETTINGS "#define COMISO_CPLEX_AVAILABLE 0" ) @@ -326,6 +329,9 @@ endif() if( EXISTS "${CMAKE_SOURCE_DIR}/Examples/small_nsolver/CMakeLists.txt" ) add_subdirectory (Examples/small_nsolver) endif() +if( EXISTS "${CMAKE_SOURCE_DIR}/Examples/small_miqp/CMakeLists.txt" ) + add_subdirectory (Examples/small_miqp) +endif() diff --git a/CoMISo/Examples/small_miqp/CMakeLists.txt b/CoMISo/Examples/small_miqp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..72b300acbb2c99c1ba3fdcf63cea6ccf0c482067 --- /dev/null +++ b/CoMISo/Examples/small_miqp/CMakeLists.txt @@ -0,0 +1,42 @@ +include (ACGCommon) +include (CoMISoExample) + +# source code directories +set (directories + . +) + +# collect all header and source files +acg_append_files (headers "*.hh" ${directories}) +acg_append_files (sources "*.cc" ${directories}) + +# remove template cc files from source file list +acg_drop_templates (sources) + +if (WIN32) + acg_add_executable (small_miqp WIN32 ${sources} ${headers} ) +elseif (APPLE) + # generate bundle on mac + acg_add_executable (small_miqp MACOSX_BUNDLE ${sources} ${headers} ) +else () + acg_add_executable (small_miqp ${sources} ${headers} ) +endif () + +# enable rpath linking +set_target_properties(small_miqp PROPERTIES INSTALL_RPATH_USE_LINK_PATH 1) + +target_link_libraries (small_miqp + CoMISo + ${COMISO_LINK_LIBRARIES} +) + +if (APPLE) + # create bundle in "Build" directory and set icon + # no install needed here, because the whole bundle will be installed in the + # toplevel CMakeLists.txt + set_target_properties ( + Example PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Build" + MACOSX_BUNDLE_INFO_STRING "CoMISo small_miqp" + ) +endif () diff --git a/CoMISo/Examples/small_miqp/main.cc b/CoMISo/Examples/small_miqp/main.cc new file mode 100644 index 0000000000000000000000000000000000000000..5b5c1df4afb8d9a0e34880e1258cd717b7dfd129 --- /dev/null +++ b/CoMISo/Examples/small_miqp/main.cc @@ -0,0 +1,149 @@ +/*===========================================================================*\ + * * + * CoMISo * + * Copyright (C) 2008-2009 by Computer Graphics Group, RWTH Aachen * + * www.rwth-graphics.de * + * * + *---------------------------------------------------------------------------* + * This file is part of CoMISo. * + * * + * CoMISo is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * CoMISo is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with CoMISo. If not, see . * + * * +\*===========================================================================*/ + +#include + +#include +#include +#include +#include +#include +#include +#include + + +// generate an instance of a nonlinear problem by deriving from base class NProblemInterface +// implement all virtual functions in order to solve this problem by any of the solvers located +// in CoMISo/NSolver + +class SmallNProblem : public COMISO::NProblemInterface +{ +public: + + // Sparse Matrix Type + // typedef Eigen::DynamicSparseMatrix SMatrixNP; + + + // specify a function which has several local minima + // f(x,y)=(x-2y+1)^2 + (x-2)^2 + + // number of unknown variables, here x and y = 2 + virtual int n_unknowns ( ) + { + return 2; + } + + // initial value where the optimization should start from + virtual void initial_x ( double* _x ) + { + _x[0] = 0.0; + _x[1] = 0.0; + } + + // function evaluation at location _x + virtual double eval_f ( const double* _x ) + { + double term = _x[0] - 2.0*_x[1] + 1.0; + double term2 = _x[0] - 2.0; + + return term*term + term2*term2; + } + + // gradient evaluation at location _x + virtual void eval_gradient( const double* _x, double* _g) + { + double term = _x[0] - 2.0*_x[1] + 1.0; + double term2 = _x[0] - 2.0; + + _g[0] = 2.0*term + 2.0*term2; + _g[1] = -4.0*term; + } + + // hessian matrix evaluation at location _x + virtual void eval_hessian ( const double* _x, SMatrixNP& _H) + { + _H.resize(n_unknowns(), n_unknowns()); + _H.setZero(); + + _H.coeffRef(0,0) = 4.0; + _H.coeffRef(1,0) = -4.0; + _H.coeffRef(0,1) = -4.0; + _H.coeffRef(1,1) = 8.0; + } + + // print result + virtual void store_result ( const double* _x ) + { + std::cerr << "Energy: " << eval_f(_x) << std::endl; + std::cerr << "(x,y) = (" << _x[0] << "," << _x[1] << ")" << std::endl; + } + + // advanced properties + virtual bool constant_hessian() { return true; } +}; + + +//------------------------------------------------------------------------------------------------------ + +// Example main +int main(void) +{ + std::cout << "---------- 1) Get an instance of a NProblem..." << std::endl; + SmallNProblem snp; + + std::cout << "---------- 2) (optional for debugging) Check derivatives of problem..." << std::endl; + COMISO::NPDerivativeChecker npd; + npd.check_all(&snp); + + std::cout << "---------- 3) setup list of integer variables..." << std::endl; + std::vector discrete_variables; + discrete_variables.push_back( COMISO::PairIndexVtype(0,COMISO::Integer) ); + + std::cout << "---------- 4) setup constraints..." << std::endl; + std::vector constraints; + + +// check if IPOPT solver available in current configuration +#if( COMISO_GUROBI_AVAILABLE) + std::cout << "---------- 5) Get GUROBI solver... " << std::endl; + COMISO::GUROBISolver gsol; + + std::cout << "---------- 4) Solve..." << std::endl; + + gsol.solve(&snp, constraints, discrete_variables); +#endif + + // check if TAO solver available in current configuration +#if( COMISO_CPLEX_AVAILABLE) + std::cout << "---------- 5) Solve with CPLEX solver... " << std::endl; + COMISO::CPLEXSolver csol; + + std::cout << "---------- 4) Solve..." << std::endl; + + csol.solve(&snp, constraints, discrete_variables); +#endif + + return 0; +} + diff --git a/CoMISo/NSolver/CPLEXSolver.cc b/CoMISo/NSolver/CPLEXSolver.cc new file mode 100644 index 0000000000000000000000000000000000000000..4ed592e32fa91a05bdeb6931ffb6dcf89943a9af --- /dev/null +++ b/CoMISo/NSolver/CPLEXSolver.cc @@ -0,0 +1,252 @@ +//============================================================================= +// +// CLASS GUROBISolver - IMPLEMENTATION +// +//============================================================================= + +//== INCLUDES ================================================================= + +//== COMPILE-TIME PACKAGE REQUIREMENTS ======================================== +#include "CPLEXSolver.hh" +#if COMISO_CPLEX_AVAILABLE +//============================================================================= + + +#include + +//== NAMESPACES =============================================================== + +namespace COMISO { + +//== IMPLEMENTATION ========================================================== + + + +CPLEXSolver:: +CPLEXSolver() +{ +} + +//----------------------------------------------------------------------------- + +// ********** SOLVE **************** // +bool +CPLEXSolver:: +solve(NProblemInterface* _problem, + std::vector& _constraints, + std::vector& _discrete_constraints, + const double _time_limit) +{ + + try + { +// //---------------------------------------------- +// // 0. set up environment +// //---------------------------------------------- +// +// GRBEnv env = GRBEnv(); +// GRBModel model = GRBModel(env); +// +// model.getEnv().set(GRB_DoubleParam_TimeLimit, _time_limit); +// +// +// //---------------------------------------------- +// // 1. allocate variables +// //---------------------------------------------- +// +// // determine variable types: 0->real, 1->integer, 2->bool +// std::vector vtypes(_problem->n_unknowns(),0); +// for(unsigned int i=0; i<_discrete_constraints.size(); ++i) +// switch(_discrete_constraints[i].second) +// { +// case Integer: vtypes[_discrete_constraints[i].first] = 1; break; +// case Binary : vtypes[_discrete_constraints[i].first] = 2; break; +// default : break; +// } +// +// // GUROBI variables +// std::vector vars; +// // first all +// for( int i=0; i<_problem->n_unknowns(); ++i) +// switch(vtypes[i]) +// { +// case 0 : vars.push_back( model.addVar(-GRB_INFINITY, GRB_INFINITY, 0.0, GRB_CONTINUOUS) ); break; +// case 1 : vars.push_back( model.addVar(-GRB_INFINITY, GRB_INFINITY, 0.0, GRB_INTEGER ) ); break; +// case 2 : vars.push_back( model.addVar(-GRB_INFINITY, GRB_INFINITY, 0.0, GRB_BINARY ) ); break; +// } +// +// +// // Integrate new variables +// model.update(); +// +// //---------------------------------------------- +// // 2. setup constraints +// //---------------------------------------------- +// +// // get zero vector +// std::vector x(_problem->n_unknowns(), 0.0); +// +// for(unsigned int i=0; i<_constraints.size(); ++i) +// { +// if(!_constraints[i]->is_linear()) +// std::cerr << "Warning: GUROBISolver received a problem with non-linear constraints!!!" << std::endl; +// +// GRBLinExpr lin_expr; +// NConstraintInterface::SVectorNC gc; +// _constraints[i]->eval_gradient(P(x), gc); +// +// NConstraintInterface::SVectorNC::InnerIterator v_it(gc); +// for(; v_it; ++v_it) +//// lin_expr += v_it.value()*vars[v_it.index()]; +// lin_expr = lin_expr + vars[v_it.index()]*v_it.value(); +// +// double b = _constraints[i]->eval_constraint(P(x)); +// +// switch(_constraints[i]->constraint_type()) +// { +// case NConstraintInterface::NC_EQUAL : model.addConstr(lin_expr + b == 0); break; +// case NConstraintInterface::NC_LESS_EQUAL : model.addConstr(lin_expr + b <= 0); break; +// case NConstraintInterface::NC_GREATER_EQUAL : model.addConstr(lin_expr + b >= 0); break; +// } +// } +// model.update(); +// +// //---------------------------------------------- +// // 3. setup energy +// //---------------------------------------------- +// +// if(!_problem->constant_hessian()) +// std::cerr << "Warning: GUROBISolver received a problem with non-constant hessian!!!" << std::endl; +// +// GRBQuadExpr objective; +// +// // add quadratic part +// NProblemInterface::SMatrixNP H; +// _problem->eval_hessian(P(x), H); +// for( int i=0; i g(_problem->n_unknowns()); +// _problem->eval_gradient(P(x), P(g)); +// for(unsigned int i=0; ieval_f(P(x)); +// +// model.set(GRB_IntAttr_ModelSense, 1); +// model.setObjective(objective); +// model.update(); +// +// +// //---------------------------------------------- +// // 4. solve problem +// //---------------------------------------------- +// +// +// if (solution_input_path_.empty()) +// { +// if (!problem_env_output_path_.empty()) +// { +// std::cout << "Writing problem's environment into file \"" << problem_env_output_path_ << "\"." << std::endl; +// model.getEnv().writeParams(problem_env_output_path_); +// } +// if (!problem_output_path_.empty()) +// { +// std::cout << "Writing problem into file \"" << problem_output_path_ << "\"." << std::endl; +// GurobiHelper::outputModelToMpsGz(model, problem_output_path_); +// } +// +// model.optimize(); +// } +// else +// { +// std::cout << "Reading solution from file \"" << solution_input_path_ << "\"." << std::endl; +// } +// +// //---------------------------------------------- +// // 5. store result +// //---------------------------------------------- +// +// if (solution_input_path_.empty()) +// { +// // store computed result +// for(unsigned int i=0; i " << oldSize << " != " << x.size() << std::endl; +// throw std::runtime_error("Loaded solution vector doesn't have expected dimension."); +// } +// } +// +// _problem->store_result(P(x)); +// +// // ObjVal is only available if the optimize was called. +// if (solution_input_path_.empty()) +// std::cout << "GUROBI Objective: " << model.get(GRB_DoubleAttr_ObjVal) << std::endl; + return true; + } + catch (IloException& e) + { + cerr << "Concert exception caught: " << e << endl; + return false; + } + catch (...) + { + cerr << "Unknown exception caught" << endl; + return false; + } + + return false; +} + + +//----------------------------------------------------------------------------- + + +//void +//CPLEXSolver:: +//set_problem_output_path( const std::string &_problem_output_path) +//{ +// problem_output_path_ = _problem_output_path; +//} +// +// +////----------------------------------------------------------------------------- +// +// +//void +//CPLEXSolver:: +//set_problem_env_output_path( const std::string &_problem_env_output_path) +//{ +// problem_env_output_path_ = _problem_env_output_path; +//} +// +// +////----------------------------------------------------------------------------- +// +// +//void +//CPLEXSolver:: +//set_solution_input_path(const std::string &_solution_input_path) +//{ +// solution_input_path_ = _solution_input_path; +//} + + +//============================================================================= +} // namespace COMISO +//============================================================================= +#endif // COMISO_CPLEX_AVAILABLE +//============================================================================= diff --git a/CoMISo/NSolver/CPLEXSolver.hh b/CoMISo/NSolver/CPLEXSolver.hh new file mode 100644 index 0000000000000000000000000000000000000000..d04b7fa4006b2c162512ae72f1af2a479aeacf8e --- /dev/null +++ b/CoMISo/NSolver/CPLEXSolver.hh @@ -0,0 +1,96 @@ +//============================================================================= +// +// CLASS CPLEXSolver +// +//============================================================================= + + +#ifndef COMISO_CPLEXSOLVER_HH +#define COMISO_CPLEXSOLVER_HH + + +//== COMPILE-TIME PACKAGE REQUIREMENTS ======================================== +#include +#if COMISO_CPLEX_AVAILABLE + +//== INCLUDES ================================================================= + +#include +#include +#include +#include "NProblemInterface.hh" +#include "NConstraintInterface.hh" +#include "VariableType.hh" + +#include + +ILOSTLBEGIN + +//== FORWARDDECLARATIONS ====================================================== + +//== NAMESPACES =============================================================== + +namespace COMISO { + +//== CLASS DEFINITION ========================================================= + + + +/** \class NewtonSolver CPLEXSolver.hh + + Brief Description. + + A more elaborate description follows. +*/ +class COMISODLLEXPORT CPLEXSolver +{ +public: + + /// Default constructor + CPLEXSolver(); + + /// Destructor + ~CPLEXSolver() { cplex_env_.end();} + + // ********** SOLVE **************** // + bool solve(NProblemInterface* _problem, // problem instance + std::vector& _constraints, // linear constraints + std::vector& _discrete_constraints, // discrete constraints + const double _time_limit = 60 ); // time limit in seconds + +// void set_problem_output_path ( const std::string &_problem_output_path); +// void set_problem_env_output_path( const std::string &_problem_env_output_path); +// void set_solution_input_path ( const std::string &_solution_input_path); + +protected: + double* P(std::vector& _v) + { + if( !_v.empty()) + return ((double*)&_v[0]); + else + return 0; + } + +private: + + // CPLEX environment + IloEnv cplex_env_; + + // filenames for exporting/importing gurobi solutions + // if string is empty nothing is imported or exported +// std::string problem_output_path_; +// std::string problem_env_output_path_; +// std::string solution_input_path_; +}; + + + +//============================================================================= +} // namespace COMISO + +//============================================================================= +#endif // COMISO_CPLEX_AVAILABLE +//============================================================================= +#endif // ACG_CPLEXSOLVER_HH defined +//============================================================================= + diff --git a/CoMISo/NSolver/GUROBISolver.cc b/CoMISo/NSolver/GUROBISolver.cc index 8e6682aa3ba0078dde7c3966cb5c274955c76c5d..60b074bcf4c46945924db0bbdf516bea3271f2a0 100644 --- a/CoMISo/NSolver/GUROBISolver.cc +++ b/CoMISo/NSolver/GUROBISolver.cc @@ -36,7 +36,7 @@ bool GUROBISolver:: solve(NProblemInterface* _problem, std::vector& _constraints, - std::vector& _discrete_constraints, + std::vector& _discrete_constraints, const double _time_limit) { try diff --git a/CoMISo/NSolver/GUROBISolver.hh b/CoMISo/NSolver/GUROBISolver.hh index 13c34f457746f8050a0f0eae9c1774abb9106c2d..caf2c7a264963b59b80339a8daa16a08eb2132d5 100644 --- a/CoMISo/NSolver/GUROBISolver.hh +++ b/CoMISo/NSolver/GUROBISolver.hh @@ -44,8 +44,6 @@ namespace COMISO { class COMISODLLEXPORT GUROBISolver { public: - - typedef std::pair PairUiV; /// Default constructor GUROBISolver(); @@ -56,7 +54,7 @@ public: // ********** SOLVE **************** // bool solve(NProblemInterface* _problem, // problem instance std::vector& _constraints, // linear constraints - std::vector& _discrete_constraints, // discrete constraints + std::vector& _discrete_constraints, // discrete constraints const double _time_limit = 60 ); // time limit in seconds void set_problem_output_path ( const std::string &_problem_output_path); diff --git a/CoMISo/NSolver/VariableType.hh b/CoMISo/NSolver/VariableType.hh index 6fcff566d0c5ec9f216ea5a423d7425d0ecaa217..c818ce55544032e0113b065e7bd028e6babc9c53 100644 --- a/CoMISo/NSolver/VariableType.hh +++ b/CoMISo/NSolver/VariableType.hh @@ -24,6 +24,8 @@ namespace COMISO { enum VariableType { Real, Integer, Binary}; +typedef std::pair PairIndexVtype; + //============================================================================= } // namespace COMISO //============================================================================= diff --git a/CoMISo/cmake/FindCPLEX.cmake b/CoMISo/cmake/FindCPLEX.cmake index c43b8bd5c0a993f67cf35917d0cc59e4654c6208..7fb1eebe69a9d855e538f3dfce92750a5339419e 100644 --- a/CoMISo/cmake/FindCPLEX.cmake +++ b/CoMISo/cmake/FindCPLEX.cmake @@ -7,66 +7,42 @@ if (CPLEX_INCLUDE_DIR) # in cache already set(CPLEX_FOUND TRUE) + set(CPLEX_INCLUDE_DIRS "${CPLEX_INCLUDE_DIR};${CPLEX_CONCERT_INCLUDE_DIR}" ) + set(CPLEX_LIBRARIES "${CPLEX_LIBRARY};${CPLEX_ILO_LIBRARY};${CPLEX_CONCERT_LIBRARY}" ) else (CPLEX_INCLUDE_DIR) -if (WIN32) -#TODO ####################################################################### - - find_path(CPLEX_INCLUDE_DIR NAMES SRC/gurobi_c++.h - PATHS - "C:\\libs\\gurobi45" - ${GUROBI_INCLUDE_PATH} - ) - - find_library( GUROBI_LIBRARY_RELEASE - SuperLU - PATHS "C:\\libs\\gurobi45\\lib" ) - find_library( GUROBI_LIBRARY_DEBUG - SuperLUd - PATHS "C:\\libs\\gurobi45\\lib" ) - - - set ( GUROBI_LIBRARY "optimized;${GUROBI_LIBRARY_RELEASE};debug;${GUROBI_LIBRARY_DEBUG}" CACHE STRING "GUROBI Libraries" ) - -ELSEIF(APPLE) -#TODO ####################################################################### - find_path(GUROBI_INCLUDE_DIR NAMES gurobi_c++.h - PATHS "${CMAKE_SOURCE_DIR}/MacOS/Libs/gurobi40" - ${GUROBI_INCLUDE_PATH} - ) - - find_library( GUROBI_LIBRARY - SuperLU - PATHS "${CMAKE_SOURCE_DIR}/MacOS/Libs/gurobi40") - -ELSE( WIN32 ) - find_path(CPLEX_INCLUDE_DIR NAMES ilcplex/cplex.h - PATHS "$ENV{CPLEX_DIR}/cplex/include" - ) - find_path(CPLEX_CONCERT_INCLUDE_DIR NAMES ilconcert/ilomodel.h - PATHS "$ENV{CPLEX_DIR}/concert/include" - ) - - -# MESSAGE(STATUS "CPLEX include dir: ${CPLEX_INCLUDE_DIR}") -# MESSAGE(STATUS "CPLEX concert include dir: ${CPLEX_CONCERT_INCLUDE_DIR}") - - find_library( CPLEX_LIBRARY - cplex - PATHS "$ENV{CPLEX_DIR}/cplex/lib/x86-64_sles10_4.1/static_pic" ) - - find_library( CPLEX_ILO_LIBRARY - ilocplex - PATHS "$ENV{CPLEX_DIR}/cplex/lib/x86-64_sles10_4.1/static_pic" ) - - find_library( CPLEX_CONCERT_LIBRARY - concert - PATHS "$ENV{CPLEX_DIR}/concert/lib/x86-64_sles10_4.1/static_pic" ) -ENDIF() +find_path(CPLEX_INCLUDE_DIR + NAMES ilcplex/cplex.h + PATHS "$ENV{CPLEX_DIR}/cplex/include" + ) + +find_path(CPLEX_CONCERT_INCLUDE_DIR + NAMES ilconcert/ilomodel.h + PATHS "$ENV{CPLEX_DIR}/concert/include" + ) + +find_library( CPLEX_LIBRARY + cplex + PATHS "$ENV{CPLEX_DIR}/cplex/lib/x86-64_sles10_4.1/static_pic" + ) + +find_library( CPLEX_ILO_LIBRARY + ilocplex + PATHS "$ENV{CPLEX_DIR}/cplex/lib/x86-64_sles10_4.1/static_pic" + ) + +find_library( CPLEX_CONCERT_LIBRARY + concert + PATHS "$ENV{CPLEX_DIR}/concert/lib/x86-64_sles10_4.1/static_pic" + ) + set(CPLEX_INCLUDE_DIRS "${CPLEX_INCLUDE_DIR};${CPLEX_CONCERT_INCLUDE_DIR}" ) set(CPLEX_LIBRARIES "${CPLEX_LIBRARY};${CPLEX_ILO_LIBRARY};${CPLEX_CONCERT_LIBRARY}" ) +# use c++ headers as default +set(CPLEX_COMPILER_FLAGS "-DIL_STD" CACHE STRING "Cplex Compiler Flags") + include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LIBCPLEX_FOUND to TRUE # if all listed variables are TRUE