MC_lp.cpp
Go to the documentation of this file.
1 // Copyright (C) 2000, International Business Machines
2 // Corporation and others. All Rights Reserved.
3 #include <cmath>
4 #include <algorithm>
5 #include <numeric>
6 
7 #include "CoinHelperFunctions.hpp"
8 
9 #include <OsiVolSolverInterface.hpp>
10 #include <OsiClpSolverInterface.hpp>
11 
12 #include "BCP_math.hpp"
13 #include "BCP_lp.hpp"
14 #include "BCP_lp_node.hpp"
15 
16 #include "MC_cut.hpp"
17 #include "MC_lp.hpp"
18 
19 //#############################################################################
20 
21 static inline void
23 {
24  if (!sol_old) {
25  sol_old = sol_new;
26  } else {
27  if (sol_new) {
28  if (sol_old->objective_value() > sol_new->objective_value()) {
29  delete sol_old;
30  sol_old = sol_new;
31  } else {
32  delete sol_new;
33  }
34  }
35  }
36  sol_new = NULL;
37 }
38 
39 
40 //#############################################################################
41 
42 static inline bool
43 MC_cycle_row_pair_comp(const std::pair<BCP_cut*, BCP_row*>& p0,
44  const std::pair<BCP_cut*, BCP_row*>& p1)
45 {
46  return MC_cycle_cut_less(p0.first, p1.first);
47 }
48 
49 //-----------------------------------------------------------------------------
50 
51 void
53  BCP_vec<BCP_row*>& new_rows)
54 {
55  size_t i;
56  const size_t cutnum = new_cuts.size();
57  if (cutnum != new_rows.size())
58  throw BCP_fatal_error("Uneven vector sizes in MC_lp_unique_cycle_cuts.\n");
59 
60  if (cutnum == 0)
61  return;
62 
63  std::pair<BCP_cut*, BCP_row*>* cut_row_pairs =
64  new std::pair<BCP_cut*, BCP_row*>[cutnum];
65  for (i = 0; i < cutnum; ++i) {
66  cut_row_pairs[i].first = new_cuts[i];
67  cut_row_pairs[i].second = new_rows[i];
68  }
69 
70  std::sort(cut_row_pairs, cut_row_pairs + cutnum, MC_cycle_row_pair_comp);
71  int k = 0;
72  new_cuts[0] = cut_row_pairs[0].first;
73  new_rows[0] = cut_row_pairs[0].second;
74  for (i = 1; i < cutnum; ++i) {
75  if (MC_cycle_cut_equal(new_cuts[k], cut_row_pairs[i].first)) {
76  delete cut_row_pairs[i].first;
77  delete cut_row_pairs[i].second;
78  } else {
79  new_cuts[++k] = cut_row_pairs[i].first;
80  new_rows[k] = cut_row_pairs[i].second;
81  }
82  }
83  ++k;
84 
85  delete[] cut_row_pairs;
86  new_cuts.erase(new_cuts.entry(k), new_cuts.end());
87  new_rows.erase(new_rows.entry(k), new_rows.end());
88 }
89 
90 //#############################################################################
91 
92 void
94 {
95  par.unpack(buf);
96  mc.unpack(buf);
97 
99 
102  hist_len = CoinMax(hist_len, par.entry(MC_lp_par::TailoffLbRelMinItcount));
103 
104  objhist = hist_len <= 0 ? 0 : new double[hist_len];
105 
111  } else {
116  }
117 }
118 
119 //#############################################################################
120 // Override the initializer so that we can choose between vol and simplex
121 // at runtime.
122 
123 OsiSolverInterface *
125 {
126  if ((par.entry(MC_lp_par::LpSolver) & MC_UseVol) != 0) {
127  return new OsiVolSolverInterface;
128  }
129 
130  if ((par.entry(MC_lp_par::LpSolver) & MC_UseClp) != 0) {
131  return new OsiClpSolverInterface;
132  }
133 
134  throw BCP_fatal_error("MC: No solver is specified!\n");
135  return 0; // fake return
136 }
137 
138 //#############################################################################
139 // Opportunity to reset things before optimization
140 void
141 MC_lp::modify_lp_parameters(OsiSolverInterface* lp, const int changeType,
142  bool in_strong_branching)
143 {
144  if (current_iteration() == 1 &&
145  ( ((par.entry(MC_lp_par::LpSolver) & MC_UseClp) != 0) )
146  ) {
147  started_exact = false;
148  }
149  {
150  OsiVolSolverInterface* vollp = dynamic_cast<OsiVolSolverInterface*>(lp);
151  if (vollp) {
152  VOL_parms& vpar = vollp->volprob()->parm;
153  vpar.lambdainit = par.entry(MC_lp_par::Vol_lambdaInit);
154  vpar.alphainit = par.entry(MC_lp_par::Vol_alphaInit);
155  vpar.alphamin = par.entry(MC_lp_par::Vol_alphaMin);
156  vpar.alphafactor = par.entry(MC_lp_par::Vol_alphaFactor);
157  vpar.primal_abs_precision = par.entry(MC_lp_par::Vol_primalAbsPrecision);
158  vpar.gap_abs_precision = par.entry(MC_lp_par::Vol_gapAbsPrecision);
159  vpar.gap_rel_precision = par.entry(MC_lp_par::Vol_gapRelPrecision);
160  vpar.granularity = par.entry(MC_lp_par::Vol_granularity);
161  vpar.minimum_rel_ascent = par.entry(MC_lp_par::Vol_minimumRelAscent);
162  vpar.ascent_first_check = par.entry(MC_lp_par::Vol_ascentFirstCheck);
163  vpar.ascent_check_invl = par.entry(MC_lp_par::Vol_ascentCheckInterval);
165  vpar.printflag = par.entry(MC_lp_par::Vol_printFlag);
166  vpar.printinvl = par.entry(MC_lp_par::Vol_printInterval);
167  vpar.greentestinvl = par.entry(MC_lp_par::Vol_greenTestInterval);
168  vpar.yellowtestinvl = par.entry(MC_lp_par::Vol_yellowTestInterval);
169  vpar.redtestinvl = par.entry(MC_lp_par::Vol_redTestInterval);
170  vpar.alphaint = par.entry(MC_lp_par::Vol_alphaInt);
171  }
172  if (in_strong_branching) {
173  // *THINK* : we might want to do fewer iterations???
174  }
175  }
176 }
177 
178 //#############################################################################
179 
182  const BCP_vec<BCP_var*>& vars,
183  const BCP_vec<BCP_cut*>& cuts)
184 {
185  int i, k;
186 
187  const double etol = par.entry(MC_lp_par::IntegerTolerance);
188  BCP_vec<double> x(lp_result.x(), vars.size());
189  // First round the integer part of the solution.
190  for (k = x.size(), i = x.size() - 1; i >= 0; --i) {
191  const double xx = x[i];
192  if (xx > 1 - etol) {
193  --k;
194  x[i] = 1;
195  } else if (xx < etol) {
196  --k;
197  x[i] = 0;
198  }
199  }
200 
201  // If everything is integer check if the soln is feasible (there might be
202  // violated cycles inequalities). Fortunately, the MST heuristic WILL find
203  // a violated cycle if everything is integer, moreover, that cycle will be
204  // violated by 1.
205  if (k == 0) {
206  BCP_vec<BCP_cut*> new_cuts;
207  BCP_vec<BCP_row*> new_rows;
208  const int improve_round = par.entry(MC_lp_par::HeurSwitchImproveRound);
209  const bool edge_switch = par.entry(MC_lp_par::DoEdgeSwitchHeur);
210  const int struct_switch = ( par.entry(MC_lp_par::StructureSwitchHeur) &
211  ((1 << mc.num_structure_type) - 1) );
212  MC_solution* sol = MC_mst_cutgen(mc, x.begin(), NULL /* no weights*/,
213  1.0, 0.0,
215  improve_round, edge_switch, struct_switch,
216  .9, 0, new_cuts, new_rows);
217  purge_ptr_vector(new_rows);
218  if (new_cuts.size() == 0) {
219  // jackpot! feasible solution
220  return sol;
221  }
222  purge_ptr_vector(new_cuts);
223  }
224 
225  return NULL;
226 }
227 
228 //#############################################################################
229 
232  const BCP_vec<BCP_var*>& vars,
233  const BCP_vec<BCP_cut*>& cuts)
234 {
235  return mc_generate_heuristic_solution(lpres.x(), vars, cuts);
236 }
237 
238 //#############################################################################
239 
242  const BCP_vec<BCP_var*>& vars,
243  const BCP_vec<BCP_cut*>& cuts)
244 {
245  const int m = mc.num_edges;
246  const int n = mc.num_nodes;
247 
248  const int heurnum = par.entry(MC_lp_par::MstHeurNum);
249  const int improve_round = par.entry(MC_lp_par::HeurSwitchImproveRound);
250  const bool do_edge_switch = par.entry(MC_lp_par::DoEdgeSwitchHeur);
251  const int struct_switch = ( par.entry(MC_lp_par::StructureSwitchHeur) &
252  ((1 << mc.num_structure_type) - 1) );
253  const double maxlambda = par.entry(MC_lp_par::MaxPerturbInMstHeur);
254 
255  double* w = new double[m];
256  double * xx = new double[m];
257 
258  BCP_vec<int> nodesign(n, 1);
259 
260  MC_solution* sol;
261  BCP_vec<double> obj;
262  BCP_vec<char> type;
263 
264  int i, j;
265 
266  // Generate with random additive perturbation
267  for (i = 0; i < heurnum; ++i) {
268  for (j = 0; j < m; ++j)
269  w[j] = CoinDrand48();
270  sol = MC_mst_heur(mc, x, w, 1.0, (maxlambda * i) / heurnum,
272  improve_round, do_edge_switch, struct_switch);
273  MC_update_solution(soln, sol);
274  }
275 #if 0
276  for (i = 0; i < heurnum; ++i) {
277  if (i > 0)
278  for (j = 0; j < m; ++j)
279  w[j] = CoinDrand48();
280  sol = MC_mst_heur(mc, x, w, 1.0, (maxlambda * i) / heurnum,
282  improve_round, do_edge_switch, struct_switch);
283  MC_update_solution(soln, sol);
284  }
285  for (i = 0; i < heurnum; ++i) {
286  if (i > 0)
287  for (j = 0; j < m; ++j)
288  w[j] = CoinDrand48();
289  sol = MC_mst_heur(mc, x, w, 1.0, (maxlambda * i) / heurnum,
291  improve_round, do_edge_switch, struct_switch);
292  MC_update_solution(soln, sol);
293  }
294 #endif
295 #if 0
296  // Generate with random multiplicative and additive perturbation
297  for (i = 0; i < heurnum; ++i) {
298  for (j = 0; j < m; ++j) {
299  w[j] = CoinDrand48();
300  xx[j] = x[j] * (.95 + .1 * CoinDrand48());
301  }
302  sol = MC_mst_heur(mc, xx, w, 1.0, (maxlambda * i) / heurnum,
305  par.entry(MC_lp_par::DoIsingSquareSwitchHeur));
306  MC_update_solution(soln, sol);
307  }
308 #endif
309 #if 0
310  // Shrink the primal solution to be feasible (well, at least the nonzero rhs
311  // constraints...) and generate with additive perturbation
312  const double * lhs = lpres.lhs();
313  const int numcuts = cuts.size();
314  double ratio = 1.0;
315  for (i = 0; i < numcuts; ++i) {
316  const double ub = cuts[i]->ub();
317  if (lhs[i] <= ub)
318  continue;
319  if (ub > 0.0) {
320  ratio = CoinMin(ratio, ub/lhs[i]);
321  }
322  }
323  for (i = 0; i < m; ++i)
324  xx[i] = x[i]*ratio;
325  for (i = 0; i < heurnum; ++i) {
326  for (j = 0; j < m; ++j) {
327  w[j] = CoinDrand48();
328  }
329  sol = MC_mst_heur(mc, xx, w, 1.0, (maxlambda * i) / heurnum,
332  par.entry(MC_lp_par::DoIsingSquareSwitchHeur));
333  MC_update_solution(soln, sol);
334  }
335 #endif
336  delete[] w;
337  delete[] xx;
338 
339  sol = soln;
340  soln = NULL;
341  return sol;
342 }
343 
344 //#############################################################################
345 
346 void
348 {
349  const MC_solution* mcsol = dynamic_cast<const MC_solution*>(sol);
350  mcsol->pack(buf);
351 }
352 
353 //#############################################################################
354 
355 void
356 MC_lp::cuts_to_rows(const BCP_vec<BCP_var*>& vars, // on what to expand
357  BCP_vec<BCP_cut*>& cuts, // what to expand
358  BCP_vec<BCP_row*>& rows, // the expanded rows
359  // things that the user can use for lifting cuts if
360  // allowed
361  const BCP_lp_result& lpres,
362  BCP_object_origin origin, bool allow_multiple)
363 {
364  const int cutnum = cuts.size();
365  rows.clear();
366  rows.reserve(cutnum);
367 
368  const double lb = -BCP_DBL_MAX;
369 
370  const int varnum = vars.size();
371  double* coefs = new double[varnum];
372  int* inds = new int[varnum];
373  int* iotainds = new int[varnum];
374  CoinIotaN(iotainds, varnum, 0);
375 
376  for (int i = 0; i < cutnum; ++i) {
377  const MC_cycle_cut* cycle_cut =
378  dynamic_cast<const MC_cycle_cut*>(cuts[i]);
379  if (cycle_cut) {
380  const int len = cycle_cut->cycle_len;
381  const int pos = cycle_cut->pos_edges;
382  CoinDisjointCopyN(cycle_cut->edges, len, inds);
383  CoinFillN(coefs, pos, 1.0);
384  CoinFillN(coefs + pos, len - pos, -1.0);
385  CoinSort_2(inds, inds + len, coefs);
386  rows.unchecked_push_back(new BCP_row(inds, inds + len,
387  coefs, coefs + len,
388  lb, pos - 1.0));
389  continue;
390  }
391  const MC_explicit_dense_cut* dense_cut =
392  dynamic_cast<const MC_explicit_dense_cut*>(cuts[i]);
393  if (dense_cut) {
394  rows.unchecked_push_back(new BCP_row(iotainds,
395  iotainds + varnum,
396  dense_cut->coeffs,
397  dense_cut->coeffs+varnum,
398  lb, dense_cut->rhs));
399  continue;
400  }
401  throw BCP_fatal_error("Non-MC_cut to be exanded!\n");
402  }
403 
404  if (mc.feas_sol) {
405  for (int i = 0; i < cutnum; ++i) {
406  const double lhs = rows[i]->dotProduct(mc.feas_sol->value);
407  if (cuts[i]->lb() != rows[i]->LowerBound() ||
408  cuts[i]->ub() != rows[i]->UpperBound()) {
409  printf("*** What! *** : cut bounds are not the same: %i %f %f %f %f\n",
410  i, cuts[i]->lb(), rows[i]->LowerBound(),
411  cuts[i]->ub(), rows[i]->UpperBound());
412  }
413  if (lhs < cuts[i]->lb() || lhs > cuts[i]->ub()) {
414  printf("*** Violation *** : index: %i lhs: %f lb: %f ub: %f\n",
415  i, lhs, cuts[i]->lb(), cuts[i]->ub());
416  }
417  }
418  }
419 
420  delete[] iotainds;
421  delete[] inds;
422  delete[] coefs;
423 }
424 
425 //#############################################################################
426 
428 MC_lp::compare_cuts(const BCP_cut* c0, const BCP_cut* c1)
429 {
431 }
432 
433 //#############################################################################
434 //#############################################################################
435 
436 void
437 MC_lp::generate_mst_cuts(const double* x, const double* lhs,
438  const double objval,
439  const BCP_vec<BCP_var*>& vars,
440  const BCP_vec<BCP_cut*>& cuts,
441  BCP_vec<BCP_cut*>& new_cuts,
442  BCP_vec<BCP_row*>& new_rows)
443 {
444  const double max_lp_viol = getMaxLpViol();
445  const int heurnum = par.entry(MC_lp_par::CycleCutHeurNum);
446  const double minviol =
447  CoinMax(max_lp_viol, par.entry(MC_lp_par::MinMstCycleCutViolation));
448  const double maxlambda = par.entry(MC_lp_par::MaxPerturbInMstCycleCutGen);
449 
450  const int heurswitchround = par.entry(MC_lp_par::HeurSwitchImproveRound);
451  const bool edge_switch = par.entry(MC_lp_par::DoEdgeSwitchHeur);
452  const int struct_switch = ( par.entry(MC_lp_par::StructureSwitchHeur) &
453  ((1 << mc.num_structure_type) - 1) );
454 
455  const int numvars = vars.size();
456  double* w = new double[numvars];
457  double* xx = new double[numvars];
458  const int max_cycle_num = par.entry(MC_lp_par::MaxCycleCutNum);
459 
460  // Generate with random additive perturbation
461  int i, j;
462  MC_solution* sol = NULL;
463  for (i = 0; i < heurnum; ++i) {
464  if (i > 0)
465  for (j = 0; j < numvars; ++j)
466  w[j] = CoinDrand48();
467  sol = MC_mst_cutgen(mc, x, w, 1.0, (maxlambda*i)/heurnum,
469  heurswitchround, edge_switch, struct_switch,
470  minviol, new_cuts.size() + max_cycle_num,
471  new_cuts, new_rows);
472  MC_update_solution(soln, sol);
473  }
474 #if 0
475  for (i = 0; i < heurnum; ++i) {
476  if (i > 0)
477  for (j = 0; j < numvars; ++j)
478  w[j] = CoinDrand48();
479  sol = MC_mst_cutgen(mc, x, w, 1.0, (maxlambda*i)/heurnum,
481  heurswitchround, edge_switch, struct_switch,
482  minviol, new_cuts.size() + max_cycle_num,
483  new_cuts, new_rows);
484  delete sol;
485  }
486  for (i = 0; i < heurnum; ++i) {
487  if (i > 0)
488  for (j = 0; j < numvars; ++j)
489  w[j] = CoinDrand48();
490  sol = MC_mst_cutgen(mc, x, w, 1.0, (maxlambda*i)/heurnum,
492  heurswitchround, edge_switch, struct_switch,
493  minviol, new_cuts.size() + max_cycle_num,
494  new_cuts, new_rows);
495  delete sol;
496  }
497  const int cutnum_add = new_cuts.size() - cutnum;
498  printf("MC: cycle cuts (add): %i\n", cutnum_add);
499 #endif
500 #if 0
501  // Generate with random multiplicative and additive perturbation
502  for (i = 0; i < numvars; ++i)
503  xx[i] = x[i]*(.95 + .1 * CoinDrand48());
504  for (i = 0; i < heurnum; ++i) {
505  if (i > 0) {
506  for (j = 0; j < numvars; ++j)
507  w[j] = CoinDrand48();
508  }
509  sol = MC_mst_cutgen(mc, xx, w, 1.0, (maxlambda*i)/heurnum, minviol,
510  heurswitchround, new_cuts.size() + max_cycle_num,
511  new_cuts, new_rows);
512  printf("MC: sol value: %.0f\n", sol->objective_value());
513 
514  MC_update_solution(soln, sol);
515  }
516  const int cutnum_mult_add = new_cuts.size() - cutnum - cutnum_add;
517  printf("MC: cycle cuts (mult & add): %i\n", cutnum_mult_add);
518 #endif
519 
520  // Shrink the primal solution to be feasible (well, at least the nonzero
521  // rhs constraints...) and generate with additive perturbation
522  {
523 #if 0
524  const double * lhs = lpres.lhs();
525  const int numcuts = cuts.size();
526  double ratio = 1.0;
527  int cnt = 0;
528  double maxviol = 0.0;
529  for (i = 0; i < numcuts; ++i) {
530  const double ub = cuts[i]->ub();
531  if (lhs[i] <= ub)
532  continue;
533  if (ub == 0.0) {
534  ++cnt;
535  maxviol = CoinMax(maxviol, lhs[i] - ub);
536  } else {
537  ratio = CoinMin(ratio, ub/lhs[i]);
538  }
539  }
540  printf("MC: primal shrinking: %.6f , %i cuts left violated (%.6f)\n",
541  ratio, cnt, maxviol);
542  for (i = 0; i < numvars; ++i)
543  xx[i] = x[i]*ratio;
544  for (i = 0; i < heurnum; ++i) {
545  if (i > 0) {
546  for (j = 0; j < numvars; ++j)
547  w[j] = CoinDrand48();
548  }
549  sol = MC_mst_cutgen(mc, xx, w, 1.0, (maxlambda*i)/heurnum, minviol,
550  heurswitchround, new_cuts.size() + max_cycle_num,
551  new_cuts, new_rows);
552  printf("MC: sol value: %.0f\n", sol->objective_value());
553  MC_update_solution(soln, sol);
554  }
555  const int cutnum_shrink_add =
556  new_cuts.size() - cutnum - cutnum_add - cutnum_mult_add;
557  printf("MC: cycle cuts (shrink & add): %i\n", cutnum_shrink_add);
558 #endif
559  }
560  delete[] w;
561  delete[] xx;
562 }
563 
564 void
565 MC_lp::generate_sp_cuts(const double* x, const double* lhs,
566  const double objval,
567  const BCP_vec<BCP_var*>& vars,
568  const BCP_vec<BCP_cut*>& cuts,
569  BCP_vec<BCP_cut*>& new_cuts,
570  BCP_vec<BCP_row*>& new_rows)
571 {
572  const double max_lp_viol = getMaxLpViol();
573  const bool all_sp_cuts = par.entry(MC_lp_par::ReportAllSPCycleCuts);
574  const double minviol =
575  CoinMax(max_lp_viol, par.entry(MC_lp_par::MinSPCycleCutViolation));
576  MC_generate_shortest_path_cycles(mc, x, all_sp_cuts, minviol,
577  new_cuts, new_rows);
578 }
579 
580 void
582  const BCP_vec<BCP_var*>& vars,
583  const BCP_vec<BCP_cut*>& cuts,
584  BCP_vec<BCP_cut*>& new_cuts,
585  BCP_vec<BCP_row*>& new_rows)
586 {
587 #if 0
588  const double* x = lpres.x();
589  double* xx = new double[vars.size()];
590  for (int i = vars.size() - 1; i >= 0; --i) {
591  if (x[i] < 0.0)
592  xx[i] = 0.0;
593  else if (x[i] > 1.0)
594  xx[i] = 1.0;
595  else
596  xx[i] = x[i];
597  }
598  generate_cuts_in_lp(xx, lpres.lhs(), lpres.objval(),
599  vars, cuts, new_cuts, new_rows);
600  delete[] xx;
601 #else
602  generate_cuts_in_lp(lpres.x(), lpres.lhs(), lpres.objval(),
603  vars, cuts, new_cuts, new_rows);
604 #endif
605 }
606 
607 double
609 {
610  double max_lp_viol = 0.0;
611  // If the volume algorithm is used than we want to go with at least as
612  // high minimum violation than the max violation of the last
613  // optimization.
614  OsiVolSolverInterface* vollp =
615  dynamic_cast<OsiVolSolverInterface*>(getLpProblemPointer()->lp_solver);
616  if (vollp) {
617  const double * lhs = getLpProblemPointer()->lp_result->lhs();
618  const double * rhs = vollp->getRightHandSide();
619  for (int k = vollp->getNumRows() - 1; k >= 0; --k)
620  max_lp_viol = CoinMax(max_lp_viol, lhs[k] - rhs[k]);
621  }
622  max_lp_viol += 0.001;
623  return max_lp_viol;
624 }
625 
626 void
627 MC_lp::generate_cuts_in_lp(const double* x, const double* lhs,
628  const double objval,
629  const BCP_vec<BCP_var*>& vars,
630  const BCP_vec<BCP_cut*>& cuts,
631  BCP_vec<BCP_cut*>& new_cuts,
632  BCP_vec<BCP_row*>& new_rows)
633 {
634  bool tailoff_gap_rel, tailoff_lb_abs, tailoff_lb_rel;
635  tailoff_test(tailoff_gap_rel, tailoff_lb_abs, tailoff_lb_rel, objval);
636 
637  const double max_lp_viol = getMaxLpViol();
638 
639  int i, cutnum = new_cuts.size();
640 
642  const int grid = static_cast<int>(sqrt(mc.num_nodes + 1.0));
643  const int grid_nodes = grid*grid;
644  const double minviol =
645  CoinMax(max_lp_viol, par.entry(MC_lp_par::MinIsingCutViolation));
646 
647  if (mc.ising_four_cycles) {
649  x, minviol, new_cuts, new_rows);
650  const int ising_four_cycle_num = new_cuts.size() - cutnum;
651  printf("MC: ising four cycles: %i \n", ising_four_cycle_num);
652  cutnum = new_cuts.size();
653  }
654 
655  if (mc.ising_triangles) {
657  x, 0.9, new_cuts, new_rows);
658  const int ising_triangle_num = new_cuts.size() - cutnum;
659  printf("MC: ising triangles: %i \n", ising_triangle_num);
660  cutnum = new_cuts.size();
661  }
662  }
663 
664  const int gen_mst_cycle = par.entry(MC_lp_par::MstCycleCutGeneration);
665 #if 0
666  const bool mst = gen_mst_cycle == MC_AlwaysGenerateMstCycleCuts;
667 #else
668  const bool mst =
669  gen_mst_cycle == MC_AlwaysGenerateMstCycleCuts ||
670  (gen_mst_cycle == MC_GenerateMstCycleCutsAsLastResort &&
671  (cutnum < 50 || tailoff_gap_rel || tailoff_lb_abs || tailoff_lb_rel));
672 #endif
673 
674  if (mst) {
675  generate_mst_cuts(x, lhs, objval, vars, cuts, new_cuts, new_rows);
676  const int cycle_num = new_cuts.size() - cutnum;
677  unique_cycle_cuts(new_cuts, new_rows);
678  printf("MC: cycle cuts: %i (%i before removing duplicates)\n",
679  static_cast<int>(new_cuts.size()) - cutnum, cycle_num);
680  cutnum = new_cuts.size();
681  }
682 
683  const MC_SPCycleCutGen gen_sp_cycle =
685 #if 0
686  const bool sp_cuts = gen_sp_cycle == MC_AlwaysGenerateSPCycleCuts;
687 #else
688  const bool sp_cuts =
689  gen_sp_cycle == MC_AlwaysGenerateSPCycleCuts ||
690  (gen_sp_cycle == MC_GenerateSPCycleCutsAsLastResort &&
691  (cutnum < 50 || tailoff_gap_rel || tailoff_lb_abs || tailoff_lb_rel));
692 #endif
693 
694  if (sp_cuts) {
695  generate_sp_cuts(x, lhs, objval, vars, cuts, new_cuts, new_rows);
696  const int sp_cycle_num = new_cuts.size() - cutnum;
697  unique_cycle_cuts(new_cuts, new_rows);
698  printf("MC: SP based cycle cuts: %i (%i before removing duplicates)\n",
699  static_cast<int>(new_cuts.size()) - cutnum, sp_cycle_num);
700  cutnum = new_cuts.size();
701  }
702 
703  if (mc.feas_sol) {
704  for (i = 0; i < cutnum; ++i) {
705  const double lhs = new_rows[i]->dotProduct(mc.feas_sol->value);
706  if (new_cuts[i]->lb() != new_rows[i]->LowerBound() ||
707  new_cuts[i]->ub() != new_rows[i]->UpperBound()) {
708  printf("*** What! *** : cut bounds are not the same: %i %f %f %f %f\n",
709  i, new_cuts[i]->lb(), new_rows[i]->LowerBound(),
710  new_cuts[i]->ub(), new_rows[i]->UpperBound());
711  }
712  if (lhs < new_cuts[i]->lb() || lhs > new_cuts[i]->ub()) {
713  printf("*** Violation *** : index: %i lhs: %f lb: %f ub: %f\n",
714  i, lhs, new_cuts[i]->lb(), new_cuts[i]->ub());
715  }
716  }
717  }
718 }
719 
720 //#############################################################################
721 
722 void
724  const BCP_vec<BCP_var*>& vars,
725  const BCP_vec<BCP_cut*>& cuts,
726  const BCP_vec<BCP_obj_status>& var_status,
727  const BCP_vec<BCP_obj_status>& cut_status,
728  const int var_bound_changes_since_logical_fixing,
729  BCP_vec<int>& changed_pos, BCP_vec<double>& new_bd)
730 {
731  /* We are going to find the connected components of the subgraph spanned by
732  the fixed edges and at the same time in each component we'll mark on
733  which side each node is */
734  if (var_bound_changes_since_logical_fixing == 0)
735  return;
736 #if 1
737  const int n = mc.num_nodes;
738  const int m = mc.num_edges;
739  const MC_graph_edge* edges = mc.edges;
740 
741  int * first_on_chain = new int[n];
742  int * last_on_chain = new int[n];
743  int * next_on_chain = new int[n];
744  int * size_of_chain = new int[n];
745  int * sig = new int[n];
746 
747  CoinIotaN(first_on_chain, n, 0);
748  CoinIotaN(last_on_chain, n, 0);
749  CoinFillN(next_on_chain, n, -1);
750  CoinFillN(size_of_chain, n, 1);
751  CoinFillN(sig, n, 1);
752 
753  int tree_size = 0;
754 
755  int label_s = -1; // shorter chain head
756  int label_l = -1; // longer chain head
757  for (int k = 0; k < m; ++k) {
758  if (vars[k]->lb() != vars[k]->ub())
759  continue;
760  const int i = edges[k].tail;
761  const int j = edges[k].head;
762  const int label_i = first_on_chain[i];
763  const int label_j = first_on_chain[j];
764  if (label_i == label_j)
765  continue;
766  if (size_of_chain[label_i] > size_of_chain[label_j]) {
767  label_s = label_j;
768  label_l = label_i;
769  } else {
770  label_s = label_i;
771  label_l = label_j;
772  }
773  ++tree_size;
774  for (int l = label_s; l != -1; l = next_on_chain[l]) {
775  first_on_chain[l] = label_l;
776  }
777  if ((vars[k]->lb() == 0.0 && sig[i] != sig[j]) ||
778  (vars[k]->lb() == 1.0 && sig[i] == sig[j])) {
779  // must reverse the sigs on the shorter chain, too
780  for (int l = label_s; l != -1; l = next_on_chain[l]) {
781  sig[l] *= -1;
782  }
783  }
784  next_on_chain[last_on_chain[label_l]] = label_s;
785  last_on_chain[label_l] = last_on_chain[label_s];
786  size_of_chain[label_l] += size_of_chain[label_s];
787  }
788 
789  delete[] last_on_chain;
790  delete[] next_on_chain;
791  delete[] size_of_chain;
792 
793  // if there are only a few components we caould do brute force
794  // *FIXME*
795  // if (n - tree_size < 6) { ... }
796 
797  const int * component = first_on_chain;
798  for (int k = 0; k < m; ++k) {
799  if (vars[k]->lb() == vars[k]->ub())
800  continue;
801  const int i = edges[k].tail;
802  const int j = edges[k].head;
803  if (component[i] == component[j]) {
804  // this can be fixed!
805  changed_pos.push_back(k);
806  if (sig[i] == sig[j]) {
807  new_bd.push_back(0.0);
808  new_bd.push_back(0.0);
809  } else {
810  new_bd.push_back(1.0);
811  new_bd.push_back(1.0);
812  }
813  }
814  }
815  printf("MC: logical fixing: # of components: %i, fixed %i variables.\n",
816  n - tree_size, static_cast<int>(changed_pos.size()));
817  delete[] first_on_chain;
818  delete[] sig;
819 #endif
820 }
BCP_object_origin
This enumerative constant describes the origin (originating process) of an object (variable or cut)...
Definition: BCP_enum.hpp:249
int * ising_four_cycles
Definition: MC.hpp:105
static bool MC_cycle_row_pair_comp(const std::pair< BCP_cut *, BCP_row * > &p0, const std::pair< BCP_cut *, BCP_row * > &p1)
Definition: MC_lp.cpp:43
MC_solution * MC_mst_cutgen(const MC_problem &mc, const double *x, const double *w, const double alpha, const double beta, const MC_EdgeOrdering edge_ordering, const int heurswitchround, const bool do_edge_switch_heur, const int struct_switch_heur, const double minviol, const int maxnewcuts, BCP_vec< BCP_cut * > &new_cuts, BCP_vec< BCP_row * > &new_rows)
Definition: MC_cutgen.cpp:152
bool MC_cycle_cut_equal(const BCP_cut *bc0, const BCP_cut *bc1)
Definition: MC_cut.hpp:122
int num_edges
Definition: MC.hpp:92
Upper limit on the number of iterations performed in each of the children of the search tree node whe...
void create_adj_lists()
Definition: MC.cpp:115
pos
position where the operator should be printed when printing the expression
void clear()
Delete every entry.
int head
Definition: MC.hpp:30
Abstract base class that defines members common to all types of cuts.
Definition: BCP_cut.hpp:29
int num_nodes
Definition: MC.hpp:91
virtual void unpack_module_data(BCP_buffer &buf)
Unpack the initial information sent to the LP process by the Tree Manager.
Definition: MC_lp.cpp:93
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: MC_lp.cpp:181
char entry(const chr_params key) const
MC_graph_edge * edges
Definition: MC.hpp:95
void MC_generate_shortest_path_cycles(const MC_problem &mc, const double *x, const bool generate_all_cuts, const double minviol, BCP_vec< BCP_cut * > &new_cuts, BCP_vec< BCP_row * > &new_rows)
double * objhist
Definition: MC_lp.hpp:27
void set_param(const BCP_lp_par::chr_params key, const bool val)
Definition: BCP_lp_user.cpp:63
int * edges
Definition: MC_cut.hpp:50
The two objects are the same.
Definition: BCP_enum.hpp:278
const double * lhs() const
const double * x() const
BCP_buffer & unpack(BCP_buffer &buf)
Definition: MC.cpp:58
virtual BCP_object_compare_result compare_cuts(const BCP_cut *c0, const BCP_cut *c1)
Compare two generated cuts.
Definition: MC_lp.cpp:428
void reserve(const size_t n)
Reallocate the object to make space for n entries.
int * ising_triangles
Definition: MC.hpp:107
int current_iteration() const
Return the iteration count within the search tree node being processed.
Definition: BCP_lp_user.cpp:34
MC_solution * soln
Definition: MC_lp.hpp:30
bool started_exact
Definition: MC_lp.hpp:32
double getMaxLpViol()
Definition: MC_lp.cpp:608
void push_back(const_reference x)
Append x to the end of the vector.
static char * j
Definition: OSdtoa.cpp:3622
virtual void modify_lp_parameters(OsiSolverInterface *lp, const int changeType, bool in_strong_branching)
Modify parameters of the LP solver before optimization.
Definition: MC_lp.cpp:141
int tail
Definition: MC.hpp:29
static void MC_update_solution(MC_solution *&sol_old, MC_solution *&sol_new)
Definition: MC_lp.cpp:22
BCP_parameter_set< MC_lp_par > par
Definition: MC_lp.hpp:21
#define BCP_DBL_MAX
Definition: BCP_math.hpp:6
virtual void cuts_to_rows(const BCP_vec< BCP_var * > &vars, BCP_vec< BCP_cut * > &cuts, BCP_vec< BCP_row * > &rows, const BCP_lp_result &lpres, BCP_object_origin origin, bool allow_multiple)
Convert (and possibly lift) a set of cuts into corresponding rows for the current LP relaxation...
Definition: MC_lp.cpp:356
static const int cycle_cut
Definition: MC_cut.cpp:7
int cycle_len
Definition: MC_cut.hpp:48
static double ratio(Bigint *a, Bigint *b)
Definition: OSdtoa.cpp:1460
virtual void logical_fixing(const BCP_lp_result &lpres, 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, const int var_bound_changes_since_logical_fixing, BCP_vec< int > &changed_pos, BCP_vec< double > &new_bd)
This method provides an opportunity for the user to tighten the bounds of variables.
Definition: MC_lp.cpp:723
void erase(iterator pos)
Erase the entry pointed to by pos.
void fint fint fint real fint real real real real real real real real real fint real fint * lp
BCP_lp_prob * getLpProblemPointer()
Get the pointer.
Definition: BCP_lp_user.hpp:95
MC_solution * MC_mst_heur(const MC_problem &mc, const double *x, const double *w, const double alpha, const double beta, const MC_EdgeOrdering edge_ordering, const int heurswitchround, const bool do_edge_switch_heur, const int struct_switch_heur)
Definition: MC_mst_heur.cpp:13
OsiSolverInterface * lp_solver
A class that holds the methods about how to pack things.
Definition: BCP_lp.hpp:137
void generate_mst_cuts(const double *x, const double *lhs, const double objval, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts, BCP_vec< BCP_cut * > &new_cuts, BCP_vec< BCP_row * > &new_rows)
Definition: MC_lp.cpp:437
BCP_lp_result * lp_result
Definition: BCP_lp.hpp:185
double * value
Definition: MC.hpp:60
double objval() const
void fint fint * k
MC_feas_sol * feas_sol
Definition: MC.hpp:114
void unique_cycle_cuts(BCP_vec< BCP_cut * > &new_cuts, BCP_vec< BCP_row * > &new_rows)
Definition: MC_lp.cpp:52
void tailoff_test(bool &tailoff_gap_rel, bool &tailoff_lb_abs, bool &tailoff_lb_rel, const double objval) const
virtual double objective_value() const
The method returning the objective value of the solution.
Definition: MC_solution.hpp:27
virtual BCP_solution * generate_heuristic_solution(const BCP_lp_result &lpres, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts)
Try to generate a heuristic solution (or return one generated during cut/variable generation...
Definition: MC_lp.cpp:231
int hist_len
Definition: MC_lp.hpp:26
Currently there isn&#39;t any error handling in BCP.
Definition: BCP_error.hpp:20
size_t size() const
Return the current number of entries.
Definition: BCP_vector.hpp:116
iterator end()
Return an iterator to the end of the object.
Definition: BCP_vector.hpp:104
This class describes the message buffer used for all processes of BCP.
Definition: BCP_buffer.hpp:39
MC_solution * mc_generate_heuristic_solution(const double *x, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts)
A local helper function.
Definition: MC_lp.cpp:241
virtual void pack_feasible_solution(BCP_buffer &buf, const BCP_solution *sol)
Pack a MIP feasible solution into a buffer.
Definition: MC_lp.cpp:347
int num_structure_type
Definition: MC.hpp:109
The two objects are not comparable or neither is better than the other.
Definition: BCP_enum.hpp:285
int pos_edges
Definition: MC_cut.hpp:49
void unchecked_push_back(const_reference x)
Append x to the end of the vector.
void generate_sp_cuts(const double *x, const double *lhs, const double objval, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts, BCP_vec< BCP_cut * > &new_cuts, BCP_vec< BCP_row * > &new_rows)
Definition: MC_lp.cpp:565
virtual OsiSolverInterface * initialize_solver_interface()
Create LP solver environment.
Definition: MC_lp.cpp:124
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.
void fint * m
This class holds the results after solving an LP relaxation.
void MC_test_ising_triangles(const int n, const int *cycles, const double *x, const double minviol, BCP_vec< BCP_cut * > &cuts, BCP_vec< BCP_row * > &rows)
MC_SPCycleCutGen
Definition: MC_lp_param.hpp:6
iterator entry(const int i)
Return an iterator to the i-th entry.
Definition: BCP_vector.hpp:109
void fint fint fint real fint real real real real real real real real * w
void fint * n
MC_problem mc
Definition: MC_lp.hpp:22
void MC_test_ising_four_cycles(const int n, const int *cycles, const double *x, const double minviol, BCP_vec< BCP_cut * > &cuts, BCP_vec< BCP_row * > &rows)
bool MC_cycle_cut_less(const BCP_cut *bc0, const BCP_cut *bc1)
Definition: MC_cut.hpp:107
BCP_object_compare_result
This enumerative constant describes the possible outcomes when comparing two objects (variables or cu...
Definition: BCP_enum.hpp:276
The maximum number of violated valid inequalities that can be added per iteration.
BCP_buffer & pack(BCP_buffer &buf) const
Definition: MC_solution.cpp:25
void fint fint fint real fint real * x
This class holds a row in a compressed form.
Definition: BCP_matrix.hpp:152
This is the abstract base class for a solution to a Mixed Integer Programming problem.
virtual void generate_cuts_in_lp(const BCP_lp_result &lpres, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts, BCP_vec< BCP_cut * > &new_cuts, BCP_vec< BCP_row * > &new_rows)
Generate cuts within the LP process.
Definition: MC_lp.cpp:581