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