MC++
|
00001 // Copyright (C) 2005-2012 Benoit Chachuat (b.chachuat@imperial.ac.uk) 00002 // All rights reserved. 00003 00004 // This code is provided "as is", without any warranty of any kind, 00005 // either expressed or implied, including but not limited to, any implied 00006 // warranty of merchantibility or fitness for any purpose. In no event 00007 // will any party who distributed the code be liable for damages or for 00008 // any claim(s) by any other party, including but not limited to, any 00009 // lost profits, lost monies, lost data or data rendered inaccurate, 00010 // losses sustained by third parties, or any other special, incidental or 00011 // consequential damages arising out of the use or inability to use the 00012 // program, even if the possibility of such damages has been advised 00013 // against. The entire risk as to the quality, the performance, and the 00014 // fitness of the program for any particular purpose lies with the party 00015 // using the code. 00016 00017 // This code, and any derivative of this code, may not be used in a 00018 // commercial package without the prior explicit written permission of 00019 // the authors. Verbatim copies of this code may be made and distributed 00020 // in any medium, provided that this copyright notice is not removed or 00021 // altered in any way. No fees may be charged for distribution of the 00022 // codes, other than a fee to cover the cost of the media and a 00023 // reasonable handling fee. 00024 00025 // *************************************************************** 00026 // ANY USE OF THIS CODE CONSTITUTES ACCEPTANCE OF THE TERMS OF THE 00027 // COPYRIGHT NOTICE 00028 // *************************************************************** 00029 00193 #ifndef MC__MCCORMICK_H 00194 #define MC__MCCORMICK_H 00195 00196 #include <iostream> 00197 #include <iomanip> 00198 #include <stdarg.h> 00199 #include <cassert> 00200 #include "mcfunc.h" 00201 #include "mcop.h" 00202 00203 namespace mc 00204 { 00213 template <typename T> 00214 class McCormick 00216 { 00217 // friends of class McCormick for constructor overloading 00218 template <typename U> friend class McCormick; 00219 00220 // friends of class McCormick for operator overloading 00221 template <typename U> friend McCormick<U> operator+ 00222 ( const McCormick<U>& ); 00223 template <typename U> friend McCormick<U> operator+ 00224 ( const McCormick<U>&, const McCormick<U>& ); 00225 template <typename U> friend McCormick<U> operator+ 00226 ( const double, const McCormick<U>& ); 00227 template <typename U> friend McCormick<U> operator+ 00228 ( const McCormick<U>&, const double ); 00229 template <typename U> friend McCormick<U> operator- 00230 ( const McCormick<U>& ); 00231 template <typename U> friend McCormick<U> operator- 00232 ( const McCormick<U>&, const McCormick<U>& ); 00233 template <typename U> friend McCormick<U> operator- 00234 ( const double, const McCormick<U>& ); 00235 template <typename U> friend McCormick<U> operator- 00236 ( const McCormick<U>&, const double ); 00237 template <typename U> friend McCormick<U> operator* 00238 ( const McCormick<U>&, const McCormick<U>& ); 00239 template <typename U> friend McCormick<U> operator* 00240 ( const double, const McCormick<U>& ); 00241 template <typename U> friend McCormick<U> operator* 00242 ( const McCormick<U>&, const double ); 00243 template <typename U> friend McCormick<U> operator/ 00244 ( const McCormick<U>&, const McCormick<U>& ); 00245 template <typename U> friend McCormick<U> operator/ 00246 ( const double, const McCormick<U>& ); 00247 template <typename U> friend McCormick<U> operator/ 00248 ( const McCormick<U>&, const double ); 00249 template <typename U> friend std::ostream& operator<< 00250 ( std::ostream&, const McCormick<U>& ); 00251 template <typename U> friend bool operator== 00252 ( const McCormick<U>&, const McCormick<U>& ); 00253 template <typename U> friend bool operator!= 00254 ( const McCormick<U>&, const McCormick<U>& ); 00255 template <typename U> friend bool operator<= 00256 ( const McCormick<U>&, const McCormick<U>& ); 00257 template <typename U> friend bool operator>= 00258 ( const McCormick<U>&, const McCormick<U>& ); 00259 template <typename U> friend bool operator< 00260 ( const McCormick<U>&, const McCormick<U>& ); 00261 template <typename U> friend bool operator> 00262 ( const McCormick<U>&, const McCormick<U>& ); 00263 00264 // friends of class McCormick for function overloading 00265 template <typename U> friend McCormick<U> inv 00266 ( const McCormick<U>& ); 00267 template <typename U> friend McCormick<U> sqr 00268 ( const McCormick<U>& ); 00269 template <typename U> friend McCormick<U> exp 00270 ( const McCormick<U>& ); 00271 template <typename U> friend McCormick<U> log 00272 ( const McCormick<U>& ); 00273 template <typename U> friend McCormick<U> cos 00274 ( const McCormick<U>& ); 00275 template <typename U> friend McCormick<U> sin 00276 ( const McCormick<U>& ); 00277 template <typename U> friend McCormick<U> tan 00278 ( const McCormick<U>& ); 00279 template <typename U> friend McCormick<U> acos 00280 ( const McCormick<U>& ); 00281 template <typename U> friend McCormick<U> asin 00282 ( const McCormick<U>& ); 00283 template <typename U> friend McCormick<U> atan 00284 ( const McCormick<U>& ); 00285 template <typename U> friend McCormick<U> fabs 00286 ( const McCormick<U>& ); 00287 template <typename U> friend McCormick<U> sqrt 00288 ( const McCormick<U>& ); 00289 template <typename U> friend McCormick<U> xlog 00290 ( const McCormick<U>& ); 00291 template <typename U> friend McCormick<U> arh 00292 ( const McCormick<U>&, const double ); 00293 template <typename U> friend McCormick<U> erf 00294 ( const McCormick<U>& ); 00295 template <typename U> friend McCormick<U> erfc 00296 ( const McCormick<U>& ); 00297 template <typename U> friend McCormick<U> fstep 00298 ( const McCormick<U>& ); 00299 template <typename U> friend McCormick<U> bstep 00300 ( const McCormick<U>& ); 00301 template <typename U> friend McCormick<U> pow 00302 ( const McCormick<U>&, const int ); 00303 template <typename U> friend McCormick<U> pow 00304 ( const McCormick<U>&, const double ); 00305 template <typename U> friend McCormick<U> pow 00306 ( const double, const McCormick<U>& ); 00307 template <typename U> friend McCormick<U> pow 00308 ( const McCormick<U>&, const McCormick<U>& ); 00309 template <typename U> friend McCormick<U> monomial 00310 ( const unsigned int, const McCormick<U>*, const int* ); 00311 template <typename U> friend McCormick<U> min 00312 ( const McCormick<U>&, const McCormick<U>& ); 00313 template <typename U> friend McCormick<U> max 00314 ( const McCormick<U>&, const McCormick<U>& ); 00315 template <typename U> friend McCormick<U> min 00316 ( const unsigned int, const McCormick<U>* ); 00317 template <typename U> friend McCormick<U> max 00318 ( const unsigned int, const McCormick<U>* ); 00319 template <typename U> friend McCormick<U> ltcond 00320 ( const McCormick<U>&, const McCormick<U>&, const McCormick<U>& ); 00321 template <typename U> friend McCormick<U> ltcond 00322 ( const U&, const McCormick<U>&, const McCormick<U>& ); 00323 template <typename U> friend McCormick<U> gtcond 00324 ( const McCormick<U>&, const McCormick<U>&, const McCormick<U>& ); 00325 template <typename U> friend McCormick<U> gtcond 00326 ( const U&, const McCormick<U>&, const McCormick<U>& ); 00327 template <typename U> friend bool inter 00328 ( McCormick<U>&, const McCormick<U>&, const McCormick<U>& ); 00329 template <typename U> friend McCormick<U> cut 00330 ( const McCormick<U>& ); 00331 00332 public: 00333 00334 // other operator overloadings 00335 McCormick<T>& operator= 00336 ( const McCormick<T>& ); 00337 McCormick<T>& operator= 00338 ( const T& ); 00339 McCormick<T>& operator= 00340 ( const double ); 00341 McCormick<T>& operator+= 00342 ( const McCormick<T>& ); 00343 McCormick<T>& operator+= 00344 ( const double ); 00345 McCormick<T>& operator-= 00346 ( const McCormick<T>& ); 00347 McCormick<T>& operator-= 00348 ( const double ); 00349 McCormick<T>& operator*= 00350 ( const McCormick<T>& ); 00351 McCormick<T>& operator*= 00352 ( const double ); 00353 McCormick<T>& operator/= 00354 ( const McCormick<T>& ); 00355 McCormick<T>& operator/= 00356 ( const double ); 00357 00361 00362 static struct Options 00363 { 00365 Options(): 00366 NEWTON_USE(true), NEWTON_MAXIT(100), NEWTON_TOL(1e-10), MVCOMP_USE(false), 00367 MVCOMP_TOL(1e1*machprec()) 00368 {} 00370 bool NEWTON_USE; 00372 unsigned int NEWTON_MAXIT; 00374 double NEWTON_TOL; 00376 bool MVCOMP_USE; 00378 double MVCOMP_TOL; 00379 } options; 00380 00382 class Exceptions 00383 { 00384 public: 00386 enum TYPE{ 00387 DIV=1, 00388 INV, 00389 LOG, 00390 SQRT, 00391 ASIN, 00392 NEWTON, 00393 MULTSUB, 00394 SUB=-1, 00395 UNDEF=-2 00396 }; 00398 Exceptions( TYPE ierr ) : _ierr( ierr ){} 00400 int ierr(){ return _ierr; } 00401 00402 private: 00403 TYPE _ierr; 00404 }; 00405 00407 McCormick(): 00408 _nsub(0), _cvsub(0), _ccsub(0), _const(true) 00409 {} 00411 McCormick 00412 ( const double c ): 00413 _nsub(0), _cv(c), _cc(c), _cvsub(0), _ccsub(0), _const(true) 00414 { 00415 Op<T>::I(_I,c); 00416 } 00418 McCormick 00419 ( const T&I ): 00420 _nsub(0), _cvsub(0), _ccsub(0), _const(true) 00421 { 00422 Op<T>::I(_I,I); 00423 _cv = Op<T>::l(I); _cc = Op<T>::u(I); 00424 } 00426 McCormick 00427 ( const T&I, const double c ): 00428 _nsub(0), _cv(c), _cc(c), _cvsub(0), _ccsub(0), _const(false) 00429 { 00430 Op<T>::I(_I,I); 00431 } 00433 McCormick 00434 ( const T&I, const double cv, const double cc ): 00435 _nsub(0), _cv(cv), _cc(cc), _cvsub(0), _ccsub(0), _const(false) 00436 { 00437 Op<T>::I(_I,I); cut(); 00438 } 00440 McCormick 00441 ( const McCormick<T>&MC ): 00442 _nsub(MC._nsub), _cv(MC._cv), _cc(MC._cc), 00443 _cvsub(_nsub>0?new double[_nsub]:0), _ccsub(_nsub>0?new double[_nsub]:0), 00444 _const(MC._const) 00445 { 00446 Op<T>::I(_I,MC._I); 00447 for ( unsigned int ip=0; ip<_nsub; ip++ ){ 00448 _cvsub[ip] = MC._cvsub[ip]; 00449 _ccsub[ip] = MC._ccsub[ip]; 00450 } 00451 } 00453 template <typename U> McCormick 00454 ( const McCormick<U>&MC ): 00455 _nsub(MC._nsub), _cv(MC._cv), _cc(MC._cc), 00456 _cvsub(_nsub>0?new double[_nsub]:0), _ccsub(_nsub>0?new double[_nsub]:0), 00457 _const(MC._const) 00458 { 00459 Op<T>::I(_I,MC._I); 00460 for ( unsigned int ip=0; ip<_nsub; ip++ ){ 00461 _cvsub[ip] = MC._cvsub[ip]; 00462 _ccsub[ip] = MC._ccsub[ip]; 00463 } 00464 } 00465 00467 ~McCormick() 00468 { 00469 delete [] _cvsub; 00470 delete [] _ccsub; 00471 } 00472 00474 unsigned int& nsub() 00475 { 00476 return _nsub; 00477 } 00478 const unsigned int nsub() const 00479 { 00480 return _nsub; 00481 } 00483 T& I() 00484 { 00485 return _I; 00486 } 00487 const T& I() const 00488 { 00489 return _I; 00490 } 00492 const double l() const 00493 { 00494 return Op<T>::l(_I); 00495 } 00497 const double u() const 00498 { 00499 return Op<T>::u(_I); 00500 } 00502 double& cv() 00503 { 00504 return _cv; 00505 } 00506 const double cv() const 00507 { 00508 return _cv; 00509 } 00511 double& cc() 00512 { 00513 return _cc; 00514 } 00515 const double cc() const 00516 { 00517 return _cc; 00518 } 00520 double*& cvsub() 00521 { 00522 return _cvsub; 00523 } 00524 const double* cvsub() const 00525 { 00526 return _cvsub; 00527 } 00529 double*& ccsub() 00530 { 00531 return _ccsub; 00532 } 00533 const double* ccsub() const 00534 { 00535 return _ccsub; 00536 } 00538 double& cvsub 00539 ( const unsigned int i ) 00540 { 00541 return _cvsub[i]; 00542 } 00543 const double cvsub 00544 ( const unsigned int i ) const 00545 { 00546 return _cvsub[i]; 00547 } 00549 double& ccsub 00550 ( const unsigned int i ) 00551 { 00552 return _ccsub[i]; 00553 } 00554 const double ccsub 00555 ( const unsigned int i ) const 00556 { 00557 return _ccsub[i]; 00558 } 00559 00561 void I 00562 ( const T& I ) 00563 { 00564 Op<T>::I(_I,I); 00565 } 00567 void cv 00568 ( const double& cv ) 00569 { 00570 _cv = cv; 00571 _const = false; 00572 } 00574 void cc 00575 ( const double& cc ) 00576 { 00577 _cc = cc; 00578 _const = false; 00579 } 00581 void c 00582 ( const double& c ) 00583 { 00584 _cv = _cc = c; 00585 _const = false; 00586 } 00587 00589 McCormick<T>& sub 00590 ( const unsigned int nsub); 00592 McCormick<T>& sub 00593 ( const unsigned int nsub, const unsigned int isub ); 00595 McCormick<T>& sub 00596 ( const unsigned int nsub, const double*cvsub, const double*ccsub ); 00597 00599 McCormick<T>& cut(); 00601 double laff 00602 ( const double*p, const double*pref ) const; 00604 double laff 00605 ( const T*Ip, const double*pref ) const; 00607 double uaff 00608 ( const double*p, const double*pref ) const; 00610 double uaff 00611 ( const T*Ip, const double*pref ) const; 00612 // //! @brief Calculates affine bounds based on the subgradient values. 00615 private: 00616 00618 unsigned int _nsub; 00620 T _I; 00622 double _cv; 00624 double _cc; 00626 double *_cvsub; 00628 double *_ccsub; 00630 bool _const; 00631 00633 void _sub 00634 ( const unsigned int nsub, const bool cst ); 00636 void _sub_reset(); 00638 void _sub_resize 00639 ( const unsigned int nsub ); 00641 void _sub_copy 00642 ( const McCormick<T>&MC ); 00643 00645 McCormick<T>& _sum1 00646 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ); 00648 McCormick<T>& _sum2 00649 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ); 00650 00652 McCormick<T>& _sub1 00653 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ); 00655 McCormick<T>& _sub2 00656 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ); 00658 McCormick<T>& _sub3 00659 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ); 00660 00662 McCormick<T>& _mul1_u1pos_u2pos 00663 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ); 00665 McCormick<T>& _mul2_u1pos_u2pos 00666 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ); 00668 McCormick<T>& _mul1_u1pos_u2mix 00669 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ); 00671 McCormick<T>& _mul2_u1pos_u2mix 00672 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ); 00674 McCormick<T>& _mul3_u1pos_u2mix 00675 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ); 00677 McCormick<T>& _mul1_u1mix_u2mix 00678 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ); 00680 McCormick<T>& _mul2_u1mix_u2mix 00681 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ); 00683 McCormick<T>& _mulMV 00684 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ); 00685 00687 typedef double (puniv) 00688 ( const double x, const double*rusr, const int*iusr ); 00690 static double _newton 00691 ( const double x0, const double xL, const double xU, const puniv f, 00692 const puniv df, const double*rusr, const int*iusr=0 ); 00694 static double _secant 00695 ( const double x0, const double x1, const double xL, const double xU, 00696 const puniv f, const double*rusr, const int*iusr ); 00697 00699 static double* _oddpowcv 00700 ( const double x, const int iexp, const double xL, const double xU ); 00702 static double* _oddpowcc 00703 ( const double x, const int iexp, const double xL, const double xU ); 00705 static double _oddpowenv_func 00706 ( const double x, const double*rusr, const int*iusr ); 00708 static double _oddpowenv_dfunc 00709 ( const double x, const double*rusr, const int*iusr ); 00710 00712 static double* _erfcv 00713 ( const double x, const double xL, const double xU ); 00715 static double* _erfcc 00716 ( const double x, const double xL, const double xU ); 00718 static double _erfenv_func 00719 ( const double x, const double*rusr, const int*iusr ); 00721 static double _erfenv_dfunc 00722 ( const double x, const double*rusr, const int*iusr ); 00723 00725 static double* _stepcv 00726 ( const double x, const double xL, const double xU ); 00728 static double* _stepcc 00729 ( const double x, const double xL, const double xU ); 00730 00732 static double* _cosarg 00733 ( const double xL, const double xU ); 00735 static double* _coscv 00736 ( const double x, const double xL, const double xU ); 00738 static double* _coscc 00739 ( const double x, const double xL, const double xU ); 00741 static double* _coscv2 00742 ( const double x, const double xL, const double xU ); 00744 static double _cosenv_func 00745 ( const double x, const double*rusr, const int*iusr ); 00747 static double _cosenv_dfunc 00748 ( const double x, const double*rusr, const int*iusr ); 00749 00751 static double* _asincv 00752 ( const double x, const double xL, const double xU ); 00754 static double* _asincc 00755 ( const double x, const double xL, const double xU ); 00757 static double _asinenv_func 00758 ( const double x, const double*rusr, const int*iusr ); 00760 static double _asinenv_dfunc 00761 ( const double x, const double*rusr, const int*iusr ); 00762 }; 00763 00765 00766 template <typename T> inline void 00767 McCormick<T>::_sub_reset() 00768 { 00769 delete [] _cvsub; 00770 delete [] _ccsub; 00771 _cvsub = _ccsub = 0; 00772 } 00773 00774 template <typename T> inline void 00775 McCormick<T>::_sub_resize 00776 ( const unsigned int nsub ) 00777 { 00778 if( _nsub != nsub ){ 00779 delete [] _cvsub; 00780 delete [] _ccsub; 00781 _nsub = nsub; 00782 if( _nsub > 0 ){ 00783 _cvsub = new double[_nsub]; 00784 _ccsub = new double[_nsub]; 00785 } 00786 else{ 00787 _cvsub = _ccsub = 0; 00788 return; 00789 } 00790 } 00791 } 00792 00793 template <typename T> inline void 00794 McCormick<T>::_sub_copy 00795 ( const McCormick<T>&MC ) 00796 { 00797 _sub_resize( MC._nsub ); 00798 for ( unsigned int i=0; i<_nsub; i++ ){ 00799 _cvsub[i] = MC._cvsub[i]; 00800 _ccsub[i] = MC._ccsub[i]; 00801 } 00802 return; 00803 } 00804 00805 template <typename T> inline void 00806 McCormick<T>::_sub 00807 ( const unsigned int nsub, const bool cst ) 00808 { 00809 _sub_resize( nsub ); 00810 for ( unsigned int i=0; i<nsub; i++ ){ 00811 _cvsub[i] = _ccsub[i] = 0.; 00812 } 00813 _const = cst; 00814 } 00815 00816 template <typename T> inline McCormick<T>& 00817 McCormick<T>::sub 00818 ( const unsigned int nsub ) 00819 { 00820 _sub( nsub, false ); 00821 return *this; 00822 } 00823 00824 template <typename T> inline McCormick<T>& 00825 McCormick<T>::sub 00826 ( const unsigned int nsub, const unsigned int isub ) 00827 { 00828 if( isub >= nsub ) throw Exceptions( Exceptions::SUB ); 00829 sub( nsub ); 00830 _cvsub[isub] = _ccsub[isub] = 1.; 00831 return *this; 00832 } 00833 00834 template <typename T> inline McCormick<T>& 00835 McCormick<T>::sub 00836 ( const unsigned int nsub, const double*cvsub, const double*ccsub ) 00837 { 00838 if( nsub && !(cvsub && ccsub) ) throw Exceptions( Exceptions::SUB ); 00839 sub( nsub ); 00840 for ( unsigned int i=0; i<nsub; i++ ){ 00841 _cvsub[i] = cvsub[i]; 00842 _ccsub[i] = ccsub[i]; 00843 } 00844 return *this; 00845 } 00846 00847 template <typename T> inline McCormick<T>& 00848 McCormick<T>::cut() 00849 { 00850 if( _cv < Op<T>::l(_I) ){ 00851 _cv = Op<T>::l(_I); 00852 for( unsigned int i=0; i<_nsub; i++ ) _cvsub[i] = 0.; 00853 } 00854 if( _cc > Op<T>::u(_I) ){ 00855 _cc = Op<T>::u(_I); 00856 for( unsigned int i=0; i<_nsub; i++ ) _ccsub[i] = 0.; 00857 } 00858 return *this; 00859 } 00860 00861 template <typename T> inline double 00862 McCormick<T>::laff 00863 ( const double*p, const double*pref ) const 00864 { 00865 double _laff = _cv; 00866 for( unsigned int i=0; i<_nsub; i++ ){ 00867 _laff += _cvsub[i]*(p[i]-pref[i]); 00868 } 00869 return _laff; 00870 } 00871 00872 template <typename T> inline double 00873 McCormick<T>::laff 00874 ( const T*Ip, const double*pref ) const 00875 { 00876 double _laff = _cv; 00877 for( unsigned int i=0; i<_nsub; i++ ){ 00878 _laff += Op<T>::l(_cvsub[i]*(Ip[i]-pref[i])); 00879 } 00880 return _laff; 00881 } 00882 00883 template <typename T> inline double 00884 McCormick<T>::uaff 00885 ( const double*p, const double*pref ) const 00886 { 00887 double _uaff = _cc; 00888 for( unsigned int i=0; i<_nsub; i++ ){ 00889 _uaff += _ccsub[i]*(p[i]-pref[i]); 00890 } 00891 return _uaff; 00892 } 00893 00894 template <typename T> inline double 00895 McCormick<T>::uaff 00896 ( const T*Ip, const double*pref ) const 00897 { 00898 double _uaff = _cc; 00899 for( unsigned int i=0; i<_nsub; i++ ){ 00900 _uaff += Op<T>::u(_ccsub[i]*(Ip[i]-pref[i])); 00901 } 00902 return _uaff; 00903 } 00904 00905 // template <typename T> template <typename U> inline U 00906 // McCormick<T>::affine 00907 // ( const U*Ip, const double*pref ) const 00908 // { 00909 // double laff = _cv; 00910 // double uaff = _cc; 00911 // for( unsigned int i=0; i<_nsub; i++ ){ 00912 // laff += Op<U>::l(_cvsub[i]*(Ip[i]-pref[i])); 00913 // uaff += Op<U>::u(_ccsub[i]*(Ip[i]-pref[i])); 00914 // } 00915 // return U(laff,uaff); 00916 // } 00917 00918 template <typename T> inline McCormick<T>& 00919 McCormick<T>::operator= 00920 ( const double c ) 00921 { 00922 _I = c; 00923 _cv = _cc = c; 00924 _sub_reset(); 00925 _nsub = 0; 00926 _const = true; 00927 return *this; 00928 } 00929 00930 template <typename T> inline McCormick<T>& 00931 McCormick<T>::operator= 00932 ( const T&I ) 00933 { 00934 _I = I; 00935 _cv = Op<T>::l(I); 00936 _cc = Op<T>::u(I); 00937 _sub_reset(); 00938 _nsub = 0; 00939 _const = true; 00940 return *this; 00941 } 00942 00943 template <typename T> inline McCormick<T>& 00944 McCormick<T>::operator= 00945 ( const McCormick<T>&MC ) 00946 { 00947 if( this == &MC ) return *this; 00948 _I = MC._I; 00949 _cv = MC._cv; 00950 _cc = MC._cc; 00951 _sub_copy( MC ); 00952 _const = MC._const; 00953 return *this; 00954 } 00955 00956 template <typename T> inline McCormick<T>& 00957 McCormick<T>::operator+= 00958 ( const double a ) 00959 { 00960 _I += a; 00961 _cv += a; 00962 _cc += a; 00963 return *this; 00964 } 00965 00966 template <typename T> inline McCormick<T>& 00967 McCormick<T>::operator+= 00968 ( const McCormick<T> &MC ) 00969 { 00970 if( _const && !MC._const ) sub( MC._nsub ); 00971 else if( !MC._const && _nsub != MC._nsub ) throw Exceptions( Exceptions::SUB ); 00972 _I += MC._I; 00973 _cv += MC._cv; 00974 _cc += MC._cc; 00975 for( unsigned int i=0; i<_nsub && !MC._const; i++ ){ 00976 _cvsub[i] += MC._cvsub[i]; 00977 _ccsub[i] += MC._ccsub[i]; 00978 } 00979 return *this; 00980 } 00981 00982 template <typename T> inline McCormick<T>& 00983 McCormick<T>::_sum1 00984 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 00985 { 00986 _I = MC1._I + MC2._I; 00987 _cv = MC1._cv + MC2._cv; 00988 _cc = MC1._cc + MC2._cc; 00989 for( unsigned int i=0; i<_nsub; i++ ){ 00990 _cvsub[i] = MC1._cvsub[i]; 00991 _ccsub[i] = MC1._ccsub[i]; 00992 } 00993 return *this; 00994 } 00995 00996 template <typename T> inline McCormick<T>& 00997 McCormick<T>::_sum2 00998 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 00999 { 01000 _I = MC1._I + MC2._I; 01001 _cv = MC1._cv + MC2._cv; 01002 _cc = MC1._cc + MC2._cc; 01003 for( unsigned int i=0; i<_nsub; i++ ){ 01004 _cvsub[i] = MC1._cvsub[i] + MC2._cvsub[i]; 01005 _ccsub[i] = MC1._ccsub[i] + MC2._ccsub[i]; 01006 } 01007 return *this; 01008 } 01009 01010 template <typename T> inline McCormick<T>& 01011 McCormick<T>::operator-= 01012 ( const double a ) 01013 { 01014 _I -= a; 01015 _cv -= a; 01016 _cc -= a; 01017 return *this; 01018 } 01019 01020 template <typename T> inline McCormick<T>& 01021 McCormick<T>::operator-= 01022 ( const McCormick<T> &MC ) 01023 { 01024 if( _const && !MC._const ) sub( MC._nsub ); 01025 else if( !MC._const && _nsub != MC._nsub ) throw Exceptions( Exceptions::SUB ); 01026 _I -= MC._I; 01027 double t_cv = MC._cv; 01028 _cv -= MC._cc; 01029 _cc -= t_cv; 01030 for( unsigned int i=0; i<_nsub && !MC._const; i++ ){ 01031 double t_cvsub = MC._cvsub[i]; 01032 _cvsub[i] -= MC._ccsub[i]; 01033 _ccsub[i] -= t_cvsub; 01034 } 01035 return *this; 01036 } 01037 01038 template <typename T> inline McCormick<T>& 01039 McCormick<T>::_sub1 01040 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 01041 { 01042 _I = MC1._I - MC2._I; 01043 _cv = MC1._cv - MC2._cc; 01044 _cc = MC1._cc - MC2._cv; 01045 for( unsigned int i=0; i<_nsub; i++ ){ 01046 _cvsub[i] = MC1._cvsub[i]; 01047 _ccsub[i] = MC1._ccsub[i]; 01048 } 01049 return *this; 01050 } 01051 01052 template <typename T> inline McCormick<T>& 01053 McCormick<T>::_sub2 01054 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 01055 { 01056 _I = MC1._I - MC2._I; 01057 _cv = MC1._cv - MC2._cc; 01058 _cc = MC1._cc - MC2._cv; 01059 for( unsigned int i=0; i<_nsub; i++ ){ 01060 _cvsub[i] = -MC2._ccsub[i]; 01061 _ccsub[i] = -MC2._cvsub[i]; 01062 } 01063 return *this; 01064 } 01065 01066 template <typename T> inline McCormick<T>& 01067 McCormick<T>::_sub3 01068 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 01069 { 01070 _I = MC1._I - MC2._I; 01071 _cv = MC1._cv - MC2._cc; 01072 _cc = MC1._cc - MC2._cv; 01073 for( unsigned int i=0; i<_nsub; i++ ){ 01074 _cvsub[i] = MC1._cvsub[i] - MC2._ccsub[i]; 01075 _ccsub[i] = MC1._ccsub[i] - MC2._cvsub[i]; 01076 } 01077 return *this; 01078 } 01079 01080 template <typename T> inline McCormick<T>& 01081 McCormick<T>::operator*= 01082 ( const double a ) 01083 { 01084 McCormick<T> MC2 = a * (*this); 01085 *this = MC2; 01086 return *this; 01087 } 01088 01089 template <typename T> inline McCormick<T>& 01090 McCormick<T>::operator*= 01091 ( const McCormick<T>&MC ) 01092 { 01093 if( _const && !MC._const ) sub( MC._nsub ); 01094 McCormick<T> MC2 = MC * (*this); 01095 *this = MC2; 01096 return *this; 01097 } 01098 01099 template <typename T> inline McCormick<T>& 01100 McCormick<T>::_mul1_u1pos_u2pos 01101 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 01102 { 01103 _I = MC1._I * MC2._I; 01104 01105 double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv 01106 - Op<T>::u(MC1._I) * Op<T>::u(MC2._I); 01107 double cv2 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::l(MC1._I) * MC2._cv 01108 - Op<T>::l(MC1._I) * Op<T>::l(MC2._I); 01109 if ( cv1 > cv2 ){ 01110 _cv = cv1; 01111 for( unsigned int i=0; i<_nsub; i++ ) 01112 _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i]; 01113 } 01114 else{ 01115 _cv = cv2; 01116 for( unsigned int i=0; i<_nsub; i++ ) 01117 _cvsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i]; 01118 } 01119 01120 double cc1 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::u(MC1._I) * MC2._cc 01121 - Op<T>::u(MC1._I) * Op<T>::l(MC2._I); 01122 double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc 01123 - Op<T>::l(MC1._I) * Op<T>::u(MC2._I); 01124 if ( cc1 < cc2 ){ 01125 _cc = cc1; 01126 for( unsigned int i=0; i<_nsub; i++ ) 01127 _ccsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i]; 01128 } 01129 else{ 01130 _cc = cc2; 01131 for( unsigned int i=0; i<_nsub; i++ ) 01132 _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i]; 01133 } 01134 return *this; 01135 } 01136 01137 template <typename T> inline McCormick<T>& 01138 McCormick<T>::_mul2_u1pos_u2pos 01139 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 01140 { 01141 _I = MC1._I * MC2._I; 01142 01143 double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv 01144 - Op<T>::u(MC1._I) * Op<T>::u(MC2._I); 01145 double cv2 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::l(MC1._I) * MC2._cv 01146 - Op<T>::l(MC1._I) * Op<T>::l(MC2._I); 01147 if ( cv1 > cv2 ){ 01148 _cv = cv1; 01149 for( unsigned int i=0; i<_nsub; i++ ) 01150 _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._cvsub[i]; 01151 } 01152 else{ 01153 _cv = cv2; 01154 for( unsigned int i=0; i<_nsub; i++ ) 01155 _cvsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i] + Op<T>::l(MC1._I) * MC2._cvsub[i]; 01156 } 01157 01158 double cc1 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::u(MC1._I) * MC2._cc 01159 - Op<T>::u(MC1._I) * Op<T>::l(MC2._I); 01160 double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc 01161 - Op<T>::l(MC1._I) * Op<T>::u(MC2._I); 01162 if ( cc1 < cc2 ){ 01163 _cc = cc1; 01164 for( unsigned int i=0; i<_nsub; i++ ) 01165 _ccsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i] + Op<T>::u(MC1._I) * MC2._ccsub[i]; 01166 } 01167 else{ 01168 _cc = cc2; 01169 for( unsigned int i=0; i<_nsub; i++ ) 01170 _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._ccsub[i]; 01171 } 01172 return *this; 01173 } 01174 01175 template <typename T> inline McCormick<T>& 01176 McCormick<T>::_mul1_u1pos_u2mix 01177 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 01178 { 01179 _I = MC1._I * MC2._I; 01180 01181 double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv 01182 - Op<T>::u(MC1._I) * Op<T>::u(MC2._I); 01183 double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv 01184 - Op<T>::l(MC1._I) * Op<T>::l(MC2._I); 01185 if ( cv1 > cv2 ){ 01186 _cv = cv1; 01187 for( unsigned int i=0; i<_nsub; i++ ) 01188 _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i]; 01189 } 01190 else{ 01191 _cv = cv2; 01192 for( unsigned int i=0; i<_nsub; i++ ) 01193 _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i]; 01194 } 01195 01196 double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc 01197 - Op<T>::u(MC1._I) * Op<T>::l(MC2._I); 01198 double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc 01199 - Op<T>::l(MC1._I) * Op<T>::u(MC2._I); 01200 if ( cc1 < cc2 ){ 01201 _cc = cc1; 01202 for( unsigned int i=0; i<_nsub; i++ ) 01203 _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i]; 01204 } 01205 else{ 01206 _cc = cc2; 01207 for( unsigned int i=0; i<_nsub; i++ ) 01208 _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i]; 01209 } 01210 return *this; 01211 } 01212 01213 template <typename T> inline McCormick<T>& 01214 McCormick<T>::_mul2_u1pos_u2mix 01215 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 01216 { 01217 _I = MC1._I * MC2._I; 01218 01219 double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv 01220 - Op<T>::u(MC1._I) * Op<T>::u(MC2._I); 01221 double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv 01222 - Op<T>::l(MC1._I) * Op<T>::l(MC2._I); 01223 if ( cv1 > cv2 ){ 01224 _cv = cv1; 01225 for( unsigned int i=0; i<_nsub; i++ ) 01226 _cvsub[i] = Op<T>::u(MC1._I) * MC2._cvsub[i]; 01227 } 01228 else{ 01229 _cv = cv2; 01230 for( unsigned int i=0; i<_nsub; i++ ) 01231 _cvsub[i] = Op<T>::l(MC1._I) * MC2._cvsub[i]; 01232 } 01233 01234 double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc 01235 - Op<T>::u(MC1._I) * Op<T>::l(MC2._I); 01236 double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc 01237 - Op<T>::l(MC1._I) * Op<T>::u(MC2._I); 01238 if ( cc1 < cc2 ){ 01239 _cc = cc1; 01240 for( unsigned int i=0; i<_nsub; i++ ) 01241 _ccsub[i] = Op<T>::u(MC1._I) * MC2._ccsub[i]; 01242 } 01243 else{ 01244 _cc = cc2; 01245 for( unsigned int i=0; i<_nsub; i++ ) 01246 _ccsub[i] = Op<T>::l(MC1._I) * MC2._ccsub[i]; 01247 } 01248 return *this; 01249 } 01250 01251 template <typename T> inline McCormick<T>& 01252 McCormick<T>::_mul3_u1pos_u2mix 01253 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 01254 { 01255 _I = MC1._I * MC2._I; 01256 01257 double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv 01258 - Op<T>::u(MC1._I) * Op<T>::u(MC2._I); 01259 double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv 01260 - Op<T>::l(MC1._I) * Op<T>::l(MC2._I); 01261 if ( cv1 > cv2 ){ 01262 _cv = cv1; 01263 for( unsigned int i=0; i<_nsub; i++ ) 01264 _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._cvsub[i]; 01265 } 01266 else{ 01267 _cv = cv2; 01268 for( unsigned int i=0; i<_nsub; i++ ) 01269 _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._cvsub[i]; 01270 } 01271 01272 double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc 01273 - Op<T>::u(MC1._I) * Op<T>::l(MC2._I); 01274 double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc 01275 - Op<T>::l(MC1._I) * Op<T>::u(MC2._I); 01276 if ( cc1 < cc2 ){ 01277 _cc = cc1; 01278 for( unsigned int i=0; i<_nsub; i++ ) 01279 _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._ccsub[i]; 01280 } 01281 else{ 01282 _cc = cc2; 01283 for( unsigned int i=0; i<_nsub; i++ ) 01284 _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._ccsub[i]; 01285 } 01286 return *this; 01287 } 01288 01289 template <typename T> inline McCormick<T>& 01290 McCormick<T>::_mul1_u1mix_u2mix 01291 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 01292 { 01293 _I = MC1._I * MC2._I; 01294 01295 double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv 01296 - Op<T>::u(MC1._I) * Op<T>::u(MC2._I); 01297 double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc 01298 - Op<T>::l(MC1._I) * Op<T>::l(MC2._I); 01299 if ( cv1 > cv2 ){ 01300 _cv = cv1; 01301 for( unsigned int i=0; i<_nsub; i++ ) 01302 _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i]; 01303 } 01304 else{ 01305 _cv = cv2; 01306 for( unsigned int i=0; i<_nsub; i++ ) 01307 _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i]; 01308 } 01309 01310 double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc 01311 - Op<T>::u(MC1._I) * Op<T>::l(MC2._I); 01312 double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv 01313 - Op<T>::l(MC1._I) * Op<T>::u(MC2._I); 01314 if ( cc1 < cc2 ){ 01315 _cc = cc1; 01316 for( unsigned int i=0; i<_nsub; i++ ) 01317 _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i]; 01318 } 01319 else{ 01320 _cc = cc2; 01321 for( unsigned int i=0; i<_nsub; i++ ) 01322 _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i]; 01323 } 01324 return *this; 01325 } 01326 01327 template <typename T> inline McCormick<T>& 01328 McCormick<T>::_mul2_u1mix_u2mix 01329 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 01330 { 01331 _I = MC1._I * MC2._I; 01332 01333 double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv 01334 - Op<T>::u(MC1._I) * Op<T>::u(MC2._I); 01335 double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc 01336 - Op<T>::l(MC1._I) * Op<T>::l(MC2._I); 01337 if ( cv1 > cv2 ){ 01338 _cv = cv1; 01339 for( unsigned int i=0; i<_nsub; i++ ) 01340 _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._cvsub[i]; 01341 } 01342 else{ 01343 _cv = cv2; 01344 for( unsigned int i=0; i<_nsub; i++ ) 01345 _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._ccsub[i]; 01346 } 01347 01348 double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc 01349 - Op<T>::u(MC1._I) * Op<T>::l(MC2._I); 01350 double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv 01351 - Op<T>::l(MC1._I) * Op<T>::u(MC2._I); 01352 if ( cc1 < cc2 ){ 01353 _cc = cc1; 01354 for( unsigned int i=0; i<_nsub; i++ ) 01355 _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._ccsub[i]; 01356 } 01357 else{ 01358 _cc = cc2; 01359 for( unsigned int i=0; i<_nsub; i++ ) 01360 _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._cvsub[i]; 01361 } 01362 return *this; 01363 } 01364 01365 template <typename T> inline McCormick<T>& 01366 McCormick<T>::_mulMV 01367 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 01368 { 01369 // Convex underestimator part 01370 {const double k = - Op<T>::diam(MC2._I) / Op<T>::diam(MC1._I); 01371 const double z = ( Op<T>::u(MC1._I)*Op<T>::u(MC2._I) 01372 - Op<T>::l(MC1._I)*Op<T>::l(MC2._I) ) 01373 / Op<T>::diam(MC1._I); 01374 struct fct{ 01375 static double t1 01376 ( const double x1, const double x2, const McCormick<T>&MC1, 01377 const McCormick<T>&MC2 ) 01378 { return Op<T>::u(MC2._I) * x1 + Op<T>::u(MC1._I) * x2 01379 - Op<T>::u(MC2._I) * Op<T>::u(MC1._I); } 01380 static double t2 01381 ( const double x1, const double x2, const McCormick<T>&MC1, 01382 const McCormick<T>&MC2 ) 01383 { return Op<T>::l(MC2._I) * x1 + Op<T>::l(MC1._I) * x2 01384 - Op<T>::l(MC2._I) * Op<T>::l(MC1._I); } 01385 static double t 01386 ( const double x1, const double x2, const McCormick<T>&MC1, 01387 const McCormick<T>&MC2 ) 01388 { return std::max( t1(x1,x2,MC1,MC2), t2(x1,x2,MC1,MC2) ); } 01389 }; 01390 01391 int imid[4] = { -1, -1, -1, -1 }; 01392 const double x1t[4] = { MC1._cv, MC1._cc, 01393 mid( MC1._cv, MC1._cc, (MC2._cv-z)/k, imid[0] ), 01394 mid( MC1._cv, MC1._cc, (MC2._cc-z)/k, imid[1] ) }; 01395 const double x2t[4] = { mid( MC2._cv, MC2._cc, k*MC1._cv+z, imid[2] ), 01396 mid( MC2._cv, MC2._cc, k*MC1._cc+z, imid[3] ), 01397 MC2._cv, MC2._cc }; 01398 const double v[4] = { fct::t( x1t[0], x2t[0], MC1, MC2 ), fct::t( x1t[1], x2t[1], MC1, MC2 ), 01399 fct::t( x1t[2], x2t[2], MC1, MC2 ), fct::t( x1t[3], x2t[3], MC1, MC2 ) }; 01400 const unsigned int ndx = argmin( 4, v ); 01401 _cv = v[ndx]; 01402 01403 if( _nsub ){ 01404 double myalpha; 01405 if( isequal( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ), 01406 fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ), 01407 options.MVCOMP_TOL, options.MVCOMP_TOL ) ){ 01408 std::pair<double,double> alpha( 0., 1. ); 01409 if( x1t[ndx] > MC1._cv ) 01410 alpha.second = std::min( alpha.second, -Op<T>::l(MC2._I)/Op<T>::diam(MC2._I) ); 01411 if( x1t[ndx] < MC1._cc ) 01412 alpha.first = std::max( alpha.first, -Op<T>::l(MC2._I)/Op<T>::diam(MC2._I) ); 01413 if( x2t[ndx] > MC2._cv ) 01414 alpha.second = std::min( alpha.second, -Op<T>::l(MC1._I)/Op<T>::diam(MC1._I) ); 01415 if( x2t[ndx] < MC2._cc ) 01416 alpha.first = std::max( alpha.first, -Op<T>::l(MC1._I)/Op<T>::diam(MC1._I) ); 01417 if( alpha.first > alpha.second ){ 01418 std::cout << "WARNING: alphaL= " << alpha.first << " alphaU= " << alpha.second 01419 << std::endl; 01420 throw Exceptions( Exceptions::MULTSUB ); 01421 } 01422 myalpha = 0.5*( alpha.first + alpha.second ); 01423 } 01424 else if( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ) > fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ) ) 01425 myalpha = 1.; 01426 else 01427 myalpha = 0.; 01428 double sigma1cv = Op<T>::l(MC2._I) + myalpha * Op<T>::diam(MC2._I), 01429 sigma2cv = Op<T>::l(MC1._I) + myalpha * Op<T>::diam(MC1._I); 01430 for( unsigned int i=0; i<_nsub; i++ ) 01431 _cvsub[i] = ( sigma1cv>=0? MC1._cvsub[i]: MC1._ccsub[i] ) * sigma1cv 01432 + ( sigma2cv>=0? MC2._cvsub[i]: MC2._ccsub[i] ) * sigma2cv; 01433 } 01434 } 01435 01436 // Concave overestimator part 01437 {const double k = Op<T>::diam(MC2._I) / Op<T>::diam(MC1._I); 01438 const double z = ( Op<T>::u(MC1._I)*Op<T>::l(MC2._I) 01439 - Op<T>::l(MC1._I)*Op<T>::u(MC2._I) ) 01440 / Op<T>::diam(MC1._I); 01441 struct fct{ 01442 static double t1 01443 ( const double x1, const double x2, const McCormick<T>&MC1, 01444 const McCormick<T>&MC2 ) 01445 { return Op<T>::l(MC2._I) * x1 + Op<T>::u(MC1._I) * x2 01446 - Op<T>::l(MC2._I) * Op<T>::u(MC1._I); } 01447 static double t2 01448 ( const double x1, const double x2, const McCormick<T>&MC1, 01449 const McCormick<T>&MC2 ) 01450 { return Op<T>::u(MC2._I) * x1 + Op<T>::l(MC1._I) * x2 01451 - Op<T>::u(MC2._I) * Op<T>::l(MC1._I); } 01452 static double t 01453 ( const double x1, const double x2, const McCormick<T>&MC1, 01454 const McCormick<T>&MC2 ) 01455 { return std::min( t1(x1,x2,MC1,MC2), t2(x1,x2,MC1,MC2) ); } 01456 }; 01457 01458 int imid[4] = { -1, -1, -1, -1 }; 01459 const double x1t[4] = { MC1._cv, MC1._cc, 01460 mid( MC1._cv, MC1._cc, (MC2._cv-z)/k, imid[0] ), 01461 mid( MC1._cv, MC1._cc, (MC2._cc-z)/k, imid[1] ) }; 01462 const double x2t[4] = { mid( MC2._cv, MC2._cc, k*MC1._cv+z, imid[2] ), 01463 mid( MC2._cv, MC2._cc, k*MC1._cc+z, imid[3] ), 01464 MC2._cv, MC2._cc }; 01465 const double v[4] = { fct::t( x1t[0], x2t[0], MC1, MC2 ), fct::t( x1t[1], x2t[1], MC1, MC2 ), 01466 fct::t( x1t[2], x2t[2], MC1, MC2 ), fct::t( x1t[3], x2t[3], MC1, MC2 ) }; 01467 const unsigned int ndx = argmax( 4, v ); 01468 _cc = v[ndx]; 01469 01470 if( _nsub ){ 01471 double myalpha; 01472 if( isequal( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ), 01473 fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ), 01474 options.MVCOMP_TOL, options.MVCOMP_TOL ) ){ 01475 std::pair<double,double> alpha( 0., 1. ); 01476 if( x1t[ndx] > MC1._cv ) 01477 alpha.first = std::max( alpha.first, -Op<T>::l(MC2._I)/Op<T>::diam(MC2._I) ); 01478 if( x1t[ndx] < MC1._cc ) 01479 alpha.second = std::min( alpha.second, -Op<T>::l(MC2._I)/Op<T>::diam(MC2._I) ); 01480 if( x2t[ndx] > MC2._cv ) 01481 alpha.second = std::min( alpha.second, Op<T>::u(MC1._I)/Op<T>::diam(MC1._I) ); 01482 if( x2t[ndx] > MC2._cc ) 01483 alpha.first = std::max( alpha.first, Op<T>::u(MC1._I)/Op<T>::diam(MC1._I) ); 01484 if( alpha.first > alpha.second ){ 01485 std::cout << "WARNING: alphaL= " << alpha.first << " alphaU= " << alpha.second 01486 << std::endl; 01487 throw Exceptions( Exceptions::MULTSUB ); 01488 } 01489 myalpha = 0.5*( alpha.first + alpha.second ); //alpha.second 01490 } 01491 else if( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ) < fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ) ) 01492 myalpha = 0.; 01493 else 01494 myalpha = 1.; 01495 double sigma1cc = Op<T>::l(MC2._I) + myalpha * Op<T>::diam(MC2._I), 01496 sigma2cc = Op<T>::u(MC1._I) - myalpha * Op<T>::diam(MC1._I); 01497 for( unsigned int i=0; i<_nsub; i++ ) 01498 _ccsub[i] = ( sigma1cc>=0? MC1._ccsub[i]: MC1._cvsub[i] ) * sigma1cc 01499 + ( sigma2cc>=0? MC2._ccsub[i]: MC2._cvsub[i] ) * sigma2cc; 01500 } 01501 } 01502 01503 return *this; 01504 } 01505 01506 template <typename T> inline McCormick<T>& 01507 McCormick<T>::operator/= 01508 ( const double a ) 01509 { 01510 McCormick<T> MC2 = (*this) / a; 01511 *this = MC2; 01512 return *this; 01513 } 01514 01515 template <typename T> inline McCormick<T>& 01516 McCormick<T>::operator/= 01517 ( const McCormick<T>&MC ) 01518 { 01519 if( _const && !MC._const ) sub( MC._nsub ); 01520 McCormick<T> MC2 = (*this) / MC; 01521 *this = MC2; 01522 return *this; 01523 } 01524 01525 template <typename T> inline double* 01526 McCormick<T>::_erfcv 01527 ( const double x, const double xL, const double xU ) 01528 { 01529 static double cv[2]; 01530 if( xU <= 0. ){ // convex part 01531 cv[0] = ::erf(x), cv[1] = 2./std::sqrt(PI)*std::exp(-sqr(x)); 01532 return cv; 01533 } 01534 01535 if( xL >= 0. ){ // concave part 01536 double r = ( isequal( xL, xU )? 0.:(::erf(xU)-::erf(xL))/(xU-xL) ); 01537 cv[0] = ::erf(xL)+r*(x-xL), cv[1] = r; 01538 return cv; 01539 } 01540 01541 double xj = _newton( xL, xL, 0., _erfenv_func, _erfenv_dfunc, &xU ); 01542 if( x <= xj ){ // convex part 01543 cv[0] = ::erf(x), cv[1] = 2./std::sqrt(PI)*std::exp(-sqr(x)); 01544 return cv; 01545 } 01546 double r = ( isequal( xj, xU )? 0.:(::erf(xU)-::erf(xj))/(xU-xj) ); 01547 cv[0] = ::erf(xU)+r*(x-xU), cv[1] = r; 01548 return cv; 01549 } 01550 01551 template <typename T> inline double* 01552 McCormick<T>::_erfcc 01553 ( const double x, const double xL, const double xU ) 01554 { 01555 static double cc[2]; 01556 if( xU <= 0. ){ // convex part 01557 double r = ( isequal( xL, xU )? 0.:(::erf(xU)-::erf(xL))/(xU-xL) ); 01558 cc[0] = ::erf(xL)+r*(x-xL), cc[1] = r; 01559 return cc; 01560 } 01561 01562 if( xL >= 0. ){ // concave part 01563 cc[0] = ::erf(x), cc[1] = 2./std::sqrt(PI)*std::exp(-sqr(x)); 01564 return cc; 01565 } 01566 01567 double xj = _newton( xU, 0., xU, _erfenv_func, _erfenv_dfunc, &xL ); 01568 if( x >= xj ){ // concave part 01569 cc[0] = ::erf(x), cc[1] = 2./std::sqrt(PI)*std::exp(-sqr(x)); 01570 return cc; 01571 } 01572 double r = ( isequal( xj, xL )? 0.:(::erf(xL)-::erf(xj))/(xL-xj) ); 01573 cc[0] = ::erf(xL)+r*(x-xL), cc[1] = r; 01574 return cc; 01575 } 01576 01577 template <typename T> inline double 01578 McCormick<T>::_erfenv_func 01579 ( const double x, const double*rusr, const int*iusr ) 01580 { 01581 // f(z) = 2/sqrt(pi)*(b-z)*exp(-z^2) + erf(z) - erf(b) = 0 01582 return 2./std::sqrt(PI)*(*rusr-x)*std::exp(-sqr(x)) + ::erf(x) 01583 - ::erf(*rusr); 01584 } 01585 01586 template <typename T> inline double 01587 McCormick<T>::_erfenv_dfunc 01588 ( const double x, const double*rusr, const int*iusr ) 01589 { 01590 // f'(z) = -4/sqrt(pi)*z*(b-z)*exp(-z^2) 01591 return -4./std::sqrt(PI)*x*(*rusr-x)*std::exp(-sqr(x)); 01592 } 01593 01594 template <typename T> inline double* 01595 McCormick<T>::_oddpowcv 01596 ( const double x, const int iexp, const double xL, const double xU ) 01597 { 01598 static double cv[2]; 01599 if( xL >= 0. ){ // convex part 01600 double v = std::pow(x,iexp-1); 01601 cv[0] = x*v, cv[1] = iexp*v; 01602 return cv; 01603 } 01604 01605 if( xU <= 0. ){ // concave part 01606 double r = ( isequal( xL, xU )? 0.: 01607 (std::pow(xU,iexp)-std::pow(xL,iexp))/(xU-xL) ); 01608 cv[0] = std::pow(xL,iexp)+r*(x-xL), cv[1] = r; 01609 return cv; 01610 } 01611 01612 double xj = _newton( xU, 0., xU, _oddpowenv_func, _oddpowenv_dfunc, 01613 &xL, &iexp ); 01614 if( x >= xj ){ // convex part 01615 double v = std::pow(x,iexp-1); 01616 cv[0] = x*v, cv[1] = iexp*v; 01617 return cv; 01618 } 01619 double r = ( isequal( xL, xj )? 0.: 01620 (std::pow(xj,iexp)-std::pow(xL,iexp))/(xj-xL) ); 01621 cv[0] = std::pow(xL,iexp)+r*(x-xL), cv[1] = r; 01622 return cv; 01623 } 01624 01625 template <typename T> inline double* 01626 McCormick<T>::_oddpowcc 01627 ( const double x, const int iexp, const double xL, const double xU ) 01628 { 01629 static double cc[2]; 01630 if( xL >= 0. ){ // convex part 01631 double r = ( isequal( xL, xU )? 0.: 01632 (std::pow(xU,iexp)-std::pow(xL,iexp))/(xU-xL) ); 01633 cc[0] = std::pow(xL,iexp)+r*(x-xL), cc[1] = r; 01634 return cc; 01635 } 01636 if( xU <= 0. ){ // concave part 01637 double v = std::pow(x,iexp-1); 01638 cc[0] = x*v, cc[1] = iexp*v; 01639 return cc; 01640 } 01641 01642 double xj = _newton( xL, xL, 0., _oddpowenv_func, _oddpowenv_dfunc, 01643 &xU, &iexp ); 01644 if( x <= xj ){ // concave part 01645 double v = std::pow(x,iexp-1); 01646 cc[0] = x*v, cc[1] = iexp*v; 01647 return cc; 01648 } 01649 double r = ( isequal( xU, xj )? 0.: 01650 (std::pow(xj,iexp)-std::pow(xU,iexp))/(xj-xU) ); 01651 cc[0] = std::pow(xU,iexp)+r*(x-xU), cc[1] = r; 01652 return cc; 01653 } 01654 01655 template <typename T> inline double 01656 McCormick<T>::_oddpowenv_func 01657 ( const double x, const double*rusr, const int*iusr ) 01658 { 01659 // f(z) = (p-1)*z^p - a*p*z^{p-1} + a^p = 0 01660 return ((*iusr-1)*x-(*rusr)*(*iusr))*std::pow(x,*iusr-1) 01661 + std::pow(*rusr,*iusr); 01662 } 01663 01664 template <typename T> inline double 01665 McCormick<T>::_oddpowenv_dfunc 01666 ( const double x, const double*rusr, const int*iusr ) 01667 { 01668 // f'(z) = p*(p-1)*z^{p-1} - a*p*(p-1)*z^{p-2} 01669 return ((*iusr)*(*iusr-1)*x-(*rusr)*(*iusr)*(*iusr-1))*std::pow(x,*iusr-2); 01670 } 01671 01672 template <typename T> inline double* 01673 McCormick<T>::_stepcv 01674 ( const double x, const double xL, const double xU ) 01675 { 01676 static double cv[2]; 01677 01678 if( x < 0. ){ 01679 cv[0] = cv[1] = 0.; 01680 return cv; 01681 } 01682 01683 if( xL >= 0. ){ 01684 cv[0] = 1., cv[1] = 0.; 01685 return cv; 01686 } 01687 01688 cv[0] = x/xU, cv[1] = 1./xU; 01689 return cv; 01690 } 01691 01692 template <typename T> inline double* 01693 McCormick<T>::_stepcc 01694 ( const double x, const double xL, const double xU ) 01695 { 01696 static double cc[2]; 01697 01698 if( x >= 0. ){ 01699 cc[0] = 1., cc[1] = 0.; 01700 return cc; 01701 } 01702 01703 else if( xU < 0. ){ 01704 cc[0] = 0., cc[1] = 0.; 01705 return cc; 01706 } 01707 01708 cc[0] = 1.-x/xL, cc[1] = -1./xL; 01709 return cc; 01710 } 01711 01712 template <typename T> inline double* 01713 McCormick<T>::_cosarg 01714 ( const double xL, const double xU ) 01715 { 01716 static double arg[2]; 01717 const int kL = std::ceil(-(1.+xL/PI)/2.); 01718 const double xL1 = xL+2.*PI*kL, xU1 = xU+2.*PI*kL; 01719 assert( xL1 >= -PI && xL1 <= PI ); 01720 if( xL1 <= 0 ){ 01721 if( xU1 <= 0 ) arg[0] = xL, arg[1] = xU; 01722 else if( xU1 >= PI ) arg[0] = PI*(1.-2.*kL), arg[1] = -PI*2.*kL; 01723 else arg[0] = std::cos(xL1)<=std::cos(xU1)?xL:xU, arg[1] = -PI*2.*kL; 01724 return arg; 01725 } 01726 if( xU1 <= PI ) arg[0] = xU, arg[1] = xL; 01727 else if( xU1 >= 2.*PI ) arg[0] = PI*(1-2.*kL), arg[1] = 2.*PI*(1.-kL); 01728 else arg[0] = PI*(1.-2.*kL), arg[1] = std::cos(xL1)>=std::cos(xU1)?xL:xU; 01729 return arg; 01730 } 01731 01732 template <typename T> inline double* 01733 McCormick<T>::_coscv 01734 ( const double x, const double xL, const double xU ) 01735 { 01736 static double cv[2]; 01737 const int kL = std::ceil(-(1.+xL/PI)/2.); 01738 if( x <= PI*(1-2*kL) ){ 01739 const double xL1 = xL+2.*PI*kL; 01740 if( xL1 >= 0.5*PI ){ 01741 cv[0] = std::cos(x), cv[1] = -std::sin(x); 01742 return cv; 01743 } 01744 const double xU1 = std::min(xU+2.*PI*kL,PI); 01745 if( xL1 >= -0.5*PI && xU1 <= 0.5*PI ){ 01746 double r = ( isequal( xL, xU )? 0.: (std::cos(xU)-std::cos(xL))/(xU-xL) ); 01747 cv[0] = std::cos(xL)+r*(x-xL), cv[1] = r; 01748 return cv; 01749 } 01750 return _coscv2( x+2.*PI*kL, xL1, xU1 ); 01751 } 01752 01753 const int kU = std::floor((1.-xU/PI)/2.); 01754 if( x >= PI*(-1-2*kU) ){ 01755 const double xU2 = xU+2.*PI*kU; 01756 if( xU2 <= -0.5*PI ){ 01757 cv[0] = std::cos(x), cv[1] = -std::sin(x); 01758 return cv; 01759 } 01760 return _coscv2( x+2.*PI*kU, std::max(xL+2.*PI*kU,-PI), xU2 ); 01761 } 01762 01763 cv[0] = -1., cv[1] = 0.; 01764 return cv; 01765 } 01766 01767 template <typename T> inline double* 01768 McCormick<T>::_coscv2 01769 ( const double x, const double xL, const double xU ) 01770 { 01771 bool left; 01772 double x0, xm; 01773 if( std::fabs(xL)<=std::fabs(xU) ) 01774 left = false, x0 = xU, xm = xL; 01775 else 01776 left = true, x0 = xL, xm = xU; 01777 double xj = _newton( x0, xL, xU, _cosenv_func, _cosenv_dfunc, &xm, 0 ); 01778 01779 static double cv[2]; 01780 if(( left && x<=xj ) || ( !left && x>=xj )){ 01781 cv[0] = std::cos(x), cv[1] = -std::sin(x); 01782 return cv; 01783 } 01784 double r = ( isequal( xm, xj )? 0.: (std::cos(xm)-std::cos(xj))/(xm-xj) ); 01785 cv[0] = std::cos(xm)+r*(x-xm), cv[1] = r; 01786 return cv; 01787 } 01788 01789 template <typename T> inline double* 01790 McCormick<T>::_coscc 01791 ( const double x, const double xL, const double xU ) 01792 { 01793 static double cc[2]; 01794 const double*cvenv = _coscv( x-PI, xL-PI, xU-PI ); 01795 cc[0] = -cvenv[0], cc[1] = -cvenv[1]; 01796 return cc; 01797 } 01798 01799 template <typename T> inline double 01800 McCormick<T>::_cosenv_func 01801 ( const double x, const double*rusr, const int*iusr ) 01802 01803 { 01804 // f(z) = (z-a)*sin(z)+cos(z)-cos(a) = 0 01805 return ((x-*rusr)*std::sin(x)+std::cos(x)-std::cos(*rusr)); 01806 } 01807 01808 template <typename T> inline double 01809 McCormick<T>::_cosenv_dfunc 01810 ( const double x, const double*rusr, const int*iusr ) 01811 { 01812 // f'(z) = (z-a)*cos(z) 01813 return ((x-*rusr)*std::cos(x)); 01814 } 01815 01816 template <typename T> inline double* 01817 McCormick<T>::_asincv 01818 ( const double x, const double xL, const double xU ) 01819 { 01820 static double cv[2]; 01821 if( xL >= 0. ){ // convex part 01822 cv[0] = std::asin(x), cv[1] = 1./std::sqrt(1-x*x); 01823 return cv; 01824 } 01825 if( xU <= 0. ){ // concave part 01826 double r = ( isequal( xL, xU )? 0.: (std::asin(xU)-std::asin(xL))/(xU-xL)); 01827 cv[0] = std::asin(xL)+r*(x-xL), cv[1] = r; 01828 return cv; 01829 } 01830 double xj = _secant( 0., xU, 0., xU, _asinenv_func, &xL, 0 ); 01831 //double xj = _newton( xU, 0., xU, _asinenv_func, _asinenv_dfunc, &xL, 0 ); 01832 if( x >= xj ){ // convex part 01833 cv[0] = std::asin(x), cv[1] = 1./std::sqrt(1-x*x); 01834 return cv; 01835 } 01836 double r = ( isequal( xL, xj )? 0.: (std::asin(xj)-std::asin(xL))/(xj-xL)); 01837 cv[0] = std::asin(xL)+r*(x-xL), cv[1] = r; // linear part 01838 return cv; 01839 } 01840 01841 template <typename T> inline double* 01842 McCormick<T>::_asincc 01843 ( const double x, const double xL, const double xU ) 01844 { 01845 static double cc[2]; 01846 if( xL >= 0. ){ // convex part 01847 double r = ( isequal( xL, xU )? 0.: (std::asin(xU)-std::asin(xL))/(xU-xL)); 01848 cc[0] = std::asin(xL)+r*(x-xL), cc[1] = r; 01849 return cc; 01850 } 01851 if( xU <= 0. ){ // concave part 01852 cc[0] = std::asin(x), cc[1] = 1./std::sqrt(1-x*x); 01853 return cc; 01854 } 01855 double xj = _secant( 0., xL, xL, 0., _asinenv_func, &xU, 0 ); 01856 //double xj = _newton( xL, xL, 0., _asinenv_func, _asinenv_dfunc, &xU, 0 ); 01857 if( x <= xj ){ // concave part 01858 cc[0] = std::asin(x), cc[1] = 1./std::sqrt(1-x*x); 01859 return cc; 01860 } 01861 double r = ( isequal( xU, xj )? 0.: (std::asin(xj)-std::asin(xU))/(xj-xU)); 01862 cc[0] = std::asin(xU)+r*(x-xU), cc[1] = r; // linear part 01863 return cc; 01864 } 01865 01866 template <typename T> inline double 01867 McCormick<T>::_asinenv_func 01868 ( const double x, const double*rusr, const int*iusr ) 01869 { 01870 // f(z) = z-a-sqrt(1-z^2)*(asin(z)-asin(a)) = 0 01871 return x-(*rusr)-std::sqrt(1.-x*x)*(std::asin(x)-std::asin(*rusr)); 01872 } 01873 01874 template <typename T> inline double 01875 McCormick<T>::_asinenv_dfunc 01876 ( const double x, const double*rusr, const int*iusr ) 01877 { 01878 // f'(z) = z/sqrt(1-z^2)*(asin(z)-asin(a)) 01879 return x/std::sqrt(1.-x*x)*(std::asin(x)-std::asin(*rusr)); 01880 } 01881 01882 template <typename T> inline double 01883 McCormick<T>::_newton 01884 ( const double x0, const double xL, const double xU, const puniv f, 01885 const puniv df, const double*rusr, const int*iusr ) 01886 { 01887 double xk = std::max(xL,std::min(xU,x0)); 01888 double fk = f(xk,rusr,iusr); 01889 01890 for( unsigned int it=0; it<options.NEWTON_MAXIT; it++ ){ 01891 if( std::fabs(fk) < options.NEWTON_TOL ) return xk; 01892 double dfk = df(xk,rusr,iusr); 01893 if( dfk == 0 ) throw Exceptions( Exceptions::NEWTON ); 01894 if( isequal(xk,xL) && fk/dfk>0 ) return xk; 01895 if( isequal(xk,xU) && fk/dfk<0 ) return xk; 01896 xk = std::max(xL,std::min(xU,xk-fk/dfk)); 01897 fk = f(xk,rusr,iusr); 01898 } 01899 01900 throw Exceptions( Exceptions::NEWTON ); 01901 } 01902 01903 template <typename T> inline double 01904 McCormick<T>::_secant 01905 ( const double x0, const double x1, const double xL, const double xU, 01906 const puniv f, const double*rusr, const int*iusr ) 01907 { 01908 double xkm = std::max(xL,std::min(xU,x0)); 01909 double fkm = f(xkm,rusr,iusr); 01910 double xk = std::max(xL,std::min(xU,x1)); 01911 01912 for( unsigned int it=0; it<options.NEWTON_MAXIT; it++ ){ 01913 double fk = f(xk,rusr,iusr); 01914 if( std::fabs(fk) < options.NEWTON_TOL ) return xk; 01915 double Bk = (fk-fkm)/(xk-xkm); 01916 if( Bk == 0 ) throw Exceptions( Exceptions::NEWTON ); 01917 if( isequal(xk,xL) && fk/Bk>0 ) return xk; 01918 if( isequal(xk,xU) && fk/Bk<0 ) return xk; 01919 xkm = xk; 01920 fkm = fk; 01921 xk = std::max(xL,std::min(xU,xk-fk/Bk)); 01922 } 01923 01924 throw Exceptions( Exceptions::NEWTON ); 01925 } 01926 01928 01929 template <typename T> inline McCormick<T> 01930 cut 01931 ( const McCormick<T>&MC ) 01932 { 01933 McCormick<T> MC2( MC ); 01934 return MC2.cut(); 01935 } 01936 01937 template <typename T> inline McCormick<T> 01938 operator+ 01939 ( const McCormick<T>&MC ) 01940 { 01941 McCormick<T> MC2( MC ); 01942 return MC2; 01943 } 01944 01945 template <typename T> inline McCormick<T> 01946 operator+ 01947 ( const double a, const McCormick<T>&MC ) 01948 { 01949 McCormick<T> MC2; 01950 MC2._sub( MC._nsub, MC._const ); 01951 MC2._I = a + MC._I; 01952 MC2._cv = a + MC._cv; 01953 MC2._cc = a + MC._cc; 01954 for( unsigned int i=0; i<MC2._nsub; i++ ){ 01955 MC2._cvsub[i] = MC._cvsub[i]; 01956 MC2._ccsub[i] = MC._ccsub[i]; 01957 } 01958 return MC2; 01959 } 01960 01961 template <typename T> inline McCormick<T> 01962 operator+ 01963 ( const McCormick<T>&MC, const double a ) 01964 { 01965 return a + MC; 01966 } 01967 01968 template <typename T> inline McCormick<T> 01969 operator+ 01970 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 01971 { 01972 if( MC2._const ){ 01973 McCormick<T> MC3; 01974 MC3._sub( MC1._nsub, MC1._const ); 01975 return MC3._sum1( MC1, MC2 ); 01976 } 01977 if( MC1._const ){ 01978 McCormick<T> MC3; 01979 MC3._sub( MC2._nsub, MC2._const ); 01980 return MC3._sum1( MC2, MC1 ); 01981 } 01982 if( MC1._nsub != MC2._nsub ) 01983 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB ); 01984 McCormick<T> MC3; 01985 MC3._sub( MC1._nsub, MC1._const||MC2._const ); 01986 return MC3._sum2( MC1, MC2 ); 01987 } 01988 01989 template <typename T> inline McCormick<T> 01990 operator- 01991 ( const McCormick<T>&MC ) 01992 { 01993 McCormick<T> MC2; 01994 MC2._sub( MC._nsub, MC._const ); 01995 MC2._I = -MC._I; 01996 MC2._cv = -MC._cc; 01997 MC2._cc = -MC._cv; 01998 for( unsigned int i=0; i<MC2._nsub; i++ ){ 01999 MC2._cvsub[i] = -MC._ccsub[i]; 02000 MC2._ccsub[i] = -MC._cvsub[i]; 02001 } 02002 return MC2; 02003 } 02004 02005 template <typename T> inline McCormick<T> 02006 operator- 02007 ( const McCormick<T>&MC, const double a ) 02008 { 02009 return MC + (-a); 02010 } 02011 02012 template <typename T> inline McCormick<T> 02013 operator- 02014 ( const double a, const McCormick<T>&MC ) 02015 { 02016 McCormick<T> MC2; 02017 MC2._sub( MC._nsub, MC._const ); 02018 MC2._I = a - MC._I; 02019 MC2._cv = a - MC._cc; 02020 MC2._cc = a - MC._cv; 02021 for( unsigned int i=0; i<MC2._nsub; i++ ){ 02022 MC2._cvsub[i] = -MC._ccsub[i]; 02023 MC2._ccsub[i] = -MC._cvsub[i]; 02024 } 02025 return MC2; 02026 } 02027 02028 template <typename T> inline McCormick<T> 02029 operator- 02030 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 02031 { 02032 if( &MC1 == &MC2 ) return 0; 02033 02034 if( MC2._const ){ 02035 McCormick<T> MC3; 02036 MC3._sub( MC1._nsub, MC1._const ); 02037 return MC3._sub1( MC1, MC2 ); 02038 } 02039 if( MC1._const ){ 02040 McCormick<T> MC3; 02041 MC3._sub( MC2._nsub, MC2._const ); 02042 return MC3._sub2( MC1, MC2 ); 02043 } 02044 if( MC1._nsub != MC2._nsub ) 02045 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB ); 02046 McCormick<T> MC3; 02047 MC3._sub( MC1._nsub, MC1._const||MC2._const ); 02048 return MC3._sub3( MC1, MC2 ); 02049 } 02050 02051 template <typename T> inline McCormick<T> 02052 operator* 02053 ( const double a, const McCormick<T>&MC ) 02054 { 02055 McCormick<T> MC2; 02056 MC2._sub( MC._nsub, MC._const ); 02057 MC2._I = a * MC._I; 02058 if ( a >= 0 ){ 02059 MC2._cv = a * MC._cv; 02060 MC2._cc = a * MC._cc; 02061 for( unsigned int i=0; i<MC2._nsub; i++ ){ 02062 MC2._cvsub[i] = a * MC._cvsub[i]; 02063 MC2._ccsub[i] = a * MC._ccsub[i]; 02064 } 02065 } 02066 else{ 02067 MC2._cv = a * MC._cc; 02068 MC2._cc = a * MC._cv; 02069 for( unsigned int i=0; i<MC2._nsub; i++ ){ 02070 MC2._cvsub[i] = a * MC._ccsub[i]; 02071 MC2._ccsub[i] = a * MC._cvsub[i]; 02072 } 02073 } 02074 return MC2; 02075 } 02076 02077 template <typename T> inline McCormick<T> 02078 operator* 02079 ( const McCormick<T>&MC, const double a ) 02080 { 02081 return a * MC; 02082 } 02083 02084 template <typename T> inline McCormick<T> 02085 operator* 02086 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 02087 { 02088 if( &MC1 == &MC2 ) return sqr(MC1); 02089 02090 bool thin1 = isequal( Op<T>::diam(MC1._I), 0. ); 02091 bool thin2 = isequal( Op<T>::diam(MC2._I), 0. ); 02092 02093 if ( McCormick<T>::options.MVCOMP_USE && !(thin1||thin2) ){ 02094 McCormick<T> MC3; 02095 if( MC2._const ) 02096 MC3._sub( MC1._nsub, MC1._const ); 02097 else if( MC1._const ) 02098 MC3._sub( MC2._nsub, MC2._const ); 02099 else if( MC1._nsub != MC2._nsub ) 02100 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB ); 02101 else 02102 MC3._sub( MC1._nsub, MC1._const||MC2._const ); 02103 02104 MC3._I = MC1._I * MC2._I; 02105 return MC3._mulMV( MC1, MC2 ).cut(); 02106 //return thin1? MC3._mulMV( MC2, MC1 ).cut(): MC3._mulMV( MC1, MC2 ).cut(); 02107 } 02108 02109 if ( Op<T>::l(MC1._I) >= 0. ){ 02110 if ( Op<T>::l(MC2._I) >= 0. ){ 02111 if( MC2._const ){ 02112 McCormick<T> MC3; 02113 MC3._sub( MC1._nsub, MC1._const ); 02114 return MC3._mul1_u1pos_u2pos( MC1, MC2 ).cut(); 02115 } 02116 if( MC1._const ){ 02117 McCormick<T> MC3; 02118 MC3._sub( MC2._nsub, MC2._const ); 02119 return MC3._mul1_u1pos_u2pos( MC2, MC1 ).cut(); 02120 } 02121 if( MC1._nsub != MC2._nsub ) 02122 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB ); 02123 McCormick<T> MC3; 02124 MC3._sub( MC1._nsub, MC1._const||MC2._const ); 02125 return MC3._mul2_u1pos_u2pos( MC1, MC2 ).cut(); 02126 } 02127 if ( Op<T>::u(MC2._I) <= 0. ){ 02128 return -( MC1 * (-MC2) ); 02129 } 02130 if( MC2._const ){ 02131 McCormick<T> MC3; 02132 MC3._sub( MC1._nsub, MC1._const ); 02133 return MC3._mul1_u1pos_u2mix( MC1, MC2 ).cut(); 02134 } 02135 if( MC1._const ){ 02136 McCormick<T> MC3; 02137 MC3._sub( MC2._nsub, MC2._const ); 02138 return MC3._mul2_u1pos_u2mix( MC1, MC2 ).cut(); 02139 } 02140 if( MC1._nsub != MC2._nsub ) 02141 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB ); 02142 McCormick<T> MC3; 02143 MC3._sub( MC1._nsub, MC1._const||MC2._const ); 02144 return MC3._mul3_u1pos_u2mix( MC1, MC2 ).cut(); 02145 } 02146 02147 if ( Op<T>::u(MC1._I) <= 0. ){ 02148 if ( Op<T>::l(MC2._I) >= 0. ){ 02149 return -( (-MC1) * MC2); 02150 } 02151 if ( Op<T>::u(MC2._I) <= 0. ){ 02152 return (-MC1) * (-MC2); 02153 } 02154 return -( MC2 * (-MC1) ); 02155 } 02156 02157 if ( Op<T>::l(MC2._I) >= 0. ){ 02158 return MC2 * MC1; 02159 } 02160 if ( Op<T>::u(MC2._I) <= 0. ){ 02161 return -( (-MC2) * MC1 ); 02162 } 02163 if( MC2._const ){ 02164 McCormick<T> MC3; 02165 MC3._sub( MC1._nsub, MC1._const ); 02166 return MC3._mul1_u1mix_u2mix( MC1, MC2 ).cut(); 02167 } 02168 if( MC1._const ){ 02169 McCormick<T> MC3; 02170 MC3._sub( MC2._nsub, MC2._const ); 02171 return MC3._mul1_u1mix_u2mix( MC2, MC1 ).cut(); 02172 } 02173 if( MC1._nsub != MC2._nsub ) 02174 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB ); 02175 McCormick<T> MC3; 02176 MC3._sub( MC1._nsub, MC1._const||MC2._const ); 02177 return MC3._mul2_u1mix_u2mix( MC1, MC2 ).cut(); 02178 } 02179 02180 template <typename T> inline McCormick<T> 02181 operator/ 02182 ( const McCormick<T>&MC, const double a ) 02183 { 02184 if ( isequal( a, 0. )) 02185 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::DIV ); 02186 return (1./a) * MC; 02187 } 02188 02189 template <typename T> inline McCormick<T> 02190 operator/ 02191 ( const double a, const McCormick<T>&MC ) 02192 { 02193 return a * inv( MC ); 02194 } 02195 02196 template <typename T> inline McCormick<T> 02197 operator/ 02198 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 02199 { 02200 if( &MC1 == &MC2 ) return 1.; 02201 02202 bool posorthant = ( Op<T>::l(MC1._I) >= 0. && Op<T>::l(MC2._I) > 0. ); 02203 02204 if ( McCormick<T>::options.MVCOMP_USE && posorthant){ 02205 McCormick<T> MC3; 02206 if( MC2._const ) 02207 MC3._sub( MC1._nsub, MC1._const ); 02208 else if( MC1._const ) 02209 MC3._sub( MC2._nsub, MC2._const ); 02210 else if( MC1._nsub != MC2._nsub ) 02211 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB ); 02212 else 02213 MC3._sub( MC1._nsub, MC1._const||MC2._const ); 02214 02215 MC3._I = MC1._I / MC2._I; 02216 02217 int imidcv1 = -1, imidcv2 = -1; 02218 double fmidcv1 = ( mid(MC1._cv, MC1._cc, Op<T>::l(MC1._I), imidcv1) 02219 + std::sqrt(Op<T>::l(MC1._I) * Op<T>::u(MC1._I)) ) 02220 / ( std::sqrt(Op<T>::l(MC1._I)) + std::sqrt(Op<T>::u(MC1._I)) ); 02221 double fmidcv2 = mid(MC2._cv, MC2._cc, Op<T>::u(MC2._I), imidcv2); 02222 MC3._cv = sqr(fmidcv1) / fmidcv2; 02223 for( unsigned int i=0; i<MC3._nsub; i++ ) 02224 MC3._cvsub[i] = 2. * fmidcv1 / fmidcv2 02225 / ( std::sqrt(Op<T>::l(MC1._I)) + std::sqrt(Op<T>::u(MC1._I)) ) 02226 * (MC1._const? 0.: mid( MC1._cvsub, MC1._ccsub, i, imidcv1 )) 02227 - sqr( fmidcv1 / fmidcv2 ) 02228 * (MC2._const? 0.: mid( MC2._cvsub, MC2._ccsub, i, imidcv2 )); 02229 02230 int imidcc1 = -1, imidcc2 = -1; 02231 double fmidcc1 = mid(MC1._cv, MC1._cc, Op<T>::l(MC1._I), imidcc1); 02232 double fmidcc2 = mid(MC2._cv, MC2._cc, Op<T>::u(MC2._I), imidcc2); 02233 double gcc1 = Op<T>::u(MC2._I) * fmidcc1 - Op<T>::l(MC1._I) * fmidcc2 02234 + Op<T>::l(MC1._I) * Op<T>::l(MC2._I); 02235 double gcc2 = Op<T>::l(MC2._I) * fmidcc1 - Op<T>::u(MC1._I) * fmidcc2 02236 + Op<T>::u(MC1._I) * Op<T>::u(MC2._I); 02237 if( gcc1 <= gcc2 ){ 02238 MC3._cc = gcc1 / ( Op<T>::l(MC2._I) * Op<T>::u(MC2._I) ); 02239 for( unsigned int i=0; i<MC3._nsub; i++ ) 02240 MC3._ccsub[i] = 1. / Op<T>::l(MC2._I) 02241 * (MC1._const? 0.: mid( MC1._cvsub, MC1._ccsub, i, imidcc1 )) 02242 - Op<T>::l(MC1._I) / ( Op<T>::l(MC2._I) * Op<T>::u(MC2._I) ) 02243 * (MC2._const? 0.: mid( MC2._cvsub, MC2._ccsub, i, imidcc2 )); 02244 } 02245 else{ 02246 MC3._cc = gcc2 / ( Op<T>::l(MC2._I) * Op<T>::u(MC2._I) ); 02247 for( unsigned int i=0; i<MC3._nsub; i++ ) 02248 MC3._ccsub[i] = 1. / Op<T>::u(MC2._I) 02249 * (MC1._const? 0.: mid( MC1._cvsub, MC1._ccsub, i, imidcc1 )) 02250 - Op<T>::u(MC1._I) / ( Op<T>::l(MC2._I) * Op<T>::u(MC2._I) ) 02251 * (MC2._const? 0.: mid( MC2._cvsub, MC2._ccsub, i, imidcc2 )); 02252 } 02253 return MC3.cut(); 02254 } 02255 02256 return MC1 * inv( MC2 ); 02257 } 02258 02259 template <typename T> inline McCormick<T> 02260 inv 02261 ( const McCormick<T>&MC ) 02262 { 02263 if ( Op<T>::l(MC._I) <= 0. && Op<T>::u(MC._I) >= 0. ) 02264 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::INV ); 02265 McCormick<T> MC2; 02266 MC2._sub( MC._nsub, MC._const ); 02267 MC2._I = Op<T>::inv( MC._I ); 02268 02269 if ( Op<T>::l(MC._I) > 0. ){ 02270 { int imid = -1; 02271 double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid ); 02272 MC2._cv = 1./vmid; 02273 for( unsigned int i=0; i<MC2._nsub; i++ ) 02274 MC2._cvsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid ) 02275 / ( vmid * vmid ); 02276 } 02277 { int imid = -1; 02278 MC2._cc = 1. / Op<T>::l(MC._I) + 1. / Op<T>::u(MC._I) - mid( MC._cv, MC._cc, 02279 Op<T>::l(MC._I), imid ) / ( Op<T>::l(MC._I) * Op<T>::u(MC._I) ); 02280 for( unsigned int i=0; i<MC2._nsub; i++ ) 02281 MC2._ccsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid ) 02282 / ( Op<T>::l(MC._I) * Op<T>::u(MC._I) ); 02283 } 02284 } 02285 02286 else{ 02287 { int imid = -1; 02288 MC2._cv = 1. / Op<T>::l(MC._I) + 1. / Op<T>::u(MC._I) - mid( MC._cv, MC._cc, 02289 Op<T>::u(MC._I), imid ) / ( Op<T>::l(MC._I) * Op<T>::u(MC._I) ); 02290 for( unsigned int i=0; i<MC2._nsub; i++ ) 02291 MC2._cvsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid ) 02292 / ( Op<T>::l(MC._I) * Op<T>::u(MC._I) ); 02293 } 02294 { int imid = -1; 02295 double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid); 02296 MC2._cc = 1. / vmid; 02297 for( unsigned int i=0; i<MC2._nsub; i++ ) 02298 MC2._ccsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid ) 02299 / ( vmid * vmid ); 02300 } 02301 } 02302 02303 return MC2.cut(); 02304 } 02305 02306 template <typename T> inline McCormick<T> 02307 sqr 02308 ( const McCormick<T>&MC ) 02309 { 02310 McCormick<T> MC2; 02311 MC2._sub( MC._nsub, MC._const ); 02312 MC2._I = Op<T>::sqr( MC._I ); 02313 { int imid = -1; 02314 double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), 0., imid ); 02315 imid = -1; 02316 MC2._cv = mc::sqr( mid( MC._cv, MC._cc, zmin, imid ) ); 02317 for( unsigned int i=0; i<MC2._nsub; i++ ) 02318 MC2._cvsub[i] = 2 * mid( MC._cvsub, MC._ccsub, i, imid ) 02319 * mid( MC._cv, MC._cc, zmin, imid ); 02320 } 02321 02322 { int imid = -1; 02323 double zmax = (mc::sqr( Op<T>::l(MC._I) )>mc::sqr( Op<T>::u(MC._I) )? 02324 Op<T>::l(MC._I): Op<T>::u(MC._I)); 02325 double r = ( isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )? 0.: 02326 ( mc::sqr( Op<T>::u(MC._I) ) - mc::sqr( Op<T>::l(MC._I) ) ) 02327 / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ) ); 02328 MC2._cc = mc::sqr( Op<T>::l(MC._I) ) + r * ( mid( MC._cv, MC._cc, zmax, 02329 imid ) - Op<T>::l(MC._I) ); 02330 for( unsigned int i=0; i<MC2._nsub; i++ ) 02331 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r; 02332 } 02333 02334 return MC2.cut(); 02335 } 02336 02337 template <typename T> inline McCormick<T> 02338 exp 02339 ( const McCormick<T>&MC ) 02340 { 02341 McCormick<T> MC2; 02342 MC2._sub( MC._nsub, MC._const ); 02343 MC2._I = Op<T>::exp( MC._I ); 02344 02345 { int imid = -1; 02346 MC2._cv = std::exp( mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid )); 02347 for( unsigned int i=0; i<MC2._nsub; i++ ) 02348 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * MC2._cv; 02349 } 02350 02351 { int imid = -1; 02352 double r = 0.; 02353 if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )) 02354 r = ( std::exp( Op<T>::u(MC._I) ) - std::exp( Op<T>::l(MC._I) ) ) 02355 / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ); 02356 MC2._cc = std::exp( Op<T>::u(MC._I) ) + r * ( mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid ) 02357 - Op<T>::u(MC._I) ); 02358 for( unsigned int i=0; i<MC2._nsub; i++ ) 02359 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r; 02360 } 02361 02362 return MC2.cut(); 02363 } 02364 02365 template <typename T> inline McCormick<T> 02366 arh 02367 ( const McCormick<T>&MC, const double k ) 02368 { 02369 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 ) ){ 02370 return exp( - k * inv( MC ) ); 02371 } 02372 02373 McCormick<T> MC2; 02374 MC2._sub( MC._nsub, MC._const ); 02375 MC2._I = Op<T>::arh( MC._I, k ); 02376 02377 if ( Op<T>::u(MC._I) <= 0.5*k ){ 02378 { int imid = -1; 02379 double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid ); 02380 MC2._cv = std::exp( - k / vmid ); 02381 for( unsigned int i=0; i<MC2._nsub; i++ ) 02382 MC2._cvsub[i] = k / ( vmid * vmid ) * MC2._cv 02383 * mid( MC._cvsub, MC._ccsub, i, imid ); 02384 } 02385 { int imid = -1; 02386 double r = 0.; 02387 if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )) 02388 r = ( mc::arh( Op<T>::u(MC._I) ) - mc::arh( Op<T>::l(MC._I) ) ) 02389 / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ); 02390 MC2._cc = mc::arh( Op<T>::l(MC._I) ) + r * ( mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid ) 02391 - Op<T>::l(MC._I) ); 02392 for( unsigned int i=0; i<MC2._nsub; i++ ) 02393 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r; 02394 } 02395 return MC2.cut(); 02396 } 02397 02398 else if ( Op<T>::l(MC._I) >= 0.5*k ){ 02399 { int imid = -1; 02400 double r = 0.; 02401 if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )) 02402 r = ( mc::arh( Op<T>::u(MC._I) ) - mc::arh( Op<T>::l(MC._I) ) ) 02403 / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ); 02404 MC2._cv = mc::arh( Op<T>::l(MC._I) ) + r * ( mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid ) 02405 - Op<T>::l(MC._I) ); 02406 for( unsigned int i=0; i<MC2._nsub; i++ ) 02407 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r; 02408 } 02409 { int imid = -1; 02410 double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid ); 02411 MC2._cc = std::exp( - k / vmid ); 02412 for( unsigned int i=0; i<MC2._nsub; i++ ) 02413 MC2._ccsub[i] = k / ( vmid * vmid ) * MC2._cc 02414 * mid( MC._cvsub, MC._ccsub, i, imid ); 02415 } 02416 return MC2.cut(); 02417 } 02418 } 02419 02420 template <typename T> inline McCormick<T> 02421 log 02422 ( const McCormick<T>&MC ) 02423 { 02424 if ( Op<T>::l(MC._I) <= 0. ) 02425 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::LOG ); 02426 McCormick<T> MC2; 02427 MC2._sub( MC._nsub, MC._const ); 02428 MC2._I = Op<T>::log( MC._I ); 02429 02430 { int imid = -1; 02431 double scal = 0.; 02432 if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )) 02433 scal = ( std::log( Op<T>::u(MC._I) ) - std::log( Op<T>::l(MC._I) ) ) 02434 / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ); 02435 MC2._cv = std::log( Op<T>::l(MC._I) ) + scal * ( mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid ) 02436 - Op<T>::l(MC._I) ); 02437 for( unsigned int i=0; i<MC2._nsub; i++ ) 02438 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * scal; 02439 } 02440 02441 { int imid = -1; 02442 double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid ); 02443 MC2._cc = std::log( vmid ); 02444 for( unsigned int i=0; i<MC2._nsub; i++ ) 02445 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) / vmid; 02446 } 02447 02448 return MC2.cut(); 02449 } 02450 02451 template <typename T> inline McCormick<T> 02452 xlog 02453 ( const McCormick<T>&MC ) 02454 { 02455 if ( Op<T>::l(MC._I) <= 0. ) 02456 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::LOG ); 02457 McCormick<T> MC2; 02458 MC2._sub( MC._nsub, MC._const ); 02459 MC2._I = Op<T>::xlog( MC._I ); 02460 02461 { int imid = -1; 02462 double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), std::exp(-1.), imid ); 02463 imid = -1; 02464 double vmid = mid( MC._cv, MC._cc, zmin, imid ); 02465 MC2._cv = xlog( vmid ); 02466 for( unsigned int i=0; i<MC2._nsub; i++ ) 02467 MC2._cvsub[i] = (std::log( vmid ) + 1.) * mid( MC._cvsub, MC._ccsub, 02468 i, imid ); 02469 } 02470 02471 { int imid = -1; 02472 double zmax = ( xlog(Op<T>::u(MC._I))>=xlog(Op<T>::l(MC._I))? Op<T>::u(MC._I): Op<T>::l(MC._I) ); 02473 double r = 0.; 02474 if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )) 02475 r = ( xlog(Op<T>::u(MC._I)) - xlog(Op<T>::l(MC._I)) ) 02476 / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ); 02477 imid = -1; 02478 MC2._cc = xlog(Op<T>::l(MC._I)) + r * ( mid( MC._cv, MC._cc, zmax, imid ) - Op<T>::l(MC._I) ); 02479 for( unsigned int i=0; i<MC2._nsub; i++ ) 02480 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r; 02481 } 02482 02483 return MC2.cut(); 02484 } 02485 02486 template <typename T> inline McCormick<T> 02487 sqrt 02488 ( const McCormick<T>&MC ) 02489 { 02490 if ( Op<T>::l(MC._I) < 0. ) 02491 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SQRT ); 02492 McCormick<T> MC2; 02493 MC2._sub( MC._nsub, MC._const ); 02494 MC2._I = Op<T>::sqrt( MC._I ); 02495 02496 { double r = 0.; 02497 if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )) 02498 r = ( std::sqrt( Op<T>::u(MC._I) ) - std::sqrt( Op<T>::l(MC._I) ) ) 02499 / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ); 02500 int imid = -1; 02501 double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid ); 02502 MC2._cv = std::sqrt( Op<T>::l(MC._I) ) + r * ( vmid - Op<T>::l(MC._I) ); 02503 for( unsigned int i=0; i<MC2._nsub; i++ ) 02504 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r; 02505 } 02506 02507 { int imid = -1; 02508 double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid ); 02509 MC2._cc = std::sqrt( vmid ); 02510 for( unsigned int i=0; i<MC2._nsub; i++ ) 02511 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) / (2.*MC2._cc); 02512 } 02513 02514 return MC2.cut(); 02515 } 02516 02517 template <typename T> inline McCormick<T> 02518 erfc 02519 ( const McCormick<T> &MC ) 02520 { 02521 return ( 1. - erf( MC ) ); 02522 } 02523 02524 template <typename T> inline McCormick<T> 02525 erf 02526 ( const McCormick<T>&MC ) 02527 { 02528 McCormick<T> MC2; 02529 MC2._sub( MC._nsub, MC._const ); 02530 MC2._I = Op<T>::erf( MC._I ); 02531 02532 if( !McCormick<T>::options.NEWTON_USE ){ 02533 MC2._cv = Op<T>::l(MC2._I); 02534 MC2._cc = Op<T>::u(MC2._I); 02535 for( unsigned int i=0; i<MC2._nsub; i++ ){ 02536 MC2._cvsub[i] = MC2._ccsub[i] = 0.; 02537 } 02538 return MC2; 02539 } 02540 02541 { int imid = -1; 02542 const double* cvenv = McCormick<T>::_erfcv( mid( MC._cv, 02543 MC._cc, Op<T>::l(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) ); 02544 MC2._cv = cvenv[0]; 02545 for( unsigned int i=0; i<MC2._nsub; i++ ){ 02546 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1]; 02547 } 02548 } 02549 { int imid = -1; 02550 const double* ccenv = McCormick<T>::_erfcc( mid( MC._cv, 02551 MC._cc, Op<T>::u(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) ); 02552 MC2._cc = ccenv[0]; 02553 for( unsigned int i=0; i<MC2._nsub; i++ ){ 02554 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1]; 02555 } 02556 } 02557 return MC2.cut(); 02558 } 02559 02560 template <typename T> inline McCormick<T> 02561 pow 02562 ( const McCormick<T>&MC, const int n ) 02563 { 02564 if( n == 0 ){ 02565 return 1.; 02566 } 02567 02568 if( n == 1 ){ 02569 return MC; 02570 } 02571 02572 if( n >= 2 && !(n%2) ){ 02573 McCormick<T> MC2; 02574 MC2._sub( MC._nsub, MC._const ); 02575 MC2._I = Op<T>::pow( MC._I, n ); 02576 { int imid = -1; 02577 double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), 0., imid ); 02578 imid = -1; 02579 MC2._cv = std::pow( mid( MC._cv, MC._cc, zmin, imid ), n ); 02580 for( unsigned int i=0; i<MC2._nsub; i++ ) 02581 MC2._cvsub[i] = n * mid( MC._cvsub, MC._ccsub, i, imid ) 02582 * std::pow( mid( MC._cv, MC._cc, zmin, imid ), n-1 ); 02583 } 02584 { int imid = -1; 02585 double zmax = (std::pow( Op<T>::l(MC._I), n )>std::pow( Op<T>::u(MC._I), n )? 02586 Op<T>::l(MC._I): Op<T>::u(MC._I)); 02587 double r = ( isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )? 0.: ( std::pow( Op<T>::u(MC._I), 02588 n ) - std::pow( Op<T>::l(MC._I), n ) ) / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ) ); 02589 MC2._cc = std::pow( Op<T>::l(MC._I), n ) + r * ( mid( MC._cv, MC._cc, zmax, 02590 imid ) - Op<T>::l(MC._I) ); 02591 for( unsigned int i=0; i<MC2._nsub; i++ ) 02592 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r; 02593 } 02594 return MC2.cut(); 02595 } 02596 02597 if( n >= 3 && McCormick<T>::options.NEWTON_USE ){ 02598 McCormick<T> MC2; 02599 MC2._sub( MC._nsub, MC._const ); 02600 MC2._I = Op<T>::pow( MC._I, n ); 02601 { int imid = -1; 02602 const double* cvenv = McCormick<T>::_oddpowcv( mid( MC._cv, 02603 MC._cc, Op<T>::l(MC._I), imid ), n, Op<T>::l(MC._I), Op<T>::u(MC._I) ); 02604 MC2._cv = cvenv[0]; 02605 for( unsigned int i=0; i<MC2._nsub; i++ ){ 02606 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1]; 02607 } 02608 } 02609 { int imid = -1; 02610 const double* ccenv = McCormick<T>::_oddpowcc( mid( MC._cv, 02611 MC._cc, Op<T>::u(MC._I), imid ), n, Op<T>::l(MC._I), Op<T>::u(MC._I) ); 02612 MC2._cc = ccenv[0]; 02613 for( unsigned int i=0; i<MC2._nsub; i++ ){ 02614 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1]; 02615 } 02616 } 02617 return MC2.cut(); 02618 } 02619 02620 if( n >= 3 ){ 02621 return pow( MC, n-1 ) * MC; 02622 } 02623 02624 if( n == -1 ){ 02625 return inv( MC ); 02626 } 02627 02628 if ( Op<T>::l(MC._I) <= 0. && Op<T>::u(MC._I) >= 0. ) 02629 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::INV ); 02630 McCormick<T> MC2; 02631 MC2._sub( MC._nsub, MC._const ); 02632 MC2._I = Op<T>::pow( MC._I, n ); 02633 02634 if ( Op<T>::l(MC._I) > 0. ){ 02635 { int imid = -1; 02636 double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid ); 02637 MC2._cv = std::pow( vmid, n ); 02638 for( unsigned int i=0; i<MC2._nsub; i++ ) 02639 MC2._cvsub[i] = n* mid( MC._cvsub, MC._ccsub, i, imid ) * std::pow( vmid, n-1 ); 02640 } 02641 { double r = std::pow( Op<T>::l(MC._I), -n-1 ) + std::pow( Op<T>::u(MC._I), -n-1 ); 02642 for( int i=1; i<=-n-2; i++ ) 02643 r += std::pow( Op<T>::l(MC._I), i ) * std::pow( Op<T>::u(MC._I), -n-1-i ); 02644 r /= - std::pow( Op<T>::l(MC._I), -n ) * std::pow( Op<T>::u(MC._I), -n ); 02645 int imid = -1; 02646 double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid ); 02647 MC2._cc = std::pow( Op<T>::l(MC._I), n ) + r * ( vmid - Op<T>::l(MC._I) ); 02648 for( unsigned int i=0; i<MC2._nsub; i++ ) 02649 MC2._ccsub[i] = r * mid( MC._cvsub, MC._ccsub, i, imid ); 02650 } 02651 return MC2.cut(); 02652 } 02653 02654 if( (-n)%2 ){ 02655 { double r = std::pow( Op<T>::l(MC._I), -n-1 ) + std::pow( Op<T>::u(MC._I), -n-1 ); 02656 for( int i=1; i<=-n-2; i++ ) 02657 r += std::pow( Op<T>::l(MC._I), i ) * std::pow( Op<T>::u(MC._I), -n-1-i ); 02658 r /= - std::pow( Op<T>::l(MC._I), -n ) * std::pow( Op<T>::u(MC._I), -n ); 02659 int imid = -1; 02660 double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid ); 02661 MC2._cv = std::pow( Op<T>::l(MC._I), n ) + r * ( vmid - Op<T>::l(MC._I) ); 02662 for( unsigned int i=0; i<MC2._nsub; i++ ) 02663 MC2._cvsub[i] = r * mid( MC._cvsub, MC._ccsub, i, imid ); 02664 } 02665 { int imid = -1; 02666 double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid ); 02667 MC2._cc = std::pow( vmid, n ); 02668 for( unsigned int i=0; i<MC2._nsub; i++ ) 02669 MC2._ccsub[i] = n* mid( MC._cvsub, MC._ccsub, i, imid ) * std::pow( vmid, n-1 ); 02670 } 02671 return MC2.cut(); 02672 } 02673 02674 { int imid = -1; 02675 double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid ); 02676 MC2._cv = std::pow( vmid, n ); 02677 for( unsigned int i=0; i<MC2._nsub; i++ ) 02678 MC2._cvsub[i] = n* mid( MC._cvsub, MC._ccsub, i, imid ) * std::pow( vmid, n-1 ); 02679 } 02680 { double r = std::pow( Op<T>::l(MC._I), -n-1 ) + std::pow( Op<T>::u(MC._I), -n-1 ); 02681 for( int i=1; i<=-n-2; i++ ) 02682 r += std::pow( Op<T>::l(MC._I), i ) * std::pow( Op<T>::u(MC._I), -n-1-i ); 02683 r /= - std::pow( Op<T>::l(MC._I), -n ) * std::pow( Op<T>::u(MC._I), -n ); 02684 int imid = -1; 02685 double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid ); 02686 MC2._cc = std::pow( Op<T>::l(MC._I), n ) + r * ( vmid - Op<T>::l(MC._I) ); 02687 for( unsigned int i=0; i<MC2._nsub; i++ ) 02688 MC2._ccsub[i] = r * mid( MC._cvsub, MC._ccsub, i, imid ); 02689 } 02690 return MC2.cut(); 02691 } 02692 02693 template <typename T> inline McCormick<T> 02694 pow 02695 ( const McCormick<T> &MC, const double a ) 02696 { 02697 return exp( a * log( MC ) ); 02698 } 02699 02700 template <typename T> inline McCormick<T> 02701 pow 02702 ( const McCormick<T> &MC1, const McCormick<T> &MC2 ) 02703 { 02704 return exp( MC2 * log( MC1 ) ); 02705 } 02706 02707 template <typename T> inline McCormick<T> 02708 pow 02709 ( const double a, const McCormick<T> &MC ) 02710 { 02711 return exp( MC * std::log( a ) ); 02712 } 02713 02714 template <typename T> inline McCormick<T> 02715 monomial 02716 (const unsigned int n, const McCormick<T>*MC, const int*k) 02717 { 02718 if( n == 0 ){ 02719 return 1.; 02720 } 02721 if( n == 1 ){ 02722 return pow( MC[0], k[0] ); 02723 } 02724 return pow( MC[0], k[0] ) * monomial( n-1, MC+1, k+1 ); 02725 } 02726 02727 template <typename T> inline McCormick<T> 02728 fabs 02729 ( const McCormick<T> &MC ) 02730 { 02731 McCormick<T> MC2; 02732 MC2._sub( MC._nsub, MC._const ); 02733 MC2._I = Op<T>::fabs( MC._I ); 02734 02735 { int imid = -1; 02736 double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), 0., imid ); 02737 imid = -1; 02738 double vmid = mid( MC._cv, MC._cc, zmin, imid ); 02739 MC2._cv = std::fabs( vmid ); 02740 if( vmid >= 0. ) 02741 for( unsigned int i=0; i<MC2._nsub; i++ ) 02742 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ); 02743 else 02744 for( unsigned int i=0; i<MC2._nsub; i++ ) 02745 MC2._cvsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid ); 02746 } 02747 02748 { int imid = -1; 02749 double zmax = (std::fabs( Op<T>::l(MC._I) )>std::fabs( Op<T>::u(MC._I) )? Op<T>::l(MC._I): 02750 Op<T>::u(MC._I)); 02751 double r = ( isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )? 0.: ( std::fabs( Op<T>::u(MC._I) ) 02752 - std::fabs( Op<T>::l(MC._I) ) ) / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ) ); 02753 MC2._cc = std::fabs( Op<T>::l(MC._I) ) + r * ( mid( MC._cv, MC._cc, zmax, imid ) 02754 - Op<T>::l(MC._I) ); 02755 for( unsigned int i=0; i<MC2._nsub; i++ ) 02756 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r; 02757 } 02758 02759 return MC2.cut(); 02760 } 02761 02762 template <typename T> inline McCormick<T> 02763 min 02764 ( const McCormick<T> &MC1, const McCormick<T> &MC2 ) 02765 { 02766 if( MC1._nsub != MC2._nsub ) 02767 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB ); 02768 02769 McCormick<T> MC3; 02770 if( MC2._const ) 02771 MC3._sub( MC1._nsub, MC1._const ); 02772 else if( MC1._const ) 02773 MC3._sub( MC2._nsub, MC2._const ); 02774 else if( MC1._nsub != MC2._nsub ) 02775 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB ); 02776 else 02777 MC3._sub( MC1._nsub, MC1._const||MC2._const ); 02778 MC3._I = Op<T>::min( MC1._I, MC2._I ); 02779 02780 if( Op<T>::u(MC1._I) <= Op<T>::l(MC2._I) ){ 02781 MC3._cv = MC1._cv; 02782 for( unsigned int i=0; i< MC3._nsub; i++ ) 02783 MC3._cvsub[i] = (MC1._const? 0.: MC1._cvsub[i]); 02784 } 02785 else if( Op<T>::u(MC2._I) <= Op<T>::l(MC1._I) ){ 02786 MC3._cv = MC2._cv; 02787 for( unsigned int i=0; i< MC3._nsub; i++ ) 02788 MC3._cvsub[i] = (MC2._const? 0.: MC2._cvsub[i]); 02789 } 02790 else if( McCormick<T>::options.MVCOMP_USE ){ 02791 double minL1L2 = std::min( Op<T>::l(MC1._I), Op<T>::l(MC2._I) ); 02792 double minL1U2 = std::min( Op<T>::l(MC1._I), Op<T>::u(MC2._I) ); 02793 double minU1L2 = std::min( Op<T>::u(MC1._I), Op<T>::l(MC2._I) ); 02794 double minU1U2 = std::min( Op<T>::u(MC1._I), Op<T>::u(MC2._I) ); 02795 02796 bool thin1 = isequal( Op<T>::diam(MC1._I), 0. ); 02797 double r11 = ( thin1? 0.: ( minU1L2 - minL1L2 ) / Op<T>::diam(MC1._I) ); 02798 double r21 = ( thin1? 0.: ( minL1U2 - minU1U2 ) / Op<T>::diam(MC1._I) ); 02799 02800 bool thin2 = isequal( Op<T>::diam(MC2._I), 0. ); 02801 double r12 = ( thin2? 0.: ( minL1U2 - minL1L2 ) / Op<T>::diam(MC2._I) ); 02802 double r22 = ( thin2? 0.: ( minU1L2 - minU1U2 ) / Op<T>::diam(MC2._I) ); 02803 02804 double g1cv = minL1L2 + r11 * ( MC1._cv - Op<T>::l(MC1._I) ) 02805 + r12 * ( MC2._cv - Op<T>::l(MC2._I) ); 02806 double g2cv = minU1U2 - r21 * ( MC1._cv - Op<T>::u(MC1._I) ) 02807 - r22 * ( MC2._cv - Op<T>::u(MC2._I) ); 02808 if( g1cv >= g2cv ){ 02809 MC3._cv = g1cv; 02810 for( unsigned int i=0; i< MC3._nsub; i++ ) 02811 MC3._cvsub[i] = (MC1._const? 0.: r11*MC1._cvsub[i]) 02812 + (MC2._const? 0.: r12*MC2._cvsub[i]); 02813 } 02814 else{ 02815 MC3._cv = g2cv; 02816 for( unsigned int i=0; i< MC3._nsub; i++ ) 02817 MC3._cvsub[i] = - (MC1._const? 0.: r21*MC1._cvsub[i]) 02818 - (MC2._const? 0.: r22*MC2._cvsub[i]); 02819 } 02820 } 02821 else{ 02822 McCormick<T> MCMin = 0.5*( MC1 + MC2 - fabs( MC2 - MC1 ) ); 02823 MC3._cv = MCMin._cv; 02824 for( unsigned int i=0; i< MC3._nsub; i++ ) 02825 MC3._cvsub[i] = MCMin._cvsub[i]; 02826 } 02827 02828 MC3._cc = std::min( MC1._cc, MC2._cc ); 02829 for( unsigned int i=0; i< MC3._nsub; i++ ) 02830 MC3._ccsub[i] = ( MC1._cc<=MC2._cc? (MC1._const? 0.: MC1._ccsub[i]) 02831 : (MC2._const? 0.: MC2._ccsub[i]) ); 02832 02833 return MC3.cut(); 02834 } 02835 02836 template <typename T> inline McCormick<T> 02837 max 02838 ( const McCormick<T> &MC1, const McCormick<T> &MC2 ) 02839 { 02840 if( MC1._nsub != MC2._nsub ) 02841 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB ); 02842 02843 McCormick<T> MC3; 02844 if( MC2._const ) 02845 MC3._sub( MC1._nsub, MC1._const ); 02846 else if( MC1._const ) 02847 MC3._sub( MC2._nsub, MC2._const ); 02848 else if( MC1._nsub != MC2._nsub ) 02849 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB ); 02850 else 02851 MC3._sub( MC1._nsub, MC1._const||MC2._const ); 02852 MC3._I = Op<T>::max( MC1._I, MC2._I ); 02853 02854 if( Op<T>::u(MC1._I) <= Op<T>::l(MC2._I) ){ 02855 MC3._cc = MC1._cc; 02856 for( unsigned int i=0; i< MC3._nsub; i++ ) 02857 MC3._ccsub[i] = (MC1._const? 0.: MC1._ccsub[i]); 02858 } 02859 else if( Op<T>::u(MC2._I) <= Op<T>::l(MC1._I) ){ 02860 MC3._cc = MC2._cc; 02861 for( unsigned int i=0; i< MC3._nsub; i++ ) 02862 MC3._ccsub[i] = (MC2._const? 0.: MC2._ccsub[i]); 02863 } 02864 else if ( McCormick<T>::options.MVCOMP_USE ){ 02865 double maxL1L2 = std::max( Op<T>::l(MC1._I), Op<T>::l(MC2._I) ); 02866 double maxL1U2 = std::max( Op<T>::l(MC1._I), Op<T>::u(MC2._I) ); 02867 double maxU1L2 = std::max( Op<T>::u(MC1._I), Op<T>::l(MC2._I) ); 02868 double maxU1U2 = std::max( Op<T>::u(MC1._I), Op<T>::u(MC2._I) ); 02869 02870 bool thin1 = isequal( Op<T>::diam(MC1._I), 0. ); 02871 double r11 = ( thin1? 0.: ( maxU1L2 - maxL1L2 ) / Op<T>::diam(MC1._I) ); 02872 double r21 = ( thin1? 0.: ( maxL1U2 - maxU1U2 ) / Op<T>::diam(MC1._I) ); 02873 02874 bool thin2 = isequal( Op<T>::diam(MC2._I), 0. ); 02875 double r12 = ( thin2? 0.: ( maxL1U2 - maxL1L2 ) / Op<T>::diam(MC2._I) ); 02876 double r22 = ( thin2? 0.: ( maxU1L2 - maxU1U2 ) / Op<T>::diam(MC2._I) ); 02877 02878 double g1cc = maxL1L2 + r11 * ( MC1._cc - Op<T>::l(MC1._I) ) 02879 + r12 * ( MC2._cc - Op<T>::l(MC2._I) ); 02880 double g2cc = maxU1U2 - r21 * ( MC1._cc - Op<T>::u(MC1._I) ) 02881 - r22 * ( MC2._cc - Op<T>::u(MC2._I) ); 02882 if( g1cc <= g2cc ){ 02883 MC3._cc = g1cc; 02884 for( unsigned int i=0; i< MC3._nsub; i++ ) 02885 MC3._ccsub[i] = (MC1._const? 0.: r11*MC1._ccsub[i]) 02886 + (MC2._const? 0.: r12*MC2._ccsub[i]); 02887 } 02888 else{ 02889 MC3._cc = g2cc; 02890 for( unsigned int i=0; i< MC3._nsub; i++ ) 02891 MC3._ccsub[i] = - (MC1._const? 0.: r21*MC1._ccsub[i]) 02892 - (MC2._const? 0.: r22*MC2._ccsub[i]); 02893 } 02894 } 02895 else{ 02896 McCormick<T> MCMax = 0.5*( MC1 + MC2 + fabs( MC1 - MC2 ) ); 02897 MC3._cc = MCMax._cc; 02898 for( unsigned int i=0; i< MC3._nsub; i++ ) 02899 MC3._ccsub[i] = MCMax._ccsub[i]; 02900 } 02901 02902 MC3._cv = std::max( MC1._cv, MC2._cv ); 02903 for( unsigned int i=0; i< MC3._nsub; i++ ) 02904 MC3._cvsub[i] = ( MC1._cv>=MC2._cv? (MC1._const? 0.: MC1._cvsub[i]) 02905 : (MC2._const? 0.: MC2._cvsub[i]) ); 02906 02907 return MC3.cut(); 02908 } 02909 02910 template <typename T> inline McCormick<T> 02911 min 02912 ( const unsigned int n, const McCormick<T>*MC ) 02913 { 02914 McCormick<T> MC2( n==0 || !MC ? 0.: MC[0] ); 02915 for( unsigned int i=1; i<n; i++ ) MC2 = min( MC2, MC[i] ); 02916 return MC2; 02917 } 02918 02919 template <typename T> inline McCormick<T> 02920 max 02921 ( const unsigned int n, const McCormick<T>*MC ) 02922 { 02923 McCormick<T> MC2( n==0 || !MC ? 0.: MC[0] ); 02924 for( unsigned int i=1; i<n; i++ ) MC2 = max( MC2, MC[i] ); 02925 return MC2; 02926 } 02927 02928 template <typename T> inline McCormick<T> 02929 fstep 02930 ( const McCormick<T> &MC ) 02931 { 02932 McCormick<T> MC2; 02933 MC2._sub( MC._nsub, MC._const ); 02934 if( Op<T>::l( MC._I ) >= 0 ) 02935 MC2._I = 1.; 02936 else if( Op<T>::u( MC._I ) < 0 ) 02937 MC2._I = 0.; 02938 else 02939 MC2._I = Op<T>::zeroone(); 02940 02941 { int imid = -1; 02942 double zmin = Op<T>::l(MC._I); 02943 double vmid = mid( MC._cv, MC._cc, zmin, imid ); 02944 const double* cvenv = McCormick<T>::_stepcv( vmid, Op<T>::l(MC._I), 02945 Op<T>::u(MC._I) ); 02946 MC2._cv = cvenv[0]; 02947 for( unsigned int i=0; i<MC2._nsub; i++ ) 02948 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid )*cvenv[1]; 02949 } 02950 02951 { int imid = -1; 02952 double zmax = Op<T>::u(MC._I); 02953 double vmid = mid( MC._cv, MC._cc, zmax, imid ); 02954 const double* ccenv = McCormick<T>::_stepcc( vmid, Op<T>::l(MC._I), 02955 Op<T>::u(MC._I) ); 02956 MC2._cc = ccenv[0]; 02957 for( unsigned int i=0; i<MC2._nsub; i++ ) 02958 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid )*ccenv[1]; 02959 } 02960 02961 return MC2.cut(); 02962 } 02963 02964 template <typename T> inline McCormick<T> 02965 bstep 02966 ( const McCormick<T> &MC ) 02967 { 02968 return fstep( -MC ); 02969 } 02970 02971 template <typename T> inline McCormick<T> 02972 ltcond 02973 ( const T &I0, const McCormick<T> &MC1, const McCormick<T> &MC2 ) 02974 { 02975 if( Op<T>::u( I0 ) < 0. ) return MC1; 02976 else if( Op<T>::l( I0 ) >= 0. ) return MC2; 02977 02978 McCormick<T> MC3; 02979 if( MC2._const ) 02980 MC3._sub( MC1._nsub, MC1._const ); 02981 else if( MC1._const ) 02982 MC3._sub( MC2._nsub, MC2._const ); 02983 else if( MC1._nsub != MC2._nsub ) 02984 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB ); 02985 else 02986 MC3._sub( MC1._nsub, MC1._const||MC2._const ); 02987 02988 MC3._I = Op<T>::hull( MC1._I, MC2._I ); 02989 McCormick<T> MCMin = 0.5*( MC1 + MC2 - fabs( MC2 - MC1 ) ); 02990 McCormick<T> MCMax = 0.5*( MC1 + MC2 + fabs( MC1 - MC2 ) ); 02991 MC3._cv = MCMin._cv; 02992 MC3._cc = MCMax._cc; 02993 for( unsigned int i=0; i< MC3._nsub; i++ ){ 02994 MC3._cvsub[i] = MCMin._cvsub[i]; 02995 MC3._ccsub[i] = MCMax._ccsub[i]; 02996 } 02997 return MC3.cut(); 02998 } 02999 03000 template <typename T> inline McCormick<T> 03001 ltcond 03002 ( const McCormick<T> &MC0, const McCormick<T> &MC1, const McCormick<T> &MC2 ) 03003 { 03004 McCormick<T> MC3 = ltcond( MC0._I, MC1, MC2 ); 03005 McCormick<T> MCStep = fstep(-MC0)*MC1 + fstep(MC0)*MC2; 03006 if( MCStep._cv > MC3._cv ){ 03007 MC3._cv = MCStep._cv; 03008 for( unsigned int i=0; i< MC3._nsub; i++ ) 03009 MC3._cvsub[i] = MCStep._cvsub[i]; 03010 } 03011 if( MCStep._cc < MC3._cc ){ 03012 MC3._cc = MCStep._cc; 03013 for( unsigned int i=0; i< MC3._nsub; i++ ) 03014 MC3._ccsub[i] = MCStep._ccsub[i]; 03015 } 03016 return MC3.cut(); 03017 } 03018 03019 template <typename T> inline McCormick<T> 03020 gtcond 03021 ( const T &I0, const McCormick<T> &MC1, const McCormick<T> &MC2 ) 03022 { 03023 return ltcond( -I0, MC1, MC2 ); 03024 } 03025 template <typename T> inline McCormick<T> 03026 gtcond 03027 ( const McCormick<T> &MC0, const McCormick<T> &MC1, const McCormick<T> &MC2 ) 03028 { 03029 return ltcond( -MC0, MC1, MC2 ); 03030 } 03031 03032 template <typename T> inline McCormick<T> 03033 cos 03034 ( const McCormick<T> &MC ) 03035 { 03036 McCormick<T> MC2; 03037 MC2._sub( MC._nsub, MC._const ); 03038 MC2._I = Op<T>::cos( MC._I ); 03039 03040 if( !McCormick<T>::options.NEWTON_USE ){ 03041 MC2._cv = Op<T>::l(MC2._I); 03042 MC2._cc = Op<T>::u(MC2._I); 03043 for( unsigned int i=0; i<MC2._nsub; i++ ){ 03044 MC2._cvsub[i] = MC2._ccsub[i] = 0.; 03045 } 03046 return MC2; 03047 } 03048 03049 double*argbnd = McCormick<T>::_cosarg( Op<T>::l(MC._I), Op<T>::u(MC._I) ); 03050 { int imid = -1; 03051 const double* cvenv = McCormick<T>::_coscv( mid( MC._cv, 03052 MC._cc, argbnd[0], imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) ); 03053 std::cout << "imid: " << imid << " " << MC._cv << " " << MC._cc 03054 << " " << argbnd[0] << std::endl; 03055 MC2._cv = cvenv[0]; 03056 for( unsigned int i=0; i< MC2._nsub; i++ ){ 03057 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1]; 03058 } 03059 } 03060 { int imid = -1; 03061 const double* ccenv = McCormick<T>::_coscc( mid( MC._cv, 03062 MC._cc, argbnd[1], imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) ); 03063 MC2._cc = ccenv[0]; 03064 for( unsigned int i=0; i< MC2._nsub; i++ ){ 03065 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1]; 03066 } 03067 } 03068 return MC2.cut(); 03069 } 03070 03071 template <typename T> inline McCormick<T> 03072 sin 03073 ( const McCormick<T> &MC ) 03074 { 03075 return cos( MC - PI/2. ); 03076 } 03077 03078 template <typename T> inline McCormick<T> 03079 asin 03080 ( const McCormick<T> &MC ) 03081 { 03082 if( !McCormick<T>::options.NEWTON_USE ) 03083 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::ASIN ); 03084 McCormick<T> MC2; 03085 MC2._sub( MC._nsub, MC._const ); 03086 MC2._I = Op<T>::asin( MC._I ); 03087 { int imid = -1; 03088 const double* cvenv = McCormick<T>::_asincv( mid( MC._cv, 03089 MC._cc, Op<T>::l(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) ); 03090 MC2._cv = cvenv[0]; 03091 for( unsigned int i=0; i<MC2._nsub; i++ ){ 03092 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1]; 03093 } 03094 } 03095 { int imid = -1; 03096 const double* ccenv = McCormick<T>::_asincc( mid( MC._cv, 03097 MC._cc, Op<T>::u(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) ); 03098 MC2._cc = ccenv[0]; 03099 for( unsigned int i=0; i<MC2._nsub; i++ ){ 03100 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1]; 03101 } 03102 } 03103 return MC2.cut(); 03104 } 03105 03106 template <typename T> inline McCormick<T> 03107 acos 03108 ( const McCormick<T> &MC ) 03109 { 03110 return asin( -MC ) + PI/2.; 03111 } 03112 03113 template <typename T> inline McCormick<T> 03114 tan 03115 ( const McCormick<T> &MC ) 03116 { 03117 return sin(MC) / cos(MC); 03118 } 03119 03120 template <typename T> inline McCormick<T> 03121 atan 03122 ( const McCormick<T> &MC ) 03123 { 03124 return asin( MC / sqrt(1+sqr(MC)) ); 03125 } 03126 03127 template <typename T> inline std::ostream& 03128 operator<< 03129 ( std::ostream&out, const McCormick<T>&MC) 03130 { 03131 const int iprec = 5; 03132 out << std::scientific << std::setprecision(iprec) << std::right 03133 << "[ " << std::setw(iprec+7) << MC.l() << " : " 03134 << std::setw(iprec+7) << MC.u() 03135 << " ] [ " << std::setw(iprec+7) << MC.cv() << " : " 03136 << std::setw(iprec+7) << MC.cc() << " ]"; 03137 if( MC._nsub ){ 03138 out << " [ ("; 03139 for( unsigned int i=0; i<MC._nsub-1; i++ ) 03140 out << std::setw(iprec+7) << MC.cvsub(i) << ","; 03141 out << std::setw(iprec+7) << MC.cvsub(MC._nsub-1) << ") : ("; 03142 for( unsigned int i=0; i<MC._nsub-1; i++ ) 03143 out << std::setw(iprec+7) << MC.ccsub(i) << ","; 03144 out << std::setw(iprec+7) << MC.ccsub(MC._nsub-1) << ") ]"; 03145 } 03146 return out; 03147 } 03148 03149 template <typename T> inline bool 03150 inter 03151 ( McCormick<T>&XIY, const McCormick<T>&X, const McCormick<T>&Y ) 03152 { 03153 if( !Op<T>::inter( XIY._I, X._I, Y._I ) ) return false; 03154 //if( X._cv > Y._cc || Y._cv > X._cc ) return false; 03155 03156 if( !X._const && !Y._const && (X._nsub != Y._nsub) ) 03157 throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB ); 03158 else if( !X._const ) 03159 XIY._sub( X._nsub, X._const ); 03160 else 03161 XIY._sub( Y._nsub, Y._const ); 03162 03163 if( Y._cv > X._cv ){ 03164 XIY._cv = Y._cv; 03165 for( unsigned int is=0; is<XIY._nsub; is++ ) 03166 XIY._cvsub[is] = ( Y._const? 0.: Y._cvsub[is] ); 03167 } 03168 else{ 03169 XIY._cv = X._cv; 03170 for( unsigned int is=0; is<XIY._nsub; is++ ) 03171 XIY._cvsub[is] = ( X._const? 0.: X._cvsub[is] ); 03172 } 03173 if( Y._cc < X._cc ){ 03174 XIY._cc = Y._cc; 03175 for( unsigned int is=0; is<XIY._nsub; is++ ) 03176 XIY._ccsub[is] = ( Y._const? 0.: Y._ccsub[is] ); 03177 } 03178 else{ 03179 XIY._cc = X._cc; 03180 for( unsigned int is=0; is<XIY._nsub; is++ ) 03181 XIY._ccsub[is] = ( X._const? 0.: X._ccsub[is] ); 03182 } 03183 return true; 03184 } 03185 03186 template <typename T> inline bool 03187 operator== 03188 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 03189 { 03190 return( Op<T>::eq(MC1._I,MC2._I) && MC1._cv == MC2._cv && MC1._cc == MC2._cc ); 03191 } 03192 03193 template <typename T> inline bool 03194 operator!= 03195 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 03196 { 03197 return( Op<T>::ne(MC1._I,MC2._I) || MC1._cv != MC2._cv || MC1._cc != MC2._cc ); 03198 } 03199 03200 template <typename T> inline bool 03201 operator<= 03202 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 03203 { 03204 return( Op<T>::le(MC1._I,MC2._I) && MC1._cv >= MC2._cv && MC1._cc <= MC2._cc ); 03205 } 03206 03207 template <typename T> inline bool 03208 operator>= 03209 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 03210 { 03211 return( Op<T>::ge(MC1._I,MC2._I) && MC1._cv <= MC2._cv && MC1._cc >= MC2._cc ); 03212 } 03213 03214 template <typename T> inline bool 03215 operator< 03216 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 03217 { 03218 return( Op<T>::lt(MC1._I,MC2._I) && MC1._cv > MC2._cv && MC1._cc < MC2._cc ); 03219 } 03220 03221 template <typename T> inline bool 03222 operator> 03223 ( const McCormick<T>&MC1, const McCormick<T>&MC2 ) 03224 { 03225 return( Op<T>::gt(MC1._I,MC2._I) && MC1._cv < MC2._cv && MC1._cc > MC2._cc ); 03226 } 03227 03228 template <typename T> typename McCormick<T>::Options McCormick<T>::options; 03229 03230 } // namespace mc 03231 03232 03233 #include "mcop.h" 03234 03235 namespace mc 03236 { 03237 03239 template <> template<typename T> struct Op< mc::McCormick<T> > 03240 { 03241 typedef mc::McCormick<T> MC; 03242 static MC point( const double c ) { return MC(c); } 03243 static MC zeroone() { return MC( mc::Op<T>::zeroone() ); } 03244 static void I(MC& x, const MC&y) { x = y; } 03245 static double l(const MC& x) { return x.l(); } 03246 static double u(const MC& x) { return x.u(); } 03247 static double abs (const MC& x) { return mc::Op<T>::abs(x.I()); } 03248 static double mid (const MC& x) { return mc::Op<T>::mid(x.I()); } 03249 static double diam(const MC& x) { return mc::Op<T>::diam(x.I()); } 03250 static MC inv (const MC& x) { return mc::inv(x); } 03251 static MC sqr (const MC& x) { return mc::sqr(x); } 03252 static MC sqrt(const MC& x) { return mc::sqrt(x); } 03253 static MC log (const MC& x) { return mc::log(x); } 03254 static MC xlog(const MC& x) { return mc::xlog(x); } 03255 static MC fabs(const MC& x) { return mc::fabs(x); } 03256 static MC exp (const MC& x) { return mc::exp(x); } 03257 static MC sin (const MC& x) { return mc::sin(x); } 03258 static MC cos (const MC& x) { return mc::cos(x); } 03259 static MC tan (const MC& x) { return mc::tan(x); } 03260 static MC asin(const MC& x) { return mc::asin(x); } 03261 static MC acos(const MC& x) { return mc::acos(x); } 03262 static MC atan(const MC& x) { return mc::atan(x); } 03263 static MC erf (const MC& x) { return mc::erf(x); } 03264 static MC erfc(const MC& x) { return mc::erfc(x); } 03265 static MC hull(const MC& x, const MC& y) { return mc::Op<T>::hull(x.I(),y.I()); } 03266 static MC min (const MC& x, const MC& y) { return mc::min(x,y); } 03267 static MC max (const MC& x, const MC& y) { return mc::max(x,y); } 03268 static MC arh (const MC& x, const double k) { return mc::arh(x,k); } 03269 template <typename X, typename Y> static MC pow(const X& x, const Y& y) { return mc::pow(x,y); } 03270 static MC monomial (const unsigned int n, const T* x, const int* k) { return mc::monomial(n,x,k); } 03271 static bool inter(MC& xIy, const MC& x, const MC& y) { return mc::inter(xIy,x,y); } 03272 static bool eq(const MC& x, const MC& y) { return x==y; } 03273 static bool ne(const MC& x, const MC& y) { return x!=y; } 03274 static bool lt(const MC& x, const MC& y) { return x<y; } 03275 static bool le(const MC& x, const MC& y) { return x<=y; } 03276 static bool gt(const MC& x, const MC& y) { return x>y; } 03277 static bool ge(const MC& x, const MC& y) { return x>=y; } 03278 }; 03279 03280 } // namespace mc 03281 03282 #endif