MC++
mccormick.hpp
1 // Copyright (C) 2009-2013 Benoit Chachuat, Imperial College London.
2 // All Rights Reserved.
3 
340 #ifndef MC__MCCORMICK_H
341 #define MC__MCCORMICK_H
342 
343 #include <iostream>
344 #include <iomanip>
345 #include <stdarg.h>
346 #include <cassert>
347 
348 #include "mcfunc.hpp"
349 #include "mcop.hpp"
350 
351 namespace mc
352 {
361 template <typename T>
364 {
365  template <typename U> friend class McCormick;
366 
367  template <typename U> friend McCormick<U> operator+
368  ( const McCormick<U>& );
369  template <typename U> friend McCormick<U> operator+
370  ( const McCormick<U>&, const McCormick<U>& );
371  template <typename U> friend McCormick<U> operator+
372  ( const double, const McCormick<U>& );
373  template <typename U> friend McCormick<U> operator+
374  ( const McCormick<U>&, const double );
375  template <typename U> friend McCormick<U> operator-
376  ( const McCormick<U>& );
377  template <typename U> friend McCormick<U> operator-
378  ( const McCormick<U>&, const McCormick<U>& );
379  template <typename U> friend McCormick<U> operator-
380  ( const double, const McCormick<U>& );
381  template <typename U> friend McCormick<U> operator-
382  ( const McCormick<U>&, const double );
383  template <typename U> friend McCormick<U> operator*
384  ( const McCormick<U>&, const McCormick<U>& );
385  template <typename U> friend McCormick<U> operator*
386  ( const double, const McCormick<U>& );
387  template <typename U> friend McCormick<U> operator*
388  ( const McCormick<U>&, const double );
389  template <typename U> friend McCormick<U> operator/
390  ( const McCormick<U>&, const McCormick<U>& );
391  template <typename U> friend McCormick<U> operator/
392  ( const double, const McCormick<U>& );
393  template <typename U> friend McCormick<U> operator/
394  ( const McCormick<U>&, const double );
395  template <typename U> friend std::ostream& operator<<
396  ( std::ostream&, const McCormick<U>& );
397  template <typename U> friend bool operator==
398  ( const McCormick<U>&, const McCormick<U>& );
399  template <typename U> friend bool operator!=
400  ( const McCormick<U>&, const McCormick<U>& );
401  template <typename U> friend bool operator<=
402  ( const McCormick<U>&, const McCormick<U>& );
403  template <typename U> friend bool operator>=
404  ( const McCormick<U>&, const McCormick<U>& );
405  template <typename U> friend bool operator<
406  ( const McCormick<U>&, const McCormick<U>& );
407  template <typename U> friend bool operator>
408  ( const McCormick<U>&, const McCormick<U>& );
409 
410  template <typename U> friend McCormick<U> inv
411  ( const McCormick<U>& );
412  template <typename U> friend McCormick<U> sqr
413  ( const McCormick<U>& );
414  template <typename U> friend McCormick<U> exp
415  ( const McCormick<U>& );
416  template <typename U> friend McCormick<U> log
417  ( const McCormick<U>& );
418  template <typename U> friend McCormick<U> cos
419  ( const McCormick<U>& );
420  template <typename U> friend McCormick<U> sin
421  ( const McCormick<U>& );
422  template <typename U> friend McCormick<U> tan
423  ( const McCormick<U>& );
424  template <typename U> friend McCormick<U> acos
425  ( const McCormick<U>& );
426  template <typename U> friend McCormick<U> asin
427  ( const McCormick<U>& );
428  template <typename U> friend McCormick<U> atan
429  ( const McCormick<U>& );
430  template <typename U> friend McCormick<U> fabs
431  ( const McCormick<U>& );
432  template <typename U> friend McCormick<U> sqrt
433  ( const McCormick<U>& );
434  template <typename U> friend McCormick<U> xlog
435  ( const McCormick<U>& );
436  template <typename U> friend McCormick<U> arh
437  ( const McCormick<U>&, const double );
438  template <typename U> friend McCormick<U> erf
439  ( const McCormick<U>& );
440  template <typename U> friend McCormick<U> erfc
441  ( const McCormick<U>& );
442  template <typename U> friend McCormick<U> fstep
443  ( const McCormick<U>& );
444  template <typename U> friend McCormick<U> bstep
445  ( const McCormick<U>& );
446  template <typename U> friend McCormick<U> pow
447  ( const McCormick<U>&, const int );
448  template <typename U> friend McCormick<U> pow
449  ( const McCormick<U>&, const double );
450  template <typename U> friend McCormick<U> pow
451  ( const double, const McCormick<U>& );
452  template <typename U> friend McCormick<U> pow
453  ( const McCormick<U>&, const McCormick<U>& );
454  template <typename U> friend McCormick<U> monomial
455  ( const unsigned int, const McCormick<U>*, const int* );
456  template <typename U> friend McCormick<U> min
457  ( const McCormick<U>&, const McCormick<U>& );
458  template <typename U> friend McCormick<U> max
459  ( const McCormick<U>&, const McCormick<U>& );
460  template <typename U> friend McCormick<U> min
461  ( const unsigned int, const McCormick<U>* );
462  template <typename U> friend McCormick<U> max
463  ( const unsigned int, const McCormick<U>* );
464  template <typename U> friend McCormick<U> ltcond
465  ( const McCormick<U>&, const McCormick<U>&, const McCormick<U>& );
466  template <typename U> friend McCormick<U> ltcond
467  ( const U&, const McCormick<U>&, const McCormick<U>& );
468  template <typename U> friend McCormick<U> gtcond
469  ( const McCormick<U>&, const McCormick<U>&, const McCormick<U>& );
470  template <typename U> friend McCormick<U> gtcond
471  ( const U&, const McCormick<U>&, const McCormick<U>& );
472  template <typename U> friend bool inter
473  ( McCormick<U>&, const McCormick<U>&, const McCormick<U>& );
474  template <typename U> friend McCormick<U> hull
475  ( const McCormick<U>&, const McCormick<U>& );
476  template <typename U> friend McCormick<U> cut
477  ( const McCormick<U>& );
478 
479 public:
480 
481  McCormick<T>& operator=
482  ( const McCormick<T>& );
483  McCormick<T>& operator=
484  ( const T& );
485  McCormick<T>& operator=
486  ( const double );
487  McCormick<T>& operator+=
488  ( const McCormick<T>& );
489  McCormick<T>& operator+=
490  ( const double );
491  McCormick<T>& operator-=
492  ( const McCormick<T>& );
493  McCormick<T>& operator-=
494  ( const double );
495  McCormick<T>& operator*=
496  ( const McCormick<T>& );
497  McCormick<T>& operator*=
498  ( const double );
499  McCormick<T>& operator/=
500  ( const McCormick<T>& );
501  McCormick<T>& operator/=
502  ( const double );
503 
507  static struct Options
509  {
512  ENVEL_USE(true), ENVEL_MAXIT(100), ENVEL_TOL(1e-10), MVCOMP_USE(false),
513  MVCOMP_TOL(1e1*machprec()), DISPLAY_DIGITS(5)
514  {}
516  bool ENVEL_USE;
518  unsigned int ENVEL_MAXIT;
520  double ENVEL_TOL;
524  double MVCOMP_TOL;
526  unsigned int DISPLAY_DIGITS;
527  } options;
528 
531  {
532  public:
534  enum TYPE{
535  DIV=1,
536  INV,
537  LOG,
540  TAN,
541  MULTSUB=-3,
544  };
546  Exceptions( TYPE ierr ) : _ierr( ierr ){}
548  int ierr(){ return _ierr; }
550  std::string what(){
551  switch( _ierr ){
552  case DIV:
553  return "mc::McCormick\t Division by zero";
554  case INV:
555  return "mc::McCormick\t Inverse with zero in range";
556  case LOG:
557  return "mc::McCormick\t Log with negative values in range";
558  case SQRT:
559  return "mc::McCormick\t Square-root with nonpositive values in range";
560  case ASIN:
561  return "mc::McCormick\t Inverse sine with values outside of [-1,1] range";
562  case TAN:
563  return "mc::McCormick\t Tangent with values pi/2+k*pi in range";
564  case MULTSUB:
565  return "mc::McCormick\t Subgradient propagation failed";
566  case ENVEL:
567  return "mc::McCormick\t Convex/concave envelope computation failed";
568  case SUB:
569  return "mc::McCormick\t Inconsistent subgradient dimension";
570  }
571  return "mc::McCormick\t Undocumented error";
572  }
573 
574  private:
575  TYPE _ierr;
576  };
577 
580  _nsub(0), _cvsub(0), _ccsub(0), _const(true)
581  {}
583  McCormick
584  ( const double c ):
585  _nsub(0), _cv(c), _cc(c), _cvsub(0), _ccsub(0), _const(true)
586  {
587  Op<T>::I(_I,c);
588  }
590  McCormick
591  ( const T&I ):
592  _nsub(0), _cvsub(0), _ccsub(0), _const(true)
593  {
594  Op<T>::I(_I,I);
595  _cv = Op<T>::l(I); _cc = Op<T>::u(I);
596  }
598  McCormick
599  ( const T&I, const double c ):
600  _nsub(0), _cv(c), _cc(c), _cvsub(0), _ccsub(0), _const(false)
601  {
602  Op<T>::I(_I,I);
603  }
605  McCormick
606  ( const T&I, const double cv, const double cc ):
607  _nsub(0), _cv(cv), _cc(cc), _cvsub(0), _ccsub(0), _const(false)
608  {
609  Op<T>::I(_I,I); cut();
610  }
612  McCormick
613  ( const McCormick<T>&MC ):
614  _nsub(MC._nsub), _cv(MC._cv), _cc(MC._cc),
615  _cvsub(_nsub>0?new double[_nsub]:0), _ccsub(_nsub>0?new double[_nsub]:0),
616  _const(MC._const)
617  {
618  Op<T>::I(_I,MC._I);
619  for ( unsigned int ip=0; ip<_nsub; ip++ ){
620  _cvsub[ip] = MC._cvsub[ip];
621  _ccsub[ip] = MC._ccsub[ip];
622  }
623  }
625  template <typename U> McCormick
626  ( const McCormick<U>&MC ):
627  _nsub(MC._nsub), _cv(MC._cv), _cc(MC._cc),
628  _cvsub(_nsub>0?new double[_nsub]:0), _ccsub(_nsub>0?new double[_nsub]:0),
629  _const(MC._const)
630  {
631  Op<T>::I(_I,MC._I);
632  for ( unsigned int ip=0; ip<_nsub; ip++ ){
633  _cvsub[ip] = MC._cvsub[ip];
634  _ccsub[ip] = MC._ccsub[ip];
635  }
636  }
637 
640  {
641  delete [] _cvsub;
642  delete [] _ccsub;
643  }
644 
646  unsigned int& nsub()
647  {
648  return _nsub;
649  }
650  unsigned int nsub() const
651  {
652  return _nsub;
653  }
655  T& I()
656  {
657  return _I;
658  }
659  const T& I() const
660  {
661  return _I;
662  }
664  double l() const
665  {
666  return Op<T>::l(_I);
667  }
669  double u() const
670  {
671  return Op<T>::u(_I);
672  }
674  double& cv()
675  {
676  return _cv;
677  }
678  double cv() const
679  {
680  return _cv;
681  }
683  double& cc()
684  {
685  return _cc;
686  }
687  double cc() const
688  {
689  return _cc;
690  }
692  double*& cvsub()
693  {
694  return _cvsub;
695  }
696  const double* cvsub() const
697  {
698  return _cvsub;
699  }
701  double*& ccsub()
702  {
703  return _ccsub;
704  }
705  const double* ccsub() const
706  {
707  return _ccsub;
708  }
710  double& cvsub
711  ( const unsigned int i )
712  {
713  return _cvsub[i];
714  }
715  double cvsub
716  ( const unsigned int i ) const
717  {
718  return _cvsub[i];
719  }
721  double& ccsub
722  ( const unsigned int i )
723  {
724  return _ccsub[i];
725  }
726  double ccsub
727  ( const unsigned int i ) const
728  {
729  return _ccsub[i];
730  }
731 
733  void I
734  ( const T& I )
735  {
736  Op<T>::I(_I,I);
737  }
739  void cv
740  ( const double& cv )
741  {
742  _cv = cv;
743  _const = false;
744  }
746  void cc
747  ( const double& cc )
748  {
749  _cc = cc;
750  _const = false;
751  }
753  void c
754  ( const double& c )
755  {
756  _cv = _cc = c;
757  _const = false;
758  }
759 
762  ( const unsigned int nsub);
765  ( const unsigned int nsub, const unsigned int isub );
768  ( const unsigned int nsub, const double*cvsub, const double*ccsub );
769 
771  McCormick<T>& cut();
773  double laff
774  ( const double*p, const double*pref ) const;
776  double laff
777  ( const T*Ip, const double*pref ) const;
779  double uaff
780  ( const double*p, const double*pref ) const;
782  double uaff
783  ( const T*Ip, const double*pref ) const;
786 private:
787 
789  unsigned int _nsub;
791  T _I;
793  double _cv;
795  double _cc;
797  double *_cvsub;
799  double *_ccsub;
801  bool _const;
802 
804  void _sub
805  ( const unsigned int nsub, const bool cst );
807  void _sub_reset();
809  void _sub_resize
810  ( const unsigned int nsub );
812  void _sub_copy
813  ( const McCormick<T>&MC );
814 
816  McCormick<T>& _sum1
817  ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
819  McCormick<T>& _sum2
820  ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
821 
823  McCormick<T>& _sub1
824  ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
826  McCormick<T>& _sub2
827  ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
829  McCormick<T>& _sub3
830  ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
831 
833  McCormick<T>& _mul1_u1pos_u2pos
834  ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
836  McCormick<T>& _mul2_u1pos_u2pos
837  ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
839  McCormick<T>& _mul1_u1pos_u2mix
840  ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
842  McCormick<T>& _mul2_u1pos_u2mix
843  ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
845  McCormick<T>& _mul3_u1pos_u2mix
846  ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
848  McCormick<T>& _mul1_u1mix_u2mix
849  ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
851  McCormick<T>& _mul2_u1mix_u2mix
852  ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
854  McCormick<T>& _mulMV
855  ( const McCormick<T>&MC1, const McCormick<T>&MC2 );
856 
858  typedef double (puniv)
859  ( const double x, const double*rusr, const int*iusr );
861  static double _newton
862  ( const double x0, const double xL, const double xU, puniv f,
863  puniv df, const double*rusr, const int*iusr=0 );
865  static double _secant
866  ( const double x0, const double x1, const double xL, const double xU,
867  puniv f, const double*rusr, const int*iusr );
869  static double _goldsect
870  ( const double xL, const double xU, puniv f, const double*rusr,
871  const int*iusr );
873  static double _goldsect_iter
874  ( const bool init, const double a, const double fa, const double b,
875  const double fb, const double c, const double fc, puniv f,
876  const double*rusr, const int*iusr );
877 
879  static double* _oddpowcv
880  ( const double x, const int iexp, const double xL, const double xU );
882  static double* _oddpowcc
883  ( const double x, const int iexp, const double xL, const double xU );
885  static double _oddpowenv_func
886  ( const double x, const double*rusr, const int*iusr );
888  static double _oddpowenv_dfunc
889  ( const double x, const double*rusr, const int*iusr );
890 
892  static double* _erfcv
893  ( const double x, const double xL, const double xU );
895  static double* _erfcc
896  ( const double x, const double xL, const double xU );
898  static double _erfenv_func
899  ( const double x, const double*rusr, const int*iusr );
901  static double _erfenv_dfunc
902  ( const double x, const double*rusr, const int*iusr );
903 
905  static double* _atancv
906  ( const double x, const double xL, const double xU );
908  static double* _atancc
909  ( const double x, const double xL, const double xU );
911  static double _atanenv_func
912  ( const double x, const double*rusr, const int*iusr );
914  static double _atanenv_dfunc
915  ( const double x, const double*rusr, const int*iusr );
916 
918  static double* _stepcv
919  ( const double x, const double xL, const double xU );
921  static double* _stepcc
922  ( const double x, const double xL, const double xU );
923 
925  static double* _cosarg
926  ( const double xL, const double xU );
928  static double* _coscv
929  ( const double x, const double xL, const double xU );
931  static double* _coscc
932  ( const double x, const double xL, const double xU );
934  static double* _coscv2
935  ( const double x, const double xL, const double xU );
937  static double _cosenv_func
938  ( const double x, const double*rusr, const int*iusr );
940  static double _cosenv_dfunc
941  ( const double x, const double*rusr, const int*iusr );
942 
944  static double* _asincv
945  ( const double x, const double xL, const double xU );
947  static double* _asincc
948  ( const double x, const double xL, const double xU );
950  static double _asinenv_func
951  ( const double x, const double*rusr, const int*iusr );
953  static double _asinenv_dfunc
954  ( const double x, const double*rusr, const int*iusr );
955 
957  static double* _tancv
958  ( const double x, const double xL, const double xU );
960  static double* _tancc
961  ( const double x, const double xL, const double xU );
963  static double _tanenv_func
964  ( const double x, const double*rusr, const int*iusr );
966  static double _tanenv_dfunc
967  ( const double x, const double*rusr, const int*iusr );
968 };
969 
971 
972 template <typename T> inline void
973 McCormick<T>::_sub_reset()
974 {
975  delete [] _cvsub;
976  delete [] _ccsub;
977  _cvsub = _ccsub = 0;
978 }
979 
980 template <typename T> inline void
981 McCormick<T>::_sub_resize
982 ( const unsigned int nsub )
983 {
984  if( _nsub != nsub ){
985  delete [] _cvsub;
986  delete [] _ccsub;
987  _nsub = nsub;
988  if( _nsub > 0 ){
989  _cvsub = new double[_nsub];
990  _ccsub = new double[_nsub];
991  }
992  else{
993  _cvsub = _ccsub = 0;
994  return;
995  }
996  }
997 }
998 
999 template <typename T> inline void
1000 McCormick<T>::_sub_copy
1001 ( const McCormick<T>&MC )
1002 {
1003  _sub_resize( MC._nsub );
1004  for ( unsigned int i=0; i<_nsub; i++ ){
1005  _cvsub[i] = MC._cvsub[i];
1006  _ccsub[i] = MC._ccsub[i];
1007  }
1008  return;
1009 }
1010 
1011 template <typename T> inline void
1012 McCormick<T>::_sub
1013 ( const unsigned int nsub, const bool cst )
1014 {
1015  _sub_resize( nsub );
1016  for ( unsigned int i=0; i<nsub; i++ ){
1017  _cvsub[i] = _ccsub[i] = 0.;
1018  }
1019  _const = cst;
1020 }
1021 
1022 template <typename T> inline McCormick<T>&
1024 ( const unsigned int nsub )
1025 {
1026  _sub( nsub, false );
1027  return *this;
1028 }
1029 
1030 template <typename T> inline McCormick<T>&
1032 ( const unsigned int nsub, const unsigned int isub )
1033 {
1034  if( isub >= nsub ) throw Exceptions( Exceptions::SUB );
1035  sub( nsub );
1036  _cvsub[isub] = _ccsub[isub] = 1.;
1037  return *this;
1038 }
1039 
1040 template <typename T> inline McCormick<T>&
1042 ( const unsigned int nsub, const double*cvsub, const double*ccsub )
1043 {
1044  if( nsub && !(cvsub && ccsub) ) throw Exceptions( Exceptions::SUB );
1045  sub( nsub );
1046  for ( unsigned int i=0; i<nsub; i++ ){
1047  _cvsub[i] = cvsub[i];
1048  _ccsub[i] = ccsub[i];
1049  }
1050  return *this;
1051 }
1052 
1053 template <typename T> inline McCormick<T>&
1055 {
1056  if( _cv < Op<T>::l(_I) ){
1057  _cv = Op<T>::l(_I);
1058  for( unsigned int i=0; i<_nsub; i++ ) _cvsub[i] = 0.;
1059  }
1060  if( _cc > Op<T>::u(_I) ){
1061  _cc = Op<T>::u(_I);
1062  for( unsigned int i=0; i<_nsub; i++ ) _ccsub[i] = 0.;
1063  }
1064  return *this;
1065 }
1066 
1067 template <typename T> inline double
1069 ( const double*p, const double*pref ) const
1070 {
1071  double _laff = _cv;
1072  for( unsigned int i=0; i<_nsub; i++ ){
1073  _laff += _cvsub[i]*(p[i]-pref[i]);
1074  }
1075  return _laff;
1076 }
1077 
1078 template <typename T> inline double
1080 ( const T*Ip, const double*pref ) const
1081 {
1082  double _laff = _cv;
1083  for( unsigned int i=0; i<_nsub; i++ ){
1084  _laff += Op<T>::l(_cvsub[i]*(Ip[i]-pref[i]));
1085  }
1086  return _laff;
1087 }
1088 
1089 template <typename T> inline double
1091 ( const double*p, const double*pref ) const
1092 {
1093  double _uaff = _cc;
1094  for( unsigned int i=0; i<_nsub; i++ ){
1095  _uaff += _ccsub[i]*(p[i]-pref[i]);
1096  }
1097  return _uaff;
1098 }
1099 
1100 template <typename T> inline double
1102 ( const T*Ip, const double*pref ) const
1103 {
1104  double _uaff = _cc;
1105  for( unsigned int i=0; i<_nsub; i++ ){
1106  _uaff += Op<T>::u(_ccsub[i]*(Ip[i]-pref[i]));
1107  }
1108  return _uaff;
1109 }
1110 
1111 template <typename T> inline McCormick<T>&
1113 ( const double c )
1114 {
1115  _I = c;
1116  _cv = _cc = c;
1117  _sub_reset();
1118  _nsub = 0;
1119  _const = true;
1120  return *this;
1121 }
1122 
1123 template <typename T> inline McCormick<T>&
1124 McCormick<T>::operator=
1125 ( const T&I )
1126 {
1127  _I = I;
1128  _cv = Op<T>::l(I);
1129  _cc = Op<T>::u(I);
1130  _sub_reset();
1131  _nsub = 0;
1132  _const = true;
1133  return *this;
1134 }
1135 
1136 template <typename T> inline McCormick<T>&
1137 McCormick<T>::operator=
1138 ( const McCormick<T>&MC )
1139 {
1140  if( this == &MC ) return *this;
1141  _I = MC._I;
1142  _cv = MC._cv;
1143  _cc = MC._cc;
1144  _sub_copy( MC );
1145  _const = MC._const;
1146  return *this;
1147 }
1148 
1149 template <typename T> inline McCormick<T>&
1150 McCormick<T>::operator+=
1151 ( const double a )
1152 {
1153  _I += a;
1154  _cv += a;
1155  _cc += a;
1156  return *this;
1157 }
1158 
1159 template <typename T> inline McCormick<T>&
1160 McCormick<T>::operator+=
1161 ( const McCormick<T> &MC )
1162 {
1163  if( _const && !MC._const ) sub( MC._nsub );
1164  else if( !MC._const && _nsub != MC._nsub ) throw Exceptions( Exceptions::SUB );
1165  _I += MC._I;
1166  _cv += MC._cv;
1167  _cc += MC._cc;
1168  for( unsigned int i=0; i<_nsub && !MC._const; i++ ){
1169  _cvsub[i] += MC._cvsub[i];
1170  _ccsub[i] += MC._ccsub[i];
1171  }
1172  return *this;
1173 }
1174 
1175 template <typename T> inline McCormick<T>&
1176 McCormick<T>::_sum1
1177 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
1178 {
1179  _I = MC1._I + MC2._I;
1180  _cv = MC1._cv + MC2._cv;
1181  _cc = MC1._cc + MC2._cc;
1182  for( unsigned int i=0; i<_nsub; i++ ){
1183  _cvsub[i] = MC1._cvsub[i];
1184  _ccsub[i] = MC1._ccsub[i];
1185  }
1186  return *this;
1187 }
1188 
1189 template <typename T> inline McCormick<T>&
1190 McCormick<T>::_sum2
1191 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
1192 {
1193  _I = MC1._I + MC2._I;
1194  _cv = MC1._cv + MC2._cv;
1195  _cc = MC1._cc + MC2._cc;
1196  for( unsigned int i=0; i<_nsub; i++ ){
1197  _cvsub[i] = MC1._cvsub[i] + MC2._cvsub[i];
1198  _ccsub[i] = MC1._ccsub[i] + MC2._ccsub[i];
1199  }
1200  return *this;
1201 }
1202 
1203 template <typename T> inline McCormick<T>&
1204 McCormick<T>::operator-=
1205 ( const double a )
1206 {
1207  _I -= a;
1208  _cv -= a;
1209  _cc -= a;
1210  return *this;
1211 }
1212 
1213 template <typename T> inline McCormick<T>&
1214 McCormick<T>::operator-=
1215 ( const McCormick<T> &MC )
1216 {
1217  if( _const && !MC._const ) sub( MC._nsub );
1218  else if( !MC._const && _nsub != MC._nsub ) throw Exceptions( Exceptions::SUB );
1219  _I -= MC._I;
1220  double t_cv = MC._cv;
1221  _cv -= MC._cc;
1222  _cc -= t_cv;
1223  for( unsigned int i=0; i<_nsub && !MC._const; i++ ){
1224  double t_cvsub = MC._cvsub[i];
1225  _cvsub[i] -= MC._ccsub[i];
1226  _ccsub[i] -= t_cvsub;
1227  }
1228  return *this;
1229 }
1230 
1231 template <typename T> inline McCormick<T>&
1232 McCormick<T>::_sub1
1233 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
1234 {
1235  _I = MC1._I - MC2._I;
1236  _cv = MC1._cv - MC2._cc;
1237  _cc = MC1._cc - MC2._cv;
1238  for( unsigned int i=0; i<_nsub; i++ ){
1239  _cvsub[i] = MC1._cvsub[i];
1240  _ccsub[i] = MC1._ccsub[i];
1241  }
1242  return *this;
1243 }
1244 
1245 template <typename T> inline McCormick<T>&
1246 McCormick<T>::_sub2
1247 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
1248 {
1249  _I = MC1._I - MC2._I;
1250  _cv = MC1._cv - MC2._cc;
1251  _cc = MC1._cc - MC2._cv;
1252  for( unsigned int i=0; i<_nsub; i++ ){
1253  _cvsub[i] = -MC2._ccsub[i];
1254  _ccsub[i] = -MC2._cvsub[i];
1255  }
1256  return *this;
1257 }
1258 
1259 template <typename T> inline McCormick<T>&
1260 McCormick<T>::_sub3
1261 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
1262 {
1263  _I = MC1._I - MC2._I;
1264  _cv = MC1._cv - MC2._cc;
1265  _cc = MC1._cc - MC2._cv;
1266  for( unsigned int i=0; i<_nsub; i++ ){
1267  _cvsub[i] = MC1._cvsub[i] - MC2._ccsub[i];
1268  _ccsub[i] = MC1._ccsub[i] - MC2._cvsub[i];
1269  }
1270  return *this;
1271 }
1272 
1273 template <typename T> inline McCormick<T>&
1274 McCormick<T>::operator*=
1275 ( const double a )
1276 {
1277  McCormick<T> MC2 = a * (*this);
1278  *this = MC2;
1279  return *this;
1280 }
1281 
1282 template <typename T> inline McCormick<T>&
1283 McCormick<T>::operator*=
1284 ( const McCormick<T>&MC )
1285 {
1286  if( _const && !MC._const ) sub( MC._nsub );
1287  McCormick<T> MC2 = MC * (*this);
1288  *this = MC2;
1289  return *this;
1290 }
1291 
1292 template <typename T> inline McCormick<T>&
1293 McCormick<T>::_mul1_u1pos_u2pos
1294 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
1295 {
1296  _I = MC1._I * MC2._I;
1297 
1298  double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
1299  - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
1300  double cv2 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::l(MC1._I) * MC2._cv
1301  - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
1302  if ( cv1 > cv2 ){
1303  _cv = cv1;
1304  for( unsigned int i=0; i<_nsub; i++ )
1305  _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i];
1306  }
1307  else{
1308  _cv = cv2;
1309  for( unsigned int i=0; i<_nsub; i++ )
1310  _cvsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i];
1311  }
1312 
1313  double cc1 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::u(MC1._I) * MC2._cc
1314  - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
1315  double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
1316  - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
1317  if ( cc1 < cc2 ){
1318  _cc = cc1;
1319  for( unsigned int i=0; i<_nsub; i++ )
1320  _ccsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i];
1321  }
1322  else{
1323  _cc = cc2;
1324  for( unsigned int i=0; i<_nsub; i++ )
1325  _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i];
1326  }
1327  return *this;
1328 }
1329 
1330 template <typename T> inline McCormick<T>&
1331 McCormick<T>::_mul2_u1pos_u2pos
1332 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
1333 {
1334  _I = MC1._I * MC2._I;
1335 
1336  double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
1337  - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
1338  double cv2 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::l(MC1._I) * MC2._cv
1339  - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
1340  if ( cv1 > cv2 ){
1341  _cv = cv1;
1342  for( unsigned int i=0; i<_nsub; i++ )
1343  _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._cvsub[i];
1344  }
1345  else{
1346  _cv = cv2;
1347  for( unsigned int i=0; i<_nsub; i++ )
1348  _cvsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i] + Op<T>::l(MC1._I) * MC2._cvsub[i];
1349  }
1350 
1351  double cc1 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::u(MC1._I) * MC2._cc
1352  - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
1353  double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
1354  - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
1355  if ( cc1 < cc2 ){
1356  _cc = cc1;
1357  for( unsigned int i=0; i<_nsub; i++ )
1358  _ccsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i] + Op<T>::u(MC1._I) * MC2._ccsub[i];
1359  }
1360  else{
1361  _cc = cc2;
1362  for( unsigned int i=0; i<_nsub; i++ )
1363  _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._ccsub[i];
1364  }
1365  return *this;
1366 }
1367 
1368 template <typename T> inline McCormick<T>&
1369 McCormick<T>::_mul1_u1pos_u2mix
1370 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
1371 {
1372  _I = MC1._I * MC2._I;
1373 
1374  double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
1375  - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
1376  double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv
1377  - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
1378  if ( cv1 > cv2 ){
1379  _cv = cv1;
1380  for( unsigned int i=0; i<_nsub; i++ )
1381  _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i];
1382  }
1383  else{
1384  _cv = cv2;
1385  for( unsigned int i=0; i<_nsub; i++ )
1386  _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i];
1387  }
1388 
1389  double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc
1390  - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
1391  double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
1392  - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
1393  if ( cc1 < cc2 ){
1394  _cc = cc1;
1395  for( unsigned int i=0; i<_nsub; i++ )
1396  _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i];
1397  }
1398  else{
1399  _cc = cc2;
1400  for( unsigned int i=0; i<_nsub; i++ )
1401  _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i];
1402  }
1403  return *this;
1404 }
1405 
1406 template <typename T> inline McCormick<T>&
1407 McCormick<T>::_mul2_u1pos_u2mix
1408 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
1409 {
1410  _I = MC1._I * MC2._I;
1411 
1412  double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
1413  - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
1414  double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv
1415  - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
1416  if ( cv1 > cv2 ){
1417  _cv = cv1;
1418  for( unsigned int i=0; i<_nsub; i++ )
1419  _cvsub[i] = Op<T>::u(MC1._I) * MC2._cvsub[i];
1420  }
1421  else{
1422  _cv = cv2;
1423  for( unsigned int i=0; i<_nsub; i++ )
1424  _cvsub[i] = Op<T>::l(MC1._I) * MC2._cvsub[i];
1425  }
1426 
1427  double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc
1428  - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
1429  double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
1430  - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
1431  if ( cc1 < cc2 ){
1432  _cc = cc1;
1433  for( unsigned int i=0; i<_nsub; i++ )
1434  _ccsub[i] = Op<T>::u(MC1._I) * MC2._ccsub[i];
1435  }
1436  else{
1437  _cc = cc2;
1438  for( unsigned int i=0; i<_nsub; i++ )
1439  _ccsub[i] = Op<T>::l(MC1._I) * MC2._ccsub[i];
1440  }
1441  return *this;
1442 }
1443 
1444 template <typename T> inline McCormick<T>&
1445 McCormick<T>::_mul3_u1pos_u2mix
1446 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
1447 {
1448  _I = MC1._I * MC2._I;
1449 
1450  double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
1451  - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
1452  double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv
1453  - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
1454  if ( cv1 > cv2 ){
1455  _cv = cv1;
1456  for( unsigned int i=0; i<_nsub; i++ )
1457  _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._cvsub[i];
1458  }
1459  else{
1460  _cv = cv2;
1461  for( unsigned int i=0; i<_nsub; i++ )
1462  _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._cvsub[i];
1463  }
1464 
1465  double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc
1466  - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
1467  double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
1468  - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
1469  if ( cc1 < cc2 ){
1470  _cc = cc1;
1471  for( unsigned int i=0; i<_nsub; i++ )
1472  _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._ccsub[i];
1473  }
1474  else{
1475  _cc = cc2;
1476  for( unsigned int i=0; i<_nsub; i++ )
1477  _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._ccsub[i];
1478  }
1479  return *this;
1480 }
1481 
1482 template <typename T> inline McCormick<T>&
1483 McCormick<T>::_mul1_u1mix_u2mix
1484 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
1485 {
1486  _I = MC1._I * MC2._I;
1487 
1488  double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
1489  - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
1490  double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
1491  - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
1492  if ( cv1 > cv2 ){
1493  _cv = cv1;
1494  for( unsigned int i=0; i<_nsub; i++ )
1495  _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i];
1496  }
1497  else{
1498  _cv = cv2;
1499  for( unsigned int i=0; i<_nsub; i++ )
1500  _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i];
1501  }
1502 
1503  double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc
1504  - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
1505  double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv
1506  - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
1507  if ( cc1 < cc2 ){
1508  _cc = cc1;
1509  for( unsigned int i=0; i<_nsub; i++ )
1510  _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i];
1511  }
1512  else{
1513  _cc = cc2;
1514  for( unsigned int i=0; i<_nsub; i++ )
1515  _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i];
1516  }
1517  return *this;
1518 }
1519 
1520 template <typename T> inline McCormick<T>&
1521 McCormick<T>::_mul2_u1mix_u2mix
1522 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
1523 {
1524  _I = MC1._I * MC2._I;
1525 
1526  double cv1 = Op<T>::u(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cv
1527  - Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
1528  double cv2 = Op<T>::l(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cc
1529  - Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
1530  if ( cv1 > cv2 ){
1531  _cv = cv1;
1532  for( unsigned int i=0; i<_nsub; i++ )
1533  _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._cvsub[i];
1534  }
1535  else{
1536  _cv = cv2;
1537  for( unsigned int i=0; i<_nsub; i++ )
1538  _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._ccsub[i];
1539  }
1540 
1541  double cc1 = Op<T>::l(MC2._I) * MC1._cv + Op<T>::u(MC1._I) * MC2._cc
1542  - Op<T>::u(MC1._I) * Op<T>::l(MC2._I);
1543  double cc2 = Op<T>::u(MC2._I) * MC1._cc + Op<T>::l(MC1._I) * MC2._cv
1544  - Op<T>::l(MC1._I) * Op<T>::u(MC2._I);
1545  if ( cc1 < cc2 ){
1546  _cc = cc1;
1547  for( unsigned int i=0; i<_nsub; i++ )
1548  _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i] + Op<T>::u(MC1._I) * MC2._ccsub[i];
1549  }
1550  else{
1551  _cc = cc2;
1552  for( unsigned int i=0; i<_nsub; i++ )
1553  _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i] + Op<T>::l(MC1._I) * MC2._cvsub[i];
1554  }
1555  return *this;
1556 }
1557 
1558 template <typename T> inline McCormick<T>&
1559 McCormick<T>::_mulMV
1560 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
1561 {
1562  // Convex underestimator part
1563  {const double k = - Op<T>::diam(MC2._I) / Op<T>::diam(MC1._I);
1564  const double z = ( Op<T>::u(MC1._I)*Op<T>::u(MC2._I)
1565  - Op<T>::l(MC1._I)*Op<T>::l(MC2._I) )
1566  / Op<T>::diam(MC1._I);
1567  struct fct{
1568  static double t1
1569  ( const double x1, const double x2, const McCormick<T>&MC1,
1570  const McCormick<T>&MC2 )
1571  { return Op<T>::u(MC2._I) * x1 + Op<T>::u(MC1._I) * x2
1572  - Op<T>::u(MC2._I) * Op<T>::u(MC1._I); }
1573  static double t2
1574  ( const double x1, const double x2, const McCormick<T>&MC1,
1575  const McCormick<T>&MC2 )
1576  { return Op<T>::l(MC2._I) * x1 + Op<T>::l(MC1._I) * x2
1577  - Op<T>::l(MC2._I) * Op<T>::l(MC1._I); }
1578  static double t
1579  ( const double x1, const double x2, const McCormick<T>&MC1,
1580  const McCormick<T>&MC2 )
1581  { return std::max( t1(x1,x2,MC1,MC2), t2(x1,x2,MC1,MC2) ); }
1582  };
1583 
1584  int imid[4] = { -1, -1, -1, -1 };
1585  const double x1t[4] = { MC1._cv, MC1._cc,
1586  mid( MC1._cv, MC1._cc, (MC2._cv-z)/k, imid[0] ),
1587  mid( MC1._cv, MC1._cc, (MC2._cc-z)/k, imid[1] ) };
1588  const double x2t[4] = { mid( MC2._cv, MC2._cc, k*MC1._cv+z, imid[2] ),
1589  mid( MC2._cv, MC2._cc, k*MC1._cc+z, imid[3] ),
1590  MC2._cv, MC2._cc };
1591  const double v[4] = { fct::t( x1t[0], x2t[0], MC1, MC2 ), fct::t( x1t[1], x2t[1], MC1, MC2 ),
1592  fct::t( x1t[2], x2t[2], MC1, MC2 ), fct::t( x1t[3], x2t[3], MC1, MC2 ) };
1593  const unsigned int ndx = argmin( 4, v );
1594  _cv = v[ndx];
1595 
1596  if( _nsub ){
1597  double myalpha;
1598  if( isequal( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ),
1599  fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ),
1600  options.MVCOMP_TOL, options.MVCOMP_TOL ) ){
1601  std::pair<double,double> alpha( 0., 1. );
1602  bool MC1thin = isequal( MC1._cv, MC1._cc, options.MVCOMP_TOL, options.MVCOMP_TOL )?
1603  true: false;
1604  if( !MC1thin && x1t[ndx] > MC1._cv )
1605  alpha.second = std::min( alpha.second, -Op<T>::l(MC2._I)/Op<T>::diam(MC2._I) );
1606  if( !MC1thin && x1t[ndx] < MC1._cc )
1607  alpha.first = std::max( alpha.first, -Op<T>::l(MC2._I)/Op<T>::diam(MC2._I) );
1608  bool MC2thin = isequal( MC2._cv, MC2._cc, options.MVCOMP_TOL, options.MVCOMP_TOL )?
1609  true: false;
1610  if( !MC2thin && x2t[ndx] > MC2._cv )
1611  alpha.second = std::min( alpha.second, -Op<T>::l(MC1._I)/Op<T>::diam(MC1._I) );
1612  if( !MC2thin && x2t[ndx] < MC2._cc )
1613  alpha.first = std::max( alpha.first, -Op<T>::l(MC1._I)/Op<T>::diam(MC1._I) );
1614  bool alphathin = isequal( alpha.first, alpha.second, options.MVCOMP_TOL, options.MVCOMP_TOL )?
1615  true: false;
1616  if( !alphathin && alpha.first > alpha.second ){
1617  std::cout << "WARNING1: alphaL= " << alpha.first << " alphaU= " << alpha.second
1618  << std::endl;
1619  throw Exceptions( Exceptions::MULTSUB );
1620  }
1621  myalpha = 0.5*( alpha.first + alpha.second );
1622  }
1623  else if( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ) > fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ) )
1624  myalpha = 1.;
1625  else
1626  myalpha = 0.;
1627  double sigma1cv = Op<T>::l(MC2._I) + myalpha * Op<T>::diam(MC2._I),
1628  sigma2cv = Op<T>::l(MC1._I) + myalpha * Op<T>::diam(MC1._I);
1629  for( unsigned int i=0; i<_nsub; i++ )
1630  _cvsub[i] = ( sigma1cv>=0? (MC1._const? 0.:MC1._cvsub[i]):
1631  (MC1._const? 0.:MC1._ccsub[i]) ) * sigma1cv
1632  + ( sigma2cv>=0? (MC2._const? 0.:MC2._cvsub[i]):
1633  (MC2._const? 0.:MC2._ccsub[i]) ) * sigma2cv;
1634  }
1635  }
1636 
1637  // Concave overestimator part
1638  {const double k = Op<T>::diam(MC2._I) / Op<T>::diam(MC1._I);
1639  const double z = ( Op<T>::u(MC1._I)*Op<T>::l(MC2._I)
1640  - Op<T>::l(MC1._I)*Op<T>::u(MC2._I) )
1641  / Op<T>::diam(MC1._I);
1642  struct fct{
1643  static double t1
1644  ( const double x1, const double x2, const McCormick<T>&MC1,
1645  const McCormick<T>&MC2 )
1646  { return Op<T>::l(MC2._I) * x1 + Op<T>::u(MC1._I) * x2
1647  - Op<T>::l(MC2._I) * Op<T>::u(MC1._I); }
1648  static double t2
1649  ( const double x1, const double x2, const McCormick<T>&MC1,
1650  const McCormick<T>&MC2 )
1651  { return Op<T>::u(MC2._I) * x1 + Op<T>::l(MC1._I) * x2
1652  - Op<T>::u(MC2._I) * Op<T>::l(MC1._I); }
1653  static double t
1654  ( const double x1, const double x2, const McCormick<T>&MC1,
1655  const McCormick<T>&MC2 )
1656  { return std::min( t1(x1,x2,MC1,MC2), t2(x1,x2,MC1,MC2) ); }
1657  };
1658 
1659  int imid[4] = { -1, -1, -1, -1 };
1660  const double x1t[4] = { MC1._cv, MC1._cc,
1661  mid( MC1._cv, MC1._cc, (MC2._cv-z)/k, imid[0] ),
1662  mid( MC1._cv, MC1._cc, (MC2._cc-z)/k, imid[1] ) };
1663  const double x2t[4] = { mid( MC2._cv, MC2._cc, k*MC1._cv+z, imid[2] ),
1664  mid( MC2._cv, MC2._cc, k*MC1._cc+z, imid[3] ),
1665  MC2._cv, MC2._cc };
1666  const double v[4] = { fct::t( x1t[0], x2t[0], MC1, MC2 ), fct::t( x1t[1], x2t[1], MC1, MC2 ),
1667  fct::t( x1t[2], x2t[2], MC1, MC2 ), fct::t( x1t[3], x2t[3], MC1, MC2 ) };
1668  const unsigned int ndx = argmax( 4, v );
1669  _cc = v[ndx];
1670 
1671  if( _nsub ){
1672  double myalpha;
1673  if( isequal( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ),
1674  fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ),
1675  options.MVCOMP_TOL, options.MVCOMP_TOL ) ){
1676  std::pair<double,double> alpha( 0., 1. );
1677  bool MC1thin = isequal( MC1._cv, MC1._cc, options.MVCOMP_TOL, options.MVCOMP_TOL )?
1678  true: false;
1679  if( !MC1thin && x1t[ndx] > MC1._cv )
1680  alpha.first = std::max( alpha.first, -Op<T>::l(MC2._I)/Op<T>::diam(MC2._I) );
1681  if( !MC1thin && x1t[ndx] < MC1._cc )
1682  alpha.second = std::min( alpha.second, -Op<T>::l(MC2._I)/Op<T>::diam(MC2._I) );
1683  bool MC2thin = isequal( MC2._cv, MC2._cc, options.MVCOMP_TOL, options.MVCOMP_TOL )?
1684  true: false;
1685  if( !MC2thin && x2t[ndx] > MC2._cv )
1686  alpha.second = std::min( alpha.second, Op<T>::u(MC1._I)/Op<T>::diam(MC1._I) );
1687  if( !MC2thin && x2t[ndx] < MC2._cc )
1688  alpha.first = std::max( alpha.first, Op<T>::u(MC1._I)/Op<T>::diam(MC1._I) );
1689  bool alphathin = isequal( alpha.first, alpha.second, options.MVCOMP_TOL, options.MVCOMP_TOL )?
1690  true: false;
1691  if( !alphathin && alpha.first > alpha.second ){
1692  std::cout << "WARNING2: alphaL= " << alpha.first << " alphaU= " << alpha.second
1693  << std::endl;
1694  throw Exceptions( Exceptions::MULTSUB );
1695  }
1696  myalpha = 0.5*( alpha.first + alpha.second );
1697  }
1698  else if( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ) < fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ) )
1699  myalpha = 0.;
1700  else
1701  myalpha = 1.;
1702  double sigma1cc = Op<T>::l(MC2._I) + myalpha * Op<T>::diam(MC2._I),
1703  sigma2cc = Op<T>::u(MC1._I) - myalpha * Op<T>::diam(MC1._I);
1704  for( unsigned int i=0; i<_nsub; i++ )
1705  _ccsub[i] = ( sigma1cc>=0? (MC1._const? 0.:MC1._ccsub[i]):
1706  (MC1._const? 0.:MC1._cvsub[i]) ) * sigma1cc
1707  + ( sigma2cc>=0? (MC2._const? 0.:MC2._ccsub[i]):
1708  (MC2._const? 0.:MC2._cvsub[i]) ) * sigma2cc;
1709  }
1710  }
1711 
1712  return *this;
1713 }
1714 
1715 template <typename T> inline McCormick<T>&
1716 McCormick<T>::operator/=
1717 ( const double a )
1718 {
1719  McCormick<T> MC2 = (*this) / a;
1720  *this = MC2;
1721  return *this;
1722 }
1723 
1724 template <typename T> inline McCormick<T>&
1725 McCormick<T>::operator/=
1726 ( const McCormick<T>&MC )
1727 {
1728  if( _const && !MC._const ) sub( MC._nsub );
1729  McCormick<T> MC2 = (*this) / MC;
1730  *this = MC2;
1731  return *this;
1732 }
1733 
1734 template <typename T> inline double*
1735 McCormick<T>::_erfcv
1736 ( const double x, const double xL, const double xU )
1737 {
1738  static double cv[2];
1739  if( xU <= 0. ){ // convex part
1740  cv[0] = ::erf(x), cv[1] = 2./std::sqrt(PI)*std::exp(-sqr(x));
1741  return cv;
1742  }
1743 
1744  if( xL >= 0. ){ // concave part
1745  double r = ( isequal( xL, xU )? 0.:(::erf(xU)-::erf(xL))/(xU-xL) );
1746  cv[0] = ::erf(xL)+r*(x-xL), cv[1] = r;
1747  return cv;
1748  }
1749 
1750  double xj;
1751  try{
1752  xj = _newton( xL, xL, 0., _erfenv_func, _erfenv_dfunc, &xU );
1753  }
1754  catch( McCormick<T>::Exceptions ){
1755  xj = _goldsect( xL, 0., _erfenv_func, &xU, 0 );
1756  }
1757  if( x <= xj ){ // convex part
1758  cv[0] = ::erf(x), cv[1] = 2./std::sqrt(PI)*std::exp(-sqr(x));
1759  return cv;
1760  }
1761  double r = ( isequal( xj, xU )? 0.:(::erf(xU)-::erf(xj))/(xU-xj) );
1762  cv[0] = ::erf(xU)+r*(x-xU), cv[1] = r;
1763  return cv;
1764 }
1765 
1766 template <typename T> inline double*
1767 McCormick<T>::_erfcc
1768 ( const double x, const double xL, const double xU )
1769 {
1770  static double cc[2];
1771  if( xU <= 0. ){ // convex part
1772  double r = ( isequal( xL, xU )? 0.:(::erf(xU)-::erf(xL))/(xU-xL) );
1773  cc[0] = ::erf(xL)+r*(x-xL), cc[1] = r;
1774  return cc;
1775  }
1776 
1777  if( xL >= 0. ){ // concave part
1778  cc[0] = ::erf(x), cc[1] = 2./std::sqrt(PI)*std::exp(-sqr(x));
1779  return cc;
1780  }
1781 
1782  double xj;
1783  try{
1784  xj = _newton( xU, 0., xU, _erfenv_func, _erfenv_dfunc, &xL );
1785  }
1786  catch( McCormick<T>::Exceptions ){
1787  xj = _goldsect( 0., xU, _erfenv_func, &xL, 0 );
1788  }
1789  if( x >= xj ){ // concave part
1790  cc[0] = ::erf(x), cc[1] = 2./std::sqrt(PI)*std::exp(-sqr(x));
1791  return cc;
1792  }
1793  double r = ( isequal( xj, xL )? 0.:(::erf(xL)-::erf(xj))/(xL-xj) );
1794  cc[0] = ::erf(xL)+r*(x-xL), cc[1] = r;
1795  return cc;
1796 }
1797 
1798 template <typename T> inline double
1799 McCormick<T>::_erfenv_func
1800 ( const double x, const double*rusr, const int*iusr )
1801 {
1802  // f(z) = (z-a)*exp(-z^2)-sqrt(pi)/2.*(erf(z)-erf(a)) = 0
1803  return (x-*rusr)*std::exp(-sqr(x))-std::sqrt(PI)/2.*(::erf(x)-::erf(*rusr));
1804 }
1805 
1806 template <typename T> inline double
1807 McCormick<T>::_erfenv_dfunc
1808 ( const double x, const double*rusr, const int*iusr )
1809 {
1810  // f'(z) = -2*z*(z-a)*exp(-z^2)
1811  return -2.*x*(x-*rusr)*std::exp(-2.*sqr(x));
1812 }
1813 
1814 template <typename T> inline double*
1815 McCormick<T>::_atancv
1816 ( const double x, const double xL, const double xU )
1817 {
1818  static double cv[2];
1819  if( xU <= 0. ){ // convex part
1820  cv[0] = std::atan(x), cv[1] = 1./(1.+sqr(x));
1821  return cv;
1822  }
1823 
1824  if( xL >= 0. ){ // concave part
1825  double r = ( isequal( xL, xU )? 0.:(std::atan(xU)-std::atan(xL))/(xU-xL) );
1826  cv[0] = std::atan(xL)+r*(x-xL), cv[1] = r;
1827  return cv;
1828  }
1829 
1830  double xj;
1831  try{
1832  xj = _newton( xL, xL, 0., _atanenv_func, _atanenv_dfunc, &xU, 0 );
1833  }
1834  catch( McCormick<T>::Exceptions ){
1835  xj = _goldsect( xL, 0., _atanenv_func, &xU, 0 );
1836  }
1837  if( x <= xj ){ // convex part
1838  cv[0] = std::atan(x), cv[1] = 1./(1.+sqr(x));
1839  return cv;
1840  }
1841  double r = ( isequal( xj, xU )? 0.:(std::atan(xU)-std::atan(xj))/(xU-xj) );
1842  cv[0] = std::atan(xU)+r*(x-xU), cv[1] = r;
1843  return cv;
1844 }
1845 
1846 template <typename T> inline double*
1847 McCormick<T>::_atancc
1848 ( const double x, const double xL, const double xU )
1849 {
1850  static double cc[2];
1851  if( xU <= 0. ){ // convex part
1852  double r = ( isequal( xL, xU )? 0.:(std::atan(xU)-std::atan(xL))/(xU-xL) );
1853  cc[0] = std::atan(xL)+r*(x-xL), cc[1] = r;
1854  return cc;
1855  }
1856 
1857  if( xL >= 0. ){ // concave part
1858  cc[0] = std::atan(x), cc[1] = 1./(1.+sqr(x));
1859  return cc;
1860  }
1861 
1862  double xj;
1863  try{
1864  xj = _newton( xU, 0., xU, _atanenv_func, _atanenv_dfunc, &xL, 0 );
1865  }
1866  catch( McCormick<T>::Exceptions ){
1867  xj = _goldsect( 0., xU, _atanenv_func, &xL, 0 );
1868  }
1869  if( x >= xj ){ // concave part
1870  cc[0] = std::atan(x), cc[1] = 1./(1.+sqr(x));
1871  return cc;
1872  }
1873  double r = ( isequal( xj, xL )? 0.:(std::atan(xL)-std::atan(xj))/(xL-xj) );
1874  cc[0] = std::atan(xL)+r*(x-xL), cc[1] = r;
1875  return cc;
1876 }
1877 
1878 template <typename T> inline double
1879 McCormick<T>::_atanenv_func
1880 ( const double x, const double*rusr, const int*iusr )
1881 {
1882  // f(z) = z-a-(1+z^2)*(asin(z)-asin(a)) = 0
1883  return (x-*rusr)-(1.+sqr(x))*(std::atan(x)-std::atan(*rusr));
1884 }
1885 
1886 template <typename T> inline double
1887 McCormick<T>::_atanenv_dfunc
1888 ( const double x, const double*rusr, const int*iusr )
1889 {
1890  // f'(z) = -2*z*(asin(z)-asin(a))
1891  return -2.*x*(std::atan(x)-std::atan(*rusr));
1892 }
1893 
1894 template <typename T> inline double*
1895 McCormick<T>::_oddpowcv
1896 ( const double x, const int iexp, const double xL, const double xU )
1897 {
1898  static double cv[2];
1899  if( xL >= 0. ){ // convex part
1900  double v = std::pow(x,iexp-1);
1901  cv[0] = x*v, cv[1] = iexp*v;
1902  return cv;
1903  }
1904 
1905  if( xU <= 0. ){ // concave part
1906  double r = ( isequal( xL, xU )? 0.:
1907  (std::pow(xU,iexp)-std::pow(xL,iexp))/(xU-xL) );
1908  cv[0] = std::pow(xL,iexp)+r*(x-xL), cv[1] = r;
1909  return cv;
1910  }
1911 
1912  double xj;
1913  try{
1914  xj = _newton( xU, 0., xU, _oddpowenv_func, _oddpowenv_dfunc, &xL, &iexp );
1915  }
1916  catch( McCormick<T>::Exceptions ){
1917  xj = _goldsect( 0., xU, _oddpowenv_func, &xL, &iexp );
1918  }
1919  if( x >= xj ){ // convex part
1920  double v = std::pow(x,iexp-1);
1921  cv[0] = x*v, cv[1] = iexp*v;
1922  return cv;
1923  }
1924  double r = ( isequal( xL, xj )? 0.:
1925  (std::pow(xj,iexp)-std::pow(xL,iexp))/(xj-xL) );
1926  cv[0] = std::pow(xL,iexp)+r*(x-xL), cv[1] = r;
1927  return cv;
1928 }
1929 
1930 template <typename T> inline double*
1931 McCormick<T>::_oddpowcc
1932 ( const double x, const int iexp, const double xL, const double xU )
1933 {
1934  static double cc[2];
1935  if( xL >= 0. ){ // convex part
1936  double r = ( isequal( xL, xU )? 0.:
1937  (std::pow(xU,iexp)-std::pow(xL,iexp))/(xU-xL) );
1938  cc[0] = std::pow(xL,iexp)+r*(x-xL), cc[1] = r;
1939  return cc;
1940  }
1941  if( xU <= 0. ){ // concave part
1942  double v = std::pow(x,iexp-1);
1943  cc[0] = x*v, cc[1] = iexp*v;
1944  return cc;
1945  }
1946 
1947  double xj;
1948  try{
1949  xj = _newton( xL, xL, 0., _oddpowenv_func, _oddpowenv_dfunc, &xU, &iexp );
1950  }
1951  catch( McCormick<T>::Exceptions ){
1952  xj = _goldsect( xL, 0., _oddpowenv_func, &xU, &iexp );
1953  }
1954  if( x <= xj ){ // concave part
1955  double v = std::pow(x,iexp-1);
1956  cc[0] = x*v, cc[1] = iexp*v;
1957  return cc;
1958  }
1959  double r = ( isequal( xU, xj )? 0.:
1960  (std::pow(xj,iexp)-std::pow(xU,iexp))/(xj-xU) );
1961  cc[0] = std::pow(xU,iexp)+r*(x-xU), cc[1] = r;
1962  return cc;
1963 }
1964 
1965 template <typename T> inline double
1966 McCormick<T>::_oddpowenv_func
1967 ( const double x, const double*rusr, const int*iusr )
1968 {
1969  // f(z) = (p-1)*z^p - a*p*z^{p-1} + a^p = 0
1970  return ((*iusr-1)*x-(*rusr)*(*iusr))*std::pow(x,*iusr-1)
1971  + std::pow(*rusr,*iusr);
1972 }
1973 
1974 template <typename T> inline double
1975 McCormick<T>::_oddpowenv_dfunc
1976 ( const double x, const double*rusr, const int*iusr )
1977 {
1978  // f'(z) = p*(p-1)*z^{p-1} - a*p*(p-1)*z^{p-2}
1979  return ((*iusr)*(*iusr-1)*x-(*rusr)*(*iusr)*(*iusr-1))*std::pow(x,*iusr-2);
1980 }
1981 
1982 template <typename T> inline double*
1983 McCormick<T>::_stepcv
1984 ( const double x, const double xL, const double xU )
1985 {
1986  static double cv[2];
1987 
1988  if( x < 0. ){
1989  cv[0] = cv[1] = 0.;
1990  return cv;
1991  }
1992 
1993  if( xL >= 0. ){
1994  cv[0] = 1., cv[1] = 0.;
1995  return cv;
1996  }
1997 
1998  cv[0] = x/xU, cv[1] = 1./xU;
1999  return cv;
2000 }
2001 
2002 template <typename T> inline double*
2003 McCormick<T>::_stepcc
2004 ( const double x, const double xL, const double xU )
2005 {
2006  static double cc[2];
2007 
2008  if( x >= 0. ){
2009  cc[0] = 1., cc[1] = 0.;
2010  return cc;
2011  }
2012 
2013  else if( xU < 0. ){
2014  cc[0] = 0., cc[1] = 0.;
2015  return cc;
2016  }
2017 
2018  cc[0] = 1.-x/xL, cc[1] = -1./xL;
2019  return cc;
2020 }
2021 
2022 template <typename T> inline double*
2023 McCormick<T>::_cosarg
2024 ( const double xL, const double xU )
2025 {
2026  static double arg[2];
2027  const int kL = std::ceil(-(1.+xL/PI)/2.);
2028  const double xL1 = xL+2.*PI*kL, xU1 = xU+2.*PI*kL;
2029  assert( xL1 >= -PI && xL1 <= PI );
2030  if( xL1 <= 0 ){
2031  if( xU1 <= 0 ) arg[0] = xL, arg[1] = xU;
2032  else if( xU1 >= PI ) arg[0] = PI*(1.-2.*kL), arg[1] = -PI*2.*kL;
2033  else arg[0] = std::cos(xL1)<=std::cos(xU1)?xL:xU, arg[1] = -PI*2.*kL;
2034  return arg;
2035  }
2036  if( xU1 <= PI ) arg[0] = xU, arg[1] = xL;
2037  else if( xU1 >= 2.*PI ) arg[0] = PI*(1-2.*kL), arg[1] = 2.*PI*(1.-kL);
2038  else arg[0] = PI*(1.-2.*kL), arg[1] = std::cos(xL1)>=std::cos(xU1)?xL:xU;
2039  return arg;
2040 }
2041 
2042 template <typename T> inline double*
2043 McCormick<T>::_coscv
2044 ( const double x, const double xL, const double xU )
2045 {
2046  static double cv[2];
2047  const int kL = std::ceil(-(1.+xL/PI)/2.);
2048  if( x <= PI*(1-2*kL) ){
2049  const double xL1 = xL+2.*PI*kL;
2050  if( xL1 >= 0.5*PI ){
2051  cv[0] = std::cos(x), cv[1] = -std::sin(x);
2052  return cv;
2053  }
2054  const double xU1 = std::min(xU+2.*PI*kL,PI);
2055  if( xL1 >= -0.5*PI && xU1 <= 0.5*PI ){
2056  double r = ( isequal( xL, xU )? 0.: (std::cos(xU)-std::cos(xL))/(xU-xL) );
2057  cv[0] = std::cos(xL)+r*(x-xL), cv[1] = r;
2058  return cv;
2059  }
2060  return _coscv2( x+2.*PI*kL, xL1, xU1 );
2061  }
2062 
2063  const int kU = std::floor((1.-xU/PI)/2.);
2064  if( x >= PI*(-1-2*kU) ){
2065  const double xU2 = xU+2.*PI*kU;
2066  if( xU2 <= -0.5*PI ){
2067  cv[0] = std::cos(x), cv[1] = -std::sin(x);
2068  return cv;
2069  }
2070  return _coscv2( x+2.*PI*kU, std::max(xL+2.*PI*kU,-PI), xU2 );
2071  }
2072 
2073  cv[0] = -1., cv[1] = 0.;
2074  return cv;
2075 }
2076 
2077 template <typename T> inline double*
2078 McCormick<T>::_coscv2
2079 ( const double x, const double xL, const double xU )
2080 {
2081  bool left;
2082  double x0, xm;
2083  if( std::fabs(xL)<=std::fabs(xU) )
2084  left = false, x0 = xU, xm = xL;
2085  else
2086  left = true, x0 = xL, xm = xU;
2087 
2088  double xj;
2089  try{
2090  xj = _newton( x0, xL, xU, _cosenv_func, _cosenv_dfunc, &xm, 0 );
2091  }
2092  catch( McCormick<T>::Exceptions ){
2093  xj = _goldsect( xL, xU, _cosenv_func, &xm, 0 );
2094  }
2095  static double cv[2];
2096  if(( left && x<=xj ) || ( !left && x>=xj )){
2097  cv[0] = std::cos(x), cv[1] = -std::sin(x);
2098  return cv;
2099  }
2100  double r = ( isequal( xm, xj )? 0.: (std::cos(xm)-std::cos(xj))/(xm-xj) );
2101  cv[0] = std::cos(xm)+r*(x-xm), cv[1] = r;
2102  return cv;
2103 }
2104 
2105 template <typename T> inline double*
2106 McCormick<T>::_coscc
2107 ( const double x, const double xL, const double xU )
2108 {
2109  static double cc[2];
2110  const double*cvenv = _coscv( x-PI, xL-PI, xU-PI );
2111  cc[0] = -cvenv[0], cc[1] = -cvenv[1];
2112  return cc;
2113 }
2114 
2115 template <typename T> inline double
2116 McCormick<T>::_cosenv_func
2117 ( const double x, const double*rusr, const int*iusr )
2118 
2119 {
2120  // f(z) = (z-a)*sin(z)+cos(z)-cos(a) = 0
2121  return ((x-*rusr)*std::sin(x)+std::cos(x)-std::cos(*rusr));
2122 }
2123 
2124 template <typename T> inline double
2125 McCormick<T>::_cosenv_dfunc
2126 ( const double x, const double*rusr, const int*iusr )
2127 {
2128  // f'(z) = (z-a)*cos(z)
2129  return ((x-*rusr)*std::cos(x));
2130 }
2131 
2132 template <typename T> inline double*
2133 McCormick<T>::_asincv
2134 ( const double x, const double xL, const double xU )
2135 {
2136  static double cv[2];
2137  if( xL >= 0. ){ // convex part
2138  cv[0] = std::asin(x), cv[1] = 1./std::sqrt(1-x*x);
2139  return cv;
2140  }
2141  if( xU <= 0. ){ // concave part
2142  double r = ( isequal( xL, xU )? 0.: (std::asin(xU)-std::asin(xL))/(xU-xL));
2143  cv[0] = std::asin(xL)+r*(x-xL), cv[1] = r;
2144  return cv;
2145  }
2146 
2147  double xj;
2148  try{
2149  xj = _secant( 0., xU, 0., xU, _asinenv_func, &xL, 0 );
2150  }
2151  catch( McCormick<T>::Exceptions ){
2152  xj = _goldsect( 0., xU, _asinenv_func, &xL, 0 );
2153  }
2154  if( x >= xj ){ // convex part
2155  cv[0] = std::asin(x), cv[1] = 1./std::sqrt(1-x*x);
2156  return cv;
2157  }
2158  double r = ( isequal( xL, xj )? 0.: (std::asin(xj)-std::asin(xL))/(xj-xL));
2159  cv[0] = std::asin(xL)+r*(x-xL), cv[1] = r; // linear part
2160  return cv;
2161 }
2162 
2163 template <typename T> inline double*
2164 McCormick<T>::_asincc
2165 ( const double x, const double xL, const double xU )
2166 {
2167  static double cc[2];
2168  if( xL >= 0. ){ // convex part
2169  double r = ( isequal( xL, xU )? 0.: (std::asin(xU)-std::asin(xL))/(xU-xL));
2170  cc[0] = std::asin(xL)+r*(x-xL), cc[1] = r;
2171  return cc;
2172  }
2173  if( xU <= 0. ){ // concave part
2174  cc[0] = std::asin(x), cc[1] = 1./std::sqrt(1-x*x);
2175  return cc;
2176  }
2177 
2178  double xj;
2179  try{
2180  xj = _secant( 0., xL, xL, 0., _asinenv_func, &xU, 0 );
2181  }
2182  catch( McCormick<T>::Exceptions ){
2183  xj = _goldsect( xL, 0., _asinenv_func, &xU, 0 );
2184  }
2185  if( x <= xj ){ // concave part
2186  cc[0] = std::asin(x), cc[1] = 1./std::sqrt(1-x*x);
2187  return cc;
2188  }
2189  double r = ( isequal( xU, xj )? 0.: (std::asin(xj)-std::asin(xU))/(xj-xU));
2190  cc[0] = std::asin(xU)+r*(x-xU), cc[1] = r; // secant part
2191  return cc;
2192 }
2193 
2194 template <typename T> inline double
2195 McCormick<T>::_asinenv_func
2196 ( const double x, const double*rusr, const int*iusr )
2197 {
2198  // f(z) = z-a-sqrt(1-z^2)*(asin(z)-asin(a)) = 0
2199  return x-(*rusr)-std::sqrt(1.-x*x)*(std::asin(x)-std::asin(*rusr));
2200 }
2201 
2202 template <typename T> inline double
2203 McCormick<T>::_asinenv_dfunc
2204 ( const double x, const double*rusr, const int*iusr )
2205 {
2206  // f'(z) = z/sqrt(1-z^2)*(asin(z)-asin(a))
2207  return x/std::sqrt(1.-x*x)*(std::asin(x)-std::asin(*rusr));
2208 }
2209 
2210 template <typename T> inline double*
2211 McCormick<T>::_tancv
2212 ( const double x, const double xL, const double xU )
2213 {
2214  static double cv[2];
2215  if( xL >= 0. ){ // convex part
2216  cv[0] = std::tan(x), cv[1] = 1.+sqr(std::tan(x));
2217  return cv;
2218  }
2219  if( xU <= 0. ){ // concave part
2220  double r = ( isequal( xL, xU )? 0.: (std::tan(xU)-std::tan(xL))/(xU-xL));
2221  cv[0] = std::tan(xL)+r*(x-xL), cv[1] = r;
2222  return cv;
2223  }
2224 
2225  double xj;
2226  try{
2227  xj = _secant( 0., xU, 0., xU, _tanenv_func, &xL, 0 );
2228  }
2229  catch( McCormick<T>::Exceptions ){
2230  xj = _goldsect( 0., xU, _tanenv_func, &xL, 0 );
2231  }
2232  if( x >= xj ){ // convex part
2233  cv[0] = std::tan(x), cv[1] = 1.+sqr(std::tan(x));
2234  return cv;
2235  }
2236  double r = ( isequal( xL, xj )? 0.: (std::tan(xj)-std::tan(xL))/(xj-xL));
2237  cv[0] = std::tan(xL)+r*(x-xL), cv[1] = r; // secant part
2238  return cv;
2239 }
2240 
2241 template <typename T> inline double*
2242 McCormick<T>::_tancc
2243 ( const double x, const double xL, const double xU )
2244 {
2245  static double cc[2];
2246  if( xL >= 0. ){ // convex part
2247  double r = ( isequal( xL, xU )? 0.: (std::tan(xU)-std::tan(xL))/(xU-xL));
2248  cc[0] = std::tan(xL)+r*(x-xL), cc[1] = r;
2249  return cc;
2250  }
2251  if( xU <= 0. ){ // concave part
2252  cc[0] = std::tan(x), cc[1] = 1.+sqr(std::tan(x));
2253  return cc;
2254  }
2255 
2256  double xj;
2257  try{
2258  xj = _secant( 0., xL, xL, 0., _tanenv_func, &xU, 0 );
2259  }
2260  catch( McCormick<T>::Exceptions ){
2261  xj = _goldsect( xL, 0., _tanenv_func, &xU, 0 );
2262  }
2263  if( x <= xj ){ // concave part
2264  cc[0] = std::tan(x), cc[1] = 1.+sqr(std::tan(x));
2265  return cc;
2266  }
2267  double r = ( isequal( xU, xj )? 0.: (std::tan(xj)-std::tan(xU))/(xj-xU));
2268  cc[0] = std::tan(xU)+r*(x-xU), cc[1] = r; // secant part
2269  return cc;
2270 }
2271 
2272 template <typename T> inline double
2273 McCormick<T>::_tanenv_func
2274 ( const double x, const double*rusr, const int*iusr )
2275 {
2276  // f(z) = (z-a)-(tan(z)-tan(a))/(1+tan(z)^2) = 0
2277  return (x-(*rusr))-(std::tan(x)-std::tan(*rusr))/(1.+sqr(std::tan(x)));
2278 }
2279 
2280 template <typename T> inline double
2281 McCormick<T>::_tanenv_dfunc
2282 ( const double x, const double*rusr, const int*iusr )
2283 {
2284  // f'(z) = (tan(z)-tan(a))/(1+tan(z)^2)*2*tan(z)
2285  return 2.*std::tan(x)/(1.+sqr(std::tan(x)))*(std::tan(x)-std::tan(*rusr));
2286 }
2287 
2288 template <typename T> inline double
2289 McCormick<T>::_newton
2290 ( const double x0, const double xL, const double xU, puniv f,
2291  puniv df, const double*rusr, const int*iusr )
2292 {
2293  double xk = std::max(xL,std::min(xU,x0));
2294  double fk = f(xk,rusr,iusr);
2295 
2296  for( unsigned int it=0; it<options.ENVEL_MAXIT; it++ ){
2297  if( std::fabs(fk) < options.ENVEL_TOL ) return xk;
2298  double dfk = df(xk,rusr,iusr);
2299  if( dfk == 0 ) throw Exceptions( Exceptions::ENVEL );
2300  if( isequal(xk,xL) && fk/dfk>0 ) return xk;
2301  if( isequal(xk,xU) && fk/dfk<0 ) return xk;
2302  xk = std::max(xL,std::min(xU,xk-fk/dfk));
2303  fk = f(xk,rusr,iusr);
2304  }
2305 
2306  throw Exceptions( Exceptions::ENVEL );
2307 }
2308 
2309 template <typename T> inline double
2310 McCormick<T>::_secant
2311 ( const double x0, const double x1, const double xL, const double xU,
2312  puniv f, const double*rusr, const int*iusr )
2313 {
2314  double xkm = std::max(xL,std::min(xU,x0));
2315  double fkm = f(xkm,rusr,iusr);
2316  double xk = std::max(xL,std::min(xU,x1));
2317 
2318  for( unsigned int it=0; it<options.ENVEL_MAXIT; it++ ){
2319  double fk = f(xk,rusr,iusr);
2320  if( std::fabs(fk) < options.ENVEL_TOL ) return xk;
2321  double Bk = (fk-fkm)/(xk-xkm);
2322  if( Bk == 0 ) throw Exceptions( Exceptions::ENVEL );
2323  if( isequal(xk,xL) && fk/Bk>0 ) return xk;
2324  if( isequal(xk,xU) && fk/Bk<0 ) return xk;
2325  xkm = xk;
2326  fkm = fk;
2327  xk = std::max(xL,std::min(xU,xk-fk/Bk));
2328  }
2329 
2330  throw Exceptions( Exceptions::ENVEL );
2331 }
2332 
2333 template <typename T> inline double
2334 McCormick<T>::_goldsect
2335 ( const double xL, const double xU, puniv f, const double*rusr,
2336  const int*iusr )
2337 {
2338  const double phi = 2.-(1.+std::sqrt(5.))/2.;
2339  const double fL = f(xL,rusr,iusr), fU = f(xU,rusr,iusr);
2340  if( fL*fU > 0 ) throw Exceptions( Exceptions::ENVEL );
2341  const double xm = xU-phi*(xU-xL), fm = f(xm,rusr,iusr);
2342  return _goldsect_iter( true, xL, fL, xm, fm, xU, fU, f, rusr, iusr );
2343 }
2344 
2345 template <typename T> inline double
2346 McCormick<T>::_goldsect_iter
2347 ( const bool init, const double a, const double fa, const double b,
2348  const double fb, const double c, const double fc, puniv f,
2349  const double*rusr, const int*iusr )
2350 // a and c are the current bounds; the minimum is between them.
2351 // b is a center point
2352 {
2353  static unsigned int iter;
2354  iter = ( init? 1: iter+1 );
2355  const double phi = 2.-(1.+std::sqrt(5.))/2.;
2356  bool b_then_x = ( c-b > b-a );
2357  double x = ( b_then_x? b+phi*(c-b): b-phi*(b-a) );
2358  if( std::fabs(c-a) < options.ENVEL_TOL*(std::fabs(b)+std::fabs(x))
2359  || iter > options.ENVEL_MAXIT ) return (c+a)/2.;
2360  double fx = f(x,rusr,iusr);
2361  if( b_then_x )
2362  return( fa*fx<0? _goldsect_iter( false, a, fa, b, fb, x, fx, f, rusr, iusr ):
2363  _goldsect_iter( false, b, fb, x, fx, c, fc, f, rusr, iusr ) );
2364  return( fa*fb<0? _goldsect_iter( false, a, fa, x, fx, b, fb, f, rusr, iusr ):
2365  _goldsect_iter( false, x, fx, b, fb, c, fc, f, rusr, iusr ) );
2366 }
2367 
2369 
2370 template <typename T> inline McCormick<T>
2371 cut
2372 ( const McCormick<T>&MC )
2373 {
2374  McCormick<T> MC2( MC );
2375  return MC2.cut();
2376 }
2377 
2378 template <typename T> inline McCormick<T>
2379 operator+
2380 ( const McCormick<T>&MC )
2381 {
2382  McCormick<T> MC2( MC );
2383  return MC2;
2384 }
2385 
2386 template <typename T> inline McCormick<T>
2387 operator+
2388 ( const double a, const McCormick<T>&MC )
2389 {
2390  McCormick<T> MC2;
2391  MC2._sub( MC._nsub, MC._const );
2392  MC2._I = a + MC._I;
2393  MC2._cv = a + MC._cv;
2394  MC2._cc = a + MC._cc;
2395  for( unsigned int i=0; i<MC2._nsub; i++ ){
2396  MC2._cvsub[i] = MC._cvsub[i];
2397  MC2._ccsub[i] = MC._ccsub[i];
2398  }
2399  return MC2;
2400 }
2401 
2402 template <typename T> inline McCormick<T>
2403 operator+
2404 ( const McCormick<T>&MC, const double a )
2405 {
2406  return a + MC;
2407 }
2408 
2409 template <typename T> inline McCormick<T>
2410 operator+
2411 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
2412 {
2413  if( MC2._const ){
2414  McCormick<T> MC3;
2415  MC3._sub( MC1._nsub, MC1._const );
2416  return MC3._sum1( MC1, MC2 );
2417  }
2418  if( MC1._const ){
2419  McCormick<T> MC3;
2420  MC3._sub( MC2._nsub, MC2._const );
2421  return MC3._sum1( MC2, MC1 );
2422  }
2423  if( MC1._nsub != MC2._nsub )
2424  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
2425  McCormick<T> MC3;
2426  MC3._sub( MC1._nsub, MC1._const||MC2._const );
2427  return MC3._sum2( MC1, MC2 );
2428 }
2429 
2430 template <typename T> inline McCormick<T>
2431 operator-
2432 ( const McCormick<T>&MC )
2433 {
2434  McCormick<T> MC2;
2435  MC2._sub( MC._nsub, MC._const );
2436  MC2._I = -MC._I;
2437  MC2._cv = -MC._cc;
2438  MC2._cc = -MC._cv;
2439  for( unsigned int i=0; i<MC2._nsub; i++ ){
2440  MC2._cvsub[i] = -MC._ccsub[i];
2441  MC2._ccsub[i] = -MC._cvsub[i];
2442  }
2443  return MC2;
2444 }
2445 
2446 template <typename T> inline McCormick<T>
2447 operator-
2448 ( const McCormick<T>&MC, const double a )
2449 {
2450  return MC + (-a);
2451 }
2452 
2453 template <typename T> inline McCormick<T>
2454 operator-
2455 ( const double a, const McCormick<T>&MC )
2456 {
2457  McCormick<T> MC2;
2458  MC2._sub( MC._nsub, MC._const );
2459  MC2._I = a - MC._I;
2460  MC2._cv = a - MC._cc;
2461  MC2._cc = a - MC._cv;
2462  for( unsigned int i=0; i<MC2._nsub; i++ ){
2463  MC2._cvsub[i] = -MC._ccsub[i];
2464  MC2._ccsub[i] = -MC._cvsub[i];
2465  }
2466  return MC2;
2467 }
2468 
2469 template <typename T> inline McCormick<T>
2470 operator-
2471 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
2472 {
2473  if( &MC1 == &MC2 ) return 0;
2474 
2475  if( MC2._const ){
2476  McCormick<T> MC3;
2477  MC3._sub( MC1._nsub, MC1._const );
2478  return MC3._sub1( MC1, MC2 );
2479  }
2480  if( MC1._const ){
2481  McCormick<T> MC3;
2482  MC3._sub( MC2._nsub, MC2._const );
2483  return MC3._sub2( MC1, MC2 );
2484  }
2485  if( MC1._nsub != MC2._nsub )
2486  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
2487  McCormick<T> MC3;
2488  MC3._sub( MC1._nsub, MC1._const||MC2._const );
2489  return MC3._sub3( MC1, MC2 );
2490 }
2491 
2492 template <typename T> inline McCormick<T>
2493 operator*
2494 ( const double a, const McCormick<T>&MC )
2495 {
2496  McCormick<T> MC2;
2497  MC2._sub( MC._nsub, MC._const );
2498  MC2._I = a * MC._I;
2499  if ( a >= 0 ){
2500  MC2._cv = a * MC._cv;
2501  MC2._cc = a * MC._cc;
2502  for( unsigned int i=0; i<MC2._nsub; i++ ){
2503  MC2._cvsub[i] = a * MC._cvsub[i];
2504  MC2._ccsub[i] = a * MC._ccsub[i];
2505  }
2506  }
2507  else{
2508  MC2._cv = a * MC._cc;
2509  MC2._cc = a * MC._cv;
2510  for( unsigned int i=0; i<MC2._nsub; i++ ){
2511  MC2._cvsub[i] = a * MC._ccsub[i];
2512  MC2._ccsub[i] = a * MC._cvsub[i];
2513  }
2514  }
2515  return MC2;
2516 }
2517 
2518 template <typename T> inline McCormick<T>
2519 operator*
2520 ( const McCormick<T>&MC, const double a )
2521 {
2522  return a * MC;
2523 }
2524 
2525 template <typename T> inline McCormick<T>
2526 operator*
2527 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
2528 {
2529  if( &MC1 == &MC2 ) return sqr(MC1);
2530 
2531  bool thin1 = isequal( Op<T>::diam(MC1._I), 0. );
2532  bool thin2 = isequal( Op<T>::diam(MC2._I), 0. );
2533 
2534  if ( McCormick<T>::options.MVCOMP_USE && !(thin1||thin2) ){
2535  McCormick<T> MC3;
2536  if( MC2._const )
2537  MC3._sub( MC1._nsub, MC1._const );
2538  else if( MC1._const )
2539  MC3._sub( MC2._nsub, MC2._const );
2540  else if( MC1._nsub != MC2._nsub )
2541  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
2542  else
2543  MC3._sub( MC1._nsub, MC1._const||MC2._const );
2544 
2545  MC3._I = MC1._I * MC2._I;
2546  return MC3._mulMV( MC1, MC2 ).cut();
2547  }
2548 
2549  if ( Op<T>::l(MC1._I) >= 0. ){
2550  if ( Op<T>::l(MC2._I) >= 0. ){
2551  if( MC2._const ){
2552  McCormick<T> MC3;
2553  MC3._sub( MC1._nsub, MC1._const );
2554  return MC3._mul1_u1pos_u2pos( MC1, MC2 ).cut();
2555  }
2556  if( MC1._const ){
2557  McCormick<T> MC3;
2558  MC3._sub( MC2._nsub, MC2._const );
2559  return MC3._mul1_u1pos_u2pos( MC2, MC1 ).cut();
2560  }
2561  if( MC1._nsub != MC2._nsub )
2562  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
2563  McCormick<T> MC3;
2564  MC3._sub( MC1._nsub, MC1._const||MC2._const );
2565  return MC3._mul2_u1pos_u2pos( MC1, MC2 ).cut();
2566  }
2567  if ( Op<T>::u(MC2._I) <= 0. ){
2568  return -( MC1 * (-MC2) );
2569  }
2570  if( MC2._const ){
2571  McCormick<T> MC3;
2572  MC3._sub( MC1._nsub, MC1._const );
2573  return MC3._mul1_u1pos_u2mix( MC1, MC2 ).cut();
2574  }
2575  if( MC1._const ){
2576  McCormick<T> MC3;
2577  MC3._sub( MC2._nsub, MC2._const );
2578  return MC3._mul2_u1pos_u2mix( MC1, MC2 ).cut();
2579  }
2580  if( MC1._nsub != MC2._nsub )
2581  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
2582  McCormick<T> MC3;
2583  MC3._sub( MC1._nsub, MC1._const||MC2._const );
2584  return MC3._mul3_u1pos_u2mix( MC1, MC2 ).cut();
2585  }
2586 
2587  if ( Op<T>::u(MC1._I) <= 0. ){
2588  if ( Op<T>::l(MC2._I) >= 0. ){
2589  return -( (-MC1) * MC2);
2590  }
2591  if ( Op<T>::u(MC2._I) <= 0. ){
2592  return (-MC1) * (-MC2);
2593  }
2594  return -( MC2 * (-MC1) );
2595  }
2596 
2597  if ( Op<T>::l(MC2._I) >= 0. ){
2598  return MC2 * MC1;
2599  }
2600  if ( Op<T>::u(MC2._I) <= 0. ){
2601  return -( (-MC2) * MC1 );
2602  }
2603  if( MC2._const ){
2604  McCormick<T> MC3;
2605  MC3._sub( MC1._nsub, MC1._const );
2606  return MC3._mul1_u1mix_u2mix( MC1, MC2 ).cut();
2607  }
2608  if( MC1._const ){
2609  McCormick<T> MC3;
2610  MC3._sub( MC2._nsub, MC2._const );
2611  return MC3._mul1_u1mix_u2mix( MC2, MC1 ).cut();
2612  }
2613  if( MC1._nsub != MC2._nsub )
2614  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
2615  McCormick<T> MC3;
2616  MC3._sub( MC1._nsub, MC1._const||MC2._const );
2617  return MC3._mul2_u1mix_u2mix( MC1, MC2 ).cut();
2618 }
2619 
2620 template <typename T> inline McCormick<T>
2621 operator/
2622 ( const McCormick<T>&MC, const double a )
2623 {
2624  if ( isequal( a, 0. ))
2625  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::DIV );
2626  return (1./a) * MC;
2627 }
2628 
2629 template <typename T> inline McCormick<T>
2630 operator/
2631 ( const double a, const McCormick<T>&MC )
2632 {
2633  return a * inv( MC );
2634 }
2635 
2636 template <typename T> inline McCormick<T>
2637 operator/
2638 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
2639 {
2640  if( &MC1 == &MC2 ) return 1.;
2641 
2642  bool posorthant = ( Op<T>::l(MC1._I) >= 0. && Op<T>::l(MC2._I) > 0. );
2643 
2644  if ( McCormick<T>::options.MVCOMP_USE && posorthant){
2645  McCormick<T> MC3;
2646  if( MC2._const )
2647  MC3._sub( MC1._nsub, MC1._const );
2648  else if( MC1._const )
2649  MC3._sub( MC2._nsub, MC2._const );
2650  else if( MC1._nsub != MC2._nsub )
2651  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
2652  else
2653  MC3._sub( MC1._nsub, MC1._const||MC2._const );
2654 
2655  MC3._I = MC1._I / MC2._I;
2656 
2657  int imidcv1 = -1, imidcv2 = -1;
2658  double fmidcv1 = ( mid(MC1._cv, MC1._cc, Op<T>::l(MC1._I), imidcv1)
2659  + std::sqrt(Op<T>::l(MC1._I) * Op<T>::u(MC1._I)) )
2660  / ( std::sqrt(Op<T>::l(MC1._I)) + std::sqrt(Op<T>::u(MC1._I)) );
2661  double fmidcv2 = mid(MC2._cv, MC2._cc, Op<T>::u(MC2._I), imidcv2);
2662  MC3._cv = sqr(fmidcv1) / fmidcv2;
2663  for( unsigned int i=0; i<MC3._nsub; i++ )
2664  MC3._cvsub[i] = 2. * fmidcv1 / fmidcv2
2665  / ( std::sqrt(Op<T>::l(MC1._I)) + std::sqrt(Op<T>::u(MC1._I)) )
2666  * (MC1._const? 0.: mid( MC1._cvsub, MC1._ccsub, i, imidcv1 ))
2667  - sqr( fmidcv1 / fmidcv2 )
2668  * (MC2._const? 0.: mid( MC2._cvsub, MC2._ccsub, i, imidcv2 ));
2669 
2670  int imidcc1 = -1, imidcc2 = -1;
2671  double fmidcc1 = mid(MC1._cv, MC1._cc, Op<T>::l(MC1._I), imidcc1);
2672  double fmidcc2 = mid(MC2._cv, MC2._cc, Op<T>::u(MC2._I), imidcc2);
2673  double gcc1 = Op<T>::u(MC2._I) * fmidcc1 - Op<T>::l(MC1._I) * fmidcc2
2674  + Op<T>::l(MC1._I) * Op<T>::l(MC2._I);
2675  double gcc2 = Op<T>::l(MC2._I) * fmidcc1 - Op<T>::u(MC1._I) * fmidcc2
2676  + Op<T>::u(MC1._I) * Op<T>::u(MC2._I);
2677  if( gcc1 <= gcc2 ){
2678  MC3._cc = gcc1 / ( Op<T>::l(MC2._I) * Op<T>::u(MC2._I) );
2679  for( unsigned int i=0; i<MC3._nsub; i++ )
2680  MC3._ccsub[i] = 1. / Op<T>::l(MC2._I)
2681  * (MC1._const? 0.: mid( MC1._cvsub, MC1._ccsub, i, imidcc1 ))
2682  - Op<T>::l(MC1._I) / ( Op<T>::l(MC2._I) * Op<T>::u(MC2._I) )
2683  * (MC2._const? 0.: mid( MC2._cvsub, MC2._ccsub, i, imidcc2 ));
2684  }
2685  else{
2686  MC3._cc = gcc2 / ( Op<T>::l(MC2._I) * Op<T>::u(MC2._I) );
2687  for( unsigned int i=0; i<MC3._nsub; i++ )
2688  MC3._ccsub[i] = 1. / Op<T>::u(MC2._I)
2689  * (MC1._const? 0.: mid( MC1._cvsub, MC1._ccsub, i, imidcc1 ))
2690  - Op<T>::u(MC1._I) / ( Op<T>::l(MC2._I) * Op<T>::u(MC2._I) )
2691  * (MC2._const? 0.: mid( MC2._cvsub, MC2._ccsub, i, imidcc2 ));
2692  }
2693  return MC3.cut();
2694  }
2695 
2696  return MC1 * inv( MC2 );
2697 }
2698 
2699 template <typename T> inline McCormick<T>
2700 inv
2701 ( const McCormick<T>&MC )
2702 {
2703  if ( Op<T>::l(MC._I) <= 0. && Op<T>::u(MC._I) >= 0. )
2704  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::INV );
2705  McCormick<T> MC2;
2706  MC2._sub( MC._nsub, MC._const );
2707  MC2._I = Op<T>::inv( MC._I );
2708 
2709  if ( Op<T>::l(MC._I) > 0. ){
2710  { int imid = -1;
2711  double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
2712  MC2._cv = 1./vmid;
2713  for( unsigned int i=0; i<MC2._nsub; i++ )
2714  MC2._cvsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid )
2715  / ( vmid * vmid );
2716  }
2717  { int imid = -1;
2718  MC2._cc = 1. / Op<T>::l(MC._I) + 1. / Op<T>::u(MC._I) - mid( MC._cv, MC._cc,
2719  Op<T>::l(MC._I), imid ) / ( Op<T>::l(MC._I) * Op<T>::u(MC._I) );
2720  for( unsigned int i=0; i<MC2._nsub; i++ )
2721  MC2._ccsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid )
2722  / ( Op<T>::l(MC._I) * Op<T>::u(MC._I) );
2723  }
2724  }
2725 
2726  else{
2727  { int imid = -1;
2728  MC2._cv = 1. / Op<T>::l(MC._I) + 1. / Op<T>::u(MC._I) - mid( MC._cv, MC._cc,
2729  Op<T>::u(MC._I), imid ) / ( Op<T>::l(MC._I) * Op<T>::u(MC._I) );
2730  for( unsigned int i=0; i<MC2._nsub; i++ )
2731  MC2._cvsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid )
2732  / ( Op<T>::l(MC._I) * Op<T>::u(MC._I) );
2733  }
2734  { int imid = -1;
2735  double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid);
2736  MC2._cc = 1. / vmid;
2737  for( unsigned int i=0; i<MC2._nsub; i++ )
2738  MC2._ccsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid )
2739  / ( vmid * vmid );
2740  }
2741  }
2742 
2743  return MC2.cut();
2744 }
2745 
2746 template <typename T> inline McCormick<T>
2747 sqr
2748 ( const McCormick<T>&MC )
2749 {
2750  McCormick<T> MC2;
2751  MC2._sub( MC._nsub, MC._const );
2752  MC2._I = Op<T>::sqr( MC._I );
2753  { int imid = -1;
2754  double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), 0., imid );
2755  imid = -1;
2756  MC2._cv = mc::sqr( mid( MC._cv, MC._cc, zmin, imid ) );
2757  for( unsigned int i=0; i<MC2._nsub; i++ )
2758  MC2._cvsub[i] = 2 * mid( MC._cvsub, MC._ccsub, i, imid )
2759  * mid( MC._cv, MC._cc, zmin, imid );
2760  }
2761 
2762  { int imid = -1;
2763  double zmax = (mc::sqr( Op<T>::l(MC._I) )>mc::sqr( Op<T>::u(MC._I) )?
2764  Op<T>::l(MC._I): Op<T>::u(MC._I));
2765  double r = ( isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )? 0.:
2766  ( mc::sqr( Op<T>::u(MC._I) ) - mc::sqr( Op<T>::l(MC._I) ) )
2767  / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ) );
2768  MC2._cc = mc::sqr( Op<T>::l(MC._I) ) + r * ( mid( MC._cv, MC._cc, zmax,
2769  imid ) - Op<T>::l(MC._I) );
2770  for( unsigned int i=0; i<MC2._nsub; i++ )
2771  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
2772  }
2773 
2774  return MC2.cut();
2775 }
2776 
2777 template <typename T> inline McCormick<T>
2778 exp
2779 ( const McCormick<T>&MC )
2780 {
2781  McCormick<T> MC2;
2782  MC2._sub( MC._nsub, MC._const );
2783  MC2._I = Op<T>::exp( MC._I );
2784 
2785  { int imid = -1;
2786  MC2._cv = std::exp( mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid ));
2787  for( unsigned int i=0; i<MC2._nsub; i++ )
2788  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * MC2._cv;
2789  }
2790 
2791  { int imid = -1;
2792  double r = 0.;
2793  if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) ))
2794  r = ( std::exp( Op<T>::u(MC._I) ) - std::exp( Op<T>::l(MC._I) ) )
2795  / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) );
2796  MC2._cc = std::exp( Op<T>::u(MC._I) ) + r * ( mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid )
2797  - Op<T>::u(MC._I) );
2798  for( unsigned int i=0; i<MC2._nsub; i++ )
2799  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
2800  }
2801 
2802  return MC2.cut();
2803 }
2804 
2805 template <typename T> inline McCormick<T>
2806 arh
2807 ( const McCormick<T>&MC, const double k )
2808 {
2809  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 ) ){
2810  return exp( - k * inv( MC ) );
2811  }
2812 
2813  McCormick<T> MC2;
2814  MC2._sub( MC._nsub, MC._const );
2815  MC2._I = Op<T>::arh( MC._I, k );
2816 
2817  if ( Op<T>::u(MC._I) <= 0.5*k ){
2818  { int imid = -1;
2819  double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid );
2820  MC2._cv = std::exp( - k / vmid );
2821  for( unsigned int i=0; i<MC2._nsub; i++ )
2822  MC2._cvsub[i] = k / ( vmid * vmid ) * MC2._cv
2823  * mid( MC._cvsub, MC._ccsub, i, imid );
2824  }
2825  { int imid = -1;
2826  double r = 0.;
2827  if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) ))
2828  r = ( mc::arh( Op<T>::u(MC._I) ) - mc::arh( Op<T>::l(MC._I) ) )
2829  / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) );
2830  MC2._cc = mc::arh( Op<T>::l(MC._I) ) + r * ( mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid )
2831  - Op<T>::l(MC._I) );
2832  for( unsigned int i=0; i<MC2._nsub; i++ )
2833  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
2834  }
2835  return MC2.cut();
2836  }
2837 
2838  else if ( Op<T>::l(MC._I) >= 0.5*k ){
2839  { int imid = -1;
2840  double r = 0.;
2841  if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) ))
2842  r = ( mc::arh( Op<T>::u(MC._I) ) - mc::arh( Op<T>::l(MC._I) ) )
2843  / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) );
2844  MC2._cv = mc::arh( Op<T>::l(MC._I) ) + r * ( mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid )
2845  - Op<T>::l(MC._I) );
2846  for( unsigned int i=0; i<MC2._nsub; i++ )
2847  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
2848  }
2849  { int imid = -1;
2850  double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
2851  MC2._cc = std::exp( - k / vmid );
2852  for( unsigned int i=0; i<MC2._nsub; i++ )
2853  MC2._ccsub[i] = k / ( vmid * vmid ) * MC2._cc
2854  * mid( MC._cvsub, MC._ccsub, i, imid );
2855  }
2856  return MC2.cut();
2857  }
2858 }
2859 
2860 template <typename T> inline McCormick<T>
2861 log
2862 ( const McCormick<T>&MC )
2863 {
2864  if ( Op<T>::l(MC._I) <= 0. )
2865  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::LOG );
2866  McCormick<T> MC2;
2867  MC2._sub( MC._nsub, MC._const );
2868  MC2._I = Op<T>::log( MC._I );
2869 
2870  { int imid = -1;
2871  double scal = 0.;
2872  if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) ))
2873  scal = ( std::log( Op<T>::u(MC._I) ) - std::log( Op<T>::l(MC._I) ) )
2874  / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) );
2875  MC2._cv = std::log( Op<T>::l(MC._I) ) + scal * ( mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid )
2876  - Op<T>::l(MC._I) );
2877  for( unsigned int i=0; i<MC2._nsub; i++ )
2878  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * scal;
2879  }
2880 
2881  { int imid = -1;
2882  double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
2883  MC2._cc = std::log( vmid );
2884  for( unsigned int i=0; i<MC2._nsub; i++ )
2885  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) / vmid;
2886  }
2887 
2888  return MC2.cut();
2889 }
2890 
2891 template <typename T> inline McCormick<T>
2892 xlog
2893 ( const McCormick<T>&MC )
2894 {
2895  if ( Op<T>::l(MC._I) <= 0. )
2896  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::LOG );
2897  McCormick<T> MC2;
2898  MC2._sub( MC._nsub, MC._const );
2899  MC2._I = Op<T>::xlog( MC._I );
2900 
2901  { int imid = -1;
2902  double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), std::exp(-1.), imid );
2903  imid = -1;
2904  double vmid = mid( MC._cv, MC._cc, zmin, imid );
2905  MC2._cv = xlog( vmid );
2906  for( unsigned int i=0; i<MC2._nsub; i++ )
2907  MC2._cvsub[i] = (std::log( vmid ) + 1.) * mid( MC._cvsub, MC._ccsub,
2908  i, imid );
2909  }
2910 
2911  { int imid = -1;
2912  double zmax = ( xlog(Op<T>::u(MC._I))>=xlog(Op<T>::l(MC._I))? Op<T>::u(MC._I): Op<T>::l(MC._I) );
2913  double r = 0.;
2914  if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) ))
2915  r = ( xlog(Op<T>::u(MC._I)) - xlog(Op<T>::l(MC._I)) )
2916  / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) );
2917  imid = -1;
2918  MC2._cc = xlog(Op<T>::l(MC._I)) + r * ( mid( MC._cv, MC._cc, zmax, imid ) - Op<T>::l(MC._I) );
2919  for( unsigned int i=0; i<MC2._nsub; i++ )
2920  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
2921  }
2922 
2923  return MC2.cut();
2924 }
2925 
2926 template <typename T> inline McCormick<T>
2927 sqrt
2928 ( const McCormick<T>&MC )
2929 {
2930  if ( Op<T>::l(MC._I) < 0. )
2931  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SQRT );
2932  McCormick<T> MC2;
2933  MC2._sub( MC._nsub, MC._const );
2934  MC2._I = Op<T>::sqrt( MC._I );
2935 
2936  { double r = 0.;
2937  if( !isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) ))
2938  r = ( std::sqrt( Op<T>::u(MC._I) ) - std::sqrt( Op<T>::l(MC._I) ) )
2939  / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) );
2940  int imid = -1;
2941  double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid );
2942  MC2._cv = std::sqrt( Op<T>::l(MC._I) ) + r * ( vmid - Op<T>::l(MC._I) );
2943  for( unsigned int i=0; i<MC2._nsub; i++ )
2944  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
2945  }
2946 
2947  { int imid = -1;
2948  double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
2949  MC2._cc = std::sqrt( vmid );
2950  for( unsigned int i=0; i<MC2._nsub; i++ )
2951  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) / (2.*MC2._cc);
2952  }
2953 
2954  return MC2.cut();
2955 }
2956 
2957 template <typename T> inline McCormick<T>
2958 erfc
2959 ( const McCormick<T> &MC )
2960 {
2961  return ( 1. - erf( MC ) );
2962 }
2963 
2964 template <typename T> inline McCormick<T>
2965 erf
2966 ( const McCormick<T>&MC )
2967 {
2968  McCormick<T> MC2;
2969  MC2._sub( MC._nsub, MC._const );
2970  MC2._I = Op<T>::erf( MC._I );
2971 
2972  if( !McCormick<T>::options.ENVEL_USE ){
2973  MC2._cv = Op<T>::l(MC2._I);
2974  MC2._cc = Op<T>::u(MC2._I);
2975  for( unsigned int i=0; i<MC2._nsub; i++ ){
2976  MC2._cvsub[i] = MC2._ccsub[i] = 0.;
2977  }
2978  return MC2;
2979  }
2980 
2981  { int imid = -1;
2982  const double* cvenv = McCormick<T>::_erfcv( mid( MC._cv,
2983  MC._cc, Op<T>::l(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
2984  MC2._cv = cvenv[0];
2985  for( unsigned int i=0; i<MC2._nsub; i++ ){
2986  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1];
2987  }
2988  }
2989  { int imid = -1;
2990  const double* ccenv = McCormick<T>::_erfcc( mid( MC._cv,
2991  MC._cc, Op<T>::u(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
2992  MC2._cc = ccenv[0];
2993  for( unsigned int i=0; i<MC2._nsub; i++ ){
2994  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
2995  }
2996  }
2997  return MC2.cut();
2998 }
2999 
3000 template <typename T> inline McCormick<T>
3001 pow
3002 ( const McCormick<T>&MC, const int n )
3003 {
3004  if( n == 0 ){
3005  return 1.;
3006  }
3007 
3008  if( n == 1 ){
3009  return MC;
3010  }
3011 
3012  if( n >= 2 && !(n%2) ){
3013  McCormick<T> MC2;
3014  MC2._sub( MC._nsub, MC._const );
3015  MC2._I = Op<T>::pow( MC._I, n );
3016  { int imid = -1;
3017  double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), 0., imid );
3018  imid = -1;
3019  MC2._cv = std::pow( mid( MC._cv, MC._cc, zmin, imid ), n );
3020  for( unsigned int i=0; i<MC2._nsub; i++ )
3021  MC2._cvsub[i] = n * mid( MC._cvsub, MC._ccsub, i, imid )
3022  * std::pow( mid( MC._cv, MC._cc, zmin, imid ), n-1 );
3023  }
3024  { int imid = -1;
3025  double zmax = (std::pow( Op<T>::l(MC._I), n )>std::pow( Op<T>::u(MC._I), n )?
3026  Op<T>::l(MC._I): Op<T>::u(MC._I));
3027  double r = ( isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )? 0.: ( std::pow( Op<T>::u(MC._I),
3028  n ) - std::pow( Op<T>::l(MC._I), n ) ) / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ) );
3029  MC2._cc = std::pow( Op<T>::l(MC._I), n ) + r * ( mid( MC._cv, MC._cc, zmax,
3030  imid ) - Op<T>::l(MC._I) );
3031  for( unsigned int i=0; i<MC2._nsub; i++ )
3032  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
3033  }
3034  return MC2.cut();
3035  }
3036 
3037  if( n >= 3 && McCormick<T>::options.ENVEL_USE ){
3038  McCormick<T> MC2;
3039  MC2._sub( MC._nsub, MC._const );
3040  MC2._I = Op<T>::pow( MC._I, n );
3041  { int imid = -1;
3042  const double* cvenv = McCormick<T>::_oddpowcv( mid( MC._cv,
3043  MC._cc, Op<T>::l(MC._I), imid ), n, Op<T>::l(MC._I), Op<T>::u(MC._I) );
3044  MC2._cv = cvenv[0];
3045  for( unsigned int i=0; i<MC2._nsub; i++ ){
3046  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1];
3047  }
3048  }
3049  { int imid = -1;
3050  const double* ccenv = McCormick<T>::_oddpowcc( mid( MC._cv,
3051  MC._cc, Op<T>::u(MC._I), imid ), n, Op<T>::l(MC._I), Op<T>::u(MC._I) );
3052  MC2._cc = ccenv[0];
3053  for( unsigned int i=0; i<MC2._nsub; i++ ){
3054  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
3055  }
3056  }
3057  return MC2.cut();
3058  }
3059 
3060  if( n >= 3 ){
3061  return pow( MC, n-1 ) * MC;
3062  }
3063 
3064  if( n == -1 ){
3065  return inv( MC );
3066  }
3067 
3068  if ( Op<T>::l(MC._I) <= 0. && Op<T>::u(MC._I) >= 0. )
3069  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::INV );
3070  McCormick<T> MC2;
3071  MC2._sub( MC._nsub, MC._const );
3072  MC2._I = Op<T>::pow( MC._I, n );
3073 
3074  if ( Op<T>::l(MC._I) > 0. ){
3075  { int imid = -1;
3076  double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
3077  MC2._cv = std::pow( vmid, n );
3078  for( unsigned int i=0; i<MC2._nsub; i++ )
3079  MC2._cvsub[i] = n* mid( MC._cvsub, MC._ccsub, i, imid ) * std::pow( vmid, n-1 );
3080  }
3081  { double r = std::pow( Op<T>::l(MC._I), -n-1 ) + std::pow( Op<T>::u(MC._I), -n-1 );
3082  for( int i=1; i<=-n-2; i++ )
3083  r += std::pow( Op<T>::l(MC._I), i ) * std::pow( Op<T>::u(MC._I), -n-1-i );
3084  r /= - std::pow( Op<T>::l(MC._I), -n ) * std::pow( Op<T>::u(MC._I), -n );
3085  int imid = -1;
3086  double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid );
3087  MC2._cc = std::pow( Op<T>::l(MC._I), n ) + r * ( vmid - Op<T>::l(MC._I) );
3088  for( unsigned int i=0; i<MC2._nsub; i++ )
3089  MC2._ccsub[i] = r * mid( MC._cvsub, MC._ccsub, i, imid );
3090  }
3091  return MC2.cut();
3092  }
3093 
3094  if( (-n)%2 ){
3095  { double r = std::pow( Op<T>::l(MC._I), -n-1 ) + std::pow( Op<T>::u(MC._I), -n-1 );
3096  for( int i=1; i<=-n-2; i++ )
3097  r += std::pow( Op<T>::l(MC._I), i ) * std::pow( Op<T>::u(MC._I), -n-1-i );
3098  r /= - std::pow( Op<T>::l(MC._I), -n ) * std::pow( Op<T>::u(MC._I), -n );
3099  int imid = -1;
3100  double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
3101  MC2._cv = std::pow( Op<T>::l(MC._I), n ) + r * ( vmid - Op<T>::l(MC._I) );
3102  for( unsigned int i=0; i<MC2._nsub; i++ )
3103  MC2._cvsub[i] = r * mid( MC._cvsub, MC._ccsub, i, imid );
3104  }
3105  { int imid = -1;
3106  double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid );
3107  MC2._cc = std::pow( vmid, n );
3108  for( unsigned int i=0; i<MC2._nsub; i++ )
3109  MC2._ccsub[i] = n* mid( MC._cvsub, MC._ccsub, i, imid ) * std::pow( vmid, n-1 );
3110  }
3111  return MC2.cut();
3112  }
3113 
3114  { int imid = -1;
3115  double vmid = mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid );
3116  MC2._cv = std::pow( vmid, n );
3117  for( unsigned int i=0; i<MC2._nsub; i++ )
3118  MC2._cvsub[i] = n* mid( MC._cvsub, MC._ccsub, i, imid ) * std::pow( vmid, n-1 );
3119  }
3120  { double r = std::pow( Op<T>::l(MC._I), -n-1 ) + std::pow( Op<T>::u(MC._I), -n-1 );
3121  for( int i=1; i<=-n-2; i++ )
3122  r += std::pow( Op<T>::l(MC._I), i ) * std::pow( Op<T>::u(MC._I), -n-1-i );
3123  r /= - std::pow( Op<T>::l(MC._I), -n ) * std::pow( Op<T>::u(MC._I), -n );
3124  int imid = -1;
3125  double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
3126  MC2._cc = std::pow( Op<T>::l(MC._I), n ) + r * ( vmid - Op<T>::l(MC._I) );
3127  for( unsigned int i=0; i<MC2._nsub; i++ )
3128  MC2._ccsub[i] = r * mid( MC._cvsub, MC._ccsub, i, imid );
3129  }
3130  return MC2.cut();
3131 }
3132 
3133 template <typename T> inline McCormick<T>
3134 pow
3135 ( const McCormick<T> &MC, const double a )
3136 {
3137  return exp( a * log( MC ) );
3138 }
3139 
3140 template <typename T> inline McCormick<T>
3141 pow
3142 ( const McCormick<T> &MC1, const McCormick<T> &MC2 )
3143 {
3144  return exp( MC2 * log( MC1 ) );
3145 }
3146 
3147 template <typename T> inline McCormick<T>
3148 pow
3149 ( const double a, const McCormick<T> &MC )
3150 {
3151  return exp( MC * std::log( a ) );
3152 }
3153 
3154 template <typename T> inline McCormick<T>
3155 monomial
3156 (const unsigned int n, const McCormick<T>*MC, const int*k)
3157 {
3158  if( n == 0 ){
3159  return 1.;
3160  }
3161  if( n == 1 ){
3162  return pow( MC[0], k[0] );
3163  }
3164  return pow( MC[0], k[0] ) * monomial( n-1, MC+1, k+1 );
3165 }
3166 
3167 template <typename T> inline McCormick<T>
3168 fabs
3169 ( const McCormick<T> &MC )
3170 {
3171  McCormick<T> MC2;
3172  MC2._sub( MC._nsub, MC._const );
3173  MC2._I = Op<T>::fabs( MC._I );
3174 
3175  { int imid = -1;
3176  double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), 0., imid );
3177  imid = -1;
3178  double vmid = mid( MC._cv, MC._cc, zmin, imid );
3179  MC2._cv = std::fabs( vmid );
3180  if( vmid >= 0. )
3181  for( unsigned int i=0; i<MC2._nsub; i++ )
3182  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid );
3183  else
3184  for( unsigned int i=0; i<MC2._nsub; i++ )
3185  MC2._cvsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid );
3186  }
3187 
3188  { int imid = -1;
3189  double zmax = (std::fabs( Op<T>::l(MC._I) )>std::fabs( Op<T>::u(MC._I) )? Op<T>::l(MC._I):
3190  Op<T>::u(MC._I));
3191  double r = ( isequal( Op<T>::l(MC._I), Op<T>::u(MC._I) )? 0.: ( std::fabs( Op<T>::u(MC._I) )
3192  - std::fabs( Op<T>::l(MC._I) ) ) / ( Op<T>::u(MC._I) - Op<T>::l(MC._I) ) );
3193  MC2._cc = std::fabs( Op<T>::l(MC._I) ) + r * ( mid( MC._cv, MC._cc, zmax, imid )
3194  - Op<T>::l(MC._I) );
3195  for( unsigned int i=0; i<MC2._nsub; i++ )
3196  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * r;
3197  }
3198 
3199  return MC2.cut();
3200 }
3201 
3202 template <typename T> inline McCormick<T>
3203 min
3204 ( const McCormick<T> &MC1, const McCormick<T> &MC2 )
3205 {
3206  McCormick<T> MC3;
3207  if( MC2._const )
3208  MC3._sub( MC1._nsub, MC1._const );
3209  else if( MC1._const )
3210  MC3._sub( MC2._nsub, MC2._const );
3211  else if( MC1._nsub != MC2._nsub )
3212  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
3213  else
3214  MC3._sub( MC1._nsub, MC1._const||MC2._const );
3215  MC3._I = Op<T>::min( MC1._I, MC2._I );
3216 
3217  if( Op<T>::u(MC1._I) <= Op<T>::l(MC2._I) ){
3218  MC3._cv = MC1._cv;
3219  for( unsigned int i=0; i< MC3._nsub; i++ )
3220  MC3._cvsub[i] = (MC1._const? 0.: MC1._cvsub[i]);
3221  }
3222  else if( Op<T>::u(MC2._I) <= Op<T>::l(MC1._I) ){
3223  MC3._cv = MC2._cv;
3224  for( unsigned int i=0; i< MC3._nsub; i++ )
3225  MC3._cvsub[i] = (MC2._const? 0.: MC2._cvsub[i]);
3226  }
3227  else if( McCormick<T>::options.MVCOMP_USE ){
3228  double minL1L2 = std::min( Op<T>::l(MC1._I), Op<T>::l(MC2._I) );
3229  double minL1U2 = std::min( Op<T>::l(MC1._I), Op<T>::u(MC2._I) );
3230  double minU1L2 = std::min( Op<T>::u(MC1._I), Op<T>::l(MC2._I) );
3231  double minU1U2 = std::min( Op<T>::u(MC1._I), Op<T>::u(MC2._I) );
3232 
3233  bool thin1 = isequal( Op<T>::diam(MC1._I), 0. );
3234  double r11 = ( thin1? 0.: ( minU1L2 - minL1L2 ) / Op<T>::diam(MC1._I) );
3235  double r21 = ( thin1? 0.: ( minL1U2 - minU1U2 ) / Op<T>::diam(MC1._I) );
3236 
3237  bool thin2 = isequal( Op<T>::diam(MC2._I), 0. );
3238  double r12 = ( thin2? 0.: ( minL1U2 - minL1L2 ) / Op<T>::diam(MC2._I) );
3239  double r22 = ( thin2? 0.: ( minU1L2 - minU1U2 ) / Op<T>::diam(MC2._I) );
3240 
3241  double g1cv = minL1L2 + r11 * ( MC1._cv - Op<T>::l(MC1._I) )
3242  + r12 * ( MC2._cv - Op<T>::l(MC2._I) );
3243  double g2cv = minU1U2 - r21 * ( MC1._cv - Op<T>::u(MC1._I) )
3244  - r22 * ( MC2._cv - Op<T>::u(MC2._I) );
3245  if( g1cv >= g2cv ){
3246  MC3._cv = g1cv;
3247  for( unsigned int i=0; i< MC3._nsub; i++ )
3248  MC3._cvsub[i] = (MC1._const? 0.: r11*MC1._cvsub[i])
3249  + (MC2._const? 0.: r12*MC2._cvsub[i]);
3250  }
3251  else{
3252  MC3._cv = g2cv;
3253  for( unsigned int i=0; i< MC3._nsub; i++ )
3254  MC3._cvsub[i] = - (MC1._const? 0.: r21*MC1._cvsub[i])
3255  - (MC2._const? 0.: r22*MC2._cvsub[i]);
3256  }
3257  }
3258  else{
3259  McCormick<T> MCMin = 0.5*( MC1 + MC2 - fabs( MC2 - MC1 ) );
3260  MC3._cv = MCMin._cv;
3261  for( unsigned int i=0; i< MC3._nsub; i++ )
3262  MC3._cvsub[i] = MCMin._cvsub[i];
3263  }
3264 
3265  MC3._cc = std::min( MC1._cc, MC2._cc );
3266  for( unsigned int i=0; i< MC3._nsub; i++ )
3267  MC3._ccsub[i] = ( MC1._cc<=MC2._cc? (MC1._const? 0.: MC1._ccsub[i])
3268  : (MC2._const? 0.: MC2._ccsub[i]) );
3269 
3270  return MC3.cut();
3271 }
3272 
3273 template <typename T> inline McCormick<T>
3274 max
3275 ( const McCormick<T> &MC1, const McCormick<T> &MC2 )
3276 {
3277  McCormick<T> MC3;
3278  if( MC2._const )
3279  MC3._sub( MC1._nsub, MC1._const );
3280  else if( MC1._const )
3281  MC3._sub( MC2._nsub, MC2._const );
3282  else if( MC1._nsub != MC2._nsub )
3283  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
3284  else
3285  MC3._sub( MC1._nsub, MC1._const||MC2._const );
3286  MC3._I = Op<T>::max( MC1._I, MC2._I );
3287 
3288  if( Op<T>::u(MC1._I) <= Op<T>::l(MC2._I) ){
3289  MC3._cc = MC1._cc;
3290  for( unsigned int i=0; i< MC3._nsub; i++ )
3291  MC3._ccsub[i] = (MC1._const? 0.: MC1._ccsub[i]);
3292  }
3293  else if( Op<T>::u(MC2._I) <= Op<T>::l(MC1._I) ){
3294  MC3._cc = MC2._cc;
3295  for( unsigned int i=0; i< MC3._nsub; i++ )
3296  MC3._ccsub[i] = (MC2._const? 0.: MC2._ccsub[i]);
3297  }
3298  else if ( McCormick<T>::options.MVCOMP_USE ){
3299  double maxL1L2 = std::max( Op<T>::l(MC1._I), Op<T>::l(MC2._I) );
3300  double maxL1U2 = std::max( Op<T>::l(MC1._I), Op<T>::u(MC2._I) );
3301  double maxU1L2 = std::max( Op<T>::u(MC1._I), Op<T>::l(MC2._I) );
3302  double maxU1U2 = std::max( Op<T>::u(MC1._I), Op<T>::u(MC2._I) );
3303 
3304  bool thin1 = isequal( Op<T>::diam(MC1._I), 0. );
3305  double r11 = ( thin1? 0.: ( maxU1L2 - maxL1L2 ) / Op<T>::diam(MC1._I) );
3306  double r21 = ( thin1? 0.: ( maxL1U2 - maxU1U2 ) / Op<T>::diam(MC1._I) );
3307 
3308  bool thin2 = isequal( Op<T>::diam(MC2._I), 0. );
3309  double r12 = ( thin2? 0.: ( maxL1U2 - maxL1L2 ) / Op<T>::diam(MC2._I) );
3310  double r22 = ( thin2? 0.: ( maxU1L2 - maxU1U2 ) / Op<T>::diam(MC2._I) );
3311 
3312  double g1cc = maxL1L2 + r11 * ( MC1._cc - Op<T>::l(MC1._I) )
3313  + r12 * ( MC2._cc - Op<T>::l(MC2._I) );
3314  double g2cc = maxU1U2 - r21 * ( MC1._cc - Op<T>::u(MC1._I) )
3315  - r22 * ( MC2._cc - Op<T>::u(MC2._I) );
3316  if( g1cc <= g2cc ){
3317  MC3._cc = g1cc;
3318  for( unsigned int i=0; i< MC3._nsub; i++ )
3319  MC3._ccsub[i] = (MC1._const? 0.: r11*MC1._ccsub[i])
3320  + (MC2._const? 0.: r12*MC2._ccsub[i]);
3321  }
3322  else{
3323  MC3._cc = g2cc;
3324  for( unsigned int i=0; i< MC3._nsub; i++ )
3325  MC3._ccsub[i] = - (MC1._const? 0.: r21*MC1._ccsub[i])
3326  - (MC2._const? 0.: r22*MC2._ccsub[i]);
3327  }
3328  }
3329  else{
3330  McCormick<T> MCMax = 0.5*( MC1 + MC2 + fabs( MC1 - MC2 ) );
3331  MC3._cc = MCMax._cc;
3332  for( unsigned int i=0; i< MC3._nsub; i++ )
3333  MC3._ccsub[i] = MCMax._ccsub[i];
3334  }
3335 
3336  MC3._cv = std::max( MC1._cv, MC2._cv );
3337  for( unsigned int i=0; i< MC3._nsub; i++ )
3338  MC3._cvsub[i] = ( MC1._cv>=MC2._cv? (MC1._const? 0.: MC1._cvsub[i])
3339  : (MC2._const? 0.: MC2._cvsub[i]) );
3340 
3341  return MC3.cut();
3342 }
3343 
3344 template <typename T> inline McCormick<T>
3345 min
3346 ( const unsigned int n, const McCormick<T>*MC )
3347 {
3348  McCormick<T> MC2( n==0 || !MC ? 0.: MC[0] );
3349  for( unsigned int i=1; i<n; i++ ) MC2 = min( MC2, MC[i] );
3350  return MC2;
3351 }
3352 
3353 template <typename T> inline McCormick<T>
3354 max
3355 ( const unsigned int n, const McCormick<T>*MC )
3356 {
3357  McCormick<T> MC2( n==0 || !MC ? 0.: MC[0] );
3358  for( unsigned int i=1; i<n; i++ ) MC2 = max( MC2, MC[i] );
3359  return MC2;
3360 }
3361 
3362 template <typename T> inline McCormick<T>
3363 fstep
3364 ( const McCormick<T> &MC )
3365 {
3366  McCormick<T> MC2;
3367  MC2._sub( MC._nsub, MC._const );
3368  if( Op<T>::l( MC._I ) >= 0 )
3369  MC2._I = Op<T>::point(1.);
3370  else if( Op<T>::u( MC._I ) < 0 )
3371  MC2._I = Op<T>::point(0.);
3372  else
3373  MC2._I = Op<T>::zeroone();
3374 
3375  { int imid = -1;
3376  double zmin = Op<T>::l(MC._I);
3377  double vmid = mid( MC._cv, MC._cc, zmin, imid );
3378  const double* cvenv = McCormick<T>::_stepcv( vmid, Op<T>::l(MC._I),
3379  Op<T>::u(MC._I) );
3380  MC2._cv = cvenv[0];
3381  for( unsigned int i=0; i<MC2._nsub; i++ )
3382  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid )*cvenv[1];
3383  }
3384 
3385  { int imid = -1;
3386  double zmax = Op<T>::u(MC._I);
3387  double vmid = mid( MC._cv, MC._cc, zmax, imid );
3388  const double* ccenv = McCormick<T>::_stepcc( vmid, Op<T>::l(MC._I),
3389  Op<T>::u(MC._I) );
3390  MC2._cc = ccenv[0];
3391  for( unsigned int i=0; i<MC2._nsub; i++ )
3392  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid )*ccenv[1];
3393  }
3394 
3395  return MC2.cut();
3396 }
3397 
3398 template <typename T> inline McCormick<T>
3399 bstep
3400 ( const McCormick<T> &MC )
3401 {
3402  return fstep( -MC );
3403 }
3404 
3405 template <typename T> inline McCormick<T>
3406 ltcond
3407 ( const T &I0, const McCormick<T> &MC1, const McCormick<T> &MC2 )
3408 {
3409  if( Op<T>::u( I0 ) < 0. ) return MC1;
3410  else if( Op<T>::l( I0 ) >= 0. ) return MC2;
3411 
3412  McCormick<T> MC3;
3413  if( MC2._const )
3414  MC3._sub( MC1._nsub, MC1._const );
3415  else if( MC1._const )
3416  MC3._sub( MC2._nsub, MC2._const );
3417  else if( MC1._nsub != MC2._nsub )
3418  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
3419  else
3420  MC3._sub( MC1._nsub, MC1._const||MC2._const );
3421 
3422  MC3._I = Op<T>::hull( MC1._I, MC2._I );
3423  McCormick<T> MCMin = 0.5*( MC1 + MC2 - fabs( MC2 - MC1 ) );
3424  McCormick<T> MCMax = 0.5*( MC1 + MC2 + fabs( MC1 - MC2 ) );
3425  MC3._cv = MCMin._cv;
3426  MC3._cc = MCMax._cc;
3427  for( unsigned int i=0; i< MC3._nsub; i++ ){
3428  MC3._cvsub[i] = MCMin._cvsub[i];
3429  MC3._ccsub[i] = MCMax._ccsub[i];
3430  }
3431  return MC3.cut();
3432 }
3433 
3434 template <typename T> inline McCormick<T>
3435 ltcond
3436 ( const McCormick<T> &MC0, const McCormick<T> &MC1, const McCormick<T> &MC2 )
3437 {
3438  McCormick<T> MC3 = ltcond( MC0._I, MC1, MC2 );
3439  McCormick<T> MCStep = fstep(-MC0)*MC1 + fstep(MC0)*MC2;
3440  if( MCStep._cv > MC3._cv ){
3441  MC3._cv = MCStep._cv;
3442  for( unsigned int i=0; i< MC3._nsub; i++ )
3443  MC3._cvsub[i] = MCStep._cvsub[i];
3444  }
3445  if( MCStep._cc < MC3._cc ){
3446  MC3._cc = MCStep._cc;
3447  for( unsigned int i=0; i< MC3._nsub; i++ )
3448  MC3._ccsub[i] = MCStep._ccsub[i];
3449  }
3450  return MC3.cut();
3451 }
3452 
3453 template <typename T> inline McCormick<T>
3454 gtcond
3455 ( const T &I0, const McCormick<T> &MC1, const McCormick<T> &MC2 )
3456 {
3457  return ltcond( -I0, MC1, MC2 );
3458 }
3459 template <typename T> inline McCormick<T>
3460 gtcond
3461 ( const McCormick<T> &MC0, const McCormick<T> &MC1, const McCormick<T> &MC2 )
3462 {
3463  return ltcond( -MC0, MC1, MC2 );
3464 }
3465 
3466 template <typename T> inline McCormick<T>
3467 cos
3468 ( const McCormick<T> &MC )
3469 {
3470  McCormick<T> MC2;
3471  MC2._sub( MC._nsub, MC._const );
3472  MC2._I = Op<T>::cos( MC._I );
3473 
3474  if( !McCormick<T>::options.ENVEL_USE ){
3475  MC2._cv = Op<T>::l(MC2._I);
3476  MC2._cc = Op<T>::u(MC2._I);
3477  for( unsigned int i=0; i<MC2._nsub; i++ ){
3478  MC2._cvsub[i] = MC2._ccsub[i] = 0.;
3479  }
3480  return MC2;
3481  }
3482 
3483  double*argbnd = McCormick<T>::_cosarg( Op<T>::l(MC._I), Op<T>::u(MC._I) );
3484  { int imid = -1;
3485  const double* cvenv = McCormick<T>::_coscv( mid( MC._cv,
3486  MC._cc, argbnd[0], imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
3487  MC2._cv = cvenv[0];
3488  for( unsigned int i=0; i< MC2._nsub; i++ ){
3489  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1];
3490  }
3491  }
3492  { int imid = -1;
3493  const double* ccenv = McCormick<T>::_coscc( mid( MC._cv,
3494  MC._cc, argbnd[1], imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
3495  MC2._cc = ccenv[0];
3496  for( unsigned int i=0; i< MC2._nsub; i++ ){
3497  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
3498  }
3499  }
3500  return MC2.cut();
3501 }
3502 
3503 template <typename T> inline McCormick<T>
3504 sin
3505 ( const McCormick<T> &MC )
3506 {
3507  return cos( MC - PI/2. );
3508 }
3509 
3510 template <typename T> inline McCormick<T>
3511 asin
3512 ( const McCormick<T> &MC )
3513 {
3514  if ( Op<T>::l(MC._I) <= -1. || Op<T>::u(MC._I) >= 1. )
3515  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::ASIN );
3516 
3517  McCormick<T> MC2;
3518  MC2._sub( MC._nsub, MC._const );
3519  MC2._I = Op<T>::asin( MC._I );
3520 
3521  if( !McCormick<T>::options.ENVEL_USE ){
3522  { int imid = -1;
3523  MC2._cv = Op<T>::l(MC2._I) + ( mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid )
3524  - Op<T>::l(MC._I) );
3525  for( unsigned int i=0; i<MC2._nsub; i++ ){
3526  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid );
3527  }
3528  }
3529  { int imid = -1;
3530  MC2._cc = Op<T>::u(MC2._I) + ( mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid )
3531  - Op<T>::u(MC._I) );
3532  for( unsigned int i=0; i<MC2._nsub; i++ ){
3533  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid );
3534  }
3535  }
3536  return MC2.cut();
3537  }
3538 
3539  { int imid = -1;
3540  const double* cvenv = McCormick<T>::_asincv( mid( MC._cv,
3541  MC._cc, Op<T>::l(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
3542  MC2._cv = cvenv[0];
3543  for( unsigned int i=0; i<MC2._nsub; i++ ){
3544  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1];
3545  }
3546  }
3547  { int imid = -1;
3548  const double* ccenv = McCormick<T>::_asincc( mid( MC._cv,
3549  MC._cc, Op<T>::u(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
3550  MC2._cc = ccenv[0];
3551  for( unsigned int i=0; i<MC2._nsub; i++ ){
3552  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
3553  }
3554  }
3555  return MC2.cut();
3556 }
3557 
3558 template <typename T> inline McCormick<T>
3559 acos
3560 ( const McCormick<T> &MC )
3561 {
3562  return asin( -MC ) + PI/2.;
3563 }
3564 
3565 template <typename T> inline McCormick<T>
3566 tan
3567 ( const McCormick<T> &MC )
3568 {
3569  if ( Op<T>::diam(MC._I) >= PI )
3570  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::TAN );
3571  const double shift = PI*std::ceil(-Op<T>::l(MC._I)/PI-1./2.);
3572  const double xL1 = Op<T>::l(MC._I)+shift, xU1 = Op<T>::u(MC._I)+shift;
3573  if ( xL1 <= -PI/2. || xU1 >= PI/2. )
3574  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::TAN );
3575 
3576  McCormick<T> MC2;
3577  MC2._sub( MC._nsub, MC._const );
3578  MC2._I = Op<T>::tan( MC._I );
3579 
3580  if( !McCormick<T>::options.ENVEL_USE ){
3581  { int imid = -1;
3582  MC2._cv = Op<T>::l(MC2._I) + ( mid( MC._cv, MC._cc, Op<T>::l(MC._I), imid )
3583  - Op<T>::l(MC._I) );
3584  for( unsigned int i=0; i<MC2._nsub; i++ ){
3585  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid );
3586  }
3587  }
3588  { int imid = -1;
3589  MC2._cc = Op<T>::u(MC2._I) + ( mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid )
3590  - Op<T>::u(MC._I) );
3591  for( unsigned int i=0; i<MC2._nsub; i++ ){
3592  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid );
3593  }
3594  }
3595  return MC2.cut();
3596  }
3597 
3598  { int imid = -1;
3599  const double* cvenv = McCormick<T>::_tancv( mid( MC._cv+shift,
3600  MC._cc+shift, Op<T>::l(MC._I)+shift, imid ), Op<T>::l(MC._I)+shift,
3601  Op<T>::u(MC._I)+shift );
3602  MC2._cv = cvenv[0];
3603  for( unsigned int i=0; i<MC2._nsub; i++ ){
3604  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1];
3605  }
3606  }
3607  { int imid = -1;
3608  const double* ccenv = McCormick<T>::_tancc( mid( MC._cv+shift,
3609  MC._cc+shift, Op<T>::u(MC._I)+shift, imid ), Op<T>::l(MC._I)+shift,
3610  Op<T>::u(MC._I)+shift );
3611  MC2._cc = ccenv[0];
3612  for( unsigned int i=0; i<MC2._nsub; i++ ){
3613  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
3614  }
3615  }
3616  return MC2.cut();
3617 }
3618 
3619 template <typename T> inline McCormick<T>
3620 atan
3621 ( const McCormick<T> &MC )
3622 {
3623  McCormick<T> MC2;
3624  MC2._sub( MC._nsub, MC._const );
3625  MC2._I = Op<T>::atan( MC._I );
3626 
3627  if( !McCormick<T>::options.ENVEL_USE ){
3628  MC2._cv = Op<T>::l(MC2._I);
3629  MC2._cc = Op<T>::u(MC2._I);
3630  for( unsigned int i=0; i<MC2._nsub; i++ ){
3631  MC2._cvsub[i] = MC2._ccsub[i] = 0.;
3632  }
3633  return MC2;
3634  }
3635 
3636  { int imid = -1;
3637  const double* cvenv = McCormick<T>::_atancv( mid( MC._cv,
3638  MC._cc, Op<T>::l(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
3639  MC2._cv = cvenv[0];
3640  for( unsigned int i=0; i<MC2._nsub; i++ ){
3641  MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[1];
3642  }
3643  }
3644  { int imid = -1;
3645  const double* ccenv = McCormick<T>::_atancc( mid( MC._cv,
3646  MC._cc, Op<T>::u(MC._I), imid ), Op<T>::l(MC._I), Op<T>::u(MC._I) );
3647  MC2._cc = ccenv[0];
3648  for( unsigned int i=0; i<MC2._nsub; i++ ){
3649  MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
3650  }
3651  }
3652  return MC2.cut();
3653 }
3654 
3655 template <typename T> inline std::ostream&
3656 operator<<
3657 ( std::ostream&out, const McCormick<T>&MC)
3658 {
3659  out << std::scientific << std::setprecision(McCormick<T>::options.DISPLAY_DIGITS) << std::right
3660  << "[ " << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.l() << " : "
3661  << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.u()
3662  << " ] [ " << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.cv() << " : "
3663  << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.cc() << " ]";
3664  if( MC._nsub ){
3665  out << " [ (";
3666  for( unsigned int i=0; i<MC._nsub-1; i++ )
3667  out << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.cvsub(i) << ",";
3668  out << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.cvsub(MC._nsub-1) << ") : (";
3669  for( unsigned int i=0; i<MC._nsub-1; i++ )
3670  out << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.ccsub(i) << ",";
3671  out << std::setw(McCormick<T>::options.DISPLAY_DIGITS+7) << MC.ccsub(MC._nsub-1) << ") ]";
3672  }
3673  return out;
3674 }
3675 
3676 
3677 template <typename T> inline McCormick<T>
3678 hull
3679 ( const McCormick<T>&X, const McCormick<T>&Y )
3680 {
3681  if( !X._const && !Y._const && (X._nsub != Y._nsub) )
3682  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
3683 
3684  McCormick<T> CV = min(X,Y);
3685  McCormick<T> CC = max(X,Y);
3686  McCormick<T> XUY( Op<T>::hull(X.I(),Y.I()), CV.cv(), CC.cc() );
3687  if( !X._const )
3688  XUY._sub( X._nsub, X._const );
3689  else
3690  XUY._sub( Y._nsub, Y._const );
3691  for( unsigned int is=0; is<XUY._nsub; is++ ){
3692  XUY._cvsub[is] = CV.cvsub(is);
3693  XUY._ccsub[is] = CC.ccsub(is);
3694  }
3695  return XUY;
3696 }
3697 
3698 template <typename T> inline bool
3699 inter
3700 ( McCormick<T>&XIY, const McCormick<T>&X, const McCormick<T>&Y )
3701 {
3702  if( !X._const && !Y._const && (X._nsub != Y._nsub) )
3703  throw typename McCormick<T>::Exceptions( McCormick<T>::Exceptions::SUB );
3704 
3705  if( !Op<T>::inter( XIY._I, X._I, Y._I ) ) return false;
3706  McCormick<T> CV = max(X,Y);
3707  McCormick<T> CC = min(X,Y);
3708  if( CV.cv() > CC.cc() ) return false;
3709  XIY._cv = CV.cv();
3710  XIY._cc = CC.cc();
3711  if( !X._const )
3712  XIY._sub( X._nsub, X._const );
3713  else
3714  XIY._sub( Y._nsub, Y._const );
3715  for( unsigned int is=0; is<XIY._nsub; is++ ){
3716  XIY._cvsub[is] = CV.cvsub(is);
3717  XIY._ccsub[is] = CC.ccsub(is);
3718  }
3719  return true;
3720 }
3721 
3722 template <typename T> inline bool
3723 operator==
3724 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
3725 {
3726  return( Op<T>::eq(MC1._I,MC2._I) && MC1._cv == MC2._cv && MC1._cc == MC2._cc );
3727 }
3728 
3729 template <typename T> inline bool
3730 operator!=
3731 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
3732 {
3733  return( Op<T>::ne(MC1._I,MC2._I) || MC1._cv != MC2._cv || MC1._cc != MC2._cc );
3734 }
3735 
3736 template <typename T> inline bool
3737 operator<=
3738 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
3739 {
3740  return( Op<T>::le(MC1._I,MC2._I) && MC1._cv >= MC2._cv && MC1._cc <= MC2._cc );
3741 }
3742 
3743 template <typename T> inline bool
3744 operator>=
3745 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
3746 {
3747  return( Op<T>::ge(MC1._I,MC2._I) && MC1._cv <= MC2._cv && MC1._cc >= MC2._cc );
3748 }
3749 
3750 template <typename T> inline bool
3751 operator<
3752 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
3753 {
3754  return( Op<T>::lt(MC1._I,MC2._I) && MC1._cv > MC2._cv && MC1._cc < MC2._cc );
3755 }
3756 
3757 template <typename T> inline bool
3758 operator>
3759 ( const McCormick<T>&MC1, const McCormick<T>&MC2 )
3760 {
3761  return( Op<T>::gt(MC1._I,MC2._I) && MC1._cv < MC2._cv && MC1._cc > MC2._cc );
3762 }
3763 
3764 template <typename T> typename McCormick<T>::Options McCormick<T>::options;
3765 
3766 } // namespace mc
3767 
3768 
3769 #include "mcop.hpp"
3770 
3771 namespace mc
3772 {
3773 
3775 template <> template<typename T> struct Op< mc::McCormick<T> >
3776 {
3777  typedef mc::McCormick<T> MC;
3778  static MC point( const double c ) { return MC(c); }
3779  static MC zeroone() { return MC( mc::Op<T>::zeroone() ); }
3780  static void I(MC& x, const MC&y) { x = y; }
3781  static double l(const MC& x) { return x.l(); }
3782  static double u(const MC& x) { return x.u(); }
3783  static double abs (const MC& x) { return mc::Op<T>::abs(x.I()); }
3784  static double mid (const MC& x) { return mc::Op<T>::mid(x.I()); }
3785  static double diam(const MC& x) { return mc::Op<T>::diam(x.I()); }
3786  static MC inv (const MC& x) { return mc::inv(x); }
3787  static MC sqr (const MC& x) { return mc::sqr(x); }
3788  static MC sqrt(const MC& x) { return mc::sqrt(x); }
3789  static MC log (const MC& x) { return mc::log(x); }
3790  static MC xlog(const MC& x) { return mc::xlog(x); }
3791  static MC fabs(const MC& x) { return mc::fabs(x); }
3792  static MC exp (const MC& x) { return mc::exp(x); }
3793  static MC sin (const MC& x) { return mc::sin(x); }
3794  static MC cos (const MC& x) { return mc::cos(x); }
3795  static MC tan (const MC& x) { return mc::tan(x); }
3796  static MC asin(const MC& x) { return mc::asin(x); }
3797  static MC acos(const MC& x) { return mc::acos(x); }
3798  static MC atan(const MC& x) { return mc::atan(x); }
3799  static MC erf (const MC& x) { return mc::erf(x); }
3800  static MC erfc(const MC& x) { return mc::erfc(x); }
3801  static MC fstep(const MC& x) { return mc::fstep(x); }
3802  static MC bstep(const MC& x) { return mc::bstep(x); }
3803  static MC hull(const MC& x, const MC& y) { return mc::Op<T>::hull(x.I(),y.I()); }
3804  static MC min (const MC& x, const MC& y) { return mc::min(x,y); }
3805  static MC max (const MC& x, const MC& y) { return mc::max(x,y); }
3806  static MC arh (const MC& x, const double k) { return mc::arh(x,k); }
3807  template <typename X, typename Y> static MC pow(const X& x, const Y& y) { return mc::pow(x,y); }
3808  static MC monomial (const unsigned int n, const MC* x, const int* k) { return mc::monomial(n,x,k); }
3809  static bool inter(MC& xIy, const MC& x, const MC& y) { return mc::inter(xIy,x,y); }
3810  static bool eq(const MC& x, const MC& y) { return x==y; }
3811  static bool ne(const MC& x, const MC& y) { return x!=y; }
3812  static bool lt(const MC& x, const MC& y) { return x<y; }
3813  static bool le(const MC& x, const MC& y) { return x<=y; }
3814  static bool gt(const MC& x, const MC& y) { return x>y; }
3815  static bool ge(const MC& x, const MC& y) { return x>=y; }
3816 };
3817 
3818 } // namespace mc
3819 
3820 #endif
Failed to compute the convex or concave envelope of a univariate term.
Definition: mccormick.hpp:542
double & cv()
Convex bound.
Definition: mccormick.hpp:674
TYPE
Enumeration type for McCormick exception handling.
Definition: mccormick.hpp:534
Square-root with nonpositive values in range.
Definition: mccormick.hpp:538
int ierr()
Inline function returning the error flag.
Definition: mccormick.hpp:548
bool MVCOMP_USE
Whether to use Tsoukalas & Mitsos's multivariate composition result for min/max, product, and division terms; see [Tsoukalas & Mitsos, 2012]. This provides tighter McCormick relaxations, but it is more time consuming.
Definition: mccormick.hpp:522
Inverse with zero in range.
Definition: mccormick.hpp:536
Tangent with values outside of range.
Definition: mccormick.hpp:540
double l() const
Lower bound.
Definition: mccormick.hpp:664
double ENVEL_TOL
Termination tolerance for determination function points in convex/concave envelopes of univariate ter...
Definition: mccormick.hpp:520
double *& cvsub()
Pointer to a subgradient of convex underestimator.
Definition: mccormick.hpp:692
McCormick< T > & sub(const unsigned int nsub)
Set dimension of subgradient to nsub
Definition: mccormick.hpp:1024
Options()
Constructor.
Definition: mccormick.hpp:511
double uaff(const double *p, const double *pref) const
Compute affine overestimator at p based on a subgradient value of the concave overestimator at pref ...
Definition: mccormick.hpp:1091
Division by zero.
Definition: mccormick.hpp:535
Options of mc::McCormick.
Definition: mccormick.hpp:508
bool ENVEL_USE
Whether to compute convex/concave envelopes for the neither-convex-nor-concave univariate functions s...
Definition: mccormick.hpp:516
double & cc()
Concave bound.
Definition: mccormick.hpp:683
unsigned int DISPLAY_DIGITS
Number of digits displayed with << operator (default=5)
Definition: mccormick.hpp:526
C++ class for McCormick relaxation arithmetic for factorable function.
Definition: mccormick.hpp:362
Exceptions(TYPE ierr)
Constructor for error ierr
Definition: mccormick.hpp:546
McCormick()
Default constructor (needed to declare arrays of McCormick class)
Definition: mccormick.hpp:579
double *& ccsub()
Pointer to a subgradient of concave overestimator.
Definition: mccormick.hpp:701
void c(const double &c)
Set both convex and concave bounds to c
Definition: mccormick.hpp:754
unsigned int & nsub()
Number of subgradient components/directions.
Definition: mccormick.hpp:646
double u() const
Upper bound.
Definition: mccormick.hpp:669
T & I()
Interval bounds.
Definition: mccormick.hpp:655
unsigned int ENVEL_MAXIT
Maximum number of iterations for determination function points in convex/concave envelopes of univari...
Definition: mccormick.hpp:518
McCormick< T > & cut()
Cut convex/concave relaxations at interval bound.
Definition: mccormick.hpp:1054
Log with negative values in range.
Definition: mccormick.hpp:537
Failed to propagate subgradients for a product term with Tsoukalas & Mitsos's multivariable compositi...
Definition: mccormick.hpp:541
Inverse sine or cosine with values outside of range.
Definition: mccormick.hpp:539
Inconsistent subgradient dimension between two mc::McCormick variables.
Definition: mccormick.hpp:543
double MVCOMP_TOL
Tolerance for testing equality in subgradient propagation for product terms with Tsoukalas & Mitsos's...
Definition: mccormick.hpp:524
Exceptions of mc::McCormick.
Definition: mccormick.hpp:530
std::string what()
Return error description.
Definition: mccormick.hpp:550
~McCormick()
Destructor.
Definition: mccormick.hpp:639
double laff(const double *p, const double *pref) const
Compute affine underestimator at p based on a subgradient value of the convex underestimator at pref ...
Definition: mccormick.hpp:1069
C++ structure to allow usage of various template parameters in the types mc::McCormick, mc::TModel, mc::TVar, and mc::SpecBnd of MC++ _ Specialization of this structure is required for the template parameters can be found in the header files defining the types mc::McCormick, mc::TModel, mc::TVar, and mc::SpecBnd.
Definition: mcop.hpp:13