00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <math.h>
00012 #ifndef M_PI
00013 # define M_PI 3.14159265358979323846
00014 #endif
00015 #ifndef M_PI_2
00016 # define M_PI_2 1.57079632679489661923
00017 #endif
00018
00019 #include "CouenneCutGenerator.hpp"
00020
00021 #include "OsiSolverInterface.hpp"
00022 #include "CouenneTypes.hpp"
00023 #include "CouenneProblem.hpp"
00024
00025 #include "CouenneExprSin.hpp"
00026 #include "CouenneExprCos.hpp"
00027 #include "CouenneExprAux.hpp"
00028
00029 namespace Couenne {
00030
00031 #define NEW_TRIG
00032
00033 #ifndef NEW_TRIG
00035 int addHexagon (const CouenneCutGenerator *, // cut generator that has called us
00036 OsiCuts &,
00037 enum cou_trig,
00038 expression *,
00039 expression *);
00040 #endif
00041
00043 int trigEnvelope (const CouenneCutGenerator *, OsiCuts &,
00044 expression *, expression *, enum cou_trig);
00045
00046
00048
00049 void exprSin::generateCuts (expression *w,
00050 OsiCuts &cs, const CouenneCutGenerator *cg,
00051 t_chg_bounds *chg, int wind,
00052 CouNumber lbw, CouNumber ubw) {
00053
00054
00055
00056
00057
00058
00059
00060
00061 #ifdef NEW_TRIG
00062 if (trigEnvelope (cg, cs, w, w -> Image () -> Argument (), COU_SINE) == 0)
00063 #else
00064 if (addHexagon (cg, cs, COU_SINE, w, w -> Image () -> Argument()) == 0)
00065 #endif
00066 {
00067
00068 }
00069 }
00070
00071
00073
00074 void exprCos::generateCuts (expression *w,
00075 OsiCuts &cs, const CouenneCutGenerator *cg,
00076 t_chg_bounds *chg, int wind,
00077 CouNumber lbw, CouNumber ubw) {
00078
00079
00080
00081
00082
00083
00084
00085
00086 #ifdef NEW_TRIG
00087 if (trigEnvelope (cg, cs, w, w -> Image () -> Argument (), COU_COSINE) == 0)
00088 #else
00089 if (addHexagon (cg, cs, COU_COSINE, w, w -> Image () -> Argument()) == 0)
00090 #endif
00091 {
00092
00093 }
00094 }
00095
00096
00098 int bayEnvelope (const CouenneCutGenerator *, OsiCuts &, int, int,
00099 CouNumber, CouNumber, CouNumber, bool &, bool &);
00100
00101
00103
00104 int trigEnvelope (const CouenneCutGenerator *cg,
00105 OsiCuts &cs,
00106 expression *w,
00107 expression *arg,
00108 enum cou_trig which_trig) {
00109
00110 CouNumber lb, ub;
00111 arg -> getBounds (lb, ub);
00112
00113
00114 CouNumber displ = (which_trig == COU_COSINE) ? M_PI_2 : 0.;
00115
00116 int ncuts = 0,
00117 xi = arg -> Index (),
00118 wi = w -> Index ();
00119
00120 if (fabs (ub - lb) < COUENNE_EPS) {
00121
00122 CouNumber x0 = 0.5 * (ub+lb), f, fp;
00123
00124 if (which_trig == COU_SINE) {f = sin (x0); fp = cos (x0);}
00125 else {f = cos (x0); fp = -sin (x0);}
00126
00127 return cg -> createCut (cs, f - fp*x0, cg -> Problem () -> Var (wi) -> sign (), wi, 1., xi, -fp);
00128 }
00129
00130
00131
00132 bool skip_up = false,
00133 skip_dn = false;
00134
00135 if (lb > -COUENNE_INFINITY) ncuts += bayEnvelope (cg, cs, wi, xi, lb, ub, displ, skip_up, skip_dn);
00136 if (ub < COUENNE_INFINITY) ncuts += bayEnvelope (cg, cs, wi, xi, ub, lb, displ, skip_up, skip_dn);
00137
00138 return ncuts;
00139 }
00140
00141
00142
00143
00144
00145
00146 int bayEnvelope (const CouenneCutGenerator *cg,
00147 OsiCuts &cs,
00148 int wi,
00149 int xi,
00150 CouNumber x0,
00151 CouNumber x1,
00152 CouNumber displacement,
00153 bool &skip_up,
00154 bool &skip_dn) {
00155
00156 enum expression::auxSign sign = cg -> Problem () -> Var (wi) -> sign ();
00157
00158 CouNumber tpt,
00159 rx0 = modulo (x0 + displacement, 2*M_PI),
00160 rx1 = rx0 + x1 - x0,
00161 base = x0 - rx0,
00162 sinrx0 = sin (rx0), zero;
00163
00164 int ncuts = 0,
00165 up = (rx0 < M_PI) ? +1 : -1,
00166 left = (x0 < x1) ? +1 : -1;
00167
00168
00169 zero = (up>0) ? 0. : M_PI;
00170
00171 bool *s0, *s1;
00172
00173 if (up>0) {s0 = &skip_up; s1 = &skip_dn;}
00174 else {s0 = &skip_dn; s1 = &skip_up;}
00175
00176 if (left * (modulo (rx0, M_PI) - M_PI_2) < 0) {
00177
00178
00179
00180
00181
00182
00183 if (sign != up)
00184 ncuts += cg -> addTangent (cs, wi, xi, x0, sin (rx0), cos (rx0), -up);
00185
00186
00187 CouNumber extr0 = .75 * M_PI * (left+1) - M_PI_2 * up;
00188
00189
00190 if ((left * (rx1 - M_PI * ((left - up) / 2 + 1)) <= 0) ||
00191 (left * (rx1 - (tpt = trigNewton
00192 (rx0, extr0, extr0 + M_PI_2))) <= 0)) {
00193 if (!*s1 && (sign != -up))
00194 *s1 = ((ncuts += cg -> addSegment (cs, wi, xi, x0, sin (rx0), x1, sin (rx1), up)) > 0);
00195 } else
00196 if (sign != -up)
00197 ncuts += cg -> addSegment (cs, wi, xi, x0, sin (rx0), base+tpt, sin (tpt), up);
00198 } else {
00199
00200
00201
00202
00203
00204 if (left * (rx1 - (4*left - up + 2) * M_PI_2) < 0) {
00205 CouNumber cosrx0 = cos (rx0);
00206 if (up * (sin (rx1) - sinrx0 - cosrx0 * (rx1-rx0)) < 0) {
00207
00208 if (sign != up)
00209 ncuts += cg -> addTangent (cs, wi, xi, x0, sinrx0, cosrx0, -up);
00210 } else {
00211 CouNumber searchpt = M_PI_2 * (2 + 3*left - up);
00212 tpt = trigNewton (rx0, searchpt, searchpt + left * M_PI_2);
00213 if (left * (rx1 - tpt) < 0) {
00214 if (!*s0 && (sign != up) )
00215 *s0 = ((ncuts += cg->addSegment (cs, wi, xi, x0, sin(rx0), x1, sin(rx1), -up)) > 0);
00216 } else
00217 if (sign != up)
00218 ncuts += cg->addSegment (cs, wi, xi, x0, sin(rx0), base+tpt, sin(tpt), -up);
00219 }
00220 } else {
00221 CouNumber searchpt = M_PI_2 * (2 + 3*left - up);
00222 tpt = trigNewton (rx0, searchpt, searchpt + left * M_PI_2);
00223 if (sign != up)
00224 ncuts += cg -> addSegment (cs, wi, xi, x0, sin (rx0), base + tpt, sin (tpt), -up);
00225 }
00226
00227
00228 if ((left * (rx1 - (zero + M_PI)) < 0) ||
00229 (left * (rx1 - (tpt = trigNewton (rx0, (2 + left - up) * M_PI_2,
00230 (2 + 2*left - up) * M_PI_2))) < 0)) {
00231 if (!*s1 && (sign != -up))
00232 *s1 = ((ncuts += cg -> addSegment (cs, wi, xi, x0, sin (rx0), x1, sin (rx1), up)) > 0);
00233 } else
00234 if (sign != -up)
00235 ncuts += cg -> addSegment (cs, wi, xi, x0, sin (rx0), base + tpt, sin (tpt), up);
00236 }
00237
00238 return ncuts;
00239 }
00240
00241
00242 #ifndef NEW_TRIG
00243
00244
00246
00247 int addHexagon (const CouenneCutGenerator *cg,
00248 OsiCuts &cs,
00249 enum cou_trig tt,
00250 expression *aux,
00251 expression *arg) {
00252
00253
00254 CouNumber lb, ub;
00255 arg -> getBounds (lb, ub);
00256
00257 int ncuts = 0,
00258 x_ind = arg -> Index (),
00259 w_ind = aux -> Index ();
00260
00261 enum auxSign sign = cg -> Problem () -> Var (w_ind) -> sign ();
00262
00263 if (fabs (ub - lb) < COUENNE_EPS) {
00264
00265 CouNumber x0 = 0.5 * (ub+lb), f, fp;
00266
00267 if (tt == COU_SINE) {f = sin (x0); fp = cos (x0);}
00268 else {f = cos (x0); fp = -sin (x0);}
00269
00270 return cg -> createCut (cs, f - fp*x0, sign, w_ind, 1., x_ind, -fp);
00271 }
00272
00273
00274
00275
00276
00277 if (lb > -COUENNE_INFINITY) {
00278 if (tt == COU_SINE) {
00279 if (sign != expression::AUX_GEQ) ncuts += cg -> createCut (cs, sin (lb) - lb, -1, w_ind, 1., x_ind, -1.);
00280 if (sign != expression::AUX_LEQ) ncuts += cg -> createCut (cs, sin (lb) + lb, +1, w_ind, 1., x_ind, 1.);
00281 }
00282 else {
00283 if (sign != expression::AUX_GEQ) ncuts += cg -> createCut (cs, cos (lb) - lb, -1, w_ind, 1., x_ind, -1.);
00284 if (sign != expression::AUX_LEQ) ncuts += cg -> createCut (cs, cos (lb) + lb, +1, w_ind, 1., x_ind, 1.);
00285 }
00286 }
00287
00288
00289 if (ub < COUENNE_INFINITY) {
00290 if (tt == COU_SINE) {
00291 if (sign != expression::AUX_LEQ) ncuts += cg -> createCut (cs, sin (ub) - ub, +1, w_ind, 1., x_ind, -1.);
00292 if (sign != expression::AUX_GEQ) ncuts += cg -> createCut (cs, sin (ub) + ub, -1, w_ind, 1., x_ind, 1.);
00293 }
00294 else {
00295 if (sign != expression::AUX_LEQ) ncuts += cg -> createCut (cs, cos (ub) - ub, +1, w_ind, 1., x_ind, -1.);
00296 if (sign != expression::AUX_GEQ) ncuts += cg -> createCut (cs, cos (ub) + ub, -1, w_ind, 1., x_ind, 1.);
00297 }
00298 }
00299
00300 return ncuts;
00301 }
00302
00303 #endif
00304
00305 }