00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "CouenneCutGenerator.hpp"
00012
00013 #include "CouenneExprMul.hpp"
00014 #include "CouennePrecisions.hpp"
00015
00016 namespace Couenne {
00017
00018
00019
00020 int findIntersection (CouNumber x0, CouNumber y0,
00021 CouNumber x1, CouNumber y1,
00022 CouNumber *wl, CouNumber *wu,
00023 CouNumber *xA, CouNumber *yA,
00024 CouNumber *xB, CouNumber *yB);
00025
00026 int genMulCoeff (CouNumber x1, CouNumber y1,
00027 CouNumber x2, CouNumber y2,
00028 char whichUse,
00029 CouNumber &cX, CouNumber &cY, CouNumber &cW);
00030
00031
00032
00033 inline void invertInterval (register double &l, register double &u, register double x) {
00034
00035 register double tmp = l;
00036 l = -u;
00037 u = -tmp;
00038
00039 x = -x;
00040 }
00041
00042 void upperEnvHull (const CouenneCutGenerator *cg, OsiCuts &cs,
00043 int xi, CouNumber x0, CouNumber xl, CouNumber xu,
00044 int yi, CouNumber y0, CouNumber yl, CouNumber yu,
00045 int wi, CouNumber w0, CouNumber wl, CouNumber wu) {
00046
00047
00048
00049
00050
00051
00052
00053
00054 #ifdef DEBUG
00055 printf ("entering points: ===================================================\n");
00056 printf ("x [%d]: %9g\t[%9g\t%9g]\n", xi, x0, xl, xu);
00057 printf ("y [%d]: %9g\t[%9g\t%9g]\n", yi, y0, yl, yu);
00058 printf ("w [%d]: %9g\t[%9g\t%9g]\n", wi, w0, wl, wu);
00059 #endif
00060
00061
00062
00063 if ((wl < 0 && wu > 0))
00064 return;
00065
00066
00067 if (x0 < xl) x0 = xl; if (x0 > xu) x0 = xu;
00068 if (y0 < yl) y0 = yl; if (y0 > yu) y0 = yu;
00069
00070
00071 if (wl >= 0) {
00072 if ((xl >= 0) || (yl >= 0) || (xl * yl < wl - COUENNE_EPS)) {
00073 if (xl < 0) xl = 0;
00074 if (yl < 0) yl = 0;
00075 } else if ((xu <= 0) || (yu <= 0) || (xu * yu < wl - COUENNE_EPS)) {
00076 if (xu > 0) xu = 0;
00077 if (yu > 0) yu = 0;
00078 }
00079 } else {
00080 if ((xl >= 0) || (yu <= 0) || (xl * yu > wu + COUENNE_EPS)) {
00081 if (xl < 0) xl = 0;
00082 if (yu > 0) yu = 0;
00083 } else if ((xu <= 0) || (yl >= 0) || (xu * yl > wu + COUENNE_EPS)) {
00084 if (xu > 0) xu = 0;
00085 if (yl < 0) yl = 0;
00086 }
00087 }
00088
00089
00090
00091 bool
00092 flipX = xl < 0,
00093 flipY = yl < 0,
00094 flipW = false;
00095
00096 if (flipX && flipY) {
00097
00098 invertInterval (xl,xu,x0);
00099 invertInterval (yl,yu,y0);
00100
00101 } else if (flipX) {
00102
00103 invertInterval (xl,xu,x0);
00104 invertInterval (wl,wu,w0);
00105
00106 flipW = true;
00107
00108 } else if (flipY) {
00109
00110 invertInterval (yl,yu,y0);
00111 invertInterval (wl,wu,w0);
00112
00113 flipW = true;
00114 }
00115
00116 #ifdef DEBUG
00117 printf ("reduced points:\n");
00118 printf ("x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
00119 printf ("y: %9g\t[%9g\t%9g]\n", y0, yl, yu);
00120 printf ("w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
00121 #endif
00122
00123
00124
00125
00126 if (((xl*yl >= wl) &&
00127 (xu*yu <= wu)) ||
00128 (x0*y0 >= w0))
00129 return;
00130
00131
00132
00133 CouNumber xLow, yLow, xUpp, yUpp;
00134 if (findIntersection (0., 0., x0, y0, &wl, &wu, &xLow, &yLow, &xUpp, &yUpp))
00135 return;
00136
00137 #ifdef DEBUG
00138 printf ("intersections:\n");
00139 printf ("lower: %9g\t%9g\tprod %9g\n", xLow, yLow, xLow*yLow);
00140 printf ("upper: %9g\t%9g\tprod %9g\n", xUpp, yUpp, xUpp*yUpp);
00141 #endif
00142
00143
00144
00145 if ((xLow <= xl && yUpp >= yu) ||
00146 (yLow <= yl && xUpp >= xu))
00147 return;
00148
00149
00150
00151
00152 CouNumber
00153 cX, cY, cW, c0, c0X, c0Y, c0W;
00154
00155 if (xLow >= xl && xUpp <= xu &&
00156 yLow >= yl && yUpp <= yu) {
00157
00158 #ifdef DEBUG
00159 printf ("easy lifting:\n");
00160 #endif
00161
00162
00163 if (genMulCoeff (xLow, yLow, xUpp, yUpp, 0, cX, cY, cW))
00164 return;
00165
00166 c0X = cX * xLow;
00167 c0Y = cY * yLow;
00168 c0W = cW * wl;
00169
00170 } else if (xLow >= xl && yLow >= yl &&
00171 (xUpp > xu || yUpp > yu)) {
00172
00173 #ifdef DEBUG
00174 printf ("through lower, not upper:\n");
00175 #endif
00176
00177
00178
00179 if (yUpp > yu) {
00180 yUpp = yu;
00181 xUpp = CoinMin (xu, wu / yu);
00182 } else {
00183 xUpp = xu;
00184 yUpp = CoinMin (yu, wu / xu);
00185 }
00186
00187
00188 if ((findIntersection (xUpp, yUpp, x0, y0, &wl, NULL, &xLow, &yLow, NULL, NULL)) ||
00189 (xLow < xl || yLow < yl) ||
00190 (genMulCoeff (xLow, yLow, xUpp, yUpp, 0, cX, cY, cW)))
00191 return;
00192
00193 c0X = cX * xLow;
00194 c0Y = cY * yLow;
00195 c0W = cW * wl;
00196
00197 } else if (xUpp <= xu && yUpp <= yu &&
00198 (xLow < xl || yLow < yl)) {
00199
00200 #ifdef DEBUG
00201 printf ("through upper, not lower:\n");
00202 #endif
00203
00204
00205
00206 if (yLow < yl) {
00207 yLow = yl;
00208 xLow = CoinMax (xl, wl / yl);
00209 } else {
00210 xLow = xl;
00211 yLow = CoinMax (yl, wl / xl);
00212 }
00213
00214
00215 if ((findIntersection (xLow, yLow, x0, y0, NULL, &wu, NULL, NULL, &xUpp, &yUpp)) ||
00216 (xUpp > xu || yUpp > yu) ||
00217 (genMulCoeff (xLow, yLow, xUpp, yUpp, 1, cX, cY, cW)))
00218 return;
00219
00220 c0X = cX * xUpp;
00221 c0Y = cY * yUpp;
00222 c0W = cW * wu;
00223
00224 } else if ((xLow < xl && xUpp > xu) ||
00225 (yLow < yl && yUpp > yu)) {
00226
00227 #ifdef DEBUG
00228 printf ("between lower and upper:\n");
00229 #endif
00230
00231
00232
00233
00234 if (yLow < yl) {
00235 yLow = yl; xLow = CoinMax (xl, wl / yl);
00236 yUpp = yu; xUpp = CoinMin (xu, wu / yu);
00237 } else {
00238 xLow = xl; yLow = CoinMax (yl, wl / xl);
00239 xUpp = xu; yUpp = CoinMax (yu, wu / xu);
00240 }
00241
00242 #ifdef DEBUG
00243 printf ("New intersections:\n");
00244 printf ("lower: %9g\t%9g\tprod %9g\n", xLow, yLow, xLow*yLow);
00245 printf ("upper: %9g\t%9g\tprod %9g\n", xUpp, yUpp, xUpp*yUpp);
00246 #endif
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 CouNumber xLow2 = xLow, yLow2 = yLow, xUpp2, yUpp2;
00260
00261 if ((findIntersection (xLow, yLow, x0, y0, NULL, &wu, NULL, NULL, &xUpp2, &yUpp2) || genMulCoeff (xLow, yLow, xUpp2, yUpp2, 0, cX, cY, cW)) &&
00262 (findIntersection (xUpp, yUpp, x0, y0, &wl, NULL, &xLow2, &yLow2, NULL, NULL) || genMulCoeff (xLow2, yLow2, xUpp, yUpp, 1, cX, cY, cW)))
00263 return;
00264
00265 #ifdef DEBUG
00266 printf ("coeffs: (%g,%g,%g)\n",
00267 cX,cY,cW);
00268 #endif
00269
00270 c0X = cX * xLow2;
00271 c0Y = cY * yLow2;
00272 c0W = cW * wl;
00273
00274
00275
00276 } else {
00277
00278 #ifdef DEBUG
00279 printf ("points are in a weird position:\n");
00280 printf ("lower: %9g\t%9g\tprod %9g\n", xLow, yLow, xLow*yLow);
00281 printf ("upper: %9g\t%9g\tprod %9g\n", xUpp, yUpp, xUpp*yUpp);
00282 #endif
00283
00284 return;
00285 }
00286
00287
00288
00289 if (flipX) {cX = -cX; c0X = -c0X;}
00290 if (flipY) {cY = -cY; c0Y = -c0Y;}
00291 if (flipW) {cW = -cW; c0W = -c0W;}
00292
00293 c0 = c0X + c0Y + c0W;
00294
00295 #ifdef DEBUG
00296 printf ("there are cuts\n");
00297 #endif
00298
00299
00300 cg -> createCut (cs, c0, 1, wi, cW, yi, cY, xi, cX);
00301 }
00302
00303
00304
00305
00306
00307 int findIntersection (CouNumber x0, CouNumber y0,
00308 CouNumber x1, CouNumber y1,
00309 CouNumber *wl, CouNumber *wu,
00310 CouNumber *xA, CouNumber *yA,
00311 CouNumber *xB, CouNumber *yB) {
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329 CouNumber
00330 a = (x1-x0) * (y1-y0),
00331 c = x0 * y0,
00332 b = x0*y1 + y0*x1 - 2*c;
00333
00334 if (fabs (a) < COUENNE_EPS)
00335 return 1;
00336
00337
00338
00339 CouNumber tL1, tL2, tU1, tU2, tL=0., tU=0.;
00340
00341 if (wl) {
00342 tL1 = (- b - sqrt (b*b - 4*a*(c-*wl))) / (2*a);
00343 tL2 = (- b + sqrt (b*b - 4*a*(c-*wl))) / (2*a);
00344
00345 tL = (tL1 < 0) ? tL2 : tL1;
00346 }
00347
00348 if (wu) {
00349 tU1 = (- b - sqrt (b*b - 4*a*(c-*wu))) / (2*a);
00350 tU2 = (- b + sqrt (b*b - 4*a*(c-*wu))) / (2*a);
00351
00352 tU = (tU1 < 0) ? tU2 : tU1;
00353 }
00354
00355 if (xA) *xA = x0 + tL * (x1-x0); if (yA) *yA = y0 + tL * (y1-y0);
00356 if (xB) *xB = x0 + tU * (x1-x0); if (yB) *yB = y0 + tU * (y1-y0);
00357
00358 return 0;
00359 }
00360
00361
00362
00363
00364
00365
00366
00367 int genMulCoeff (CouNumber x1, CouNumber y1,
00368 CouNumber x2, CouNumber y2,
00369 char whichUse,
00370 CouNumber &cX, CouNumber &cY, CouNumber &cW) {
00371
00372
00373
00374
00375 CouNumber xD, yD, xO, yO;
00376
00377 if (!whichUse) {
00378 xD = x1; xO = x2;
00379 yD = y1; yO = y2;
00380 } else {
00381 xD = x2; xO = x1;
00382 yD = y2; yO = y1;
00383 }
00384
00385 cX = yD;
00386 cY = xD;
00387
00388
00389 #ifdef DEBUG
00390 printf ("points: (%g,%g) (%g,%g), cW = (%g - %g) / %g = %g\n",
00391 xD,yD, xO,yO, 2*xD*yD, (cX*xO + cY*yO), (xO*yO - xD*yD),
00392 (2*xD*yD - (cX*xO + cY*yO)) / (xO*yO - xD*yD));
00393 #endif
00394
00395
00396
00397 if (fabs (xO*yO - xD*yD) < COUENNE_EPS)
00398 return 1;
00399
00400
00401 cW = (2*xD*yD - (cX*xO + cY*yO)) / (xO*yO - xD*yD);
00402
00403 return 0;
00404 }
00405
00406 }