From 55be72ded87be15f16aaf90256fe863d9c0b265f Mon Sep 17 00:00:00 2001 From: Maroon502 Date: Sun, 28 Jan 2024 00:25:59 +0800 Subject: [PATCH] first version --- .github/workflows/release.yml | 11 + BonminCInterface/src/BonStdCInterface.cpp | 454 ++++++++++++++++++ BonminCInterface/src/BonStdCInterface.h | 210 ++++++++ .../src/BonStdInterfaceTMINLP.cpp | 348 ++++++++++++++ .../src/BonStdInterfaceTMINLP.hpp | 207 ++++++++ Cargo.toml | 3 +- Makefile | 6 - README.md | 2 + build.rs | 14 + 9 files changed, 1247 insertions(+), 8 deletions(-) create mode 100644 BonminCInterface/src/BonStdCInterface.cpp create mode 100644 BonminCInterface/src/BonStdCInterface.h create mode 100644 BonminCInterface/src/BonStdInterfaceTMINLP.cpp create mode 100644 BonminCInterface/src/BonStdInterfaceTMINLP.hpp delete mode 100644 Makefile diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dcdb154..9ff7165 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,6 +19,17 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Cache + uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo- - name: initial submodule run: git submodule update --init diff --git a/BonminCInterface/src/BonStdCInterface.cpp b/BonminCInterface/src/BonStdCInterface.cpp new file mode 100644 index 0000000..0d6e74e --- /dev/null +++ b/BonminCInterface/src/BonStdCInterface.cpp @@ -0,0 +1,454 @@ +// (C) Copyright Shaurya Sharma +// All Rights Reserved. +// This code is published under the Eclipse Public License. +// +// Authors : +// S. Sharma +// +// Date : 07.06.2015 + +#include "BonStdCInterface.h" +#include "BonStdInterfaceTMINLP.hpp" +#include "IpOptionsList.hpp" +#include "IpIpoptApplication.hpp" +#include "BonBonminSetup.hpp" +#include "BonCbc.hpp" + +using namespace Bonmin; +using namespace Ipopt; + + +//Note BonminSosInfo and BonminBranchingInfo are copied from BonTMINLP.hpp. This is not ideal +struct BonminSosInfo +{ +/** Number of SOS constraints.*/ + int num; + +/** Type of sos. At present Only type '1' SOS are supported by Cbc*/ + char * types; + +/** priorities of sos constraints.*/ + int * priorities; + +/** \name Sparse storage of the elements of the SOS constraints.*/ +/** @{ */ +/** Total number of non zeroes in SOS constraints.*/ + int numNz; +/** For 0 <= i < nums, start[i] gives the indice of indices and weights arrays at which the description of constraints i begins..*/ + int * starts; +/** indices of elements belonging to the SOS.*/ + int * indices; +/** weights of the elements of the SOS.*/ + double * weights; +}; + +struct BonminBranchingInfo +{ + /**number of variables*/ + int size; + /** User set priorities on variables. */ + int * priorities; + /** User set preferered branching direction. */ + int * branchingDirections; + /** User set up pseudo costs.*/ + double * upPsCosts; + /** User set down pseudo costs.*/ + double * downPsCosts; +}; + +struct BonminProblemInfo +{ + Index n; + Number* x_L; + Number* x_U; + Index m; + Number* g_L; + Number* g_U; + Index nele_jac; + Index nele_hess; + Index index_style; + Eval_F_CB eval_f; + Eval_G_CB eval_g; + Eval_Grad_F_CB eval_grad_f; + Eval_Jac_G_CB eval_jac_g; + Eval_H_CB eval_h; + VariableTypeC* var_types; + LinearityTypeC* var_linearity_types; + LinearityTypeC* constraint_linearity_types; + BonminBranchingInfo* branch_info; + BonminSosInfo* sos_info; + Intermediate_CB* intermediate_cb; + BonminSetup bonmin_setup; + Number obj_scaling; + Number* x_scaling; + Number* g_scaling; +}; + +BonminProblem CreateBonminProblem( + Index n + , Number* x_L + , Number* x_U + , Index m + , Number* g_L + , Number* g_U + , Index nele_jac + , Index nele_hess + , Index index_style + , Eval_F_CB eval_f + , Eval_G_CB eval_g + , Eval_Grad_F_CB eval_grad_f + , Eval_Jac_G_CB eval_jac_g + , Eval_H_CB eval_h + , VariableTypeC* var_types + , LinearityTypeC* var_linearity_types + , LinearityTypeC* constraint_linearity_types + , BonminSosInfo* sos_info + , BonminBranchingInfo* branch_info ) +{ + if ( n<1 || m<0 || !x_L || !x_U || (m>0 && (!g_L || !g_U)) || + (m==0 && nele_jac != 0) || (m>0 && nele_jac < 1) || nele_hess < 0 || + !eval_f || !eval_grad_f || (m>0 && (!eval_g || !eval_jac_g)) || + !var_types || !var_linearity_types || (m>0 && !constraint_linearity_types) ) + { + return NULL; + } + BonminProblem retval = new BonminProblemInfo; + + retval->n = n; + retval->x_L = new Number[n]; + + for (Index i=0; ix_L[i] = x_L[i]; + } + retval->x_U = new Number[n]; + for (Index i=0; ix_U[i] = x_U[i]; + } + + retval->m = m; + if (m>0) + { + retval->g_L = new Number[m]; + for (Index i=0; ig_L[i] = g_L[i]; + } + retval->g_U = new Number[m]; + for (Index i=0; ig_U[i] = g_U[i]; + } + } + else + { + retval->g_L = NULL; + retval->g_U = NULL; + } + + retval->var_types = new VariableTypeC[n]; + retval->var_linearity_types = new LinearityTypeC[n]; + retval->constraint_linearity_types = new LinearityTypeC[m]; + for (int i = 0; i < n; ++i) + { + retval->var_types[i] = var_types[i]; + retval->var_linearity_types[i] = var_linearity_types[i]; + } + for (int i = 0; i < m; ++i) + { + retval->constraint_linearity_types[i] = constraint_linearity_types[i]; + } + + retval->nele_jac = nele_jac; + retval->nele_hess = nele_hess; + retval->index_style = index_style; + retval->eval_f = eval_f; + retval->eval_g = eval_g; + retval->eval_grad_f = eval_grad_f; + retval->eval_jac_g = eval_jac_g; + retval->eval_h = eval_h; + retval->intermediate_cb = NULL; + + retval->obj_scaling = 1; + retval->x_scaling = NULL; + retval->g_scaling = NULL; + + retval->bonmin_setup.initializeOptionsAndJournalist(); + + return retval; +} + +void FreeBonminProblem(BonminProblem bonmin_problem) +{ + if (bonmin_problem == NULL) + { + return; + } + + delete [] bonmin_problem->x_L; + delete [] bonmin_problem->x_U; + delete [] bonmin_problem->var_types; + delete [] bonmin_problem->var_linearity_types; + if (bonmin_problem->m>0) + { + delete [] bonmin_problem->constraint_linearity_types; + delete [] bonmin_problem->g_L; + delete [] bonmin_problem->g_U; + } + + if(bonmin_problem->x_scaling != NULL) + { + delete [] bonmin_problem->x_scaling; + } + if(bonmin_problem->g_scaling != NULL) + { + delete [] bonmin_problem->g_scaling; + } + + delete bonmin_problem; +} + +Bool AddBonminStrOption(BonminProblem bonmin_problem, char* keyword, char* val) +{ + std::string tag( keyword ); + std::string value( val ); + return (Bool) bonmin_problem->bonmin_setup.options()->SetStringValue( tag, value ); +} + +Bool AddBonminNumOption(BonminProblem bonmin_problem, char* keyword, Number val) +{ + std::string tag(keyword); + Number value=val; + return (Bool) bonmin_problem->bonmin_setup.options()->SetNumericValue( tag, value ); +} + +Bool AddBonminIntOption(BonminProblem bonmin_problem, char* keyword, Int val) +{ + std::string tag(keyword); + Index value=val; + return (Bool) bonmin_problem->bonmin_setup.options()->SetIntegerValue( tag, value ); +} +Bool ReadBonminOptString( BonminProblem bonmin_problem, char* option ) +{ + std::string opt_string( option ); + bonmin_problem->bonmin_setup.readOptionsString( opt_string ); + return TRUE; +} + +Bool ReadBonminOptFile( BonminProblem bonmin_problem, char* file_path ) +{ + std::string file_path_str( file_path ); + if( file_path_str.compare( "" ) == 0 ) + { + bonmin_problem->bonmin_setup.readOptionsFile(); + } + else + { + bonmin_problem->bonmin_setup.readOptionsFile(file_path_str); + } + return TRUE; +} + +Bool OpenBonminOutputFile(BonminProblem bonmin_problem, char* file_name, Int print_level) +{ + // TODO + // std::string name(file_name); + // EJournalLevel level = EJournalLevel(print_level); + // return (Bool) bonmin_problem->bonmin_setup.options()->OpenOutputFile(name, level); + return ( Bool )true; +} + +Bool SetBonminProblemScaling(BonminProblem bonmin_problem, + Number obj_scaling, + Number* x_scaling, + Number* g_scaling) +{ + bonmin_problem->obj_scaling = obj_scaling; + if (x_scaling) + { + if (!bonmin_problem->x_scaling) + { + bonmin_problem->x_scaling = new Number[bonmin_problem->n]; + } + for (Index i=0; in; i++) + { + bonmin_problem->x_scaling[i] = x_scaling[i]; + } + } + else + { + delete [] bonmin_problem->x_scaling; + bonmin_problem->x_scaling = NULL; + } + if (g_scaling) + { + if (!bonmin_problem->g_scaling) + { + bonmin_problem->g_scaling = new Number[bonmin_problem->m]; + } + for (Index i=0; im; i++) + { + bonmin_problem->g_scaling[i] = g_scaling[i]; + } + } + else + { + delete [] bonmin_problem->g_scaling; + bonmin_problem->g_scaling = NULL; + } + + return (Bool)true; +} + +Int BonminSolve( + BonminProblem bonmin_problem +, Number* x +, Number* g +, Number* obj_val +, Number* mult_g +, Number* mult_x_L +, Number* mult_x_U +, UserDataPtr user_data) +{ + // TODO return a meaningful status code + // Initialize and process options + // ApplicationReturnStatus retval = ipopt_problem->app->Initialize(); + // if (retval!=Solve_Succeeded) { + // return (::ApplicationReturnStatus) retval; + // } + + if (!x) { + return 0; + // ipopt_problem->app->Jnlst()->Printf(J_ERROR, J_MAIN, + // "Error: Array x with starting point information is NULL."); + // return (::ApplicationReturnStatus) Invalid_Problem_Definition; + } + + // Copy the starting point information + Number* start_x = new Number[bonmin_problem->n]; + for (Index i=0; in; i++) + { + start_x[i] = x[i]; + } + Number* start_lam = NULL; + if (mult_g) + { + start_lam = new Number[bonmin_problem->m]; + for (Index i=0; im; i++) + { + start_lam[i] = mult_g[i]; + } + } + Number* start_z_L = NULL; + if (mult_x_L) + { + start_z_L = new Number[bonmin_problem->n]; + for (Index i=0; in; i++) + { + start_z_L[i] = mult_x_L[i]; + } + } + Number* start_z_U = NULL; + if (mult_x_U) + { + start_z_U = new Number[bonmin_problem->n]; + for (Index i=0; in; i++) + { + start_z_U[i] = mult_x_U[i]; + } + } + + + // convert from C type enum to C++ enum + TMINLP::VariableType* variable_types = new TMINLP::VariableType[bonmin_problem->n]; + TNLP::LinearityType* variable_linearity_types = new TNLP::LinearityType[bonmin_problem->n]; + for (Index i=0; in; i++) + { + variable_types[i] = static_cast( (int)bonmin_problem->var_types[i] ); // yikes + variable_linearity_types[i] = static_cast( (int)bonmin_problem->var_linearity_types[i] ); // yikes + } + + TNLP::LinearityType* constraint_linearity_types = NULL; + if( bonmin_problem->m > 0 ) + { + constraint_linearity_types = new TNLP::LinearityType[bonmin_problem->m]; + for (Index i=0; im; i++) + { + constraint_linearity_types[i] = static_cast( (int)bonmin_problem->constraint_linearity_types[i] ); // yikes + } + } + + + SmartPtr tminlp; + SmartPtr interfaceTMINLP; + try + { + interfaceTMINLP = new StdInterfaceTMINLP(bonmin_problem->n, bonmin_problem->x_L, + bonmin_problem->x_U, bonmin_problem->m, + bonmin_problem->g_L, bonmin_problem->g_U, + bonmin_problem->nele_jac, + bonmin_problem->nele_hess, + bonmin_problem->index_style, + start_x, start_lam, start_z_L, start_z_U, + bonmin_problem->eval_f, bonmin_problem->eval_g, + bonmin_problem->eval_grad_f, + bonmin_problem->eval_jac_g, + bonmin_problem->eval_h, + variable_types, + variable_linearity_types, + constraint_linearity_types, + // bonmin_problem->intermediate_cb, + x, mult_x_L, mult_x_U, g, mult_g, + obj_val, user_data, + bonmin_problem->obj_scaling, + bonmin_problem->x_scaling, + bonmin_problem->g_scaling); + + if( bonmin_problem->sos_info != NULL ) + { + interfaceTMINLP->getSosInfo()->num = bonmin_problem->sos_info->num; + interfaceTMINLP->getSosInfo()->types = bonmin_problem->sos_info->types; + interfaceTMINLP->getSosInfo()->priorities = bonmin_problem->sos_info->priorities; + interfaceTMINLP->getSosInfo()->numNz = bonmin_problem->sos_info->numNz; + interfaceTMINLP->getSosInfo()->starts = bonmin_problem->sos_info->starts; + interfaceTMINLP->getSosInfo()->indices = bonmin_problem->sos_info->indices; + interfaceTMINLP->getSosInfo()->weights = bonmin_problem->sos_info->weights; + } + + if ( bonmin_problem->branch_info != NULL ) + { + interfaceTMINLP->getBranchingInfo()->size = bonmin_problem->branch_info->size; + interfaceTMINLP->getBranchingInfo()->priorities = bonmin_problem->branch_info->priorities; + interfaceTMINLP->getBranchingInfo()->branchingDirections = bonmin_problem->branch_info->branchingDirections; + interfaceTMINLP->getBranchingInfo()->upPsCosts = bonmin_problem->branch_info->upPsCosts; + interfaceTMINLP->getBranchingInfo()->downPsCosts = bonmin_problem->branch_info->downPsCosts; + + } + + + tminlp = interfaceTMINLP; + + bonmin_problem->bonmin_setup.initialize( GetRawPtr( tminlp ) ); + Bab branch_and_bound; + branch_and_bound( bonmin_problem->bonmin_setup ); + } + catch(TNLPSolver::UnsolvedError *E) + { + std::cerr<<"Bonmin has failed to solve a problem"< jnlst_; */ + + /** @name Information about the problem */ + //@{ + /** Ipopt::Number of variables */ + const Ipopt::Index n_var_; + /** Ipopt::Number of constraints */ + const Ipopt::Index n_con_; + /** Pointer to Ipopt::Number array containing lower bounds for variables */ + const Ipopt::Number* x_L_; + /** Pointer to Ipopt::Number array containing upper bounds for variables */ + const Ipopt::Number* x_U_; + /** Pointer to Ipopt::Number array containing lower bounds for constraints */ + const Ipopt::Number* g_L_; + /** Pointer to Ipopt::Number array containing upper bounds for constraints */ + const Ipopt::Number* g_U_; + /** Ipopt::Number of non-zero elements in the constraint Jacobian */ + const Ipopt::Index nele_jac_; + /** Ipopt::Number of non-zero elements in the Hessian */ + const Ipopt::Index nele_hess_; + /** Starting value of the iRow and jCol parameters for matrices */ + const Ipopt::Index index_style_; + /** Pointer to Ipopt::Number array containing starting point for variables */ + const Ipopt::Number* start_x_; + /** Poitner to Ipopt::Number array containing starting values for + * constraint multipliers */ + const Ipopt::Number* start_lam_; + /** Pointer to Ipopt::Number array containing starting values for lower + * bound multipliers */ + const Ipopt::Number* start_z_L_; + /** Pointer to Ipopt::Number array containing starting values for upper + * bound multipliers */ + const Ipopt::Number* start_z_U_; + /** Pointer to callback function evaluating value of objective function */ + Eval_F_CB eval_f_; + /** Pointer to callback function evaluating value of constraints */ + Eval_G_CB eval_g_; + /** Pointer to callback function evaluating gradient of objective + * function */ + Eval_Grad_F_CB eval_grad_f_; + /** Pointer to callback function evaluating Jacobian of constraints */ + Eval_Jac_G_CB eval_jac_g_; + + /** Pointer to callback function evaluating Hessian of Lagrangian */ + Eval_H_CB eval_h_; + + VariableType* var_types_; + + Ipopt::TNLP::LinearityType* var_linearity_types_; + + Ipopt::TNLP::LinearityType* constraint_linearity_types_; + + /** Pointer to intermediate callback function giving control to user */ + Intermediate_CB intermediate_cb_; + + /** Storage of branching priorities information.*/ + BranchingInfo* branch_info_; + + /** Storage of sos constraints */ + SosInfo* sos_info_; + + /** Pointer to user data */ + UserDataPtr user_data_; + /** Objective scaling factor */ + Ipopt::Number obj_scaling_; + /** Scaling factors for variables (if not NULL) */ + const Ipopt::Number* x_scaling_; + /** Scaling factors for constraints (if not NULL) */ + const Ipopt::Number* g_scaling_; + //@} + + + /** A non-const copy of x - this is kept up-to-date in apply_new_x */ + Ipopt::Number* non_const_x_; + + /** Pointers to the user provided vectors for solution */ + Ipopt::Number* x_sol_; + Ipopt::Number* z_L_sol_; + Ipopt::Number* z_U_sol_; + Ipopt::Number* g_sol_; + Ipopt::Number* lambda_sol_; + Ipopt::Number* obj_sol_; + + // /** Default Constructor */ + // StdInterfaceTMINLP(); + + // /** Copy Constructor */ + // StdInterfaceTMINLP(const StdInterfaceTMINLP&); + + // /** Overloaded Equals Operator */ + // void operator=(const StdInterfaceTMINLP&); + // //@} + }; +} + + +#endif // BONSTDINTERFACETMINLP_HPP diff --git a/Cargo.toml b/Cargo.toml index 198f5c3..cd1f359 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,9 +15,8 @@ authors = [ ] exclude = [ "Bonmin/**/*", - "!Bonmin/src/**/*", + "!Bonmin/Bonmin/src/**/*", "!**/LICENSE", - "!**/AUTHORS", ] [features] diff --git a/Makefile b/Makefile deleted file mode 100644 index 0e1ae95..0000000 --- a/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -include Bonmin/src.mk - -bonmin_lib_sources.txt: Bonmin/src.mk - @echo -n "${LIB_SOURCES}" | tr ' ' '\n' > bonmin_lib_sources.txt - -gen_lib_sources: bonmin_lib_sources.txt \ No newline at end of file diff --git a/README.md b/README.md index 30049c5..dec8e72 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,8 @@ By this package, you don't need to worry about installing Bonmin in the system, This package does not provide bindings. Please use [coinbonmin-sys] to use Bonmin, e.g. +> Note: The C interface is taken from the master branch of [Bonmin], which is still has a number of todos. + ## Configuration The following Cargo features are supported: diff --git a/build.rs b/build.rs index 804562e..c8a3526 100644 --- a/build.rs +++ b/build.rs @@ -35,6 +35,14 @@ fn build_lib_and_link() { .display() ); + let src_dir_interface = format!( + "{}", + PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("BonminCInterface") + .join("src") + .display() + ); + let mut includes_dir = vec![ format!("{}/Algorithms", src_dir), format!("{}/Algorithms/Branching", src_dir), @@ -53,6 +61,12 @@ fn build_lib_and_link() { .map(|file| format!("{}/{}", src_dir, file.trim())) .collect::>(); + includes_dir.push(src_dir_interface.to_string()); + lib_sources.extend(vec![ + format!("{}/BonStdCInterface.cpp", src_dir_interface), + format!("{}/BonStdInterfaceTMINLP.cpp", src_dir_interface), + ]); + let mut coinflags = vec!["Bonmin".to_string()]; if cfg!(feature = "filtersqp") {