/home/coin/SVN-release/OS-2.4.0/Couenne/src/convex/operators/conv-exprSinCos.cpp

Go to the documentation of this file.
00001 /* $Id: conv-exprSinCos.cpp 748 2011-07-28 16:13:32Z pbelotti $
00002  *
00003  * Name:    conv-exprSinCos.cpp
00004  * Author:  Pietro Belotti
00005  * Purpose: convexification methods for sines and cosines
00006  *
00007  * (C) Carnegie-Mellon University, 2006-10.
00008  * This file is licensed under the Eclipse Public License (EPL)
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 &,                   // cut set to be enriched
00037                 enum cou_trig,               // sine or cosine
00038                 expression *,                // auxiliary variable
00039                 expression *);               // argument of cos/sin (should be a variable)
00040 #endif
00041 
00043 int trigEnvelope (const CouenneCutGenerator *, OsiCuts &,
00044                   expression *, expression *, enum cou_trig);
00045 
00046 
00048 
00049 void exprSin::generateCuts (expression *w, //const OsiSolverInterface &si, 
00050                             OsiCuts &cs, const CouenneCutGenerator *cg,
00051                             t_chg_bounds *chg, int wind, 
00052                             CouNumber lbw, CouNumber ubw) {
00053 
00054   //  int wi = w -> Index ();
00055 
00056   /*if (chg && !(cg -> isFirst ()) && 
00057       (chg [wi].lower() == t_chg_bounds::UNCHANGED) && 
00058       (chg [wi].upper() == t_chg_bounds::UNCHANGED))
00059       return;*/
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, //const OsiSolverInterface &si, 
00075                             OsiCuts &cs, const CouenneCutGenerator *cg,
00076                             t_chg_bounds *chg, int wind, 
00077                             CouNumber lbw, CouNumber ubw) {
00078 
00079   //  int wi = w -> Index ();
00080 
00081   /*if (chg && !(cg -> isFirst ()) && 
00082       (chg [wi].lower() == t_chg_bounds::UNCHANGED) && 
00083       (chg [wi].upper() == t_chg_bounds::UNCHANGED))
00084       return;*/
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, // cut generator that has called us
00105                    OsiCuts &cs,                  // cut set to be enriched
00106                    expression *w,
00107                    expression *arg,
00108                    enum cou_trig which_trig) {
00109 
00110   CouNumber lb, ub;
00111   arg -> getBounds (lb, ub);
00112 
00113   // if cosine, scale variables to pretend this is a sine problem
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   // true if, in the first call (lb), a lower/upper chord was added
00131   // --> no such chord must be generated in the second call (ub)
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 // study single bay ( \__/ or /  \ ) of the trigonometric function
00144 //
00145 
00146 int bayEnvelope (const CouenneCutGenerator *cg, // cut generator that has called us
00147                  OsiCuts &cs,                   // cut set to be enriched
00148                  int wi,                        //   dependent variable's index
00149                  int xi,                        // independent
00150                  CouNumber x0,                  // starting point
00151                  CouNumber x1,                  // other bound
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   // starting point of the current bay
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     // after  flex (i.e., at \_ or /~ ) for left  bound, 
00179     // before flex (i.e., at _/ or ~\ ) for right bound
00180 
00181     // out of the "belly": tangent. If on upper bay consider the lower
00182     // half-plane, and viceversa --> use -up
00183     if (sign != up) 
00184       ncuts += cg -> addTangent (cs, wi, xi, x0, sin (rx0), cos (rx0), -up);
00185 
00186     // leftmost extreme to search for tangent point
00187     CouNumber extr0 = .75 * M_PI * (left+1) - M_PI_2 * up; 
00188 
00189     // in:
00190     if ((left * (rx1 - M_PI * ((left - up) / 2 + 1)) <= 0) ||   // if rx1 in same "belly", or
00191         (left * (rx1 - (tpt = trigNewton
00192                         (rx0, extr0, extr0 + M_PI_2))) <= 0)) { // before closest leaning point 
00193       if (!*s1 && (sign != -up)) // -> chord, if not already added in previous call
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     // after  stationary point (i.e., _/ or ~\ ) for left  bound, 
00201     // before stationary point (i.e., /~ or \_ ) for right bound
00202   
00203     //    if (left * (rx1 - left * (zero + 5*M_PI_2)) < 0) {
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         // (b,sinb) below tangent --> tangent
00208         if (sign != up)
00209           ncuts += cg -> addTangent (cs, wi, xi, x0, sinrx0, cosrx0, -up);
00210       } else {    // up: either chord or leaning plane
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     // down: other chord or leaning plane
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, // cut generator that has called us
00248                 OsiCuts &cs,                   // cut set to be enriched
00249                 enum cou_trig tt,              // sine or cosine
00250                 expression *aux,               // auxiliary variable
00251                 expression *arg) {             // argument of cos/sin (should be a variable)
00252 
00253   // retrieve argument bounds
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   // add  /    \ envelope
00274   //      \    /
00275 
00276   // left
00277   if (lb > -COUENNE_INFINITY) { // if not unbounded
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.); // up: w-x <= f lb - lb
00280       if (sign != expression::AUX_LEQ) ncuts += cg -> createCut (cs, sin (lb) + lb, +1, w_ind, 1., x_ind,  1.); // dn: w+x >= f lb + lb
00281     }
00282     else {
00283       if (sign != expression::AUX_GEQ) ncuts += cg -> createCut (cs, cos (lb) - lb, -1, w_ind, 1., x_ind, -1.); // up: w-x <= f lb - lb
00284       if (sign != expression::AUX_LEQ) ncuts += cg -> createCut (cs, cos (lb) + lb, +1, w_ind, 1., x_ind,  1.); // dn: w+x >= f lb + lb
00285     }
00286   }
00287 
00288   // right
00289   if (ub <  COUENNE_INFINITY) { // if not unbounded
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.); // dn: w-x >= f ub - ub
00292       if (sign != expression::AUX_GEQ) ncuts += cg -> createCut (cs, sin (ub) + ub, -1, w_ind, 1., x_ind,  1.); // up: w+x <= f ub + ub
00293     }
00294     else {
00295       if (sign != expression::AUX_LEQ) ncuts += cg -> createCut (cs, cos (ub) - ub, +1, w_ind, 1., x_ind, -1.); // dn: w-x >= f ub - ub
00296       if (sign != expression::AUX_GEQ) ncuts += cg -> createCut (cs, cos (ub) + ub, -1, w_ind, 1., x_ind,  1.); // up: w+x <= f ub + ub
00297     }
00298   }
00299 
00300   return ncuts;
00301 }
00302 
00303 #endif
00304 
00305 }

Generated on Thu Sep 22 03:05:56 2011 by  doxygen 1.4.7