MC++
ffunc.hpp
1 // Copyright (C) 2013-2014 Benoit Chachuat, Imperial College London.
2 // All Rights Reserved.
3 
524 #ifndef MC__FFUNC_HPP
525 #define MC__FFUNC_HPP
526 
527 #include <iostream>
528 #include <string>
529 #include <sstream>
530 #include <stdarg.h>
531 #include <set>
532 #include <list>
533 #include <vector>
534 #include <utility>
535 #include <algorithm>
536 #include <stdexcept>
537 #include <sys/time.h>
538 
539 #include "mcfadbad.hpp"
540 #include "mcfunc.hpp"
541 #include "mclapack.hpp"
542 #include "ffdep.hpp"
543 
544 #undef MC__FFUNC_DEBUG
545 #undef MC__FFUNC_DEBUG_TAD
546 #undef MC__FFUNC_DEBUG_DEPMAP
547 #undef MC__FFUNC_CPU_EVAL
548 
549 namespace mc
550 {
551 class FFOp;
552 class FFGraph;
553 
560 struct FFNum
561 {
563  enum TYPE{
564  INT=0,
566  };
570  union{
571  int n;
572  double x;
573  };
574 
576  FFNum( const int i=0 ):
577  t(INT), n(i)
578  {}
580  FFNum( const double d ):
581  t(REAL), x(d)
582  {}
583 
585  FFNum& operator=
586  ( const int i )
587  { t = INT; n = i; return *this; }
589  FFNum& operator=
590  ( const double d )
591  { t = REAL; x = d; return *this; }
593  FFNum& operator=
594  ( const FFNum&num )
595  { t = num.t; t==REAL? x=num.x: n=num.n; return *this; }
596 };
597 
603 struct eq_FFNum
605 {
606  bool operator()
607  ( const FFNum*Num1, const FFNum*Num2 ) const
608  {
609  if( Num1->t != Num2->t ) return false;
610  switch( Num1->t ){
611  case FFNum::INT: return Num1->n==Num2->n? true: false;
612  case FFNum::REAL: return isequal( Num1->x, Num2->x );
613  }
614  }
615 };
616 
622 struct lt_FFNum
624 {
625  bool operator()
626  ( const FFNum*Num1, const FFNum*Num2 ) const
627  {
628  if( Num1->t < Num2->t ) return true;
629  if( Num1->t > Num2->t ) return false;
630  switch( Num1->t ){
631  case FFNum::INT: return Num1->n<Num2->n? true: false;
632  case FFNum::REAL: return !isequal( Num1->x, Num2->x ) && Num1->x<Num2->x? true: false;
633  }
634  return false;
635  }
636 };
637 
643 class FFVar
645 {
646  // friends of this class with other classes/structures/operators
647  friend class FFGraph;
648  friend struct lt_FFVar;
649  friend std::ostream& operator<< ( std::ostream&, const FFGraph& );
650  friend std::ostream& operator<< ( std::ostream&, const FFOp& );
651 
652  // friends of this class for operator and function overloading
653  friend std::ostream& operator<< ( std::ostream&, const FFVar& );
654  friend FFVar operator+ ( const FFVar& );
655  friend FFVar operator+ ( const FFVar&, const FFVar& );
656  template <typename V> friend FFVar operator+ ( const V&, const FFVar& );
657  template <typename V> friend FFVar operator+ ( const FFVar&, const V& );
658  friend FFVar operator- ( const FFVar& );
659  friend FFVar operator- ( const FFVar&, const FFVar& );
660  template <typename V> friend FFVar operator- ( const V&, const FFVar& );
661  template <typename V> friend FFVar operator- ( const FFVar&, const V& );
662  friend FFVar operator* ( const FFVar&, const FFVar& );
663  template <typename V> friend FFVar operator* ( const V&, const FFVar& );
664  template <typename V> friend FFVar operator* ( const FFVar&, const V& );
665  friend FFVar operator/ ( const FFVar&, const FFVar& );
666  template <typename V> friend FFVar operator/ ( const V&, const FFVar& );
667  template <typename V> friend FFVar operator/ ( const FFVar&, const V& );
668  friend FFVar max ( const FFVar&, const FFVar& );
669  friend FFVar max ( const unsigned int, const FFVar* );
670  template <typename V> friend FFVar max ( const V&, const FFVar& );
671  template <typename V> friend FFVar max ( const FFVar&, const V& );
672  friend FFVar min ( const FFVar&, const FFVar& );
673  friend FFVar min ( const unsigned int, const FFVar* );
674  template <typename V> friend FFVar min ( const V&, const FFVar& );
675  template <typename V> friend FFVar min ( const FFVar&, const V& );
676  friend FFVar inv ( const FFVar& );
677  friend FFVar sqr ( const FFVar& );
678  friend FFVar exp ( const FFVar& );
679  friend FFVar log ( const FFVar& );
680  friend FFVar sqrt ( const FFVar& );
681  friend FFVar fabs ( const FFVar& );
682  friend FFVar cos ( const FFVar& );
683  friend FFVar sin ( const FFVar& );
684  friend FFVar tan ( const FFVar& );
685  friend FFVar acos ( const FFVar& );
686  friend FFVar asin ( const FFVar& );
687  friend FFVar atan ( const FFVar& );
688  friend FFVar erf ( const FFVar& );
689  friend FFVar erfc ( const FFVar& );
690  friend FFVar fstep ( const FFVar& );
691  friend FFVar bstep ( const FFVar& );
692  friend FFVar pow ( const FFVar&, const int );
693  friend FFVar pow ( const FFVar&, const double );
694  friend FFVar pow ( const FFVar&, const FFVar& );
695  friend FFVar pow ( const double, const FFVar& );
696 
697 public:
698 
699  // other operator overloadings
700  FFVar& operator= ( const FFVar& );
701  FFVar& operator= ( const int );
702  FFVar& operator= ( const double );
703  template <typename V> FFVar& operator+= ( const V& );
704  template <typename V> FFVar& operator-= ( const V& );
705  template <typename V> FFVar& operator*= ( const V& );
706  template <typename V> FFVar& operator/= ( const V& );
707 
708  typedef std::list< FFOp* > t_Ops;
709  //typedef typename t_Ops::iterator it_Ops;
710  //typedef typename t_Ops::const_iterator cit_Ops;
711  typedef typename std::pair< FFOp*, t_Ops > pt_Ops;
712 
716  static const long NOREF = -33;
719  enum TYPE{
720  VAR=0,
721  AUX,
724  };
726  typedef std::pair< TYPE, long > pt_idVar;
729 private:
731  FFGraph *_dag;
733  pt_idVar _id;
735  FFNum _num;
737  FFDep _dep;
739  void *_val;
741  pt_Ops _ops;
742 
743 public:
744 
748  FFVar
750  ( FFGraph*dag );//, const unsigned long ix );
751 
753  FFVar& set
754  ( FFGraph*dag )//, const unsigned long ix )
755  { *this = FFVar( dag );//, ix );
756  return *this; }
757 
759  FFVar
760  ( const int i=0 )
761  : _dag( 0 ), _id( CINT, NOREF ), _num( i ), _dep( i ), _val( 0 )
762  { _ops.first = 0; }
763 
765  FFVar
766  ( const double d )
767  : _dag( 0 ), _id( CREAL, NOREF ), _num( d ), _dep( d ), _val( 0 )
768  { _ops.first = 0; }
769 
771  FFVar
772  ( const FFVar&Var )
773  : _dag( Var._dag ), _id( Var._id ), _num( Var._num ), _dep( Var._dep ),
774  _val( Var._val ), _ops( Var._ops )
775  {}
778 private:
779 
781  FFVar
782  ( FFGraph*dag, const FFDep&dep, FFOp*op=0 );
783 
785  FFVar
786  ( FFGraph*dag, const pt_idVar&id );
787 
788 public:
789 
793  const std::pair<TYPE,long> id() const
795  { return _id; }
796 
798  std::pair<TYPE,long>& id()
799  { return _id; }
800 
802  const FFNum& num() const
803  { return _num; }
804 
806  const FFDep& dep() const
807  { return _dep; }
808 
811  { return _dep; }
812 
814  const pt_Ops ops() const
815  { return _ops; }
816 
818  pt_Ops& ops()
819  { return _ops; }
820 
822  const FFGraph* dag() const
823  { return _dag; }
824 
827  { return _dag; }
828 
830  void*& val()
831  { return _val; }
832 
834  template <typename U> void reset_val
835  ( const U& U_dum )
836  { delete static_cast<U*>( _val ); _val = 0; }
837 
839  std::string name() const
840  { return _name(_id); }
843 private:
844 
846  static std::string _name
847  ( const std::pair<TYPE,long> id )
848  {
849  std::ostringstream ovar;
850  id.first==VAR? ovar<<"X": ovar<<"Z";
851  ovar<<id.second;
852  return ovar.str();
853  }
854 };
855 const long FFVar::NOREF;
856 
862 struct lt_FFVar
864 {
865  bool operator()
866  ( const FFVar*Var1, const FFVar*Var2 ) const
867  {
868  // Order variables/constants w.r.t. their types first
869  if( Var1->_id.first < Var2->_id.first ) return true;
870  if( Var1->_id.first > Var2->_id.first ) return false;
871  // If variables, order w.r.t. their index next
872  switch( Var1->_id.first ){
873  case FFVar::VAR:
874  case FFVar::AUX:
875  if( Var1->_id.second < Var2->_id.second ) return true;
876  if( Var1->_id.second > Var2->_id.second ) return false;
877  break;
878  case FFVar::CINT: case FFVar::CREAL:
879  lt_FFNum ltNum;
880  return ltNum( &Var1->_num, &Var2->_num );
881  break;
882  }
883  return false;
884  }
885 };
886 
892 class FFOp
894 {
895 public:
896 
900  enum TYPE{
902  CNST=0, VAR,
903  PLUS, NEG, MINUS, TIMES, SCALE, DIV,
904  EXP, LOG, SQRT, SQR, IPOW, POW, SIN, COS, TAN, ASIN, ACOS, ATAN,
905  FABS, ERF, FSTEP, MINF, MAXF
906  };
907 
909  FFOp( TYPE top, FFVar*lop=0, FFVar*rop=0, FFVar*res=0 );
910 
913  {}
914 
923 
925  void propagate_subgraph
926  ( std::list<const FFOp*>&Ops ) const;
928  template <typename U> void reset_val_subgraph
929  ( const U& U_dum ) const;
931  template <typename U> void reset_val_subgraph
932  ( const U& U_dum, const std::vector<const FFVar*>&vDep,
933  const std::vector<const FFVar*>&vIndep ) const;
936  ( std::ostream&os ) const;
938  void append_dot_script
939  ( std::ostream&os ) const;
942  ( std::ostream&os, const std::string&fname, const bool unary,
943  const unsigned int fontsize, const bool dotted=false ) const;
946  ( std::ostream&os, const bool constant, const unsigned int fontsize ) const;
948  template <typename U> void evaluate
949  ( const U& U_dum ) const;
951  template <typename U> void evaluate
952  ( U* pUres ) const;
953 
955  void flag
956  ( const bool visited=true ) const
957  { _visited = visited; }
959  const bool stat() const
960  { return _visited; }
962  const bool& stat()
963  { return _visited; }
965  bool is_univariate() const;
966 
969 private:
971  mutable bool _visited;
972 };
973 
980 struct lt_FFOp
982 {
983  bool operator()
984  ( const FFOp*Op1, const FFOp*Op2 ) const
985  {
986  // Sort by type of operation first
987  if( Op1->type < Op2->type ) return true;
988  if( Op1->type > Op2->type ) return false;
989 
990  // Sort by variable type next
991  lt_FFVar ltVar;
992  if( !Op1->plop ) return ltVar( Op1->pres, Op2->pres );
993  if( ltVar( Op1->plop, Op2->plop ) ) return true;
994  if( ltVar( Op2->plop, Op1->plop ) ) return false;
995  if( Op1->prop ) return ltVar( Op1->prop, Op2->prop );
996  return false;
997  }
998 };
999 
1007 {
1008  bool operator()
1009  ( const FFOp*Op1, const FFOp*Op2 ) const
1010  { return ( Op1->type < Op2->type ); }
1011 };
1012 
1019 class FFGraph
1021 {
1022  // friends of this class with other classes/structures/operators
1023  friend class FFVar;
1024  friend class FFOp;
1025  friend FFVar operator+ ( const FFVar& );
1026  friend FFVar operator+ ( const FFVar&, const FFVar& );
1027  template <typename V> friend FFVar operator+ ( const V&, const FFVar& );
1028  template <typename V> friend FFVar operator+ ( const FFVar&, const V& );
1029  friend FFVar operator- ( const FFVar& );
1030  friend FFVar operator- ( const FFVar&, const FFVar& );
1031  template <typename V> friend FFVar operator- ( const V&, const FFVar& );
1032  template <typename V> friend FFVar operator- ( const FFVar&, const V& );
1033  friend FFVar operator* ( const FFVar&, const FFVar& );
1034  template <typename V> friend FFVar operator* ( const V&, const FFVar& );
1035  template <typename V> friend FFVar operator* ( const FFVar&, const V& );
1036  friend FFVar operator/ ( const FFVar&, const FFVar& );
1037  template <typename V> friend FFVar operator/ ( const V&, const FFVar& );
1038  template <typename V> friend FFVar operator/ ( const FFVar&, const V& );
1039  friend FFVar max ( const FFVar&, const FFVar& );
1040  friend FFVar max ( const unsigned int, const FFVar* );
1041  template <typename V> friend FFVar max ( const V&, const FFVar& );
1042  template <typename V> friend FFVar max ( const FFVar&, const V& );
1043  friend FFVar min ( const FFVar&, const FFVar& );
1044  friend FFVar min ( const unsigned int, const FFVar* );
1045  template <typename V> friend FFVar min ( const V&, const FFVar& );
1046  template <typename V> friend FFVar min ( const FFVar&, const V& );
1047  friend FFVar inv ( const FFVar& );
1048  friend FFVar sqr ( const FFVar& );
1049  friend FFVar exp ( const FFVar& );
1050  friend FFVar log ( const FFVar& );
1051  friend FFVar sqrt ( const FFVar& );
1052  friend FFVar fabs ( const FFVar& );
1053  friend FFVar cos ( const FFVar& );
1054  friend FFVar sin ( const FFVar& );
1055  friend FFVar tan ( const FFVar& );
1056  friend FFVar acos ( const FFVar& );
1057  friend FFVar asin ( const FFVar& );
1058  friend FFVar atan ( const FFVar& );
1059  friend FFVar erf ( const FFVar& );
1060  friend FFVar erfc ( const FFVar& );
1061  friend FFVar fstep ( const FFVar& );
1062  friend FFVar bstep ( const FFVar& );
1063  friend FFVar pow ( const FFVar&, const int );
1064  friend FFVar pow ( const FFVar&, const double );
1065  friend FFVar pow ( const FFVar&, const FFVar& );
1066  friend FFVar pow ( const double, const FFVar& );
1067 
1068  // friends of this class for operator and function overloading
1069  friend std::ostream& operator<< ( std::ostream&, const FFGraph& );
1070 
1071 public:
1075  typedef typename FFVar::pt_idVar pt_idVar;
1076  typedef std::set< FFVar*, lt_FFVar > t_Vars;
1077  typedef std::set< FFOp*, lt_FFOp > t_Ops;
1078  typedef typename t_Vars::iterator it_Vars;
1079  typedef typename t_Vars::const_iterator cit_Vars;
1080  typedef typename t_Ops::iterator it_Ops;
1081  typedef typename t_Ops::const_iterator cit_Ops;
1084 protected:
1086  unsigned long _nvar;
1087 
1089  unsigned long _naux;
1090 
1092  t_Vars _Vars;
1093 
1095  t_Ops _Ops;
1096 
1097 public:
1101  FFGraph():
1103  _nvar( 0 ), _naux( 0 )
1104  {}
1105 
1107  virtual ~FFGraph()
1108  { clear(); }
1109 
1112  {
1113  public:
1115  enum TYPE{
1116  INIT = 1,
1120  INTERN = -1,
1121  UNDEF = -33,
1122  };
1124  Exceptions( TYPE ierr ) : _ierr( ierr ){}
1126  int ierr(){ return _ierr; }
1128  std::string what(){
1129  switch( _ierr ){
1130  case INIT:
1131  return "Invalid mc::FFGraph passed for initilization of an mc:FFVar object";
1132  case DAG:
1133  return "Operation between mc::FFVar objects linked to different mc::FFGraph objects";
1134  case MISSVAR:
1135  return "Missing independent variable for evaluating a given subgraph using FFGraph::eval";
1136  case EVAL:
1137  return "Exception thrown during subgraph evaluation";
1138  case UNDEF:
1139  return "Feature not yet implemented in mc::FFGraph";
1140  default:
1141  return "Undocumented error in mc::FFGraph";
1142  }
1143  }
1144  private:
1145  TYPE _ierr;
1146  };
1147 
1148 /*
1150  struct Options
1151  {
1153  Options():
1154  SOLVER_OUTPUT_FILE("")
1155  {}
1157  std::string SOLVER_OUTPUT_FILE;
1158  } options;
1159 */
1160 
1162  unsigned long nvar() const
1163  { return _nvar; }
1164 
1166  unsigned long naux() const
1167  { return _naux; }
1168 
1170  const t_Vars& Vars() const
1171  { return _Vars; }
1172 
1174  void clear()
1176 
1178  std::list<const FFOp*> subgraph
1179  ( const unsigned int nDep, const FFVar*pDep ) const;
1180 
1182  std::list<const FFOp*> subgraph
1183  ( const std::vector<const FFVar*>&vDep ) const;
1184 
1186  CPPL::dssmatrix depmap
1187  ( const unsigned nDep, const FFVar* const pDep, const unsigned nIndep,
1188  const FFVar* const pIndep );
1189 
1191  CPPL::dssmatrix depmap
1192  ( std::list<const FFOp*>&opDep, const unsigned nDep, const FFVar* const pDep,
1193  const unsigned nIndep, const FFVar* const pIndep );
1194 
1196  CPPL::dssmatrix depmap
1197  ( const std::vector<const FFVar*>&vDep, const std::vector<const FFVar*>&vIndep ) ;
1198 
1200  CPPL::dssmatrix depmap
1201  ( std::list<const FFOp*>&opDep, const std::vector<const FFVar*>&vDep, const std::vector<const FFVar*>&vIndep ) ;
1202 
1204  static void output
1205  ( const std::list<const FFOp*>&Ops, std::ostream&os=std::cout );
1206 
1208  void dot_script
1209  ( const unsigned int nDep, const FFVar*pDep, std::ostream&os=std::cout ) const;
1210 
1212  void dot_script
1213  ( const std::vector<const FFVar*>&vDep, std::ostream&os=std::cout ) const;
1214 
1216  std::vector<const FFVar*> FAD
1217  ( const std::vector<const FFVar*>&vDep, const std::vector<const FFVar*>&vIndep );
1218 
1220  const FFVar* FAD
1221  ( const unsigned nDep, const FFVar* const pDep, const unsigned nIndep,
1222  const FFVar* const pIndep, const bool transp=false );
1223 
1225  std::vector<const FFVar*> BAD
1226  ( const std::vector<const FFVar*>&vDep, const std::vector<const FFVar*>&vIndep );
1227 
1229  const FFVar* BAD
1230  ( const unsigned nDep, const FFVar* const pDep, const unsigned nIndep,
1231  const FFVar* const pIndep, const bool transp=false );
1232 
1234  std::vector<const FFVar*> TAD
1235  ( const unsigned int ordermax, const std::vector<const FFVar*>&vDep,
1236  const std::vector<const FFVar*>&vVar, const FFVar* const pIndep=0 );
1237 
1239  const FFVar* TAD
1240  ( const unsigned int ordermax, const unsigned nDep, const FFVar* const pDep,
1241  const unsigned nVar, const FFVar* const pVar, const FFVar* const pIndep=0 );
1242 
1244  std::vector<const FFVar*> compose
1245  ( const std::vector<const FFVar*>&vDepOut,
1246  const std::vector< std::pair<const FFVar*,const FFVar*> >&vDepIn );
1247 
1249  const FFVar* compose
1250  ( const unsigned nDepOut, const FFVar*pDepOut, const unsigned nDepIn,
1251  const FFVar*pVarOut, const FFVar*pDepIn );
1252 
1254  template <typename U> std::vector<U> eval
1255  ( const std::vector<const FFVar*>&vDep,
1256  const std::vector< std::pair<const FFVar*,U> >&vVar );
1257 
1259  template <typename U> std::vector<U> eval
1260  ( std::list<const FFOp*>&opDep, const std::vector<const FFVar*>&vDep,
1261  const std::vector< std::pair<const FFVar*,U> >&vVar );
1262 
1264  template <typename U> std::vector<U> eval
1265  ( std::list<const FFOp*>&opDep, U*opRes, const std::vector<const FFVar*>&vDep,
1266  const std::vector< std::pair<const FFVar*,U> >&vVar );
1267 
1269  template <typename U> void eval
1270  ( const unsigned nDep, const FFVar*pDep, U*vDep,
1271  const unsigned nVar, const FFVar*pVar, U*vVar, const bool add=false );
1272 
1274  template <typename U> void eval
1275  ( std::list<const FFOp*>&opDep, const unsigned nDep, const FFVar*pDep,
1276  U*vDep, const unsigned nVar, const FFVar*pVar, U*vVar, const bool add=false );
1277 
1279  template <typename U> void eval
1280  ( std::list<const FFOp*>&opDep, U*opRes, const unsigned nDep, const FFVar*pDep,
1281  U*vDep, const unsigned nVar, const FFVar*pVar, U*vVar, const bool add=false );
1282 
1284  static double cpuclock()
1285  { timeval time; gettimeofday(&time, 0) ;
1286  return time.tv_sec + time.tv_usec*1e-6; }
1287 
1290 protected:
1292  bool _remove_operation
1293  ( FFOp*op );
1294 
1297  { it_Ops ito = _Ops.begin();
1298  for( ; ito != _Ops.end(); ++ito ) delete *ito;
1299  _Ops.clear(); }
1300 
1302  void _reset_operations() const
1303  { it_Ops ito = _Ops.begin();
1304  for( ; ito != _Ops.end(); ++ito ) (*ito)->flag( false ); }
1305 
1308  ( const typename FFOp::TYPE top, FFVar*lop, FFVar*rop=0 );
1309 
1312  ( const typename FFOp::TYPE top, const FFDep&dep, const FFVar&Var1, const FFVar&Var2 );
1313 
1315  template <typename U> static FFVar&
1317  ( const typename FFOp::TYPE top, const FFDep&dep, const U&Cst1, const FFVar&Var2 );
1318 
1320  template <typename U> static FFVar&
1322  ( const typename FFOp::TYPE top, const FFDep&dep, const FFVar&Var1, const U&Cst2 );
1323 
1326  ( const typename FFOp::TYPE top, const FFDep&dep, const FFVar&Var );
1327 
1330  ( const FFDep&dep, FFOp*pOp );
1331 
1334  ( const double x );
1335 
1338  ( const int n );
1339 
1342  { it_Vars itv = _Vars.begin();
1343  for( ; itv != _Vars.end(); ++itv ) delete *itv;
1344  _Vars.clear(); }
1345 
1347  void _append_aux
1348  ( FFVar*pAux, typename FFOp::TYPE tOp );
1349 
1351  virtual void _append_aux
1352  ( FFVar*pAux );
1353 
1355  virtual void _append_var
1356  ( FFVar*pVar );
1357 
1359  FFVar* _find_var
1360  ( const typename FFVar::pt_idVar&id );
1361 
1362 private:
1364  FFGraph(const FFGraph&);
1365  FFGraph& operator=(const FFGraph&);
1366 
1367 };
1368 
1370 
1371 inline std::ostream&
1372 operator <<
1373 ( std::ostream&out, const FFNum&Num )
1374 {
1375  switch( Num.t ){
1376  case FFNum::INT:
1377  out << Num.n << "(I)"; break;
1378  case FFNum::REAL:
1379  out << Num.x << "(D)"; break;
1380  }
1381  return out;
1382 }
1383 
1385 
1386 inline FFVar::FFVar
1387 ( FFGraph*dag )
1388 : _dag( dag? dag: throw typename FFGraph::Exceptions( FFGraph::Exceptions::INIT )),
1389  _id( VAR, _dag->_nvar++ ), _num( 0./0. ), _dep(), _val( 0 )
1390 {
1391 // if( !_dag ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INIT );
1392 
1393  // Initialize dependence
1394  _dep.indep(_id.second);
1395 
1396  // Insert new variable in set FFGraph::_Vars and corresponding operation in set FFGraph::_Ops
1397  FFVar* pVar = new FFVar( *this );
1398  FFOp* pOp = new FFOp( FFOp::VAR, 0, 0, pVar );
1399  _dag->_Ops.insert( pOp );
1400  pVar->_ops.first = _ops.first = pOp;
1401  _dag->_append_var( pVar );
1402 }
1403 
1404 /*
1405 inline FFVar::FFVar
1406 ( FFGraph*dag, const unsigned long ix )
1407 : _id( VAR, ix ), _num( 0./0. ), _dep(), _dag( dag ), _val( 0 )
1408 {
1409  if( !_dag ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INIT );
1410  // Keep track of variable count
1411  if( _dag->_nvar <= ix ) _dag->_nvar = ix+1;
1412  // Initialize dependence
1413  _dep.indep(ix);
1414  // Search for existing variable with same identifier in set FFGraph::_Vars
1415  // If found, remove variable and corresponding operation in FFGraph::_Ops
1416  FFVar* pVar = new FFVar( *this );
1417  typename FFGraph::it_Vars iVar = _dag->_Vars.find( pVar );
1418  if( iVar!=_dag->_Vars.end() ){
1419  _dag->_Ops.erase( (*iVar)->_ops.first );
1420  delete (*iVar)->_ops.first;
1421  (*iVar)->_ops.second.clear();
1422  delete *iVar;
1423  _dag->_Vars.erase( iVar );
1424  }
1425  // Insert new variable in set FFGraph::_Vars and corresponding operation in set FFGraph::_Ops
1426  FFOp* pOp = new FFOp( FFOp::VAR, 0, 0, pVar );
1427  _dag->_Ops.insert( pOp );
1428  pVar->_ops.first = _ops.first = pOp;
1429  _dag->_append_var( pVar );
1430 }
1431 */
1432 
1433 inline FFVar::FFVar
1434 ( FFGraph*dag, const FFDep&dep, FFOp*op )
1435 : _dag( dag ), _id( AUX, dag->_naux++ ), _num( 0./0. ), _dep(dep), _val ( 0 )
1436 { _ops.first = op; }
1437 
1438 inline FFVar::FFVar
1439 ( FFGraph*dag, const pt_idVar&id )
1440 : _dag( dag ), _id( id ), _num( 0 ), _dep(), _val( 0 )
1441 { _ops.first = 0; }
1442 
1443 inline std::ostream&
1444 operator <<
1445 ( std::ostream&out, const FFVar&Var)
1446 {
1447  out << Var.name();
1448  // << " <= " << std::left << Var._num << "\t(" << Var._dag << ")";
1449  return out;
1450 }
1451 
1452 inline FFVar&
1453 FFVar::operator=
1454 ( const FFVar&Var )
1455 {
1456  if( this == &Var ) return *this;
1457  _id = Var._id;
1458  _num = Var._num;
1459  _dep = Var._dep;
1460  _dag = Var._dag;
1461  _val = Var._val;
1462  _ops = Var._ops;
1463  return *this;
1464 }
1465 
1466 inline FFVar&
1467 FFVar::operator=
1468 ( const int n )
1469 {
1470  _id = std::make_pair(CINT,NOREF);
1471  _num = n;
1472  _dep = n;
1473  _dag = 0;
1474  _val = 0;
1475  _ops.first = 0;
1476  _ops.second.clear();
1477  return *this;
1478 }
1479 
1480 inline FFVar&
1481 FFVar::operator=
1482 ( const double x )
1483 {
1484  _id = std::make_pair(CREAL,NOREF);
1485  _num = x;
1486  _dep = x;
1487  _dag = 0;
1488  _val = 0;
1489  _ops.first = 0;
1490  _ops.second.clear();
1491  return *this;
1492 }
1493 
1494 inline FFVar
1495 operator+
1496 ( const FFVar&Var )
1497 {
1498  return Var;
1499 }
1500 
1501 template <typename U> inline FFVar&
1502 FFVar::operator+=
1503 ( const U&Var )
1504 {
1505  FFVar VarNew = *this + Var;
1506  *this = VarNew;
1507  return *this;
1508 }
1509 
1510 inline FFVar
1511 operator+
1512 ( const FFVar&Var1, const FFVar&Var2 )
1513 {
1514  if( &Var1 == &Var2 ) return( 2. * Var1 );
1515 
1516  // Case either or both operands are (unreferenced) numeric constants
1517  if( Var1._id.second == FFVar::NOREF && Var2._id.second == FFVar::NOREF ){
1518  switch( Var1._num.t ){
1519  case FFNum::INT:
1520  switch( Var2._num.t ){
1521  case FFNum::INT: return( Var1._num.n + Var2._num.n );
1522  case FFNum::REAL: return( Var1._num.n + Var2._num.x );
1523  }
1524  case FFNum::REAL:
1525  switch( Var2._num.t ){
1526  case FFNum::INT: return( Var1._num.x + Var2._num.n );
1527  case FFNum::REAL: return( Var1._num.x + Var2._num.x );
1528  }
1529  }
1530  }
1531  if( Var1._id.second == FFVar::NOREF ){
1532  switch( Var1._num.t ){
1533  case FFNum::INT: return( Var2 + Var1._num.n );
1534  case FFNum::REAL: return( Var2 + Var1._num.x );
1535  }
1536  }
1537  if( Var2._id.second == FFVar::NOREF ){
1538  switch( Var2._num.t ){
1539  case FFNum::INT: return( Var1 + Var2._num.n );
1540  case FFNum::REAL: return( Var1 + Var2._num.x );
1541  }
1542  }
1543 
1544  // Append new intermediate variable and corresponding operation
1545  // (only if operation does not exist already)
1546  return FFGraph::_insert_binary_operation( FFOp::PLUS, Var1._dep+Var2._dep, Var1, Var2 );
1547 }
1548 
1549 template <typename U> inline FFVar
1550 operator+
1551 ( const U&Cst1, const FFVar&Var2 )
1552 {
1553  // Case constant is zero
1554  if( Cst1 == 0. ) return Var2;
1555 
1556  // Case right operand is (unreferenced) numeric constrants
1557  if( Var2._id.second == FFVar::NOREF ){
1558  switch( Var2._num.t ){
1559  case FFNum::INT: return( Cst1 + Var2._num.n );
1560  case FFNum::REAL: return( Cst1 + Var2._num.x );
1561  }
1562  }
1563 
1564  // Append new intermediate variable and corresponding operation
1565  // (only if operation does not exist already)
1566  // Also append constant Cst1 if not defined
1567  return FFGraph::_insert_binary_operation( FFOp::PLUS, Cst1+Var2._dep, (double)Cst1, Var2 );
1568 }
1569 
1570 template <typename U> inline FFVar
1571 operator+
1572 ( const FFVar&Var1, const U&Cst2 )
1573 {
1574  return( Cst2 + Var1 );
1575 }
1576 
1577 inline FFVar
1578 operator-
1579 ( const FFVar&Var )
1580 {
1581  // Case right operand is a numeric constant
1582  if( Var._id.second == FFVar::NOREF ){
1583  switch( Var._num.t ){
1584  case FFNum::INT: return( -Var._num.n );
1585  case FFNum::REAL: return( -Var._num.x );
1586  }
1587  }
1588 
1589  // Append new intermediate variable and corresponding operation
1590  // (only if operation does not exist already)
1591  return FFGraph::_insert_unary_operation( FFOp::NEG, -Var._dep, Var );
1592 }
1593 
1594 template <typename U> inline FFVar&
1595 FFVar::operator-=
1596 ( const U&Var )
1597 {
1598  FFVar VarNew = *this - Var;
1599  *this = VarNew;
1600  return *this;
1601 }
1602 
1603 inline FFVar
1604 operator-
1605 ( const FFVar&Var1, const FFVar&Var2 )
1606 {
1607  if( &Var1 == &Var2 ) return double(0);
1608 
1609  // Case either or both operands are numeric constants
1610  if( Var1._id.second == FFVar::NOREF
1611  && Var2._id.second == FFVar::NOREF ){
1612  switch( Var1._num.t ){
1613  case FFNum::INT:
1614  switch( Var2._num.t ){
1615  case FFNum::INT: return( Var1._num.n - Var2._num.n );
1616  case FFNum::REAL: return( Var1._num.n - Var2._num.x );
1617  }
1618  case FFNum::REAL:
1619  switch( Var2._num.t ){
1620  case FFNum::INT: return( Var1._num.x - Var2._num.n );
1621  case FFNum::REAL: return( Var1._num.x - Var2._num.x );
1622  }
1623  }
1624  }
1625 
1626  if( Var1._id.second == FFVar::NOREF ){
1627  switch( Var1._num.t ){
1628  case FFNum::INT: return( (double)Var1._num.n - Var2 );
1629  case FFNum::REAL: return( Var1._num.x - Var2 );
1630  }
1631  }
1632 
1633  if( Var2._id.second == FFVar::NOREF ){
1634  switch( Var2._num.t ){
1635  case FFNum::INT: return( Var1 - (double)Var2._num.n );
1636  case FFNum::REAL: return( Var1 - Var2._num.x );
1637  }
1638  }
1639 
1640  // Append new intermediate variable and corresponding operation
1641  // (only if operation does not exist already)
1642  return FFGraph::_insert_binary_operation( FFOp::MINUS, Var1._dep-Var2._dep, Var1, Var2 );
1643 }
1644 
1645 template <typename U> inline FFVar
1646 operator-
1647 ( const FFVar&Var1, const U&Cst2 )
1648 {
1649  //return( Var1 + (-Cst2) );
1650 
1651  // Case constant is zero
1652  if( Cst2 == 0. ) return Var1;
1653 
1654  // Case right operand is a numeric constant
1655  if( Var1._id.second == FFVar::NOREF ){
1656  switch( Var1._num.t ){
1657  case FFNum::INT: return( Var1._num.n - Cst2 );
1658  case FFNum::REAL: return( Var1._num.x - Cst2 );
1659  }
1660  }
1661 
1662  // Append new intermediate variable and corresponding operation
1663  // (only if operation does not exist already)
1664  // Also append constant Cst2 if not defined
1665  return FFGraph::_insert_binary_operation( FFOp::MINUS, Var1._dep-Cst2, Var1, (double)Cst2 );
1666 }
1667 
1668 template <typename U> inline FFVar
1669 operator-
1670 ( const U&Cst1, const FFVar&Var2 )
1671 {
1672  // Case constant is zero
1673  if( Cst1 == 0. ) return -Var2;
1674 
1675  // Case right operand is a numeric constant
1676  if( Var2._id.second == FFVar::NOREF ){
1677  switch( Var2._num.t ){
1678  case FFNum::INT: return( Cst1 - Var2._num.n );
1679  case FFNum::REAL: return( Cst1 - Var2._num.x );
1680  }
1681  }
1682 
1683  // Append new intermediate variable and corresponding operation
1684  // (only if operation does not exist already)
1685  // Also append constant Cst1 if not defined
1686  return FFGraph::_insert_binary_operation( FFOp::MINUS, Cst1-Var2._dep, (double)Cst1, Var2 );
1687 }
1688 
1689 template <typename U> inline FFVar&
1690 FFVar::operator*=
1691 ( const U&Var )
1692 {
1693  FFVar VarNew = *this * Var;
1694  *this = VarNew;
1695  return *this;
1696 }
1697 
1698 inline FFVar
1699 operator*
1700 ( const FFVar&Var1, const FFVar&Var2 )
1701 {
1702  if( &Var1 == &Var2 ) return sqr(Var1);
1703 
1704  // Case either or both operands are numeric constants
1705  if( Var1._id.second == FFVar::NOREF && Var2._id.second == FFVar::NOREF ){
1706  switch( Var1._num.t ){
1707  case FFNum::INT:
1708  switch( Var2._num.t ){
1709  case FFNum::INT: return( Var1._num.n * Var2._num.n );
1710  case FFNum::REAL: return( Var1._num.n * Var2._num.x );
1711  }
1712  case FFNum::REAL:
1713  switch( Var2._num.t ){
1714  case FFNum::INT: return( Var1._num.x * Var2._num.n );
1715  case FFNum::REAL: return( Var1._num.x * Var2._num.x );
1716  }
1717  }
1718  }
1719 
1720  if( Var1._id.second == FFVar::NOREF ){
1721  switch( Var1._num.t ){
1722  case FFNum::INT: return( (double)Var1._num.n * Var2 );
1723  case FFNum::REAL: return( Var1._num.x * Var2 );
1724  }
1725  }
1726 
1727  if( Var2._id.second == FFVar::NOREF ){
1728  switch( Var2._num.t ){
1729  case FFNum::INT: return( Var1 * (double)Var2._num.n );
1730  case FFNum::REAL: return( Var1 * Var2._num.x );
1731  }
1732  }
1733 
1734  // Append new intermediate variable and corresponding operation
1735  // (only if operation does not exist already)
1736  return FFGraph::_insert_binary_operation( FFOp::TIMES, Var1._dep*Var2._dep, Var1, Var2 );
1737 }
1738 
1739 template <typename U> inline FFVar
1740 operator*
1741 ( const FFVar&Var1, const U&Cst2 )
1742 {
1743  return( Cst2 * Var1 );
1744 }
1745 
1746 template <typename U> inline FFVar
1747 operator*
1748 ( const U&Cst1, const FFVar&Var2 )
1749 {
1750  // Case constant is zero
1751  if( Cst1 == 0. ) return double(0);
1752  // Case constant is one
1753  if( Cst1 == 1. ) return Var2;
1754  // Case constant is one
1755  if( Cst1 == -1. ) return -Var2;
1756 
1757  // Case right operand is a numeric constant
1758  if( Var2._id.second == FFVar::NOREF ){
1759  switch( Var2._num.t ){
1760  case FFNum::INT: return( Cst1 * Var2._num.n );
1761  case FFNum::REAL: return( Cst1 * Var2._num.x );
1762  }
1763  }
1764 
1765  // Append new intermediate variable and corresponding operation
1766  // (only if operation does not exist already)
1767  // Also append constant Cst1 if not defined
1768  return FFGraph::_insert_binary_operation( FFOp::SCALE, Cst1*Var2._dep, (double)Cst1, Var2 );
1769 }
1770 
1771 template <typename U> inline FFVar&
1772 FFVar::operator/=
1773 ( const U&Var )
1774 {
1775  FFVar VarNew = *this / Var;
1776  *this = VarNew;
1777  return *this;
1778 }
1779 
1780 inline FFVar
1781 operator/
1782 ( const FFVar&Var1, const FFVar&Var2 )
1783 {
1784  if( &Var1 == &Var2 ) return double(1);
1785 
1786  // Case either or both operands are numeric constants
1787  if( Var1._id.second == FFVar::NOREF && Var2._id.second == FFVar::NOREF ){
1788  switch( Var1._num.t ){
1789  case FFNum::INT:
1790  switch( Var2._num.t ){
1791  case FFNum::INT: return( Var1._num.n / Var2._num.n );
1792  case FFNum::REAL: return( Var1._num.n / Var2._num.x );
1793  }
1794  case FFNum::REAL:
1795  switch( Var2._num.t ){
1796  case FFNum::INT: return( Var1._num.x / Var2._num.n );
1797  case FFNum::REAL: return( Var1._num.x / Var2._num.x );
1798  }
1799  }
1800  }
1801 
1802  if( Var1._id.second == FFVar::NOREF ){
1803  switch( Var1._num.t ){
1804  case FFNum::INT: return( Var1._num.n / Var2 );
1805  case FFNum::REAL: return( Var1._num.x / Var2 );
1806  }
1807  }
1808 
1809  if( Var2._id.second == FFVar::NOREF ){
1810  switch( Var2._num.t ){
1811  case FFNum::INT: return( Var1 / Var2._num.n );
1812  case FFNum::REAL: return( Var1 / Var2._num.x );
1813  }
1814  }
1815 
1816  // Append new intermediate variable and corresponding operation
1817  // (only if operation does not exist already)
1818  return FFGraph::_insert_binary_operation( FFOp::DIV, Var1._dep/Var2._dep, Var1, Var2 );
1819 }
1820 
1821 template <typename U> inline FFVar
1822 operator/
1823 ( const FFVar&Var1, const U&Cst2 )
1824 {
1825  return( ( 1 / Cst2 ) * Var1 );
1826 }
1827 
1828 template <typename U> inline FFVar
1829 operator/
1830 ( const U&Cst1, const FFVar&Var2 )
1831 {
1832  // Case constant is zero
1833  if( Cst1 == 0. ) return int(0);
1834 
1835  // Case right operand is a numeric constant
1836  if( Var2._id.second == FFVar::NOREF ){
1837  switch( Var2._num.t ){
1838  case FFNum::INT: return( Cst1 / Var2._num.n );
1839  case FFNum::REAL: return( Cst1 / Var2._num.x );
1840  }
1841  }
1842 
1843  // Append new intermediate variable and corresponding operation
1844  // (only if operation does not exist already)
1845  // Also append constant Cst1 if not defined
1846  return FFGraph::_insert_binary_operation( FFOp::DIV, Cst1/Var2._dep, (double)Cst1, Var2 );
1847 }
1848 
1849 inline FFVar
1850 inv
1851 ( const FFVar&Var )
1852 {
1853  return( 1 / Var );
1854 }
1855 
1856 inline FFVar
1857 max
1858 ( const FFVar&Var1, const FFVar&Var2 )
1859 {
1860  if( &Var1 == &Var2 ) return Var1;
1861 
1862  // Case either or both operands are numeric constants
1863  if( Var1._id.second == FFVar::NOREF && Var2._id.second == FFVar::NOREF ){
1864  switch( Var1._num.t ){
1865  case FFNum::INT:
1866  switch( Var2._num.t ){
1867  case FFNum::INT: return( Var1._num.n>Var2._num.n? Var1._num.n: Var2._num.n );
1868  case FFNum::REAL: return( std::max((double)Var1._num.n,Var2._num.x) );
1869  }
1870  case FFNum::REAL:
1871  switch( Var2._num.t ){
1872  case FFNum::INT: return( std::max(Var1._num.x,(double)Var2._num.n) );
1873  case FFNum::REAL: return( std::max(Var1._num.x,Var2._num.x) );
1874  }
1875  }
1876  }
1877 
1878  if( Var1._id.second == FFVar::NOREF ){
1879  switch( Var1._num.t ){
1880  case FFNum::INT: return( max((double)Var1._num.n,Var2) );
1881  case FFNum::REAL: return( max(Var1._num.x,Var2) );
1882  }
1883  }
1884 
1885  if( Var2._id.second == FFVar::NOREF ){
1886  switch( Var2._num.t ){
1887  case FFNum::INT: return( max((double)Var2._num.n,Var1) );
1888  case FFNum::REAL: return( max(Var2._num.x,Var1) );
1889  }
1890  }
1891 
1892  // Append new intermediate variable and corresponding operation
1893  // (only if operation does not exist already)
1894  return FFGraph::_insert_binary_operation( FFOp::MAXF, max(Var1._dep,Var2._dep), Var1, Var2 );
1895 }
1896 
1897 template <typename U> inline FFVar
1898 max
1899 ( const FFVar&Var1, const U&Cst2 )
1900 {
1901  return( max( Cst2, Var1 ) );
1902 }
1903 
1904 template <typename U> inline FFVar
1905 max
1906 ( const U&Cst1, const FFVar&Var2 )
1907 {
1908  // Case right operand is a numeric constant
1909  if( Var2._id.second == FFVar::NOREF ){
1910  switch( Var2._num.t ){
1911  case FFNum::INT: return( std::max(Cst1,(double)Var2._num.n) );
1912  case FFNum::REAL: return( std::max(Cst1,Var2._num.x) );
1913  }
1914  }
1915 
1916  // Append new intermediate variable and corresponding operation
1917  // (only if operation does not exist already)
1918  // Also append constant Cst1 if not defined
1919  return FFGraph::_insert_binary_operation( FFOp::MAXF, max((double)Cst1,Var2._dep), (double)Cst1, Var2 );
1920 }
1921 
1922 inline FFVar
1923 max
1924 ( const unsigned nVar, const FFVar*pVar )
1925 {
1926  if( nVar<=0 || !pVar ) return( 0 );
1927 
1928  FFVar VarR = pVar[0];
1929  for( unsigned int i=1; i<nVar; i++ ) VarR = max( VarR, pVar[i] );
1930  return( VarR );
1931 }
1932 
1933 inline FFVar
1934 min
1935 ( const FFVar&Var1, const FFVar&Var2 )
1936 {
1937  if( &Var1 == &Var2 ) return Var1;
1938 
1939  // Case either or both operands are numeric constants
1940  if( Var1._id.second == FFVar::NOREF && Var2._id.second == FFVar::NOREF ){
1941  switch( Var1._num.t ){
1942  case FFNum::INT:
1943  switch( Var2._num.t ){
1944  case FFNum::INT: return( Var1._num.n<Var2._num.n? Var1._num.n: Var2._num.n );
1945  case FFNum::REAL: return( std::min((double)Var1._num.n,Var2._num.x) );
1946  }
1947  case FFNum::REAL:
1948  switch( Var2._num.t ){
1949  case FFNum::INT: return( std::min(Var1._num.x,(double)Var2._num.n) );
1950  case FFNum::REAL: return( std::min(Var1._num.x,Var2._num.x) );
1951  }
1952  }
1953  }
1954 
1955  if( Var1._id.second == FFVar::NOREF ){
1956  switch( Var1._num.t ){
1957  case FFNum::INT: return( min((double)Var1._num.n,Var2) );
1958  case FFNum::REAL: return( min(Var1._num.x,Var2) );
1959  }
1960  }
1961 
1962  if( Var2._id.second == FFVar::NOREF ){
1963  switch( Var2._num.t ){
1964  case FFNum::INT: return( min((double)Var2._num.n,Var1) );
1965  case FFNum::REAL: return( min(Var2._num.x,Var1) );
1966  }
1967  }
1968 
1969  // Append new intermediate variable and corresponding operation
1970  // (only if operation does not exist already)
1971  return FFGraph::_insert_binary_operation( FFOp::MINF, min(Var1._dep,Var2._dep), Var1, Var2 );
1972 }
1973 
1974 template <typename U> inline FFVar
1975 min
1976 ( const FFVar&Var1, const U&Cst2 )
1977 {
1978  return( min( Cst2, Var1 ) );
1979 }
1980 
1981 template <typename U> inline FFVar
1982 min
1983 ( const U&Cst1, const FFVar&Var2 )
1984 {
1985  // Case right operand is a numeric constant
1986  if( Var2._id.second == FFVar::NOREF ){
1987  switch( Var2._num.t ){
1988  case FFNum::INT: return( std::min(Cst1,(double)Var2._num.n) );
1989  case FFNum::REAL: return( std::min(Cst1,Var2._num.x) );
1990  }
1991  }
1992 
1993  // Append new intermediate variable and corresponding operation
1994  // (only if operation does not exist already)
1995  // Also append constant Cst1 if not defined
1996  return FFGraph::_insert_binary_operation( FFOp::MINF, min((double)Cst1,Var2._dep), (double)Cst1, Var2 );
1997 }
1998 
1999 inline FFVar
2000 min
2001 ( const unsigned nVar, const FFVar*pVar )
2002 {
2003  if( nVar<=0 || !pVar ) return( 0 );
2004 
2005  FFVar VarR = pVar[0];
2006  for( unsigned int i=1; i<nVar; i++ ) VarR = min( VarR, pVar[i] );
2007  return( VarR );
2008 }
2009 
2010 inline FFVar
2011 exp
2012 ( const FFVar&Var )
2013 {
2014  // Case operand is a numeric constant
2015  if( Var._id.second == FFVar::NOREF ){
2016  switch( Var._num.t ){
2017  case FFNum::INT: return( std::exp( Var._num.n ) );
2018  case FFNum::REAL: return( std::exp( Var._num.x ) );
2019  }
2020  }
2021 
2022  // Append new intermediate variable and corresponding operation
2023  // (only if operation does not exist already)
2024  return FFGraph::_insert_unary_operation( FFOp::EXP, exp(Var._dep), Var );
2025 }
2026 
2027 inline FFVar
2028 log
2029 ( const FFVar&Var )
2030 {
2031  // Case operand is a numeric constant
2032  if( Var._id.second == FFVar::NOREF ){
2033  switch( Var._num.t ){
2034  case FFNum::INT: return( std::log( Var._num.n ) );
2035  case FFNum::REAL: return( std::log( Var._num.x ) );
2036  }
2037  }
2038 
2039  // Append new intermediate variable and corresponding operation
2040  // (only if operation does not exist already)
2041  return FFGraph::_insert_unary_operation( FFOp::LOG, log(Var._dep), Var );
2042 }
2043 
2044 inline FFVar
2045 sqr
2046 ( const FFVar&Var )
2047 {
2048  // Case operand is a numeric constant
2049  if( Var._id.second == FFVar::NOREF ){
2050  switch( Var._num.t ){
2051  case FFNum::INT: return( mc::sqr( Var._num.n ) );
2052  case FFNum::REAL: return( mc::sqr( Var._num.x ) );
2053  }
2054  }
2055 
2056  // Append new intermediate variable and corresponding operation
2057  // (only if operation does not exist already)
2058  return FFGraph::_insert_unary_operation( FFOp::SQR, sqr(Var._dep), Var );
2059 }
2060 
2061 inline FFVar
2062 sqrt
2063 ( const FFVar&Var )
2064 {
2065  // Case operand is a numeric constant
2066  if( Var._id.second == FFVar::NOREF ){
2067  switch( Var._num.t ){
2068  case FFNum::INT: return( std::sqrt( Var._num.n ) );
2069  case FFNum::REAL: return( std::sqrt( Var._num.x ) );
2070  }
2071  }
2072 
2073  // Append new intermediate variable and corresponding operation
2074  // (only if operation does not exist already)
2075  return FFGraph::_insert_unary_operation( FFOp::SQRT, sqrt(Var._dep), Var );
2076 }
2077 
2078 inline FFVar
2079 fabs
2080 ( const FFVar&Var )
2081 {
2082  // Case operand is a numeric constant
2083  if( Var._id.second == FFVar::NOREF ){
2084  switch( Var._num.t ){
2085  case FFNum::INT: return( std::fabs( Var._num.n ) );
2086  case FFNum::REAL: return( std::fabs( Var._num.x ) );
2087  }
2088  }
2089 
2090  // Append new intermediate variable and corresponding operation
2091  // (only if operation does not exist already)
2092  return FFGraph::_insert_unary_operation( FFOp::FABS, fabs(Var._dep), Var );
2093 }
2094 
2095 inline FFVar
2096 pow
2097 ( const FFVar&Var, const int iExp )
2098 {
2099  // Case operand is a numeric constant
2100  if( Var._id.second == FFVar::NOREF ){
2101  switch( Var._num.t ){
2102  case FFNum::INT: return( std::pow( Var._num.n, iExp ) );
2103  case FFNum::REAL: return( std::pow( Var._num.x, iExp ) );
2104  }
2105  }
2106 
2107  // Case integer exponent is 0,1, or 2
2108  if( iExp == 0 ) return( 1. );
2109  if( iExp == 1 ) return Var;
2110  if( iExp == 2 ) return sqr(Var);
2111 
2112  // Append new intermediate variable and corresponding operation
2113  // (only if operation does not exist already)
2114  // Also append constant iExp if not defined
2115  return FFGraph::_insert_binary_operation( FFOp::IPOW, pow(Var._dep,iExp), Var, iExp );
2116 }
2117 
2118 inline FFVar
2119 pow
2120 ( const FFVar&Var1, const double Cst2 )
2121 {
2122  return exp( Cst2 * log( Var1 ) );
2123 }
2124 
2125 inline FFVar
2126 pow
2127 ( const FFVar&Var1, const FFVar&Var2 )
2128 {
2129  // Case exponent is integer constant
2130  if( Var2._id.second == FFVar::NOREF && Var2._num.t == FFNum::INT )
2131  return pow( Var1, Var2._num.n );
2132 
2133  return exp( Var2 * log( Var1 ) );
2134 }
2135 
2136 inline FFVar
2137 pow
2138 ( const double Cst1, const FFVar&Var2 )
2139 {
2140  // Case exponent is integer constant
2141  if( Var2._id.second == FFVar::NOREF && Var2._num.t == FFNum::INT )
2142  return std::pow( Cst1, Var2._num.n );
2143 
2144  return exp( Var2 * std::log( Cst1 ) );
2145 }
2146 
2147 inline FFVar
2148 cos
2149 ( const FFVar&Var )
2150 {
2151  // Case operand is a numeric constant
2152  if( Var._id.second == FFVar::NOREF ){
2153  switch( Var._num.t ){
2154  case FFNum::INT: return( std::cos( Var._num.n ) );
2155  case FFNum::REAL: return( std::cos( Var._num.x ) );
2156  }
2157  }
2158 
2159  // Append new intermediate variable and corresponding operation
2160  // (only if operation does not exist already)
2161  return FFGraph::_insert_unary_operation( FFOp::COS, cos(Var._dep), Var );
2162 }
2163 
2164 inline FFVar
2165 sin
2166 ( const FFVar&Var )
2167 {
2168  // Case operand is a numeric constant
2169  if( Var._id.second == FFVar::NOREF ){
2170  switch( Var._num.t ){
2171  case FFNum::INT: return( std::sin( Var._num.n ) );
2172  case FFNum::REAL: return( std::sin( Var._num.x ) );
2173  }
2174  }
2175 
2176  // Append new intermediate variable and corresponding operation
2177  // (only if operation does not exist already)
2178  return FFGraph::_insert_unary_operation( FFOp::SIN, sin(Var._dep), Var );
2179 }
2180 
2181 inline FFVar
2182 tan
2183 ( const FFVar&Var )
2184 {
2185  // Case operand is a numeric constant
2186  if( Var._id.second == FFVar::NOREF ){
2187  switch( Var._num.t ){
2188  case FFNum::INT: return( std::tan( Var._num.n ) );
2189  case FFNum::REAL: return( std::tan( Var._num.x ) );
2190 
2191  }
2192  }
2193 
2194  // Append new intermediate variable and corresponding operation
2195  // (only if operation does not exist already)
2196  return FFGraph::_insert_unary_operation( FFOp::TAN, tan(Var._dep), Var );
2197 }
2198 
2199 inline FFVar
2200 asin
2201 ( const FFVar&Var )
2202 {
2203  // Case operand is a numeric constant
2204  if( Var._id.second == FFVar::NOREF ){
2205  switch( Var._num.t ){
2206  case FFNum::INT: return( std::asin( Var._num.n ) );
2207  case FFNum::REAL: return( std::asin( Var._num.x ) );
2208  }
2209  }
2210 
2211  // Append new intermediate variable and corresponding operation
2212  // (only if operation does not exist already)
2213  return FFGraph::_insert_unary_operation( FFOp::ASIN, asin(Var._dep), Var );
2214 }
2215 
2216 inline FFVar
2217 acos
2218 ( const FFVar&Var )
2219 {
2220  // Case operand is a numeric constant
2221  if( Var._id.second == FFVar::NOREF ){
2222  switch( Var._num.t ){
2223  case FFNum::INT: return( std::acos( Var._num.n ) );
2224  case FFNum::REAL: return( std::acos( Var._num.x ) );
2225  }
2226  }
2227 
2228  // Append new intermediate variable and corresponding operation
2229  // (only if operation does not exist already)
2230  return FFGraph::_insert_unary_operation( FFOp::ACOS, acos(Var._dep), Var );
2231 }
2232 
2233 inline FFVar
2234 atan
2235 ( const FFVar&Var )
2236 {
2237  // Case operand is a numeric constant
2238  if( Var._id.second == FFVar::NOREF ){
2239  switch( Var._num.t ){
2240  case FFNum::INT: return( std::atan( Var._num.n ) );
2241  case FFNum::REAL: return( std::atan( Var._num.x ) );
2242  }
2243  }
2244 
2245  // Append new intermediate variable and corresponding operation
2246  // (only if operation does not exist already)
2247  return FFGraph::_insert_unary_operation( FFOp::ATAN, atan(Var._dep), Var );
2248 }
2249 
2250 inline FFVar
2251 erf
2252 ( const FFVar&Var )
2253 {
2254  // Case operand is a numeric constant
2255  if( Var._id.second == FFVar::NOREF ){
2256  switch( Var._num.t ){
2257  case FFNum::INT: return( ::erf( Var._num.n ) );
2258  case FFNum::REAL: return( ::erf( Var._num.x ) );
2259  }
2260  }
2261 
2262  // Append new intermediate variable and corresponding operation
2263  // (only if operation does not exist already)
2264  return FFGraph::_insert_unary_operation( FFOp::ERF, erf(Var._dep), Var );
2265 }
2266 
2267 inline FFVar
2268 erfc
2269 ( const FFVar&Var )
2270 {
2271  return ( 1. - erf( Var ) );
2272 }
2273 
2274 inline FFVar
2275 fstep
2276 ( const FFVar&Var )
2277 {
2278  // Case operand is a numeric constant
2279  if( Var._id.second == FFVar::NOREF ){
2280  switch( Var._num.t ){
2281  case FFNum::INT: return( mc::fstep( Var._num.n ) );
2282  case FFNum::REAL: return( mc::fstep( Var._num.x ) );
2283  }
2284  }
2285 
2286  // Append new intermediate variable and corresponding operation
2287  // (only if operation does not exist already)
2288  return FFGraph::_insert_unary_operation( FFOp::FSTEP, fstep(Var._dep), Var );
2289 }
2290 
2291 inline FFVar
2292 bstep
2293 ( const FFVar&Var )
2294 {
2295  return ( fstep( -Var ) );
2296 }
2297 
2298 
2300 
2301 inline
2302 FFOp::FFOp
2303 ( TYPE top, FFVar*lop, FFVar*rop, FFVar*res ):
2304  type( top ), pres( res ), _visited(false)
2305 {
2306  // Order operands for commutative binary operators
2307  if( !lop
2308  || ( top != PLUS && top != TIMES && top != SCALE )
2309  || lt_FFVar()( lop, rop ) )
2310  { plop = lop; prop = rop; }
2311  else
2312  { plop = rop; prop = lop; }
2313 }
2314 
2315 inline std::ostream&
2316 operator <<
2317 ( std::ostream&out, const FFOp&Op)
2318 {
2319  switch( Op.type ){
2320  case FFOp::CNST: out << Op.pres->num() << "\t"; break;
2321  case FFOp::VAR: out << "VARIABLE"; break;
2322  case FFOp::PLUS: out << FFVar::_name( Op.plop->id() ) << " + " << FFVar::_name( Op.prop->id() ) << "\t"; break;
2323  case FFOp::NEG: out << "- " << FFVar::_name( Op.plop->id() ) << "\t" ; break;
2324  case FFOp::MINUS: out << FFVar::_name( Op.plop->id() ) << " - " << FFVar::_name( Op.prop->id() ) << "\t"; break;
2325  case FFOp::TIMES:
2326  case FFOp::SCALE: out << FFVar::_name( Op.plop->id() ) << " * " << FFVar::_name( Op.prop->id() ) << "\t"; break;
2327  case FFOp::DIV: out << FFVar::_name( Op.plop->id() ) << " / " << FFVar::_name( Op.prop->id() ) << "\t"; break;
2328  case FFOp::MINF: out << "MIN( " << FFVar::_name( Op.plop->id() ) << ", " << FFVar::_name( Op.prop->id() ) << " )"; break;
2329  case FFOp::MAXF: out << "MAX( " << FFVar::_name( Op.plop->id() ) << ", " << FFVar::_name( Op.prop->id() ) << " )"; break;
2330  case FFOp::EXP: out << "EXP( " << FFVar::_name( Op.plop->id() ) << " )\t"; break;
2331  case FFOp::LOG: out << "LOG( " << FFVar::_name( Op.plop->id() ) << " )\t"; break;
2332  case FFOp::SQR: out << "SQR( " << FFVar::_name( Op.plop->id() ) << " )\t"; break;
2333  case FFOp::SQRT: out << "SQRT( " << FFVar::_name( Op.plop->id() ) << " )\t"; break;
2334  case FFOp::FABS: out << "FABS( " << FFVar::_name( Op.plop->id() ) << " )\t"; break;
2335  case FFOp::IPOW: out << "POW( " << FFVar::_name( Op.plop->id() ) << ", " << FFVar::_name( Op.prop->id() ) << " )"; break;
2336  case FFOp::COS: out << "COS( " << FFVar::_name( Op.plop->id() ) << " )\n"; break;
2337  case FFOp::SIN: out << "SIN( " << FFVar::_name( Op.plop->id() ) << " )\n"; break;
2338  case FFOp::TAN: out << "TAN( " << FFVar::_name( Op.plop->id() ) << " )\n"; break;
2339  case FFOp::ASIN: out << "ASIN( " << FFVar::_name( Op.plop->id() ) << " )\n"; break;
2340  case FFOp::ACOS: out << "ACOS( " << FFVar::_name( Op.plop->id() ) << " )\n"; break;
2341  case FFOp::ATAN: out << "ATAN( " << FFVar::_name( Op.plop->id() ) << " )\n"; break;
2342  case FFOp::ERF: out << "ERF( " << FFVar::_name( Op.plop->id() ) << " )\n"; break;
2343  case FFOp::FSTEP: out << "FSTEP( " << FFVar::_name( Op.plop->id() ) << " )\n"; break;
2344  default:;
2345  }
2346  return out;
2347 }
2348 
2349 inline void
2351 ( std::list<const FFOp*>&Ops ) const
2352 {
2353  if( _visited ) return;
2354  _visited = true;
2355 
2356  //Ops.push_front( this );
2357  if( plop && plop->ops().first ) plop->ops().first->propagate_subgraph( Ops );
2358  if( prop && prop->ops().first ) prop->ops().first->propagate_subgraph( Ops );
2359  Ops.push_back( this );
2360 }
2361 
2362 template <typename U> inline void
2364 ( const U& U_dum ) const
2365 {
2366  if( _visited ) return;
2367  _visited = true;
2368 
2369  if( plop && plop->ops().first ) plop->ops().first->reset_val_subgraph( U_dum );
2370  if( prop && prop->ops().first ) prop->ops().first->reset_val_subgraph( U_dum );
2371  if( pres && pres->val() ) pres->reset_val( U_dum );
2372 }
2373 
2374 template <typename U> inline void
2376 ( const U& U_dum, const std::vector<const FFVar*>&vDep,
2377  const std::vector<const FFVar*>&vIndep ) const
2378 {
2379  if( _visited ) return;
2380  _visited = true;
2381 
2382  if( plop && plop->ops().first ) plop->ops().first->reset_val_subgraph( U_dum, vDep, vIndep );
2383  if( prop && prop->ops().first ) prop->ops().first->reset_val_subgraph( U_dum, vDep, vIndep );
2384  if( pres && pres->val() ){
2385  // Do not reset _val field of independent variables
2386  typename std::vector<const FFVar*>::const_iterator iti = vIndep.begin();
2387  for( ; iti!=vIndep.end(); ++iti ) if( pres->id() == (*iti)->id() ) return;
2388  // Do not reset _val field of dependent variables
2389  typename std::vector<const FFVar*>::const_iterator itd = vDep.begin();
2390  for( ; itd!=vDep.end(); ++itd ) if( pres->id() == (*itd)->id() ) return;
2391  pres->reset_val( U_dum );
2392  }
2393 }
2394 
2395 template <typename U> inline void
2397 ( const U& U_dum ) const
2398 {
2399  switch( type ){
2400  case FFOp::VAR:
2401  if( !pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::MISSVAR );
2402  return;
2403 
2404  case FFOp::CNST:
2405  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2406  switch( pres->num().t ){
2407  case FFNum::INT: pres->val() = new U( pres->num().n ); return;
2408  case FFNum::REAL: pres->val() = new U( pres->num().x ); return;
2409  }
2410 
2411  case FFOp::PLUS:
2412  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2413  pres->val() = new U( *static_cast<U*>( plop->val() )
2414  + *static_cast<U*>( prop->val() ) );
2415 #ifdef MC__FFUNC_DEBUG_EVAL
2416  std::cout << "FFOp::PLUS:" << std::endl;
2417  std::cout << "plop: " << plop << " plop->val(): " << plop->val() << std::endl;
2418  std::cout << "prop: " << prop << " prop->val(): " << prop->val() << std::endl;
2419  std::cout << "pres: " << pres << " pres->val(): " << pres->val() << std::endl;
2420 #endif
2421  return;
2422 
2423  case FFOp::NEG:
2424  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2425  pres->val() = new U( - *static_cast<U*>( plop->val() ) );
2426  return;
2427 
2428  case FFOp::MINUS:
2429  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2430  pres->val() = new U( *static_cast<U*>( plop->val() )
2431  - *static_cast<U*>( prop->val() ) );
2432  return;
2433 
2434  case FFOp::SCALE:
2435  case FFOp::TIMES:
2436  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2437  pres->val() = new U( *static_cast<U*>( plop->val() )
2438  * *static_cast<U*>( prop->val() ) );
2439 #ifdef MC__FFUNC_DEBUG_EVAL
2440  std::cout << "FFOp::TIMES:" << std::endl;
2441  std::cout << "plop: " << plop << " plop->val(): " << plop->val() << std::endl;
2442  std::cout << "prop: " << prop << " prop->val(): " << prop->val() << std::endl;
2443  std::cout << "pres: " << pres << " pres->val(): " << pres->val() << std::endl;
2444 #endif
2445  return;
2446 
2447  case FFOp::DIV:
2448  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2449  pres->val() = new U( *static_cast<U*>( plop->val() )
2450  / *static_cast<U*>( prop->val() ) );
2451  return;
2452 
2453  case FFOp::IPOW:
2454  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2455  pres->val() = new U( Op<U>::pow( *static_cast<U*>( plop->val() ),
2456  prop->num().n ) );
2457  return;
2458 
2459  case FFOp::EXP:
2460  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2461  pres->val() = new U( Op<U>::exp( *static_cast<U*>( plop->val() ) ) );
2462  return;
2463 
2464  case FFOp::LOG:
2465  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2466  pres->val() = new U( Op<U>::log( *static_cast<U*>( plop->val() ) ) );
2467  return;
2468 
2469  case FFOp::SQR:
2470  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2471  pres->val() = new U( Op<U>::sqr( *static_cast<U*>( plop->val() ) ) );
2472 #ifdef MC__FFUNC_DEBUG_EVAL
2473  std::cout << "FFOp::SQR:" << std::endl;
2474  std::cout << "plop: " << plop << " plop->val(): " << plop->val() << std::endl;
2475  std::cout << "pres: " << pres << " pres->val(): " << pres->val() << std::endl;
2476 #endif
2477  return;
2478 
2479  case FFOp::SQRT:
2480  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2481  pres->val() = new U( Op<U>::sqrt( *static_cast<U*>( plop->val() ) ) );
2482  return;
2483 
2484  case FFOp::COS:
2485  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2486  pres->val() = new U( Op<U>::cos( *static_cast<U*>( plop->val() ) ) );
2487  return;
2488 
2489  case FFOp::SIN:
2490  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2491  pres->val() = new U( Op<U>::sin( *static_cast<U*>( plop->val() ) ) );
2492  return;
2493 
2494  case FFOp::TAN:
2495  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2496  pres->val() = new U( Op<U>::tan( *static_cast<U*>( plop->val() ) ) );
2497  return;
2498 
2499  case FFOp::ACOS:
2500  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2501  pres->val() = new U( Op<U>::acos( *static_cast<U*>( plop->val() ) ) );
2502  return;
2503 
2504  case FFOp::ASIN:
2505  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2506  pres->val() = new U( Op<U>::asin( *static_cast<U*>( plop->val() ) ) );
2507  return;
2508 
2509  case FFOp::ATAN:
2510  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2511  pres->val() = new U( Op<U>::atan( *static_cast<U*>( plop->val() ) ) );
2512  return;
2513 
2514  case FFOp::ERF:
2515  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2516  pres->val() = new U( Op<U>::erf( *static_cast<U*>( plop->val() ) ) );
2517  return;
2518 
2519  case FFOp::FABS:
2520  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2521  pres->val() = new U( Op<U>::fabs( *static_cast<U*>( plop->val() ) ) );
2522  return;
2523 
2524  case FFOp::FSTEP:
2525  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2526  pres->val() = new U( Op<U>::fstep( *static_cast<U*>( plop->val() ) ) );
2527  return;
2528 
2529  case FFOp::MINF:
2530  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2531  pres->val() = new U( Op<U>::min( *static_cast<U*>( plop->val() ),
2532  *static_cast<U*>( prop->val() ) ) );
2533  return;
2534 
2535  case FFOp::MAXF:
2536  //if( pres->val() ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::INTERN );
2537  pres->val() = new U( Op<U>::max( *static_cast<U*>( plop->val() ),
2538  *static_cast<U*>( prop->val() ) ) );
2539  return;
2540 
2541  default:
2543  }
2544 }
2545 
2546 template <typename U> inline void
2548 ( U* pUres ) const
2549 {
2550  switch( type ){
2551  case FFOp::VAR:
2552  // Nothing to do, besides setting pres->val()
2553  break;
2554 
2555  case FFOp::CNST:
2556  switch( pres->num().t ){
2557  case FFNum::INT: *pUres = pres->num().n; break;
2558  case FFNum::REAL: *pUres = pres->num().x; break;
2559  }
2560  break;
2561 
2562  case FFOp::PLUS:
2563  *pUres = *static_cast<U*>( plop->val() ) + *static_cast<U*>( prop->val() );
2564  break;
2565 
2566  case FFOp::NEG:
2567  *pUres = - *static_cast<U*>( plop->val() );
2568  break;
2569 
2570  case FFOp::MINUS:
2571  *pUres = *static_cast<U*>( plop->val() ) - *static_cast<U*>( prop->val() );
2572  break;
2573 
2574  case FFOp::SCALE:
2575  case FFOp::TIMES:
2576  *pUres = *static_cast<U*>( plop->val() ) * *static_cast<U*>( prop->val() );
2577  break;
2578 
2579  case FFOp::DIV:
2580  *pUres = *static_cast<U*>( plop->val() ) / *static_cast<U*>( prop->val() );
2581  break;
2582 
2583  case FFOp::IPOW:
2584  *pUres = Op<U>::pow( *static_cast<U*>( plop->val() ), prop->num().n );
2585  break;
2586 
2587  case FFOp::EXP:
2588  *pUres = Op<U>::exp( *static_cast<U*>( plop->val() ) );
2589  break;
2590 
2591  case FFOp::LOG:
2592  *pUres = Op<U>::log( *static_cast<U*>( plop->val() ) );
2593  break;
2594 
2595  case FFOp::SQR:
2596  *pUres = Op<U>::sqr( *static_cast<U*>( plop->val() ) );
2597  break;
2598 
2599  case FFOp::SQRT:
2600  *pUres = Op<U>::sqrt( *static_cast<U*>( plop->val() ) );
2601  break;
2602 
2603  case FFOp::COS:
2604  *pUres = Op<U>::cos( *static_cast<U*>( plop->val() ) );
2605  break;
2606 
2607  case FFOp::SIN:
2608  *pUres = Op<U>::sin( *static_cast<U*>( plop->val() ) );
2609  break;
2610 
2611  case FFOp::TAN:
2612  *pUres = Op<U>::tan( *static_cast<U*>( plop->val() ) );
2613  break;
2614 
2615  case FFOp::ACOS:
2616  *pUres = Op<U>::acos( *static_cast<U*>( plop->val() ) );
2617  break;
2618 
2619  case FFOp::ASIN:
2620  *pUres = Op<U>::asin( *static_cast<U*>( plop->val() ) );
2621  break;
2622 
2623  case FFOp::ATAN:
2624  *pUres = Op<U>::atan( *static_cast<U*>( plop->val() ) );
2625  break;
2626 
2627  case FFOp::ERF:
2628  *pUres = Op<U>::erf( *static_cast<U*>( plop->val() ) );
2629  break;
2630 
2631  case FFOp::FABS:
2632  *pUres = Op<U>::fabs( *static_cast<U*>( plop->val() ) );
2633  break;
2634 
2635  case FFOp::FSTEP:
2636  *pUres = Op<U>::fstep( *static_cast<U*>( plop->val() ) );
2637  break;
2638 
2639  case FFOp::MINF:
2640  *pUres = Op<U>::min( *static_cast<U*>( plop->val() ), *static_cast<U*>( prop->val() ) );
2641  break;
2642 
2643  case FFOp::MAXF:
2644  *pUres = Op<U>::max( *static_cast<U*>( plop->val() ), *static_cast<U*>( prop->val() ) );
2645  break;
2646 
2647  default:
2649  }
2650 
2651  pres->val() = pUres;
2652  return;
2653 }
2654 
2655 inline void
2657 ( std::ostream&os ) const
2658 {
2659  if( _visited ) return;
2660  _visited = true;
2661 
2662  if( plop && plop->ops().first ) plop->ops().first->generate_dot_script( os );
2663  if( prop && prop->ops().first ) prop->ops().first->generate_dot_script( os );
2664  append_dot_script( os );
2665 }
2666 
2667 inline void
2669 ( std::ostream&os ) const
2670 {
2671  std::ostringstream var_color; var_color << "red";
2672  std::ostringstream aux_color; aux_color << "blue";
2673  std::ostringstream op_color; op_color << "black";
2674  switch( type ){
2675  case FFOp::VAR: return append_dot_script_variable( os, false, 14 );
2676  case FFOp::CNST: return append_dot_script_variable( os, true, 14 );
2677  case FFOp::PLUS: return append_dot_script_factor( os, " + ", false, 18 );
2678  case FFOp::NEG: return append_dot_script_factor( os, " - ", true, 18 );
2679  case FFOp::MINUS: return append_dot_script_factor( os, " - ", false, 18 );
2680  case FFOp::SCALE: return append_dot_script_factor( os, " x ", false, 18 );
2681  case FFOp::TIMES: return append_dot_script_factor( os, " x ", false, 18 );
2682  case FFOp::DIV: return append_dot_script_factor( os, " / ", false, 18 );
2683  case FFOp::MINF: return append_dot_script_factor( os, "min", false, 14 );
2684  case FFOp::MAXF: return append_dot_script_factor( os, "max", false, 14 );
2685  case FFOp::IPOW: return append_dot_script_factor( os, "pow", false, 14, true );
2686  case FFOp::EXP: return append_dot_script_factor( os, "exp", true, 14 );
2687  case FFOp::LOG: return append_dot_script_factor( os, "log", true, 14 );
2688  case FFOp::FABS: return append_dot_script_factor( os, "fabs", true, 14 );
2689  case FFOp::SQR: return append_dot_script_factor( os, "sqr", true, 14 );
2690  case FFOp::SQRT: return append_dot_script_factor( os, "sqrt", true, 14 );
2691  case FFOp::COS: return append_dot_script_factor( os, "cos", true, 14 );
2692  case FFOp::SIN: return append_dot_script_factor( os, "sin", true, 14 );
2693  case FFOp::TAN: return append_dot_script_factor( os, "tan", true, 14 );
2694  case FFOp::ACOS: return append_dot_script_factor( os, "acos", true, 14 );
2695  case FFOp::ASIN: return append_dot_script_factor( os, "asin", true, 14 );
2696  case FFOp::ATAN: return append_dot_script_factor( os, "atan", true, 14 );
2697  case FFOp::ERF: return append_dot_script_factor( os, "erf", true, 14 );
2698  case FFOp::FSTEP: return append_dot_script_factor( os, "fstep", true, 14 );
2699  default: os << "/* a factor was not displayed */\n";
2700  }
2701  return;
2702 }
2703 
2704 inline void
2706 ( std::ostream&os, const std::string&fname, const bool unary,
2707  const unsigned int fontsize, const bool dotted ) const
2708 {
2709  std::ostringstream op_color; op_color << "black";
2710 
2711  os << " " << pres->name() << " [shape=record,fontname=\"Arial\",color="
2712  << op_color.str().c_str() << ",label=\"<f0> " << fname.c_str() << "|<f1> "
2713  << pres->name() << "\"];\n";
2714  //os << " \"" << plop->name() << "\":f0 -> \"" << pres->name() << "\":f0;\n";
2715  os << " " << plop->name() << " -> " << pres->name() << " [arrowsize=0.7];\n";
2716  if( unary ) return;
2717  os << " " << prop->name() << " -> " << pres->name() << " [arrowsize=0.7"
2718  << (dotted? ",style=dotted];\n": "];\n");
2719  //os << " \"" << prop->name() << "\":f0 -> \"" << pres->name() << "\":f0 "
2720  // << (dotted? "[style=dotted];\n": ";\n");
2721 }
2722 
2723 inline void
2725 ( std::ostream&os, const bool constant, const unsigned int fontsize ) const
2726 {
2727  std::ostringstream var_color; var_color << "red";
2728  std::ostringstream cst_color; cst_color << "blue";
2729 
2730  if( constant )
2731  os << " " << pres->name() << " [shape=record,fontname=\"Arial\",color="
2732  << cst_color.str().c_str() << ",label=\"<f0> " << pres->num() << "|<f1> "
2733  << pres->name() << "\"];\n";
2734  else
2735  os << " " << pres->name() << " [shape=ellipse,fontname=\"Arial\",color="
2736  << (var_color.str().c_str()) << "];\n";
2737  // << (var_color.str().c_str()) << ",label=\"<f0> " << pres->name() << "\"];\n";
2738 }
2739 
2740 inline bool
2742 () const
2743 {
2744  switch( type ){
2745  case FFOp::PLUS: case FFOp::MINUS: case FFOp::TIMES: case FFOp::DIV:
2746  case FFOp::MINF: case FFOp::MAXF:
2747  return false;
2748  case FFOp::NEG: case FFOp::SCALE: case FFOp::IPOW: case FFOp::EXP:
2749  case FFOp::LOG: case FFOp::FABS: case FFOp::SQR: case FFOp::SQRT:
2750  case FFOp::COS: case FFOp::SIN: case FFOp::TAN: case FFOp::ACOS:
2751  case FFOp::ASIN: case FFOp::ATAN: case FFOp::ERF: case FFOp::FSTEP:
2752  default:
2753  return true;
2754  }
2755 }
2756 
2758 
2759 inline std::ostream&
2760 operator <<
2761 ( std::ostream&out, const FFGraph&dag)
2762 {
2763  typename FFGraph::t_Vars Vars = dag._Vars;
2764  typename FFGraph::it_Vars itv = Vars.begin();
2765 
2766  out << ( dag._nvar? "\nDAG VARIABLES:\n": "\nNO DAG VARIABLES\n" );
2767  for( ; itv!=Vars.end() && (*itv)->_id.first<=FFVar::VAR; ++itv ){
2768  //out << " " << **itv << " (" << *itv << ")";
2769  out << " " << **itv;
2770  out << "\t => {";
2771  typename FFVar::t_Ops Ops = (*itv)->_ops.second;
2772  typename FFVar::t_Ops::iterator ito = Ops.begin();
2773  for( ; ito!=Ops.end(); ++ito ) out << " " << *(*ito)->pres;
2774  out << " }" << std::endl;
2775  }
2776 
2777  out << ( dag._naux? "\nDAG INTERMEDIATES:\n": "\nNO DAG INTERMEDIATES\n" );
2778  for( ; itv!=Vars.end(); ++itv ){
2779  //out << " " << **itv << " (" << *itv << ")";
2780  out << " " << **itv;
2781  if( (*itv)->_ops.first ) out << "\t" << "<= " << *((*itv)->_ops.first);
2782  out << "\t => {";
2783  typename FFVar::t_Ops Ops = (*itv)->_ops.second;
2784  typename FFVar::t_Ops::iterator ito = Ops.begin();
2785  for( ; ito!=Ops.end(); ++ito ) out << " " << *(*ito)->pres;
2786  out << " }" << std::endl;
2787  }
2788 
2789  return out;
2790 }
2791 
2792 inline FFVar&
2794 ( const typename FFOp::TYPE top, const FFDep&dep, const FFVar&Var1, const FFVar&Var2 )
2795 {
2796  if( Var1._dag != Var2._dag ) throw Exceptions( Exceptions::DAG );
2797  FFGraph *pdag = Var1._dag;
2798  FFVar *pVar1 = Var1._ops.first->pres, *pVar2 = Var2._ops.first->pres;
2799 
2800  FFOp *pOp = pdag->_insert_operation( top, pVar1, pVar2 );
2801  if( pOp->pres ) return *pOp->pres;
2802  pVar1->_ops.second.push_back( pOp );
2803  pVar2->_ops.second.push_back( pOp );
2804  pOp->pres = pdag->_add_auxiliary( dep, pOp );
2805  return *pOp->pres;
2806 }
2807 
2808 template <typename U> inline FFVar&
2810 ( const typename FFOp::TYPE top, const FFDep&dep, const U&Cst1, const FFVar&Var2 )
2811 {
2812  FFGraph *pdag = Var2._dag;
2813  FFVar *pVar2 = Var2._ops.first->pres;
2814  FFVar* pCst1 = pdag->_add_constant( Cst1 );
2815  FFVar *pVar1 = pCst1->_ops.first->pres;
2816 
2817  FFOp *pOp = pdag->_insert_operation( top, pVar1, pVar2 );
2818  if( pOp->pres ) return *pOp->pres;
2819  pVar1->_ops.second.push_back( pOp );
2820  pVar2->_ops.second.push_back( pOp );
2821  pOp->pres = pdag->_add_auxiliary( dep, pOp );
2822  return *pOp->pres;
2823 }
2824 
2825 template <typename U> inline FFVar&
2827 ( const typename FFOp::TYPE top, const FFDep&dep, const FFVar&Var1, const U&Cst2 )
2828 {
2829  FFGraph *pdag = Var1._dag;
2830  FFVar *pVar1 = Var1._ops.first->pres;
2831  FFVar* pCst2 = pdag->_add_constant( Cst2 );
2832  FFVar *pVar2 = pCst2->_ops.first->pres;
2833 
2834  FFOp *pOp = pdag->_insert_operation( top, pVar1, pVar2 );
2835  if( pOp->pres ) return *pOp->pres;
2836  pVar1->_ops.second.push_back( pOp );
2837  pVar2->_ops.second.push_back( pOp );
2838  pOp->pres = pdag->_add_auxiliary( dep, pOp );
2839  return *pOp->pres;
2840 }
2841 
2842 inline FFVar&
2844 ( const typename FFOp::TYPE top, const FFDep&dep, const FFVar&Var )
2845 {
2846  FFGraph* pdag = Var._dag;
2847  FFVar *pVar = Var._ops.first->pres;
2848 
2849  FFOp* pOp = pdag->_insert_operation( top, Var._ops.first->pres );
2850  if( pOp->pres ) return *pOp->pres;
2851  pVar->_ops.second.push_back( pOp );
2852  pOp->pres = pdag->_add_auxiliary( dep, pOp );
2853  return *pOp->pres;
2854 }
2855 
2856 inline FFOp*
2858 ( const typename FFOp::TYPE top, FFVar*lop, FFVar*rop )
2859 {
2860  FFOp* op = new FFOp( top, lop, rop );
2861  typename FFGraph::it_Ops itop = _Ops.find( op );
2862  if( itop!=_Ops.end() ){ delete op; return *itop; }
2863  _Ops.insert( op );
2864  return op;
2865 }
2866 
2867 inline bool
2869 ( FFOp* op )
2870 {
2871  typename FFGraph::it_Ops itop = _Ops.find( op );
2872  if( itop==_Ops.end() ) return false;
2873  delete op;
2874  _Ops.erase( itop );
2875  return true;
2876 }
2877 
2878 inline FFVar*
2880 ( const FFDep&dep, FFOp*pOp )
2881 {
2882  pOp->pres = new FFVar( this, dep, pOp );
2883  _append_aux( pOp->pres );
2884  return pOp->pres;
2885 }
2886 
2887 inline FFVar*
2889 ( const double x )
2890 {
2891  // Check if real constant x already defined in _Vars
2892  FFVar* pAux = new FFVar( x );
2893  it_Vars iAux = _Vars.find( pAux );
2894  if( iAux!=_Vars.end() ){ delete pAux; return *iAux; }
2895 
2896  // Otherwise, append constant x
2897  _append_aux( pAux, FFOp::CNST );
2898  return pAux;
2899 }
2900 
2901 inline FFVar*
2903 ( const int n )
2904 {
2905  // Check if real constant x already defined in _Vars
2906  FFVar* pAux = new FFVar( n );
2907  it_Vars iAux = _Vars.find( pAux );
2908  if( iAux!=_Vars.end() ){ delete pAux; return *iAux; }
2909 
2910  // Otherwise, append constant n
2911  _append_aux( pAux, FFOp::CNST );
2912  return pAux;
2913 }
2914 
2915 inline void
2917 ( FFVar*pAux, typename FFOp::TYPE tOp )
2918 {
2919  FFOp*pOp = new FFOp( tOp, 0, 0, pAux );
2920  _Ops.insert( pOp );
2921  pAux->dag() = this;
2922  pAux->ops().first = pOp;
2923  pAux->id().second = _naux++;
2924  _append_aux( pAux );
2925 }
2926 
2927 inline void
2929 ( FFVar*pAux )
2930 {
2931  _Vars.insert( pAux );
2932 }
2933 
2934 inline void
2936 ( FFVar*pVar )
2937 {
2938  _Vars.insert( pVar );
2939 }
2940 
2941 inline FFVar*
2943 ( const typename FFVar::pt_idVar&id )
2944 {
2945  FFVar* pVar = new FFVar( this, id );
2946  it_Vars iVar = _Vars.find( pVar );
2947  delete pVar;
2948  return( iVar==_Vars.end()? 0: *iVar );
2949 }
2950 
2951 inline std::list<const FFOp*>
2953 ( const unsigned int nDep, const FFVar*pDep ) const
2954 {
2955  std::list<const FFOp*> Ops;
2956  _reset_operations();
2957  for( unsigned int i=0; i<nDep; i++ ){
2958  if( !pDep[i].ops().first ) continue;
2959  pDep[i].ops().first->propagate_subgraph( Ops );
2960  }
2961  return Ops;
2962 }
2963 
2964 inline std::list<const FFOp*>
2966 ( const std::vector<const FFVar*>&vDep ) const
2967 {
2968  //return subgraph( vDep.size(), vDep.data() );
2969 
2970  std::list<const FFOp*> Ops;
2971  _reset_operations();
2972  typename std::vector<const FFVar*>::const_iterator it = vDep.begin();
2973  for( ; it!=vDep.end(); ++it ){
2974  if( !(*it)->ops().first ) continue;
2975  (*it)->ops().first->propagate_subgraph( Ops );
2976  }
2977  return Ops;
2978 }
2979 
2980 inline void
2982 ( const std::list<const FFOp*>&Ops, std::ostream&os )
2983 {
2984  os << ( !Ops.empty()? "\nFACTORS IN SUBGRAPH:\n": "\nNO FACTORS IN SUBGRAPH\n" );
2985  typename std::list<const FFOp*>::const_iterator ito = Ops.begin();
2986  for( ; ito!=Ops.end(); ++ito )
2987  os << " " << *(*ito)->pres << "\t" << "<= " << **ito << std::endl;
2988 }
2989 
2990 inline void
2992 ( const unsigned int nDep, const FFVar*pDep, std::ostream&os ) const
2993 {
2994  _reset_operations();
2995  os << "\ndigraph G {\n";
2996  for( unsigned int i=0; i<nDep; i++ ){
2997  if( !pDep[i].ops().first ) continue;
2998  pDep[i].ops().first->generate_dot_script( os );
2999  }
3000  os << "}\n";
3001 }
3002 
3003 inline void
3005 ( const std::vector<const FFVar*>&vDep, std::ostream&os ) const
3006 {
3007  //dot_script( vDep.size(), *vDep.data(), os )
3008 
3009  _reset_operations();
3010  os << "\ndigraph G {\nnode [shape=record];\n";
3011  typename std::vector<const FFVar*>::const_iterator it = vDep.begin();
3012  for( ; it!=vDep.end(); ++it ){
3013  if( !(*it)->ops().first ) continue;
3014  (*it)->ops().first->generate_dot_script( os );
3015  }
3016  os << "}\n";
3017 }
3018 
3019 inline const FFVar*
3021 ( const unsigned nDep, const FFVar* const pDep, const unsigned nIndep,
3022  const FFVar* const pIndep, const bool transp )
3023 {
3024  if( !nDep || !nIndep ) return 0; // Nothing to do!
3025  assert( pDep && pIndep );
3026 
3027  std::vector<const FFVar*> vDep, vIndep;
3028  for( unsigned i=0; i<nDep; i++ ) vDep.push_back( pDep+i );
3029  for( unsigned i=0; i<nIndep; i++ ) vIndep.push_back( pIndep+i );
3030 
3031  std::vector<const FFVar*> vDep_F = FAD( vDep, vIndep );
3032  FFVar* pDep_F = new FFVar[ vDep_F.size() ];
3033  typename std::vector<const FFVar*>::const_iterator it = vDep_F.begin();
3034  if( !transp )
3035  for( unsigned k=0; it!=vDep_F.end(); ++it, k++ ) pDep_F[k] = **it;
3036  else
3037  for( unsigned i=0; it!=vDep_F.end(); i++ )
3038  for( unsigned j=0; j<nIndep; ++it, j++ ) pDep_F[i+j*nDep] = **it;
3039 
3040  return pDep_F;
3041 }
3042 
3043 inline std::vector<const FFVar*>
3045 ( const std::vector<const FFVar*>&vDep, const std::vector<const FFVar*>&vIndep )
3046 {
3047  // Nothing to do!
3048  if( !vIndep.size() || !vDep.size() ) return std::vector<const FFVar*>();
3049  //fadbad::F<mc::FFVar> FFVar_dum();
3050 
3051  // Initialize of all independent variables participating in the dependent ones
3052  it_Vars itv = _Vars.begin();
3053  for( ; itv!=_Vars.end() && (*itv)->_id.first<=FFVar::VAR; ++itv ){
3054  fadbad::F<mc::FFVar>* pX_F = new fadbad::F<mc::FFVar>( **itv );
3055  typename std::vector<const FFVar*>::const_iterator iti = vIndep.begin();
3056  for( unsigned int i=0; iti!=vIndep.end(); ++iti, i++ )
3057  if( (*itv)->id().second == (*iti)->id().second )
3058  pX_F->diff( i, vIndep.size() );
3059  // Attach fadbad::F<mc::FFVar>* variable to corresponding variable in _Vars
3060  (*itv)->val() = pX_F;
3061  }
3062  // THIS IS DOING A BIT TOO MUCH WORK AS ONLY THE INDEPENDENT VARIABLES
3063  // PARTICIPATING IN THE DEPENDENTS SHOULD BE TAKEN INTO ACCOUNT REALLY
3064  // (E.G., THIS COULD BE DONE USING THE .dep() FIELD IN THE DEPENDENTS)
3065 
3066  // Evaluate dependents given by vDep in fadbad::F type
3067  std::list<const FFOp*> opDep = subgraph( vDep );
3068  typename std::list<const FFOp*>::iterator ito = opDep.begin();
3069  for( ; ito!=opDep.end(); ++ito ) (*ito)->evaluate( fadbad::F<mc::FFVar>() );
3070 
3071  // Retreive dependents variables in fadbad::F as given by vDep
3072  std::vector<const FFVar*> vDep_F; // <- vector holding the results
3073  typename std::vector<const FFVar*>::const_iterator itd = vDep.begin();
3074  for( ; itd!=vDep.end(); ++itd ){
3075  // Obtain pointer to dependent variable in FFGraph
3076  FFVar* pF = _find_var( (*itd)->id() );
3077  typename std::vector<const FFVar*>::const_iterator iti = vIndep.begin();
3078  // Push corresponding evaluation in fadbad::F into result vector
3079  for( unsigned int i=0; iti!=vIndep.end(); ++iti, i++ ){
3080  if( !pF ){
3081  vDep_F.push_back( _add_constant( 0. ) ); continue;
3082  }
3083  // THE FOLLOWING MATCHING IS NECESSARY BECAUSE THE VARIABLES CREATED
3084  // BY FFOp::evaluate ARE NOT THE SAME AS THOSE STORED IN FFGraph
3085  fadbad::F<mc::FFVar>* pF_F = static_cast<fadbad::F<mc::FFVar>*>( pF->val() );
3086  const FFVar* pdFdX = _find_var( pF_F->deriv(i).id() );
3087  if( !pdFdX ){
3088  const FFNum& num = pF_F->deriv(i).num();
3089  switch( num.t ){
3090  case FFNum::INT: vDep_F.push_back( _add_constant( num.n ) ); continue;
3091  case FFNum::REAL: vDep_F.push_back( _add_constant( num.x ) ); continue;
3092  }
3093  }
3094  else vDep_F.push_back( pdFdX );
3095  }
3096  }
3097 
3098  // Reset mc::FFVAR_val field to NULL
3099  itv = _Vars.begin();
3100  for( ; itv!=_Vars.end() && (*itv)->_id.first<=FFVar::VAR; ++itv )
3101  (*itv)->reset_val( fadbad::F<mc::FFVar>() );
3102 
3103  _reset_operations();
3104  itd = vDep.begin();
3105  for( ; itd!=vDep.end(); ++itd ){
3106  if( !(*itd)->ops().first ) continue;
3107  (*itd)->ops().first->reset_val_subgraph( fadbad::F<mc::FFVar>() );
3108  }
3109 
3110  return vDep_F;
3111 }
3112 
3113 inline const FFVar*
3115 ( const unsigned nDep, const FFVar* const pDep, const unsigned nIndep,
3116  const FFVar* const pIndep, const bool transp )
3117 {
3118  if( !nDep || !nIndep ) return 0; // Nothing to do!
3119  assert( pDep && pIndep );
3120 
3121  std::vector<const FFVar*> vDep, vIndep;
3122  for( unsigned i=0; i<nDep; i++ ) vDep.push_back( pDep+i );
3123  for( unsigned i=0; i<nIndep; i++ ) vIndep.push_back( pIndep+i );
3124 
3125  std::vector<const FFVar*> vDep_B = BAD( vDep, vIndep );
3126  FFVar* pDep_B = new FFVar[ vDep_B.size() ];
3127  typename std::vector<const FFVar*>::const_iterator it = vDep_B.begin();
3128  if( !transp )
3129  for( unsigned k=0; it!=vDep_B.end(); ++it, k++ ) pDep_B[k] = **it;
3130  else
3131  for( unsigned i=0; it!=vDep_B.end(); i++ )
3132  for( unsigned j=0; j<nIndep; ++it, j++ ) pDep_B[i+j*nDep] = **it;
3133 
3134  return pDep_B;
3135 }
3136 
3137 inline std::vector<const FFVar*>
3139 ( const std::vector<const FFVar*>&vDep, const std::vector<const FFVar*>&vIndep )
3140 {
3141  // Nothing to do!
3142  if( !vIndep.size() || !vDep.size() ) return std::vector<const FFVar*>();
3143  //fadbad::B<mc::FFVar> FFVar_dum();
3144 
3145  // Initialize of all independent variables participating in the dependent ones
3146  it_Vars itv = _Vars.begin();
3147  for( ; itv!=_Vars.end() && (*itv)->_id.first<=FFVar::VAR; ++itv ){
3148  fadbad::B<mc::FFVar>* pX_B = new fadbad::B<mc::FFVar>( **itv );
3149  // Attach fadbad::B<mc::FFVar>* variable to corresponding variable in _Vars
3150  (*itv)->val() = pX_B;
3151  //std::cout << "*itv: " << *itv << " pX_B: " << pX_B << std::endl;
3152  }
3153  // THIS IS DOING A BIT TOO MUCH WORK AS ONLY THE INDEPENDENT VARIABLES
3154  // PARTICIPATING IN THE DEPENDENTS SHOULD BE TAKEN INTO ACCOUNT REALLY
3155  // (E.G., THIS COULD BE DONE USING THE .dep() FIELD IN THE DEPENDENTS)
3156 
3157  // Propagate dependents given by vDep in fadbad::B type
3158  std::list<const FFOp*> opDep = subgraph( vDep );
3159  typename std::list<const FFOp*>::iterator ito = opDep.begin();
3160  for( ; ito!=opDep.end(); ++ito ) (*ito)->evaluate( fadbad::B<mc::FFVar>() );
3161 
3162  // Erase pointers to intermediate so they go out of scope
3163  // OTHERWISE BADIFF COMPLAINS
3164  _reset_operations();
3165  typename std::vector<const FFVar*>::const_iterator itd = vDep.begin();
3166  for( ; itd!=vDep.end(); ++itd ){
3167  if( !(*itd)->ops().first ) continue;
3168  (*itd)->ops().first->reset_val_subgraph( fadbad::B<mc::FFVar>(), vDep, vIndep );
3169  }
3170 
3171  // Propagate derivatives of dependents using fadbad::B
3172  itd = vDep.begin();
3173  for( unsigned j=0; itd!=vDep.end(); ++itd, j++ ){
3174  // Obtain pointer to dependent variable in FFGraph
3175  FFVar* pF = _find_var( (*itd)->id() );
3176  //std::cout << "pF: " << pF;
3177  if( !pF ) continue;
3178  fadbad::B<mc::FFVar>* pF_B = static_cast<fadbad::B<mc::FFVar>*>( pF->val() );
3179  pF_B->diff( j, vDep.size() );
3180  //std::cout << " pF_B: " << pF_B << std::endl;
3181  }
3182 
3183  // Retreive dependents variables in fadbad::B as given by vDep
3184  std::vector<const FFVar*> vDep_B; // <- vector holding the results
3185  itd = vDep.begin();
3186  for( unsigned j=0; itd!=vDep.end(); ++itd, j++ ){
3187  // Obtain pointer to dependent variable in FFGraph
3188  FFVar* pF = _find_var( (*itd)->id() );
3189  typename std::vector<const FFVar*>::const_iterator iti = vIndep.begin();
3190  // Push corresponding evaluation in fadbad::F into result vector
3191  for( ; iti!=vIndep.end(); ++iti ){
3192  if( !pF ){
3193  vDep_B.push_back( _add_constant( 0. ) ); std::cout << "here: 1!\n\n\n"; continue;
3194  }
3195  // Obtain pointer to independent variable in FFGraph
3196  FFVar* pX = _find_var( (*iti)->id() );
3197  // THE FOLLOWING MATCHING IS NECESSARY BECAUSE THE VARIABLES CREATED
3198  // BY FFOp::evaluate ARE NOT THE SAME AS THOSE STORED IN FFGraph
3199  fadbad::B<mc::FFVar>* pX_B = static_cast<fadbad::B<mc::FFVar>*>( pX->val() );
3200  FFVar* dXj = &pX_B->d(j);
3201  const FFVar* pdFdX = _find_var( dXj->id() );
3202  //std::cout << "pX: " << pX << " pX_B: " << pX_B << std::endl;
3203  //std::cout << "dXj: " << *dXj << " (" << dXj << ")" << std::endl;
3204  if( !pdFdX ){
3205  switch( dXj->num().t ){
3206  case FFNum::INT: vDep_B.push_back( _add_constant( dXj->num().n ) ); continue;
3207  case FFNum::REAL: vDep_B.push_back( _add_constant( dXj->num().x ) ); continue;
3208  }
3209  }
3210  else vDep_B.push_back( pdFdX );
3211  }
3212  }
3213 
3214  // Reset mc::FFVAR::_val field to NULL in dependent and independent variables
3215  itv = _Vars.begin();
3216  for( ; itv!=_Vars.end() && (*itv)->_id.first<=FFVar::VAR; ++itv )
3217  (*itv)->reset_val( fadbad::B<mc::FFVar>() );
3218 
3219  itd = vDep.begin();
3220  for( ; itd!=vDep.end(); ++itd )
3221  _find_var( (*itd)->id() )->reset_val( fadbad::B<mc::FFVar>() );
3222 
3223  return vDep_B;
3224 }
3225 
3226 inline const FFVar*
3228 ( const unsigned int ordermax, const unsigned nDep, const FFVar* const pDep,
3229  const unsigned nVar, const FFVar* const pVar, const FFVar* const pIndep )
3230 {
3231  if( !nDep || !nVar ) return 0; // Nothing to do!
3232  assert( pDep && pVar );
3233 
3234  std::vector<const FFVar*> vDep, vVar;
3235  for( unsigned i=0; i<nDep; i++ ) vDep.push_back( pDep+i );
3236  for( unsigned i=0; i<nVar; i++ ) vVar.push_back( pVar+i );
3237 
3238  std::vector<const FFVar*> vDep_T = TAD( ordermax, vDep, vVar, pIndep );
3239  FFVar* pDep_T = new FFVar[ vDep_T.size() ];
3240  typename std::vector<const FFVar*>::const_iterator it = vDep_T.begin();
3241  for( unsigned k=0; it!=vDep_T.end(); ++it, k++ ) pDep_T[k] = **it;
3242 
3243  return pDep_T;
3244 }
3245 
3246 inline std::vector<const FFVar*>
3248 ( const unsigned int ordermax, const std::vector<const FFVar*>&vDep,
3249  const std::vector<const FFVar*>&vVar, const FFVar* const pIndep )
3250 {
3251  // Check dependent and independent vector sizes
3252  if( !vVar.size() || !vDep.size() || vVar.size() != vDep.size() )
3253  return std::vector<const FFVar*>();
3254  //fadbad::T<mc::FFVar> FFVar_dum();
3255  std::vector<const FFVar*> vDep_T; // <- vector holding the results
3256 
3257  // Initialize of all independent variables participating in the dependent ones
3258  fadbad::T<mc::FFVar>** pX_T = new fadbad::T<mc::FFVar>*[ vVar.size() ];
3259  it_Vars itv = _Vars.begin();
3260  for( ; itv!=_Vars.end() && (*itv)->_id.first<=FFVar::VAR; ++itv ){
3261  fadbad::T<mc::FFVar>* pXi_T = new fadbad::T<mc::FFVar>( **itv );
3262  typename std::vector<const FFVar*>::const_iterator iti = vVar.begin();
3263  // Time
3264  if( pIndep && (*itv)->id().second == pIndep->id().second )
3265  (*pXi_T)[1] = 1.;
3266  // Time-dependents
3267  for( unsigned int i=0; iti!=vVar.end(); ++iti, i++ ){
3268  if( (*itv)->id().second == (*iti)->id().second ){
3269  pX_T[i] = pXi_T;
3270  vDep_T.push_back( *itv ); // <- Append 0th-order Taylor coefficient of ith-dependent to result vector
3271 #ifdef MC__FFUNC_DEBUG_TAD
3272  std::cout << "FFGraph::TAD *** f(" << i << ")[0] = "
3273  << **itv << " (" << *itv << ")\n";
3274 #endif
3275  }
3276  }
3277  // Attach fadbad::F<mc::FFVar>* variable to corresponding variable in _Vars
3278  (*itv)->val() = pXi_T;
3279  }
3280  // THIS IS DOING A BIT TOO MUCH WORK AS ONLY THE INDEPENDENT VARIABLES
3281  // PARTICIPATING IN THE DEPENDENTS SHOULD BE TAKEN INTO ACCOUNT REALLY
3282  // (E.G., THIS COULD BE DONE USING THE .dep() FIELD IN THE DEPENDENTS)
3283 
3284  // Evaluate dependents given by vDep in fadbad::T type
3285  std::list<const FFOp*> opDep = subgraph( vDep );
3286  typename std::list<const FFOp*>::iterator ito = opDep.begin();
3287  for( ; ito!=opDep.end(); ++ito ) (*ito)->evaluate( fadbad::T<mc::FFVar>() );
3288 
3289  // Set pointers to the dependents
3290  fadbad::T<mc::FFVar>** pF_T = new fadbad::T<mc::FFVar>*[ vDep.size() ];
3291  typename std::vector<const FFVar*>::const_iterator itd = vDep.begin();
3292  for( unsigned j=0; itd!=vDep.end(); ++itd, j++ ){
3293  FFVar*pF = _find_var( (*itd)->id() );
3294  pF_T[j] = ( pF? static_cast<fadbad::T<mc::FFVar>*>( pF->val() ): 0 );
3295  }
3296 
3297  // Evaluate Taylor coefficients recursively
3298  for( unsigned int q=0; q<ordermax; q++ ){
3299  itd = vDep.begin();
3300  for( unsigned j=0; itd!=vDep.end(); ++itd, j++ ){
3301  // Case dependent is not a variable
3302  if( !pF_T[j] ){
3303  vDep_T.push_back( _add_constant( 0. ) ); continue;
3304  }
3305  // Evaluate qth-order Taylor coefficient for jth dependent
3306  pF_T[j]->eval(q);
3307  // Set result as (q+1)-th Taylor coefficient for x[i]
3308  mc::FFVar Xjq = (*pF_T[j])[q]/double(q+1);
3309  //mc::FFVar& Xjq = (*pF_T[j])[q];
3310  FFVar*pXjq = _find_var( Xjq.id() );
3311  if( !pXjq ) switch( Xjq.num().t ){
3312  case FFNum::INT:
3313  (*pX_T[j])[q+1] = Xjq.num().n;
3314  vDep_T.push_back( _add_constant( Xjq.num().n ) );
3315  break;
3316  case FFNum::REAL:
3317  (*pX_T[j])[q+1] = Xjq.num().x;
3318  vDep_T.push_back( _add_constant( Xjq.num().x ) );
3319  break;
3320  }
3321  else{
3322  (*pX_T[j])[q+1] = *pXjq;
3323  vDep_T.push_back( pXjq ); // <- Append (q+1)th-order Taylor coefficient of jth-dependent to result vector
3324  }
3325 #ifdef MC__FFUNC_DEBUG_TAD
3326  std::cout << "FFGraph::TAD *** f(" << j << ")[" << q+1 << "] = "
3327  << *pXjq << " (" << pXjq << ")\n";
3328 #endif
3329  }
3330  }
3331 
3332  // Reset mc::FFVAR_val field to NULL
3333  itv = _Vars.begin();
3334  for( ; itv!=_Vars.end() && (*itv)->_id.first<=FFVar::VAR; ++itv )
3335  (*itv)->reset_val( fadbad::T<mc::FFVar>() );
3336 
3337  _reset_operations();
3338  itd = vDep.begin();
3339  for( ; itd!=vDep.end(); ++itd ){
3340  if( !(*itd)->ops().first ) continue;
3341  (*itd)->ops().first->reset_val_subgraph( fadbad::T<mc::FFVar>() );
3342  }
3343 
3344  delete[] pX_T;
3345  delete[] pF_T;
3346 
3347  return vDep_T;
3348 }
3349 
3350 inline const FFVar*
3352 ( const unsigned nDepOut, const FFVar*pDepOut, const unsigned nDepIn,
3353  const FFVar*pVarOut, const FFVar*pDepIn )
3354 {
3355  if( !nDepOut || !nDepIn ) return pDepOut; // Nothing to do!
3356  assert( pDepOut && pVarOut && pDepIn );
3357 
3358  std::vector<const FFVar*> vDepOut;
3359  std::vector< std::pair<const FFVar*,const FFVar*> > vDepIn;
3360  for( unsigned i=0; i<nDepOut; i++ ) vDepOut.push_back( pDepOut+i );
3361  for( unsigned i=0; i<nDepIn; i++ ) vDepIn.push_back( std::make_pair(pVarOut+i,pDepIn+i) );
3362 
3363  std::vector<const FFVar*> vDepComp = compose( vDepOut, vDepIn );
3364 
3365  FFVar* pDepComp = new FFVar[ vDepComp.size() ];
3366  typename std::vector<const FFVar*>::const_iterator it = vDepComp.begin();
3367  for( unsigned k=0; it!=vDepComp.end(); ++it, k++ ) pDepComp[k] = **it;
3368 
3369  return pDepComp;
3370 }
3371 
3372 inline std::vector<const FFVar*>
3374 ( const std::vector<const FFVar*>&vDepOut,
3375  const std::vector< std::pair<const FFVar*,const FFVar*> >&vDepIn )
3376 {
3377  // Nothing to do!
3378  if( !vDepIn.size() || !vDepOut.size() ) return vDepOut;
3379 
3380  // Initialize of all independent variables participating in the dependent ones
3381  std::vector< std::pair<const FFVar*,FFVar> > vIndep;
3382  it_Vars itv = _Vars.begin();
3383  for( ; itv!=_Vars.end() && (*itv)->_id.first<=FFVar::VAR; ++itv ){
3384  typename std::vector< std::pair<const FFVar*,const FFVar*> >::const_iterator iti = vDepIn.begin();
3385  bool match = false;
3386  // Pair with corresponding dependent if matching
3387  for( ; !match && iti!=vDepIn.end(); ++iti )
3388  if( (*itv)->id().second == (*iti).first->id().second ){
3389  FFVar DepIn = *(*iti).second; // to avoid constness issue
3390  vIndep.push_back( std::make_pair( (*iti).first, DepIn ) ); //_find_var( (*iti).second->id() );
3391 #ifdef MC__FFUNC_DEBUG_COMPOSE
3392  std::cout << *(*iti).first << " <-> " << DepIn << std::endl;
3393 #endif
3394  match = true;
3395  }
3396  // Pair with itself otherwise
3397  if( !match ){
3398  vIndep.push_back( std::make_pair( *itv, **itv ) );
3399 #ifdef MC__FFUNC_DEBUG_COMPOSE
3400  std::cout << **itv << " <-> " << **itv << std::endl;
3401 #endif
3402  }
3403  }
3404 
3405  std::vector<FFVar> vDepComp = eval( vDepOut, vIndep );
3406  std::vector<const FFVar*> vDepNew;
3407  typename std::vector<FFVar>::iterator itd = vDepComp.begin();
3408  for( ; itd!=vDepComp.end(); ++itd ){
3409  FFVar* pF = _find_var( (*itd).id() );
3410  if( !pF ){
3411  const FFNum& num = (*itd).num();
3412  switch( num.t ){
3413  case FFNum::INT: vDepNew.push_back( _add_constant( num.n ) ); continue;
3414  case FFNum::REAL: vDepNew.push_back( _add_constant( num.x ) ); continue;
3415  }
3416  }
3417  else vDepNew.push_back( pF );
3418  }
3419  return vDepNew;
3420 }
3421 
3422 template <typename U> inline std::vector<U>
3424 ( const std::vector<const FFVar*>&vDep,
3425  const std::vector< std::pair<const FFVar*,U> >&vVar )
3426 {
3427  // Nothing to do!
3428  if( !vDep.size() ) return std::vector<U>();
3429 
3430  // Generate subgraph -- This can be the most time consuming step!!!
3431  std::list<const FFOp*> opDep = subgraph( vDep );
3432 
3433  return eval( opDep, vDep, vVar );
3434 }
3435 
3436 template <typename U> inline std::vector<U>
3438 ( std::list<const FFOp*>&opDep, const std::vector<const FFVar*>&vDep,
3439  const std::vector< std::pair<const FFVar*,U> >&vVar )
3440 {
3441  // Nothing to do!
3442  if( !vDep.size() ) return std::vector<U>();
3443 #ifdef MC__FFUNC_CPU_EVAL
3444  double cputime;
3445 #endif
3446 
3447  // Initialize all independent variables participating in the dependent ones
3448 #ifdef MC__FFUNC_CPU_EVAL
3449  cputime = -cpuclock();
3450 #endif
3451  typename std::vector< std::pair<const FFVar*,U> >::const_iterator iti = vVar.begin();
3452  for( ; iti!=vVar.end(); ++iti ){
3453  FFVar* pF = _find_var( (*iti).first->id() );
3454  if( pF ){
3455  pF->val() = new U( (*iti).second ); //const_cast<U*>( &(*iti).second );
3456 #ifdef MC__FFUNC_DEBUG_EVAL
3457  std::cout << (*iti).first << " " << (*iti).second << std::endl;
3458 #endif
3459  }
3460  }
3461 #ifdef MC__FFUNC_CPU_EVAL
3462  cputime += cpuclock();
3463  std::cout << "\nIndep. init. time: " << std::fixed << cputime << std::endl;
3464 #endif
3465  // THIS IS DOING A BIT TOO MUCH WORK AS ONLY THE INDEPENDENT VARIABLES
3466  // PARTICIPATING IN THE DEPENDENTS SHOULD BE TAKEN INTO ACCOUNT STRICTLY
3467  // (E.G., THIS COULD BE DONE USING THE .dep() FIELD IN THE DEPENDENTS)
3468 
3469  std::vector<U> vDep_U; // <- vector holding the results
3470  bool rethrow = false;
3471  try{
3472 #ifdef MC__FFUNC_CPU_EVAL
3473  cputime = -cpuclock();
3474 #endif
3475  // Evaluate dependents given by vDep in U type
3476  typename std::list<const FFOp*>::iterator ito = opDep.begin();
3477  for( ; ito!=opDep.end(); ++ito ) (*ito)->evaluate( U() );
3478 #ifdef MC__FFUNC_CPU_EVAL
3479  cputime += cpuclock();
3480  std::cout << "Evaluation time: " << std::fixed << cputime << std::endl;
3481 #endif
3482 
3483  // Retreive dependents variables in U type as given by vDep
3484 #ifdef MC__FFUNC_CPU_EVAL
3485  cputime = -cpuclock();
3486 #endif
3487  typename std::vector<const FFVar*>::const_iterator itd = vDep.begin();
3488  for( ; itd!=vDep.end(); ++itd ){
3489  // Obtain pointer to dependent variable in FFGraph
3490  FFVar* pF = _find_var( (*itd)->id() );
3491  // Push corresponding evaluation in U type into result vector
3492  if( pF ) vDep_U.push_back( U( *static_cast<U*>( pF->val() ) ) );
3493  else switch( (*itd)->num().t ){
3494  case FFNum::INT:
3495  vDep_U.push_back( (*itd)->num().n );
3496  break;
3497  case FFNum::REAL:
3498  vDep_U.push_back( (*itd)->num().x );
3499  break;
3500  }
3501  }
3502 #ifdef MC__FFUNC_CPU_EVAL
3503  cputime += cpuclock();
3504  std::cout << "Dep. collect. time: " << std::fixed << cputime << std::endl;
3505 #endif
3506  }
3507  catch(...){
3508  rethrow = true;
3509  }
3510 
3511  // Reset mc::FFVAR_val field to NULL
3512 #ifdef MC__FFUNC_CPU_EVAL
3513  cputime = -cpuclock();
3514 #endif
3515  iti = vVar.begin();
3516  for( ; iti!=vVar.end(); ++iti ){
3517  FFVar* pF = _find_var( (*iti).first->id() );
3518  if( pF ) pF->reset_val( U() );
3519  }
3520  //it_Vars itv = _Vars.begin();
3521  //for( ; itv!=_Vars.end() && (*itv)->_id.first<=FFVar::VAR; ++itv )
3522  // (*itv)->reset_val( U() );
3523 
3524  typename std::list<const FFOp*>::iterator ito = opDep.begin();
3525  for( ; ito!=opDep.end(); ++ito ) (*ito)->flag( false );
3526  typename std::vector<const FFVar*>::const_iterator itd = vDep.begin();
3527  for( ; itd!=vDep.end(); ++itd ){
3528  if( !(*itd)->ops().first ) continue;
3529  (*itd)->ops().first->reset_val_subgraph( U() );
3530  }
3531 #ifdef MC__FFUNC_CPU_EVAL
3532  cputime += cpuclock();
3533  std::cout << "Clean-up time: " << std::fixed << cputime << std::endl;
3534 #endif
3535 
3536  if( rethrow ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::EVAL );
3537  return vDep_U;
3538 }
3539 
3540 template <typename U> inline std::vector<U>
3542 ( std::list<const FFOp*>&opDep, U*opRes, const std::vector<const FFVar*>&vDep,
3543  const std::vector< std::pair<const FFVar*,U> >&vVar )
3544 {
3545  // Nothing to do!
3546  if( !vDep.size() ) return std::vector<U>();
3547  assert( opDep.size() && opRes );
3548 
3549  // Propagate values in U arithmetic through subgraph
3550 #ifdef MC__FFUNC_CPU_EVAL
3551  double cputime = -cpuclock();
3552 #endif
3553  typename std::list<const FFOp*>::iterator ito = opDep.begin();
3554  for( U*pUres=opRes; ito!=opDep.end(); ++ito, pUres++ ){
3555  // Initialize variable using values in vVar
3556  if( (*ito)->type == FFOp::VAR ){
3557  FFVar* pF = 0;
3558  typename std::vector< std::pair<const FFVar*,U> >::const_iterator iti = vVar.begin();
3559  for( ; iti!=vVar.end(); ++iti ){
3560  if( (*ito)->pres->id() == (*iti).first->id() ){
3561  pF = (*ito)->pres; //_find_var( (*iti).first->id() );
3562  *pUres = (*iti).second;
3563  break;
3564  }
3565  }
3566  if( !pF ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::MISSVAR );
3567  }
3568  (*ito)->evaluate( pUres );
3569  }
3570 #ifdef MC__FFUNC_CPU_EVAL
3571  cputime += cpuclock();
3572  std::cout << "\nEvaluation time: " << std::fixed << cputime << std::endl;
3573 #endif
3574 
3575  // Retreive dependents variables in U type as given by vDep
3576 #ifdef MC__FFUNC_CPU_EVAL
3577  cputime = -cpuclock();
3578 #endif
3579  std::vector<U> vDep_U; // <- vector holding the results
3580  typename std::vector<const FFVar*>::const_iterator itd = vDep.begin();
3581  for( ; itd!=vDep.end(); ++itd ){
3582  // Obtain pointer to dependent variable in FFGraph
3583  FFVar* pF = _find_var( (*itd)->id() );
3584  // Push corresponding evaluation in U type into result vector
3585  if( pF ) vDep_U.push_back( U( *static_cast<U*>( pF->val() ) ) );
3586  else switch( (*itd)->num().t ){
3587  case FFNum::INT:
3588  vDep_U.push_back( (*itd)->num().n );
3589  break;
3590  case FFNum::REAL:
3591  vDep_U.push_back( (*itd)->num().x );
3592  break;
3593  }
3594  }
3595 #ifdef MC__FFUNC_CPU_EVAL
3596  cputime += cpuclock();
3597  std::cout << "Dep. collect. time: " << std::fixed << cputime << std::endl;
3598 #endif
3599 
3600  return vDep_U;
3601 }
3602 
3603 template <typename U> inline void
3605 ( const unsigned nDep, const FFVar*pDep, U*vDep, const unsigned nVar,
3606  const FFVar*pVar, U*vVar, const bool add )
3607 {
3608  // Nothing to do!
3609  if( !nDep ) return;
3610 
3611  // Generate subgraph -- This can be the most time consuming step!!!
3612  std::list<const FFOp*> opDep = subgraph( nDep, pDep );
3613 
3614  return eval( opDep, nDep, pDep, vDep, nVar, pVar, vVar, add );
3615 }
3616 
3617 template <typename U> inline void
3619 ( std::list<const FFOp*>&opDep, const unsigned nDep, const FFVar*pDep,
3620  U*vDep, const unsigned nVar, const FFVar*pVar, U*vVar, const bool add )
3621 {
3622  // Nothing to do!
3623  if( !nDep ) return;
3624  assert( pDep && vDep );
3625  assert( !nVar || ( pVar && vVar ) );
3626 #ifdef MC__FFUNC_CPU_EVAL
3627  double cputime;
3628 #endif
3629 
3630  // Initialize all independent variables participating in the dependent ones
3631 #ifdef MC__FFUNC_CPU_EVAL
3632  cputime = -cpuclock();
3633 #endif
3634  for( unsigned int i=0; i<nVar; i++ ){
3635  FFVar* pF = _find_var( pVar[i].id() );
3636  if( pF ){
3637  pF->val() = new U( vVar[i] );
3638 #ifdef MC__FFUNC_DEBUG_EVAL
3639  std::cout << pVar[i] << " " << vVar[i] << std::endl;
3640 #endif
3641  }
3642  }
3643 #ifdef MC__FFUNC_CPU_EVAL
3644  cputime += cpuclock();
3645  std::cout << "\nIndep. init. time: " << std::fixed << cputime << std::endl;
3646 #endif
3647  // THIS IS DOING A BIT TOO MUCH WORK AS ONLY THE INDEPENDENT VARIABLES
3648  // PARTICIPATING IN THE DEPENDENTS SHOULD BE TAKEN INTO ACCOUNT STRICTLY
3649  // (E.G., THIS COULD BE DONE USING THE .dep() FIELD IN THE DEPENDENTS)
3650 
3651  bool rethrow = false;
3652  try{
3653 #ifdef MC__FFUNC_CPU_EVAL
3654  cputime = -cpuclock();
3655 #endif
3656  // Evaluate dependents given by vDep in U type
3657  typename std::list<const FFOp*>::iterator ito = opDep.begin();
3658  for( ; ito!=opDep.end(); ++ito ) (*ito)->evaluate( U() );
3659 #ifdef MC__FFUNC_CPU_EVAL
3660  cputime += cpuclock();
3661  std::cout << "Evaluation time: " << std::fixed << cputime << std::endl;
3662 #endif
3663 
3664  // Retreive dependents variables in U type as given by vDep
3665 #ifdef MC__FFUNC_CPU_EVAL
3666  cputime = -cpuclock();
3667 #endif
3668  for( unsigned i=0; i<nDep; i++ ){
3669  // Obtain pointer to dependent variable in FFGraph
3670  FFVar* pF = _find_var( pDep[i].id() );
3671  // Write/add corresponding evaluation in U type into/to result vector
3672  if( !add && pF ) vDep[i] = *static_cast<U*>( pF->val() );
3673  else if( pF ) vDep[i] += *static_cast<U*>( pF->val() );
3674  else if( !add ) switch( pDep[i].num().t ){
3675  case FFNum::INT:
3676  vDep[i] = pDep[i].num().n;
3677  break;
3678  case FFNum::REAL:
3679  vDep[i] = pDep[i].num().x;
3680  break;
3681  }
3682  else switch( pDep[i].num().t ){
3683  case FFNum::INT:
3684  vDep[i] += pDep[i].num().n;
3685  break;
3686  case FFNum::REAL:
3687  vDep[i] += pDep[i].num().x;
3688  break;
3689  }
3690  }
3691 #ifdef MC__FFUNC_CPU_EVAL
3692  cputime += cpuclock();
3693  std::cout << "Dep. collect. time: " << std::fixed << cputime << std::endl;
3694 #endif
3695  }
3696  catch(...){
3697  rethrow = true;
3698  }
3699 
3700  // Reset mc::FFVAR_val field to NULL
3701 #ifdef MC__FFUNC_CPU_EVAL
3702  cputime = -cpuclock();
3703 #endif
3704  for( unsigned int i=0; i<nVar; i++ ){
3705  FFVar* pF = _find_var( pVar[i].id() );
3706  if( pF ) pF->reset_val( U() );
3707  }
3708  //it_Vars itv = _Vars.begin();
3709  //for( ; itv!=_Vars.end() && (*itv)->_id.first<=FFVar::VAR; ++itv )
3710  // (*itv)->reset_val( U() );
3711 
3712  typename std::list<const FFOp*>::iterator ito = opDep.begin();
3713  for( ; ito!=opDep.end(); ++ito ) (*ito)->flag( false );
3714  for( unsigned i=0; i<nDep; i++ ){
3715  if( !pDep[i].ops().first ) continue;
3716  pDep[i].ops().first->reset_val_subgraph( U() );
3717  }
3718 #ifdef MC__FFUNC_CPU_EVAL
3719  cputime += cpuclock();
3720  std::cout << "Clean-up time: " << std::fixed << cputime << std::endl;
3721 #endif
3722 
3723  if( rethrow ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::EVAL );
3724  return;
3725 }
3726 
3727 template <typename U> inline void
3729 ( std::list<const FFOp*>&opDep, U*opRes, const unsigned nDep, const FFVar*pDep,
3730  U*vDep, const unsigned nVar, const FFVar*pVar, U*vVar, const bool add )
3731 {
3732  // Nothing to do!
3733  if( !nDep ) return;
3734  assert( opDep.size() && opRes );
3735  assert( pDep && vDep );
3736  assert( !nVar || ( pVar && vVar ) );
3737 #ifdef MC__FFUNC_CPU_EVAL
3738  double cputime;
3739 #endif
3740 
3741  // Propagate values in U arithmetic through subgraph
3742 #ifdef MC__FFUNC_CPU_EVAL
3743  double cputime = -cpuclock();
3744 #endif
3745  typename std::list<const FFOp*>::iterator ito = opDep.begin();
3746  for( U*pUres=opRes; ito!=opDep.end(); ++ito, pUres++ ){
3747  // Initialize variable using values in vVar
3748  if( (*ito)->type == FFOp::VAR ){
3749  FFVar* pF = 0;
3750  for( unsigned i=0; i<nVar; i++ ){
3751  if( (*ito)->pres->id() == pVar[i].id() ){
3752  pF = (*ito)->pres; //_find_var( (*iti).first->id() );
3753  *pUres = vVar[i];
3754  break;
3755  }
3756  }
3757  if( !pF ) throw typename FFGraph::Exceptions( FFGraph::Exceptions::MISSVAR );
3758  }
3759  (*ito)->evaluate( pUres );
3760  }
3761 #ifdef MC__FFUNC_CPU_EVAL
3762  cputime += cpuclock();
3763  std::cout << "\nEvaluation time: " << std::fixed << cputime << std::endl;
3764 #endif
3765 
3766  // Retreive dependents variables in U type as given by vDep
3767 #ifdef MC__FFUNC_CPU_EVAL
3768  cputime = -cpuclock();
3769 #endif
3770  for( unsigned i=0; i<nDep; i++ ){
3771  // Obtain pointer to dependent variable in FFGraph
3772  FFVar* pF = _find_var( pDep[i].id() );
3773  // Write/add corresponding evaluation in U type into/to result vector
3774  if( !add && pF ) vDep[i] = *static_cast<U*>( pF->val() );
3775  else if( pF ) vDep[i] += *static_cast<U*>( pF->val() );
3776  else if( !add ) switch( pDep[i].num().t ){
3777  case FFNum::INT:
3778  vDep[i] = pDep[i].num().n;
3779  break;
3780  case FFNum::REAL:
3781  vDep[i] = pDep[i].num().x;
3782  break;
3783  }
3784  else switch( pDep[i].num().t ){
3785  case FFNum::INT:
3786  vDep[i] += pDep[i].num().n;
3787  break;
3788  case FFNum::REAL:
3789  vDep[i] += pDep[i].num().x;
3790  break;
3791  }
3792  }
3793 #ifdef MC__FFUNC_CPU_EVAL
3794  cputime += cpuclock();
3795  std::cout << "Dep. collect. time: " << std::fixed << cputime << std::endl;
3796 #endif
3797 
3798  return;
3799 }
3800 
3801 inline CPPL::dssmatrix
3803 ( const unsigned nDep, const FFVar* const pDep, const unsigned nIndep,
3804  const FFVar* const pIndep )
3805 {
3806  // generate subgraph
3807  std::list<const FFOp*> opDep = subgraph( nDep, pDep );
3808 #ifdef MC__FFUNC_DEBUG_DEPMAP
3809  output( opDep );
3810 #endif
3811 
3812  return depmap( opDep, nDep, pDep, nIndep, pIndep );
3813 }
3814 
3815 inline CPPL::dssmatrix
3817 ( std::list<const FFOp*>&opDep, const unsigned nDep, const FFVar* const pDep,
3818  const unsigned nIndep, const FFVar* const pIndep )
3819 {
3820  std::vector<const FFVar*> vDep, vIndep;
3821  for( unsigned i=0; i<nDep; i++ ) vDep.push_back( pDep+i );
3822  for( unsigned i=0; i<nIndep; i++ ) vIndep.push_back( pIndep+i );
3823 
3824  return depmap( opDep, vDep, vIndep );
3825 }
3826 
3827 inline CPPL::dssmatrix
3829 ( const std::vector<const FFVar*>&vDep, const std::vector<const FFVar*>&vIndep )
3830 {
3831  // generate subgraph
3832  std::list<const FFOp*> opDep = subgraph( vDep );
3833 #ifdef MC__FFUNC_DEBUG_DEPMAP
3834  output( opDep );
3835 #endif
3836 
3837  return depmap( opDep, vDep, vIndep );
3838 }
3839 
3840 inline CPPL::dssmatrix
3842 ( std::list<const FFOp*>&opDep, const std::vector<const FFVar*>&vDep,
3843  const std::vector<const FFVar*>&vIndep )
3844 {
3845 
3846  bool contains_product = false;
3847  long ndepmap;
3848  std::map< const FFVar* , long > aux_map;
3849  long vindex = 0 , prod_index = 0;
3850 
3851  for (std::vector<const FFVar*>::const_iterator i=vIndep.begin(); i!=vIndep.end(); ++i ){
3852  aux_map[ _find_var((*i)->_id) ] = vindex; // <-- !!!Consider adding safeguards here!!!
3853  vindex += 1;
3854  }
3855 
3856  for(std::list<const FFOp*>::const_iterator i=opDep.begin(); i!=opDep.end(); ++i)
3857  switch((*i) -> pres ->id().first){
3858  case FFVar::AUX:
3859  if( (*i)->type == mc::FFOp::TIMES && !contains_product ){
3860  contains_product = true;
3861  prod_index = vindex;
3862  vindex += 6; // Add block for product
3863  }
3864  aux_map[ (*i)->pres ] = vindex;
3865  vindex += 1;
3866  break;
3867 
3868  case FFVar::VAR: case FFVar::CINT: case FFVar::CREAL: default:
3869  break;
3870  }
3871 
3872 #ifdef MC__FFUNC_DEBUG_DEPMAP
3873  std::cout << "AUX MAP: " << std::endl;
3874  for( std::map<const FFVar*,long>::const_iterator i=aux_map.begin(); i!=aux_map.end(); ++i )
3875  std::cout << *(i->first) << " , " << i->second << std::endl;
3876 #endif
3877 
3878  ndepmap = aux_map.size();
3879  if( contains_product ) ndepmap += 6;
3880  CPPL::dssmatrix depmap(ndepmap);
3881 
3882  //initialize independent variables
3883  for( unsigned long i=0 ; i<vIndep.size(); ++i ){
3884  for( unsigned long j=i ; j<vIndep.size(); ++j ) depmap.put( i, j, 1 );
3885  depmap.put( i, i, 1 );
3886  }
3887 
3888  //initialize dependent variables
3889  for( std::vector<const FFVar*>::const_iterator i_it=vDep.begin(); i_it!=vDep.end(); ++i_it ){
3890  long i = aux_map.find( _find_var((*i_it)->_id) )->second;
3891  for( std::vector<const FFVar*>::const_iterator j_it = i_it ; j_it != vDep.end(); ++j_it ){
3892  long j = aux_map.find( _find_var((*j_it)->_id) )->second;
3893  depmap.put( i, j, 1 );
3894  }
3895  depmap.put( i, i, 1);
3896  }
3897 
3898  long idep = ndepmap - 1;
3899  contains_product = false;
3900  for(std::list<const FFOp*>::const_reverse_iterator i_it=opDep.rbegin(); i_it!=opDep.rend(); ++i_it){
3901  if( (*i_it)->pres->id().first == FFVar::AUX ){
3902  if( !(*i_it)->is_univariate() ){
3903  long k, l;
3904  if( (*i_it)->plop->id().first == FFVar::AUX || (*i_it)->plop->id().first == FFVar::VAR )
3905  k = aux_map.find((*i_it)->plop)->second;
3906  if( (*i_it)->prop->id().first == FFVar::AUX || (*i_it)->prop->id().first == FFVar::VAR )
3907  l = aux_map.find((*i_it)->prop)->second;
3908  else
3909  l = -1;
3910  if( k != -1 && l != -1 ) depmap.put(k,l,1);
3911  for( long j=0; j<idep ; ++j ){
3912  if( depmap.isListed( idep, j ) ){
3913  if( k != -1 ) depmap.put( j, k, 1 );
3914  if( l != -1 ) depmap.put( j, l, 1 ) ;
3915  }
3916  }
3917  if( k != -1 ) depmap.put( k, k ,1 );
3918  if( l != -1 ) depmap.put( l, l ,1 );
3919 #ifdef MC__FFUNC_DEBUG_DEPMAP
3920  std::cout << " Row Info: \n";
3921  std::cout << " Operation : " << *((*i_it)->pres) << " = " <<*(*i_it) << std::endl;
3922  std::cout << "i = " << idep << " k = " << k << " l = " << l << std::endl;
3923 #endif
3924  if( (*i_it)->type == FFOp::TIMES && ( idep == prod_index+6 ) )
3925  idep -= 6; // jump product block if it is the first occurrence of a product
3926  }
3927  else{
3928  long k;
3929  if( (*i_it)->plop->id().first == FFVar::AUX || (*i_it)->plop->id().first == FFVar::VAR )
3930  k = aux_map.find((*i_it)->plop)->second;
3931  else
3932  k = -1;
3933  for( long j=0; j<idep; ++j )
3934  if( depmap.isListed( idep, j ) && k != -1 ) depmap.put( j, k, 1 );
3935  if( k != -1 ) depmap.put( k, k, 1 );
3936 #ifdef MC__FFUNC_DEBUG_DEPMAP
3937  std::cout << " Row Info: \n";
3938  std::cout << " Operation : " << *((*i_it)->pres) << " = " <<*(*i_it) << std::endl;
3939  std::cout << "i = " << idep << " k = " << k << " l = " << -1 << std::endl;
3940 #endif
3941  }
3942  idep -= 1;
3943  }
3944  }
3945 
3946  return depmap;
3947 }
3948 
3949 } // namespace mc
3950 
3951 namespace mc
3952 {
3953 
3955 template <> struct Op< mc::FFVar >
3956 {
3957  typedef mc::FFVar FV;
3958  static FV point( const double c ) { return FV(c); }
3959  static FV zeroone() { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3960  static void I(FV& x, const FV&y) { x = y; }
3961  static double l(const FV& x) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3962  static double u(const FV& x) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3963  static double abs (const FV& x) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3964  static double mid (const FV& x) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3965  static double diam(const FV& x) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3966  static FV inv (const FV& x) { return mc::inv(x); }
3967  static FV sqr (const FV& x) { return mc::sqr(x); }
3968  static FV sqrt(const FV& x) { return mc::sqrt(x); }
3969  static FV log (const FV& x) { return mc::log(x); }
3970  static FV xlog(const FV& x) { return x*mc::log(x); }
3971  static FV fabs(const FV& x) { return mc::fabs(x); }
3972  static FV exp (const FV& x) { return mc::exp(x); }
3973  static FV sin (const FV& x) { return mc::sin(x); }
3974  static FV cos (const FV& x) { return mc::cos(x); }
3975  static FV tan (const FV& x) { return mc::tan(x); }
3976  static FV asin(const FV& x) { return mc::asin(x); }
3977  static FV acos(const FV& x) { return mc::acos(x); }
3978  static FV atan(const FV& x) { return mc::atan(x); }
3979  static FV erf (const FV& x) { return mc::erf(x); }
3980  static FV erfc(const FV& x) { return mc::erfc(x); }
3981  static FV fstep(const FV& x) { return mc::fstep(x); }
3982  static FV bstep(const FV& x) { return mc::bstep(x); }
3983  static FV hull(const FV& x, const FV& y) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3984  static FV min (const FV& x, const FV& y) { return mc::min(x,y); }
3985  static FV max (const FV& x, const FV& y) { return mc::max(x,y); }
3986  static FV arh (const FV& x, const double k) { return mc::exp(-k/x); }
3987  template <typename X, typename Y> static FV pow(const X& x, const Y& y) { return mc::pow(x,y); }
3988  static FV monomial (const unsigned int n, const FV* x, const int* k) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3989  static bool inter(FV& xIy, const FV& x, const FV& y) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3990  static bool eq(const FV& x, const FV& y) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3991  static bool ne(const FV& x, const FV& y) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3992  static bool lt(const FV& x, const FV& y) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3993  static bool le(const FV& x, const FV& y) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3994  static bool gt(const FV& x, const FV& y) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3995  static bool ge(const FV& x, const FV& y) { throw typename FFGraph::Exceptions( FFGraph::Exceptions::UNDEF ); }
3996 };
3997 
3998 } // namespace mc
3999 
4000 namespace fadbad
4001 {
4003  template <> struct Op<mc::FFVar>{
4004  typedef double Base;
4005  typedef mc::FFVar FV;
4006  static Base myInteger( const int i ) { return Base(i); }
4007  static Base myZero() { return myInteger(0); }
4008  static Base myOne() { return myInteger(1);}
4009  static Base myTwo() { return myInteger(2); }
4010  static double myPI() { return mc::PI; }
4011  static FV myPos( const FV& x ) { return x; }
4012  static FV myNeg( const FV& x ) { return -x; }
4013  template <typename U> static FV& myCadd( FV& x, const U& y ) { return x+=y; }
4014  template <typename U> static FV& myCsub( FV& x, const U& y ) { return x-=y; }
4015  template <typename U> static FV& myCmul( FV& x, const U& y ) { return x*=y; }
4016  template <typename U> static FV& myCdiv( FV& x, const U& y ) { return x/=y; }
4017  static FV myInv( const FV& x ) { return mc::inv( x ); }
4018  static FV mySqr( const FV& x ) { return mc::pow( x, 2 ); }
4019  template <typename X, typename Y> static FV myPow( const X& x, const Y& y ) { return mc::pow( x, y ); }
4020  static FV mySqrt( const FV& x ) { return mc::sqrt( x ); }
4021  static FV myLog( const FV& x ) { return mc::log( x ); }
4022  static FV myExp( const FV& x ) { return mc::exp( x ); }
4023  static FV mySin( const FV& x ) { return mc::sin( x ); }
4024  static FV myCos( const FV& x ) { return mc::cos( x ); }
4025  static FV myTan( const FV& x ) { return mc::tan( x ); }
4026  static FV myAsin( const FV& x ) { return mc::asin( x ); }
4027  static FV myAcos( const FV& x ) { return mc::acos( x ); }
4028  static FV myAtan( const FV& x ) { return mc::atan( x ); }
4029  static bool myEq( const FV& x, const FV& y ) { throw std::runtime_error("fadbad::Op<FFVar>::myEq -- operation not permitted"); }
4030  static bool myNe( const FV& x, const FV& y ) { throw std::runtime_error("fadbad::Op<FFVar>::myNe -- operation not permitted"); }
4031  static bool myLt( const FV& x, const FV& y ) { throw std::runtime_error("fadbad::Op<FFVar>::myLt -- operation not permitted"); }
4032  static bool myLe( const FV& x, const FV& y ) { throw std::runtime_error("fadbad::Op<FFVar>::myLe -- operation not permitted"); }
4033  static bool myGt( const FV& x, const FV& y ) { throw std::runtime_error("fadbad::Op<FFVar>::myGt -- operation not permitted"); }
4034  static bool myGe( const FV& x, const FV& y ) { throw std::runtime_error("fadbad::Op<FFVar>::myGe -- operation not permitted"); }
4035  };
4036 } // end namespace fadbad
4037 
4038 #endif
C++ structure for comparing operations in a factorable program for ordering in set FFGraph::_Ops...
Definition: ffunc.hpp:980
void flag(const bool visited=true) const
Flag operation as visited or not.
Definition: ffunc.hpp:956
FFVar * prop
Pointer to right operand.
Definition: ffunc.hpp:922
Error due to a invalid FFGraph pointer in initialization of FFVar.
Definition: ffunc.hpp:1116
unsigned long _nvar
Number of original variables in DAG.
Definition: ffunc.hpp:1086
Error due to a missing independent variable for evaluating a given subgraph using FFGraph::eval...
Definition: ffunc.hpp:1118
void evaluate(const U &U_dum) const
Evaluate operation in U arithmetic, dynamically allocating the result.
Definition: ffunc.hpp:2397
void *& val()
Get pointer to value field.
Definition: ffunc.hpp:830
Real constant.
Definition: ffunc.hpp:723
void append_dot_script_factor(std::ostream &os, const std::string &fname, const bool unary, const unsigned int fontsize, const bool dotted=false) const
Append script for factor fname using DOT to os
Definition: ffunc.hpp:2706
pt_Ops & ops()
Get pointer to defining operation.
Definition: ffunc.hpp:818
void _reset_operations() const
Reset all operations in set _Ops
Definition: ffunc.hpp:1302
TYPE
Enumeration type for variables in factorable function.
Definition: ffunc.hpp:719
void dot_script(const unsigned int nDep, const FFVar *pDep, std::ostream &os=std::cout) const
Generate script for DAG visualization of factors *F using DOT.
Definition: ffunc.hpp:2992
static FFVar & _insert_binary_operation(const typename FFOp::TYPE top, const FFDep &dep, const FFVar &Var1, const FFVar &Var2)
Looks for the binary operation of type top with left and right operands Var1, Var2 in set _Ops and ad...
Definition: ffunc.hpp:2794
void _append_aux(FFVar *pAux, typename FFOp::TYPE tOp)
Appends the auxiliary variable pAux and define it in _Ops with type tOp
Definition: ffunc.hpp:2917
const std::pair< TYPE, long > id() const
Get variable identifier.
Definition: ffunc.hpp:794
Exceptions(TYPE ierr)
Constructor for error ierr
Definition: ffunc.hpp:1124
Error due to calling a function/feature not yet implemented in MC++.
Definition: ffunc.hpp:1121
void reset_val(const U &U_dum)
Get pointer to value field.
Definition: ffunc.hpp:835
Structure comparing values of scalars in factorable functions for strict inequality.
Definition: ffunc.hpp:622
const bool stat() const
Retreive operation status (visited or not)
Definition: ffunc.hpp:959
Structure comparing variable identifiers in a factorable function for ordering in set FFGraph::_Vars...
Definition: ffunc.hpp:862
FFVar * plop
Pointer to left operand.
Definition: ffunc.hpp:920
const pt_Ops ops() const
Get const pointer to defining operation.
Definition: ffunc.hpp:814
std::vector< const FFVar * > FAD(const std::vector< const FFVar * > &vDep, const std::vector< const FFVar * > &vIndep)
Expand DAG with derivatives of dependents vDep with respect to independents vIndep using fadbad::F – ...
Definition: ffunc.hpp:3045
unsigned long nvar() const
Number of original variables in DAG.
Definition: ffunc.hpp:1162
Real value.
Definition: ffunc.hpp:565
FFOp(TYPE top, FFVar *lop=0, FFVar *rop=0, FFVar *res=0)
Constructor.
Definition: ffunc.hpp:2303
const FFDep & dep() const
Get const reference to variable dependencies.
Definition: ffunc.hpp:806
Class defining operations in a factorable function.
Definition: ffunc.hpp:892
FFOp * _insert_operation(const typename FFOp::TYPE top, FFVar *lop, FFVar *rop=0)
Looks for the operation of type top with left and right operands lop, rop in set _Ops and adds it if ...
Definition: ffunc.hpp:2858
std::list< const FFOp * > subgraph(const unsigned int nDep, const FFVar *pDep) const
Extract list of operations corresponding to nDep dependents in array pDep
Definition: ffunc.hpp:2953
C++ class for evaluation of the sparsity pattern of a factorable function.
Definition: ffdep.hpp:90
t_Ops _Ops
Set of operations in DAG.
Definition: ffunc.hpp:1095
bool is_univariate() const
Return whether or not operation is univariate.
Definition: ffunc.hpp:2742
std::vector< const FFVar * > compose(const std::vector< const FFVar * > &vDepOut, const std::vector< std::pair< const FFVar *, const FFVar * > > &vDepIn)
Compose the dependents in vDepOut with those in vDepIn – This function creates the subgraph for the o...
Definition: ffunc.hpp:3374
Integer value.
Definition: ffunc.hpp:564
Error during subgraph evaluation using FFGraph::eval.
Definition: ffunc.hpp:1119
Error due to an operation between variables linked to different DAGs.
Definition: ffunc.hpp:1117
~FFOp()
Destructor.
Definition: ffunc.hpp:912
static void output(const std::list< const FFOp * > &Ops, std::ostream &os=std::cout)
Output list of nodes in Ops to os
Definition: ffunc.hpp:2982
unsigned long _naux
Number of auxiliary variables in DAG.
Definition: ffunc.hpp:1089
void _clear_operations()
Erase all operations in set _Ops
Definition: ffunc.hpp:1296
Structure comparing values of scalars in factorable functions for equality.
Definition: ffunc.hpp:603
Integer constant.
Definition: ffunc.hpp:722
void append_dot_script(std::ostream &os) const
Append script for current operation using DOT to os
Definition: ffunc.hpp:2669
FFDep & dep()
Get reference to variable dependencies.
Definition: ffunc.hpp:810
void append_dot_script_variable(std::ostream &os, const bool constant, const unsigned int fontsize) const
Append script for variable/contant using DOT to os
Definition: ffunc.hpp:2725
std::string name() const
Get variable name.
Definition: ffunc.hpp:839
FFVar * _find_var(const typename FFVar::pt_idVar &id)
Search for the variable with identify id in _Vars
Definition: ffunc.hpp:2943
FFGraph *& dag()
Get pointer to factorable function dag.
Definition: ffunc.hpp:826
void _clear_variables()
Erase all variables in _Vars.
Definition: ffunc.hpp:1341
virtual ~FFGraph()
Destructor.
Definition: ffunc.hpp:1107
const FFGraph * dag() const
Get const pointer to factorable function.
Definition: ffunc.hpp:822
std::string what()
Error description.
Definition: ffunc.hpp:1128
Auxiliary variable.
Definition: ffunc.hpp:721
virtual void _append_var(FFVar *pVar)
Appends new original variable.
Definition: ffunc.hpp:2936
void propagate_subgraph(std::list< const FFOp * > &Ops) const
Propagate subset of operations participating in subgraph.
Definition: ffunc.hpp:2351
std::vector< const FFVar * > TAD(const unsigned int ordermax, const std::vector< const FFVar * > &vDep, const std::vector< const FFVar * > &vVar, const FFVar *const pIndep=0)
Expand DAG with Taylor coefficients of dependents vDep with respect to independents vIndep using fadb...
Definition: ffunc.hpp:3248
C++ class representing the DAG of factorable functions.
Definition: ffunc.hpp:1019
void generate_dot_script(std::ostream &os) const
Propagate script for DAG using DOT and display to os
Definition: ffunc.hpp:2657
void reset_val_subgraph(const U &U_dum) const
Reset mc::FFVar::_val field in subgraph.
Definition: ffunc.hpp:2364
TYPE
Enumeration type for exception handling.
Definition: ffunc.hpp:1115
static double cpuclock()
Return current clock time.
Definition: ffunc.hpp:1284
Structure defining the numeric field of a factorable program variable.
Definition: ffunc.hpp:560
TYPE
Enumeration type for unary and binary operations.
Definition: ffunc.hpp:901
Internal error.
Definition: ffunc.hpp:1120
unsigned long naux() const
Number of auxiliary variables in DAG.
Definition: ffunc.hpp:1166
Exceptions of mc::FFGraph.
Definition: ffunc.hpp:1111
std::vector< const FFVar * > BAD(const std::vector< const FFVar * > &vDep, const std::vector< const FFVar * > &vIndep)
Expand DAG with derivatives of dependents vDep with respect to independents vIndep using fadbad::B – ...
Definition: ffunc.hpp:3139
CPPL::dssmatrix depmap(const unsigned nDep, const FFVar *const pDep, const unsigned nIndep, const FFVar *const pIndep)
Create dependency map corresponding to nDep dependents in array pDep and nIndep independents in array...
Definition: ffunc.hpp:3803
static FFVar & _insert_unary_operation(const typename FFOp::TYPE top, const FFDep &dep, const FFVar &Var)
Looks for the unary operation of type top with operand Var1, Var2 in set _Ops and adds it if not foun...
Definition: ffunc.hpp:2844
TYPE
Enumeration type for numeric variables in factorable function.
Definition: ffunc.hpp:563
const bool & stat()
Retreive/set operation status (visited or not)
Definition: ffunc.hpp:962
FFVar * _add_auxiliary(const FFDep &dep, FFOp *pOp)
Adds the auxiliary variable with dependency dep from operation op
Definition: ffunc.hpp:2880
FFNum(const int i=0)
Constructor for an integer variable.
Definition: ffunc.hpp:576
std::pair< TYPE, long > pt_idVar
Typedef for variable identifier in factorable function.
Definition: ffunc.hpp:726
FFVar(FFGraph *dag)
Constructor for variable in DAG *dag
Definition: ffunc.hpp:1387
FFNum(const double d)
Constructor for a real variable.
Definition: ffunc.hpp:580
const FFNum & num() const
Get const reference to variable numeric field.
Definition: ffunc.hpp:802
FFVar * _add_constant(const double x)
Looks for the real constant x and adds it if not found.
Definition: ffunc.hpp:2889
FFGraph()
Default Constructor.
Definition: ffunc.hpp:1102
t_Vars _Vars
Set of variables in DAG.
Definition: ffunc.hpp:1092
TYPE t
Variable type.
Definition: ffunc.hpp:568
FFVar * pres
Pointer to operation result.
Definition: ffunc.hpp:918
std::pair< TYPE, long > & id()
Get reference to variable identifier.
Definition: ffunc.hpp:798
bool _remove_operation(FFOp *op)
Erase operation op in set _Ops
Definition: ffunc.hpp:2869
Original variable.
Definition: ffunc.hpp:720
static const long NOREF
Index for 'free' variables in factorable function.
Definition: ffunc.hpp:717
const t_Vars & Vars() const
Reference to set of (all) variables in factorable function.
Definition: ffunc.hpp:1170
FFVar & set(FFGraph *dag)
Attach variable to DAG *dag.
Definition: ffunc.hpp:754
int ierr()
Inline function returning the error flag.
Definition: ffunc.hpp:1126
TYPE type
Type of operation.
Definition: ffunc.hpp:916
std::vector< U > eval(const std::vector< const FFVar * > &vDep, const std::vector< std::pair< const FFVar *, U > > &vVar)
Evaluate the dependents in vDep in U arithmetic for the variable values specified in vVar – This func...
Definition: ffunc.hpp:3424
Class defining variables in a factorable function.
Definition: ffunc.hpp:643
C++ structure for comparing operations in a factorable program.
Definition: ffunc.hpp:1005
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
void clear()
Clear DAG (all variables and operations)
Definition: ffunc.hpp:1174