Bonmin
Bonmin copied to clipboard
segfault with bound_relax_factor=0.0 on macos
I'm using the bound_relax_factor set to 0 to enforce strict bounds in my program but I got a crash on macos only (clang 17), here is a minimal program to reproduce it based on the c++ example but rewritten with dense matrices:
#include <BonBonminSetup.hpp>
#include <BonCbc.hpp>
#include <BonminConfig.h>
#include <BonTMINLP.hpp>
#include <IpTNLP.hpp>
typedef ::Bonmin::TMINLP::VariableType * VariableTypeTable;
typedef ::Ipopt::TNLP::LinearityType * LinearityTypeTable;
class MyTMINLP
: public ::Bonmin::TMINLP
{
public:
/** Constructor with parameters */
MyTMINLP() : ::Bonmin::TMINLP() {}
bool get_nlp_info(int & n,
int & m,
int & nnz_jac_g, // Number of non-zero components in the Jacobian of g
int & nnz_h_lag, // Number of non-zero components in Hessian of Lagrangean
::Ipopt::TNLP::IndexStyleEnum & index_style)
{
m = 3;
n = 4;
// All components of the jacobian and lagrangian's hessian are assumed to be non-zero
nnz_jac_g = n * m;
nnz_h_lag = n * n;
// Index style is C-like
index_style = ::Ipopt::TNLP::C_STYLE;
return true;
}
bool get_variables_types( int n,
VariableTypeTable var_types)
{
var_types[0] = ::Bonmin::TMINLP::BINARY;
var_types[1] = ::Bonmin::TMINLP::CONTINUOUS;
var_types[2] = ::Bonmin::TMINLP::CONTINUOUS;
var_types[3] = ::Bonmin::TMINLP::INTEGER;
return true;
}
bool get_variables_linearity( int n,
LinearityTypeTable var_types)
{
var_types[0] = ::Ipopt::TNLP::LINEAR;
var_types[1] = ::Ipopt::TNLP::NON_LINEAR;
var_types[2] = ::Ipopt::TNLP::NON_LINEAR;
var_types[3] = ::Ipopt::TNLP::LINEAR;
return true;
}
bool get_constraints_linearity( int m, LinearityTypeTable const_types)
{
return true;
}
bool get_bounds_info( int n,
double* x_l,
double* x_u,
int m,
double* g_l,
double* g_u)
{
for (int i = 0; i < n; ++i)
{
x_l[i] = 0.0;
x_u[i] = std::numeric_limits<double>::max();
}
x_u[0] = 1.0;
x_u[3] = 5.0;
for (int i = 0; i < 3; ++i)
{
g_l[i] = 0.0; // OT constraints are expressed as g(x) = 0 and h(x) >= 0
g_u[i] = std::numeric_limits<double>::max();
}
return true;
}
bool get_starting_point(int n,
bool init_x,
double* x,
bool init_z,
double* z_L,
double* z_U,
int m,
bool init_lambda,
double* lambda)
{
for (int i=0;i <4; ++i)
x[i] = 0.0;
return true;
}
bool eval_f(int n,
const double* x,
bool new_x,
double& obj_value)
{
obj_value = -x[0] -x[1] -x[2];
static int ncalls = 0;
++ ncalls;
return ncalls <= 10000;
}
bool eval_grad_f( int n,
const double* x,
bool new_x,
double* grad_f)
{
grad_f[0] = -1.0;
grad_f[1] = -1.0;
grad_f[2] = -1.0;
return true;
}
bool eval_g(int n,
const double* x,
bool new_x,
int m,
double* g)
{
g[0] = -(x[1] - 0.5)*(x[1] - 0.5) - (x[2] - 0.5)*(x[2] - 0.5) + 0.25;
g[1] = -x[0] +x[1];
g[2] = -x[0] -x[2]-x[3] + 2.0;
return true;
}
bool eval_jac_g(int n,
const double* x,
bool new_x,
int m,
int nele_jac,
int* iRow,
int *jCol,
double* values)
{
/* Switch on first call / later calls */
if (values == NULL)
{
// First call: initialization of iRow/jCol
int k = 0;
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
{
iRow[k] = i;
jCol[k] = j;
++k;
}
}
else // Later calls
{
for (int i = 0; i < 12; ++i)
values[i] = 0.0;
values[1] = -2.0*(x[1]-0.5);
values[2] = -2.0*(x[2]-0.5);
values[4] = -1.0;
values[5] = 1.0;
values[8] = -1.0;
values[10] = -1.0;
values[11] = -1.0;
}
return true;
}
bool eval_h(int n,
const double* x,
bool new_x,
double obj_factor,
int m,
const double* lambda,
bool new_lambda,
int nele_hess,
int* iRow,
int* jCol,
double* values)
{
/* Switch on first call / later calls */
if (values == NULL) // First call: initialization of iRow/jCol
{
int k = 0;
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
{
iRow[k] = i;
jCol[k] = j;
++k;
}
}
else // Later calls
{
int k = 0;
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
{
values[k] = 0.0;
++k;
}
values[5] = -2.0 * lambda[0];
values[10] = -2.0 * lambda[0];
}
return true;
}
bool eval_gi(int n,
const double* x,
bool new_x,
int i,
double& gi)
{
return true;
}
bool eval_grad_gi(int n,
const double* x,
bool new_x,
int i,
int& nele_grad_gi,
int* jCol,
double* values)
{
return true;
}
void finalize_solution( ::Bonmin::TMINLP::SolverReturn status,
::Ipopt::Index n,
const ::Ipopt::Number* x,
::Ipopt::Number obj_value)
{
status_ = status;
}
const ::Bonmin::TMINLP::BranchingInfo * branchingInfo() const
{
return NULL;
};
const ::Bonmin::TMINLP::SosInfo * sosConstraints() const
{
return NULL;
};
::Bonmin::TMINLP::SolverReturn getStatus() const
{
return status_;
}
private:
::Bonmin::TMINLP::SolverReturn status_;
};
int main()
{
::Ipopt::SmartPtr<MyTMINLP> tminlp = new MyTMINLP();
::Bonmin::BonminSetup app;
app.initializeOptionsAndJournalist();
app.options()->SetStringValue("bonmin.algorithm", "B-BB");
app.options()->SetNumericValue("bound_relax_factor", 0.0);
// Update setup with MyTMINLP
try
{
app.initialize(GetRawPtr(tminlp));
// Solve problem
::Bonmin::Bab solver;
solver(app);
}
catch (::Bonmin::TNLPSolver::UnsolvedError *exc)
{
return 1;
}
catch(const ::Bonmin::OsiTMINLPInterface::SimpleError & exc)
{
return 1;
}
catch(const CoinError & exc)
{
return 1;
}
// print used options
std::string optionsLog;
app.options()->PrintList(optionsLog);
std::cout << optionsLog << std::endl;
return 0;
}
here some some of the trace, I tried to debug it and it seems it boild down to the continousSolver_ attribute being freed several times:
2024-10-24T13:12:29.7453620Z (lldb) process launch
2024-10-24T13:12:30.3710190Z
2024-10-24T13:12:30.3711250Z ******************************************************************************
2024-10-24T13:12:30.3712160Z This program contains Ipopt, a library for large-scale nonlinear optimization.
2024-10-24T13:12:30.3713140Z Ipopt is released as open source code under the Eclipse Public License (EPL).
2024-10-24T13:12:30.3713860Z For more information visit https://github.com/coin-or/Ipopt
2024-10-24T13:12:30.3714440Z ******************************************************************************
2024-10-24T13:12:30.3714820Z
2024-10-24T13:12:30.5555360Z NLP0012I
2024-10-24T13:12:30.5556220Z Num Status Obj It time Location
2024-10-24T13:12:30.5556870Z NLP0014I 1 OPT -2.618034 17 0.28445
2024-10-24T13:12:30.5978020Z NLP0012I
2024-10-24T13:12:30.5979220Z Num Status Obj It time Location
2024-10-24T13:12:30.5980570Z NLP0014I 1 OPT -1.7071068 5 0.080399
2024-10-24T13:12:30.6474980Z NLP0012I
2024-10-24T13:12:30.6476040Z Num Status Obj It time Location
2024-10-24T13:12:30.6477150Z NLP0014I 1 OPT -1.7071068 4 0.071529
2024-10-24T13:12:30.6478410Z Cbc0012I Integer solution of -1.7071068 found by DiveMIPFractional after 0 iterations and 0 nodes (0.16 seconds)
2024-10-24T13:12:30.6954460Z NLP0014I 2 OPT -2.618034 5 0.080884
2024-10-24T13:12:30.7782900Z NLP0014I 3 OPT -2 9 0.177716
2024-10-24T13:12:30.8344660Z NLP0014I 4 OPT -1.7071068 5 0.10837
2024-10-24T13:12:31.1507680Z NLP0014I 5 OPT -2.5 38 0.621345
2024-10-24T13:12:31.5107530Z NLP0014I 6 OPT -2.5 38 0.542727
2024-10-24T13:12:31.5109460Z Cbc0010I After 0 nodes, 1 on tree, -1.7071068 best solution, best possible -2.5 (1.69 seconds)
2024-10-24T13:12:31.8530360Z NLP0014I 7 OPT -2.5 36 0.402693
2024-10-24T13:12:32.2198180Z Process 67939 launched: '$SRC_DIR/build/lib/test/t_Bonmin_std' (x86_64)
2024-10-24T13:12:32.2199070Z Process 67939 stopped
2024-10-24T13:12:32.2201380Z * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xfffffe4085f60000)
2024-10-24T13:12:32.2202640Z frame #0: 0xfffffe4085f60000
2024-10-24T13:12:32.2204290Z error: memory read failed for 0xfffffe4085f60000
2024-10-24T13:12:32.2205480Z (lldb) bt
2024-10-24T13:12:32.2608770Z * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xfffffe4085f60000)
2024-10-24T13:12:32.2610580Z * frame #0: 0xfffffe4085f60000
2024-10-24T13:12:32.2611810Z frame #1: 0x0000000100b4a5b0 libCbc.3.dylib`CbcModel::resetModel(this=0x00007ff7bfefa8d8) at CbcModel.cpp:7052:3 [opt]
2024-10-24T13:12:32.2612570Z frame #2: 0x0000000100b4a561 libCbc.3.dylib`CbcModel::gutsOfDestructor2(this=<unavailable>) at CbcModel.cpp:7039:3 [opt] [artificial]
2024-10-24T13:12:32.2613320Z frame #3: 0x0000000100b4a2f8 libCbc.3.dylib`CbcModel::gutsOfDestructor(this=<unavailable>) at CbcModel.cpp:7013:3 [opt] [artificial]
2024-10-24T13:12:32.2614510Z frame #4: 0x0000000100b4a379 libCbc.3.dylib`CbcModel::~CbcModel(this=0x00007ff7bfefa8d8) at CbcModel.cpp:6976:3 [opt]
2024-10-24T13:12:32.2615200Z frame #5: 0x0000000100001d19 t_Bonmin_std`main at t_Bonmin_std.cxx:278:3 [opt]
2024-10-24T13:12:32.2615740Z frame #6: 0x000000010000c52e dyld`start + 462
2024-10-24T13:12:32.2616190Z (lldb) quit
I'm using the latest stable bonmin 1.8.9, ipopt 3.14.16, cbc 2.10.12 etc
it also works if I set the input variable upper bounds to 1e6 for example instead of numeric_limits::max<double>