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