340 #ifndef MC__MCCORMICK_H
341 #define MC__MCCORMICK_H
348 #include "mcfunc.hpp"
361 template <
typename T>
365 template <
typename U>
friend class McCormick;
395 template <
typename U>
friend std::ostream&
operator<<
397 template <
typename U>
friend bool operator==
399 template <
typename U>
friend bool operator!=
401 template <
typename U>
friend bool operator<=
403 template <
typename U>
friend bool operator>=
405 template <
typename U>
friend bool operator<
407 template <
typename U>
friend bool operator>
455 (
const unsigned int,
const McCormick<U>*,
const int* );
472 template <
typename U>
friend bool inter
553 return "mc::McCormick\t Division by zero";
555 return "mc::McCormick\t Inverse with zero in range";
557 return "mc::McCormick\t Log with negative values in range";
559 return "mc::McCormick\t Square-root with nonpositive values in range";
561 return "mc::McCormick\t Inverse sine with values outside of [-1,1] range";
563 return "mc::McCormick\t Tangent with values pi/2+k*pi in range";
565 return "mc::McCormick\t Subgradient propagation failed";
567 return "mc::McCormick\t Convex/concave envelope computation failed";
569 return "mc::McCormick\t Inconsistent subgradient dimension";
571 return "mc::McCormick\t Undocumented error";
580 _nsub(0), _cvsub(0), _ccsub(0), _const(true)
585 _nsub(0), _cv(c), _cc(c), _cvsub(0), _ccsub(0), _const(
true)
592 _nsub(0), _cvsub(0), _ccsub(0), _const(
true)
599 (
const T&I,
const double c ):
600 _nsub(0), _cv(c), _cc(c), _cvsub(0), _ccsub(0), _const(
false)
606 (
const T&I,
const double cv,
const double cc ):
607 _nsub(0), _cv(cv), _cc(cc), _cvsub(0), _ccsub(0), _const(
false)
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),
619 for (
unsigned int ip=0; ip<_nsub; ip++ ){
620 _cvsub[ip] = MC._cvsub[ip];
621 _ccsub[ip] = MC._ccsub[ip];
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),
632 for (
unsigned int ip=0; ip<_nsub; ip++ ){
633 _cvsub[ip] = MC._cvsub[ip];
634 _ccsub[ip] = MC._ccsub[ip];
650 unsigned int nsub()
const
696 const double*
cvsub()
const
705 const double*
ccsub()
const
711 (
const unsigned int i )
716 (
const unsigned int i )
const
722 (
const unsigned int i )
727 (
const unsigned int i )
const
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 );
774 (
const double*p,
const double*pref )
const;
777 (
const T*Ip,
const double*pref )
const;
780 (
const double*p,
const double*pref )
const;
783 (
const T*Ip,
const double*pref )
const;
805 (
const unsigned int nsub,
const bool cst );
810 (
const unsigned int nsub );
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,
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 );
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 );
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 );
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 );
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 );
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 );
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 );
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 );
972 template <
typename T>
inline void
973 McCormick<T>::_sub_reset()
980 template <
typename T>
inline void
981 McCormick<T>::_sub_resize
982 (
const unsigned int nsub )
989 _cvsub =
new double[_nsub];
990 _ccsub =
new double[_nsub];
999 template <
typename T>
inline void
1000 McCormick<T>::_sub_copy
1001 (
const McCormick<T>&MC )
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];
1011 template <
typename T>
inline void
1013 (
const unsigned int nsub,
const bool cst )
1015 _sub_resize( nsub );
1016 for (
unsigned int i=0; i<nsub; i++ ){
1017 _cvsub[i] = _ccsub[i] = 0.;
1022 template <
typename T>
inline McCormick<T>&
1024 (
const unsigned int nsub )
1026 _sub( nsub,
false );
1032 (
const unsigned int nsub,
const unsigned int isub )
1034 if( isub >= nsub )
throw Exceptions( Exceptions::SUB );
1036 _cvsub[isub] = _ccsub[isub] = 1.;
1042 (
const unsigned int nsub,
const double*cvsub,
const double*ccsub )
1044 if( nsub && !(cvsub && ccsub) )
throw Exceptions( Exceptions::SUB );
1046 for (
unsigned int i=0; i<nsub; i++ ){
1047 _cvsub[i] = cvsub[i];
1048 _ccsub[i] = ccsub[i];
1058 for(
unsigned int i=0; i<_nsub; i++ ) _cvsub[i] = 0.;
1062 for(
unsigned int i=0; i<_nsub; i++ ) _ccsub[i] = 0.;
1067 template <
typename T>
inline double
1069 (
const double*p,
const double*pref )
const
1072 for(
unsigned int i=0; i<_nsub; i++ ){
1073 _laff += _cvsub[i]*(p[i]-pref[i]);
1078 template <
typename T>
inline double
1080 (
const T*Ip,
const double*pref )
const
1083 for(
unsigned int i=0; i<_nsub; i++ ){
1084 _laff +=
Op<T>::l(_cvsub[i]*(Ip[i]-pref[i]));
1089 template <
typename T>
inline double
1091 (
const double*p,
const double*pref )
const
1094 for(
unsigned int i=0; i<_nsub; i++ ){
1095 _uaff += _ccsub[i]*(p[i]-pref[i]);
1100 template <
typename T>
inline double
1102 (
const T*Ip,
const double*pref )
const
1105 for(
unsigned int i=0; i<_nsub; i++ ){
1106 _uaff +=
Op<T>::u(_ccsub[i]*(Ip[i]-pref[i]));
1123 template <
typename T>
inline McCormick<T>&
1124 McCormick<T>::operator=
1136 template <
typename T>
inline McCormick<T>&
1137 McCormick<T>::operator=
1138 (
const McCormick<T>&MC )
1140 if(
this == &MC )
return *
this;
1149 template <
typename T>
inline McCormick<T>&
1150 McCormick<T>::operator+=
1159 template <
typename T>
inline McCormick<T>&
1160 McCormick<T>::operator+=
1161 (
const McCormick<T> &MC )
1163 if( _const && !MC._const ) sub( MC._nsub );
1164 else if( !MC._const && _nsub != MC._nsub )
throw Exceptions( Exceptions::SUB );
1168 for(
unsigned int i=0; i<_nsub && !MC._const; i++ ){
1169 _cvsub[i] += MC._cvsub[i];
1170 _ccsub[i] += MC._ccsub[i];
1175 template <
typename T>
inline McCormick<T>&
1177 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
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];
1189 template <
typename T>
inline McCormick<T>&
1191 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
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];
1203 template <
typename T>
inline McCormick<T>&
1204 McCormick<T>::operator-=
1213 template <
typename T>
inline McCormick<T>&
1214 McCormick<T>::operator-=
1215 (
const McCormick<T> &MC )
1217 if( _const && !MC._const ) sub( MC._nsub );
1218 else if( !MC._const && _nsub != MC._nsub )
throw Exceptions( Exceptions::SUB );
1220 double t_cv = MC._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;
1231 template <
typename T>
inline McCormick<T>&
1233 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
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];
1245 template <
typename T>
inline McCormick<T>&
1247 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
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];
1259 template <
typename T>
inline McCormick<T>&
1261 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
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];
1273 template <
typename T>
inline McCormick<T>&
1274 McCormick<T>::operator*=
1277 McCormick<T> MC2 = a * (*this);
1282 template <
typename T>
inline McCormick<T>&
1283 McCormick<T>::operator*=
1284 (
const McCormick<T>&MC )
1286 if( _const && !MC._const ) sub( MC._nsub );
1287 McCormick<T> MC2 = MC * (*this);
1292 template <
typename T>
inline McCormick<T>&
1293 McCormick<T>::_mul1_u1pos_u2pos
1294 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
1296 _I = MC1._I * MC2._I;
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);
1304 for(
unsigned int i=0; i<_nsub; i++ )
1305 _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i];
1309 for(
unsigned int i=0; i<_nsub; i++ )
1310 _cvsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i];
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);
1319 for(
unsigned int i=0; i<_nsub; i++ )
1320 _ccsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i];
1324 for(
unsigned int i=0; i<_nsub; i++ )
1325 _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i];
1330 template <
typename T>
inline McCormick<T>&
1331 McCormick<T>::_mul2_u1pos_u2pos
1332 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
1334 _I = MC1._I * MC2._I;
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);
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];
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];
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);
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];
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];
1368 template <
typename T>
inline McCormick<T>&
1369 McCormick<T>::_mul1_u1pos_u2mix
1370 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
1372 _I = MC1._I * MC2._I;
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);
1380 for(
unsigned int i=0; i<_nsub; i++ )
1381 _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i];
1385 for(
unsigned int i=0; i<_nsub; i++ )
1386 _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i];
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);
1395 for(
unsigned int i=0; i<_nsub; i++ )
1396 _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i];
1400 for(
unsigned int i=0; i<_nsub; i++ )
1401 _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i];
1406 template <
typename T>
inline McCormick<T>&
1407 McCormick<T>::_mul2_u1pos_u2mix
1408 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
1410 _I = MC1._I * MC2._I;
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);
1418 for(
unsigned int i=0; i<_nsub; i++ )
1419 _cvsub[i] = Op<T>::u(MC1._I) * MC2._cvsub[i];
1423 for(
unsigned int i=0; i<_nsub; i++ )
1424 _cvsub[i] = Op<T>::l(MC1._I) * MC2._cvsub[i];
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);
1433 for(
unsigned int i=0; i<_nsub; i++ )
1434 _ccsub[i] = Op<T>::u(MC1._I) * MC2._ccsub[i];
1438 for(
unsigned int i=0; i<_nsub; i++ )
1439 _ccsub[i] = Op<T>::l(MC1._I) * MC2._ccsub[i];
1444 template <
typename T>
inline McCormick<T>&
1445 McCormick<T>::_mul3_u1pos_u2mix
1446 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
1448 _I = MC1._I * MC2._I;
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);
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];
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];
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);
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];
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];
1482 template <
typename T>
inline McCormick<T>&
1483 McCormick<T>::_mul1_u1mix_u2mix
1484 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
1486 _I = MC1._I * MC2._I;
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);
1494 for(
unsigned int i=0; i<_nsub; i++ )
1495 _cvsub[i] = Op<T>::u(MC2._I) * MC1._cvsub[i];
1499 for(
unsigned int i=0; i<_nsub; i++ )
1500 _cvsub[i] = Op<T>::l(MC2._I) * MC1._ccsub[i];
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);
1509 for(
unsigned int i=0; i<_nsub; i++ )
1510 _ccsub[i] = Op<T>::l(MC2._I) * MC1._cvsub[i];
1514 for(
unsigned int i=0; i<_nsub; i++ )
1515 _ccsub[i] = Op<T>::u(MC2._I) * MC1._ccsub[i];
1520 template <
typename T>
inline McCormick<T>&
1521 McCormick<T>::_mul2_u1mix_u2mix
1522 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
1524 _I = MC1._I * MC2._I;
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);
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];
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];
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);
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];
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];
1558 template <
typename T>
inline McCormick<T>&
1559 McCormick<T>::_mulMV
1560 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
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);
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); }
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); }
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) ); }
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] ),
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 );
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 )?
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 )?
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 )?
1616 if( !alphathin && alpha.first > alpha.second ){
1617 std::cout <<
"WARNING1: alphaL= " << alpha.first <<
" alphaU= " << alpha.second
1619 throw Exceptions( Exceptions::MULTSUB );
1621 myalpha = 0.5*( alpha.first + alpha.second );
1623 else if( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ) > fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ) )
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;
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);
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); }
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); }
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) ); }
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] ),
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 );
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 )?
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 )?
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 )?
1691 if( !alphathin && alpha.first > alpha.second ){
1692 std::cout <<
"WARNING2: alphaL= " << alpha.first <<
" alphaU= " << alpha.second
1694 throw Exceptions( Exceptions::MULTSUB );
1696 myalpha = 0.5*( alpha.first + alpha.second );
1698 else if( fct::t1( x1t[ndx], x2t[ndx], MC1, MC2 ) < fct::t2( x1t[ndx], x2t[ndx], MC1, MC2 ) )
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;
1715 template <
typename T>
inline McCormick<T>&
1716 McCormick<T>::operator/=
1719 McCormick<T> MC2 = (*this) / a;
1724 template <
typename T>
inline McCormick<T>&
1725 McCormick<T>::operator/=
1726 (
const McCormick<T>&MC )
1728 if( _const && !MC._const ) sub( MC._nsub );
1729 McCormick<T> MC2 = (*this) / MC;
1734 template <
typename T>
inline double*
1735 McCormick<T>::_erfcv
1736 (
const double x,
const double xL,
const double xU )
1738 static double cv[2];
1740 cv[0] = ::erf(x), cv[1] = 2./std::sqrt(PI)*std::exp(-sqr(x));
1745 double r = ( isequal( xL, xU )? 0.:(::erf(xU)-::erf(xL))/(xU-xL) );
1746 cv[0] = ::erf(xL)+r*(x-xL), cv[1] = r;
1752 xj = _newton( xL, xL, 0., _erfenv_func, _erfenv_dfunc, &xU );
1754 catch( McCormick<T>::Exceptions ){
1755 xj = _goldsect( xL, 0., _erfenv_func, &xU, 0 );
1758 cv[0] = ::erf(x), cv[1] = 2./std::sqrt(PI)*std::exp(-sqr(x));
1761 double r = ( isequal( xj, xU )? 0.:(::erf(xU)-::erf(xj))/(xU-xj) );
1762 cv[0] = ::erf(xU)+r*(x-xU), cv[1] = r;
1766 template <
typename T>
inline double*
1767 McCormick<T>::_erfcc
1768 (
const double x,
const double xL,
const double xU )
1770 static double cc[2];
1772 double r = ( isequal( xL, xU )? 0.:(::erf(xU)-::erf(xL))/(xU-xL) );
1773 cc[0] = ::erf(xL)+r*(x-xL), cc[1] = r;
1778 cc[0] = ::erf(x), cc[1] = 2./std::sqrt(PI)*std::exp(-sqr(x));
1784 xj = _newton( xU, 0., xU, _erfenv_func, _erfenv_dfunc, &xL );
1786 catch( McCormick<T>::Exceptions ){
1787 xj = _goldsect( 0., xU, _erfenv_func, &xL, 0 );
1790 cc[0] = ::erf(x), cc[1] = 2./std::sqrt(PI)*std::exp(-sqr(x));
1793 double r = ( isequal( xj, xL )? 0.:(::erf(xL)-::erf(xj))/(xL-xj) );
1794 cc[0] = ::erf(xL)+r*(x-xL), cc[1] = r;
1798 template <
typename T>
inline double
1799 McCormick<T>::_erfenv_func
1800 (
const double x,
const double*rusr,
const int*iusr )
1803 return (x-*rusr)*std::exp(-sqr(x))-std::sqrt(PI)/2.*(::erf(x)-::erf(*rusr));
1806 template <
typename T>
inline double
1807 McCormick<T>::_erfenv_dfunc
1808 (
const double x,
const double*rusr,
const int*iusr )
1811 return -2.*x*(x-*rusr)*std::exp(-2.*sqr(x));
1814 template <
typename T>
inline double*
1815 McCormick<T>::_atancv
1816 (
const double x,
const double xL,
const double xU )
1818 static double cv[2];
1820 cv[0] = std::atan(x), cv[1] = 1./(1.+sqr(x));
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;
1832 xj = _newton( xL, xL, 0., _atanenv_func, _atanenv_dfunc, &xU, 0 );
1834 catch( McCormick<T>::Exceptions ){
1835 xj = _goldsect( xL, 0., _atanenv_func, &xU, 0 );
1838 cv[0] = std::atan(x), cv[1] = 1./(1.+sqr(x));
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;
1846 template <
typename T>
inline double*
1847 McCormick<T>::_atancc
1848 (
const double x,
const double xL,
const double xU )
1850 static double cc[2];
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;
1858 cc[0] = std::atan(x), cc[1] = 1./(1.+sqr(x));
1864 xj = _newton( xU, 0., xU, _atanenv_func, _atanenv_dfunc, &xL, 0 );
1866 catch( McCormick<T>::Exceptions ){
1867 xj = _goldsect( 0., xU, _atanenv_func, &xL, 0 );
1870 cc[0] = std::atan(x), cc[1] = 1./(1.+sqr(x));
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;
1878 template <
typename T>
inline double
1879 McCormick<T>::_atanenv_func
1880 (
const double x,
const double*rusr,
const int*iusr )
1883 return (x-*rusr)-(1.+sqr(x))*(std::atan(x)-std::atan(*rusr));
1886 template <
typename T>
inline double
1887 McCormick<T>::_atanenv_dfunc
1888 (
const double x,
const double*rusr,
const int*iusr )
1891 return -2.*x*(std::atan(x)-std::atan(*rusr));
1894 template <
typename T>
inline double*
1895 McCormick<T>::_oddpowcv
1896 (
const double x,
const int iexp,
const double xL,
const double xU )
1898 static double cv[2];
1900 double v = std::pow(x,iexp-1);
1901 cv[0] = x*v, cv[1] = iexp*v;
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;
1914 xj = _newton( xU, 0., xU, _oddpowenv_func, _oddpowenv_dfunc, &xL, &iexp );
1916 catch( McCormick<T>::Exceptions ){
1917 xj = _goldsect( 0., xU, _oddpowenv_func, &xL, &iexp );
1920 double v = std::pow(x,iexp-1);
1921 cv[0] = x*v, cv[1] = iexp*v;
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;
1930 template <
typename T>
inline double*
1931 McCormick<T>::_oddpowcc
1932 (
const double x,
const int iexp,
const double xL,
const double xU )
1934 static double cc[2];
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;
1942 double v = std::pow(x,iexp-1);
1943 cc[0] = x*v, cc[1] = iexp*v;
1949 xj = _newton( xL, xL, 0., _oddpowenv_func, _oddpowenv_dfunc, &xU, &iexp );
1951 catch( McCormick<T>::Exceptions ){
1952 xj = _goldsect( xL, 0., _oddpowenv_func, &xU, &iexp );
1955 double v = std::pow(x,iexp-1);
1956 cc[0] = x*v, cc[1] = iexp*v;
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;
1965 template <
typename T>
inline double
1966 McCormick<T>::_oddpowenv_func
1967 (
const double x,
const double*rusr,
const int*iusr )
1970 return ((*iusr-1)*x-(*rusr)*(*iusr))*std::pow(x,*iusr-1)
1971 + std::pow(*rusr,*iusr);
1974 template <
typename T>
inline double
1975 McCormick<T>::_oddpowenv_dfunc
1976 (
const double x,
const double*rusr,
const int*iusr )
1979 return ((*iusr)*(*iusr-1)*x-(*rusr)*(*iusr)*(*iusr-1))*std::pow(x,*iusr-2);
1982 template <
typename T>
inline double*
1983 McCormick<T>::_stepcv
1984 (
const double x,
const double xL,
const double xU )
1986 static double cv[2];
1994 cv[0] = 1., cv[1] = 0.;
1998 cv[0] = x/xU, cv[1] = 1./xU;
2002 template <
typename T>
inline double*
2003 McCormick<T>::_stepcc
2004 (
const double x,
const double xL,
const double xU )
2006 static double cc[2];
2009 cc[0] = 1., cc[1] = 0.;
2014 cc[0] = 0., cc[1] = 0.;
2018 cc[0] = 1.-x/xL, cc[1] = -1./xL;
2022 template <
typename T>
inline double*
2023 McCormick<T>::_cosarg
2024 (
const double xL,
const double xU )
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 );
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;
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;
2042 template <
typename T>
inline double*
2043 McCormick<T>::_coscv
2044 (
const double x,
const double xL,
const double xU )
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);
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;
2060 return _coscv2( x+2.*PI*kL, xL1, xU1 );
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);
2070 return _coscv2( x+2.*PI*kU, std::max(xL+2.*PI*kU,-PI), xU2 );
2073 cv[0] = -1., cv[1] = 0.;
2077 template <
typename T>
inline double*
2078 McCormick<T>::_coscv2
2079 (
const double x,
const double xL,
const double xU )
2083 if( std::fabs(xL)<=std::fabs(xU) )
2084 left =
false, x0 = xU, xm = xL;
2086 left =
true, x0 = xL, xm = xU;
2090 xj = _newton( x0, xL, xU, _cosenv_func, _cosenv_dfunc, &xm, 0 );
2092 catch( McCormick<T>::Exceptions ){
2093 xj = _goldsect( xL, xU, _cosenv_func, &xm, 0 );
2095 static double cv[2];
2096 if(( left && x<=xj ) || ( !left && x>=xj )){
2097 cv[0] = std::cos(x), cv[1] = -std::sin(x);
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;
2105 template <
typename T>
inline double*
2106 McCormick<T>::_coscc
2107 (
const double x,
const double xL,
const double xU )
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];
2115 template <
typename T>
inline double
2116 McCormick<T>::_cosenv_func
2117 (
const double x,
const double*rusr,
const int*iusr )
2121 return ((x-*rusr)*std::sin(x)+std::cos(x)-std::cos(*rusr));
2124 template <
typename T>
inline double
2125 McCormick<T>::_cosenv_dfunc
2126 (
const double x,
const double*rusr,
const int*iusr )
2129 return ((x-*rusr)*std::cos(x));
2132 template <
typename T>
inline double*
2133 McCormick<T>::_asincv
2134 (
const double x,
const double xL,
const double xU )
2136 static double cv[2];
2138 cv[0] = std::asin(x), cv[1] = 1./std::sqrt(1-x*x);
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;
2149 xj = _secant( 0., xU, 0., xU, _asinenv_func, &xL, 0 );
2151 catch( McCormick<T>::Exceptions ){
2152 xj = _goldsect( 0., xU, _asinenv_func, &xL, 0 );
2155 cv[0] = std::asin(x), cv[1] = 1./std::sqrt(1-x*x);
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;
2163 template <
typename T>
inline double*
2164 McCormick<T>::_asincc
2165 (
const double x,
const double xL,
const double xU )
2167 static double cc[2];
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;
2174 cc[0] = std::asin(x), cc[1] = 1./std::sqrt(1-x*x);
2180 xj = _secant( 0., xL, xL, 0., _asinenv_func, &xU, 0 );
2182 catch( McCormick<T>::Exceptions ){
2183 xj = _goldsect( xL, 0., _asinenv_func, &xU, 0 );
2186 cc[0] = std::asin(x), cc[1] = 1./std::sqrt(1-x*x);
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;
2194 template <
typename T>
inline double
2195 McCormick<T>::_asinenv_func
2196 (
const double x,
const double*rusr,
const int*iusr )
2199 return x-(*rusr)-std::sqrt(1.-x*x)*(std::asin(x)-std::asin(*rusr));
2202 template <
typename T>
inline double
2203 McCormick<T>::_asinenv_dfunc
2204 (
const double x,
const double*rusr,
const int*iusr )
2207 return x/std::sqrt(1.-x*x)*(std::asin(x)-std::asin(*rusr));
2210 template <
typename T>
inline double*
2211 McCormick<T>::_tancv
2212 (
const double x,
const double xL,
const double xU )
2214 static double cv[2];
2216 cv[0] = std::tan(x), cv[1] = 1.+sqr(std::tan(x));
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;
2227 xj = _secant( 0., xU, 0., xU, _tanenv_func, &xL, 0 );
2229 catch( McCormick<T>::Exceptions ){
2230 xj = _goldsect( 0., xU, _tanenv_func, &xL, 0 );
2233 cv[0] = std::tan(x), cv[1] = 1.+sqr(std::tan(x));
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;
2241 template <
typename T>
inline double*
2242 McCormick<T>::_tancc
2243 (
const double x,
const double xL,
const double xU )
2245 static double cc[2];
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;
2252 cc[0] = std::tan(x), cc[1] = 1.+sqr(std::tan(x));
2258 xj = _secant( 0., xL, xL, 0., _tanenv_func, &xU, 0 );
2260 catch( McCormick<T>::Exceptions ){
2261 xj = _goldsect( xL, 0., _tanenv_func, &xU, 0 );
2264 cc[0] = std::tan(x), cc[1] = 1.+sqr(std::tan(x));
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;
2272 template <
typename T>
inline double
2273 McCormick<T>::_tanenv_func
2274 (
const double x,
const double*rusr,
const int*iusr )
2277 return (x-(*rusr))-(std::tan(x)-std::tan(*rusr))/(1.+sqr(std::tan(x)));
2280 template <
typename T>
inline double
2281 McCormick<T>::_tanenv_dfunc
2282 (
const double x,
const double*rusr,
const int*iusr )
2285 return 2.*std::tan(x)/(1.+sqr(std::tan(x)))*(std::tan(x)-std::tan(*rusr));
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 )
2293 double xk = std::max(xL,std::min(xU,x0));
2294 double fk = f(xk,rusr,iusr);
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);
2306 throw Exceptions( Exceptions::ENVEL );
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 )
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));
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;
2327 xk = std::max(xL,std::min(xU,xk-fk/Bk));
2330 throw Exceptions( Exceptions::ENVEL );
2333 template <
typename T>
inline double
2334 McCormick<T>::_goldsect
2335 (
const double xL,
const double xU, puniv f,
const double*rusr,
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 );
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 )
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);
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 ) );
2370 template <
typename T>
inline McCormick<T>
2372 (
const McCormick<T>&MC )
2374 McCormick<T> MC2( MC );
2378 template <
typename T>
inline McCormick<T>
2380 (
const McCormick<T>&MC )
2382 McCormick<T> MC2( MC );
2386 template <
typename T>
inline McCormick<T>
2388 (
const double a,
const McCormick<T>&MC )
2391 MC2._sub( MC._nsub, MC._const );
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];
2402 template <
typename T>
inline McCormick<T>
2404 (
const McCormick<T>&MC,
const double a )
2409 template <
typename T>
inline McCormick<T>
2411 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
2415 MC3._sub( MC1._nsub, MC1._const );
2416 return MC3._sum1( MC1, MC2 );
2420 MC3._sub( MC2._nsub, MC2._const );
2421 return MC3._sum1( MC2, MC1 );
2423 if( MC1._nsub != MC2._nsub )
2426 MC3._sub( MC1._nsub, MC1._const||MC2._const );
2427 return MC3._sum2( MC1, MC2 );
2430 template <
typename T>
inline McCormick<T>
2432 (
const McCormick<T>&MC )
2435 MC2._sub( MC._nsub, MC._const );
2439 for(
unsigned int i=0; i<MC2._nsub; i++ ){
2440 MC2._cvsub[i] = -MC._ccsub[i];
2441 MC2._ccsub[i] = -MC._cvsub[i];
2446 template <
typename T>
inline McCormick<T>
2448 (
const McCormick<T>&MC,
const double a )
2453 template <
typename T>
inline McCormick<T>
2455 (
const double a,
const McCormick<T>&MC )
2458 MC2._sub( MC._nsub, MC._const );
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];
2469 template <
typename T>
inline McCormick<T>
2471 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
2473 if( &MC1 == &MC2 )
return 0;
2477 MC3._sub( MC1._nsub, MC1._const );
2478 return MC3._sub1( MC1, MC2 );
2482 MC3._sub( MC2._nsub, MC2._const );
2483 return MC3._sub2( MC1, MC2 );
2485 if( MC1._nsub != MC2._nsub )
2488 MC3._sub( MC1._nsub, MC1._const||MC2._const );
2489 return MC3._sub3( MC1, MC2 );
2492 template <
typename T>
inline McCormick<T>
2494 (
const double a,
const McCormick<T>&MC )
2497 MC2._sub( MC._nsub, MC._const );
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];
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];
2518 template <
typename T>
inline McCormick<T>
2520 (
const McCormick<T>&MC,
const double a )
2525 template <
typename T>
inline McCormick<T>
2527 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
2529 if( &MC1 == &MC2 )
return sqr(MC1);
2531 bool thin1 = isequal( Op<T>::diam(MC1._I), 0. );
2532 bool thin2 = isequal( Op<T>::diam(MC2._I), 0. );
2534 if ( McCormick<T>::options.MVCOMP_USE && !(thin1||thin2) ){
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 )
2543 MC3._sub( MC1._nsub, MC1._const||MC2._const );
2545 MC3._I = MC1._I * MC2._I;
2546 return MC3._mulMV( MC1, MC2 ).cut();
2549 if ( Op<T>::l(MC1._I) >= 0. ){
2550 if ( Op<T>::l(MC2._I) >= 0. ){
2553 MC3._sub( MC1._nsub, MC1._const );
2554 return MC3._mul1_u1pos_u2pos( MC1, MC2 ).cut();
2558 MC3._sub( MC2._nsub, MC2._const );
2559 return MC3._mul1_u1pos_u2pos( MC2, MC1 ).cut();
2561 if( MC1._nsub != MC2._nsub )
2564 MC3._sub( MC1._nsub, MC1._const||MC2._const );
2565 return MC3._mul2_u1pos_u2pos( MC1, MC2 ).cut();
2567 if ( Op<T>::u(MC2._I) <= 0. ){
2568 return -( MC1 * (-MC2) );
2572 MC3._sub( MC1._nsub, MC1._const );
2573 return MC3._mul1_u1pos_u2mix( MC1, MC2 ).cut();
2577 MC3._sub( MC2._nsub, MC2._const );
2578 return MC3._mul2_u1pos_u2mix( MC1, MC2 ).cut();
2580 if( MC1._nsub != MC2._nsub )
2583 MC3._sub( MC1._nsub, MC1._const||MC2._const );
2584 return MC3._mul3_u1pos_u2mix( MC1, MC2 ).cut();
2587 if ( Op<T>::u(MC1._I) <= 0. ){
2588 if ( Op<T>::l(MC2._I) >= 0. ){
2589 return -( (-MC1) * MC2);
2591 if ( Op<T>::u(MC2._I) <= 0. ){
2592 return (-MC1) * (-MC2);
2594 return -( MC2 * (-MC1) );
2597 if ( Op<T>::l(MC2._I) >= 0. ){
2600 if ( Op<T>::u(MC2._I) <= 0. ){
2601 return -( (-MC2) * MC1 );
2605 MC3._sub( MC1._nsub, MC1._const );
2606 return MC3._mul1_u1mix_u2mix( MC1, MC2 ).cut();
2610 MC3._sub( MC2._nsub, MC2._const );
2611 return MC3._mul1_u1mix_u2mix( MC2, MC1 ).cut();
2613 if( MC1._nsub != MC2._nsub )
2616 MC3._sub( MC1._nsub, MC1._const||MC2._const );
2617 return MC3._mul2_u1mix_u2mix( MC1, MC2 ).cut();
2620 template <
typename T>
inline McCormick<T>
2622 (
const McCormick<T>&MC,
const double a )
2624 if ( isequal( a, 0. ))
2629 template <
typename T>
inline McCormick<T>
2631 (
const double a,
const McCormick<T>&MC )
2633 return a * inv( MC );
2636 template <
typename T>
inline McCormick<T>
2638 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
2640 if( &MC1 == &MC2 )
return 1.;
2642 bool posorthant = ( Op<T>::l(MC1._I) >= 0. && Op<T>::l(MC2._I) > 0. );
2644 if ( McCormick<T>::options.MVCOMP_USE && posorthant){
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 )
2653 MC3._sub( MC1._nsub, MC1._const||MC2._const );
2655 MC3._I = MC1._I / MC2._I;
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 ));
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);
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 ));
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 ));
2696 return MC1 * inv( MC2 );
2699 template <
typename T>
inline McCormick<T>
2701 (
const McCormick<T>&MC )
2703 if ( Op<T>::l(MC._I) <= 0. && Op<T>::u(MC._I) >= 0. )
2706 MC2._sub( MC._nsub, MC._const );
2707 MC2._I = Op<T>::inv( MC._I );
2709 if ( Op<T>::l(MC._I) > 0. ){
2711 double vmid = mid( MC._cv, MC._cc, Op<T>::u(MC._I), imid );
2713 for(
unsigned int i=0; i<MC2._nsub; i++ )
2714 MC2._cvsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid )
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) );
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) );
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 )
2746 template <
typename T>
inline McCormick<T>
2748 (
const McCormick<T>&MC )
2751 MC2._sub( MC._nsub, MC._const );
2752 MC2._I = Op<T>::sqr( MC._I );
2754 double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), 0., imid );
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 );
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;
2777 template <
typename T>
inline McCormick<T>
2779 (
const McCormick<T>&MC )
2782 MC2._sub( MC._nsub, MC._const );
2783 MC2._I = Op<T>::exp( MC._I );
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;
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;
2805 template <
typename T>
inline McCormick<T>
2807 (
const McCormick<T>&MC,
const double k )
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 ) );
2814 MC2._sub( MC._nsub, MC._const );
2815 MC2._I = Op<T>::arh( MC._I, k );
2817 if ( Op<T>::u(MC._I) <= 0.5*k ){
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 );
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;
2838 else if ( Op<T>::l(MC._I) >= 0.5*k ){
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;
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 );
2860 template <
typename T>
inline McCormick<T>
2862 (
const McCormick<T>&MC )
2864 if ( Op<T>::l(MC._I) <= 0. )
2867 MC2._sub( MC._nsub, MC._const );
2868 MC2._I = Op<T>::log( MC._I );
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;
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;
2891 template <
typename T>
inline McCormick<T>
2893 (
const McCormick<T>&MC )
2895 if ( Op<T>::l(MC._I) <= 0. )
2898 MC2._sub( MC._nsub, MC._const );
2899 MC2._I = Op<T>::xlog( MC._I );
2902 double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), std::exp(-1.), imid );
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,
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) );
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) );
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;
2926 template <
typename T>
inline McCormick<T>
2928 (
const McCormick<T>&MC )
2930 if ( Op<T>::l(MC._I) < 0. )
2933 MC2._sub( MC._nsub, MC._const );
2934 MC2._I = Op<T>::sqrt( MC._I );
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) );
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;
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);
2957 template <
typename T>
inline McCormick<T>
2959 (
const McCormick<T> &MC )
2961 return ( 1. - erf( MC ) );
2964 template <
typename T>
inline McCormick<T>
2966 (
const McCormick<T>&MC )
2969 MC2._sub( MC._nsub, MC._const );
2970 MC2._I = Op<T>::erf( MC._I );
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.;
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) );
2985 for(
unsigned int i=0; i<MC2._nsub; i++ ){
2986 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[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) );
2993 for(
unsigned int i=0; i<MC2._nsub; i++ ){
2994 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
3000 template <
typename T>
inline McCormick<T>
3002 (
const McCormick<T>&MC,
const int n )
3012 if( n >= 2 && !(n%2) ){
3014 MC2._sub( MC._nsub, MC._const );
3015 MC2._I = Op<T>::pow( MC._I, n );
3017 double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), 0., imid );
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 );
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;
3037 if( n >= 3 && McCormick<T>::options.ENVEL_USE ){
3039 MC2._sub( MC._nsub, MC._const );
3040 MC2._I = Op<T>::pow( MC._I, n );
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) );
3045 for(
unsigned int i=0; i<MC2._nsub; i++ ){
3046 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[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) );
3053 for(
unsigned int i=0; i<MC2._nsub; i++ ){
3054 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
3061 return pow( MC, n-1 ) * MC;
3068 if ( Op<T>::l(MC._I) <= 0. && Op<T>::u(MC._I) >= 0. )
3071 MC2._sub( MC._nsub, MC._const );
3072 MC2._I = Op<T>::pow( MC._I, n );
3074 if ( Op<T>::l(MC._I) > 0. ){
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 );
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 );
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 );
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 );
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 );
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 );
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 );
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 );
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 );
3133 template <
typename T>
inline McCormick<T>
3135 (
const McCormick<T> &MC,
const double a )
3137 return exp( a * log( MC ) );
3140 template <
typename T>
inline McCormick<T>
3142 (
const McCormick<T> &MC1,
const McCormick<T> &MC2 )
3144 return exp( MC2 * log( MC1 ) );
3147 template <
typename T>
inline McCormick<T>
3149 (
const double a,
const McCormick<T> &MC )
3151 return exp( MC * std::log( a ) );
3154 template <
typename T>
inline McCormick<T>
3156 (
const unsigned int n,
const McCormick<T>*MC,
const int*k)
3162 return pow( MC[0], k[0] );
3164 return pow( MC[0], k[0] ) * monomial( n-1, MC+1, k+1 );
3167 template <
typename T>
inline McCormick<T>
3169 (
const McCormick<T> &MC )
3172 MC2._sub( MC._nsub, MC._const );
3173 MC2._I = Op<T>::fabs( MC._I );
3176 double zmin = mid( Op<T>::l(MC._I), Op<T>::u(MC._I), 0., imid );
3178 double vmid = mid( MC._cv, MC._cc, zmin, imid );
3179 MC2._cv = std::fabs( vmid );
3181 for(
unsigned int i=0; i<MC2._nsub; i++ )
3182 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid );
3184 for(
unsigned int i=0; i<MC2._nsub; i++ )
3185 MC2._cvsub[i] = - mid( MC._cvsub, MC._ccsub, i, imid );
3189 double zmax = (std::fabs( Op<T>::l(MC._I) )>std::fabs( Op<T>::u(MC._I) )? Op<T>::l(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;
3202 template <
typename T>
inline McCormick<T>
3204 (
const McCormick<T> &MC1,
const McCormick<T> &MC2 )
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 )
3214 MC3._sub( MC1._nsub, MC1._const||MC2._const );
3215 MC3._I = Op<T>::min( MC1._I, MC2._I );
3217 if( Op<T>::u(MC1._I) <= Op<T>::l(MC2._I) ){
3219 for(
unsigned int i=0; i< MC3._nsub; i++ )
3220 MC3._cvsub[i] = (MC1._const? 0.: MC1._cvsub[i]);
3222 else if( Op<T>::u(MC2._I) <= Op<T>::l(MC1._I) ){
3224 for(
unsigned int i=0; i< MC3._nsub; i++ )
3225 MC3._cvsub[i] = (MC2._const? 0.: MC2._cvsub[i]);
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) );
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) );
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) );
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) );
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]);
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]);
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];
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]) );
3273 template <
typename T>
inline McCormick<T>
3275 (
const McCormick<T> &MC1,
const McCormick<T> &MC2 )
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 )
3285 MC3._sub( MC1._nsub, MC1._const||MC2._const );
3286 MC3._I = Op<T>::max( MC1._I, MC2._I );
3288 if( Op<T>::u(MC1._I) <= Op<T>::l(MC2._I) ){
3290 for(
unsigned int i=0; i< MC3._nsub; i++ )
3291 MC3._ccsub[i] = (MC1._const? 0.: MC1._ccsub[i]);
3293 else if( Op<T>::u(MC2._I) <= Op<T>::l(MC1._I) ){
3295 for(
unsigned int i=0; i< MC3._nsub; i++ )
3296 MC3._ccsub[i] = (MC2._const? 0.: MC2._ccsub[i]);
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) );
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) );
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) );
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) );
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]);
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]);
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];
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]) );
3344 template <
typename T>
inline McCormick<T>
3346 (
const unsigned int n,
const McCormick<T>*MC )
3348 McCormick<T> MC2( n==0 || !MC ? 0.: MC[0] );
3349 for(
unsigned int i=1; i<n; i++ ) MC2 = min( MC2, MC[i] );
3353 template <
typename T>
inline McCormick<T>
3355 (
const unsigned int n,
const McCormick<T>*MC )
3357 McCormick<T> MC2( n==0 || !MC ? 0.: MC[0] );
3358 for(
unsigned int i=1; i<n; i++ ) MC2 = max( MC2, MC[i] );
3362 template <
typename T>
inline McCormick<T>
3364 (
const McCormick<T> &MC )
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.);
3373 MC2._I = Op<T>::zeroone();
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),
3381 for(
unsigned int i=0; i<MC2._nsub; i++ )
3382 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid )*cvenv[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),
3391 for(
unsigned int i=0; i<MC2._nsub; i++ )
3392 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid )*ccenv[1];
3398 template <
typename T>
inline McCormick<T>
3400 (
const McCormick<T> &MC )
3402 return fstep( -MC );
3405 template <
typename T>
inline McCormick<T>
3407 (
const T &I0,
const McCormick<T> &MC1,
const McCormick<T> &MC2 )
3409 if( Op<T>::u( I0 ) < 0. )
return MC1;
3410 else if( Op<T>::l( I0 ) >= 0. )
return MC2;
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 )
3420 MC3._sub( MC1._nsub, MC1._const||MC2._const );
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];
3434 template <
typename T>
inline McCormick<T>
3436 (
const McCormick<T> &MC0,
const McCormick<T> &MC1,
const McCormick<T> &MC2 )
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];
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];
3453 template <
typename T>
inline McCormick<T>
3455 (
const T &I0,
const McCormick<T> &MC1,
const McCormick<T> &MC2 )
3457 return ltcond( -I0, MC1, MC2 );
3459 template <
typename T>
inline McCormick<T>
3461 (
const McCormick<T> &MC0,
const McCormick<T> &MC1,
const McCormick<T> &MC2 )
3463 return ltcond( -MC0, MC1, MC2 );
3466 template <
typename T>
inline McCormick<T>
3468 (
const McCormick<T> &MC )
3471 MC2._sub( MC._nsub, MC._const );
3472 MC2._I = Op<T>::cos( MC._I );
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.;
3483 double*argbnd = McCormick<T>::_cosarg( Op<T>::l(MC._I), Op<T>::u(MC._I) );
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) );
3488 for(
unsigned int i=0; i< MC2._nsub; i++ ){
3489 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[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) );
3496 for(
unsigned int i=0; i< MC2._nsub; i++ ){
3497 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
3503 template <
typename T>
inline McCormick<T>
3505 (
const McCormick<T> &MC )
3507 return cos( MC - PI/2. );
3510 template <
typename T>
inline McCormick<T>
3512 (
const McCormick<T> &MC )
3514 if ( Op<T>::l(MC._I) <= -1. || Op<T>::u(MC._I) >= 1. )
3518 MC2._sub( MC._nsub, MC._const );
3519 MC2._I = Op<T>::asin( MC._I );
3521 if( !McCormick<T>::options.ENVEL_USE ){
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 );
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 );
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) );
3543 for(
unsigned int i=0; i<MC2._nsub; i++ ){
3544 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[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) );
3551 for(
unsigned int i=0; i<MC2._nsub; i++ ){
3552 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
3558 template <
typename T>
inline McCormick<T>
3560 (
const McCormick<T> &MC )
3562 return asin( -MC ) + PI/2.;
3565 template <
typename T>
inline McCormick<T>
3567 (
const McCormick<T> &MC )
3569 if ( Op<T>::diam(MC._I) >= PI )
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. )
3577 MC2._sub( MC._nsub, MC._const );
3578 MC2._I = Op<T>::tan( MC._I );
3580 if( !McCormick<T>::options.ENVEL_USE ){
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 );
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 );
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 );
3603 for(
unsigned int i=0; i<MC2._nsub; i++ ){
3604 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[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 );
3612 for(
unsigned int i=0; i<MC2._nsub; i++ ){
3613 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
3619 template <
typename T>
inline McCormick<T>
3621 (
const McCormick<T> &MC )
3624 MC2._sub( MC._nsub, MC._const );
3625 MC2._I = Op<T>::atan( MC._I );
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.;
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) );
3640 for(
unsigned int i=0; i<MC2._nsub; i++ ){
3641 MC2._cvsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * cvenv[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) );
3648 for(
unsigned int i=0; i<MC2._nsub; i++ ){
3649 MC2._ccsub[i] = mid( MC._cvsub, MC._ccsub, i, imid ) * ccenv[1];
3655 template <
typename T>
inline std::ostream&
3657 ( std::ostream&out,
const McCormick<T>&MC)
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() <<
" ]";
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) <<
") ]";
3677 template <
typename T>
inline McCormick<T>
3679 (
const McCormick<T>&X,
const McCormick<T>&Y )
3681 if( !X._const && !Y._const && (X._nsub != Y._nsub) )
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() );
3688 XUY._sub( X._nsub, X._const );
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);
3698 template <
typename T>
inline bool
3700 ( McCormick<T>&XIY,
const McCormick<T>&X,
const McCormick<T>&Y )
3702 if( !X._const && !Y._const && (X._nsub != Y._nsub) )
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;
3712 XIY._sub( X._nsub, X._const );
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);
3722 template <
typename T>
inline bool
3724 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
3726 return( Op<T>::eq(MC1._I,MC2._I) && MC1._cv == MC2._cv && MC1._cc == MC2._cc );
3729 template <
typename T>
inline bool
3731 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
3733 return( Op<T>::ne(MC1._I,MC2._I) || MC1._cv != MC2._cv || MC1._cc != MC2._cc );
3736 template <
typename T>
inline bool
3738 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
3740 return( Op<T>::le(MC1._I,MC2._I) && MC1._cv >= MC2._cv && MC1._cc <= MC2._cc );
3743 template <
typename T>
inline bool
3745 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
3747 return( Op<T>::ge(MC1._I,MC2._I) && MC1._cv <= MC2._cv && MC1._cc >= MC2._cc );
3750 template <
typename T>
inline bool
3752 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
3754 return( Op<T>::lt(MC1._I,MC2._I) && MC1._cv > MC2._cv && MC1._cc < MC2._cc );
3757 template <
typename T>
inline bool
3759 (
const McCormick<T>&MC1,
const McCormick<T>&MC2 )
3761 return( Op<T>::gt(MC1._I,MC2._I) && MC1._cv < MC2._cv && MC1._cc > MC2._cc );
3764 template <
typename T>
typename McCormick<T>::Options McCormick<T>::options;
3778 static MC point(
const double c ) {
return MC(c); }
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(); }
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; }
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