Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

int_evaluator.h

Go to the documentation of this file.
00001 // Interval Evaluator implementation -*- C++ -*-
00002 
00003 // Copyright (C) 2001-2003 Hermann Schichl
00004 //
00005 // This file is part of the COCONUT API.  This library
00006 // is free software; you can redistribute it and/or modify it under the
00007 // terms of the Library GNU General Public License as published by the
00008 // Free Software Foundation; either version 2, or (at your option)
00009 // any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // Library GNU General Public License for more details.
00015 
00016 // As a special exception, you may use this file as part of a free software
00017 // library without restriction.  Specifically, if other files instantiate
00018 // templates or use macros or inline functions from this file, or you compile
00019 // this file and link it with other files to produce an executable, this
00020 // file does not by itself cause the resulting executable to be covered by
00021 // the Library GNU General Public License.  This exception does not however
00022 // invalidate any other reasons why the executable file might be covered by
00023 // the Library GNU General Public License.
00024 
00027 #ifndef _INTERVAL_EVALUATOR_H_
00028 #define _INTERVAL_EVALUATOR_H_
00029 
00030 #include <coconut_config.h>
00031 #include <evaluator.h>
00032 #include <expression.h>
00033 #include <model.h>
00034 #include <eval_main.h>
00035 #include <linalg.h>
00036 #include <math.h>
00037 
00038 using namespace vgtl;
00039 
00040 typedef interval (*interval_evaluator)(const std::vector<interval>* __x,
00041                                  const variable_indicator& __v);
00042 
00043 struct interval_eval_type
00044 {
00045   const std::vector<interval>* x;
00046   std::vector<interval>* cache;
00047   const model* mod;
00048   union { void *p; interval_st d; int info; } u;
00049   interval r;
00050   unsigned int n;
00051   bool do_intersect;
00052 };
00053 
00054 class interval_eval : public
00055   cached_forward_evaluator_base<interval_eval_type,expression_node,interval,
00056                                 model::walker>
00057 {
00058 private:
00059   typedef cached_forward_evaluator_base<interval_eval_type,expression_node,
00060                                         interval,model::walker> _Base;
00061 
00062 protected:
00063   bool is_cached(const node_data_type& __data)
00064   {
00065     if(__data.operator_type == EXPRINFO_LIN ||
00066        __data.operator_type == EXPRINFO_QUAD)
00067       return true;
00068     else
00069       return false;
00070 #if 0
00071     if(eval_data.cache && __data.n_parents > 1 && __data.n_children > 0)
00072       return true;
00073     else
00074       return false;
00075 #endif
00076   }
00077 
00078 private:
00079   interval __power(double __coeff, interval __x, int __exp)
00080   {
00081     if(__exp == 0)
00082       return 1.;
00083     else
00084     {
00085       interval k = __coeff*__x;
00086       switch(__exp)
00087       {
00088         case 1:
00089           return k;
00090           break;
00091         case 2:
00092           return sqr(k);
00093           break;
00094         case -1:
00095           return 1./k;
00096           break;
00097         case -2:
00098           return 1./sqr(k);
00099           break;
00100         default:
00101           return ipow(k, __exp);
00102           break;
00103       }
00104     }
00105     return 0;           // we never come here!
00106   }
00107 
00108 public:
00109   interval_eval(const std::vector<interval>& __x, const variable_indicator& __v,
00110                 const model& __m, std::vector<interval>* __c, bool do_i = true)
00111                 : _Base()
00112   {
00113     eval_data.x = &__x;
00114     eval_data.cache = __c;
00115     eval_data.mod = &__m;
00116     eval_data.u.d = 0.;
00117     v_ind = &__v;
00118     eval_data.n = 0;
00119     eval_data.do_intersect = do_i;
00120   }
00121 
00122   interval_eval(const interval_eval& __v) : _Base(__v) {}
00123   
00124   ~interval_eval() {}
00125 
00126   model::walker short_cut_to(const expression_node& __data)
00127   { return eval_data.mod->node(0); }    // return anything
00128 
00129   void initialize() { return; }
00130   
00131   int initialize(const expression_node& __data)
00132   {
00133     eval_data.n = 0;
00134     if(__data.ev && (*__data.ev)[FUNC_RANGE])
00135     // is there a short-cut evaluator defined?
00136     {
00137       eval_data.r =
00138         (*(interval_evaluator)(*__data.ev)[FUNC_RANGE])(eval_data.x,
00139                                                                  *v_ind);
00140       return 0;     // don't perform the remaining graph walk
00141     }
00142     else
00143     {
00144       switch(__data.operator_type)
00145       {
00146         case EXPRINFO_SUM:
00147         case EXPRINFO_PROD:
00148         case EXPRINFO_MAX:
00149         case EXPRINFO_MIN:
00150         case EXPRINFO_INVERT:
00151         case EXPRINFO_DIV:
00152           eval_data.r = __data.params.nd();
00153           break;
00154         case EXPRINFO_MONOME:
00155         case EXPRINFO_IN:
00156         case EXPRINFO_AND:
00157         case EXPRINFO_NOGOOD:
00158           eval_data.r = 1.;
00159           break;
00160         case EXPRINFO_ALLDIFF:
00161           eval_data.u.p = (void*) new std::vector<interval>;
00162           ((std::vector<interval>*)eval_data.u.p)->reserve(__data.n_children);
00163           // no break!
00164         case EXPRINFO_MEAN:
00165         case EXPRINFO_IF:
00166         case EXPRINFO_OR:
00167         case EXPRINFO_NOT:
00168         case EXPRINFO_COUNT:
00169         case EXPRINFO_SCPROD:
00170         case EXPRINFO_NORM:
00171         case EXPRINFO_LEVEL:
00172           eval_data.r = 0.;
00173           break;
00174         case EXPRINFO_DET:
00175         case EXPRINFO_PSD:
00176           // here construct square interval matrix
00177           break;
00178         case EXPRINFO_COND:
00179         case EXPRINFO_FEM:
00180         case EXPRINFO_MPROD:
00181           // here construct rectangular interval matrix
00182           break;
00183       }
00184       return 1;
00185     }
00186   }
00187 
00188   void calculate(const expression_node& __data)
00189   {
00190     if(__data.operator_type > 0)
00191     {
00192       eval_data.r = __data.i_evaluate(-1, __data.params.nn(), *eval_data.x,
00193                                       *v_ind, eval_data.r, interval(0,0), NULL);
00194     }
00195     if(eval_data.do_intersect)
00196       eval_data.r.intersect(__data.f_bounds);
00197   }
00198 
00199   void retrieve_from_cache(const expression_node& __data)
00200   {
00201     if(__data.operator_type == EXPRINFO_LIN)
00202     {
00203       const matrix<double>::Row& lrw(eval_data.mod->lin[__data.params.nn()]);
00204       matrix<double>::Row::const_iterator _x, _e;
00205 
00206       eval_data.r = interval(0.);
00207       for(_x = lrw.begin(); _x != _e; ++_x)
00208         eval_data.r += (*eval_data.x)[_x.index()] * *_x;
00209     }
00210     else if(__data.operator_type == EXPRINFO_QUAD)
00211     {
00212       throw "Interval Evaluation of QUAD: NYI!";
00213     }
00214     else
00215       eval_data.r = (*eval_data.cache)[__data.node_num];
00216   }
00217 
00218   int update(const interval& __rval)
00219   {
00220     eval_data.r = __rval;
00221     return 0;
00222   }
00223 
00224   int update(const expression_node& __data, const interval& __rval)
00225   {
00226     interval __x;
00227     int ret = 0;
00228     if(__data.operator_type < 0)
00229     {
00230       switch(__data.operator_type)
00231       {
00232         case EXPRINFO_CONSTANT:
00233           eval_data.r = __data.params.nd();
00234           break;
00235         case EXPRINFO_VARIABLE:
00236           eval_data.r = (*eval_data.x)[__data.params.nn()];
00237           break;
00238         case EXPRINFO_SUM:
00239         case EXPRINFO_MEAN:
00240           eval_data.r += __data.coeffs[eval_data.n++]*__rval;
00241           break;
00242         case EXPRINFO_PROD:
00243           // the coefficients MUST be collected in __data.params.nd()
00244           eval_data.r *= __rval;
00245           if(eval_data.r == 0.) ret = -1;
00246           break;
00247         case EXPRINFO_MONOME:
00248           // the coefficients MUST be collected in __data.params.nd()
00249           eval_data.r *= __power(__data.coeffs[eval_data.n], __rval,
00250                                  __data.params.n()[eval_data.n]);
00251           if(eval_data.r == 0.) ret = -1;
00252           eval_data.n++;
00253           break;
00254         case EXPRINFO_MAX:
00255           { interval h = __rval * __data.coeffs[eval_data.n++];
00256             eval_data.r = imax(eval_data.r, h);
00257           }
00258           break;
00259         case EXPRINFO_MIN:
00260           { interval h = __rval * __data.coeffs[eval_data.n++];
00261             eval_data.r = imin(eval_data.r, h);
00262           }
00263           break;
00264         case EXPRINFO_SCPROD:
00265           { interval h = __data.coeffs[eval_data.n]*__rval;
00266             // if the number of children is odd, the list is implicitly
00267             // lengthened by one null element (i.e. implicitly shortened)
00268             if(eval_data.n & 1) // y_n
00269               eval_data.r += __data.coeffs[eval_data.n]*__rval*h;
00270             else // x_n
00271               eval_data.u.d = h;
00272           }
00273           eval_data.n++;
00274           break;
00275         case EXPRINFO_NORM:
00276           if(__data.params.nd() == INFINITY)
00277           {
00278             interval h = abs(__rval * __data.coeffs[eval_data.n]);
00279             eval_data.r = imax(eval_data.r, h);
00280           }
00281           else
00282           {
00283             interval h = abs(__data.coeffs[eval_data.n]*__rval);
00284             eval_data.r += pow(h, interval(__data.params.nd()));
00285           }
00286           ++eval_data.n;
00287           if(eval_data.n == __data.n_children)
00288             eval_data.r = pow(eval_data.r, interval(1.)/__data.params.nd());
00289           break;
00290         case EXPRINFO_INVERT:
00291           eval_data.r /= __rval;
00292           break;
00293         case EXPRINFO_DIV:
00294           // this evaluator requires, that the second coefficient
00295           // is put into the first.
00296           if(eval_data.n == 0)
00297             eval_data.r *= __rval;
00298           else
00299             eval_data.r /= __rval;
00300           ++eval_data.n;
00301           break;
00302         case EXPRINFO_SQUARE:
00303           { interval h = __data.coeffs[0]*__rval+__data.params.nd();
00304             eval_data.r = sqr(h);
00305           }
00306           break;
00307         case EXPRINFO_INTPOWER:
00308           eval_data.r = __power(__data.coeffs[0], __rval, __data.params.nn());
00309           break;
00310         case EXPRINFO_SQROOT:
00311           eval_data.r = sqrt(__data.coeffs[0]*__rval+__data.params.nd());
00312           break;
00313         case EXPRINFO_ABS:
00314           eval_data.r = abs(__data.coeffs[0]*__rval+__data.params.nd());
00315           break;
00316         case EXPRINFO_POW:
00317           { interval h = __rval * __data.coeffs[eval_data.n];
00318             if(eval_data.n == 0)
00319               eval_data.r = h+__data.params.nd();
00320             else
00321               eval_data.r = pow(eval_data.r, h);
00322           }
00323           ++eval_data.n;
00324           break;
00325         case EXPRINFO_EXP:
00326           eval_data.r = exp(__rval*__data.coeffs[0]+__data.params.nd());
00327           break;
00328         case EXPRINFO_LOG:
00329           eval_data.r = log(__rval*__data.coeffs[0]+__data.params.nd());
00330           break;
00331         case EXPRINFO_SIN:
00332           eval_data.r = sin(__rval*__data.coeffs[0]+__data.params.nd());
00333           break;
00334         case EXPRINFO_COS:
00335           eval_data.r = cos(__rval*__data.coeffs[0]+__data.params.nd());
00336           break;
00337         case EXPRINFO_ATAN2:
00338           { interval h = __rval * __data.coeffs[eval_data.n];
00339             if(eval_data.n == 0)
00340               eval_data.r = h;
00341             else
00342               eval_data.r = atan2(eval_data.r, h);
00343             ++eval_data.n;
00344           }
00345           break;
00346         case EXPRINFO_GAUSS:
00347           { interval h = (__data.coeffs[0]*__rval-__data.params.d()[0])/
00348                                 __data.params.d()[1];
00349             eval_data.r = gauss(h);
00350           }
00351           break;
00352         case EXPRINFO_POLY:
00353           std::cerr << "Polynomes NYI" << std::endl;
00354           throw "NYI";
00355           break;
00356         case EXPRINFO_LIN:
00357         case EXPRINFO_QUAD:
00358           // we will never be here
00359           break;
00360         case EXPRINFO_IN:
00361           {
00362             __x = __data.coeffs[eval_data.n]*__rval;
00363             const interval& i(__data.params.i()[eval_data.n]);
00364             if(i.disjoint(__x))     // it is not in
00365             {
00366               eval_data.r = -1.;
00367               ret = -1;
00368             }
00369             else if(eval_data.r != interval(-1.))
00370             {
00371               if(!i.superset(__x))  // in and out are possible
00372               {
00373                 if(i.sup() == __x.inf() || i.inf() == __x.sup())
00374                 // intersection is only on the border
00375                   eval_data.r = interval(-1.,0.);
00376                 else if(eval_data.r.sup() > 0)
00377                   eval_data.r = interval(-1.,1.);
00378               }
00379               else if(i.inf() == __x.inf() || i.sup() == __x.sup())
00380               // they are not disjoint, and i is a superset of __x
00381               // but a border is possible
00382               {
00383                 if(eval_data.r.inf() == 1.)
00384                 {
00385                   if(__x.is_thin())       // only border
00386                     eval_data.r = 0.;
00387                   else                    // interior and border possible
00388                     eval_data.r = interval(0.,1.);
00389                 }
00390                 else if(__x.is_thin() && eval_data.r.inf() == 0.)
00391                   eval_data.r = 0.;
00392               }
00393               // if __x is in the interior of i eval_data.r does not change
00394             }
00395           }
00396           eval_data.n++;
00397           break;
00398         case EXPRINFO_IF:
00399           __x = __rval * __data.coeffs[eval_data.n];
00400           if(eval_data.n == 0) // this is the condition
00401           {
00402             const interval& i(__data.params.ni());
00403             if(i.superset(__x))      // always true
00404               eval_data.u.info = 0;
00405             else if(i.disjoint(__x)) // never true
00406             {
00407               eval_data.u.info = 1;
00408               ret = 1;               // skip if part
00409             }
00410             else                     // both is possible
00411               eval_data.u.info = 2;
00412           }
00413           else if(eval_data.n == 1)  // this is the if part
00414           {
00415             eval_data.r = __x;
00416             if(eval_data.u.info == 0)  // it was always true
00417               ret = -1;              // don't continue walking
00418           }
00419           else // this is the else part
00420           {
00421             if(eval_data.u.info == 1) // only the else part
00422               eval_data.r = __x;
00423             else                      // both parts
00424               eval_data.r = eval_data.r.hull(__x);
00425           }
00426           eval_data.n += ret+1;
00427           break;
00428         case EXPRINFO_AND:
00429           { __x = __data.coeffs[eval_data.n]*__rval;
00430             const interval& i(__data.params.i()[eval_data.n]);
00431             if(eval_data.r != 0.)
00432             {
00433               if(i.disjoint(__x))
00434               {
00435                 eval_data.r = 0;
00436                 ret = -1;         // result cannot become more false
00437               }
00438               else if(!i.superset(__x))
00439                 eval_data.r = interval(0.,1.);
00440               // else this does not change the value
00441             }
00442           }
00443           eval_data.n++;
00444           break;
00445         case EXPRINFO_OR:
00446           { __x = __data.coeffs[eval_data.n]*__rval;
00447             const interval& i(__data.params.i()[eval_data.n]);
00448             if(eval_data.r != 1.)
00449             {
00450               if(i.superset(__x))
00451               {
00452                 eval_data.r = 1;
00453                 ret = -1;         // result cannot become more true
00454               }
00455               else if(!i.disjoint(__x))
00456                 eval_data.r = interval(0.,1.);
00457             }
00458           }
00459           eval_data.n++;
00460           break;
00461         case EXPRINFO_NOT:
00462           { __x = __data.coeffs[0]*__rval;
00463             const interval& i(__data.params.ni());
00464             if(i.superset(__x))
00465               eval_data.r = 0;
00466             else if(i.disjoint(__x))
00467               eval_data.r = 1;
00468             else
00469               eval_data.r = interval(0.,1.);
00470           }
00471           break;
00472         case EXPRINFO_IMPLIES:
00473           { const interval& i(__data.params.i()[eval_data.n]);
00474             __x = __rval * __data.coeffs[eval_data.n];
00475             if(eval_data.n == 0)
00476             {
00477               if(i.disjoint(__x))
00478               {
00479                 eval_data.r = 1.;
00480                 ret = -1;        // ex falso quodlibet
00481               }
00482               else if(!i.superset(__x))
00483                 eval_data.r = interval(0.,1.);
00484               else
00485                 eval_data.r = interval(0.);
00486             }
00487             else // we only get here if first clause might be true
00488             {
00489               if(i.superset(__x))
00490                 eval_data.r = 1.;
00491               else if(!i.disjoint(__x))
00492                 eval_data.r = interval(0.,1.);
00493               // else the value does not change
00494             }
00495             ++eval_data.n;
00496           }
00497           break;
00498         case EXPRINFO_COUNT:
00499           { __x = __data.coeffs[eval_data.n]*__rval;
00500             const interval& i(__data.params.i()[eval_data.n]);
00501             if(i.superset(__x))
00502               eval_data.r += 1;
00503             else if(!i.disjoint(__x))
00504               eval_data.r += interval(0.,1.);
00505           }
00506           eval_data.n++;
00507           break;
00508         case EXPRINFO_ALLDIFF:
00509           { __x = __data.coeffs[eval_data.n]*__rval;
00510             for(std::vector<interval>::const_iterator _b =
00511                         ((std::vector<interval>*)eval_data.u.p)->begin();
00512                 _b != ((std::vector<interval>*)eval_data.u.p)->end(); ++_b)
00513             {
00514               interval __h = abs(__x-*_b);
00515               if(__h.sup() <= __data.params.nd())  // they are always equal
00516               {
00517                 eval_data.r = 0;
00518                 ret = -1;               // don't continue
00519                 break;
00520               }
00521               else if(__h.inf() <= __data.params.nd()) // they are not always different
00522                 eval_data.r = interval(0.,1.);
00523             }
00524             if(ret != -1)
00525               ((std::vector<interval>*) eval_data.u.p)->push_back(__x);
00526           }
00527           eval_data.n++;
00528           if(eval_data.n == __data.n_children || ret == -1)
00529             delete (std::vector<interval>*) eval_data.u.p;
00530           break;
00531         case EXPRINFO_HISTOGRAM:
00532           std::cerr << "int_evaluator: histogram NYI" << std::endl;
00533           throw "NYI";
00534           break;
00535         case EXPRINFO_LEVEL:
00536           { int lo = (int)eval_data.r.inf();
00537             int hi = (int)eval_data.r.sup();
00538             __x = __data.coeffs[eval_data.n]*__rval;
00539             interval _h;
00540 
00541             // first adjust upper bound
00542             if(hi != INT_MAX)
00543             {
00544               while(hi < __data.params.im().nrows())
00545               { 
00546                 _h = __data.params.im()[hi][eval_data.n];
00547                 if(_h.superset(__x))
00548                   break;
00549                 hi++;
00550               }
00551               if(hi == __data.params.im().nrows())
00552                 hi = INT_MAX;
00553             }
00554             // then adjust lower bound
00555             if(lo != INT_MAX)
00556             {
00557               while(lo < __data.params.im().nrows())
00558               { 
00559                 _h = __data.params.im()[lo][eval_data.n];
00560                 if(!_h.disjoint(__x))
00561                   break;
00562                 lo++;
00563               }
00564               if(lo == __data.params.im().nrows())
00565                 lo = INT_MAX;
00566             }
00567             if(hi == INT_MAX && lo == INT_MAX)
00568             {
00569               eval_data.r = INT_MAX;
00570               ret = -1;
00571             }
00572             else
00573               eval_data.r = interval(lo+0.,hi+0.);
00574           }
00575           eval_data.n++;
00576           break;
00577         case EXPRINFO_NEIGHBOR:
00578           // this is suboptimal. It does not take into account
00579           // all the possibilities to proove that the result actually
00580           // EQUALS 1
00581           if(eval_data.n == 0)
00582             eval_data.r = __data.coeffs[0]*__rval;
00583           else
00584           {
00585             interval h = eval_data.r;
00586             eval_data.r = 0;
00587             __x = __data.coeffs[1]*__rval;
00588             for(unsigned int i = 0; i < __data.params.n().size(); i+=2)
00589             {
00590               if(h == __data.params.n()[i]+0. &&
00591                  __x == __data.params.n()[i+1]+0.)
00592               {
00593                 eval_data.r = 1;
00594                 break;
00595               }
00596               else if(h.contains(__data.params.n()[i]+0.) &&
00597                       __x.contains(__data.params.n()[i+1]+0.))
00598               {
00599                 eval_data.r = interval(0.,1.);
00600                 break;
00601               }
00602             }
00603           }
00604           eval_data.n++;
00605           break;
00606         case EXPRINFO_NOGOOD:
00607           __x = __data.coeffs[eval_data.n]*__rval;
00608           if(eval_data.r != 0.)
00609           { 
00610             if(!__x.contains(__data.params.n()[eval_data.n]+0.))
00611             {
00612               eval_data.r = 0.;
00613               ret = -1;
00614             }
00615             else if(__x != __data.params.n()[eval_data.n]+0.)
00616               eval_data.r = interval(0.,1.);
00617           }
00618           eval_data.n++;
00619           break;
00620         case EXPRINFO_EXPECTATION:
00621           std::cerr << "int_evaluator: E NYI" << std::endl;
00622           throw "NYI";
00623           break;
00624         case EXPRINFO_INTEGRAL:
00625           std::cerr << "int_evaluator: INT NYI" << std::endl;
00626           throw "NYI";
00627           break;
00628         case EXPRINFO_LOOKUP:
00629         case EXPRINFO_PWLIN:
00630         case EXPRINFO_SPLINE:
00631         case EXPRINFO_PWCONSTLC:
00632         case EXPRINFO_PWCONSTRC:
00633           std::cerr << "int_evaluator: Table Operations NYI" << std::endl;
00634           throw "NYI";
00635           break;
00636         case EXPRINFO_DET:
00637         case EXPRINFO_COND:
00638         case EXPRINFO_PSD:
00639         case EXPRINFO_MPROD:
00640         case EXPRINFO_FEM:
00641           std::cerr << "int_evaluator: Matrix Operations NYI" << std::endl;
00642           throw "NYI";
00643           break;
00644         case EXPRINFO_RE:
00645         case EXPRINFO_IM:
00646         case EXPRINFO_ARG:
00647         case EXPRINFO_CPLXCONJ:
00648           std::cerr << "int_evaluator: Complex Numbers NYI" << std::endl;
00649           throw "NYI";
00650           break;
00651         case EXPRINFO_CMPROD:
00652         case EXPRINFO_CGFEM:
00653           std::cerr << "int_evaluator: Const Matrix Operations NYI" << std::endl;
00654           throw "NYI";
00655           break;
00656         default:
00657           std::cerr << "int_evaluator: unknown function type " <<
00658                    __data.operator_type << std::endl;
00659           throw "Programming error";
00660           break;
00661       }
00662     }
00663     else if(__data.operator_type > 0)
00664       // update the function arguments
00665       eval_data.r = __data.i_evaluate(eval_data.n++, __data.params.nn(),
00666                         *eval_data.x, *v_ind, eval_data.r, __rval, NULL);
00667     // use the cache only if it is worthwhile
00668     //    if(eval_data.cache && __data.n_parents > 1 && __data.n_children > 0)
00669     if(eval_data.cache)
00670       (*eval_data.cache)[__data.node_num] = eval_data.r;
00671     return ret;
00672   }
00673 
00674   interval calculate_value(bool eval_all)
00675   {
00676     return eval_data.r;
00677   }
00678 };
00679 
00680 #endif /* _INTERVAL_EVALUATOR_H_ */

Generated on Tue Nov 4 01:57:58 2003 for COCONUT API by doxygen1.2.18