MCF1_lp.cpp
Go to the documentation of this file.
1 #include "CoinHelperFunctions.hpp"
2 #include "OsiClpSolverInterface.hpp"
3 #include "BCP_lp.hpp"
4 #include "MCF1_lp.hpp"
5 
6 //#############################################################################
7 
9 {
10  return new OsiClpSolverInterface;
11 }
12 
13 //#############################################################################
14 
15 void
17  std::vector<MCF1_branch_decision>* history,
18  BCP_vec<int>& var_changed_pos,
19  BCP_vec<double>& var_new_bd)
20 {
21  for (int i = vars.size()-1; i >= 0; --i) {
22  MCF1_var* v = dynamic_cast<MCF1_var*>(vars[i]);
23  if (!v) continue;
24  const int vsize = v->flow.getNumElements();
25  const int* vind = v->flow.getIndices();
26  const double* vval = v->flow.getElements();
27 
28  bool violated = false;
29  const std::vector<MCF1_branch_decision>& hist = history[v->commodity];
30  for (int j = hist.size()-1; !violated && j >= 0; --j) {
31  const MCF1_branch_decision& h = hist[j];
32  double f = 0.0;
33  for (int k = 0; k < vsize; ++k) {
34  if (vind[k] == h.arc_index) {
35  f = vval[k];
36  break;
37  }
38  }
39  violated = (f < h.lb || f > h.ub);
40  }
41  if (violated) {
42  var_changed_pos.push_back(i);
43  var_new_bd.push_back(0.0); // the new lower bound on the var
44  var_new_bd.push_back(0.0); // the new upper bound on the var
45  }
46  }
47 }
48 
49 /*---------------------------------------------------------------------------*/
50 
51 void
53  const int commodity,
54  const MCF1_branch_decision& decision,
55  BCP_vec<int>& var_changed_pos,
56  BCP_vec<double>& var_new_bd)
57 {
58  for (int i = vars.size()-1; i >= 0; --i) {
59  MCF1_var* v = dynamic_cast<MCF1_var*>(vars[i]);
60  if (!v)
61  continue;
62  if (v->commodity != commodity)
63  continue;
64  const int vsize = v->flow.getNumElements();
65  const int* vind = v->flow.getIndices();
66  const double* vval = v->flow.getElements();
67 
68  double f = 0.0;
69  for (int k = 0; k < vsize; ++k) {
70  if (vind[k] == decision.arc_index) {
71  f = vval[k];
72  break;
73  }
74  }
75  if (f < decision.lb || f > decision.ub) {
76  var_changed_pos.push_back(i);
77  var_new_bd.push_back(0.0); // the new lower bound on the var
78  var_new_bd.push_back(0.0); // the new upper bound on the var
79  }
80  }
81 }
82 
83 /*---------------------------------------------------------------------------*/
84 
85 void MCF1_lp::
87  const BCP_vec<BCP_cut*>& cuts,
88  const BCP_vec<BCP_obj_status>& var_status,
89  const BCP_vec<BCP_obj_status>& cut_status,
90  BCP_vec<int>& var_changed_pos,
91  BCP_vec<double>& var_new_bd,
92  BCP_vec<int>& cut_changed_pos,
93  BCP_vec<double>& cut_new_bd)
94 {
95  // Go through all the variables, select the MCF1_branching_var's and save
96  // the upper/lower bounds to be applied in the subproblems
97  int i;
98  for (i = data.numcommodities-1; i >= 0; --i) {
99  branch_history[i].clear();
100  }
101  for (i = vars.size()-1; i >= 0; --i) {
102  MCF1_branching_var* v = dynamic_cast<MCF1_branching_var*>(vars[i]);
103  if (v) {
104  if (v->ub() == 0.0) {
105  // the upper bound of the branching var in this child is set
106  // to 0, so we are in child 0v->lb_child0
108  push_back(MCF1_branch_decision(v->arc_index,
109  v->lb_child0,
110  v->ub_child0));
111  } else {
113  push_back(MCF1_branch_decision(v->arc_index,
114  v->lb_child1,
115  v->ub_child1));
116  }
117  }
118  }
119 
120  MCF1_adjust_bounds(vars, branch_history, var_changed_pos, var_new_bd);
121 
122  // clear out our local pool
124 }
125 
126 /*---------------------------------------------------------------------------*/
127 
130  const BCP_vec<BCP_var*>& vars,
131  const BCP_vec<BCP_cut*>& cuts)
132 {
133 #if 0
134  static int cnt = 0;
135  char name[100];
136  sprintf(name, "currlp-%i", cnt++);
137  // sprintf(name, "currlp");
138  getLpProblemPointer()->lp_solver->writeMps(name, "mps");
139  printf("Current LP written in file %s.mps\n", name);
140  getLpProblemPointer()->lp_solver->writeLp(name, "lp");
141  printf("Current LP written in file %s.lp\n", name);
142 #endif
143 
144  // Feasibility testing: we need to test whether the convex combination of
145  // the current columns (according to \lambda, the current primal solution)
146  // is integer feasible for the original problem. The only thing that can
147  // be violated is integrality.
148 
149  int i, j;
150  for (i = data.numcommodities-1; i >= 0; --i) {
151  flows[i].clear();
152  }
153 
154  const double* x = lpres.x();
155  for (i = vars.size()-1; i >= 0; --i) {
156  MCF1_var* v = dynamic_cast<MCF1_var*>(vars[i]);
157  if (!v) continue;
158  std::map<int,double>& f = flows[v->commodity];
159  const int vsize = v->flow.getNumElements();
160  const int* vind = v->flow.getIndices();
161  const double* vval = v->flow.getElements();
162  for (j = 0; j < vsize; ++j) {
163  f[vind[j]] += vval[j]*x[i];
164  }
165  }
166  for (i = data.numcommodities-1; i >= 0; --i) {
167  std::map<int,double>& f = flows[i];
168  for (std::map<int,double>::iterator fi=f.begin(); fi != f.end(); ++fi) {
169  const double frac = fabs(fi->second - floor(fi->second) - 0.5);
170  if (frac < 0.5-1e-6)
171  return NULL;
172  }
173  }
174 
175  // Found an integer solution
177  for (i = data.numcommodities-1; i >= 0; --i) {
178  std::map<int,double>& f = flows[i];
179  CoinPackedVector flow(false);
180  double weight = 0;
181  for (std::map<int,double>::iterator fi=f.begin();
182  fi != f.end();
183  ++fi) {
184  const double val = floor(fi->second + 0.5);
185  if (val > 0) {
186  flow.insert(fi->first, val);
187  weight += val * data.arcs[fi->first].weight;
188  }
189  }
190  gsol->add_entry(new MCF1_var(i, flow, weight), 1.0);
191  }
192  return gsol;
193 }
194 
195 /*---------------------------------------------------------------------------*/
196 
197 double MCF1_lp::
198 compute_lower_bound(const double old_lower_bound,
199  const BCP_lp_result& lpres,
200  const BCP_vec<BCP_var*>& vars,
201  const BCP_vec<BCP_cut*>& cuts)
202 {
203  // To compute a true lower bound we need to generate variables first (if
204  // we can). These are saved so that we can return them in
205  // generate_vars_in_lp.
206 
207  // generate variables: for each commodity generate a flow.
208 
209  const int numarcs = data.numarcs;
210  double* cost = new double[numarcs];
211  const double* pi = lpres.pi();
212  const double* nu = pi + numarcs;
213 
214  int i, j;
215 
216  for (i = numarcs-1; i >= 0; --i) {
217  cost[i] = data.arcs[i].weight - pi[i];
218  }
219  cg_lp->setObjective(cost);
220 
221  // This will hold generated variables
222  int* ind = new int[numarcs];
223  double* val = new double[numarcs];
224  int cnt = 0;
225 
226  for (i = data.numcommodities-1; i >= 0; --i) {
227  const MCF1_data::commodity& comm = data.commodities[i];
228  cg_lp->setRowBounds(comm.source, -comm.demand, -comm.demand);
229  cg_lp->setRowBounds(comm.sink, comm.demand, comm.demand);
230  const std::vector<MCF1_branch_decision>& hist = branch_history[i];
231  for (j = hist.size() - 1; j >= 0; --j) {
232  const MCF1_branch_decision& h = hist[j];
233  cg_lp->setColBounds(h.arc_index, h.lb, h.ub);
234  }
235  cg_lp->initialSolve();
236  if (cg_lp->isProvenOptimal() && cg_lp->getObjValue() < nu[i] - 1e-8) {
237  // we have generated a column. Create a var out of it. Round the
238  // double values while we are here, after all, they should be
239  // integer. there can only be some tiny roundoff error by the LP
240  // solver
241  const double* x = cg_lp->getColSolution();
242  cnt = 0;
243  double obj = 0.0;
244  for (int j = 0; j < numarcs; ++j) {
245  const double xval = floor(x[j] + 0.5);
246  if (xval != 0.0) {
247  ind[cnt] = j;
248  val[cnt] = xval;
249  ++cnt;
250  obj += data.arcs[j].weight * xval;
251  }
252  }
253  gen_vars.push_back(new MCF1_var(i, CoinPackedVector(cnt, ind, val,
254  false), obj));
255  }
256  for (j = hist.size() - 1; j >= 0; --j) {
257  const int ind = hist[j].arc_index;
258  cg_lp->setColBounds(ind, data.arcs[ind].lb, data.arcs[ind].ub);
259  }
260  cg_lp->setRowBounds(comm.source, 0, 0);
261  cg_lp->setRowBounds(comm.sink, 0, 0);
262  }
263  delete[] val;
264  delete[] ind;
265  delete[] cost;
266 
267  // Excercise: do the same in a random order and apply dual discounting
268  // Not yet implemented.
269 
270  // Now get a true lower bound
271  double true_lower_bound = 0.0;
272  generated_vars = (gen_vars.size() > 0);
273 
274  if (generated_vars) {
275  true_lower_bound = old_lower_bound;
276  } else {
277  true_lower_bound = lpres.objval();
278  }
279 
280  // Excercise: Get a better true lower bound
281  // Hint: lpres.objval() + The sum of the reduced costs of the
282  // variables with the most negative reduced cost in each subproblem
283  // yield a true lower bound
284  // Not yet implemented.
285 
286  return true_lower_bound;
287 }
288 
289 /*---------------------------------------------------------------------------*/
290 
291 void MCF1_lp::
293  const BCP_vec<BCP_var*>& vars,
294  const BCP_vec<BCP_cut*>& cuts,
295  const bool before_fathom,
296  BCP_vec<BCP_var*>& new_vars,
297  BCP_vec<BCP_col*>& new_cols)
298 {
299  new_vars.append(gen_vars);
300  gen_vars.clear();
301 }
302 
303 /*---------------------------------------------------------------------------*/
304 
305 void MCF1_lp::
307  BCP_vec<BCP_var*>& vars,
308  BCP_vec<BCP_col*>& cols,
309  const BCP_lp_result& lpres,
310  BCP_object_origin origin, bool allow_multiple)
311 {
312  static const CoinPackedVector emptyVector(false);
313  const int numvars = vars.size();
314  for (int i = 0; i < numvars; ++i) {
315  const MCF1_var* v =
316  dynamic_cast<const MCF1_var*>(vars[i]);
317  if (v) {
318  // Since we do not generate cuts, we can just disregard the "cuts"
319  // argument, since the column corresponding to the var is exactly
320  // the flow (plus the entry in the appropriate convexity
321  // constraint)
322  BCP_col* col = new BCP_col(v->flow, v->weight, 0.0, 1.0);
323  col->insert(data.numarcs + v->commodity, 1.0);
324  cols.push_back(col);
325  // Excercise: if we had generated cuts, then the coefficients for
326  // those rows would be appended to the end of each column
327  continue;
328  }
329  const MCF1_branching_var* bv =
330  dynamic_cast<const MCF1_branching_var*>(vars[i]);
331  if (bv) {
332  cols.push_back(new BCP_col(emptyVector, 0.0, bv->lb(), bv->ub()));
333  }
334  }
335 }
336 
337 /*---------------------------------------------------------------------------*/
338 
341  const BCP_vec<BCP_var*>& vars,
342  const BCP_vec<BCP_cut*>& cuts,
343  const BCP_lp_var_pool& local_var_pool,
344  const BCP_lp_cut_pool& local_cut_pool,
346  bool force_branch)
347 {
348  if (generated_vars > 0) {
349  return BCP_DoNotBranch;
350  }
351 
352  if (lpres.objval() > upper_bound() - 1e-6) {
354  }
355 
356  int i, j;
357 
358  const int dummyStart = par.entry(MCF1_par::AddDummySourceSinkArcs) ?
360 
361  // find a few fractional original variables and do strong branching on them
362  for (i = data.numcommodities-1; i >= 0; --i) {
363  std::map<int,double>& f = flows[i];
364  int most_frac_ind = -1;
365  double most_frac_val = 0.5-1e-6;
366  double frac_val = 0.0;
367  for (std::map<int,double>::iterator fi=f.begin(); fi != f.end(); ++fi){
368  if (fi->first >= dummyStart)
369  continue;
370  const double frac = fabs(fi->second - floor(fi->second) - 0.5);
371  if (frac < most_frac_val) {
372  most_frac_ind = fi->first;
373  most_frac_val = frac;
374  frac_val = fi->second;
375  }
376  }
377  if (most_frac_ind >= 0) {
378  BCP_vec<BCP_var*> new_vars;
379  BCP_vec<int> fvp;
380  BCP_vec<double> fvb;
381  int lb = data.arcs[most_frac_ind].lb;
382  int ub = data.arcs[most_frac_ind].ub;
383  for (j = branch_history[i].size() - 1; j >= 0; --j) {
384  // To correctly set lb/ub we need to check whether we have
385  // already branched on this arc
386  const MCF1_branch_decision& h = branch_history[i][j];
387  if (h.arc_index == most_frac_ind) {
388  lb = CoinMax(lb, h.lb);
389  ub = CoinMin(ub, h.ub);
390  }
391  }
392  const int mid = static_cast<int>(floor(frac_val));
393  new_vars.push_back(new MCF1_branching_var(i, most_frac_ind,
394  lb, mid, mid+1, ub));
395  // Look at the consequences of of this branch
396  BCP_vec<int> child0_pos, child1_pos;
397  BCP_vec<double> child0_bd, child1_bd;
398 
399  MCF1_branch_decision child0(most_frac_ind, lb, mid);
400  MCF1_adjust_bounds(vars, i, child0, child0_pos, child0_bd);
401 
402  MCF1_branch_decision child1(most_frac_ind, mid+1, ub);
403  MCF1_adjust_bounds(vars, i, child1, child1_pos, child1_bd);
404 
405  // Now put together the changes
406  fvp.push_back(-1);
407  fvp.append(child0_pos);
408  fvp.append(child1_pos);
409  fvb.push_back(0.0);
410  fvb.push_back(0.0);
411  fvb.append(child0_bd);
412  for (j = child1_pos.size() - 1; j >= 0; --j) {
413  fvb.push_back(0.0);
414  fvb.push_back(1.0);
415  }
416  fvb.push_back(1.0);
417  fvb.push_back(1.0);
418  for (j = child0_pos.size() - 1; j >= 0; --j) {
419  fvb.push_back(0.0);
420  fvb.push_back(1.0);
421  }
422  fvb.append(child1_bd);
423  cands.push_back(new BCP_lp_branching_object(2, // num of children
424  &new_vars,
425  NULL, // no new cuts
426  &fvp,NULL,&fvb,NULL,
427  NULL,NULL,NULL,NULL));
428  }
429  }
430  return BCP_DoBranch;
431 }
432 
433 /*===========================================================================*/
434 
435 void MCF1_lp::
437 {
438  par.unpack(buf);
439  data.unpack(buf);
440 
441  // This is the place where we can preallocate some data structures
442  branch_history = new std::vector<MCF1_branch_decision>[data.numcommodities];
443  flows = new std::map<int,double>[data.numcommodities];
444 
445  // Create the LP that will be used to generate columns
446  cg_lp = new OsiClpSolverInterface();
447 
448  const int numCols = data.numarcs;
449  const int numRows = data.numnodes;
450  const int numNz = 2*numCols;
451 
452  double *clb = new double[numCols];
453  double *cub = new double[numCols];
454  double *obj = new double[numCols];
455  double *rlb = new double[numRows];
456  double *rub = new double[numRows];
457  CoinBigIndex *start = new int[numCols+1];
458  int *index = new int[numNz];
459  double *value = new double[numNz];
460 
461  // all these will be properly set for the search tree node in the
462  // initialize_new_search_tree_node method
463  CoinZeroN(obj, numCols);
464  CoinZeroN(clb, numCols);
465  for (int i = numCols - 1; i >= 0; --i) {
466  cub[i] = data.arcs[i].ub;
467  }
468  // and these will be properly set for the subproblem in the
469  // generate_vars_in_lp method
470  CoinZeroN(rlb, numRows);
471  CoinZeroN(rub, numRows);
472 
473  for (int i = 0; i < data.numarcs; ++i) {
474  start[i] = 2*i;
475  index[2*i] = data.arcs[i].tail;
476  index[2*i+1] = data.arcs[i].head;
477  value[2*i] = -1;
478  value[2*i+1] = 1;
479  }
480  start[numCols] = 2*numCols;
481 
482  cg_lp->loadProblem(numCols, numRows, start, index, value,
483  clb, cub, obj, rlb, rub);
484 
485  delete[] value;
486  delete[] index;
487  delete[] start;
488  delete[] rub;
489  delete[] rlb;
490  delete[] obj;
491  delete[] cub;
492  delete[] clb;
493 }
OsiSolverInterface * cg_lp
Definition: MCF1_lp.hpp:14
BCP_object_origin
This enumerative constant describes the origin (originating process) of an object (variable or cut)...
Definition: BCP_enum.hpp:249
This class holds a column in a compressed form.
Definition: BCP_matrix.hpp:26
std::vector< MCF1_branch_decision > * branch_history
Definition: MCF1_lp.hpp:17
void clear()
Delete every entry.
void unpack(BCP_buffer &buf)
Definition: MCF1_data.cpp:31
int commodity
Definition: MCF1_var.hpp:23
char entry(const chr_params key) const
virtual void unpack_module_data(BCP_buffer &buf)
Unpack the initial information sent to the LP process by the Tree Manager.
Definition: MCF1_lp.cpp:436
BCP should continue to work on this node.
const double * x() const
int numnodes
Definition: MCF1_data.hpp:29
bool generated_vars
Definition: MCF1_lp.hpp:22
static const CouNumber pi
Definition: exprCos.cpp:23
virtual OsiSolverInterface * initialize_solver_interface()
Create LP solver environment.
Definition: MCF1_lp.cpp:8
void push_back(const_reference x)
Append x to the end of the vector.
static char * j
Definition: OSdtoa.cpp:3622
void fint fint fint real fint real real real real * f
virtual void generate_vars_in_lp(const BCP_lp_result &lpres, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts, const bool before_fathom, BCP_vec< BCP_var * > &new_vars, BCP_vec< BCP_col * > &new_cols)
Generate variables within the LP process.
Definition: MCF1_lp.cpp:292
CoinPackedVector flow
Definition: MCF1_var.hpp:24
void fint fint fint real fint real real real real real real real real real * e
double ub() const
Return the upper bound.
Definition: BCP_var.hpp:91
virtual BCP_branching_decision select_branching_candidates(const BCP_lp_result &lpres, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts, const BCP_lp_var_pool &local_var_pool, const BCP_lp_cut_pool &local_cut_pool, BCP_vec< BCP_lp_branching_object * > &cands, bool force_branch=false)
Decide whether to branch or not and select a set of branching candidates if branching is decided upon...
Definition: MCF1_lp.cpp:340
BCP_lp_prob * getLpProblemPointer()
Get the pointer.
Definition: BCP_lp_user.hpp:95
OsiSolverInterface * lp_solver
A class that holds the methods about how to pack things.
Definition: BCP_lp.hpp:137
MCF1_data data
Definition: MCF1_lp.hpp:16
BCP_vec< BCP_var * > gen_vars
Definition: MCF1_lp.hpp:21
double objval() const
void fint fint * k
This class describes a generic branching object.
void MCF1_adjust_bounds(const BCP_vec< BCP_var * > &vars, std::vector< MCF1_branch_decision > *history, BCP_vec< int > &var_changed_pos, BCP_vec< double > &var_new_bd)
Definition: MCF1_lp.cpp:16
BCP_branching_decision
This enumerative constant is the return value of the select_branching_candidates() method in [BCP_lp_...
virtual BCP_solution * test_feasibility(const BCP_lp_result &lp_result, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts)
Evaluate and return MIP feasibility of the current solution.
Definition: MCF1_lp.cpp:129
void add_entry(BCP_var *var, double value)
Append a variable and the corresponding value to the end of the appropriate vectors.
double upper_bound() const
Return what is the best known upper bound (might be BCP_DBL_MAX)
Definition: BCP_lp_user.cpp:29
virtual void vars_to_cols(const BCP_vec< BCP_cut * > &cuts, BCP_vec< BCP_var * > &vars, BCP_vec< BCP_col * > &cols, const BCP_lp_result &lpres, BCP_object_origin origin, bool allow_multiple)
Convert a set of variables into corresponding columns for the current LP relaxation.
Definition: MCF1_lp.cpp:306
int numarcs
Definition: MCF1_data.hpp:28
The node should be fathomed without even trying to branch.
size_t size() const
Return the current number of entries.
Definition: BCP_vector.hpp:116
This class describes the message buffer used for all processes of BCP.
Definition: BCP_buffer.hpp:39
const double * pi() const
virtual double compute_lower_bound(const double old_lower_bound, const BCP_lp_result &lpres, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts)
Compute a true lower bound for the subproblem.
Definition: MCF1_lp.cpp:198
commodity * commodities
Definition: MCF1_data.hpp:27
virtual void initialize_new_search_tree_node(const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts, const BCP_vec< BCP_obj_status > &var_status, const BCP_vec< BCP_obj_status > &cut_status, BCP_vec< int > &var_changed_pos, BCP_vec< double > &var_new_bd, BCP_vec< int > &cut_changed_pos, BCP_vec< double > &cut_new_bd)
Initializing a new search tree node.
Definition: MCF1_lp.cpp:86
double lb() const
Return the lower bound.
Definition: BCP_var.hpp:89
void purge_ptr_vector(BCP_vec< T * > &pvec, typename BCP_vec< T * >::iterator first, typename BCP_vec< T * >::iterator last)
This function purges the entries [first,last) from the vector of pointers pvec.
Definition: BCP_vector.hpp:266
void unpack(BCP_buffer &buf)
Unpack the parameter set from the buffer.
std::map< int, double > * flows
Definition: MCF1_lp.hpp:19
This class holds the results after solving an LP relaxation.
Branching must be done.
BCP_parameter_set< MCF1_par > par
Definition: MCF1_lp.hpp:15
fint nu
int numcommodities
Definition: MCF1_data.hpp:30
This class holds a MIP feasible primal solution.
arc * arcs
Definition: MCF1_data.hpp:26
double weight
Definition: MCF1_var.hpp:25
void append(const BCP_vec< T > &x)
Append the entries in x to the end of the vector.
Definition: BCP_vector.hpp:169
void fint fint fint real fint real * x
This is the abstract base class for a solution to a Mixed Integer Programming problem.