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