00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "CglCutGenerator.hpp"
00012
00013 #include "CouenneCutGenerator.hpp"
00014
00015 #include "CouenneProblem.hpp"
00016 #include "CouenneChooseStrong.hpp"
00017 #include "CouenneChooseVariable.hpp"
00018
00019 #include "CbcTree.hpp"
00020 #include "BonCbc.hpp"
00021 #include "CouenneRecordBestSol.hpp"
00022
00023 using namespace Ipopt;
00024 using namespace Couenne;
00025
00027 CouenneCutGenerator::CouenneCutGenerator (Bonmin::OsiTMINLPInterface *nlp,
00028 Bonmin::BabSetupBase *base,
00029 CouenneProblem *problem,
00030 struct ASL *asl):
00031
00032 CglCutGenerator (),
00033
00034 firstcall_ (true),
00035 problem_ (problem),
00036 nrootcuts_ (0),
00037 ntotalcuts_ (0),
00038 septime_ (0),
00039 objValue_ (- DBL_MAX),
00040 nlp_ (nlp),
00041 BabPtr_ (NULL),
00042 infeasNode_ (false),
00043 jnlst_ (base ? base -> journalist () : NULL),
00044 rootTime_ (-1.) {
00045
00046 if (base) {
00047
00048 base -> options () -> GetIntegerValue ("convexification_points", nSamples_, "couenne.");
00049
00050 std::string s;
00051
00052 base -> options () -> GetStringValue ("convexification_type", s, "couenne.");
00053 if (s == "current-point-only") convtype_ = CURRENT_ONLY;
00054 else if (s == "uniform-grid") convtype_ = UNIFORM_GRID;
00055 else convtype_ = AROUND_CURPOINT;
00056
00057 base -> options () -> GetStringValue ("violated_cuts_only", s, "couenne.");
00058 addviolated_ = (s == "yes");
00059
00060 base -> options () -> GetStringValue ("check_lp", s, "couenne.");
00061 check_lp_ = (s == "yes");
00062
00063 base -> options () -> GetStringValue ("enable_lp_implied_bounds", s, "couenne.");
00064 enable_lp_implied_bounds_ = (s == "yes");
00065
00066 } else {
00067
00068 nSamples_ = 4;
00069 convtype_ = CURRENT_ONLY;
00070 addviolated_ = true;
00071 check_lp_ = false;
00072 enable_lp_implied_bounds_ = false;
00073 }
00074
00075 lastPrintLine = -1;
00076
00077
00078
00079 }
00080
00081
00083 CouenneCutGenerator::~CouenneCutGenerator ()
00084 {}
00085
00086
00088 CouenneCutGenerator::CouenneCutGenerator (const CouenneCutGenerator &src):
00089
00090 CglCutGenerator (src),
00091
00092 firstcall_ (src. firstcall_),
00093 addviolated_ (src. addviolated_),
00094 convtype_ (src. convtype_),
00095 nSamples_ (src. nSamples_),
00096 problem_ (src. problem_),
00097 nrootcuts_ (src. nrootcuts_),
00098 ntotalcuts_ (src. ntotalcuts_),
00099 septime_ (src. septime_),
00100 objValue_ (src. objValue_),
00101 nlp_ (src. nlp_),
00102 BabPtr_ (src. BabPtr_),
00103 infeasNode_ (src. infeasNode_),
00104 jnlst_ (src. jnlst_),
00105 rootTime_ (src. rootTime_),
00106 check_lp_ (src. check_lp_),
00107 enable_lp_implied_bounds_ (src.enable_lp_implied_bounds_),
00108 lastPrintLine(src.lastPrintLine)
00109 {}
00110
00111
00112 #define MAX_SLOPE 1e3
00113
00115 int CouenneCutGenerator::addSegment (OsiCuts &cs, int wi, int xi,
00116 CouNumber x1, CouNumber y1,
00117 CouNumber x2, CouNumber y2, int sign) const {
00118
00119 if (fabs (x2-x1) < COUENNE_EPS) {
00120 if (fabs (y2-y1) > MAX_SLOPE * COUENNE_EPS)
00121 jnlst_->Printf(J_WARNING, J_CONVEXIFYING,
00122 "warning, discontinuity of %e over an interval of %e\n", y2-y1, x2-x1);
00123
00124 }
00125
00126 CouNumber dx = x2-x1, dy = y2-y1;
00127
00128
00129 return createCut (cs, y1*dx - dy*x1, (dx>0) ? sign : -sign, wi, dx, xi, -dy);
00130 }
00131
00132
00134 int CouenneCutGenerator::addTangent (OsiCuts &cs, int wi, int xi,
00135 CouNumber x, CouNumber w,
00136 CouNumber slope, int sign) const
00137 {return createCut (cs, w - slope * x, sign, wi, 1., xi, - slope);}
00138
00139
00141 int CouenneCutGenerator::getnvars () const
00142 {return problem_ -> nVars ();}
00143
00144
00146 void CouenneCutGenerator::registerOptions (Ipopt::SmartPtr <Bonmin::RegisteredOptions> roptions) {
00147
00148 roptions -> SetRegisteringCategory ("Couenne options", Bonmin::RegisteredOptions::CouenneCategory);
00149
00150 roptions -> AddLowerBoundedIntegerOption
00151 ("convexification_cuts",
00152 "Specify the frequency (in terms of nodes) at which couenne ecp cuts are generated.",
00153 -99,1,
00154 "A frequency of 0 amounts to never solve the NLP relaxation.");
00155
00156 roptions -> AddStringOption2
00157 ("check_lp",
00158 "Check all LPs through an independent call to OsiClpSolverInterface::initialSolve()",
00159 "no",
00160 "no","",
00161 "yes","");
00162
00163 roptions -> AddStringOption3
00164 ("convexification_type",
00165 "Determines in which point the linear over/under-estimator are generated",
00166 "current-point-only",
00167 "current-point-only","Only at current optimum of relaxation",
00168 "uniform-grid","Points chosen in a uniform grid between the bounds of the problem",
00169 "around-current-point","At points around current optimum of relaxation",
00170 "For the lower envelopes of convex functions, this is the number of points where a supporting hyperplane is generated. "
00171 "This only holds for the initial linearization, as all other linearizations only add at most one cut per expression."
00172 );
00173
00174 roptions -> AddLowerBoundedIntegerOption
00175 ("convexification_points",
00176 "Specify the number of points at which to convexify when convexification type "
00177 "is uniform-grid or around-current-point.",
00178 0,4,
00179 "");
00180
00181 roptions -> AddStringOption2
00182 ("violated_cuts_only",
00183 "Yes if only violated convexification cuts should be added",
00184 "yes",
00185 "no","",
00186 "yes","");
00187
00188 roptions -> AddStringOption2
00189 ("enable_lp_implied_bounds",
00190 "Enable OsiSolverInterface::tightenBounds () -- warning: it has caused "
00191 "some trouble to Couenne",
00192 "no",
00193 "no","",
00194 "yes","");
00195
00196 roptions -> AddStringOption3
00197 ("multilinear_separation",
00198 "Separation for multilinear terms",
00199 "tight",
00200 "none", "No separation -- just use the four McCormick inequalities",
00201 "simple", "Use one considering lower curve only",
00202 "tight", "Use one considering both curves pi(x) = l_{k+1} and pi(x) = u_{k+1}",
00203 "Type of separation for multilinear terms where the dependent variable is also bounded"
00204 );
00205 }
00206
00207
00208 void CouenneCutGenerator::printLineInfo() const {
00209
00210 double cbcLb = BabPtr_->model().getBestPossibleObjValue();
00211 double lpVal = BabPtr_->model().solver()->getObjValue();
00212 int nbNodes = BabPtr_->model().getNodeCount();
00213 int nbNodesRem = BabPtr_->model().tree()->size();
00214 int depth = BabPtr_->model().currentDepth();
00215 CouenneRecordBestSol *rs = problem_->getRecordBestSol();
00216
00217 if(rs->getHasSol()) {
00218 double bestSolVal = rs->getVal();
00219 printf("%10d %8d %6d %10.6f %10.6f %10.6f\n",
00220 nbNodes, nbNodesRem, depth, cbcLb, lpVal, bestSolVal);
00221 }
00222 else {
00223 printf("%10d %8d %6d %10.6f %10.6f ----------\n",
00224 nbNodes, nbNodesRem, depth, cbcLb, lpVal);
00225 }
00226 problem_->doPrint_ = true;
00227 if((depth < problem_->minDepthPrint_) ||
00228 (nbNodes < problem_->minNodePrint_)) {
00229 problem_->doPrint_ = false;
00230 }
00231
00232
00233
00234
00235
00236
00237 }