BonFpForMinlp.cpp
Go to the documentation of this file.
1 // (C) Copyright CNRS 2008
2 // All Rights Reserved.
3 // This code is published under the Eclipse Public License.
4 //
5 // Authors :
6 // P. Bonami, CNRS
7 //
8 // Date : 02/13/2009
9 
10 #include "BonFpForMinlp.hpp"
11 #include "BonminConfig.h"
12 
13 #include "OsiClpSolverInterface.hpp"
14 
15 #include "CbcModel.hpp"
16 #include "BonCbcLpStrategy.hpp"
17 #ifdef COIN_HAS_CPX
18 #include "OsiCpxSolverInterface.hpp"
19 #endif
20 #include "OsiAuxInfo.hpp"
21 #include "BonSolverHelp.hpp"
22 
23 #include <climits>
24 
25 namespace Bonmin
26 {
27  static const char * txt_id = "FP for MINLP";
30  OaDecompositionBase(b, true, false),
31  subMip_(NULL)
32  {
33  std::string bonmin="bonmin.";
34  std::string prefix = (b.prefix() == bonmin) ? "" : b.prefix();
35  prefix += "pump_for_minlp.";
36  subMip_ = new SubMipSolver(b, prefix);
37  double oaTime;
38  b.options()->GetNumericValue("time_limit",oaTime,prefix);
39  parameter().maxLocalSearch_ = INT_MAX;
40  b.options()->GetIntegerValue("solution_limit", parameter().maxSols_,prefix);
42  std::min(b.getDoubleParameter(BabSetupBase::MaxTime), oaTime);
45  b.options()->GetEnumValue("fp_pass_infeasible", passBound_, prefix);
46  }
47 
49  {
50  delete subMip_;
51  }
52 
54  bool
56  {
58  CoinCpuTime() - timeBegin_ < parameters_.maxLocalSearchTime_ &&
60  }
62  double
64  solverManip &lpManip,
65  BabInfo * babInfo,
66  double & cutoff,const CglTreeInfo &info) const
67  {
68 
69  //bool interuptOnLimit = false;
70  //double lastPeriodicLog = CoinCpuTime();
71 
72  const int numcols = nlp_->getNumCols();
73  vector<double> savedColLower(nlp_->getNumCols());
74  CoinCopyN(nlp_->getColLower(), nlp_->getNumCols(), savedColLower());
75  vector<double> savedColUpper(nlp_->getNumCols());
76  CoinCopyN(nlp_->getColUpper(), nlp_->getNumCols(), savedColUpper());
77 
78 
79  subMip_->setLpSolver(lpManip.si());
80  OsiSolverInterface * lp = subMip_->solver();
81 
82  assert(lp);
83  vector<int> indices;
84  for(int i = 0; i < numcols ; i++) {
85  lp->setObjCoeff(i,0);
86  if(!lp->isInteger(i)) {
87  }
88  else { indices.push_back(i);}
89  }
90 
91  // If objective is linear need to add to lp constraint for objective
92  const double * colsol = NULL;
93  lp->resolve();
94  OsiBranchingInformation branch_info(lp, false);
95  branch_info.lower_ = savedColLower();
96  branch_info.upper_ = savedColUpper();
97  if(lp->getNumCols() == nlp_->getNumCols())
99  lp->setObjCoeff(numcols,0);
100 
101  bool milpOptimal = false;
102  nlp_->resolve(txt_id);
104  lp->initialSolve();
105  lp->setColUpper(numcols, cutoff);
107  //subMip_->optimize(DBL_MAX, parameters_.subMilpLogLevel_,
108  (parameters_.maxLocalSearchTime_ + timeBegin_ - CoinCpuTime()) /* time limit */);
109 
110  milpOptimal = subMip_ -> optimal();
111  colsol = subMip_->getLastSolution();
112  nLocalSearch_++;
113  if(milpOptimal)
115  <<subMip_->nodeCount()<<subMip_->iterationCount()<<CoinMessageEol;
116  else
118  <<subMip_->nodeCount()<<subMip_->iterationCount()<<CoinMessageEol;
119  int numberPasses = 0;
120 
121 #ifdef OA_DEBUG
122  bool foundSolution = 0;
123 #endif
124  double * nlpSol = NULL;
125  int major_iteration = 0;
126  double ub = cutoff;
127  while (colsol) {
128  numberPasses++;
129 
130  //setup the nlp
131  int numberCutsBefore = cs.sizeRowCuts();
132 
133  //Fix the variable which have to be fixed, after having saved the bounds
134  branch_info.solution_ = colsol;
135 
136  vector<double> x_bar(indices.size());
137  for(unsigned int i = 0 ; i < indices.size() ; i++){
138  assert(fabs(colsol[indices[i]] - floor(colsol[indices[i]] + 0.5)) < 1e-5);
139  x_bar[i] = colsol[indices[i]];
140  }
141 
142  double dist = nlp_->solveFeasibilityProblem(indices.size(), x_bar(), indices(), 1, 0, 2);
143 
144  handler_->message(FP_DISTANCE, messages_)
145  <<dist<<CoinMessageEol;
146 
147  if(dist < 1e-06){
149 
150  nlp_->resolve(txt_id);
151  if(!nlp_->isProvenOptimal()){
153  nlp_->resolve(txt_id);
154  }
155  bool restart = false;
156  if (post_nlp_solve(babInfo, cutoff)) {
157  restart = true;
158  //nlp is solved and feasible
159  // Update the cutoff
160  ub = std::min(ub, nlp_->getObjValue());
161  cutoff = ub * (1 - parameters_.cbcCutoffIncrement_);
162 
163  numSols_++;
164  }
165  else{
166  //nlp_->setColLower(savedColLower());
167  //nlp_->setColUpper(savedColUpper());
168  //dist = nlp_->solveFeasibilityProblem(indices.size(), x_bar(), indices(), 1, 0, 2);
169  }
170  nlpSol = const_cast<double *>(nlp_->getColSolution());
171  nlp_->getOuterApproximation(cs, nlpSol, 1, NULL,
172  parameter().global_);
173  //if(restart){
174  nlp_->setColLower(savedColLower());
175  nlp_->setColUpper(savedColUpper());
176  if(restart){
177  major_iteration++;
179  <<major_iteration<<cutoff<<CoinMessageEol;
180  nlp_->resolve(txt_id);
181  }
182 
183  //}
184  }
185  else {
186  nlpSol = const_cast<double *>(nlp_->getColSolution());
187  nlp_->getOuterApproximation(cs, nlpSol, 1, NULL,
188  parameter().global_);
189  }
190 
191 
192 #if 0
194  <<nLocalSearch_<<cutoff<<CoinMessageEol;
195 #endif
196 
197  int numberCuts = cs.sizeRowCuts() - numberCutsBefore;
198  assert(numberCuts);
199  installCuts(*lp, cs, numberCuts);
200  numberCutsBefore = cs.sizeRowCuts();
201 
202  //check time
203  if (CoinCpuTime() - timeBegin_ > parameters_.maxLocalSearchTime_){
204  colsol = NULL;
205  break;
206  }
207  //do we perform a new local search ?
210 
211  nLocalSearch_++;
213 
214  lp->setColUpper(numcols, cutoff);
215 
217  // subMip_->optimize(DBL_MAX, parameters_.subMilpLogLevel_,
218  parameters_.maxLocalSearchTime_ + timeBegin_ - CoinCpuTime());
219  milpOptimal = subMip_ -> optimal();
220  colsol = subMip_->getLastSolution();
221  if(milpOptimal)
222  handler_->message(SOLVED_LOCAL_SEARCH, messages_)<<subMip_->nodeCount()<<subMip_->iterationCount()<<CoinMessageEol;
223  else
224  handler_->message(LOCAL_SEARCH_ABORT, messages_)<<subMip_->nodeCount()<<subMip_->iterationCount()<<CoinMessageEol;
225  if(colsol)
226  handler_->message(FP_MILP_VAL, messages_)
227  <<colsol[nlp_->getNumCols()]<<CoinMessageEol;
228 
229  }
230  else {
231  colsol = NULL;
232  }
233  }
234  //return -DBL_MAX;
235  if(!passBound_ || colsol || ! milpOptimal)
236  return -DBL_MAX;
237  else{
238  handler_->message(OASUCCESS, messages_)<<"FP"<<CoinCpuTime() - timeBegin_
239  <<ub<<CoinMessageEol;
240  return DBL_MAX;
241  }
242  }
243 
245  void
247  {
248  roptions->SetRegisteringCategory("Primal Heuristics", RegisteredOptions::BonminCategory);
249 
250  roptions->AddStringOption2("fp_pass_infeasible", "Say whether feasibility pump should claim to converge or not",
251  "no",
252  "no", "When master MILP is infeasible just bail out (don't stop all algorithm). This is the option for using in B-Hyb.",
253  "yes", "Claim convergence, numerically dangerous.","");
254 
255  roptions->SetRegisteringCategory("Output and Loglevel", RegisteredOptions::BonminCategory);
256  roptions->AddBoundedIntegerOption("fp_log_level",
257  "specify FP iterations log level.",
258  0,2,1,
259  "Set the level of output of OA decomposition solver : "
260  "0 - none, 1 - normal, 2 - verbose"
261  );
262  roptions->setOptionExtraInfo("fp_log_level",3);
263 
264  roptions->AddLowerBoundedNumberOption("fp_log_frequency",
265  "display an update on lower and upper bounds in FP every n seconds",
266  0.,1.,100.,
267  "");
268  roptions->setOptionExtraInfo("fp_log_frequency",3);
269  }
270 
272 void
273 MinlpFeasPump::set_fp_objective(OsiSolverInterface &si, const double * colsol) const{
274  if (objects_) {
275  for (int i = 0 ; i < nObjects_ ; i++) {
276  OsiObject * obj = objects_[i];
277  int colnum = obj->columnNumber();
278  if (colnum >= 0) {//Variable branching object
279  double round = floor(colsol[colnum] + 0.5);
280  double coeff = (colsol[colnum] - round ) < 0;
281  si.setObjCoeff(colnum, 1 - 2 * coeff);
282  }
283  else {
284  throw CoinError("OaDecompositionBase::solverManip",
285  "setFpObjective",
286  "Can not use FP on problem with SOS constraints");
287  }
288  }
289  }
290  else {
291  int numcols = nlp_->getNumCols();
292  for (int i = 0; i < numcols ; i++) {
293  if (nlp_->isInteger(i)){
294  double round = floor(colsol[i] + 0.5);
295  double coeff = (colsol[i] - round ) < 0;
296  si.setObjCoeff(i, 1 - 2*coeff);
297  }
298  }
299  }
300  si.initialSolve();
301 }
302 
303 }/* End namespace Bonmin. */
int getIntParameter(const IntParameter &p) const
Return value of integer parameter.
int maxSols_
maximum number of solutions
Small class to manipulatee various things in an OsiSolverInterface and restore them.
int nLocalSearch_
number of local searches performed
SubMipSolver * subMip_
void getOuterApproximation(OsiCuts &cs, int getObj, const double *x2, bool global)
Get the outer approximation constraints at the current optimal point.
virtual const double * getColLower() const
Get pointer to array[getNumCols()] of column lower bounds.
void fint fint fint real fint real real real real real real real real real fint real fint fint fint real fint fint fint fint * info
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Register OA options.
virtual bool isInteger(int columnNumber) const
Return true if column is integer.
int passBound_
Wether or not to pass bound to master algorithm.
double maxLocalSearchTime_
maximum time for local searches
double cbcIntegerTolerance_
integer tolerance (has to be the same as Cbc&#39;s)
virtual int getNumCols() const
Get number of columns.
virtual bool isProvenOptimal() const
Is optimality proven?
virtual double getObjValue() const
Get objective function value (can&#39;t use default)
OsiObject ** objects_
Some objects the feasiblitiy of which to verify.
const double * getLastSolution()
get the solution found in last local search (return NULL if no solution).
CoinMessageHandler * handler_
messages handler.
double solveFeasibilityProblem(size_t n, const double *x_bar, const int *ind, double a, double s, int L)
Given a point x_bar this solves the problem of finding the point which minimize a convex combination ...
int nObjects_
Number of objects.*/.
virtual const double * getColSolution() const
Get pointer to array[getNumCols()] of primal solution vector.
void fint fint fint real fint real real real real real real real real real * e
A very simple class to provide a common interface for solving MIPs with Cplex and Cbc...
~MinlpFeasPump()
Destructor.
virtual void setColUpper(int elementIndex, double elementValue)
Set a single column upper bound.
A class to have all elements necessary to setup a branch-and-bound.
limit on number of integer feasible solution.
void installCuts(OsiSolverInterface &si, const OsiCuts &cs, int numberCuts)
Install cuts in solver.
virtual double performOa(OsiCuts &cs, solverManip &lpManip, BabInfo *babInfo, double &cutoff, const CglTreeInfo &info) const
virtual method which performs the OA algorithm by modifying lp and nlp.
double timeBegin_
time of construction
void fint fint fint real fint real real real real real real real real real fint real fint * lp
virtual void resolve()
Resolve the continuous relaxation after problem modification.
Parameters parameters_
Parameters.
int numSols_
number of solutions found by OA_decomposition.
void solve(double cutoff, int loglevel, double maxTime)
double cbcCutoffIncrement_
cutoff min increase (has to be intialized trhough Cbc)
OsiSolverInterface * solver()
int subMilpLogLevel_
sub milp log level.
void fixIntegers(OsiSolverInterface &si, const OsiBranchingInformation &info, double integer_tolerance, OsiObject **objects, int nObjects)
Fix integer variables in si to their values in colsol.
CoinMessages messages_
Messages for OA.
int maxLocalSearch_
Total max number of local searches.
MinlpFeasPump(BabSetupBase &b)
Constructor with basic setup.
void relaxIntegers(OsiSolverInterface &si, const OsiBranchingInformation &info, double integer_tolerance, OsiObject **objects, int nObjects)
Slightly relax integer variables in si.
virtual const double * getColUpper() const
Get pointer to array[getNumCols()] of column upper bounds.
virtual void addObjectiveFunction(OsiSolverInterface &si, const double *x)
Add constraint corresponding to objective function.
int iterationCount()
Returns number of simplex iterations in last solve.
OsiSolverInterface * si()
Get pointer to solver interface.
Ipopt::SmartPtr< Ipopt::OptionsList > options()
Acces list of Options.
double getDoubleParameter(const DoubleParameter &p) const
Return value of double parameter.
void set_fp_objective(OsiSolverInterface &si, const double *colsol) const
Put objective of MIP according to FP scheme.
static const char * txt_id
Base class for OA algorithms.
static char prefix[100]
Definition: BM_lp.cpp:26
virtual void setColLower(int elementIndex, double elementValue)
Set a single column lower bound.
OsiTMINLPInterface * nlp_
Pointer to nlp interface.
virtual bool doLocalSearch(BabInfo *babInfo) const
virutal method to decide if local search is performed
return b
Definition: OSdtoa.cpp:1719
const char * prefix() const
Get prefix to use for options.
void setLpSolver(OsiSolverInterface *lp)
Assign lp solver.
Bonmin class for passing info between components of branch-and-cuts.
Definition: BonBabInfos.hpp:19
int nodeCount()
Returns number of nodes in last solve.
bool post_nlp_solve(BabInfo *babInfo, double cutoff) const
Solve the nlp and do output.