MC++
~mccormick.hpp
00001 // Copyright (C) 2009-2013 Benoit Chachuat, Imperial College London.
00002 // All Rights Reserved.
00003 
00340 #ifndef MC__MCCORMICK_H
00341 #define MC__MCCORMICK_H
00342 
00343 #include <iostream>
00344 #include <iomanip>
00345 #include <stdarg.h>
00346 #include <cassert>
00347 
00348 #include "mcfunc.hpp"
00349 #include "mcop.hpp"
00350 
00351 namespace mc
00352 {
00361 template <typename T>
00362 class McCormick
00364 {
00365   template <typename U> friend class McCormick;
00366 
00367   template <typename U> friend McCormick<U> operator+
00368     ( const McCormick<U>& );
00369   template <typename U> friend McCormick<U> operator+
00370     ( const McCormick<U>&, const McCormick<U>& );
00371   template <typename U> friend McCormick<U> operator+
00372     ( const double, const McCormick<U>& );
00373   template <typename U> friend McCormick<U> operator+
00374     ( const McCormick<U>&, const double );
00375   template <typename U> friend McCormick<U> operator-
00376     ( const McCormick<U>& );
00377   template <typename U> friend McCormick<U> operator-
00378     ( const McCormick<U>&, const McCormick<U>& );
00379   template <typename U> friend McCormick<U> operator-
00380     ( const double, const McCormick<U>& );
00381   template <typename U> friend McCormick<U> operator-
00382     ( const McCormick<U>&, const double );
00383   template <typename U> friend McCormick<U> operator*
00384     ( const McCormick<U>&, const McCormick<U>& );
00385   template <typename U> friend McCormick<U> operator*
00386     ( const double, const McCormick<U>& );
00387   template <typename U> friend McCormick<U> operator*
00388     ( const McCormick<U>&, const double );
00389   template <typename U> friend McCormick<U> operator/
00390     ( const McCormick<U>&, const McCormick<U>& );
00391   template <typename U> friend McCormick<U> operator/
00392     ( const double, const McCormick<U>& );
00393   template <typename U> friend McCormick<U> operator/
00394     ( const McCormick<U>&, const double );
00395   template <typename U> friend std::ostream& operator<<
00396     ( std::ostream&, const McCormick<U>& );
00397   template <typename U> friend bool operator==
00398     ( const McCormick<U>&, const McCormick<U>& );
00399   template <typename U> friend bool operator!=
00400     ( const McCormick<U>&, const McCormick<U>& );
00401   template <typename U> friend bool operator<=
00402     ( const McCormick<U>&, const McCormick<U>& );
00403   template <typename U> friend bool operator>=
00404     ( const McCormick<U>&, const McCormick<U>& );
00405   template <typename U> friend bool operator<
00406     ( const McCormick<U>&, const McCormick<U>& );
00407   template <typename U> friend bool operator>
00408     ( const McCormick<U>&, const McCormick<U>& );
00409 
00410   template <typename U> friend McCormick<U> inv
00411     ( const McCormick<U>& );
00412   template <typename U> friend McCormick<U> sqr
00413     ( const McCormick<U>& );
00414   template <typename U> friend McCormick<U> exp
00415     ( const McCormick<U>& );
00416   template <typename U> friend McCormick<U> log
00417     ( const McCormick<U>& );
00418   template <typename U> friend McCormick<U> cos
00419     ( const McCormick<U>& );
00420   template <typename U> friend McCormick<U> sin
00421     ( const McCormick<U>& );
00422   template <typename U> friend McCormick<U> tan
00423     ( const McCormick<U>& );
00424   template <typename U> friend McCormick<U> acos
00425     ( const McCormick<U>& );
00426   template <typename U> friend McCormick<U> asin
00427     ( const McCormick<U>& );
00428   template <typename U> friend McCormick<U> atan
00429     ( const McCormick<U>& );
00430   template <typename U> friend McCormick<U> fabs
00431     ( const McCormick<U>& );
00432   template <typename U> friend McCormick<U> sqrt
00433     ( const McCormick<U>& );
00434   template <typename U> friend McCormick<U> xlog
00435     ( const McCormick<U>& );
00436   template <typename U> friend McCormick<U> arh
00437     ( const McCormick<U>&, const double );
00438   template <typename U> friend McCormick<U> erf
00439     ( const McCormick<U>& );
00440   template <typename U> friend McCormick<U> erfc
00441     ( const McCormick<U>& );
00442   template <typename U> friend McCormick<U> fstep
00443     ( const McCormick<U>& );
00444   template <typename U> friend McCormick<U> bstep
00445     ( const McCormick<U>& );
00446   template <typename U> friend McCormick<U> pow
00447     ( const McCormick<U>&, const int );
00448   template <typename U> friend McCormick<U> pow
00449     ( const McCormick<U>&, const double );
00450   template <typename U> friend McCormick<U> pow
00451     ( const double, const McCormick<U>& );
00452   template <typename U> friend McCormick<U> pow
00453     ( const McCormick<U>&, const McCormick<U>& );
00454   template <typename U> friend McCormick<U> monomial
00455     ( const unsigned int, const McCormick<U>*, const int* );
00456   template <typename U> friend McCormick<U> min
00457     ( const McCormick<U>&, const McCormick<U>& );
00458   template <typename U> friend McCormick<U> max
00459     ( const McCormick<U>&, const McCormick<U>& );
00460   template <typename U> friend McCormick<U> min
00461     ( const unsigned int, const McCormick<U>* );
00462   template <typename U> friend McCormick<U> max
00463     ( const unsigned int, const McCormick<U>* );
00464   template <typename U> friend McCormick<U> ltcond
00465     ( const McCormick<U>&, const McCormick<U>&, const McCormick<U>& );
00466   template <typename U> friend McCormick<U> ltcond
00467     ( const U&, const McCormick<U>&, const McCormick<U>& );
00468   template <typename U> friend McCormick<U> gtcond
00469     ( const McCormick<U>&, const McCormick<U>&, const McCormick<U>& );
00470   template <typename U> friend McCormick<U> gtcond
00471     ( const U&, const McCormick<U>&, const McCormick<U>& );
00472   template <typename U> friend bool inter
00473     ( McCormick<U>&, const McCormick<U>&, const McCormick<U>& );
00474   template <typename U> friend McCormick<U> hull
00475     ( const McCormick<U>&, const McCormick<U>& );
00476   template <typename U> friend McCormick<U> cut
00477     ( const McCormick<U>& );
00478 
00479 public:
00480 
00481   McCormick<T>& operator=
00482     ( const McCormick<T>& );
00483   McCormick<T>& operator=
00484     ( const T& );
00485   McCormick<T>& operator=
00486     ( const double );
00487   McCormick<T>& operator+=
00488     ( const McCormick<T>& );
00489   McCormick<T>& operator+=
00490     ( const double );
00491   McCormick<T>& operator-=
00492     ( const McCormick<T>& );
00493   McCormick<T>& operator-=
00494     ( const double );
00495   McCormick<T>& operator*=
00496     ( const McCormick<T>& );
00497   McCormick<T>& operator*=
00498     ( const double );
00499   McCormick<T>& operator/=
00500     ( const McCormick<T>& );
00501   McCormick<T>& operator/=
00502     ( const double );
00503 
00507 
00508   static struct Options
00509   {
00511     Options():
00512       ENVEL_USE(true), ENVEL_MAXIT(100), ENVEL_TOL(1e-10), MVCOMP_USE(false),
00513       MVCOMP_TOL(1e1*machprec()), DISPLAY_DIGITS(5)
00514       {}
00516     bool ENVEL_USE;
00518     unsigned int ENVEL_MAXIT;
00520     double ENVEL_TOL;
00522     bool MVCOMP_USE;
00524     double MVCOMP_TOL;
00526     unsigned int DISPLAY_DIGITS;
00527   } options;
00528 
00530   class Exceptions
00531   {
00532   public:
00534     enum TYPE{
00535       DIV=1,   
00536       INV,  
00537       LOG,  
00538       SQRT, 
00539       ASIN, 
00540       TAN,  
00541       MULTSUB=-3, 
00542       ENVEL,   
00543       SUB   
00544     };
00546     Exceptions( TYPE ierr ) : _ierr( ierr ){}
00548     int ierr(){ return _ierr; }
00550     std::string what(){
00551       switch( _ierr ){
00552       case DIV:
00553         return "mc::McCormick\t Division by zero";
00554       case INV:
00555         return "mc::McCormick\t Inverse with zero in range";
00556       case LOG:
00557         return "mc::McCormick\t Log with negative values in range";
00558       case SQRT:
00559         return "mc::McCormick\t Square-root with nonpositive values in range";
00560       case ASIN:
00561         return "mc::McCormick\t Inverse sine with values outside of [-1,1] range";
00562       case TAN:
00563         return "mc::McCormick\t Tangent with values pi/2+k*pi in range";
00564       case MULTSUB:
00565         return "mc::McCormick\t Subgradient propagation failed";
00566       case ENVEL:
00567         return "mc::McCormick\t Convex/concave envelope computation failed";
00568       case SUB:
00569         return "mc::McCormick\t Inconsistent subgradient dimension";
00570       }
00571       return "mc::McCormick\t Undocument error";
00572     }
00573 
00574   private:
00575     TYPE _ierr;
00576   };
00577 
00579   McCormick():
00580     _nsub(0), _cvsub(0), _ccsub(0), _const(true)
00581     {}
00583   McCormick
00584     ( const double c ):
00585     _nsub(0), _cv(c), _cc(c), _cvsub(0), _ccsub(0), _const(true)
00586     {
00587       Op<T>::I(_I,c);
00588     }
00590   McCormick
00591     ( const T&I ):
00592     _nsub(0), _cvsub(0), _ccsub(0), _const(true)
00593     {
00594       Op<T>::I(_I,I);
00595       _cv = Op<T>::l(I); _cc = Op<T>::u(I);
00596     }
00598   McCormick
00599     ( const T&I, const double c ):
00600     _nsub(0), _cv(c), _cc(c), _cvsub(0), _ccsub(0), _const(false)
00601     {
00602       Op<T>::I(_I,I);
00603     }
00605   McCormick
00606     ( const T&I, const double cv, const double cc ):
00607     _nsub(0), _cv(cv), _cc(cc), _cvsub(0), _ccsub(0), _const(false)
00608     {
00609       Op<T>::I(_I,I); cut();
00610     }
00612   McCormick
00613     ( const McCormick<T>&MC ):
00614     _nsub(MC._nsub), _cv(MC._cv), _cc(MC._cc),
00615     _cvsub(_nsub>0?new double[_nsub]:0), _ccsub(_nsub>0?new double[_nsub]:0),
00616     _const(MC._const)
00617     {
00618       Op<T>::I(_I,MC._I);
00619       for ( unsigned int ip=0; ip<_nsub; ip++ ){
00620         _cvsub[ip] = MC._cvsub[ip];
00621         _ccsub[ip] = MC._ccsub[ip];
00622       }
00623     }
00625   template <typename U> McCormick
00626     ( const McCormick<U>&MC ):
00627     _nsub(MC._nsub), _cv(MC._cv), _cc(MC._cc),
00628     _cvsub(_nsub>0?new double[_nsub]:0), _ccsub(_nsub>0?new double[_nsub]:0),
00629     _const(MC._const)
00630     {
00631       Op<T>::I(_I,MC._I);
00632       for ( unsigned int ip=0; ip<_nsub; ip++ ){
00633         _cvsub[ip] = MC._cvsub[ip];
00634         _ccsub[ip] = MC._ccsub[ip];
00635       }
00636     }
00637 
00639   ~McCormick()
00640     {
00641       delete [] _cvsub;
00642       delete [] _ccsub;
00643     }
00644 
00646   unsigned int& nsub()
00647     {
00648       return _nsub;
00649     }
00650   const unsigned int nsub() const
00651     {
00652       return _nsub;
00653     }
00655   T& I()
00656     {
00657       return _I;
00658     }
00659   const T& I() const
00660     {
00661       return _I;
00662     }
00664   const double l() const
00665     {
00666       return Op<T>::l(_I);
00667     }
00669   const double u() const
00670     {
00671       return Op<T>::u(_I);
00672     }
00674   double& cv()
00675     {
00676       return _cv;
00677     }
00678   const double cv() const
00679     {
00680       return _cv;
00681     }
00683   double& cc()
00684     {
00685       return _cc;
00686     }
00687   const double cc() const
00688     {
00689       return _cc;
00690     }
00692   double*& cvsub()
00693     {
00694       return _cvsub;
00695     }
00696   const double* cvsub() const
00697     {
00698       return _cvsub;
00699     }
00701   double*& ccsub()
00702     {
00703       return _ccsub;
00704     }
00705   const double* ccsub() const
00706     {
00707       return _ccsub;
00708     }
00710   double& cvsub
00711     ( const unsigned int i )
00712     {
00713       return _cvsub[i];
00714     }
00715   const double cvsub
00716     ( const unsigned int i ) const
00717     {
00718       return _cvsub[i];
00719     }
00721   double& ccsub
00722     ( const unsigned int i )
00723     {
00724       return _ccsub[i];
00725     }
00726   const double ccsub
00727     ( const unsigned int i ) const
00728     {
00729       return _ccsub[i];
00730     }
00731 
00733   void I
00734     ( const T& I )
00735     {
00736       Op<T>::I(_I,I);
00737     }
00739   void cv
00740     ( const double& cv )
00741     {
00742       _cv = cv;
00743       _const = false;
00744     }
00746   void cc
00747     ( const double& cc )
00748     {
00749       _cc = cc;
00750       _const = false;
00751     }
00753   void c
00754     ( const double& c )
00755     {
00756       _cv = _cc = c;
00757       _const = false;
00758     }
00759 
00761   McCormick<T>& sub
00762     ( const unsigned int nsub);
00764   McCormick<T>& sub
00765     ( const unsigned int nsub, const unsigned int isub );
00767   McCormick<T>& sub
00768     ( const unsigned int nsub, const double*cvsub, const double*ccsub );
00769 
00771   McCormick<T>& cut();
00773   double laff
00774     ( const double*p, const double*pref ) const;
00776   double laff
00777     ( const T*Ip, const double*pref ) const;
00779   double uaff
00780     ( const double*p, const double*pref ) const;
00782   double uaff
00783     ( const T*Ip, const double*pref ) const;
00786 private:
00787 
00789   unsigned int _nsub;
00791   T _I;
00793   double _cv;
00795   double _cc;
00797   double *_cvsub;
00799   double *_ccsub;
00801   bool _const;
00802   
00804   void _sub
00805     ( const unsigned int nsub, const bool cst );
00807   void _sub_reset();
00809   void _sub_resize
00810     ( const unsigned int nsub );
00812   void _sub_copy
00813     ( const McCormick<T>&MC );
00814 
00816   McCormick<T>& _sum1
00817     ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
00819   McCormick<T>& _sum2
00820     ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
00821 
00823   McCormick<T>& _sub1
00824     ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
00826   McCormick<T>& _sub2
00827     ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
00829   McCormick<T>& _sub3
00830     ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
00831 
00833   McCormick<T>& _mul1_u1pos_u2pos
00834     ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
00836   McCormick<T>& _mul2_u1pos_u2pos
00837     ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
00839   McCormick<T>& _mul1_u1pos_u2mix
00840     ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
00842   McCormick<T>& _mul2_u1pos_u2mix
00843     ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
00845   McCormick<T>& _mul3_u1pos_u2mix
00846     ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
00848   McCormick<T>& _mul1_u1mix_u2mix
00849     ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
00851   McCormick<T>& _mul2_u1mix_u2mix
00852     ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
00854   McCormick<T>& _mulMV
00855     ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
00856 
00858   typedef double (puniv)
00859     ( const double x, const double*rusr, const int*iusr );
00861   static double _newton
00862     ( const double x0, const double xL, const double xU, const puniv f,
00863       const puniv df, const double*rusr, const int*iusr=0 );
00865   static double _secant
00866     ( const double x0, const double x1, const double xL, const double xU,
00867       const puniv f, const double*rusr, const int*iusr );
00869   static double _goldsect
00870     ( const double xL, const double xU, const puniv f, const double*rusr,
00871       const int*iusr );
00873   static double _goldsect_iter
00874     ( const bool init, const double a, const double fa, const double b,
00875       const double fb, const double c, const double fc, const puniv f,
00876       const double*rusr, const int*iusr );
00877 
00879   static double* _oddpowcv
00880     ( const double x, const int iexp, const double xL, const double xU );
00882   static double* _oddpowcc
00883     ( const double x, const int iexp, const double xL, const double xU );
00885   static double _oddpowenv_func
00886     ( const double x, const double*rusr, const int*iusr );
00888   static double _oddpowenv_dfunc
00889     ( const double x, const double*rusr, const int*iusr );
00890 
00892   static double* _erfcv
00893     ( const double x, const double xL, const double xU );
00895   static double* _erfcc
00896     ( const double x, const double xL, const double xU );
00898   static double _erfenv_func
00899     ( const double x, const double*rusr, const int*iusr );
00901   static double _erfenv_dfunc
00902     ( const double x, const double*rusr, const int*iusr );
00903 
00905   static double* _atancv
00906     ( const double x, const double xL, const double xU );
00908   static double* _atancc
00909     ( const double x, const double xL, const double xU );
00911   static double _atanenv_func
00912     ( const double x, const double*rusr, const int*iusr );
00914   static double _atanenv_dfunc
00915     ( const double x, const double*rusr, const int*iusr );
00916 
00918   static double* _stepcv
00919     ( const double x, const double xL, const double xU );
00921   static double* _stepcc
00922     ( const double x, const double xL, const double xU );
00923 
00925   static double* _cosarg
00926     (  const double xL, const double xU );
00928   static double* _coscv
00929     ( const double x, const double xL, const double xU );
00931   static double* _coscc
00932     ( const double x, const double xL, const double xU );
00934   static double* _coscv2
00935     ( const double x, const double xL, const double xU );
00937   static double _cosenv_func
00938     ( const double x, const double*rusr, const int*iusr );
00940   static double _cosenv_dfunc
00941     ( const double x, const double*rusr, const int*iusr );
00942 
00944   static double* _asincv
00945     ( const double x, const double xL, const double xU );
00947   static double* _asincc
00948     ( const double x, const double xL, const double xU );
00950   static double _asinenv_func
00951     ( const double x, const double*rusr, const int*iusr );
00953   static double _asinenv_dfunc
00954     ( const double x, const double*rusr, const int*iusr );
00955 
00957   static double* _tancv
00958     ( const double x, const double xL, const double xU );
00960   static double* _tancc
00961     ( const double x, const double xL, const double xU );
00963   static double _tanenv_func
00964     ( const double x, const double*rusr, const int*iusr );
00966   static double _tanenv_dfunc
00967     ( const double x, const double*rusr, const int*iusr );
00968 };
00969 
00971 
00972 template <typename T> inline void
00973 McCormick<T>::_sub_reset()
00974 {
00975   delete [] _cvsub;
00976   delete [] _ccsub;
00977   _cvsub = _ccsub = 0;
00978 }
00979 
00980 template <typename T> inline void
00981 McCormick<T>::_sub_resize
00982 ( const unsigned int nsub )
00983 {
00984   if( _nsub != nsub ){
00985     delete [] _cvsub;
00986     delete [] _ccsub;
00987     _nsub = nsub;
00988     if( _nsub > 0 ){
00989       _cvsub = new double[_nsub];
00990       _ccsub = new double[_nsub];
00991     }
00992     else{
00993       _cvsub = _ccsub = 0;
00994       return;
00995     }
00996   }
00997 }
00998 
00999 template <typename T> inline void
01000 McCormick<T>::_sub_copy
01001 ( const McCormick<T>&MC )
01002 {
01003   _sub_resize( MC._nsub );
01004   for ( unsigned int i=0; i<_nsub; i++ ){
01005     _cvsub[i] = MC._cvsub[i];
01006     _ccsub[i] = MC._ccsub[i];
01007   }
01008   return;
01009 }
01010 
01011 template <typename T> inline void
01012 McCormick<T>::_sub
01013 ( const unsigned int nsub, const bool cst )
01014 {
01015   _sub_resize( nsub );
01016   for ( unsigned int i=0; i<nsub; i++ ){
01017     _cvsub[i] = _ccsub[i] = 0.;
01018   }
01019   _const = cst;
01020 }
01021 
01022 template <typename T> inline McCormick<T>&
01023 McCormick<T>::sub
01024 ( const unsigned int nsub )
01025 {
01026   _sub( nsub, false );
01027   return *this;
01028 }
01029 
01030 template <typename T> inline McCormick<T>&
01031 McCormick<T>::sub
01032 ( const unsigned int nsub, const unsigned int isub )
01033 {
01034   if( isub >= nsub ) throw Exceptions( Exceptions::SUB );
01035   sub( nsub );
01036   _cvsub[isub] = _ccsub[isub] = 1.;
01037   return *this;
01038 }
01039 
01040 template <typename T> inline McCormick<T>&
01041 McCormick<T>::sub
01042 ( const unsigned int nsub, const double*cvsub, const double*ccsub )
01043 {
01044   if( nsub && !(cvsub && ccsub) ) throw Exceptions( Exceptions::SUB );
01045   sub( nsub );
01046   for ( unsigned int i=0; i<nsub; i++ ){
01047     _cvsub[i] = cvsub[i];
01048     _ccsub[i] = ccsub[i];
01049   }
01050   return *this;
01051 }
01052 
01053 template <typename T> inline McCormick<T>&
01054 McCormick<T>::cut()
01055 {
01056   if( _cv < Op<T>::l(_I) ){
01057     _cv = Op<T>::l(_I);
01058     for( unsigned int i=0; i<_nsub; i++ ) _cvsub[i] = 0.;
01059   }
01060   if( _cc > Op<T>::u(_I) ){
01061     _cc = Op<T>::u(_I);
01062     for( unsigned int i=0; i<_nsub; i++ ) _ccsub[i] = 0.;
01063   }
01064   return *this;
01065 }
01066 
01067 template <typename T> inline double
01068 McCormick<T>::laff
01069 ( const double*p, const double*pref ) const
01070 {
01071   double _laff = _cv;
01072   for( unsigned int i=0; i<_nsub; i++ ){
01073     _laff += _cvsub[i]*(p[i]-pref[i]);
01074   }
01075   return _laff;
01076 }
01077 
01078 template <typename T> inline double
01079 McCormick<T>::laff
01080 ( const T*Ip, const double*pref ) const
01081 {
01082   double _laff = _cv;
01083   for( unsigned int i=0; i<_nsub; i++ ){
01084     _laff += Op<T>::l(_cvsub[i]*(Ip[i]-pref[i]));
01085   }
01086   return _laff;
01087 }
01088 
01089 template <typename T> inline double
01090 McCormick<T>::uaff
01091 ( const double*p, const double*pref ) const
01092 {
01093   double _uaff = _cc;
01094   for( unsigned int i=0; i<_nsub; i++ ){
01095     _uaff += _ccsub[i]*(p[i]-pref[i]);
01096   }
01097   return _uaff;
01098 }
01099 
01100 template <typename T> inline double
01101 McCormick<T>::uaff
01102 ( const T*Ip, const double*pref ) const
01103 {
01104   double _uaff = _cc;
01105   for( unsigned int i=0; i<_nsub; i++ ){
01106     _uaff += Op<T>::u(_ccsub[i]*(Ip[i]-pref[i]));
01107   }
01108   return _uaff;
01109 }
01110 
01111 template <typename T> inline McCormick<T>&
01112 McCormick<T>::operator=
01113 ( const double c )
01114 {
01115   _I = c;
01116   _cv = _cc = c;
01117   _sub_reset();  
01118   _nsub = 0;
01119   _const = true; 
01120   return *this;
01121 }
01122 
01123 template <typename T> inline McCormick<T>&
01124 McCormick<T>::operator=
01125 ( const T&I )
01126 {
01127   _I = I;
01128   _cv = Op<T>::l(I);
01129   _cc = Op<T>::u(I);
01130   _sub_reset();
01131   _nsub = 0;
01132   _const = true;
01133   return *this;
01134 }
01135 
01136 template <typename T> inline McCormick<T>&
01137 McCormick<T>::operator=
01138 ( const McCormick<T>&MC )
01139 {
01140   if( this == &MC ) return *this;
01141   _I = MC._I;
01142   _cv = MC._cv;
01143   _cc = MC._cc;
01144   _sub_copy( MC );
01145   _const = MC._const;
01146   return *this;
01147 }
01148 
01149 template <typename T> inline McCormick<T>&
01150 McCormick<T>::operator+=
01151 ( const double a )
01152 { 
01153   _I += a;
01154   _cv += a;
01155   _cc += a; 
01156   return *this;
01157 }
01158 
01159 template <typename T> inline McCormick<T>&
01160 McCormick<T>::operator+=
01161 ( const McCormick<T> &MC )
01162 {
01163   if( _const && !MC._const ) sub( MC._nsub );
01164   else if( !MC._const && _nsub != MC._nsub ) throw Exceptions( Exceptions::SUB );
01165   _I += MC._I;
01166   _cv += MC._cv;
01167   _cc += MC._cc;
01168   for( unsigned int i=0; i<_nsub && !MC._const; i++ ){
01169     _cvsub[i] += MC._cvsub[i];
01170     _ccsub[i] += MC._ccsub[i];
01171   }
01172   return *this;
01173 }
01174 
01175 template <typename T> inline McCormick<T>&
01176 McCormick<T>::_sum1
01177 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
01178 {
01179   _I = MC1._I + MC2._I;
01180   _cv = MC1._cv + MC2._cv;
01181   _cc = MC1._cc + MC2._cc;
01182   for( unsigned int i=0; i<_nsub; i++ ){
01183     _cvsub[i] = MC1._cvsub[i];
01184     _ccsub[i] = MC1._ccsub[i];
01185   }
01186   return *this;
01187 }
01188 
01189 template <typename T> inline McCormick<T>&
01190 McCormick<T>::_sum2
01191 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
01192 {
01193   _I = MC1._I + MC2._I;
01194   _cv = MC1._cv + MC2._cv;
01195   _cc = MC1._cc + MC2._cc;
01196   for( unsigned int i=0; i<_nsub; i++ ){
01197     _cvsub[i] = MC1._cvsub[i] + MC2._cvsub[i];
01198     _ccsub[i] = MC1._ccsub[i] + MC2._ccsub[i];
01199   }
01200   return *this;
01201 }
01202 
01203 template <typename T> inline McCormick<T>&
01204 McCormick<T>::operator-=
01205 ( const double a )
01206 { 
01207   _I -= a;
01208   _cv -= a;
01209   _cc -= a; 
01210   return *this;
01211 }
01212 
01213 template <typename T> inline McCormick<T>&
01214 McCormick<T>::operator-=
01215 ( const McCormick<T> &MC )
01216 {
01217   if( _const && !MC._const ) sub( MC._nsub );
01218   else if( !MC._const && _nsub != MC._nsub ) throw Exceptions( Exceptions::SUB );
01219   _I -= MC._I;
01220   double t_cv = MC._cv;
01221   _cv -= MC._cc;
01222   _cc -= t_cv;
01223   for( unsigned int i=0; i<_nsub && !MC._const; i++ ){
01224     double t_cvsub = MC._cvsub[i];
01225     _cvsub[i] -= MC._ccsub[i];
01226     _ccsub[i] -= t_cvsub;
01227   }
01228   return *this;
01229 }
01230 
01231 template <typename T> inline McCormick<T>&
01232 McCormick<T>::_sub1
01233 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
01234 {
01235   _I = MC1._I - MC2._I;
01236   _cv = MC1._cv - MC2._cc;
01237   _cc = MC1._cc - MC2._cv;
01238   for( unsigned int i=0; i<_nsub; i++ ){
01239     _cvsub[i] = MC1._cvsub[i];
01240     _ccsub[i] = MC1._ccsub[i];
01241   }
01242   return *this;
01243 }
01244 
01245 template <typename T> inline McCormick<T>&
01246 McCormick<T>::_sub2
01247 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
01248 {
01249   _I = MC1._I - MC2._I;
01250   _cv = MC1._cv - MC2._cc;
01251   _cc = MC1._cc - MC2._cv;
01252   for( unsigned int i=0; i<_nsub; i++ ){
01253     _cvsub[i] = -MC2._ccsub[i];
01254     _ccsub[i] = -MC2._cvsub[i];
01255   }
01256   return *this;
01257 }
01258 
01259 template <typename T> inline McCormick<T>&
01260 McCormick<T>::_sub3
01261 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
01262 {
01263   _I = MC1._I - MC2._I;
01264   _cv = MC1._cv - MC2._cc;
01265   _cc = MC1._cc - MC2._cv;
01266   for( unsigned int i=0; i<_nsub; i++ ){
01267     _cvsub[i] = MC1._cvsub[i] - MC2._ccsub[i];
01268     _ccsub[i] = MC1._ccsub[i] - MC2._cvsub[i];
01269   }
01270   return *this;
01271 }
01272 
01273 template <typename T> inline McCormick<T>&
01274 McCormick<T>::operator*=
01275 ( const double a )
01276 {
01277   McCormick<T> MC2 = a * (*this);
01278   *this = MC2;
01279   return *this;
01280 }
01281 
01282 template <typename T> inline McCormick<T>&
01283 McCormick<T>::operator*=
01284 ( const McCormick<T>&MC )
01285 {
01286   if( _const && !MC._const ) sub( MC._nsub );
01287   McCormick<T> MC2 = MC * (*this);
01288   *this = MC2;
01289   return *this;
01290 }
01291 
01292 template <typename T> inline McCormick<T>&
01293 McCormick<T>::_mul1_u1pos_u2pos
01294 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
01295 {
01296   _I = MC1._I * MC2._I;
01297 
01298   double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
01299     - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
01300   double cv2 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::l(MC1._I) * MC2._cv
01301     - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
01302   if ( cv1 > cv2 ){
01303     _cv = cv1;
01304     for( unsigned int i=0; i<_nsub; i++ )
01305       _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i];
01306   }
01307   else{
01308     _cv = cv2;
01309     for( unsigned int i=0; i<_nsub; i++ )
01310       _cvsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i];
01311   }
01312 
01313   double cc1 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::u(MC1._I) * MC2._cc
01314     - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
01315   double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
01316     - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
01317   if ( cc1 < cc2 ){
01318     _cc = cc1;
01319     for( unsigned int i=0; i<_nsub; i++ )
01320       _ccsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i];
01321   }
01322   else{
01323     _cc = cc2;
01324     for( unsigned int i=0; i<_nsub; i++ )
01325       _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i];
01326   }
01327   return *this;
01328 }
01329 
01330 template <typename T> inline McCormick<T>&
01331 McCormick<T>::_mul2_u1pos_u2pos
01332 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
01333 {
01334   _I = MC1._I * MC2._I;
01335 
01336   double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
01337     - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
01338   double cv2 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::l(MC1._I) * MC2._cv
01339     - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
01340   if ( cv1 > cv2 ){
01341     _cv = cv1;
01342     for( unsigned int i=0; i<_nsub; i++ )
01343       _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._cvsub[i];
01344   }
01345   else{
01346     _cv = cv2;
01347     for( unsigned int i=0; i<_nsub; i++ )
01348       _cvsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i] + Op<T>::l(MC1._I) * MC2._cvsub[i];
01349   }
01350 
01351   double cc1 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::u(MC1._I) * MC2._cc
01352     - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
01353   double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
01354     - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
01355   if ( cc1 < cc2 ){
01356     _cc = cc1;
01357     for( unsigned int i=0; i<_nsub; i++ )
01358       _ccsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i] + Op<T>::u(MC1._I) * MC2._ccsub[i];
01359   }
01360   else{
01361     _cc = cc2;
01362     for( unsigned int i=0; i<_nsub; i++ )
01363       _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._ccsub[i];
01364   }
01365   return *this;
01366 }
01367 
01368 template <typename T> inline McCormick<T>&
01369 McCormick<T>::_mul1_u1pos_u2mix
01370 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
01371 {
01372   _I = MC1._I * MC2._I;
01373 
01374   double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
01375     - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
01376   double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv
01377     - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
01378   if ( cv1 > cv2 ){
01379     _cv = cv1;
01380     for( unsigned int i=0; i<_nsub; i++ )
01381       _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i];
01382   }
01383   else{
01384     _cv = cv2;
01385     for( unsigned int i=0; i<_nsub; i++ )
01386       _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i];
01387   }
01388 
01389   double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc
01390     - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
01391   double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
01392     - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
01393   if ( cc1 < cc2 ){
01394     _cc = cc1;
01395     for( unsigned int i=0; i<_nsub; i++ )
01396       _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i];
01397   }
01398   else{
01399     _cc = cc2;
01400     for( unsigned int i=0; i<_nsub; i++ )
01401       _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i];
01402   }
01403   return *this;
01404 }
01405 
01406 template <typename T> inline McCormick<T>&
01407 McCormick<T>::_mul2_u1pos_u2mix
01408 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
01409 {
01410   _I = MC1._I * MC2._I;
01411 
01412   double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
01413     - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
01414   double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv
01415     - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
01416   if ( cv1 > cv2 ){
01417     _cv = cv1;
01418     for( unsigned int i=0; i<_nsub; i++ )
01419       _cvsub[i] = Op<T>::u(MC1._I) * MC2._cvsub[i];
01420   }
01421   else{
01422     _cv = cv2;
01423     for( unsigned int i=0; i<_nsub; i++ )
01424       _cvsub[i] = Op<T>::l(MC1._I) * MC2._cvsub[i];
01425   }
01426 
01427   double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc
01428     - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
01429   double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
01430     - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
01431   if ( cc1 < cc2 ){
01432     _cc = cc1;
01433     for( unsigned int i=0; i<_nsub; i++ )
01434       _ccsub[i] = Op<T>::u(MC1._I) * MC2._ccsub[i];
01435   }
01436   else{
01437     _cc = cc2;
01438     for( unsigned int i=0; i<_nsub; i++ )
01439       _ccsub[i] = Op<T>::l(MC1._I) * MC2._ccsub[i];
01440   }
01441   return *this;
01442 }
01443 
01444 template <typename T> inline McCormick<T>&
01445 McCormick<T>::_mul3_u1pos_u2mix
01446 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
01447 {
01448   _I = MC1._I * MC2._I;
01449 
01450   double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
01451     - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
01452   double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv
01453     - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
01454   if ( cv1 > cv2 ){
01455     _cv = cv1;
01456     for( unsigned int i=0; i<_nsub; i++ )
01457       _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._cvsub[i];
01458   }
01459   else{
01460     _cv = cv2;
01461     for( unsigned int i=0; i<_nsub; i++ )
01462       _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._cvsub[i];
01463   }
01464 
01465   double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc
01466     - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
01467   double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
01468     - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
01469   if ( cc1 < cc2 ){
01470     _cc = cc1;
01471     for( unsigned int i=0; i<_nsub; i++ )
01472       _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._ccsub[i];
01473   }
01474   else{
01475     _cc = cc2;
01476     for( unsigned int i=0; i<_nsub; i++ )
01477       _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._ccsub[i];
01478   }
01479   return *this;
01480 }
01481 
01482 template <typename T> inline McCormick<T>&
01483 McCormick<T>::_mul1_u1mix_u2mix
01484 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
01485 {
01486   _I = MC1._I * MC2._I;
01487 
01488   double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
01489     - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
01490   double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
01491     - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
01492   if ( cv1 > cv2 ){
01493     _cv = cv1;
01494     for( unsigned int i=0; i<_nsub; i++ )
01495       _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i];
01496   }
01497   else{
01498     _cv = cv2;
01499     for( unsigned int i=0; i<_nsub; i++ )
01500       _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i];
01501   }
01502 
01503   double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc
01504     - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
01505   double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv
01506     - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
01507   if ( cc1 < cc2 ){
01508     _cc = cc1;
01509     for( unsigned int i=0; i<_nsub; i++ )
01510       _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i];
01511   }
01512   else{
01513     _cc = cc2;
01514     for( unsigned int i=0; i<_nsub; i++ )
01515       _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i];
01516   }
01517   return *this;
01518 }
01519 
01520 template <typename T> inline McCormick<T>&
01521 McCormick<T>::_mul2_u1mix_u2mix
01522 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
01523 {
01524   _I = MC1._I * MC2._I;
01525 
01526   double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
01527     - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
01528   double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
01529     - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
01530   if ( cv1 > cv2 ){
01531     _cv = cv1;
01532     for( unsigned int i=0; i<_nsub; i++ )
01533       _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._cvsub[i];
01534   }
01535   else{
01536     _cv = cv2;
01537     for( unsigned int i=0; i<_nsub; i++ )
01538       _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._ccsub[i];
01539   }
01540 
01541   double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc
01542     - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
01543   double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv
01544     - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
01545   if ( cc1 < cc2 ){
01546     _cc = cc1;
01547     for( unsigned int i=0; i<_nsub; i++ )
01548       _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._ccsub[i];
01549   }
01550   else{
01551     _cc = cc2;
01552     for( unsigned int i=0; i<_nsub; i++ )
01553       _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._cvsub[i];
01554   }
01555   return *this;
01556 }
01557 
01558 template <typename T> inline McCormick<T>&
01559 McCormick<T>::_mulMV
01560 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
01561 {
01562  // Convex underestimator part
01563  {const double k = - Op<T>::diam(MC2._I) / Op<T>::diam(MC1._I);
01564   const double z = ( Op<T>::u(MC1._I)*Op<T>::u(MC2._I)
01565                    - Op<T>::l(MC1._I)*Op<T>::l(MC2._I) )
01566                    / Op<T>::diam(MC1._I);
01567   struct fct{
01568     static double t1
01569       ( const double x1, const double x2, const McCormick<T>&MC1,
01570         const McCormick<T>&MC2 )
01571       { return Op<T>::u(MC2._I) * x1 + Op<T>::u(MC1._I) * x2
01572         - Op<T>::u(MC2._I) * Op<T>::u(MC1._I); }
01573     static double t2
01574       ( const double x1, const double x2, const McCormick<T>&MC1,
01575         const McCormick<T>&MC2 )
01576       { return Op<T>::l(MC2._I) * x1 + Op<T>::l(MC1._I) * x2
01577         - Op<T>::l(MC2._I) * Op<T>::l(MC1._I); }
01578     static double t
01579       ( const double x1, const double x2, const McCormick<T>&MC1,
01580         const McCormick<T>&MC2 )
01581       { return std::max( t1(x1,x2,MC1,MC2), t2(x1,x2,MC1,MC2) ); }
01582   };
01583 
01584   int imid[4] = { -1, -1, -1, -1 };
01585   const double x1t[4] = { MC1._cv, MC1._cc,
01586                           mid( MC1._cv, MC1._cc, (MC2._cv-z)/k, imid[0] ),
01587                 mid( MC1._cv, MC1._cc, (MC2._cc-z)/k, imid[1] ) };
01588   const double x2t[4] = { mid( MC2._cv, MC2._cc, k*MC1._cv+z, imid[2] ),
01589                 mid( MC2._cv, MC2._cc, k*MC1._cc+z, imid[3] ),
01590                           MC2._cv, MC2._cc };
01591   const double v[4] = { fct::t( x1t[0], x2t[0], MC1, MC2 ), fct::t( x1t[1], x2t[1], MC1, MC2 ),
01592                         fct::t( x1t[2], x2t[2], MC1, MC2 ), fct::t( x1t[3], x2t[3], MC1, MC2 ) };
01593   const unsigned int ndx = argmin( 4, v );
01594   _cv = v[ndx];
01595 
01596   if( _nsub ){
01597     double myalpha;
01598     if( isequal( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ),
01599                  fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ),
01600        options.MVCOMP_TOL, options.MVCOMP_TOL ) ){
01601       std::pair<double,double> alpha( 0., 1. );
01602       if( x1t[ndx] > MC1._cv )
01603         alpha.second = std::min( alpha.second, -Op<T>::l(MC2._I)/Op<T>::diam(MC2._I) );
01604       if( x1t[ndx] < MC1._cc )
01605         alpha.first = std::max( alpha.first, -Op<T>::l(MC2._I)/Op<T>::diam(MC2._I) );
01606       if( x2t[ndx] > MC2._cv )
01607         alpha.second = std::min( alpha.second, -Op<T>::l(MC1._I)/Op<T>::diam(MC1._I) );
01608       if( x2t[ndx] < MC2._cc )
01609         alpha.first = std::max( alpha.first, -Op<T>::l(MC1._I)/Op<T>::diam(MC1._I) );
01610       if( alpha.first > alpha.second ){
01611         std::cout << "WARNING: alphaL= " << alpha.first << "  alphaU= " << alpha.second
01612              << std::endl;
01613         throw Exceptions( Exceptions::MULTSUB );
01614       }
01615       myalpha = 0.5*( alpha.first + alpha.second );
01616     }
01617     else if( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ) > fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ) )
01618       myalpha = 1.;
01619     else
01620       myalpha = 0.;
01621     double sigma1cv = Op<T>::l(MC2._I) + myalpha * Op<T>::diam(MC2._I),
01622            sigma2cv = Op<T>::l(MC1._I) + myalpha * Op<T>::diam(MC1._I);
01623     for( unsigned int i=0; i<_nsub; i++ )
01624       _cvsub[i] = ( sigma1cv>=0? MC1._cvsub[i]: MC1._ccsub[i] ) * sigma1cv
01625                 + ( sigma2cv>=0? MC2._cvsub[i]: MC2._ccsub[i] ) * sigma2cv;
01626   }
01627  }
01628 
01629  // Concave overestimator part
01630  {const double k = Op<T>::diam(MC2._I) / Op<T>::diam(MC1._I);
01631   const double z = ( Op<T>::u(MC1._I)*Op<T>::l(MC2._I)
01632                    - Op<T>::l(MC1._I)*Op<T>::u(MC2._I) )
01633                    / Op<T>::diam(MC1._I);
01634   struct fct{
01635     static double t1
01636       ( const double x1, const double x2, const McCormick<T>&MC1,
01637         const McCormick<T>&MC2 )
01638       { return Op<T>::l(MC2._I) * x1 + Op<T>::u(MC1._I) * x2
01639         - Op<T>::l(MC2._I) * Op<T>::u(MC1._I); }
01640     static double t2
01641       ( const double x1, const double x2, const McCormick<T>&MC1,
01642         const McCormick<T>&MC2 )
01643       { return Op<T>::u(MC2._I) * x1 + Op<T>::l(MC1._I) * x2
01644         - Op<T>::u(MC2._I) * Op<T>::l(MC1._I); }
01645     static double t
01646       ( const double x1, const double x2, const McCormick<T>&MC1,
01647         const McCormick<T>&MC2 )
01648       { return std::min( t1(x1,x2,MC1,MC2), t2(x1,x2,MC1,MC2) ); }
01649   };
01650 
01651   int imid[4] = { -1, -1, -1, -1 };
01652   const double x1t[4] = { MC1._cv, MC1._cc,
01653                           mid( MC1._cv, MC1._cc, (MC2._cv-z)/k, imid[0] ),
01654                 mid( MC1._cv, MC1._cc, (MC2._cc-z)/k, imid[1] ) };
01655   const double x2t[4] = { mid( MC2._cv, MC2._cc, k*MC1._cv+z, imid[2] ),
01656                 mid( MC2._cv, MC2._cc, k*MC1._cc+z, imid[3] ),
01657            MC2._cv, MC2._cc };
01658   const double v[4] = { fct::t( x1t[0], x2t[0], MC1, MC2 ), fct::t( x1t[1], x2t[1], MC1, MC2 ),
01659                         fct::t( x1t[2], x2t[2], MC1, MC2 ), fct::t( x1t[3], x2t[3], MC1, MC2 ) };
01660   const unsigned int ndx = argmax( 4, v );
01661   _cc = v[ndx];
01662 
01663   if( _nsub ){
01664     double myalpha;
01665     if( isequal( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ),
01666                  fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ),
01667        options.MVCOMP_TOL, options.MVCOMP_TOL ) ){
01668       std::pair<double,double> alpha( 0., 1. );
01669       if( x1t[ndx] > MC1._cv )
01670         alpha.first = std::max( alpha.first, -Op<T>::l(MC2._I)/Op<T>::diam(MC2._I) );
01671       if( x1t[ndx] < MC1._cc )
01672         alpha.second = std::min( alpha.second, -Op<T>::l(MC2._I)/Op<T>::diam(MC2._I) );
01673       if( x2t[ndx] > MC2._cv )
01674         alpha.second = std::min( alpha.second, Op<T>::u(MC1._I)/Op<T>::diam(MC1._I) );
01675       if( x2t[ndx] < MC2._cc )
01676         alpha.first = std::max( alpha.first, Op<T>::u(MC1._I)/Op<T>::diam(MC1._I) );
01677       if( alpha.first > alpha.second ){
01678         std::cout << "WARNING: alphaL= " << alpha.first << "  alphaU= " << alpha.second
01679              << std::endl;
01680         throw Exceptions( Exceptions::MULTSUB );
01681       }
01682       myalpha = 0.5*( alpha.first + alpha.second );
01683     }
01684     else if( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ) < fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ) )
01685       myalpha = 0.;
01686     else
01687       myalpha = 1.;
01688     double sigma1cc = Op<T>::l(MC2._I) + myalpha * Op<T>::diam(MC2._I),
01689            sigma2cc = Op<T>::u(MC1._I) - myalpha * Op<T>::diam(MC1._I);
01690     for( unsigned int i=0; i<_nsub; i++ )
01691       _ccsub[i] = ( sigma1cc>=0? MC1._ccsub[i]: MC1._cvsub[i] ) * sigma1cc
01692                 + ( sigma2cc>=0? MC2._ccsub[i]: MC2._cvsub[i] ) * sigma2cc;
01693   }
01694  }
01695 
01696   return *this;
01697 }
01698 
01699 template <typename T> inline McCormick<T>&
01700 McCormick<T>::operator/=
01701 ( const double a )
01702 {
01703   McCormick<T> MC2 = (*this) / a;
01704   *this = MC2;
01705   return *this;
01706 }
01707 
01708 template <typename T> inline McCormick<T>&
01709 McCormick<T>::operator/=
01710 ( const McCormick<T>&MC )
01711 {
01712   if( _const && !MC._const ) sub( MC._nsub );
01713   McCormick<T> MC2 = (*this) / MC;
01714   *this = MC2;
01715   return *this;
01716 }
01717 
01718 template <typename T> inline double*
01719 McCormick<T>::_erfcv
01720 ( const double x, const double xL, const double xU )
01721 {
01722   static double cv[2];
01723   if( xU <= 0. ){  // convex part
01724     cv[0] = ::erf(x), cv[1] = 2./std::sqrt(PI)*std::exp(-sqr(x));
01725     return cv;
01726   }
01727 
01728   if( xL >= 0. ){  // concave part
01729     double r = ( isequal( xL, xU )? 0.:(::erf(xU)-::erf(xL))/(xU-xL) );
01730     cv[0] = ::erf(xL)+r*(x-xL), cv[1] = r;
01731     return cv;
01732   }
01733     
01734   double xj;
01735   try{
01736     xj = _newton( xL, xL, 0., _erfenv_func, _erfenv_dfunc, &xU );
01737   }
01738   catch( McCormick<T>::Exceptions ){
01739     xj = _goldsect( xL, 0., _erfenv_func, &xU, 0 );
01740   }
01741   if( x <= xj ){   // convex part
01742     cv[0] = ::erf(x), cv[1] = 2./std::sqrt(PI)*std::exp(-sqr(x));
01743     return cv;
01744   }
01745   double r = ( isequal( xj, xU )? 0.:(::erf(xU)-::erf(xj))/(xU-xj) );
01746   cv[0] = ::erf(xU)+r*(x-xU), cv[1] = r;
01747   return cv;
01748 }
01749 
01750 template <typename T> inline double*
01751 McCormick<T>::_erfcc
01752 ( const double x, const double xL, const double xU )
01753 {
01754   static double cc[2];
01755   if( xU <= 0. ){  // convex part
01756     double r = ( isequal( xL, xU )? 0.:(::erf(xU)-::erf(xL))/(xU-xL) );
01757     cc[0] = ::erf(xL)+r*(x-xL), cc[1] = r;
01758     return cc;
01759   }
01760 
01761   if( xL >= 0. ){  // concave part
01762     cc[0] = ::erf(x), cc[1] = 2./std::sqrt(PI)*std::exp(-sqr(x));
01763     return cc;
01764   }
01765 
01766   double xj;
01767   try{
01768     xj = _newton( xU, 0., xU, _erfenv_func, _erfenv_dfunc, &xL );
01769   }
01770   catch( McCormick<T>::Exceptions ){
01771     xj = _goldsect( 0., xU, _erfenv_func, &xL, 0 );
01772   }
01773   if( x >= xj ){   // concave part
01774     cc[0] = ::erf(x), cc[1] = 2./std::sqrt(PI)*std::exp(-sqr(x));
01775     return cc;
01776   }
01777   double r = ( isequal( xj, xL )? 0.:(::erf(xL)-::erf(xj))/(xL-xj) );
01778   cc[0] = ::erf(xL)+r*(x-xL), cc[1] = r;
01779   return cc;
01780 }
01781 
01782 template <typename T> inline double
01783 McCormick<T>::_erfenv_func
01784 ( const double x, const double*rusr, const int*iusr )
01785 {
01786   // f(z) = (z-a)*exp(-z^2)-sqrt(pi)/2.*(erf(z)-erf(a)) = 0
01787   return (x-*rusr)*std::exp(-sqr(x))-std::sqrt(PI)/2.*(::erf(x)-::erf(*rusr));
01788 }
01789 
01790 template <typename T> inline double
01791 McCormick<T>::_erfenv_dfunc
01792 ( const double x, const double*rusr, const int*iusr )
01793 {
01794   // f'(z) = -2*z*(z-a)*exp(-z^2)
01795   return -2.*x*(x-*rusr)*std::exp(-2.*sqr(x));
01796 }
01797 
01798 template <typename T> inline double*
01799 McCormick<T>::_atancv
01800 ( const double x, const double xL, const double xU )
01801 {
01802   static double cv[2];
01803   if( xU <= 0. ){  // convex part
01804     cv[0] = std::atan(x), cv[1] = 1./(1.+sqr(x));
01805     return cv;
01806   }
01807 
01808   if( xL >= 0. ){  // concave part
01809     double r = ( isequal( xL, xU )? 0.:(std::atan(xU)-std::atan(xL))/(xU-xL) );
01810     cv[0] = std::atan(xL)+r*(x-xL), cv[1] = r;
01811     return cv;
01812   }
01813     
01814   double xj;
01815   try{
01816     xj = _newton( xL, xL, 0., _atanenv_func, _atanenv_dfunc, &xU, 0 );
01817   }
01818   catch( McCormick<T>::Exceptions ){
01819     xj = _goldsect( xL, 0., _atanenv_func, &xU, 0 );
01820   }
01821   if( x <= xj ){   // convex part
01822     cv[0] = std::atan(x), cv[1] = 1./(1.+sqr(x));
01823     return cv;
01824   }
01825   double r = ( isequal( xj, xU )? 0.:(std::atan(xU)-std::atan(xj))/(xU-xj) );
01826   cv[0] = std::atan(xU)+r*(x-xU), cv[1] = r;
01827   return cv;
01828 }
01829 
01830 template <typename T> inline double*
01831 McCormick<T>::_atancc
01832 ( const double x, const double xL, const double xU )
01833 {
01834   static double cc[2];
01835   if( xU <= 0. ){  // convex part
01836     double r = ( isequal( xL, xU )? 0.:(std::atan(xU)-std::atan(xL))/(xU-xL) );
01837     cc[0] = std::atan(xL)+r*(x-xL), cc[1] = r;
01838     return cc;
01839   }
01840 
01841   if( xL >= 0. ){  // concave part
01842     cc[0] = std::atan(x), cc[1] = 1./(1.+sqr(x));
01843     return cc;
01844   }
01845     
01846   double xj;
01847   try{
01848     xj = _newton( xU, 0., xU, _atanenv_func, _atanenv_dfunc, &xL, 0 );
01849   }
01850   catch( McCormick<T>::Exceptions ){
01851     xj = _goldsect( 0., xU, _atanenv_func, &xL, 0 );
01852   }
01853   if( x >= xj ){   // concave part
01854     cc[0] = std::atan(x), cc[1] = 1./(1.+sqr(x));
01855     return cc;
01856   }
01857   double r = ( isequal( xj, xL )? 0.:(std::atan(xL)-std::atan(xj))/(xL-xj) );
01858   cc[0] = std::atan(xL)+r*(x-xL), cc[1] = r;
01859   return cc;
01860 }
01861 
01862 template <typename T> inline double
01863 McCormick<T>::_atanenv_func
01864 ( const double x, const double*rusr, const int*iusr )
01865 {
01866   // f(z) = z-a-(1+z^2)*(asin(z)-asin(a)) = 0
01867   return (x-*rusr)-(1.+sqr(x))*(std::atan(x)-std::atan(*rusr));
01868 }
01869 
01870 template <typename T> inline double
01871 McCormick<T>::_atanenv_dfunc
01872 ( const double x, const double*rusr, const int*iusr )
01873 {
01874   // f'(z) = -2*z*(asin(z)-asin(a))
01875   return -2.*x*(std::atan(x)-std::atan(*rusr));
01876 }
01877 
01878 template <typename T> inline double*
01879 McCormick<T>::_oddpowcv
01880 ( const double x, const int iexp, const double xL, const double xU )
01881 {
01882   static double cv[2];
01883   if( xL >= 0. ){  // convex part
01884     double v = std::pow(x,iexp-1);
01885     cv[0] = x*v, cv[1] = iexp*v;
01886     return cv;
01887   }
01888 
01889   if( xU <= 0. ){  // concave part
01890     double r = ( isequal( xL, xU )? 0.:
01891       (std::pow(xU,iexp)-std::pow(xL,iexp))/(xU-xL) );
01892     cv[0] = std::pow(xL,iexp)+r*(x-xL), cv[1] = r;
01893     return cv;
01894   }
01895     
01896   double xj;
01897   try{
01898     xj = _newton( xU, 0., xU, _oddpowenv_func, _oddpowenv_dfunc, &xL, &iexp );
01899   }
01900   catch( McCormick<T>::Exceptions ){
01901     xj = _goldsect( 0., xU, _oddpowenv_func, &xL, &iexp );
01902   }
01903   if( x >= xj ){   // convex part
01904     double v = std::pow(x,iexp-1);
01905     cv[0] = x*v, cv[1] = iexp*v;
01906     return cv;
01907   }
01908   double r = ( isequal( xL, xj )? 0.:
01909     (std::pow(xj,iexp)-std::pow(xL,iexp))/(xj-xL) );
01910   cv[0] = std::pow(xL,iexp)+r*(x-xL), cv[1] = r;
01911   return cv;
01912 }
01913 
01914 template <typename T> inline double*
01915 McCormick<T>::_oddpowcc
01916 ( const double x, const int iexp, const double xL, const double xU )
01917 {
01918   static double cc[2];
01919   if( xL >= 0. ){  // convex part
01920     double r = ( isequal( xL, xU )? 0.:
01921       (std::pow(xU,iexp)-std::pow(xL,iexp))/(xU-xL) );
01922     cc[0] = std::pow(xL,iexp)+r*(x-xL), cc[1] = r;
01923     return cc;
01924   }
01925   if( xU <= 0. ){  // concave part
01926     double v = std::pow(x,iexp-1);
01927     cc[0] = x*v, cc[1] = iexp*v;
01928     return cc;
01929   }
01930 
01931   double xj;
01932   try{
01933     xj = _newton( xL, xL, 0., _oddpowenv_func, _oddpowenv_dfunc, &xU, &iexp );
01934   }
01935   catch( McCormick<T>::Exceptions ){
01936     xj = _goldsect( xL, 0., _oddpowenv_func, &xU, &iexp );
01937   }
01938   if( x <= xj ){   // concave part
01939     double v = std::pow(x,iexp-1);
01940     cc[0] = x*v, cc[1] = iexp*v;
01941     return cc;
01942   }
01943   double r = ( isequal( xU, xj )? 0.:
01944     (std::pow(xj,iexp)-std::pow(xU,iexp))/(xj-xU) );
01945   cc[0] = std::pow(xU,iexp)+r*(x-xU), cc[1] = r;
01946   return cc;
01947 }
01948 
01949 template <typename T> inline double
01950 McCormick<T>::_oddpowenv_func
01951 ( const double x, const double*rusr, const int*iusr )
01952 {
01953   // f(z) = (p-1)*z^p - a*p*z^{p-1} + a^p = 0
01954   return ((*iusr-1)*x-(*rusr)*(*iusr))*std::pow(x,*iusr-1)
01955     + std::pow(*rusr,*iusr);
01956 }
01957 
01958 template <typename T> inline double
01959 McCormick<T>::_oddpowenv_dfunc
01960 ( const double x, const double*rusr, const int*iusr )
01961 {
01962   // f'(z) = p*(p-1)*z^{p-1} - a*p*(p-1)*z^{p-2}
01963   return ((*iusr)*(*iusr-1)*x-(*rusr)*(*iusr)*(*iusr-1))*std::pow(x,*iusr-2);
01964 }
01965 
01966 template <typename T> inline double*
01967 McCormick<T>::_stepcv
01968 ( const double x, const double xL, const double xU )
01969 {
01970   static double cv[2];
01971 
01972   if( x < 0. ){
01973     cv[0] = cv[1] = 0.;
01974     return cv;
01975   }
01976 
01977   if( xL >= 0. ){
01978     cv[0] = 1., cv[1] = 0.;
01979     return cv;
01980   }
01981 
01982   cv[0] = x/xU, cv[1] = 1./xU;
01983   return cv;
01984 }
01985 
01986 template <typename T> inline double*
01987 McCormick<T>::_stepcc
01988 ( const double x, const double xL, const double xU )
01989 {
01990   static double cc[2];
01991 
01992   if( x >= 0. ){
01993     cc[0] = 1., cc[1] = 0.;
01994     return cc;
01995   }
01996 
01997   else if( xU < 0. ){
01998     cc[0] = 0., cc[1] = 0.;
01999     return cc;
02000   }
02001 
02002   cc[0] = 1.-x/xL, cc[1] = -1./xL;
02003   return cc;
02004 }
02005 
02006 template <typename T> inline double*
02007 McCormick<T>::_cosarg
02008 ( const double xL, const double xU )
02009 {
02010   static double arg[2];
02011   const int kL = std::ceil(-(1.+xL/PI)/2.);
02012   const double xL1 = xL+2.*PI*kL, xU1 = xU+2.*PI*kL;
02013   assert( xL1 >= -PI && xL1 <= PI );
02014   if( xL1 <= 0 ){
02015     if( xU1 <= 0 ) arg[0] = xL, arg[1] = xU;
02016     else if( xU1 >= PI ) arg[0] = PI*(1.-2.*kL), arg[1] = -PI*2.*kL;
02017     else arg[0] = std::cos(xL1)<=std::cos(xU1)?xL:xU, arg[1] = -PI*2.*kL;
02018     return arg;
02019   }
02020   if( xU1 <= PI ) arg[0] = xU, arg[1] = xL;
02021   else if( xU1 >= 2.*PI ) arg[0] = PI*(1-2.*kL), arg[1] = 2.*PI*(1.-kL);
02022   else arg[0] = PI*(1.-2.*kL), arg[1] = std::cos(xL1)>=std::cos(xU1)?xL:xU;
02023   return arg;
02024 }
02025 
02026 template <typename T> inline double*
02027 McCormick<T>::_coscv
02028 ( const double x, const double xL, const double xU )
02029 {
02030   static double cv[2];
02031   const int kL = std::ceil(-(1.+xL/PI)/2.);
02032   if( x <= PI*(1-2*kL) ){
02033     const double xL1 = xL+2.*PI*kL;
02034     if( xL1 >= 0.5*PI ){
02035       cv[0] = std::cos(x), cv[1] = -std::sin(x);
02036       return cv;
02037     }
02038     const double xU1 = std::min(xU+2.*PI*kL,PI);
02039     if( xL1 >= -0.5*PI && xU1 <= 0.5*PI ){
02040       double r = ( isequal( xL, xU )? 0.: (std::cos(xU)-std::cos(xL))/(xU-xL) );
02041       cv[0] = std::cos(xL)+r*(x-xL), cv[1] = r;
02042       return cv;
02043     }
02044     return _coscv2( x+2.*PI*kL, xL1, xU1 );
02045   }
02046 
02047   const int kU = std::floor((1.-xU/PI)/2.);
02048   if( x >= PI*(-1-2*kU) ){
02049     const double xU2 = xU+2.*PI*kU;
02050     if( xU2 <= -0.5*PI ){
02051       cv[0] = std::cos(x), cv[1] = -std::sin(x);
02052       return cv;
02053     }
02054     return _coscv2( x+2.*PI*kU, std::max(xL+2.*PI*kU,-PI), xU2 );
02055   }
02056 
02057   cv[0] = -1., cv[1] = 0.;
02058   return cv;
02059 }
02060 
02061 template <typename T> inline double*
02062 McCormick<T>::_coscv2
02063 ( const double x, const double xL, const double xU )
02064 {
02065   bool left;
02066   double x0, xm;
02067   if( std::fabs(xL)<=std::fabs(xU) )
02068     left = false, x0 = xU, xm = xL;
02069   else
02070     left = true, x0 = xL, xm = xU;
02071 
02072   double xj;
02073   try{
02074     xj = _newton( x0, xL, xU, _cosenv_func, _cosenv_dfunc, &xm, 0 );
02075   }
02076   catch( McCormick<T>::Exceptions ){
02077     xj = _goldsect( xL, xU, _cosenv_func, &xm, 0 );
02078   }
02079   static double cv[2];
02080   if(( left && x<=xj ) || ( !left && x>=xj )){
02081     cv[0] = std::cos(x), cv[1] = -std::sin(x);
02082     return cv;
02083   }
02084   double r = ( isequal( xm, xj )? 0.: (std::cos(xm)-std::cos(xj))/(xm-xj) );
02085   cv[0] = std::cos(xm)+r*(x-xm), cv[1] = r;
02086   return cv;
02087 }
02088 
02089 template <typename T> inline double*
02090 McCormick<T>::_coscc
02091 ( const double x, const double xL, const double xU )
02092 {
02093   static double cc[2];
02094   const double*cvenv = _coscv( x-PI, xL-PI, xU-PI );
02095   cc[0] = -cvenv[0], cc[1] = -cvenv[1];
02096   return cc;
02097 }
02098 
02099 template <typename T> inline double
02100 McCormick<T>::_cosenv_func
02101 ( const double x, const double*rusr, const int*iusr )
02102 
02103 {
02104   // f(z) = (z-a)*sin(z)+cos(z)-cos(a) = 0
02105   return ((x-*rusr)*std::sin(x)+std::cos(x)-std::cos(*rusr));
02106 }
02107 
02108 template <typename T> inline double
02109 McCormick<T>::_cosenv_dfunc
02110 ( const double x, const double*rusr, const int*iusr )
02111 {
02112   // f'(z) = (z-a)*cos(z)
02113   return ((x-*rusr)*std::cos(x));
02114 }
02115 
02116 template <typename T> inline double*
02117 McCormick<T>::_asincv
02118 ( const double x, const double xL, const double xU )
02119 {
02120   static double cv[2];
02121   if( xL >= 0. ){  // convex part
02122     cv[0] = std::asin(x), cv[1] = 1./std::sqrt(1-x*x);
02123     return cv;
02124   }
02125   if( xU <= 0. ){  // concave part
02126     double r = ( isequal( xL, xU )? 0.: (std::asin(xU)-std::asin(xL))/(xU-xL));
02127     cv[0] = std::asin(xL)+r*(x-xL), cv[1] = r;
02128     return cv;
02129   } 
02130 
02131   double xj;
02132   try{
02133     xj = _secant( 0., xU, 0., xU, _asinenv_func, &xL, 0 );
02134   }
02135   catch( McCormick<T>::Exceptions ){
02136     xj = _goldsect( 0., xU, _asinenv_func, &xL, 0 );
02137   }
02138   if( x >= xj ){   // convex part
02139     cv[0] = std::asin(x), cv[1] = 1./std::sqrt(1-x*x);
02140     return cv;
02141   }
02142   double r = ( isequal( xL, xj )? 0.: (std::asin(xj)-std::asin(xL))/(xj-xL));
02143   cv[0] = std::asin(xL)+r*(x-xL), cv[1] = r; // linear part
02144   return cv;
02145 }
02146 
02147 template <typename T> inline double*
02148 McCormick<T>::_asincc
02149 ( const double x, const double xL, const double xU )
02150 {
02151   static double cc[2];
02152   if( xL >= 0. ){  // convex part
02153     double r = ( isequal( xL, xU )? 0.: (std::asin(xU)-std::asin(xL))/(xU-xL));
02154     cc[0] = std::asin(xL)+r*(x-xL), cc[1] = r;
02155     return cc;
02156   }
02157   if( xU <= 0. ){  // concave part
02158     cc[0] = std::asin(x), cc[1] = 1./std::sqrt(1-x*x);
02159     return cc;
02160   }
02161 
02162   double xj;
02163   try{
02164     xj = _secant( 0., xL, xL, 0., _asinenv_func, &xU, 0 );
02165   }
02166   catch( McCormick<T>::Exceptions ){
02167     xj = _goldsect( xL, 0., _asinenv_func, &xU, 0 );
02168   }
02169   if( x <= xj ){   // concave part
02170     cc[0] = std::asin(x), cc[1] = 1./std::sqrt(1-x*x);
02171     return cc;
02172   }
02173   double r = ( isequal( xU, xj )? 0.: (std::asin(xj)-std::asin(xU))/(xj-xU));
02174   cc[0] = std::asin(xU)+r*(x-xU), cc[1] = r; // secant part
02175   return cc;
02176 }
02177 
02178 template <typename T> inline double
02179 McCormick<T>::_asinenv_func
02180 ( const double x, const double*rusr, const int*iusr )
02181 {
02182   // f(z) = z-a-sqrt(1-z^2)*(asin(z)-asin(a)) = 0
02183   return x-(*rusr)-std::sqrt(1.-x*x)*(std::asin(x)-std::asin(*rusr));
02184 }
02185 
02186 template <typename T> inline double
02187 McCormick<T>::_asinenv_dfunc
02188 ( const double x, const double*rusr, const int*iusr )
02189 {
02190   // f'(z) = z/sqrt(1-z^2)*(asin(z)-asin(a))
02191   return x/std::sqrt(1.-x*x)*(std::asin(x)-std::asin(*rusr));
02192 }
02193 
02194 template <typename T> inline double*
02195 McCormick<T>::_tancv
02196 ( const double x, const double xL, const double xU )
02197 {
02198   static double cv[2];
02199   if( xL >= 0. ){  // convex part
02200     cv[0] = std::tan(x), cv[1] = 1.+sqr(std::tan(x));
02201     return cv;
02202   }
02203   if( xU <= 0. ){  // concave part
02204     double r = ( isequal( xL, xU )? 0.: (std::tan(xU)-std::tan(xL))/(xU-xL));
02205     cv[0] = std::tan(xL)+r*(x-xL), cv[1] = r;
02206     return cv;
02207   } 
02208 
02209   double xj;
02210   try{
02211     xj = _secant( 0., xU, 0., xU, _tanenv_func, &xL, 0 );
02212   }
02213   catch( McCormick<T>::Exceptions ){
02214     xj = _goldsect( 0., xU, _tanenv_func, &xL, 0 );
02215   }
02216   if( x >= xj ){   // convex part
02217     cv[0] = std::tan(x), cv[1] = 1.+sqr(std::tan(x));
02218     return cv;
02219   }
02220   double r = ( isequal( xL, xj )? 0.: (std::tan(xj)-std::tan(xL))/(xj-xL));
02221   cv[0] = std::tan(xL)+r*(x-xL), cv[1] = r;  // secant part
02222   return cv;
02223 }
02224 
02225 template <typename T> inline double*
02226 McCormick<T>::_tancc
02227 ( const double x, const double xL, const double xU )
02228 {
02229   static double cc[2];
02230   if( xL >= 0. ){  // convex part
02231     double r = ( isequal( xL, xU )? 0.: (std::tan(xU)-std::tan(xL))/(xU-xL));
02232     cc[0] = std::tan(xL)+r*(x-xL), cc[1] = r;
02233     return cc;
02234   }
02235   if( xU <= 0. ){  // concave part
02236     cc[0] = std::tan(x), cc[1] = 1.+sqr(std::tan(x));
02237     return cc;
02238   }
02239 
02240   double xj;
02241   try{
02242     xj = _secant( 0., xL, xL, 0., _tanenv_func, &xU, 0 );
02243   }
02244   catch( McCormick<T>::Exceptions ){
02245     xj = _goldsect( xL, 0., _tanenv_func, &xU, 0 );
02246   }
02247   if( x <= xj ){   // concave part
02248     cc[0] = std::tan(x), cc[1] = 1.+sqr(std::tan(x));
02249     return cc;
02250   }
02251   double r = ( isequal( xU, xj )? 0.: (std::tan(xj)-std::tan(xU))/(xj-xU));
02252   cc[0] = std::tan(xU)+r*(x-xU), cc[1] = r;  // secant part
02253   return cc;
02254 }
02255 
02256 template <typename T> inline double
02257 McCormick<T>::_tanenv_func
02258 ( const double x, const double*rusr, const int*iusr )
02259 {
02260   // f(z) = (z-a)-(tan(z)-tan(a))/(1+tan(z)^2) = 0
02261   return (x-(*rusr))-(std::tan(x)-std::tan(*rusr))/(1.+sqr(std::tan(x)));
02262 }
02263 
02264 template <typename T> inline double
02265 McCormick<T>::_tanenv_dfunc
02266 ( const double x, const double*rusr, const int*iusr )
02267 {
02268   // f'(z) = (tan(z)-tan(a))/(1+tan(z)^2)*2*tan(z)
02269   return 2.*std::tan(x)/(1.+sqr(std::tan(x)))*(std::tan(x)-std::tan(*rusr));
02270 }
02271 
02272 template <typename T> inline double
02273 McCormick<T>::_newton
02274 ( const double x0, const double xL, const double xU, const puniv f,
02275   const puniv df, const double*rusr, const int*iusr )
02276 {
02277   double xk = std::max(xL,std::min(xU,x0));
02278   double fk = f(xk,rusr,iusr);
02279   
02280   for( unsigned int it=0; it<options.ENVEL_MAXIT; it++ ){
02281     if( std::fabs(fk) < options.ENVEL_TOL ) return xk;
02282     double dfk = df(xk,rusr,iusr);
02283     if( dfk == 0 ) throw Exceptions( Exceptions::ENVEL );
02284     if( isequal(xk,xL) && fk/dfk>0 ) return xk;
02285     if( isequal(xk,xU) && fk/dfk<0 ) return xk;
02286     xk = std::max(xL,std::min(xU,xk-fk/dfk));
02287     fk = f(xk,rusr,iusr);
02288   }
02289 
02290   throw Exceptions( Exceptions::ENVEL );
02291 }
02292 
02293 template <typename T> inline double
02294 McCormick<T>::_secant
02295 ( const double x0, const double x1, const double xL, const double xU,
02296   const puniv f, const double*rusr, const int*iusr )
02297 {
02298   double xkm = std::max(xL,std::min(xU,x0));
02299   double fkm = f(xkm,rusr,iusr);
02300   double xk = std::max(xL,std::min(xU,x1));
02301   
02302   for( unsigned int it=0; it<options.ENVEL_MAXIT; it++ ){
02303     double fk = f(xk,rusr,iusr);
02304     if( std::fabs(fk) < options.ENVEL_TOL ) return xk;
02305     double Bk = (fk-fkm)/(xk-xkm);
02306     if( Bk == 0 ) throw Exceptions( Exceptions::ENVEL );
02307     if( isequal(xk,xL) && fk/Bk>0 ) return xk;
02308     if( isequal(xk,xU) && fk/Bk<0 ) return xk;
02309     xkm = xk;
02310     fkm = fk;
02311     xk = std::max(xL,std::min(xU,xk-fk/Bk));
02312   }
02313 
02314   throw Exceptions( Exceptions::ENVEL );
02315 }
02316 
02317 template <typename T> inline double
02318 McCormick<T>::_goldsect
02319 ( const double xL, const double xU, const puniv f, const double*rusr,
02320   const int*iusr )
02321 {
02322   const double phi = 2.-(1.+std::sqrt(5.))/2.;
02323   const double fL = f(xL,rusr,iusr), fU = f(xU,rusr,iusr);
02324   if( fL*fU > 0 ) throw Exceptions( Exceptions::ENVEL );
02325   const double xm = xU-phi*(xU-xL), fm = f(xm,rusr,iusr);
02326   return _goldsect_iter( true, xL, fL, xm, fm, xU, fU, f, rusr, iusr );
02327 }
02328 
02329 template <typename T> inline double
02330 McCormick<T>::_goldsect_iter
02331 ( const bool init, const double a, const double fa, const double b,
02332   const double fb, const double c, const double fc, const puniv f,
02333   const double*rusr, const int*iusr )
02334 // a and c are the current bounds; the minimum is between them.
02335 // b is a center point
02336 {
02337   static unsigned int iter;
02338   iter = ( init? 1: iter+1 );
02339   const double phi = 2.-(1.+std::sqrt(5.))/2.;
02340   bool b_then_x = ( c-b > b-a );
02341   double x = ( b_then_x? b+phi*(c-b): b-phi*(b-a) );
02342   if( std::fabs(c-a) < options.ENVEL_TOL*(std::fabs(b)+std::fabs(x)) 
02343    || iter > options.ENVEL_MAXIT ) return (c+a)/2.;
02344   double fx = f(x,rusr,iusr);
02345   if( b_then_x )
02346     return( fa*fx<0? _goldsect_iter( false, a, fa, b, fb, x, fx, f, rusr, iusr ):
02347                       _goldsect_iter( false, b, fb, x, fx, c, fc, f, rusr, iusr ) );
02348   return( fa*fb<0? _goldsect_iter( false, a, fa, x, fx, b, fb, f, rusr, iusr ):
02349                     _goldsect_iter( false, x, fx, b, fb, c, fc, f, rusr, iusr ) );
02350 }
02351 
02353 
02354 template <typename T> inline McCormick<T>
02355 cut
02356 ( const McCormick<T>&MC )
02357 {
02358   McCormick<T> MC2( MC );
02359   return MC2.cut();
02360 }
02361 
02362 template <typename T> inline McCormick<T>
02363 operator+
02364 ( const McCormick<T>&MC )
02365 {
02366   McCormick<T> MC2( MC );
02367   return MC2;
02368 }
02369 
02370 template <typename T> inline McCormick<T>
02371 operator+
02372 ( const double a, const McCormick<T>&MC )
02373 {
02374   McCormick<T> MC2;
02375   MC2._sub( MC._nsub, MC._const );
02376   MC2._I = a + MC._I;
02377   MC2._cv = a + MC._cv;
02378   MC2._cc = a + MC._cc;
02379   for( unsigned int i=0; i<MC2._nsub; i++ ){
02380     MC2._cvsub[i] = MC._cvsub[i];
02381     MC2._ccsub[i] = MC._ccsub[i];
02382   }
02383   return MC2;
02384 }
02385 
02386 template <typename T> inline McCormick<T>
02387 operator+
02388 ( const McCormick<T>&MC, const double a )
02389 {
02390   return a + MC;
02391 }
02392 
02393 template <typename T> inline McCormick<T>
02394 operator+
02395 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
02396 {
02397   if( MC2._const ){
02398     McCormick<T> MC3;
02399     MC3._sub( MC1._nsub, MC1._const );
02400     return MC3._sum1( MC1, MC2 );
02401   }
02402   if( MC1._const ){
02403     McCormick<T> MC3;
02404     MC3._sub( MC2._nsub, MC2._const );
02405     return MC3._sum1( MC2, MC1 );
02406   } 
02407   if( MC1._nsub != MC2._nsub )
02408     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
02409   McCormick<T> MC3;
02410   MC3._sub( MC1._nsub, MC1._const||MC2._const );
02411   return MC3._sum2( MC1, MC2 );
02412 }
02413 
02414 template <typename T> inline McCormick<T>
02415 operator-
02416 ( const McCormick<T>&MC )
02417 {
02418   McCormick<T> MC2;
02419   MC2._sub( MC._nsub, MC._const );
02420   MC2._I = -MC._I;
02421   MC2._cv = -MC._cc;
02422   MC2._cc = -MC._cv;
02423   for( unsigned int i=0; i<MC2._nsub; i++ ){
02424     MC2._cvsub[i] = -MC._ccsub[i];
02425     MC2._ccsub[i] = -MC._cvsub[i];
02426   }
02427   return MC2;
02428 }
02429 
02430 template <typename T> inline McCormick<T>
02431 operator-
02432 ( const McCormick<T>&MC, const double a )
02433 {
02434   return MC + (-a);
02435 }
02436 
02437 template <typename T> inline McCormick<T>
02438 operator-
02439 ( const double a, const McCormick<T>&MC )
02440 {
02441   McCormick<T> MC2;
02442   MC2._sub( MC._nsub, MC._const );
02443   MC2._I = a - MC._I;
02444   MC2._cv = a - MC._cc;
02445   MC2._cc = a - MC._cv;
02446   for( unsigned int i=0; i<MC2._nsub; i++ ){
02447     MC2._cvsub[i] = -MC._ccsub[i];
02448     MC2._ccsub[i] = -MC._cvsub[i];
02449   }
02450   return MC2;
02451 }
02452 
02453 template <typename T> inline McCormick<T>
02454 operator-
02455 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
02456 {
02457   if( &MC1 == &MC2 ) return 0;
02458 
02459   if( MC2._const ){
02460     McCormick<T> MC3;
02461     MC3._sub( MC1._nsub, MC1._const );
02462     return MC3._sub1( MC1, MC2 );  
02463   }
02464   if( MC1._const ){
02465     McCormick<T> MC3;
02466     MC3._sub( MC2._nsub, MC2._const );
02467     return MC3._sub2( MC1, MC2 );
02468   }
02469   if( MC1._nsub != MC2._nsub )
02470     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
02471   McCormick<T> MC3;
02472   MC3._sub( MC1._nsub, MC1._const||MC2._const );
02473   return MC3._sub3( MC1, MC2 );
02474 }
02475 
02476 template <typename T> inline McCormick<T>
02477 operator*
02478 ( const double a, const McCormick<T>&MC )
02479 {
02480   McCormick<T> MC2;
02481   MC2._sub( MC._nsub, MC._const );
02482   MC2._I = a * MC._I;
02483   if ( a >= 0 ){
02484     MC2._cv = a * MC._cv;
02485     MC2._cc = a * MC._cc;
02486     for( unsigned int i=0; i<MC2._nsub; i++ ){
02487       MC2._cvsub[i] = a * MC._cvsub[i];
02488       MC2._ccsub[i] = a * MC._ccsub[i];
02489     }
02490   }
02491   else{
02492     MC2._cv = a * MC._cc;
02493     MC2._cc = a * MC._cv;
02494     for( unsigned int i=0; i<MC2._nsub; i++ ){
02495       MC2._cvsub[i] = a * MC._ccsub[i];
02496       MC2._ccsub[i] = a * MC._cvsub[i];
02497     }
02498   }
02499   return MC2;
02500 }
02501 
02502 template <typename T> inline McCormick<T>
02503 operator*
02504 ( const McCormick<T>&MC, const double a )
02505 {  
02506   return a * MC;
02507 }
02508 
02509 template <typename T> inline McCormick<T>
02510 operator*
02511 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
02512 {
02513   if( &MC1 == &MC2 ) return sqr(MC1);
02514 
02515   bool thin1 = isequal( Op<T>::diam(MC1._I), 0. );
02516   bool thin2 = isequal( Op<T>::diam(MC2._I), 0. );
02517 
02518   if ( McCormick<T>::options.MVCOMP_USE && !(thin1||thin2) ){
02519     McCormick<T> MC3;
02520     if( MC2._const )
02521       MC3._sub( MC1._nsub, MC1._const );
02522     else if( MC1._const )
02523       MC3._sub( MC2._nsub, MC2._const );
02524     else if( MC1._nsub != MC2._nsub )
02525       throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
02526     else
02527       MC3._sub( MC1._nsub, MC1._const||MC2._const );
02528 
02529     MC3._I = MC1._I * MC2._I;
02530     return MC3._mulMV( MC1, MC2 ).cut();
02531   }
02532 
02533   if ( Op<T>::l(MC1._I) >= 0. ){
02534     if ( Op<T>::l(MC2._I) >= 0. ){
02535       if( MC2._const ){
02536         McCormick<T> MC3;
02537         MC3._sub( MC1._nsub, MC1._const );
02538         return MC3._mul1_u1pos_u2pos( MC1, MC2 ).cut();
02539       }
02540       if( MC1._const ){
02541         McCormick<T> MC3;
02542         MC3._sub( MC2._nsub, MC2._const );
02543         return MC3._mul1_u1pos_u2pos( MC2, MC1 ).cut();
02544       }
02545       if( MC1._nsub != MC2._nsub )
02546         throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
02547       McCormick<T> MC3;
02548       MC3._sub( MC1._nsub, MC1._const||MC2._const );
02549       return MC3._mul2_u1pos_u2pos( MC1, MC2 ).cut();
02550     }
02551     if ( Op<T>::u(MC2._I) <= 0. ){
02552       return -( MC1 * (-MC2) );
02553     }
02554     if( MC2._const ){
02555       McCormick<T> MC3;
02556       MC3._sub( MC1._nsub, MC1._const );
02557       return MC3._mul1_u1pos_u2mix( MC1, MC2 ).cut();
02558     }
02559     if( MC1._const ){
02560       McCormick<T> MC3;
02561       MC3._sub( MC2._nsub, MC2._const );
02562       return MC3._mul2_u1pos_u2mix( MC1, MC2 ).cut();
02563     }
02564     if( MC1._nsub != MC2._nsub )
02565       throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
02566     McCormick<T> MC3;
02567     MC3._sub( MC1._nsub, MC1._const||MC2._const );
02568     return MC3._mul3_u1pos_u2mix( MC1, MC2 ).cut();
02569   }
02570 
02571   if ( Op<T>::u(MC1._I) <= 0. ){
02572     if ( Op<T>::l(MC2._I) >= 0. ){
02573       return -( (-MC1) * MC2);
02574     }
02575     if ( Op<T>::u(MC2._I) <= 0. ){
02576       return (-MC1) * (-MC2);
02577     }
02578     return -( MC2 * (-MC1) );
02579   }
02580 
02581   if ( Op<T>::l(MC2._I) >= 0. ){
02582     return MC2 * MC1;
02583   }
02584   if ( Op<T>::u(MC2._I) <= 0. ){
02585     return -( (-MC2) * MC1 );
02586   }
02587   if( MC2._const ){
02588     McCormick<T> MC3;
02589     MC3._sub( MC1._nsub, MC1._const );
02590     return MC3._mul1_u1mix_u2mix( MC1, MC2 ).cut();
02591   }
02592   if( MC1._const ){
02593     McCormick<T> MC3;
02594     MC3._sub( MC2._nsub, MC2._const );
02595     return MC3._mul1_u1mix_u2mix( MC2, MC1 ).cut();
02596   }
02597   if( MC1._nsub != MC2._nsub )
02598     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
02599   McCormick<T> MC3;
02600   MC3._sub( MC1._nsub, MC1._const||MC2._const );
02601   return MC3._mul2_u1mix_u2mix( MC1, MC2 ).cut();
02602 }
02603 
02604 template <typename T> inline McCormick<T>
02605 operator/
02606 ( const McCormick<T>&MC, const double a )
02607 {
02608   if ( isequal( a, 0. ))
02609     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::DIV );
02610   return (1./a) * MC;
02611 }
02612 
02613 template <typename T> inline McCormick<T>
02614 operator/
02615 ( const double a, const McCormick<T>&MC )
02616 {
02617   return a * inv( MC );
02618 }
02619 
02620 template <typename T> inline McCormick<T>
02621 operator/
02622 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
02623 {
02624   if( &MC1 == &MC2 ) return 1.;
02625 
02626   bool posorthant = ( Op<T>::l(MC1._I) >= 0. && Op<T>::l(MC2._I) > 0. );
02627 
02628   if ( McCormick<T>::options.MVCOMP_USE && posorthant){
02629     McCormick<T> MC3;
02630     if( MC2._const )
02631       MC3._sub( MC1._nsub, MC1._const );
02632     else if( MC1._const )
02633       MC3._sub( MC2._nsub, MC2._const );
02634     else if( MC1._nsub != MC2._nsub )
02635       throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
02636     else
02637       MC3._sub( MC1._nsub, MC1._const||MC2._const );
02638 
02639     MC3._I = MC1._I / MC2._I;
02640 
02641     int imidcv1 = -1, imidcv2 = -1;
02642     double fmidcv1 = ( mid(MC1._cv, MC1._cc, Op<T>::l(MC1._I), imidcv1)
02643       + std::sqrt(Op<T>::l(MC1._I) * Op<T>::u(MC1._I)) )
02644       / ( std::sqrt(Op<T>::l(MC1._I)) + std::sqrt(Op<T>::u(MC1._I)) );
02645     double fmidcv2 = mid(MC2._cv, MC2._cc, Op<T>::u(MC2._I), imidcv2);
02646     MC3._cv = sqr(fmidcv1) / fmidcv2;
02647     for( unsigned int i=0; i<MC3._nsub; i++ )
02648       MC3._cvsub[i] = 2. * fmidcv1 / fmidcv2
02649         / ( std::sqrt(Op<T>::l(MC1._I)) + std::sqrt(Op<T>::u(MC1._I)) )
02650         * (MC1._const? 0.: mid( MC1._cvsub, MC1._ccsub, i, imidcv1 ))
02651         - sqr( fmidcv1 / fmidcv2 )
02652         * (MC2._const? 0.: mid( MC2._cvsub, MC2._ccsub, i, imidcv2 ));
02653 
02654     int imidcc1 = -1, imidcc2 = -1;
02655     double fmidcc1 = mid(MC1._cv, MC1._cc, Op<T>::l(MC1._I), imidcc1);
02656     double fmidcc2 = mid(MC2._cv, MC2._cc, Op<T>::u(MC2._I), imidcc2);
02657     double gcc1 = Op<T>::u(MC2._I) * fmidcc1 - Op<T>::l(MC1._I) * fmidcc2
02658                  + Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
02659     double gcc2 = Op<T>::l(MC2._I) * fmidcc1 - Op<T>::u(MC1._I) * fmidcc2
02660                  + Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
02661     if( gcc1 <= gcc2 ){
02662       MC3._cc = gcc1 / ( Op<T>::l(MC2._I) * Op<T>::u(MC2._I) );
02663       for( unsigned int i=0; i<MC3._nsub; i++ )
02664         MC3._ccsub[i] = 1. / Op<T>::l(MC2._I)
02665           * (MC1._const? 0.: mid( MC1._cvsub, MC1._ccsub, i, imidcc1 ))
02666           - Op<T>::l(MC1._I) / ( Op<T>::l(MC2._I) * Op<T>::u(MC2._I) )
02667           * (MC2._const? 0.: mid( MC2._cvsub, MC2._ccsub, i, imidcc2 ));
02668     }
02669     else{
02670       MC3._cc = gcc2 / ( Op<T>::l(MC2._I) * Op<T>::u(MC2._I) );
02671       for( unsigned int i=0; i<MC3._nsub; i++ )
02672         MC3._ccsub[i] = 1. / Op<T>::u(MC2._I)
02673           * (MC1._const? 0.: mid( MC1._cvsub, MC1._ccsub, i, imidcc1 ))
02674           - Op<T>::u(MC1._I) / ( Op<T>::l(MC2._I) * Op<T>::u(MC2._I) )
02675           * (MC2._const? 0.: mid( MC2._cvsub, MC2._ccsub, i, imidcc2 ));
02676     }
02677     return MC3.cut();
02678   }
02679 
02680   return MC1 * inv( MC2 );
02681 }
02682 
02683 template <typename T> inline McCormick<T>
02684 inv
02685 ( const McCormick<T>&MC )
02686 {
02687   if ( Op<T>::l(MC._I) <= 0. && Op<T>::u(MC._I) >= 0. )
02688     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::INV );
02689   McCormick<T> MC2;
02690   MC2._sub( MC._nsub, MC._const );
02691   MC2._I = Op<T>::inv( MC._I );
02692 
02693   if ( Op<T>::l(MC._I) > 0. ){
02694     { int imid = -1;
02695       double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
02696       MC2._cv = 1./vmid;
02697       for( unsigned int i=0; i<MC2._nsub; i++ )
02698         MC2._cvsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid )
02699           / ( vmid * vmid );
02700     }
02701     { int imid = -1;
02702       MC2._cc = 1. / Op<T>::l(MC._I) + 1. / Op<T>::u(MC._I) - mid( MC._cv, MC._cc,
02703         Op<T>::l(MC._I), imid ) / ( Op<T>::l(MC._I) * Op<T>::u(MC._I) );
02704       for( unsigned int i=0; i<MC2._nsub; i++ )
02705         MC2._ccsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid )
02706           / ( Op<T>::l(MC._I) * Op<T>::u(MC._I) );
02707     }
02708   }
02709 
02710   else{
02711     { int imid = -1;
02712       MC2._cv = 1. / Op<T>::l(MC._I) + 1. / Op<T>::u(MC._I) - mid( MC._cv, MC._cc,
02713         Op<T>::u(MC._I), imid ) / ( Op<T>::l(MC._I) * Op<T>::u(MC._I) );
02714       for( unsigned int i=0; i<MC2._nsub; i++ )
02715         MC2._cvsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid )
02716           / ( Op<T>::l(MC._I) * Op<T>::u(MC._I) );
02717     }
02718     { int imid = -1;
02719       double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid);
02720       MC2._cc = 1. / vmid;
02721       for( unsigned int i=0; i<MC2._nsub; i++ )
02722         MC2._ccsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid )
02723           / ( vmid * vmid );
02724     }
02725   }
02726   
02727   return MC2.cut();
02728 }
02729 
02730 template <typename T> inline McCormick<T>
02731 sqr
02732 ( const McCormick<T>&MC )
02733 {
02734   McCormick<T> MC2;
02735   MC2._sub( MC._nsub, MC._const );
02736   MC2._I = Op<T>::sqr( MC._I );
02737   { int imid = -1;
02738     double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), 0., imid );
02739     imid = -1;
02740     MC2._cv = mc::sqr( mid( MC._cv, MC._cc, zmin, imid ) );
02741     for( unsigned int i=0; i<MC2._nsub; i++ )
02742       MC2._cvsub[i] = 2 * mid( MC._cvsub, MC._ccsub, i, imid )
02743         * mid( MC._cv, MC._cc, zmin, imid );
02744   }
02745 
02746   { int imid = -1;
02747     double zmax = (mc::sqr( Op<T>::l(MC._I) )>mc::sqr( Op<T>::u(MC._I) )?
02748       Op<T>::l(MC._I): Op<T>::u(MC._I));
02749     double r = ( isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )? 0.:
02750       ( mc::sqr( Op<T>::u(MC._I) ) - mc::sqr( Op<T>::l(MC._I) ) )
02751       / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ) );
02752     MC2._cc = mc::sqr( Op<T>::l(MC._I) ) + r * ( mid( MC._cv, MC._cc, zmax,
02753       imid ) - Op<T>::l(MC._I) );
02754     for( unsigned int i=0; i<MC2._nsub; i++ )
02755       MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
02756   }
02757 
02758   return MC2.cut();
02759 }
02760 
02761 template <typename T> inline McCormick<T>
02762 exp
02763 ( const McCormick<T>&MC )
02764 {
02765   McCormick<T> MC2;
02766   MC2._sub( MC._nsub, MC._const );
02767   MC2._I = Op<T>::exp( MC._I );
02768 
02769   { int imid = -1;
02770     MC2._cv = std::exp( mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid ));
02771     for( unsigned int i=0; i<MC2._nsub; i++ )
02772       MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * MC2._cv;
02773   }
02774 
02775   { int imid = -1;
02776     double r = 0.;
02777     if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) ))
02778       r = ( std::exp( Op<T>::u(MC._I) ) - std::exp( Op<T>::l(MC._I) ) )
02779         / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) );
02780     MC2._cc = std::exp( Op<T>::u(MC._I) ) + r * ( mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid )
02781       - Op<T>::u(MC._I) );
02782     for( unsigned int i=0; i<MC2._nsub; i++ )
02783       MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
02784   }
02785 
02786   return MC2.cut();
02787 }
02788 
02789 template <typename T> inline McCormick<T>
02790 arh
02791 ( const McCormick<T>&MC, const double k )
02792 {
02793   if( Op<T>::l(MC._I) <= 0. || k < 0. || ( Op<T>::u(MC._I) > 0.5*k && Op<T>::l(MC._I) >= 0.5*k ) ){
02794     return exp( - k * inv( MC ) );
02795   }
02796 
02797   McCormick<T> MC2;
02798   MC2._sub( MC._nsub, MC._const );
02799   MC2._I = Op<T>::arh( MC._I, k );
02800 
02801   if ( Op<T>::u(MC._I) <= 0.5*k ){
02802     { int imid = -1;
02803       double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid );
02804       MC2._cv = std::exp( - k / vmid );
02805       for( unsigned int i=0; i<MC2._nsub; i++ )
02806         MC2._cvsub[i] = k / ( vmid * vmid ) * MC2._cv
02807           * mid( MC._cvsub, MC._ccsub, i, imid );
02808     }
02809     { int imid = -1;
02810       double r = 0.;
02811       if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) ))
02812         r = ( mc::arh( Op<T>::u(MC._I) ) - mc::arh( Op<T>::l(MC._I) ) )
02813           / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) );
02814       MC2._cc = mc::arh( Op<T>::l(MC._I) ) + r * ( mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid )
02815         - Op<T>::l(MC._I) );
02816       for( unsigned int i=0; i<MC2._nsub; i++ )
02817         MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
02818     }
02819     return MC2.cut();
02820   }
02821 
02822   else if ( Op<T>::l(MC._I) >= 0.5*k ){
02823     { int imid = -1;
02824       double r = 0.;
02825       if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) ))
02826         r = ( mc::arh( Op<T>::u(MC._I) ) - mc::arh( Op<T>::l(MC._I) ) )
02827           / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) );
02828       MC2._cv = mc::arh( Op<T>::l(MC._I) ) + r * ( mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid )
02829         - Op<T>::l(MC._I) );
02830       for( unsigned int i=0; i<MC2._nsub; i++ )
02831         MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
02832     }
02833     { int imid = -1;
02834       double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
02835       MC2._cc = std::exp( - k / vmid );
02836       for( unsigned int i=0; i<MC2._nsub; i++ )
02837         MC2._ccsub[i] = k / ( vmid * vmid ) * MC2._cc
02838           * mid( MC._cvsub, MC._ccsub, i, imid );
02839     }
02840     return MC2.cut();
02841   }
02842 }
02843 
02844 template <typename T> inline McCormick<T>
02845 log
02846 ( const McCormick<T>&MC )
02847 {
02848   if ( Op<T>::l(MC._I) <= 0. )
02849     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::LOG );
02850   McCormick<T> MC2;
02851   MC2._sub( MC._nsub, MC._const );
02852   MC2._I = Op<T>::log( MC._I );
02853 
02854   { int imid = -1;
02855     double scal = 0.;
02856     if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) ))
02857       scal = ( std::log( Op<T>::u(MC._I) ) - std::log( Op<T>::l(MC._I) ) )
02858         / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) );
02859     MC2._cv = std::log( Op<T>::l(MC._I) ) + scal * ( mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid )
02860       - Op<T>::l(MC._I) );
02861     for( unsigned int i=0; i<MC2._nsub; i++ )
02862       MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * scal;
02863   }
02864 
02865   { int imid = -1;
02866     double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
02867     MC2._cc = std::log( vmid );
02868     for( unsigned int i=0; i<MC2._nsub; i++ )
02869       MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) / vmid;
02870   }
02871 
02872   return MC2.cut();
02873 }
02874 
02875 template <typename T> inline McCormick<T>
02876 xlog
02877 ( const McCormick<T>&MC )
02878 {
02879   if ( Op<T>::l(MC._I) <= 0. )
02880     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::LOG );
02881   McCormick<T> MC2;
02882   MC2._sub( MC._nsub, MC._const );
02883   MC2._I = Op<T>::xlog( MC._I );
02884 
02885   { int imid = -1;
02886     double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), std::exp(-1.), imid );
02887     imid = -1;
02888     double vmid = mid( MC._cv, MC._cc, zmin, imid );
02889     MC2._cv = xlog( vmid );
02890     for( unsigned int i=0; i<MC2._nsub; i++ )
02891       MC2._cvsub[i] = (std::log( vmid ) + 1.) * mid( MC._cvsub, MC._ccsub,
02892         i, imid );
02893   }
02894 
02895   { int imid = -1;
02896     double zmax = ( xlog(Op<T>::u(MC._I))>=xlog(Op<T>::l(MC._I))? Op<T>::u(MC._I): Op<T>::l(MC._I) );
02897     double r = 0.;
02898     if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) ))
02899       r = ( xlog(Op<T>::u(MC._I)) - xlog(Op<T>::l(MC._I)) )
02900         / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) );
02901     imid = -1;
02902     MC2._cc = xlog(Op<T>::l(MC._I)) + r * ( mid( MC._cv, MC._cc, zmax, imid ) - Op<T>::l(MC._I) );
02903     for( unsigned int i=0; i<MC2._nsub; i++ )
02904       MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
02905   }
02906 
02907   return MC2.cut();
02908 }
02909 
02910 template <typename T> inline McCormick<T>
02911 sqrt
02912 ( const McCormick<T>&MC )
02913 {
02914   if ( Op<T>::l(MC._I) < 0. )
02915     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SQRT );
02916   McCormick<T> MC2;
02917   MC2._sub( MC._nsub, MC._const );
02918   MC2._I = Op<T>::sqrt( MC._I );
02919 
02920   { double r = 0.;
02921     if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) ))
02922       r = ( std::sqrt( Op<T>::u(MC._I) ) - std::sqrt( Op<T>::l(MC._I) ) )
02923         / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) );
02924     int imid = -1;
02925     double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid );
02926     MC2._cv = std::sqrt( Op<T>::l(MC._I) ) + r * ( vmid - Op<T>::l(MC._I) );
02927     for( unsigned int i=0; i<MC2._nsub; i++ )
02928       MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
02929   }
02930 
02931   { int imid = -1;
02932     double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
02933     MC2._cc = std::sqrt( vmid );
02934     for( unsigned int i=0; i<MC2._nsub; i++ )
02935       MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) / (2.*MC2._cc);
02936   }
02937 
02938   return MC2.cut();
02939 }
02940 
02941 template <typename T> inline McCormick<T>
02942 erfc
02943 ( const McCormick<T> &MC )
02944 {
02945   return ( 1. - erf( MC ) );
02946 }
02947 
02948 template <typename T> inline McCormick<T>
02949 erf
02950 ( const McCormick<T>&MC )
02951 {
02952   McCormick<T> MC2;
02953   MC2._sub( MC._nsub, MC._const );
02954   MC2._I = Op<T>::erf( MC._I );
02955 
02956   if( !McCormick<T>::options.ENVEL_USE ){
02957      MC2._cv = Op<T>::l(MC2._I);
02958      MC2._cc = Op<T>::u(MC2._I);
02959     for( unsigned int i=0; i<MC2._nsub; i++ ){
02960       MC2._cvsub[i] = MC2._ccsub[i] = 0.;
02961     }
02962     return MC2;
02963   }
02964 
02965   { int imid = -1;
02966     const double* cvenv = McCormick<T>::_erfcv( mid( MC._cv,
02967       MC._cc, Op<T>::l(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
02968     MC2._cv = cvenv[0];
02969     for( unsigned int i=0; i<MC2._nsub; i++ ){
02970       MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1];
02971     }
02972   }
02973   { int imid = -1;
02974     const double* ccenv = McCormick<T>::_erfcc( mid( MC._cv,
02975       MC._cc, Op<T>::u(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
02976     MC2._cc = ccenv[0];
02977     for( unsigned int i=0; i<MC2._nsub; i++ ){
02978       MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
02979     }
02980   }
02981   return MC2.cut();
02982 }
02983 
02984 template <typename T> inline McCormick<T>
02985 pow
02986 ( const McCormick<T>&MC, const int n )
02987 {
02988   if( n == 0 ){
02989     return 1.;
02990   }
02991 
02992   if( n == 1 ){
02993     return MC;
02994   }
02995 
02996   if( n >= 2 && !(n%2) ){ 
02997     McCormick<T> MC2;
02998     MC2._sub( MC._nsub, MC._const );
02999     MC2._I = Op<T>::pow( MC._I, n );
03000     { int imid = -1;
03001       double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), 0., imid );
03002       imid = -1;
03003       MC2._cv = std::pow( mid( MC._cv, MC._cc, zmin, imid ), n );
03004       for( unsigned int i=0; i<MC2._nsub; i++ )
03005         MC2._cvsub[i] = n * mid( MC._cvsub, MC._ccsub, i, imid )
03006           * std::pow( mid( MC._cv, MC._cc, zmin, imid ), n-1 );
03007     }
03008     { int imid = -1;
03009       double zmax = (std::pow( Op<T>::l(MC._I), n )>std::pow( Op<T>::u(MC._I), n )?
03010         Op<T>::l(MC._I): Op<T>::u(MC._I));
03011       double r = ( isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )? 0.: ( std::pow( Op<T>::u(MC._I),
03012         n ) - std::pow( Op<T>::l(MC._I), n ) ) / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ) );
03013       MC2._cc = std::pow( Op<T>::l(MC._I), n ) + r * ( mid( MC._cv, MC._cc, zmax,
03014         imid ) - Op<T>::l(MC._I) );
03015       for( unsigned int i=0; i<MC2._nsub; i++ )
03016         MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
03017     }
03018     return MC2.cut();
03019   }
03020 
03021   if( n >= 3 && McCormick<T>::options.ENVEL_USE ){
03022     McCormick<T> MC2;
03023     MC2._sub( MC._nsub, MC._const );
03024     MC2._I = Op<T>::pow( MC._I, n );
03025     { int imid = -1;
03026       const double* cvenv = McCormick<T>::_oddpowcv( mid( MC._cv,
03027         MC._cc, Op<T>::l(MC._I), imid ), n, Op<T>::l(MC._I), Op<T>::u(MC._I) );
03028       MC2._cv = cvenv[0];
03029       for( unsigned int i=0; i<MC2._nsub; i++ ){
03030         MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1];
03031       }
03032     }
03033     { int imid = -1;
03034       const double* ccenv = McCormick<T>::_oddpowcc( mid( MC._cv,
03035         MC._cc, Op<T>::u(MC._I), imid ), n, Op<T>::l(MC._I), Op<T>::u(MC._I) );
03036       MC2._cc = ccenv[0];
03037       for( unsigned int i=0; i<MC2._nsub; i++ ){
03038         MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
03039       }
03040     }
03041     return MC2.cut();
03042   }
03043 
03044   if( n >= 3 ){
03045     return pow( MC, n-1 ) * MC;
03046   }
03047 
03048   if( n == -1 ){
03049     return inv( MC );
03050   }
03051 
03052   if ( Op<T>::l(MC._I) <= 0. && Op<T>::u(MC._I) >= 0. )
03053     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::INV );
03054   McCormick<T> MC2;
03055   MC2._sub( MC._nsub, MC._const );
03056   MC2._I = Op<T>::pow( MC._I, n );
03057 
03058   if ( Op<T>::l(MC._I) > 0. ){
03059     { int imid = -1;
03060       double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
03061       MC2._cv = std::pow( vmid, n );
03062       for( unsigned int i=0; i<MC2._nsub; i++ )
03063         MC2._cvsub[i] = n* mid( MC._cvsub, MC._ccsub, i, imid ) * std::pow( vmid, n-1 );
03064     }
03065     { double r = std::pow( Op<T>::l(MC._I), -n-1 ) + std::pow( Op<T>::u(MC._I), -n-1 );
03066       for( int i=1; i<=-n-2; i++ )
03067          r += std::pow( Op<T>::l(MC._I), i ) * std::pow( Op<T>::u(MC._I), -n-1-i );
03068       r /= - std::pow( Op<T>::l(MC._I), -n ) * std::pow( Op<T>::u(MC._I), -n );
03069       int imid = -1;
03070       double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid );
03071       MC2._cc = std::pow( Op<T>::l(MC._I), n ) + r * ( vmid - Op<T>::l(MC._I) );
03072       for( unsigned int i=0; i<MC2._nsub; i++ )
03073         MC2._ccsub[i] = r * mid( MC._cvsub, MC._ccsub, i, imid );
03074     }
03075     return MC2.cut();
03076   }
03077 
03078   if( (-n)%2 ){
03079     { double r = std::pow( Op<T>::l(MC._I), -n-1 ) + std::pow( Op<T>::u(MC._I), -n-1 );
03080       for( int i=1; i<=-n-2; i++ )
03081          r += std::pow( Op<T>::l(MC._I), i ) * std::pow( Op<T>::u(MC._I), -n-1-i );
03082       r /= - std::pow( Op<T>::l(MC._I), -n ) * std::pow( Op<T>::u(MC._I), -n );
03083       int imid = -1;
03084       double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
03085       MC2._cv = std::pow( Op<T>::l(MC._I), n ) + r * ( vmid - Op<T>::l(MC._I) );
03086       for( unsigned int i=0; i<MC2._nsub; i++ )
03087         MC2._cvsub[i] = r * mid( MC._cvsub, MC._ccsub, i, imid );
03088     }
03089     { int imid = -1;
03090       double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid );
03091       MC2._cc = std::pow( vmid, n );
03092       for( unsigned int i=0; i<MC2._nsub; i++ )
03093         MC2._ccsub[i] = n* mid( MC._cvsub, MC._ccsub, i, imid ) * std::pow( vmid, n-1 );
03094     }
03095     return MC2.cut();
03096   }
03097 
03098   { int imid = -1;
03099     double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid );
03100     MC2._cv = std::pow( vmid, n );
03101     for( unsigned int i=0; i<MC2._nsub; i++ )
03102       MC2._cvsub[i] = n* mid( MC._cvsub, MC._ccsub, i, imid ) * std::pow( vmid, n-1 );
03103   }
03104     { double r = std::pow( Op<T>::l(MC._I), -n-1 ) + std::pow( Op<T>::u(MC._I), -n-1 );
03105       for( int i=1; i<=-n-2; i++ )
03106          r += std::pow( Op<T>::l(MC._I), i ) * std::pow( Op<T>::u(MC._I), -n-1-i );
03107       r /= - std::pow( Op<T>::l(MC._I), -n ) * std::pow( Op<T>::u(MC._I), -n );
03108     int imid = -1;
03109     double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
03110     MC2._cc = std::pow( Op<T>::l(MC._I), n ) + r * ( vmid - Op<T>::l(MC._I) );
03111     for( unsigned int i=0; i<MC2._nsub; i++ )
03112       MC2._ccsub[i] = r * mid( MC._cvsub, MC._ccsub, i, imid );
03113   }
03114   return MC2.cut();
03115 }
03116 
03117 template <typename T> inline McCormick<T>
03118 pow
03119 ( const McCormick<T> &MC, const double a )
03120 {
03121   return exp( a * log( MC ) );
03122 }
03123 
03124 template <typename T> inline McCormick<T>
03125 pow
03126 ( const McCormick<T> &MC1, const McCormick<T> &MC2 )
03127 {
03128   return exp( MC2 * log( MC1 ) );
03129 }
03130 
03131 template <typename T> inline McCormick<T>
03132 pow
03133 ( const double a, const McCormick<T> &MC )
03134 {
03135   return exp( MC * std::log( a ) );
03136 }
03137 
03138 template <typename T> inline McCormick<T>
03139 monomial
03140 (const unsigned int n, const McCormick<T>*MC, const int*k)
03141 {
03142   if( n == 0 ){
03143     return 1.;
03144   }
03145   if( n == 1 ){
03146     return pow( MC[0], k[0] );
03147   }
03148   return pow( MC[0], k[0] ) * monomial( n-1, MC+1, k+1 );
03149 }
03150 
03151 template <typename T> inline McCormick<T>
03152 fabs
03153 ( const McCormick<T> &MC )
03154 {
03155   McCormick<T> MC2;
03156   MC2._sub( MC._nsub, MC._const );
03157   MC2._I = Op<T>::fabs( MC._I );
03158 
03159   { int imid = -1;
03160     double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), 0., imid );
03161     imid = -1;
03162     double vmid = mid( MC._cv, MC._cc, zmin, imid );
03163     MC2._cv = std::fabs( vmid );
03164     if( vmid >= 0. )
03165       for( unsigned int i=0; i<MC2._nsub; i++ )
03166         MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid );
03167     else
03168       for( unsigned int i=0; i<MC2._nsub; i++ )
03169         MC2._cvsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid );
03170   }
03171 
03172   { int imid = -1;
03173     double zmax = (std::fabs( Op<T>::l(MC._I) )>std::fabs( Op<T>::u(MC._I) )? Op<T>::l(MC._I):
03174       Op<T>::u(MC._I));
03175     double r = ( isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )? 0.: ( std::fabs( Op<T>::u(MC._I) )
03176       - std::fabs( Op<T>::l(MC._I) ) ) / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ) );
03177     MC2._cc = std::fabs( Op<T>::l(MC._I) ) + r * ( mid( MC._cv, MC._cc, zmax, imid )
03178       - Op<T>::l(MC._I) );
03179     for( unsigned int i=0; i<MC2._nsub; i++ )
03180       MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
03181   }
03182 
03183   return MC2.cut();
03184 }
03185 
03186 template <typename T> inline McCormick<T>
03187 min
03188 ( const McCormick<T> &MC1, const McCormick<T> &MC2 )
03189 {
03190   McCormick<T> MC3;
03191   if( MC2._const )
03192     MC3._sub( MC1._nsub, MC1._const );
03193   else if( MC1._const )
03194     MC3._sub( MC2._nsub, MC2._const );
03195   else if( MC1._nsub != MC2._nsub )
03196     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
03197   else
03198     MC3._sub( MC1._nsub, MC1._const||MC2._const );
03199   MC3._I = Op<T>::min( MC1._I, MC2._I );
03200 
03201   if( Op<T>::u(MC1._I) <= Op<T>::l(MC2._I) ){
03202     MC3._cv = MC1._cv;
03203     for( unsigned int i=0; i< MC3._nsub; i++ )
03204       MC3._cvsub[i] = (MC1._const? 0.: MC1._cvsub[i]);
03205   }
03206   else if( Op<T>::u(MC2._I) <= Op<T>::l(MC1._I) ){
03207     MC3._cv = MC2._cv;
03208     for( unsigned int i=0; i< MC3._nsub; i++ )
03209       MC3._cvsub[i] = (MC2._const? 0.: MC2._cvsub[i]);
03210   }
03211   else if( McCormick<T>::options.MVCOMP_USE ){
03212      double minL1L2 = std::min( Op<T>::l(MC1._I), Op<T>::l(MC2._I) );
03213      double minL1U2 = std::min( Op<T>::l(MC1._I), Op<T>::u(MC2._I) );
03214      double minU1L2 = std::min( Op<T>::u(MC1._I), Op<T>::l(MC2._I) );
03215      double minU1U2 = std::min( Op<T>::u(MC1._I), Op<T>::u(MC2._I) );
03216 
03217      bool thin1 = isequal( Op<T>::diam(MC1._I), 0. );
03218      double r11 = ( thin1?  0.: ( minU1L2 - minL1L2 ) / Op<T>::diam(MC1._I) );
03219      double r21 = ( thin1?  0.: ( minL1U2 - minU1U2 ) / Op<T>::diam(MC1._I) );
03220 
03221      bool thin2 = isequal( Op<T>::diam(MC2._I), 0. );
03222      double r12 = ( thin2?  0.: ( minL1U2 - minL1L2 ) / Op<T>::diam(MC2._I) );
03223      double r22 = ( thin2?  0.: ( minU1L2 - minU1U2 ) / Op<T>::diam(MC2._I) );
03224 
03225      double g1cv = minL1L2 + r11 * ( MC1._cv - Op<T>::l(MC1._I) )
03226                            + r12 * ( MC2._cv - Op<T>::l(MC2._I) );
03227      double g2cv = minU1U2 - r21 * ( MC1._cv - Op<T>::u(MC1._I) )
03228                            - r22 * ( MC2._cv - Op<T>::u(MC2._I) );
03229      if( g1cv >= g2cv ){
03230        MC3._cv = g1cv;
03231       for( unsigned int i=0; i< MC3._nsub; i++ )
03232         MC3._cvsub[i] = (MC1._const? 0.: r11*MC1._cvsub[i])
03233                       + (MC2._const? 0.: r12*MC2._cvsub[i]);
03234      }
03235      else{
03236        MC3._cv = g2cv;
03237       for( unsigned int i=0; i< MC3._nsub; i++ )
03238         MC3._cvsub[i] = - (MC1._const? 0.: r21*MC1._cvsub[i])
03239                         - (MC2._const? 0.: r22*MC2._cvsub[i]);
03240      }
03241   }
03242   else{
03243     McCormick<T> MCMin = 0.5*( MC1 + MC2 - fabs( MC2 - MC1 ) );
03244     MC3._cv = MCMin._cv;
03245     for( unsigned int i=0; i< MC3._nsub; i++ )
03246       MC3._cvsub[i] = MCMin._cvsub[i];
03247   }
03248 
03249   MC3._cc = std::min( MC1._cc, MC2._cc );
03250   for( unsigned int i=0; i< MC3._nsub; i++ )
03251     MC3._ccsub[i] = ( MC1._cc<=MC2._cc? (MC1._const? 0.: MC1._ccsub[i])
03252                                       : (MC2._const? 0.: MC2._ccsub[i]) );
03253 
03254   return  MC3.cut();
03255 }
03256 
03257 template <typename T> inline McCormick<T>
03258 max
03259 ( const McCormick<T> &MC1, const McCormick<T> &MC2 )
03260 {
03261   McCormick<T> MC3;
03262   if( MC2._const )
03263     MC3._sub( MC1._nsub, MC1._const );
03264   else if( MC1._const )
03265     MC3._sub( MC2._nsub, MC2._const );
03266   else if( MC1._nsub != MC2._nsub )
03267     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
03268   else
03269     MC3._sub( MC1._nsub, MC1._const||MC2._const );
03270   MC3._I = Op<T>::max( MC1._I, MC2._I );
03271 
03272   if( Op<T>::u(MC1._I) <= Op<T>::l(MC2._I) ){
03273     MC3._cc = MC1._cc;
03274     for( unsigned int i=0; i< MC3._nsub; i++ )
03275       MC3._ccsub[i] = (MC1._const? 0.: MC1._ccsub[i]);
03276   }
03277   else if( Op<T>::u(MC2._I) <= Op<T>::l(MC1._I) ){
03278     MC3._cc = MC2._cc;
03279     for( unsigned int i=0; i< MC3._nsub; i++ )
03280       MC3._ccsub[i] = (MC2._const? 0.: MC2._ccsub[i]);
03281   }
03282   else if ( McCormick<T>::options.MVCOMP_USE ){
03283      double maxL1L2 = std::max( Op<T>::l(MC1._I), Op<T>::l(MC2._I) );
03284      double maxL1U2 = std::max( Op<T>::l(MC1._I), Op<T>::u(MC2._I) );
03285      double maxU1L2 = std::max( Op<T>::u(MC1._I), Op<T>::l(MC2._I) );
03286      double maxU1U2 = std::max( Op<T>::u(MC1._I), Op<T>::u(MC2._I) );
03287 
03288      bool thin1 = isequal( Op<T>::diam(MC1._I), 0. );
03289      double r11 = ( thin1?  0.: ( maxU1L2 - maxL1L2 ) / Op<T>::diam(MC1._I) );
03290      double r21 = ( thin1?  0.: ( maxL1U2 - maxU1U2 ) / Op<T>::diam(MC1._I) );
03291 
03292      bool thin2 = isequal( Op<T>::diam(MC2._I), 0. );
03293      double r12 = ( thin2?  0.: ( maxL1U2 - maxL1L2 ) / Op<T>::diam(MC2._I) );
03294      double r22 = ( thin2?  0.: ( maxU1L2 - maxU1U2 ) / Op<T>::diam(MC2._I) );
03295 
03296      double g1cc = maxL1L2 + r11 * ( MC1._cc - Op<T>::l(MC1._I) )
03297                            + r12 * ( MC2._cc - Op<T>::l(MC2._I) );
03298      double g2cc = maxU1U2 - r21 * ( MC1._cc - Op<T>::u(MC1._I) )
03299                            - r22 * ( MC2._cc - Op<T>::u(MC2._I) );
03300      if( g1cc <= g2cc ){
03301        MC3._cc = g1cc;
03302       for( unsigned int i=0; i< MC3._nsub; i++ )
03303         MC3._ccsub[i] = (MC1._const? 0.: r11*MC1._ccsub[i])
03304                       + (MC2._const? 0.: r12*MC2._ccsub[i]);
03305      }
03306      else{
03307        MC3._cc = g2cc;
03308       for( unsigned int i=0; i< MC3._nsub; i++ )
03309         MC3._ccsub[i] = - (MC1._const? 0.: r21*MC1._ccsub[i])
03310                         - (MC2._const? 0.: r22*MC2._ccsub[i]);
03311      }
03312   }
03313   else{
03314     McCormick<T> MCMax = 0.5*( MC1 + MC2 + fabs( MC1 - MC2 ) );
03315     MC3._cc = MCMax._cc;
03316     for( unsigned int i=0; i< MC3._nsub; i++ )
03317       MC3._ccsub[i] = MCMax._ccsub[i];
03318   }
03319 
03320   MC3._cv = std::max( MC1._cv, MC2._cv );
03321   for( unsigned int i=0; i< MC3._nsub; i++ )
03322     MC3._cvsub[i] = ( MC1._cv>=MC2._cv? (MC1._const? 0.: MC1._cvsub[i])
03323                                       : (MC2._const? 0.: MC2._cvsub[i]) );
03324 
03325   return  MC3.cut();
03326 }
03327 
03328 template <typename T> inline McCormick<T>
03329 min
03330 ( const unsigned int n, const McCormick<T>*MC )
03331 {
03332   McCormick<T> MC2( n==0 || !MC ? 0.: MC[0] );
03333   for( unsigned int i=1; i<n; i++ ) MC2 = min( MC2, MC[i] );
03334   return MC2;
03335 }
03336 
03337 template <typename T> inline McCormick<T>
03338 max
03339 ( const unsigned int n, const McCormick<T>*MC )
03340 {
03341   McCormick<T> MC2( n==0 || !MC ? 0.: MC[0] );
03342   for( unsigned int i=1; i<n; i++ ) MC2 = max( MC2, MC[i] );
03343   return MC2;
03344 }
03345 
03346 template <typename T> inline McCormick<T>
03347 fstep
03348 ( const McCormick<T> &MC )
03349 {
03350   McCormick<T> MC2;
03351   MC2._sub( MC._nsub, MC._const );
03352   if( Op<T>::l( MC._I ) >= 0 )
03353     MC2._I = 1.;
03354   else if( Op<T>::u( MC._I ) < 0 )
03355     MC2._I = 0.;
03356   else
03357     MC2._I = Op<T>::zeroone();
03358   
03359   { int imid = -1;
03360     double zmin = Op<T>::l(MC._I);
03361     double vmid = mid( MC._cv, MC._cc, zmin, imid );
03362     const double* cvenv = McCormick<T>::_stepcv( vmid, Op<T>::l(MC._I),
03363       Op<T>::u(MC._I) );
03364     MC2._cv = cvenv[0];
03365     for( unsigned int i=0; i<MC2._nsub; i++ )
03366       MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid )*cvenv[1];
03367   }
03368   
03369   { int imid = -1;
03370     double zmax = Op<T>::u(MC._I);
03371     double vmid = mid( MC._cv, MC._cc, zmax, imid );
03372     const double* ccenv = McCormick<T>::_stepcc( vmid, Op<T>::l(MC._I),
03373       Op<T>::u(MC._I) );
03374     MC2._cc = ccenv[0];
03375     for( unsigned int i=0; i<MC2._nsub; i++ )
03376       MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid )*ccenv[1];
03377   }
03378 
03379   return  MC2.cut();
03380 }
03381 
03382 template <typename T> inline McCormick<T>
03383 bstep
03384 ( const McCormick<T> &MC )
03385 {
03386   return fstep( -MC );  
03387 }
03388 
03389 template <typename T> inline McCormick<T>
03390 ltcond
03391 ( const T &I0, const McCormick<T> &MC1, const McCormick<T> &MC2 )
03392 {
03393   if( Op<T>::u( I0 ) < 0. )       return MC1;
03394   else if( Op<T>::l( I0 ) >= 0. ) return MC2;
03395 
03396   McCormick<T> MC3;
03397   if( MC2._const )
03398     MC3._sub( MC1._nsub, MC1._const );
03399   else if( MC1._const )
03400     MC3._sub( MC2._nsub, MC2._const );
03401   else if( MC1._nsub != MC2._nsub )
03402     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
03403   else
03404     MC3._sub( MC1._nsub, MC1._const||MC2._const );
03405 
03406   MC3._I = Op<T>::hull( MC1._I, MC2._I );
03407   McCormick<T> MCMin  = 0.5*( MC1 + MC2 - fabs( MC2 - MC1 ) );
03408   McCormick<T> MCMax  = 0.5*( MC1 + MC2 + fabs( MC1 - MC2 ) );
03409   MC3._cv = MCMin._cv;
03410   MC3._cc = MCMax._cc;
03411   for( unsigned int i=0; i< MC3._nsub; i++ ){
03412     MC3._cvsub[i] = MCMin._cvsub[i];
03413     MC3._ccsub[i] = MCMax._ccsub[i];
03414   }    
03415   return  MC3.cut();
03416 }
03417 
03418 template <typename T> inline McCormick<T>
03419 ltcond
03420 ( const McCormick<T> &MC0, const McCormick<T> &MC1, const McCormick<T> &MC2 )
03421 {
03422   McCormick<T> MC3 = ltcond( MC0._I, MC1, MC2 );
03423   McCormick<T> MCStep = fstep(-MC0)*MC1 + fstep(MC0)*MC2;
03424   if( MCStep._cv > MC3._cv ){
03425     MC3._cv = MCStep._cv;
03426     for( unsigned int i=0; i< MC3._nsub; i++ )
03427       MC3._cvsub[i] = MCStep._cvsub[i];
03428   }    
03429   if( MCStep._cc < MC3._cc ){
03430     MC3._cc = MCStep._cc;
03431     for( unsigned int i=0; i< MC3._nsub; i++ )
03432       MC3._ccsub[i] = MCStep._ccsub[i];
03433   }    
03434   return  MC3.cut();
03435 }
03436 
03437 template <typename T> inline McCormick<T>
03438 gtcond
03439 ( const T &I0, const McCormick<T> &MC1, const McCormick<T> &MC2 )
03440 {
03441   return ltcond( -I0, MC1, MC2 );
03442 }
03443 template <typename T> inline McCormick<T>
03444 gtcond
03445 ( const McCormick<T> &MC0, const McCormick<T> &MC1, const McCormick<T> &MC2 )
03446 {
03447   return ltcond( -MC0, MC1, MC2 );
03448 }
03449 
03450 template <typename T> inline McCormick<T>
03451 cos
03452 ( const McCormick<T> &MC )
03453 {
03454   McCormick<T> MC2;
03455   MC2._sub( MC._nsub, MC._const );
03456   MC2._I = Op<T>::cos( MC._I );
03457 
03458   if( !McCormick<T>::options.ENVEL_USE ){
03459      MC2._cv = Op<T>::l(MC2._I);
03460      MC2._cc = Op<T>::u(MC2._I);
03461     for( unsigned int i=0; i<MC2._nsub; i++ ){
03462       MC2._cvsub[i] = MC2._ccsub[i] = 0.;
03463     }
03464     return MC2;
03465   }
03466   
03467   double*argbnd = McCormick<T>::_cosarg( Op<T>::l(MC._I), Op<T>::u(MC._I) );
03468   { int imid = -1;
03469     const double* cvenv = McCormick<T>::_coscv( mid( MC._cv,
03470       MC._cc, argbnd[0], imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
03471     MC2._cv = cvenv[0];
03472     for( unsigned int i=0; i< MC2._nsub; i++ ){
03473        MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1];
03474     }
03475   }
03476   { int imid = -1;
03477     const double* ccenv = McCormick<T>::_coscc( mid( MC._cv,
03478       MC._cc, argbnd[1], imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
03479      MC2._cc = ccenv[0];
03480     for( unsigned int i=0; i< MC2._nsub; i++ ){
03481        MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
03482     }
03483   }
03484   return  MC2.cut();
03485 }
03486 
03487 template <typename T> inline McCormick<T>
03488 sin
03489 ( const McCormick<T> &MC )
03490 {
03491   return cos( MC - PI/2. );
03492 }
03493 
03494 template <typename T> inline McCormick<T>
03495 asin
03496 ( const McCormick<T> &MC )
03497 {
03498   if ( Op<T>::l(MC._I) <= -1. || Op<T>::u(MC._I) >= 1. )
03499     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::ASIN );
03500 
03501   McCormick<T> MC2;
03502   MC2._sub( MC._nsub, MC._const );
03503   MC2._I = Op<T>::asin( MC._I );
03504 
03505   if( !McCormick<T>::options.ENVEL_USE ){
03506     { int imid = -1;
03507       MC2._cv = Op<T>::l(MC2._I) + ( mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid )
03508         - Op<T>::l(MC._I) );
03509       for( unsigned int i=0; i<MC2._nsub; i++ ){
03510         MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid );
03511       }
03512     }
03513     { int imid = -1;
03514       MC2._cc = Op<T>::u(MC2._I) + ( mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid )
03515         - Op<T>::u(MC._I) );
03516       for( unsigned int i=0; i<MC2._nsub; i++ ){
03517         MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid );
03518       }
03519     }
03520     return MC2.cut();
03521   }
03522 
03523   { int imid = -1;
03524     const double* cvenv = McCormick<T>::_asincv( mid( MC._cv,
03525       MC._cc, Op<T>::l(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
03526     MC2._cv = cvenv[0];
03527     for( unsigned int i=0; i<MC2._nsub; i++ ){
03528       MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1];
03529     }
03530   }
03531   { int imid = -1;
03532     const double* ccenv = McCormick<T>::_asincc( mid( MC._cv,
03533       MC._cc, Op<T>::u(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
03534     MC2._cc = ccenv[0];
03535     for( unsigned int i=0; i<MC2._nsub; i++ ){
03536       MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
03537     }
03538   }
03539   return MC2.cut();
03540 }
03541 
03542 template <typename T> inline McCormick<T>
03543 acos
03544 ( const McCormick<T> &MC )
03545 {
03546   return asin( -MC ) + PI/2.;
03547 }
03548 
03549 template <typename T> inline McCormick<T>
03550 tan
03551 ( const McCormick<T> &MC )
03552 {
03553   if ( Op<T>::diam(MC._I) >= PI )
03554     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::TAN );
03555   const double shift = PI*std::ceil(-Op<T>::l(MC._I)/PI-1./2.);
03556   const double xL1 = Op<T>::l(MC._I)+shift, xU1 = Op<T>::u(MC._I)+shift;
03557   if ( xL1 <= -PI/2. || xU1 >= PI/2. )
03558     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::TAN );
03559 
03560   McCormick<T> MC2;
03561   MC2._sub( MC._nsub, MC._const );
03562   MC2._I = Op<T>::tan( MC._I );
03563 
03564   if( !McCormick<T>::options.ENVEL_USE ){
03565     { int imid = -1;
03566       MC2._cv = Op<T>::l(MC2._I) + ( mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid )
03567         - Op<T>::l(MC._I) );
03568       for( unsigned int i=0; i<MC2._nsub; i++ ){
03569         MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid );
03570       }
03571     }
03572     { int imid = -1;
03573       MC2._cc = Op<T>::u(MC2._I) + ( mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid )
03574         - Op<T>::u(MC._I) );
03575       for( unsigned int i=0; i<MC2._nsub; i++ ){
03576         MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid );
03577       }
03578     }
03579     return MC2.cut();
03580   }
03581 
03582   { int imid = -1;
03583     const double* cvenv = McCormick<T>::_tancv( mid( MC._cv+shift,
03584       MC._cc+shift, Op<T>::l(MC._I)+shift, imid ), Op<T>::l(MC._I)+shift,
03585       Op<T>::u(MC._I)+shift );
03586     MC2._cv = cvenv[0];
03587     for( unsigned int i=0; i<MC2._nsub; i++ ){
03588       MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1];
03589     }
03590   }
03591   { int imid = -1;
03592     const double* ccenv = McCormick<T>::_tancc( mid( MC._cv+shift,
03593       MC._cc+shift, Op<T>::u(MC._I)+shift, imid ), Op<T>::l(MC._I)+shift,
03594       Op<T>::u(MC._I)+shift );
03595     MC2._cc = ccenv[0];
03596     for( unsigned int i=0; i<MC2._nsub; i++ ){
03597       MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
03598     }
03599   }
03600   return MC2.cut();
03601 }
03602 
03603 template <typename T> inline McCormick<T>
03604 atan
03605 ( const McCormick<T> &MC )
03606 {
03607   McCormick<T> MC2;
03608   MC2._sub( MC._nsub, MC._const );
03609   MC2._I = Op<T>::atan( MC._I );
03610 
03611   if( !McCormick<T>::options.ENVEL_USE ){
03612      MC2._cv = Op<T>::l(MC2._I);
03613      MC2._cc = Op<T>::u(MC2._I);
03614     for( unsigned int i=0; i<MC2._nsub; i++ ){
03615       MC2._cvsub[i] = MC2._ccsub[i] = 0.;
03616     }
03617     return MC2;
03618   }
03619 
03620   { int imid = -1;
03621     const double* cvenv = McCormick<T>::_atancv( mid( MC._cv,
03622       MC._cc, Op<T>::l(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
03623     MC2._cv = cvenv[0];
03624     for( unsigned int i=0; i<MC2._nsub; i++ ){
03625       MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1];
03626     }
03627   }
03628   { int imid = -1;
03629     const double* ccenv = McCormick<T>::_atancc( mid( MC._cv,
03630       MC._cc, Op<T>::u(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
03631     MC2._cc = ccenv[0];
03632     for( unsigned int i=0; i<MC2._nsub; i++ ){
03633       MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
03634     }
03635   }
03636   return MC2.cut();
03637 }
03638 
03639 template <typename T> inline std::ostream&
03640 operator<<
03641 ( std::ostream&out, const McCormick<T>&MC)
03642 {
03643   out << std::scientific << std::setprecision(McCormick<T>::options.DISPLAY_DIGITS) << std::right
03644       << "[ " << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.l() << " : "
03645               << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.u()
03646       << " ] [ "  << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.cv() << " : "
03647                   << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.cc() << " ]";
03648   if( MC._nsub ){
03649     out << " [ (";
03650     for( unsigned int i=0; i<MC._nsub-1; i++ )
03651       out << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.cvsub(i) << ",";
03652     out << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.cvsub(MC._nsub-1) << ") : (";
03653     for( unsigned int i=0; i<MC._nsub-1; i++ )
03654       out << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.ccsub(i) << ",";
03655     out << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.ccsub(MC._nsub-1) << ") ]";
03656   }
03657   return out;
03658 }
03659 
03660 
03661 template <typename T> inline McCormick<T>
03662 hull
03663 ( const McCormick<T>&X, const McCormick<T>&Y )
03664 {
03665   if( !X._const && !Y._const && (X._nsub != Y._nsub) )
03666     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
03667 
03668   McCormick<T> CV = min(X,Y);
03669   McCormick<T> CC = max(X,Y);
03670   McCormick<T> XUY( Op<T>::hull(X.I(),Y.I()), CV.cv(), CC.cc() );
03671   if( !X._const )
03672     XUY._sub( X._nsub, X._const );
03673   else
03674     XUY._sub( Y._nsub, Y._const );
03675   for( unsigned int is=0; is<XUY._nsub; is++ ){
03676     XUY._cvsub[is] = CV.cvsub(is);
03677     XUY._ccsub[is] = CC.ccsub(is);
03678   }
03679   return XUY;
03680 }
03681 
03682 template <typename T> inline bool
03683 inter
03684 ( McCormick<T>&XIY, const McCormick<T>&X, const McCormick<T>&Y )
03685 {
03686   if( !X._const && !Y._const && (X._nsub != Y._nsub) )
03687     throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
03688 
03689   if( !Op<T>::inter( XIY._I, X._I, Y._I ) ) return false;
03690   McCormick<T> CV = max(X,Y);
03691   McCormick<T> CC = min(X,Y);
03692   if( CV.cv() > CC.cc() ) return false;
03693   XIY._cv = CV.cv();
03694   XIY._cc = CC.cc();
03695   if( !X._const )
03696     XIY._sub( X._nsub, X._const );
03697   else
03698     XIY._sub( Y._nsub, Y._const );
03699   for( unsigned int is=0; is<XIY._nsub; is++ ){
03700     XIY._cvsub[is] = CV.cvsub(is);
03701     XIY._ccsub[is] = CC.ccsub(is);
03702   }
03703   return true;
03704 }
03705 
03706 template <typename T> inline bool
03707 operator==
03708 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
03709 {
03710   return( Op<T>::eq(MC1._I,MC2._I) && MC1._cv == MC2._cv && MC1._cc == MC2._cc );
03711 }
03712 
03713 template <typename T> inline bool
03714 operator!=
03715 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
03716 {
03717   return( Op<T>::ne(MC1._I,MC2._I) || MC1._cv != MC2._cv || MC1._cc != MC2._cc );
03718 }
03719 
03720 template <typename T> inline bool
03721 operator<=
03722 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
03723 {
03724   return( Op<T>::le(MC1._I,MC2._I) && MC1._cv >= MC2._cv && MC1._cc <= MC2._cc );
03725 }
03726 
03727 template <typename T> inline bool
03728 operator>=
03729 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
03730 {
03731   return( Op<T>::ge(MC1._I,MC2._I) && MC1._cv <= MC2._cv && MC1._cc >= MC2._cc );
03732 }
03733 
03734 template <typename T> inline bool
03735 operator<
03736 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
03737 {
03738   return( Op<T>::lt(MC1._I,MC2._I) && MC1._cv > MC2._cv && MC1._cc < MC2._cc );
03739 }
03740 
03741 template <typename T> inline bool
03742 operator>
03743 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
03744 {
03745   return( Op<T>::gt(MC1._I,MC2._I) && MC1._cv < MC2._cv && MC1._cc > MC2._cc );
03746 }
03747 
03748 template <typename T> typename McCormick<T>::Options McCormick<T>::options;
03749 
03750 } // namespace mc
03751 
03752 
03753 #include "mcop.hpp"
03754 
03755 namespace mc
03756 {
03757 
03759 template <> template<typename T> struct Op< mc::McCormick<T> >
03760 {
03761   typedef mc::McCormick<T> MC;
03762   static MC point( const double c ) { return MC(c); }
03763   static MC zeroone() { return MC( mc::Op<T>::zeroone() ); }
03764   static void I(MC& x, const MC&y) { x = y; }
03765   static double l(const MC& x) { return x.l(); }
03766   static double u(const MC& x) { return x.u(); }
03767   static double abs (const MC& x) { return mc::Op<T>::abs(x.I());  }
03768   static double mid (const MC& x) { return mc::Op<T>::mid(x.I());  }
03769   static double diam(const MC& x) { return mc::Op<T>::diam(x.I()); }
03770   static MC inv (const MC& x) { return mc::inv(x);  }
03771   static MC sqr (const MC& x) { return mc::sqr(x);  }
03772   static MC sqrt(const MC& x) { return mc::sqrt(x); }
03773   static MC log (const MC& x) { return mc::log(x);  }
03774   static MC xlog(const MC& x) { return mc::xlog(x); }
03775   static MC fabs(const MC& x) { return mc::fabs(x); }
03776   static MC exp (const MC& x) { return mc::exp(x);  }
03777   static MC sin (const MC& x) { return mc::sin(x);  }
03778   static MC cos (const MC& x) { return mc::cos(x);  }
03779   static MC tan (const MC& x) { return mc::tan(x);  }
03780   static MC asin(const MC& x) { return mc::asin(x); }
03781   static MC acos(const MC& x) { return mc::acos(x); }
03782   static MC atan(const MC& x) { return mc::atan(x); }
03783   static MC erf (const MC& x) { return mc::erf(x);  }
03784   static MC erfc(const MC& x) { return mc::erfc(x); }
03785   static MC hull(const MC& x, const MC& y) { return mc::Op<T>::hull(x.I(),y.I()); }
03786   static MC min (const MC& x, const MC& y) { return mc::min(x,y);  }
03787   static MC max (const MC& x, const MC& y) { return mc::max(x,y);  }
03788   static MC arh (const MC& x, const double k) { return mc::arh(x,k); }
03789   template <typename X, typename Y> static MC pow(const X& x, const Y& y) { return mc::pow(x,y); }
03790   static MC monomial (const unsigned int n, const T* x, const int* k) { return mc::monomial(n,x,k); }
03791   static bool inter(MC& xIy, const MC& x, const MC& y) { return mc::inter(xIy,x,y); }
03792   static bool eq(const MC& x, const MC& y) { return x==y; }
03793   static bool ne(const MC& x, const MC& y) { return x!=y; }
03794   static bool lt(const MC& x, const MC& y) { return x<y;  }
03795   static bool le(const MC& x, const MC& y) { return x<=y; }
03796   static bool gt(const MC& x, const MC& y) { return x>y;  }
03797   static bool ge(const MC& x, const MC& y) { return x>=y; }
03798 };
03799 
03800 } // namespace mc
03801 
03802 #endif