MC++
cmodel.hpp
1 // Copyright (C) 2013-2014 Benoit Chachuat, Imperial College London.
2 // All Rights Reserved.
3 
190 #ifndef MC__CMODEL_H
191 #define MC__CMODEL_H
192 
193 #include "polymodel.hpp"
194 #include "mcop.hpp"
195 #include "mclapack.hpp"
196 
197 #undef MC__CMODEL_DEBUG
198 #undef MC__CMODEL_DEBUG_SCALE
199 #define MC__CMODEL_CHECK
200 #undef MC__CMODEL_CHECK_PMODEL
201 #undef MC__CVAR_DEBUG_EXP
202 #undef MC__CVAR_DEBUG_BERSTEIN
203 
204 namespace mc
205 {
206 
207 template <typename T> class CVar;
208 
217 template <typename T>
218 class CModel: public PolyModel
220 {
221  friend class CVar<T>;
222  template <typename U> friend class CModel;
223 
224  template <typename U> friend CVar<U> pow
225  ( const CVar<U>&, const int );
226 
227 public:
228 
232  CModel
234  ( const unsigned int nvar, const unsigned int nord )
235  : PolyModel( nvar, nord )
236  { _size(); }
237 
240  { _cleanup(); }
241 
243  const T* bndvar() const
244  { return _bndvar; }
245 
248  {
249  public:
251  enum TYPE{
252  DIV=1,
253  INV,
254  LOG,
258  INIT=-1,
259  INCON=-2,
260  CMODEL=-3,
261  UNDEF=-33
262  };
264  Exceptions( TYPE ierr ) : _ierr( ierr ){}
266  int ierr(){ return _ierr; }
268  std::string what(){
269  switch( _ierr ){
270  case DIV:
271  return "mc::CModel\t Division by zero scalar";
272  case INV:
273  return "mc::CModel\t Inverse operation with zero in range";
274  case LOG:
275  return "mc::CModel\t Log operation with non-positive numbers in range";
276  case SQRT:
277  return "mc::CModel\t Square-root operation with negative numbers in range";
278  case ACOS:
279  return "mc::CModel\t Sine/Cosine inverse operation with range outside [-1,1]";
280  case EIGEN:
281  return "mc::CModel\t Range bounder with eigenvalue decomposition failed";
282  case INIT:
283  return "mc::CModel\t Chebyshev variable initialization failed";
284  case INCON:
285  return "mc::CModel\t Inconsistent bounds with template parameter arithmetic";
286  case CMODEL:
287  return "mc::CModel\t Operation between Chebyshev variables in different Chebyshev model environment not allowed";
288  case UNDEF:
289  return "mc::CModel\t Feature not yet implemented in mc::CModel class";
290  default:
291  return "mc::CModel\t Undocumented error";
292  }
293  }
294 
295  private:
296  TYPE _ierr;
297  };
298 
300  struct Options
301  {
305  DISPLAY_DIGITS(5)
306  {}
308  template <typename U> Options
309  ( U&options )
310  : INTERP_EXTRA( options.INTERP_EXTRA ),
311  BOUNDER_TYPE( options.BOUNDER_TYPE ),
312  BOUNDER_ORDER( options.BOUNDER_ORDER ),
313  REF_POLY(options.REF_POLY),
314  DISPLAY_DIGITS(options.DISPLAY_DIGITS)
315  {}
317  template <typename U> Options& operator =
318  ( U&options ){
319  INTERP_EXTRA = options.INTERP_EXTRA;
320  BOUNDER_TYPE = options.BOUNDER_TYPE;
321  BOUNDER_ORDER = options.BOUNDER_ORDER;
322  REF_POLY = options.REF_POLY,
323  DISPLAY_DIGITS = options.DISPLAY_DIGITS;
324  return *this;
325  }
327  enum BOUNDER{
328  NAIVE=0,
329  LSB,
333  };
335  unsigned INTERP_EXTRA;
339  unsigned int BOUNDER_ORDER;
341  static const std::string BOUNDER_NAME[5];
343  double REF_POLY;
345  unsigned int DISPLAY_DIGITS;
346  } options;
349 private:
351  unsigned int ***_prodmon;
352 
354  T *_bndvar;
355 
357  double *_coefinterp;
358 
360  unsigned int _ncoefinterp;
361 
363  CVar<T>* _CV;
364 
366  void _size
367  ();
368 
370  void _reset();
371 
373  void _cleanup();
374 
376  double* _resize_coefinterp();
377 
379  void _set_prodmon();
380 
382  void _set_prodmon_exp
383  ( unsigned int&ivar, const unsigned int*iexp, const unsigned int iord,
384  unsigned int*iprodexp, unsigned int&nprodmon );
385 
387  void _set_bndvar
388  ( const unsigned int ivar, const T&X );
389 
391  T _bndmon
392  ( const unsigned int iord, const T&X );
393 
395  typedef double (puniv)
396  ( const double x );
397 
399  CVar<T> _intpow
400  ( const CVar<T>&CV, const int n ) const;
401 
403  static void _interpolation
404  ( double*coefmon, const unsigned nord, const T&X, puniv f );
405 
407  static CVar<T> _composition
408  ( const double* coefmon, const unsigned nord, const CVar<T>& CVI );
409 };
410 
411 template <typename T> const std::string CModel<T>::Options::BOUNDER_NAME[5]
412  = { "NAIVE", "LSB", "EIGEN", "BERNSTEIN", "HYBRID" };
413 
420 template <typename T>
421 class CVar: public PolyVar<T>
423 {
424  template <typename U> friend class CVar;
425  template <typename U> friend class CModel;
426 
427  template <typename U> friend CVar<U> operator+
428  ( const CVar<U>& );
429  template <typename U, typename V> friend CVar<U> operator+
430  ( const CVar<U>&, const CVar<V>& );
431  template <typename U> friend CVar<U> operator+
432  ( const CVar<U>&, const U& );
433  template <typename U> friend CVar<U> operator+
434  ( const U&, const CVar<U>& );
435  template <typename U> friend CVar<U> operator+
436  ( const double, const CVar<U>& );
437  template <typename U> friend CVar<U> operator+
438  ( const CVar<U>&, const double );
439  template <typename U> friend CVar<U> operator-
440  ( const CVar<U>& );
441  template <typename U, typename V> friend CVar<U> operator-
442  ( const CVar<U>&, const CVar<V>& );
443  template <typename U> friend CVar<U> operator-
444  ( const CVar<U>&, const U& );
445  template <typename U> friend CVar<U> operator-
446  ( const U&, const CVar<U>& );
447  template <typename U> friend CVar<U> operator-
448  ( const double, const CVar<U>& );
449  template <typename U> friend CVar<U> operator-
450  ( const CVar<U>&, const double );
451  template <typename U> friend CVar<U> operator*
452  ( const CVar<U>&, const CVar<U>& );
453  template <typename U> friend CVar<U> operator*
454  ( const CVar<U>&, const U& );
455  template <typename U> friend CVar<U> operator*
456  ( const U&, const CVar<U>& );
457  template <typename U> friend CVar<U> operator*
458  ( const CVar<U>&, const double );
459  template <typename U> friend CVar<U> operator*
460  ( const double, const CVar<U>& );
461  template <typename U> friend CVar<U> operator/
462  ( const CVar<U>&, const CVar<U>& );
463  template <typename U> friend CVar<U> operator/
464  ( const double, const CVar<U>& );
465  template <typename U> friend CVar<U> operator/
466  ( const CVar<U>&, const double );
467  template <typename U> friend std::ostream& operator<<
468  ( std::ostream&, const CVar<U>& );
469 
470  template <typename U> friend CVar<U> inv
471  ( const CVar<U>& );
472  template <typename U> friend CVar<U> sqr
473  ( const CVar<U>& );
474  template <typename U> friend U funcptr
475  ( const U, const unsigned int );
476  template <typename U> friend void interpolation
477  ( double*, const CVar<U>&, const unsigned int );
478  template <typename U> friend CVar<U> composition
479  ( const double*, const CVar<U>& );
480  template <typename U> friend CVar<U> sqrt
481  ( const CVar<U>& );
482  template <typename U> friend CVar<U> exp
483  ( const CVar<U>& );
484  template <typename U> friend CVar<U> log
485  ( const CVar<U>& );
486  template <typename U> friend CVar<U> xlog
487  ( const CVar<U>& );
488  template <typename U> friend CVar<U> pow
489  ( const CVar<U>&, const int );
490  template <typename U> friend CVar<U> pow
491  ( const CVar<U>&, const double );
492  template <typename U> friend CVar<U> pow
493  ( const double, const CVar<U>& );
494  template <typename U> friend CVar<U> pow
495  ( const CVar<U>&, const CVar<U>& );
496  template <typename U> friend CVar<U> monomial
497  ( const unsigned int, const CVar<U>*, const int* );
498  template <typename U> friend CVar<U> cos
499  ( const CVar<U>& );
500  template <typename U> friend CVar<U> sin
501  ( const CVar<U>& );
502  template <typename U> friend CVar<U> tan
503  ( const CVar<U>& );
504  template <typename U> friend CVar<U> acos
505  ( const CVar<U>& );
506  template <typename U> friend CVar<U> asin
507  ( const CVar<U>& );
508  template <typename U> friend CVar<U> atan
509  ( const CVar<U>& );
510  template <typename U> friend CVar<U> fabs
511  ( const CVar<U>& );
512  template <typename U> friend CVar<U> hull
513  ( const CVar<U>&, const CVar<U>& );
514  template <typename U> friend bool inter
515  ( CVar<U>&, const CVar<U>&, const CVar<U>& );
516 
517 public:
518  using PolyVar<T>::_coefmon;
519  using PolyVar<T>::_bndord;
520  using PolyVar<T>::_bndord_uptd;
521  using PolyVar<T>::_bndrem;
522  using PolyVar<T>::_bndpol;
523  using PolyVar<T>::_set_bndpol;
524  using PolyVar<T>::_unset_bndpol;
525  using PolyVar<T>::nvar;
526  using PolyVar<T>::nord;
527  using PolyVar<T>::nmon;
528  using PolyVar<T>::_posord;
529  using PolyVar<T>::_expmon;
530  using PolyVar<T>::_loc_expmon;
531  using PolyVar<T>::_get_binom;
532  using PolyVar<T>::_resize;
533  using PolyVar<T>::_set;
534  using PolyVar<T>::set;
535  using PolyVar<T>::get;
536  using PolyVar<T>::bound;
537  using PolyVar<T>::bndord;
538  using PolyVar<T>::_center;
539 
540 private:
542  CModel<T> *_CM;
543 
545  CVar<T>* _CV() const
546  { return _CM->_CV; };
547 
549  unsigned int* _prodmon
550  ( const unsigned int imon, const unsigned int jmon ) const
551  { return _CM->_prodmon[imon][jmon]; };
552 
554  const T& _bndvar
555  ( const unsigned int ivar ) const
556  { return _CM->_bndvar[ivar]; };
557 
559  double* _coefinterp() const
560  { return _CM->_resize_coefinterp(); };
561 
562 public:
566  CModel<T>* env() const
568  { return _CM; }
569 
571  CVar
572  ( const double d=0. );
573 
575  CVar
576  ( const T&B );
577 
579  CVar
580  ( CModel<T>*CM, const unsigned int ix, const T&X );
581 
583  template <typename U> CVar
584  ( CModel<T>*&CM, const CVar<U>&CV );
585 
587  template <typename U> CVar
588  ( CModel<T>*&CM, const CVar<U>&CV, const T& (U::*method)() const );
590  template <typename U> CVar
591  ( CModel<T>*&CM, const CVar<U>&CV, T (*method)( const U& ) );
592 
594  CVar
595  ( const CVar<T>&CV )
596  : PolyVar<T>( CV ), _CM( CV._CM )
597  {
598 #ifdef MC__CMODEL_CHECK_PMODEL
599  if( _CM != dynamic_cast< CModel<T>* >( PolyVar<T>::_CM ) ) assert( false );
600 #endif
601  }
602 
605  {}
608 private:
610  CVar
611  ( CModel<T>*CM, const double d=0. );
612 
614  CVar
615  ( CModel<T>*CM, const T&B );
616 
618  CVar<T>& _set
619  ( const unsigned int ivar, const T&X );
620 
621 public:
625  CVar<T>& set
627  ( CModel<T>*CM, const unsigned int ix, const T&X )
628  { set( CM ); _set( ix, X ); return *this; }
629 
631  CVar<T>& set
632  ( CModel<T>*CM )
633  { if( CM != _CM ){ _CM = CM; PolyVar<T>::set( _CM ); } return *this; }
634 
636  double polynomial
637  ( const double*x ) const;
638 
640  double P
641  ( const double*x ) const
642  { return polynomial( x ); }
643 
646  ()
647  const
648  { CVar<T> var = *this; *(var._bndrem) = 0.; return var; }
649 
651  CVar<T> P
652  ()
653  const
654  { return polynomial(); }
655 
658  { _center(); return *this; }
659 
662  { return center(); }
663 
665  double constant
666  ( const bool reset=false );
667 
669  double* linear() const;
670 
672  double linear
673  ( const unsigned int ivar, const bool reset=false );
676  CVar<T>& operator =
677  ( const CVar<T>& );
678  CVar<T>& operator =
679  ( const double );
680  CVar<T>& operator =
681  ( const T& );
682  template <typename U> CVar<T>& operator +=
683  ( const CVar<U>& );
684  template <typename U> CVar<T>& operator +=
685  ( const U& );
686  CVar<T>& operator +=
687  ( const double );
688  template <typename U> CVar<T>& operator -=
689  ( const CVar<U>& );
690  template <typename U> CVar<T>& operator -=
691  ( const U& );
692  CVar<T>& operator -=
693  ( const double );
694  CVar<T>& operator *=
695  ( const CVar<T>& );
696  CVar<T>& operator *=
697  ( const double );
698  CVar<T>& operator *=
699  ( const T& );
700  CVar<T>& operator /=
701  ( const CVar<T>& );
702  CVar<T>& operator /=
703  ( const double );
704 
705 private:
707  void _update_bndord() const;
708 
710  T _polybound
711  ( const int type ) const;
712 
714  T _polybound
715  () const
716  { return _polybound( _CM? _CM->options.BOUNDER_TYPE: 0 ); }
717 
719  T _polybound_naive() const;
720 
722  T _polybound_LSB() const;
723 
725  T _polybound_eigen() const;
726 
728  T _polybound_bernstein() const;
729 
731  typedef double (puniv)
732  ( const double x );
733 
735  void _interpolation
736  ( double*coefmon, puniv f ) const
737  { CModel<T>::_interpolation( coefmon, nord()+_CM->options.INTERP_EXTRA, bound(), f ); }
738 
740  CVar<T> _composition
741  ( const double* coefmon ) const
742  { return CModel<T>::_composition( coefmon, nord(), *this ); }
743 
745  CVar<T> _rescale
746  ( const double w, const double c ) const
747  { return( !isequal(w,0.)? (*this-c)*(2./w): c ); }
748 
750  //double _coef_bernstein
751  // ( const double*coefmon, const unsigned int*jexp,
752  // const unsigned int jmon, const unsigned int maxord ) const;
753 };
754 
756 
757 template <typename T> inline void
758 CModel<T>::_size
759 ()
760 {
761  _set_prodmon();
762  _bndvar = new T[_nvar];
763  for( unsigned int i=0; i<_nvar; i++ ) _bndvar[i] = 0.;
764  _ncoefinterp = 0; _coefinterp = 0;
765 
766  _CV = new CVar<T>( this );
767 }
768 /*
769 template <typename T> inline void
770 CModel<T>::_reset()
771 {
772  for( unsigned int i=0; i<_nvar; i++ ){
773  _bndvar[i] = 0;
774  }
775 }
776 */
777 template <typename T> inline void
778 CModel<T>::_cleanup()
779 {
780  for( unsigned int i=0; i<_nmon; i++ ){
781  for( unsigned int j=0; j<=i; j++ )
782  delete[] _prodmon[i][j];
783  delete[] _prodmon[i];
784  }
785  delete[] _prodmon;
786  delete[] _bndvar;
787  delete[] _coefinterp;
788  delete _CV;
789 }
790 
791 template <typename T> inline double*
792 CModel<T>::_resize_coefinterp()
793 {
794  if( _ncoefinterp > _nord+options.INTERP_EXTRA ) return _coefinterp;
795  delete[] _coefinterp;
796  _ncoefinterp = _nord+options.INTERP_EXTRA+1;
797  _coefinterp = new double[_ncoefinterp];
798  return _coefinterp;
799 }
800 
801 template <typename T> inline void
802 CModel<T>::_set_prodmon()
803 {
804  _prodmon = new unsigned int**[_nmon];
805  size_t prodmon_max = _nvar+1;
806  for( unsigned int i=0; i<_nvar && i<_nord; i++ ){ // <-- SIZE COULD BE TOO RESTRICTIVE!!!
807  if( prodmon_max > std::numeric_limits<size_t>::max()/2 )
808  throw typename PolyModel::Exceptions( PolyModel::Exceptions::MAXSIZE );
809  prodmon_max *= 2;
810  }
811  unsigned int *iexp = new unsigned int[prodmon_max];
812 
813  // Loop over all monic terms
814  for( unsigned int iord=0; iord<=_nord; iord++ ){
815  for( unsigned int imon=_posord[iord]; imon<_posord[iord+1]; imon++ ){
816 
817  // Loop over all monics whose indices are lower than or equal to imon
818  _prodmon[imon] = new unsigned int*[imon+1];
819  for( unsigned int jord=0, jmon=0; jord<=iord; jord++ ){
820  for( ; jmon<_posord[jord+1] && jmon<=imon; jmon++ ){
821 
822  // Current monic operand
823  iexp[0] = 0; // used to store partial order
824  for( unsigned int ivar=0; ivar<_nvar; ivar++ )
825  iexp[ivar+1] = _expmon[imon*_nvar+ivar];
826 #ifdef MC__CMODEL_DEBUG
827  mc::display( 1, _nvar, iexp+1, 1, "iexp:", std::cout );
828  mc::display( 1, _nvar, _expmon+jmon*_nvar, 1, "jexp:", std::cout );
829 #endif
830  // Construct product monics recursively and only keep those of order <= _nord
831  unsigned int nprodmax = 1, nprodmon = 1, kvar = 0;
832  for( unsigned int ivar=0; ivar<_nvar; ivar++ )
833  if( iexp[ivar+1] && _expmon[jmon*_nvar+ivar] ) nprodmax*=2;
834  _set_prodmon_exp( kvar, _expmon+jmon*_nvar, jord, iexp, nprodmon );
835  _prodmon[imon][jmon] = new unsigned int[nprodmon+2];
836  _prodmon[imon][jmon][0] = nprodmax;
837  _prodmon[imon][jmon][1] = 0;
838  for( unsigned int kmon=0; kmon<nprodmon; kmon++ ){
839 #ifdef MC__CMODEL_DEBUG
840  mc::display( 1, _nvar+1, iexp+kmon*(_nvar+1), 1, "ijexp:", std::cout );
841 #endif
842  // Eliminate monic terms with order > _nord
843  if( iexp[kmon*(_nvar+1)] > _nord ) continue;
844  _prodmon[imon][jmon][++_prodmon[imon][jmon][1]+1] = _loc_expmon( iexp+kmon*(_nvar+1)+1 );
845  }
846 #ifdef MC__CMODEL_DEBUG
847  std::ostringstream oheadi;
848  oheadi << "_prodmon[" << imon << "," << jmon << "]: max=" << nprodmax
849  << " cur=" << _prodmon[imon][jmon][1];
850  mc::display( 1, _prodmon[imon][jmon][1], _prodmon[imon][jmon]+2, 1, oheadi.str(), std::cout );
851 #endif
852  }
853  }
854  }
855  }
856 
857  delete[] iexp;
858 }
859 
860 template <typename T> inline void
861 CModel<T>::_set_prodmon_exp
862 ( unsigned int&kvar, const unsigned int*iexp, const unsigned int iord,
863  unsigned int*iprodexp, unsigned int&nprodmon )
864 {
865  if( kvar == _nvar || !nprodmon ) return;
866 
867  int nprodnew = 0;
868  for( unsigned int imon=0; imon<nprodmon; imon++ ){
869  // Product with Chebyshev basis function T0
870  if( !iexp[kvar] || !iprodexp[imon*(_nvar+1)+kvar+1] ){
871  iprodexp[imon*(_nvar+1)] += iprodexp[imon*(_nvar+1)+kvar+1] + iexp[kvar];
872  if( iprodexp[imon*(_nvar+1)] <= _nord )
873  iprodexp[imon*(_nvar+1)+kvar+1] += iexp[kvar];
874  }
875  // Product with Chebyshev basis function Ti, i>0
876  else{
877  // Only add term if resulting monic index remain less than or equal to _nord
878  if( iprodexp[imon*(_nvar+1)] + iprodexp[imon*(_nvar+1)+kvar+1] + iexp[kvar] <= _nord ){
879  for( unsigned int ivar=0; ivar<=_nvar; ivar++ )
880  iprodexp[(nprodmon+nprodnew)*(_nvar+1)+ivar] = iprodexp[imon*(_nvar+1)+ivar];
881  iprodexp[(nprodmon+nprodnew)*(_nvar+1)] += iprodexp[imon*(_nvar+1)+kvar+1] + iexp[kvar];
882  iprodexp[(nprodmon+nprodnew)*(_nvar+1)+kvar+1] += iexp[kvar];
883  nprodnew++;
884  }
885  if( iexp[kvar] <= iprodexp[imon*(_nvar+1)+kvar+1] ){
886  iprodexp[imon*(_nvar+1)] += iprodexp[imon*(_nvar+1)+kvar+1] - iexp[kvar];
887  if( iprodexp[imon*(_nvar+1)] <= _nord )
888  iprodexp[imon*(_nvar+1)+kvar+1] -= iexp[kvar];
889  }
890  else{
891  iprodexp[imon*(_nvar+1)] += iexp[kvar] - iprodexp[imon*(_nvar+1)+kvar+1];
892  if( iprodexp[imon*(_nvar+1)] <= _nord )
893  iprodexp[imon*(_nvar+1)+kvar+1] = iexp[kvar] - iprodexp[imon*(_nvar+1)+kvar+1];
894  }
895  }
896  }
897  nprodmon += nprodnew;
898  return _set_prodmon_exp( ++kvar, iexp, iord, iprodexp, nprodmon );
899 }
900 
901 template <typename T> inline void
902 CModel<T>::_set_bndvar
903 ( const unsigned int ivar, const T&X )
904 {
905  _bndvar[ivar] = X;
906 
907 #ifdef MC__CMODEL_DEBUG
908  mc::display( 1, _nvar, _bndvar, 1, "_bndvar", std::cout );
909 #endif
910 }
911 
912 template <typename T> inline T
913 CModel<T>::_bndmon
914 ( const unsigned int iord, const T&X )
915 {
916  assert( Op<T>::l(X) >= -1. && Op<T>::u(X) <= 1. );
917  switch( iord ){
918  case 0: return 1.;
919  case 1: return X;
920  case 2: return 2.*Op<T>::sqr(X)-1.;
921  default:{
922  double XL = Op<T>::l(X), XU = Op<T>::u(X), TL, TU;
923  unsigned kL = iord - std::ceil(iord*std::acos(XL)/mc::PI);
924  unsigned kU = iord - std::floor(iord*std::acos(XU)/mc::PI);
925  #ifdef MC__CMODEL_DEBUG
926  std::cout << "iord: " << iord << " X: " << X
927  << " kL: " << kL << " kU: " << kU << std::endl;
928 #endif
929  switch( kU-kL ){
930  case 0: case 1: // monotonic part
931  TL = std::cos(iord*std::acos(XL));
932  TU = std::cos(iord*std::acos(XU));
933  return( TL<=TU? Op<T>::zeroone()*(TU-TL)+TL: Op<T>::zeroone()*(TL-TU)+TU );
934  case 2: // extremum in range
935  TL = std::cos(iord*std::acos(XL));
936  TU = std::cos(iord*std::acos(XU));
937  if( (iord%2 && kL%2) || (!(iord%2) && !(kL%2)) ){
938  if( kL%2 ) return( Op<T>::zeroone()*((TU>TL?TU:TL)+1.)-1. ); // minimum
939  else return( Op<T>::zeroone()*((TU>TL?TL:TU)-1.)+1. ); // maximum
940  }
941  default: // two or more extrema in range
942  return Op<T>::zeroone();
943  }
944  } // ends: default case
945  }
946 }
947 
948 template <typename T> inline CVar<T>
949 CModel<T>::_intpow
950 ( const CVar<T>&CV, const int n ) const
951 {
952  if( n == 0 ) return 1.;
953  else if( n == 1 ) return CV;
954  return n%2 ? sqr( _intpow( CV, n/2 ) ) * CV : sqr( _intpow( CV, n/2 ) );
955 }
956 
957 template <typename T> inline void
958 CModel<T>::_interpolation
959 ( double*coefmon, const unsigned nord, const T&X, puniv f )
960 {
961  double b( Op<T>::mid(X) ), a( Op<T>::u(X)-b ), x[nord+1], fx[nord+1];
962  double mulconst( PI/(2.*double(nord+1)) );
963  for( unsigned int i(0); i<=nord; i++ ){
964  x[i] = std::cos(mulconst*(2.*double(i)+1.));
965  fx[i] = f( a*x[i]+b );
966  }
967 
968  switch( nord ){
969  case 0:
970  coefmon[0] = fx[0];
971  return;
972  case 1:
973  coefmon[0] = 0.5 * ( fx[0] + fx[1] );
974  coefmon[1] = ( fx[1] - fx[0] ) / ( x[1] - x[0] );
975  return;
976  default:
977  for( unsigned int i(0); i<=nord; i++ ){
978  double mulconst2( std::cos(mulconst*double(i)) ),
979  mulconst3( 4*std::pow(mulconst2,2)-2 ),
980  b0( 0 ), b1( 0 );
981  b0 = fx[nord];
982  b1 = fx[nord-1] + mulconst3*b0;
983  for( unsigned int j=nord-2; j>1; j-=2 ){
984  b0 = fx[j] + mulconst3*b1 - b0;
985  b1 = fx[j-1] + mulconst3*b0 - b1;
986  }
987  if( !(nord%2) )
988  b0 = fx[0] + mulconst3*b1 - b0 - b1;
989  else{
990  b0 = fx[1] + mulconst3*b1 - b0;
991  b0 = fx[0] + mulconst3*b0 - b1 - b0;
992  }
993  coefmon[i] = 2./double(nord+1)*mulconst2*b0;
994  }
995  coefmon[0] *=0.5;
996  return;
997  }
998 }
999 
1000 template <typename T> inline CVar<T>
1001 CModel<T>::_composition
1002 ( const double* coefmon, const unsigned nord, const CVar<T>& CVI )
1003 {
1004  CVar<T> CV1, CV2;
1005 
1006  //composition based on http://en.wikipedia.org/wiki/Clenshaw_algorithm#Special_case_for_Chebyshev_series
1007  switch( nord ){
1008  case 0:
1009  CV1 = coefmon[0];
1010  break;
1011  case 1:
1012  CV1 = coefmon[0] + 0.5*coefmon[1]*CVI;
1013  break;
1014  default:
1015  CV1 = coefmon[nord];
1016  CV2 = coefmon[nord-1] + CVI*CV1;
1017  for( unsigned i=nord-2; i>1; i-=2 ){
1018  CV1 = coefmon[i] + CVI*CV2 - CV1;
1019  CV2 = coefmon[i-1] + CVI*CV1 - CV2;
1020  }
1021  if( !(nord%2) ){
1022  CV1 = coefmon[0] + 0.5*CVI*CV2 - CV1;
1023  }
1024  else{
1025  CV1 = coefmon[1] + CVI*CV2 - CV1;
1026  CV1 = coefmon[0] + 0.5*CVI*CV1 - CV2;
1027  }
1028  break;
1029  }
1030  return CV1;
1031 }
1032 
1034 
1035 template <typename T> inline CVar<T>&
1036 CVar<T>::operator =
1037 ( const CVar<T>&CV )
1038 {
1039  _CM = CV._CM;
1040  _set( CV );
1041 #ifdef MC__CMODEL_CHECK_PMODEL
1042  if( _CM != dynamic_cast< CModel<T>* >( PolyVar<T>::_PM ) ) assert( false );
1043 #endif
1044  return *this;
1045 }
1046 
1047 template <typename T> inline
1048 CVar<T>::CVar
1049 ( const double d )
1050 : PolyVar<T>(), _CM( 0 )
1051 {
1052  _coefmon[0] = d;
1053  *_bndrem = 0.;
1054  _set_bndpol( d );
1055 }
1056 
1057 template <typename T> inline CVar<T>&
1059 ( const double d )
1060 {
1061  if( _CM ){ _CM = 0; _resize( _CM ); }
1062  _coefmon[0] = d;
1063  *_bndrem = 0.;
1064  _set_bndpol( d );
1065  return *this;
1066 }
1067 
1068 template <typename T> inline
1069 CVar<T>::CVar
1070 ( const T&B )
1071 : PolyVar<T>(), _CM( 0 )
1072 {
1073  _coefmon[0] = 0.;
1074  *_bndrem = B;
1075  _set_bndpol( 0. );
1076 }
1077 
1078 template <typename T> inline CVar<T>&
1080 ( const T&B )
1081 {
1082  if( _CM ){ _CM = 0; _resize( _CM ); }
1083  _coefmon[0] = 0.;
1084  *_bndrem = B;
1085  _set_bndpol( 0. );
1086  return *this;
1087 }
1088 
1089 template <typename T> inline
1090 CVar<T>::CVar
1091 ( CModel<T>*CM, const double d )
1092 : PolyVar<T>( CM ), _CM( CM )
1093 {
1094  if( !_CM ) throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::INIT );
1095  _coefmon[0] = d; for( unsigned int i=1; i<nmon(); i++ ) _coefmon[i] = 0.;
1096  _bndord[0] = d; for( unsigned int i=1; i<nord()+2; i++) _bndord[i] = 0.;
1097  _bndord_uptd = true;
1098  _set_bndpol( d );
1099 }
1100 
1101 template <typename T> inline
1102 CVar<T>::CVar
1103 ( CModel<T>*CM, const T&B )
1104 : PolyVar<T>( CM ), _CM( CM )
1105 {
1106  if( !_CM ) throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::INIT );
1107  for( unsigned int i=0; i<nmon(); i++ ) _coefmon[i] = 0.;
1108  for( unsigned int i=0; i<=nord(); i++) _bndord[i] = 0.;
1109  _bndord_uptd = true;
1110  *_bndrem = B;
1111  _set_bndpol( 0. );
1112  _center();
1113 }
1114 
1115 template <typename T> template <typename U> inline
1116 CVar<T>::CVar
1117 ( CModel<T>*&CM, const CVar<U>&CV )
1118 : PolyVar<T>( CM ), _CM( CM )
1119 {
1120  CVar<U> CVtrunc( CV );
1121  _coefmon[0] = CVtrunc._coefmon[0];
1122  CVtrunc._coefmon[0] = 0. ;
1123  for( unsigned int i=1; CM && i<nmon(); i++ ){
1124  if( CVtrunc.CM && i < CVtrunc.nmon() ){
1125  _coefmon[i] = CVtrunc._coefmon[i];
1126  CVtrunc._coefmon[i] = 0.;
1127  }
1128  else
1129  _coefmon[i] = 0.;
1130  }
1131  CVtrunc._bndord_uptd = false;
1132  *_bndrem = T( CVtrunc.B() );
1133  _bndord_uptd = false;
1134  return;
1135 }
1136 
1137 template <typename T> template <typename U> inline
1139 ( CModel<T>*&CM, const CVar<U>&CV, T (*method)( const U& ) )
1140 : PolyVar<T>( CM ), _CM( CM )
1141 {
1142  if( !method ) throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::INIT );
1143  CVar<U> CVtrunc( CV );
1144  _coefmon[0] = CVtrunc._coefmon[0];
1145  CVtrunc._coefmon[0] = 0. ;
1146  for( unsigned int i=1; CM && i<nmon(); i++ ){
1147  if( CVtrunc.CM && i < CVtrunc.nmon() ){
1148  _coefmon[i] = CVtrunc._coefmon[i];
1149  CVtrunc._coefmon[i] = 0.;
1150  }
1151  else
1152  _coefmon[i] = 0.;
1153  }
1154  CVtrunc._bndord_uptd = false;
1155  *_bndrem = (*method)( CVtrunc.B() );
1156  _bndord_uptd = false;
1157  return;
1158 }
1159 
1160 template <typename T> template <typename U> inline
1162 ( CModel<T>*&CM, const CVar<U>&CV, const T& (U::*method)() const )
1163 : PolyVar<T>( CM ), _CM( CM )
1164 {
1165  if( !method ) throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::INIT );
1166  CVar<U> CVtrunc( CV );
1167  _coefmon[0] = CVtrunc._coefmon[0];
1168  CVtrunc._coefmon[0] = 0. ;
1169  for( unsigned int i=1; CM && i<nmon(); i++ ){
1170  if( CVtrunc.CM && i < CVtrunc.nmon() ){
1171  _coefmon[i] = CVtrunc._coefmon[i];
1172  CVtrunc._coefmon[i] = 0.;
1173  }
1174  else
1175  _coefmon[i] = 0.;
1176  }
1177  CVtrunc._bndord_uptd = false;
1178  *_bndrem = (CVtrunc.B().*method)();
1179  _bndord_uptd = false;
1180  return;
1181 }
1182 
1183 template <typename T> inline CVar<T>&
1185 ( const unsigned int ivar, const T&X )
1186 {
1187  if( !_CM ) throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::INIT );
1188 
1189  // Keep track of variable bounds in CModel
1190  _CM->_set_bndvar( ivar, X );
1191 
1192  // Populate _coefmon w/ CVar coefficients
1193  _coefmon[0] = Op<T>::mid(X);
1194  for( unsigned int i=1; i<nmon(); i++ ) _coefmon[i] = 0.;
1195  if( nord() > 0 ) _coefmon[nvar()-ivar] = Op<T>::diam(X)/2.;
1196 
1197  // Populate _bndord w/ bounds on CVar terms
1198  _bndord[0] = _coefmon[0];
1199  if( nord() ){
1200  _bndord[1] = X-_coefmon[0];
1201  for( unsigned int i=2; i<nord()+2; i++) _bndord[i] = 0.;
1202  _set_bndpol( X );
1203  }
1204  else{ // 0th-order Taylor model
1205  *_bndrem = X-_coefmon[0];
1206  _set_bndpol( _coefmon[0] );
1207  }
1208  _bndord_uptd = true;
1209 
1210  return *this;
1211 }
1212 
1213 template <typename T> inline
1214 CVar<T>::CVar
1215 ( CModel<T>*CM, const unsigned int ivar, const T&X )
1216 : PolyVar<T>( CM ), _CM( CM )
1217 {
1218  _set( ivar, X );
1219 }
1220 
1221 template <typename T> inline void
1223 {
1224  if( !_CM || _bndord_uptd ) return;
1225  _bndord[0] = _coefmon[0];
1226  for( unsigned int i=1; i<=nord(); i++ ){
1227  _bndord[i] = 0.;
1228  for( unsigned int j=_posord(i); j<_posord(i+1); j++ )
1229  _bndord[i] += _coefmon[j] * T(-1.,1.);
1230  }
1231  _bndord_uptd = true;
1232 }
1233 
1234 template <typename T> inline T
1235 CVar<T>::_polybound_eigen() const
1236 {
1237  static const double TOL = 1e-8;
1238 
1239  T bndpol = _coefmon[0];
1240  if( nord() == 1 ) bndpol += _bndord[1];
1241 
1242  else if( nord() > 1 ){
1243  T bndmon = Op<T>::zeroone()*2.-1.;
1244  double*U = new double[nvar()*nvar()];
1245  for( unsigned int i=_posord(2); i<_posord(3); i++ ){
1246  unsigned int i1=0, i2=nvar();
1247  const unsigned int*iexp=_expmon(i);
1248  for( ; i1<nvar(); i1++ ) if( iexp[i1] ) break;
1249  if( iexp[i1] == 2 ){
1250  U[nvar()*i1+i1] = 2.*_coefmon[i];
1251  bndpol -= _coefmon[i];
1252  continue;
1253  }
1254  for( i2=i1+1; i2<nvar(); i2++ ) if( iexp[i2] ) break;
1255  U[nvar()*i1+i2] = 0.;
1256  U[nvar()*i2+i1] = _coefmon[i]/2.;
1257  }
1258 #ifdef MC__CVAR_DEBUG_EIGEN
1259  display( nvar(), nvar(), U, nvar(), "Matrix U", std::cout );
1260 #endif
1261  double*D = mc::dsyev_wrapper( nvar(), U, true );
1262  if( !D ){
1263  delete[] U;
1264  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::EIGEN );
1265  }
1266 
1267  for( unsigned int i=0; i<nvar(); i++ ){
1268  double linaux = 0.;
1269  T bndaux(0.);
1270  for( unsigned int k=0; k<nvar(); k++ ){
1271  linaux += U[i*nvar()+k] * _coefmon[nvar()-k];
1272  bndaux += U[i*nvar()+k] * bndmon;
1273  }
1274 #ifdef MC__CVAR_DEBUG_EIGEN
1275  std::cout << i << ": LINAUX = " << linaux
1276  << " BNDAUX = " << bndaux << std::endl;
1277 #endif
1278  if( std::fabs(D[i]) > TOL )
1279  bndpol += D[i] * Op<T>::sqr( linaux/D[i]/2. + bndaux )
1280  - linaux*linaux/D[i]/4.;
1281  else
1282  bndpol += linaux * bndaux + D[i] * Op<T>::sqr( bndaux );
1283 #ifdef MC__CVAR_DEBUG_EIGEN
1284  std::cout << "BNDPOL: " << bndpol << std::endl;
1285 #endif
1286  }
1287  delete[] U;
1288  delete[] D;
1289  }
1290 #ifdef MC__CVAR_DEBUG_EIGEN
1291  int tmp; std::cin >> tmp;
1292 #endif
1293 
1294  for( unsigned int i=3; i<=nord(); i++ ) bndpol += _bndord[i];
1295  return bndpol;
1296 }
1297 
1298 template <typename T> inline T
1299 CVar<T>::_polybound_LSB() const
1300 {
1301  static const double TOL = 1e-8;
1302 
1303  T bndpol = _coefmon[0];
1304  if( nord() == 1 ) bndpol += _bndord[1];
1305 
1306  else if( nord() > 1 ){
1307  T bndmon = Op<T>::zeroone()*2.-1.;
1308  for( unsigned int i=_posord(2); i<_posord(3); i++ ){
1309  unsigned int k=0;
1310  const unsigned int*iexp=_expmon(i);
1311  for( unsigned int j=0; j<nvar(); j++ ){
1312  k = ( iexp[j]==1? nvar(): j );
1313  if( iexp[j] ) break;
1314  }
1315  // off-diagonal quadratic terms
1316  if( k == nvar() ){
1317  bndpol += _coefmon[i] * bndmon;
1318  continue;
1319  }
1320  // linear and diagonal quadratic terms
1321  const double ai = _coefmon[nvar()-k], aii = _coefmon[i];
1322  if( std::fabs(aii) > TOL )
1323  bndpol += (2.*aii)*Op<T>::sqr(bndmon+ai/(aii*4.))-aii-ai*ai/8./aii;
1324  else
1325  bndpol += ai*bndmon+aii*bndmon;
1326  }
1327  }
1328  // higher-order terms
1329  for( unsigned int i=3; i<=nord(); i++ ) bndpol += _bndord[i];
1330  return bndpol;
1331 }
1332 
1333 template <typename T> inline T
1334 CVar<T>::_polybound_bernstein() const
1335 {
1336  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::UNDEF );
1337 /*
1338  // Scale Chebyshev model in unit hypercube with reference point at the origin
1339  double *coeftrans = new double[nmon()];
1340  for( unsigned int imon=0; imon<nmon(); imon++ )
1341  coeftrans[imon] = _coefmon[imon];
1342  for( unsigned int ivar=0; ivar<nvar(); ivar++ )
1343  _CM->_scale( ivar, coeftrans );
1344 
1345  // Expand binomial coefficient and exponent arrays if needed
1346  const unsigned int maxord = (_CM->options.BOUNDER_ORDER>nord()?
1347  _CM->options.BOUNDER_ORDER: nord() );
1348  const unsigned int maxmon = std::pow(maxord+1,nvar());
1349  _CM->_ext_expmon( maxord, true );
1350 
1351  // Compute min/max amongst all Bernstein coefficients
1352  bndmod = coeftrans[0];
1353 #ifdef MC__CVAR_DEBUG_BERSTEIN
1354  std::cout << "\n0: " << bndmod << std::endl;
1355 #endif
1356  for( unsigned int jmon=1; jmon<maxmon; jmon++ ){
1357  const unsigned int*jexp = _CM->_expmon + jmon*nvar();
1358  const double coefbern = _coef_bernstein( coeftrans, jexp, jmon, maxord );
1359  bndmod = Op<T>::hull( bndmod, coefbern );
1360 #ifdef MC__CVAR_DEBUG_BERNSTEIN
1361  std::cout << jmon << " [";
1362  for( unsigned int ivar=0; ivar<nvar(); ivar++ )
1363  std::cout << std::setw(3) << jexp[ivar];
1364  std::cout << "] : " << coefbern << " : " << bndmod << std::endl;
1365 #endif
1366  }
1367 
1368  delete[] coeftrans;
1369  bndmod += *_bndrem;
1370 */
1371  return T(0.);
1372 }
1373 
1374 /*
1375 template <typename T> inline double
1376 CVar<T>::_coef_bernstein
1377 ( const double*coefmon, const unsigned int*jexp,
1378  const unsigned int jmon, const unsigned int maxord ) const
1379 {
1380  // Compute bernstein coefficient with variables indices <tt>jexp</tt>
1381  double coefbern = coefmon[0];
1382  for( unsigned int imon=1; imon<=std::min(jmon,nmon()-1); imon++ ){
1383  const unsigned int*iexp = _CM->_expmon + imon*nvar();
1384  // Only append term if monomial degrees are lower
1385  bool inrange = true;
1386  for( unsigned int ivar=0; ivar<nvar() && inrange; ivar++ )
1387  if( iexp[ivar] > jexp[ivar] ) inrange = false;
1388  if( !inrange ) continue;
1389  double termbern = coefmon[imon];
1390 #ifdef MC__CVAR_DEBUG_BERSTEIN
1391  std::cout << " [";
1392  for( unsigned int ivar=0; ivar<nvar(); ivar++ )
1393  std::cout << std::setw(3) << iexp[ivar];
1394  std::cout << "]";
1395 #endif
1396  for( unsigned int ivar=0; ivar<nvar(); ivar++ )
1397  termbern *= (double)_CM->_get_binom(jexp[ivar],iexp[ivar])
1398  / (double)_CM->_get_binom(maxord,iexp[ivar]);
1399  coefbern += termbern;
1400  }
1401 #ifdef MC__CVAR_DEBUG_BERSTEIN
1402  std::cout << std::endl;
1403 #endif
1404  return coefbern;
1405 }
1406 */
1407 
1408 template <typename T> inline T
1409 CVar<T>::_polybound_naive() const
1410 {
1411  T bndpol = _coefmon[0];
1412  for( unsigned int i=1; i<=nord(); i++ ) bndpol += _bndord[i];
1413  return bndpol;
1414 }
1415 
1416 template <typename T> inline T
1417 CVar<T>::_polybound
1418 ( const int type ) const
1419 {
1420  if( !_CM ) return _coefmon[0];
1421 
1422  _update_bndord();
1423  switch( type ){
1425  return _polybound_naive();
1427  return _polybound_bernstein();
1429  return _polybound_eigen();
1431  T bndpol, bndpol_LSB = _polybound_LSB(), bndpol_eigen = _polybound_eigen();
1432  if( !Op<T>::inter( bndpol, bndpol_LSB, bndpol_eigen ) )
1433  // throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::INCON );
1434  return Op<T>::diam(bndpol_LSB)<Op<T>::diam(bndpol_eigen)? bndpol_LSB: bndpol_eigen;
1435  return bndpol;
1436  }
1437  case CModel<T>::Options::LSB: default:
1438  return _polybound_LSB();
1439  }
1440 }
1441 
1442 template <typename T> inline double
1444 ( const double*x ) const
1445 {
1446  if( !_CM ) return _coefmon[0];
1447 
1448  static const double TOL = machprec()*1e2;
1449  double xs[nvar()];
1450  for( unsigned k=0; k<nvar(); k++ ){
1451  const double dXk = Op<T>::diam(_CM->_bndvar[k]);
1452  xs[k] = ( dXk>TOL? 2.*(x[k]-Op<T>::l(_CM->_bndvar[k]))/dXk-1.
1453  : Op<T>::mid(_CM->_bndvar[k]) );
1454  }
1455  double Pval = _coefmon[0];
1456  for( unsigned int i=1; i<nmon(); i++ ){
1457  const unsigned int *iexp = _expmon(i);
1458  double valmon = 1.;
1459  for( unsigned int k=0; k<nvar(); k++ ){
1460  if( !iexp[k] ) continue;
1461  if( iexp[k] == 1 ) valmon *= xs[k];
1462  else if( iexp[k] == 2 ) valmon *= 2*xs[k]*xs[k]-1;
1463  else valmon *= std::cos(iexp[k]*std::acos(xs[k]));
1464  }
1465  Pval += _coefmon[i] * valmon;
1466  }
1467  return Pval;
1468 }
1469 
1470 template <typename T> inline double
1471 CVar<T>::constant( const bool reset )
1472 {
1473  const double coefconst = _coefmon[0];
1474  if( reset ) *this -= coefconst;
1475  return coefconst;
1476 }
1477 
1478 template <typename T> inline double*
1480 {
1481  if( !nvar() || !nord() ) return 0;
1482 
1483  double*plin = new double[nvar()];
1484  for( unsigned int i=0; i<nvar(); i++ )
1485  plin[i] = ( isequal( Op<T>::diam(_CM->bndvar()[i]), 0. )? 0.:
1486  _coefmon[nvar()-i] / Op<T>::diam(_CM->bndvar()[i]) * 2. );
1487  return plin;
1488 }
1489 
1490 template <typename T> inline double
1492 ( const unsigned int ivar, const bool reset )
1493 {
1494  if( ivar>=nvar() || !nord() ) return 0.;
1495  const bool zerorange = isequal( Op<T>::diam(_CM->bndvar()[ivar]), 0. );
1496  const double coeflin = ( zerorange? 0.: _coefmon[nvar()-ivar] / Op<T>::diam(_CM->bndvar()[ivar]) * 2. );
1497  if( !zerorange && reset ){ _coefmon[nvar()-ivar] = 0.; _bndord_uptd = false; _unset_bndpol(); }
1498  return coeflin;
1499 }
1500 
1501 template <typename T> inline std::ostream&
1502 operator <<
1503 ( std::ostream&out, const CVar<T>&CV )
1504 {
1505  out << std::endl
1506  << std::scientific << std::setprecision(5)
1507  << std::right;
1508 
1509  // Constant model
1510  if( !CV._CM ){
1511  out << " a0 = " << std::right << std::setw(12) << CV._coefmon[0]
1512  << std::endl
1513  << " R = " << *(CV._bndrem) << std::endl;
1514  }
1515 
1516  // Chebyshev coefficients and corresponding exponents
1517  else{
1518  out << std::setprecision(CV._CM->options.DISPLAY_DIGITS);
1519  for( unsigned int i=0; i<CV.nmon(); i++ ){
1520  out << " a" << std::left << std::setw(4) << i << " = "
1521  << std::right << std::setw(CV._CM->options.DISPLAY_DIGITS+7)
1522  << CV._coefmon[i] << " ";
1523  for( unsigned int k=0; k<CV.nvar(); k++ )
1524  out << std::setw(3) << CV._expmon(i)[k];
1525  out << std::endl;
1526  }
1527  // Remainder term
1528  out << std::right << " R = " << *(CV._bndrem)
1529  << std::endl;
1530  }
1531 
1532  // Range bounder
1533  out << std::right << " B = " << CV.B()
1534  << std::endl;
1535 
1536  return out;
1537 }
1538 
1539 template <typename T> inline CVar<T>
1540 operator +
1541 ( const CVar<T>&CV )
1542 {
1543  return CV;
1544 }
1545 
1546 template <typename T> template <typename U> inline CVar<T>&
1547 CVar<T>::operator +=
1548 ( const CVar<U>&CV )
1549 {
1550  if( !CV._CM ){
1551  _coefmon[0] += CV._coefmon[0];
1552  if( _CM && _bndord_uptd ) _bndord[0] += CV._coefmon[0];
1553  *_bndrem += *(CV._bndrem);
1554  if( _bndpol ) *_bndpol += CV._coefmon[0];
1555  }
1556  else if( !_CM ){
1557  CVar<T> CV2(*this);
1558  *this = CV; *this += CV2;
1559  }
1560  else{
1561  if( _CM != CV._CM )
1562  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::CMODEL );
1563  for( unsigned int i=0; i<nmon(); i++ )
1564  _coefmon[i] += CV._coefmon[i];
1565  if( CV._bndord_uptd )
1566  for( unsigned int i=0; _bndord_uptd && i<=nord(); i++ )
1567  _bndord[i] += CV._bndord[i];
1568  else _bndord_uptd = false;
1569  *_bndrem += *(CV._bndrem);
1570  if( _bndpol && CV._bndpol ) *_bndpol += *(CV._bndpol);
1571  else _unset_bndpol();
1572  }
1573  //if( _CM && _CM->options.CENTER_REMAINDER ) _center();
1574  return *this;
1575 }
1576 
1577 template <typename T, typename U> inline CVar<T>
1578 operator +
1579 ( const CVar<T>&CV1, const CVar<U>&CV2 )
1580 {
1581  CVar<T> CV3( CV1 );
1582  CV3 += CV2;
1583  return CV3;
1584 }
1585 
1586 template <typename T> inline CVar<T>&
1587 CVar<T>::operator +=
1588 ( const double c )
1589 {
1590  _coefmon[0] += c;
1591  if( _CM && _bndord_uptd ) _bndord[0] += c;
1592  if( _bndpol ) *_bndpol += c;
1593  //if( _CM && _CM->options.CENTER_REMAINDER ) _center();
1594  return *this;
1595 }
1596 
1597 template <typename T> inline CVar<T>
1598 operator +
1599 ( const CVar<T>&CV1, const double c )
1600 {
1601  CVar<T> CV3( CV1 );
1602  CV3 += c;
1603  return CV3;
1604 }
1605 
1606 template <typename T> inline CVar<T>
1607 operator +
1608 ( const double c, const CVar<T>&CV2 )
1609 {
1610  CVar<T> CV3( CV2 );
1611  CV3 += c;
1612  return CV3;
1613 }
1614 
1615 template <typename T> template <typename U> inline CVar<T>&
1616 CVar<T>::operator +=
1617 ( const U&I )
1618 {
1619  *_bndrem += I;
1620  _center();
1621  return *this;
1622 }
1623 
1624 template <typename T, typename U> inline CVar<T>
1625 operator +
1626 ( const CVar<T>&CV1, const U&I )
1627 {
1628  CVar<T> CV3( CV1 );
1629  CV3 += I;
1630  return CV3;
1631 }
1632 
1633 template <typename T, typename U> inline CVar<T>
1634 operator +
1635 ( const U&I, const CVar<T>&CV2 )
1636 {
1637  CVar<T> CV3( CV2 );
1638  CV2 += I;
1639  return CV3;
1640 }
1641 
1642 template <typename T> inline CVar<T>
1643 operator -
1644 ( const CVar<T>&CV )
1645 {
1646  if( !CV._CM ){
1647  CVar<T> CV2;
1648  CV2._coefmon[0] = -CV._coefmon[0];
1649  *CV2._bndrem = - *CV._bndrem;
1650  if( CV._bndpol ) CV2._set_bndpol( - *CV._bndpol );
1651  return CV2;
1652  }
1653  CVar<T>& CV2 = *CV._CV(); // Use internal Taylor variable to save time
1654  CV2._unset_bndpol(); CV2._bndord_uptd = false;
1655  for( unsigned int i=0; i<CV.nmon(); i++ ) CV2._coefmon[i] = -CV._coefmon[i];
1656  *CV2._bndrem = - *CV._bndrem;
1657  if( CV._bndord_uptd ){
1658  for( unsigned int i=0; i<=CV.nord(); i++ ) CV2._bndord[i] = -CV._bndord[i];
1659  CV2._bndord_uptd = true;
1660  }
1661  if( CV._bndpol ) CV2._set_bndpol( - *CV._bndpol );
1662  //if( CV._CM->options.CENTER_REMAINDER ) CV2._center();
1663  return CV2;
1664 }
1665 
1666 template <typename T> template <typename U> inline CVar<T>&
1667 CVar<T>::operator -=
1668 ( const CVar<U>&CV )
1669 {
1670  if( !CV._CM ){
1671  _coefmon[0] -= CV._coefmon[0];
1672  if( _CM && _bndord_uptd ) _bndord[0] -= CV._coefmon[0];
1673  *_bndrem -= *(CV._bndrem);
1674  if( _bndpol ) *_bndpol -= CV._coefmon[0];
1675  }
1676  else if( !_CM ){
1677  CVar<T> CV2(*this);
1678  *this = -CV; *this += CV2;
1679  }
1680  else{
1681  if( _CM != CV._CM )
1682  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::CMODEL );
1683  for( unsigned int i=0; i<nmon(); i++ )
1684  _coefmon[i] -= CV._coefmon[i];
1685  if( CV._bndord_uptd )
1686  for( unsigned int i=0; _bndord_uptd && i<=nord(); i++ )
1687  _bndord[i] -= CV._bndord[i];
1688  else _bndord_uptd = false;
1689  *_bndrem -= *(CV._bndrem);
1690  if( _bndpol && CV._bndpol ) *_bndpol -= *(CV._bndpol);
1691  else _unset_bndpol();
1692  }
1693  //if( _CM && _CM->options.CENTER_REMAINDER ) _center();
1694  return *this;
1695 }
1696 
1697 template <typename T, typename U> inline CVar<T>
1698 operator-
1699 ( const CVar<T>&CV1, const CVar<U>&CV2 )
1700 {
1701  CVar<T> CV3( CV1 );
1702  CV3 -= CV2;
1703  return CV3;
1704 }
1705 
1706 template <typename T> inline CVar<T>&
1707 CVar<T>::operator -=
1708 ( const double c )
1709 {
1710  _coefmon[0] -= c;
1711  if( _CM && _bndord_uptd ) _bndord[0] -= c;
1712  if( _bndpol ) *_bndpol -= c;
1713  //if( _CM && _CM->options.CENTER_REMAINDER ) _center();
1714  return *this;
1715 }
1716 
1717 template <typename T> inline CVar<T>
1718 operator -
1719 ( const CVar<T>&CV1, const double c )
1720 {
1721  CVar<T> CV3( CV1 );
1722  CV3 -= c;
1723  return CV3;
1724 }
1725 
1726 template <typename T> inline CVar<T>
1727 operator -
1728 ( const double c, const CVar<T>&CV2 )
1729 {
1730  CVar<T> CV3( -CV2 );
1731  CV3 += c;
1732  return CV3;
1733 }
1734 
1735 template <typename T> template <typename U> inline CVar<T>&
1736 CVar<T>::operator -=
1737 ( const U&I )
1738 {
1739  *_bndrem -= I;
1740  //if( _CM && _CM->options.CENTER_REMAINDER ) _center();
1741  return *this;
1742 }
1743 
1744 template <typename T, typename U> inline CVar<T>
1745 operator -
1746 ( const CVar<T>&CV1, const U&I )
1747 {
1748  CVar<T> CV3( CV1 );
1749  CV3 -= I;
1750  return CV3;
1751 }
1752 
1753 template <typename T, typename U> inline CVar<T>
1754 operator -
1755 ( const U&I, const CVar<T>&CV2 )
1756 {
1757  CVar<T> CV3( -CV2 );
1758  CV3 += I;
1759  return CV3;
1760 }
1761 
1762 template <typename T> inline CVar<T>&
1763 CVar<T>::operator *=
1764 ( const CVar<T>&CV )
1765 {
1766  CVar<T> CV2( *this );
1767  *this = CV * CV2;
1768  return *this;
1769 }
1770 
1771 template <typename T> inline CVar<T>
1772 operator *
1773 ( const CVar<T>&CV1, const CVar<T>&CV2 )
1774 {
1775  if( !CV2._CM ) return( CV1 * CV2._coefmon[0] + CV1 * *(CV2._bndrem) );
1776  else if( !CV1._CM ) return( CV2 * CV1._coefmon[0] + CV2 * *(CV1._bndrem) );
1777  else if( &CV1 == &CV2 ) return sqr(CV1);
1778 
1779  if( CV1._CM != CV2._CM )
1780  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::CMODEL );
1781  CVar<T>& CV3 = *CV1._CV();
1782  for( unsigned int i=0; i<CV3.nmon(); i++ ) CV3._coefmon[i] = 0.;
1783  *(CV3._bndrem) = 0.;
1784  T bndmon = Op<T>::zeroone()*2.-1.;
1785 
1786  // Populate _coefmon and _bndrem for product of polynomial parts
1787  for( unsigned int i=0; i<CV3.nmon(); i++ ){
1788  for( unsigned int j=0; j<i; j++ ){
1789  const unsigned int*prodij = CV3._prodmon(i,j);
1790  for( unsigned int k=0; k<prodij[1]; k++ )
1791  CV3._coefmon[prodij[2+k]] += ( CV1._coefmon[i] * CV2._coefmon[j]
1792  + CV1._coefmon[j] * CV2._coefmon[i] ) / (double)prodij[0];
1793  *(CV3._bndrem) += bndmon * ( ( CV1._coefmon[i] * CV2._coefmon[j]
1794  + CV1._coefmon[j] * CV2._coefmon[i] )
1795  * ( 1. - (double)prodij[1] / (double)prodij[0] ) );
1796  }
1797  const unsigned int*prodii = CV3._prodmon(i,i);
1798  for( unsigned int k=0; k<prodii[1]; k++ )
1799  CV3._coefmon[prodii[2+k]] += CV1._coefmon[i] * CV2._coefmon[i]
1800  / (double)prodii[0];
1801  *(CV3._bndrem) += bndmon * ( CV1._coefmon[i] * CV2._coefmon[i]
1802  * ( 1. - (double)prodii[1] / (double)prodii[0] ) );
1803  }
1804 
1805  // Populate _coefmon and _bndrem for product of polynomial and remainder parts
1806  T P1 = CV1._polybound(), P2 = CV2._polybound();
1807  //T P1 = 0., P2 = 0.;
1808  //for( unsigned int i=0; i<=CV3.nord(); i++ ){
1809  // P1 += CV1._bndord[i];
1810  // P2 += CV2._bndord[i];
1811  //}
1812  T R1 = *(CV3._bndrem) + ( P1 + *(CV1._bndrem) ) * *(CV2._bndrem) + P2 * *(CV1._bndrem);
1813  T R2 = *(CV3._bndrem) + P1 * *(CV2._bndrem) + ( P2 + *(CV2._bndrem) ) * *(CV1._bndrem);
1814  if( !Op<T>::inter( *(CV3._bndrem), R1, R2) )
1815  *(CV3._bndrem) = ( Op<T>::diam(R1)<Op<T>::diam(R2)? R1: R2 );
1816 
1817  // Update _bndord for product term (except remainder term)
1818  CV3._unset_bndpol();
1819  CV3._bndord_uptd = false;
1820  //if( CV3._CM->options.CENTER_REMAINDER ) CV3._center_CM();
1821  return CV3;
1822 }
1823 
1824 template <typename T> inline CVar<T>
1825 sqr
1826 ( const CVar<T>&CV )
1827 {
1828  if( !CV._CM ){
1829  CVar<T> CV2( CV );
1830  CV2._coefmon[0] *= CV2._coefmon[0];
1831  *(CV2._bndrem) *= 2. + *(CV2._bndrem);
1832  CV2._unset_bndpol();
1833  return CV2;
1834  }
1835 
1836  CVar<T>& CV2 = *CV._CV();
1837  for( unsigned int i=0; i<CV2.nmon(); i++ ) CV2._coefmon[i] = 0.;
1838  *(CV2._bndrem) = 0.;
1839  T bndmon = Op<T>::zeroone()*2.-1.;
1840 
1841  // Populate _coefmon and _bndrem for product of polynomial parts
1842  for( unsigned int i=0; i<CV2.nmon(); i++ ){
1843  for( unsigned int j=0; j<i; j++ ){
1844  const unsigned int*prodij = CV2._prodmon(i,j);
1845  for( unsigned int k=0; k<prodij[1]; k++ )
1846  CV2._coefmon[prodij[2+k]] += 2. * CV._coefmon[i] * CV._coefmon[j]
1847  / (double)prodij[0];
1848  *(CV2._bndrem) += bndmon * ( 2. * CV._coefmon[i] * CV._coefmon[j]
1849  * ( 1. - (double)prodij[1] / (double)prodij[0] ) );
1850  }
1851  const unsigned int*prodii = CV2._prodmon(i,i);
1852  for( unsigned int k=0; k<prodii[1]; k++ )
1853  CV2._coefmon[prodii[2+k]] += CV._coefmon[i] * CV._coefmon[i]
1854  / (double)prodii[0];
1855  *(CV2._bndrem) += bndmon * ( CV._coefmon[i] * CV._coefmon[i]
1856  * ( 1. - (double)prodii[1] / (double)prodii[0] ) );
1857  }
1858 
1859  // Populate _coefmon and _bndrem for product of polynomial and remainder parts
1860  //T PB = 0.;
1861  //for( unsigned int i=0; i<=CV3.nord(); i++ ) PB += CV._bndord[i];
1862  T PB = CV._polybound();
1863  *(CV2._bndrem) += ( 2. * PB + *(CV._bndrem) ) * *(CV._bndrem);
1864 
1865  // Populate _bndord for product term (except remainder term)
1866  CV2._unset_bndpol();
1867  CV2._bndord_uptd = false;
1868  //if( CV2._CM->options.CENTER_REMAINDER ) CV2._center_CM();
1869  return CV2;
1870 }
1871 
1872 template <typename T> inline CVar<T>&
1873 CVar<T>::operator *=
1874 ( const double c )
1875 {
1876  if( !_CM ){
1877  _coefmon[0] *= c;
1878  *(_bndrem) *= c;
1879  }
1880  else{
1881  for( unsigned int i=0; i<nmon(); i++ ) _coefmon[i] *= c;
1882  for( unsigned int i=0; _bndord_uptd && i<=nord(); i++ ) _bndord[i] *= c;
1883  *_bndrem *= c;
1884  }
1885  if( _bndpol ) *_bndpol *= c;
1886  return *this;
1887 }
1888 
1889 template <typename T> inline CVar<T>
1890 operator *
1891 ( const CVar<T>&CV1, const double c )
1892 {
1893  CVar<T> CV3( CV1 );
1894  CV3 *= c;
1895  return CV3;
1896 }
1897 
1898 template <typename T> inline CVar<T>
1899 operator *
1900 ( const double c, const CVar<T>&CV2 )
1901 {
1902  CVar<T> CV3( CV2 );
1903  CV3 *= c;
1904  return CV3;
1905 }
1906 
1907 template <typename T> inline CVar<T>&
1908 CVar<T>::operator *=
1909 ( const T&I )
1910 {
1911  if( !_CM ){
1912  *(_bndrem) += _coefmon[0];
1913  _coefmon[0] = 0.;
1914  *(_bndrem) *= I;
1915  }
1916  else{
1917  const double Imid = Op<T>::mid(I);
1918  T Icur = bound();
1919  for( unsigned int i=0; i<nmon(); i++ ) _coefmon[i] *= Imid;
1920  for( unsigned int i=0; _bndord_uptd && i<=nord(); i++ ) _bndord[i] *= Imid;
1921  *_bndrem *= Imid;
1922  *_bndrem += (I-Imid)*Icur;
1923  }
1924  //_bndord_uptd = false;
1925  _unset_bndpol();
1926  //if( _CM && _CM->options.CENTER_REMAINDER ) _center_CM();
1927  return (*this);
1928 }
1929 
1930 template <typename T> inline CVar<T>
1931 operator *
1932 ( const CVar<T>&CV1, const T&I )
1933 {
1934  CVar<T> CV3( CV1 );
1935  CV3 *= I;
1936  return CV3;
1937 }
1938 
1939 template <typename T> inline CVar<T>
1940 operator *
1941 ( const T&I, const CVar<T>&CV2 )
1942 {
1943  CVar<T> CV3( CV2 );
1944  CV3 *= I;
1945  return CV3;
1946 }
1947 
1948 template <typename T> inline CVar<T>&
1949 CVar<T>::operator /=
1950 ( const CVar<T>&CV )
1951 {
1952  *this *= inv(CV);
1953  return *this;
1954 }
1955 
1956 template <typename T> inline CVar<T>
1957 operator /
1958 ( const CVar<T>&CV1, const CVar<T>&CV2 )
1959 {
1960  return CV1 * inv(CV2);
1961 }
1962 
1963 template <typename T> inline CVar<T>&
1964 CVar<T>::operator /=
1965 ( const double c )
1966 {
1967  if( isequal( c, 0. ) )
1968  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::DIV );
1969  *this *= (1./c);
1970  return *this;
1971 }
1972 
1973 template <typename T> inline CVar<T>
1974 operator /
1975 ( const CVar<T>&CV, const double c )
1976 {
1977  if ( isequal( c, 0. ))
1978  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::DIV );
1979  return CV * (1./c);
1980 }
1981 
1982 template <typename T> inline CVar<T>
1983 operator /
1984 ( const double c, const CVar<T>&CV )
1985 {
1986  return inv(CV) * c;
1987 }
1988 /*
1989 template <typename T> inline CVar<T>
1990 inv
1991 ( const CVar<T>&CV )
1992 {
1993  if( !CV._CM )
1994  return CVar<T>( Op<T>::inv(CV._coefmon[0] + *(CV._bndrem)) );
1995 
1996  double b(Op<T>::mid(CV.B())), a(Op<T>::u(CV.B())-b), z0sq(-b/a), z0(std::sqrt(z0sq*z0sq-1.)),
1997  az0(b*b-a*a), invz0sq(-a/b), an, rem;
1998  CVar<T> CV2( CV._CM, 0. ), CV3( CV._CM, 0. ), CVm2 = CV._rescale(a,b);
1999 
2000  if(z0sq < 0) z0sq -= z0;
2001  else {z0sq += z0; z0*=-1.;}
2002 
2003  an = 2./az0*std::pow(invz0sq,-double(CV.nord()));
2004  //std::cout << "an: " << an << std::endl;
2005 
2006  //remainder based on sum of geometric series
2007  rem = an/(std::abs(z0sq)-1.);
2008 
2009  //composition based on http://en.wikipedia.org/wiki/Clenshaw_algorithm#Special_case_for_Chebyshev_series
2010  if (CV.nord() == 0)
2011  CV2 = an/2.;
2012  else if (CV.nord() == 1)
2013  CV2 = an*z0sq/2. + CVm2*an;
2014  else{
2015  CV2 = an;
2016  an *= z0sq;
2017  CV3 = an + CVm2*CV2;
2018 
2019  if (CV.nord() > 2) for( unsigned int i=CV.nord()-2; i>1; i-=2 ){
2020  an *= z0sq;
2021  CV2 = an + CVm2*CV3 - CV2;
2022  an *= z0sq;
2023  CV3 = an + CVm2*CV2 - CV3;
2024  }
2025 
2026  if (CV.nord()%2 == 0) {
2027  an *= 0.5*z0sq;
2028  CV2 = an + (CVm2/2.)*CV3 - CV2;
2029  }
2030  else {
2031  an *= z0sq;
2032  CV2 = an + CVm2*CV3 - CV2;
2033  an *= 0.5*z0sq;
2034  CV2 = an + (CVm2/2.)*CV2 - CV3;
2035  }
2036  }
2037 
2038  CV2 += T(-rem,rem);
2039 
2040  //CV2._bndord_uptd = false;
2041  //CV2._unset_bndpol();
2042  //if( CV2._CM->options.CENTER_REMAINDER ) CV2._center(); //crashes on order 0 for some reason.
2043  return CV2;
2044 }
2045 */
2046 
2047 template <typename T> inline CVar<T>
2048 inv
2049 ( const CVar<T>&CV )
2050 {
2051  if( !CV._CM )
2052  return CVar<T>( Op<T>::inv(CV._coefmon[0] + *(CV._bndrem)) );
2053  if ( Op<T>::l(CV.B()) <= 0. && Op<T>::u(CV.B()) >= 0. )
2054  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::INV );
2055 
2056  CVar<T> CVI( CV._CM, 0. ), CV2( CV._CM, 0. );
2057  //double coefmon[CV.nord()+1];
2058  double* coefmon = CV._coefinterp();
2059  CV._interpolation( coefmon, mc::inv );
2060 
2061  double b(Op<T>::mid(CV.B())), a(Op<T>::u(CV.B())-b), rem, ub(0), lb(0);
2062  for (unsigned i(0); i<=CV.nord(); i++) {
2063  ub += coefmon[i];
2064  lb += std::pow(-1.,i)*coefmon[i];
2065  }
2066  rem = std::max(std::fabs(mc::inv(a+b)-ub), std::fabs(mc::inv(b-a)-lb));
2067 
2068  CVI = CV._rescale(a,b);
2069  CV2 = CVI._composition( coefmon );
2070  CV2 += T(-rem, rem);
2071 
2072  return CV2;
2073 }
2074 
2075 template <typename T> inline CVar<T>
2076 sqrt
2077 ( const CVar<T>&CV )
2078 {
2079  if( !CV._CM )
2080  return CVar<T>( Op<T>::sqrt(CV._coefmon[0] + *(CV._bndrem)) );
2081  if ( Op<T>::l(CV.B()) < 0. )
2082  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::SQRT );
2083 
2084  CVar<T> CVI( CV._CM, 0. ), CV2( CV._CM, 0. );
2085  //double coefmon[CV.nord()+1];
2086  double* coefmon = CV._coefinterp();
2087  CV._interpolation( coefmon, std::sqrt );
2088 
2089  double b(Op<T>::mid(CV.B())), a(Op<T>::u(CV.B())-b), rem, ub(0), lb(0);
2090  for (unsigned i(0); i<=CV.nord(); i++) {
2091  ub += coefmon[i];
2092  lb += std::pow(-1.,i)*coefmon[i];
2093  }
2094  rem = std::max(std::sqrt(a+b)-ub, std::sqrt(b-a)-lb);
2095 
2096  CVI = CV._rescale(a,b);
2097  CV2 = CVI._composition( coefmon );
2098  CV2 += T(-rem, rem);
2099 
2100  return CV2;
2101 }
2102 
2103 template <typename T> inline CVar<T>
2104 exp
2105 ( const CVar<T>&CV )
2106 {
2107  if( !CV._CM )
2108  return CVar<T>( Op<T>::exp(CV._coefmon[0] + *(CV._bndrem)) );
2109 
2110  CVar<T> CVI( CV._CM, 0. ), CV2( CV._CM, 0. );
2111  //double coefmon[CV.nord()+1];
2112  double* coefmon = CV._coefinterp();
2113  CV._interpolation( coefmon, std::exp );
2114 
2115  double b(Op<T>::mid(CV.B())), a(Op<T>::u(CV.B())-b), rem, ub(0), lb(0);
2116  for (unsigned i(0); i<=CV.nord(); i++) {
2117  ub += coefmon[i];
2118  lb += std::pow(-1.,i)*coefmon[i];
2119  }
2120  rem = std::max(std::exp(a+b)-ub, std::exp(b-a)-lb);
2121 
2122  CVI = CV._rescale(a,b);
2123  CV2 = CVI._composition( coefmon );
2124  CV2 += T(-rem, rem);
2125 
2126  //if( CV2._CM->options.CENTER_REMAINDER ) CV2._center();
2127  return CV2;
2128 }
2129 
2130 template <typename T> inline CVar<T>
2131 log
2132 ( const CVar<T>&CV )
2133 {
2134  if( !CV._CM )
2135  return CVar<T>( Op<T>::log(CV._coefmon[0] + *(CV._bndrem)) );
2136  if ( Op<T>::l(CV.B()) <= 0. )
2137  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::SQRT );
2138 
2139  CVar<T> CVI( CV._CM, 0. ), CV2( CV._CM, 0. );
2140  //double coefmon[CV.nord()+1];
2141  double* coefmon = CV._coefinterp();
2142  CV._interpolation( coefmon, std::log );
2143 
2144  double b(Op<T>::mid(CV.B())), a(Op<T>::u(CV.B())-b), rem, ub(0), lb(0);
2145  for (unsigned i(0); i<=CV.nord(); i++) {
2146  ub += coefmon[i];
2147  lb += std::pow(-1.,i)*coefmon[i];
2148  }
2149  rem = std::max(std::fabs(std::log(a+b)-ub), std::fabs(std::log(b-a)-lb));
2150 
2151  CVI = CV._rescale(a,b);
2152  CV2 = CVI._composition( coefmon );
2153  CV2 += T(-rem, rem);
2154 
2155  //if( CV2._CM->options.CENTER_REMAINDER ) CV2._center();
2156  return CV2;
2157 }
2158 
2159 template <typename T> inline CVar<T>
2160 xlog
2161 ( const CVar<T>&CV )
2162 {
2163  return CV * log( CV );
2164 }
2165 
2166 template <typename T> inline CVar<T>
2167 pow
2168 ( const CVar<T>&CV, const int n )
2169 {
2170  if( !CV._CM )
2171  return CVar<T>( Op<T>::pow(CV._coefmon[0] + *(CV._bndrem), n) );
2172 
2173  if( n < 0 ) return pow( inv( CV ), -n );
2174  CVar<T> CV2( CV._CM->_intpow( CV, n ) );
2175  //if( CV2._CM->options.CENTER_REMAINDER ) CV2._center();
2176  return CV2;
2177 }
2178 
2179 template <typename T> inline CVar<T>
2180 pow
2181 ( const CVar<T> &CV, const double a )
2182 {
2183  return exp( a * log( CV ) );
2184 }
2185 
2186 template <typename T> inline CVar<T>
2187 pow
2188 ( const CVar<T> &CV1, const CVar<T> &CV2 )
2189 {
2190  return exp( CV2 * log( CV1 ) );
2191 }
2192 
2193 template <typename T> inline CVar<T>
2194 pow
2195 ( const double a, const CVar<T> &CV )
2196 {
2197  return exp( CV * std::log( a ) );
2198 }
2199 
2200 template <typename T> inline CVar<T>
2201 monomial
2202 (const unsigned int n, const CVar<T>*CV, const int*k)
2203 {
2204  if( n == 0 ){
2205  return 1.;
2206  }
2207  if( n == 1 ){
2208  return pow( CV[0], k[0] );
2209  }
2210  return pow( CV[0], k[0] ) * monomial( n-1, CV+1, k+1 );
2211 }
2212 
2213 template <typename T> inline CVar<T>
2214 cos
2215 ( const CVar<T> &CV )
2216 {
2217  if( !CV._CM )
2218  return CVar<T>( Op<T>::cos(CV._coefmon[0] + *(CV._bndrem)) );
2219 
2220  CVar<T> CVI( CV._CM, 0. ), CV2( CV._CM, 0. );
2221  //double coefmon[CV.nord()+1];
2222  double* coefmon = CV._coefinterp();
2223  CV._interpolation( coefmon, std::cos );
2224 
2225  double b(Op<T>::mid(CV.B())), a(Op<T>::u(CV.B())-b), rem, fact(1);
2226  for (unsigned i(1); i<=CV.nord()+1; i++) fact *= double(i);
2227  rem = 4.*std::pow(a/2.,double(CV.nord()+1))/fact;
2228 
2229  CVI = CV._rescale(a,b);
2230  CV2 = CVI._composition( coefmon );
2231  CV2 += T(-rem, rem);
2232 
2233  //if( CV2._CM->options.CENTER_REMAINDER ) CV2._center();
2234  return CV2;
2235 }
2236 
2237 template <typename T> inline CVar<T>
2238 sin
2239 ( const CVar<T> &CV )
2240 {
2241  return cos( CV - PI/2. );
2242 }
2243 
2244 template <typename T> inline CVar<T>
2245 acos
2246 ( const CVar<T> &CV )
2247 {
2248  if( !CV._CM )
2249  return CVar<T>( Op<T>::acos(CV._coefmon[0] + *(CV._bndrem)) );
2250  if ( Op<T>::l(CV.B()) < -1. && Op<T>::u(CV.B()) > 1. )
2251  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::ACOS );
2252 
2253  CVar<T> CVI( CV._CM, 0. ), CV2( CV._CM, 0. );
2254  // INCORRECT AS IMPLEMENTED -- NEEDS FIXING
2255  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::UNDEF );
2256 
2257  double coefmon[CV.nord()+1];
2258  double b(Op<T>::mid(CV.B())), a(Op<T>::u(CV.B())-b), rem, ub(-4.*a/PI);
2259  coefmon[0] = 0.5*PI*a+b;
2260  coefmon[1] = ub;
2261  for (unsigned i(3); i<=CV.nord(); i+=2) {
2262  coefmon[i-1] = 0.;
2263  coefmon[i] = coefmon[1]/std::pow(double(i),2.);
2264  ub += coefmon[i];
2265  }
2266  if (CV.nord()%2==0) coefmon[CV.nord()] = 0.;
2267  rem = a*PI/6. + ub;
2268 
2269  CVI = CV._rescale(a,b);
2270  CV2 = CVI._composition( coefmon );
2271  CV2 += T(-rem, rem);
2272 
2273  //if( CV2._CM->options.CENTER_REMAINDER ) CV2._center();
2274  return CV2;
2275 }
2276 
2277 template <typename T> inline CVar<T>
2278 asin
2279 ( const CVar<T> &CV )
2280 {
2281  return PI/2. - acos( CV );
2282 }
2283 
2284 template <typename T> inline CVar<T>
2285 tan
2286 ( const CVar<T> &CV )
2287 {
2288  return sin( CV ) / cos( CV );
2289 }
2290 
2291 template <typename T> inline CVar<T>
2292 atan
2293 ( const CVar<T> &CV )
2294 {
2295  return asin( CV / sqrt( sqr( CV ) + 1. ) );
2296 }
2297 
2298 template <typename T> inline CVar<T>
2299 fabs
2300 ( const CVar<T> &CV )
2301 {
2302  if( !CV._CM )
2303  return CVar<T>( Op<T>::fabs(CV._coefmon[0] + *(CV._bndrem)) );
2304 
2305  return sqrt( sqr( CV ) );
2306 /*
2307  CVar<T> CVI( CV._CM, 0. ), CV2( CV._CM, 0. );
2308  //REMAINDER TO BE IMPLEMENTED
2309  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::UNDEF );
2310  //double coefmon[CV.nord()+1];
2311  double* coefmon = CV._coefinterp();
2312  CV._interpolation( coefmon, std::fabs );
2313 
2314  double b(Op<T>::mid(CV.B())), a(Op<T>::u(CV.B())-b), rem, ub(0), lb(0);
2315  for (unsigned i(0); i<=CV.nord(); i++) {
2316  ub += coefmon[i];
2317  lb += std::pow(-1.,i)*coefmon[i];
2318  }
2319  rem = std::max(std::fabs(a+b)-ub, std::fabs(b-a)-lb);
2320 
2321  CVI = CV._rescale(a,b);
2322  CV2 = CVI._composition( coefmon );
2323  CV2 += T(-rem, rem);
2324 
2325  //if( CV2._CM->options.CENTER_REMAINDER ) CV2._center();
2326  return CV2;
2327 */
2328 }
2329 
2330 template <typename T> inline CVar<T>
2331 hull
2332 ( const CVar<T>&CV1, const CVar<T>&CV2 )
2333 {
2334  // Neither operands associated to CModel -- Make intersection in T type
2335  if( !CV1._CM && !CV2._CM ){
2336  T R1 = CV1._coefmon[0] + *(CV1._bndrem);
2337  T R2 = CV2._coefmon[0] + *(CV2._bndrem);
2338  return Op<T>::hull(R1, R2);
2339  }
2340 
2341  // First operand not associated to CModel
2342  else if( !CV1._CM )
2343  return hull( CV2, CV1 );
2344 
2345  // Second operand not associated to CModel
2346  else if( !CV2._CM ){
2347  CVar<T> CVR = CV1.P();
2348  return CVR + Op<T>::hull( CV1.R(), CV2._coefmon[0]+*(CV2._bndrem)-CVR.B() );
2349  }
2350 
2351  // CModel for first and second operands are inconsistent
2352  else if( CV1._CM != CV2._CM )
2353  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::CMODEL );
2354 
2355  // Perform union
2356  CVar<T> CV1C( CV1 ), CV2C( CV2 );
2357  const double eta = CV1._CM->options.REF_POLY;
2358  T R1C = CV1C.C().R(), R2C = CV2C.C().R();
2359  CV1C.set(T(0.));
2360  CV2C.set(T(0.));
2361  T BCVD = (CV1C-CV2C).B();
2362  return (1.-eta)*CV1C + eta*CV2C + Op<T>::hull( R1C+eta*BCVD, R2C+(eta-1.)*BCVD );
2363 }
2364 
2365 template <typename T> inline bool
2366 inter
2367 ( CVar<T>&CVR, const CVar<T>&CV1, const CVar<T>&CV2 )
2368 {
2369  // Neither operands associated to CModel -- Make intersection in T type
2370  if( !CV1._CM && !CV2._CM ){
2371  T R1 = CV1._coefmon[0] + CV1._bndord[0];
2372  T R2 = CV2._coefmon[0] + CV2._bndord[0];
2373  T RR( 0. );
2374  bool flag = Op<T>::inter(RR, R1, R2);
2375  CVR = RR;
2376  return flag;
2377  }
2378 
2379  // First operand not associated to CModel
2380  else if( !CV1._CM )
2381  return inter( CVR, CV2, CV1 );
2382 
2383  // Second operand not associated to CModel
2384  else if( !CV2._CM ){
2385  T R1 = CV1.R(), B2 = CV2.B();
2386  CVR = CV1.P();
2387  if( !Op<T>::inter(*(CVR._bndrem), R1, B2-CVR.B()) )
2388  return false;
2389  //if( CVR._CM->options.CENTER_REMAINDER ) CVR._center();
2390  return true;
2391  }
2392 
2393  // CModel for first and second operands are inconsistent
2394  else if( CV1._CM != CV2._CM )
2395  throw typename CModel<T>::Exceptions( CModel<T>::Exceptions::CMODEL );
2396 
2397  // Perform intersection
2398  CVar<T> CV1C( CV1 ), CV2C( CV2 );
2399  const double eta = CV1._CM->options.REF_POLY;
2400  T R1C = CV1C.C().R(), R2C = CV2C.C().R();
2401  CV1C.set(T(0.));
2402  CV2C.set(T(0.));
2403  CVR = (1.-eta)*CV1C + eta*CV2C;
2404  CV1C -= CV2C;
2405  T BCVD = CV1C.B();
2406  if( !Op<T>::inter( *(CVR._bndrem), R1C+eta*BCVD, R2C+(eta-1.)*BCVD ) )
2407  return false;
2408  //if( CVR._CM->options.CENTER_REMAINDER ) CVR._center();
2409  return true;
2410 }
2411 
2412 } // namespace mc
2413 
2414 #include "mcop.hpp"
2415 
2416 namespace mc
2417 {
2418 
2420 template <> template<typename T> struct Op< mc::CVar<T> >
2421 {
2422  typedef mc::CVar<T> CV;
2423  static CV point( const double c ) { return CV(c); }
2424  static CV zeroone() { return CV( mc::Op<T>::zeroone() ); }
2425  static void I(CV& x, const CV&y) { x = y; }
2426  static double l(const CV& x) { return mc::Op<T>::l(x.B()); }
2427  static double u(const CV& x) { return mc::Op<T>::u(x.B()); }
2428  static double abs (const CV& x) { return mc::Op<T>::abs(x.B()); }
2429  static double mid (const CV& x) { return mc::Op<T>::mid(x.B()); }
2430  static double diam(const CV& x) { return mc::Op<T>::diam(x.B()); }
2431  static CV inv (const CV& x) { return mc::inv(x); }
2432  static CV sqr (const CV& x) { return mc::sqr(x); }
2433  static CV sqrt(const CV& x) { return mc::sqrt(x); }
2434  static CV log (const CV& x) { return mc::log(x); }
2435  static CV xlog(const CV& x) { return x*mc::log(x); }
2436  static CV fabs(const CV& x) { return mc::fabs(x); }
2437  static CV exp (const CV& x) { return mc::exp(x); }
2438  static CV sin (const CV& x) { return mc::sin(x); }
2439  static CV cos (const CV& x) { return mc::cos(x); }
2440  static CV tan (const CV& x) { return mc::tan(x); }
2441  static CV asin(const CV& x) { return mc::asin(x); }
2442  static CV acos(const CV& x) { return mc::acos(x); }
2443  static CV atan(const CV& x) { return mc::atan(x); }
2444  static CV erf (const CV& x) { throw typename mc::CModel<T>::Exceptions( CModel<T>::Exceptions::UNDEF ); }
2445  static CV erfc(const CV& x) { throw typename mc::CModel<T>::Exceptions( CModel<T>::Exceptions::UNDEF ); }
2446  static CV fstep(const CV& x) { return CV( mc::Op<T>::fstep(x.B()) ); }
2447  static CV bstep(const CV& x) { return CV( mc::Op<T>::bstep(x.B()) ); }
2448  static CV hull(const CV& x, const CV& y) { return mc::hull(x,y); }
2449  static CV min (const CV& x, const CV& y) { return mc::Op<T>::min(x.B(),y.B()); }
2450  static CV max (const CV& x, const CV& y) { return mc::Op<T>::max(x.B(),y.B()); }
2451  static CV arh (const CV& x, const double k) { return mc::exp(-k/x); }
2452  template <typename X, typename Y> static CV pow(const X& x, const Y& y) { return mc::pow(x,y); }
2453  static CV monomial (const unsigned int n, const T* x, const int* k) { return mc::monomial(n,x,k); }
2454  static bool inter(CV& xIy, const CV& x, const CV& y) { return mc::inter(xIy,x,y); }
2455  static bool eq(const CV& x, const CV& y) { return mc::Op<T>::eq(x.B(),y.B()); }
2456  static bool ne(const CV& x, const CV& y) { return mc::Op<T>::ne(x.B(),y.B()); }
2457  static bool lt(const CV& x, const CV& y) { return mc::Op<T>::lt(x.B(),y.B()); }
2458  static bool le(const CV& x, const CV& y) { return mc::Op<T>::le(x.B(),y.B()); }
2459  static bool gt(const CV& x, const CV& y) { return mc::Op<T>::gt(x.B(),y.B()); }
2460  static bool ge(const CV& x, const CV& y) { return mc::Op<T>::ge(x.B(),y.B()); }
2461 };
2462 
2463 } // namespace mc
2464 
2465 #endif
Options of mc::CModel.
Definition: cmodel.hpp:300
Chebyshev model bound does not intersect with bound in template parameter arithmetic.
Definition: cmodel.hpp:259
Lin & Stadtherr range bounder.
Definition: cmodel.hpp:329
~CVar()
Destructor of Chebyshev variable.
Definition: cmodel.hpp:604
double REF_POLY
Scalar in related to the choice of the polynomial part in the overloaded functions mc::inter and mc:...
Definition: cmodel.hpp:343
Options()
Constructor of mc::CModel::Options.
Definition: cmodel.hpp:303
Operation between Chebyshev variables linked to different Chebyshev models.
Definition: cmodel.hpp:260
Failed to construct Chebyshev variable.
Definition: cmodel.hpp:258
unsigned int nmon() const
Total number of monomial terms in polynomial model.
Definition: polymodel.hpp:463
int ierr()
Error flag.
Definition: cmodel.hpp:266
C++ base class for the computation of polynomial models for factorable functions: Environment...
Definition: polymodel.hpp:36
std::pair< unsigned int, const double * > coefmon() const
Get pair of size of, and const pointer to, array of (possibly scaled) monomial coefficients in multiv...
Definition: polymodel.hpp:870
Division by zero scalar.
Definition: cmodel.hpp:252
CVar< T > P() const
Shortcut to mc::CVar::polynomial.
Definition: cmodel.hpp:652
Exceptions of mc::CModel.
Definition: cmodel.hpp:247
virtual void _center()
Center remainder error term _bndrem
Definition: polymodel.hpp:850
unsigned int DISPLAY_DIGITS
Number of digits in output stream for Chebyshev model coefficients.
Definition: cmodel.hpp:345
unsigned INTERP_EXTRA
Extra terms in chebyshev interpolation of univariates: 0-Chebyshev interpolation of order NORD; extra...
Definition: cmodel.hpp:335
T * _bndrem
Pointer to remainder bound of variable (possibly NULL if not computed)
Definition: polymodel.hpp:443
Eigenvalue decomposition-based bounder.
Definition: cmodel.hpp:330
Naive polynomial range bounder.
Definition: cmodel.hpp:328
Log operation with non-positive numbers in range.
Definition: cmodel.hpp:254
Exceptions(TYPE ierr)
Constructor for error ierr
Definition: cmodel.hpp:264
Hybrid LSB + EIGEN range bounder.
Definition: cmodel.hpp:332
C++ class for the computation of Chebyshev models of factorable function - Chebyshev model environmen...
Definition: cmodel.hpp:218
double * linear() const
Get pointer to array of size nvar with coefficients of linear term in Chebyshev variable.
Definition: cmodel.hpp:1479
~CModel()
Destructor of Chebyshev model environment.
Definition: cmodel.hpp:239
CVar< T > & center()
Center remainder term of Chebyshev variable.
Definition: cmodel.hpp:657
Bernstein range bounder.
Definition: cmodel.hpp:331
Inverse operation with zero in range.
Definition: cmodel.hpp:253
std::string what()
Error description.
Definition: cmodel.hpp:268
virtual T B() const
Shortcut to mc::PolyVar::bound.
Definition: polymodel.hpp:651
virtual PolyVar< T > & set(PolyModel *env)
Set polynomial model environment in variable as env
Definition: polymodel.hpp:573
Feature not yet implemented in mc::CModel.
Definition: cmodel.hpp:261
BOUNDER BOUNDER_TYPE
Chebyshev model range bounder - See How are the options set for the computation of a Chebyshev model...
Definition: cmodel.hpp:337
C++ base class for the computation of polynomial models for factorable functions: Variable...
Definition: polymodel.hpp:425
BOUNDER
Chebyshev model range bounder option.
Definition: cmodel.hpp:327
virtual T B(const int type) const
Shortcut to mc::PolyVar::bound.
Definition: polymodel.hpp:645
Maximum size of polynomial model reached (monomials indexed as unsigned int)
Definition: polymodel.hpp:103
unsigned int nord() const
Order of polynomial model.
Definition: polymodel.hpp:451
CVar< T > & C()
Shortcut to mc::CVar::center.
Definition: cmodel.hpp:661
virtual void _set_bndpol(const T &bndpol)
Set polynomial bound in variable as bndpol
Definition: polymodel.hpp:841
bool _bndord_uptd
Whether the bounds in bndord are up-to-date.
Definition: polymodel.hpp:440
unsigned int nord() const
Order of polynomial model environment.
Definition: polymodel.hpp:62
T bound() const
Retreive bound on variable using default bounder.
Definition: polymodel.hpp:620
TYPE
Enumeration type for CModel exception handling.
Definition: cmodel.hpp:251
unsigned int BOUNDER_ORDER
Order of Bernstein polynomial for Chebyshev model range bounding (no less than Chebyshev model order!...
Definition: cmodel.hpp:339
PolyModel(const unsigned int nvar, const unsigned int nord)
Constructor of polynomial model environment for nvar variables and order nord
Definition: polymodel.hpp:46
C++ class for Chebyshev model computation of factorable function - Chebyshev model propagation...
Definition: cmodel.hpp:207
double constant(const bool reset=false)
Get coefficient of constant term in Chebyshev variable. The value of this coefficient is reset to 0 i...
Definition: cmodel.hpp:1471
CModel< T > * env() const
Get pointer to linked Chebyshev model environment.
Definition: cmodel.hpp:567
double * _coefmon
Array of size _nmon with monomial coefficients of variable.
Definition: polymodel.hpp:434
Square-root operation with negative numbers in range.
Definition: cmodel.hpp:255
const T * bndvar() const
Get const pointer to array of size _nvar with original variable bounds.
Definition: cmodel.hpp:243
CVar< T > polynomial() const
Return new Chebyshev variable with same multivariate polynomial part but zero remainder.
Definition: cmodel.hpp:646
T * _bndord
Array of size _nord+2 with bounds for all terms of degrees iord=0,...,_nord as well as the remainder ...
Definition: polymodel.hpp:437
Failed to compute eigenvalue decomposition in range bounder CModel::Options::EIGEN.
Definition: cmodel.hpp:257
unsigned int nvar() const
Number of variables in polynomial model environment.
Definition: polymodel.hpp:56
static const std::string BOUNDER_NAME[5]
Array of Chebyshev model range bounder names (for display)
Definition: cmodel.hpp:341
Sine/Cosine inverse operation with range outside [-1,1].
Definition: cmodel.hpp:256
CVar< T > & set(CModel< T > *CM, const unsigned int ix, const T &X)
Set Chebyshev variable with index ix (starting from 0) and bounded by X
Definition: cmodel.hpp:627
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