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

cint_evaluator.h

Go to the documentation of this file.
00001 // Complex Interval Evaluator implementation -*- C++ -*-
00002 
00003 // Copyright (C) 2001-2003 Hermann Schichl, Knut Petras
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 _CINT_EVALUATOR_H_
00028 #define _CINT_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 #include <cinterval.h>
00038 
00039 using namespace vgtl;
00040 
00041 typedef cinterval (*cinterval_evaluator)(const std::vector<cinterval>* __x,
00042                                  const variable_indicator& __v);
00043 
00044 struct cinterval_eval_type
00045 {
00046   const std::vector<cinterval>* x;
00047   std::vector<cinterval>* cache;
00048   const model* mod;
00049   void *p;
00050   cinterval d;
00051   int info;
00052   cinterval r;
00053   unsigned int n;
00054 };
00055 
00056 class cinterval_eval : public
00057   cached_forward_evaluator_base<cinterval_eval_type,expression_node,cinterval,
00058                                 model::walker>
00059 {
00060 private:
00061   typedef cached_forward_evaluator_base<cinterval_eval_type,expression_node,
00062                                         cinterval,model::walker> _Base;
00063 
00064 protected:
00065   bool is_cached(const node_data_type& __data)
00066   {
00067     if(__data.operator_type == EXPRINFO_LIN ||
00068        __data.operator_type == EXPRINFO_QUAD)
00069       return true;
00070     else
00071       return false;
00072 #if 0
00073     if(eval_data.cache && __data.n_parents > 1 && __data.n_children > 0)
00074       return true;
00075     else
00076       return false;
00077 #endif
00078   }
00079 
00080 private:
00081   /*  cinterval __power(double __coeff, cinterval __x, int __exp)
00082   {
00083     if(__exp == 0)
00084       return 1.;
00085     else
00086     {
00087       cinterval k = __coeff*__x;
00088       switch(__exp)
00089       {
00090         case 1:
00091           return k;
00092           break;
00093         case 2:
00094           return sqr(k);
00095           break;
00096         case -1:
00097           return 1./k;
00098           break;
00099         case -2:
00100           return 1./sqr(k);
00101           break;
00102         default:
00103           return ipow(k, __exp);
00104           break;
00105       }
00106     }
00107     return 0;           // we never come here!
00108   }
00109   */
00110 public:
00111   cinterval_eval(const std::vector<cinterval>& __x, const variable_indicator& __v,
00112                 const model& __m, std::vector<cinterval>* __c) : _Base()
00113   {
00114     eval_data.x = &__x;
00115     eval_data.cache = __c;
00116     eval_data.mod = &__m;
00117     eval_data.d = 0.;
00118     eval_data.p = NULL;
00119     v_ind = &__v;
00120     eval_data.n = 0;
00121   }
00122 
00123   cinterval_eval(const cinterval_eval& __v) : _Base(__v) {}
00124   
00125   ~cinterval_eval() {}
00126 
00127   model::walker short_cut_to(const expression_node& __data)
00128   { return eval_data.mod->node(0); }    // return anything
00129 
00130   void initialize() { return; }
00131   
00132   int initialize(const expression_node& __data)
00133   {
00134     if(__data.ev && (*__data.ev)[FUNC_CRANGE])
00135     // is there a short-cut evaluator defined?
00136     {
00137       eval_data.r =
00138         (*(cinterval_evaluator)(*__data.ev)[FUNC_CRANGE])(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.p = (void*) new std::vector<cinterval>;
00162           ((std::vector<cinterval>*)eval_data.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 cinterval matrix
00177           break;
00178         case EXPRINFO_COND:
00179         case EXPRINFO_FEM:
00180         case EXPRINFO_MPROD:
00181           // here construct rectangular cinterval 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, cintval(0.0), NULL);
00194     }
00195     eval_data.r.intersect(__data.f_bounds);
00196   }
00197 
00198   void retrieve_from_cache(const expression_node& __data)
00199   {
00200     if(__data.operator_type == EXPRINFO_LIN)
00201     {
00202       const matrix<double>::Row& lrw(eval_data.mod->lin[__data.params.nn()]);
00203       matrix<double>::Row::const_iterator _x, _e;
00204 
00205       eval_data.r = cinterval(0.);
00206       for(_x = lrw.begin(); _x != _e; ++_x)
00207         eval_data.r += (*eval_data.x)[_x.index()] * *_x;
00208     }
00209     else if(__data.operator_type == EXPRINFO_QUAD)
00210     {
00211       throw "Interval Evaluation of QUAD: NYI!";
00212     }
00213     else
00214       eval_data.r = (*eval_data.cache)[__data.node_num];
00215   }
00216 
00217   int update(const cinterval& __rval)
00218   {
00219     eval_data.r = __rval;
00220     return 0;
00221   }
00222 
00223   int update(const expression_node& __data, const cinterval& __rval)
00224   {
00225     cinterval __x;
00226     int ret = 0;
00227     if(__data.operator_type < 0)
00228     {
00229       switch(__data.operator_type)
00230       {
00231         case EXPRINFO_CONSTANT:
00232           eval_data.r = __data.params.nd();
00233           break;
00234         case EXPRINFO_VARIABLE:
00235           eval_data.r = (*eval_data.x)[__data.params.nn()];
00236           break;
00237         case EXPRINFO_SUM:
00238         case EXPRINFO_MEAN:
00239           eval_data.r += __data.coeffs[eval_data.n++]*__rval;
00240           break;
00241         case EXPRINFO_PROD:
00242           // the coefficients MUST be collected in __data.params.nd()
00243           eval_data.r *= __rval;
00244           if(eval_data.r == 0.) ret = -1;
00245           break;
00246         case EXPRINFO_MONOME:
00247           // the coefficients MUST be collected in __data.params.nd()
00248           eval_data.r *= __power(__data.coeffs[eval_data.n], __rval,
00249                                  __data.params.n()[eval_data.n]);
00250           if(eval_data.r == 0.) ret = -1;
00251           eval_data.n++;
00252           break;
00253         case EXPRINFO_MAX:
00254           /* CHANGE HERE */
00255           { cinterval h = __rval * __data.coeffs[eval_data.n++];
00256             eval_data.r = imax(eval_data.r, h);
00257           }
00258           break;
00259         case EXPRINFO_MIN:
00260           /* CHANGE HERE */
00261           { cinterval h = __rval * __data.coeffs[eval_data.n++];
00262             eval_data.r = imin(eval_data.r, h);
00263           }
00264           break;
00265         case EXPRINFO_SCPROD:
00266           { cinterval h = __data.coeffs[eval_data.n]*__rval;
00267             // if the number of children is odd, the list is implicitly
00268             // lengthened by one null element (i.e. implicitly shortened)
00269             if(eval_data.n & 1) // y_n
00270               eval_data.r += __data.coeffs[eval_data.n]*__rval*h;
00271             else // x_n
00272               eval_data.d = h;
00273           }
00274           eval_data.n++;
00275           break;
00276         case EXPRINFO_NORM:
00277           if(__data.params.nd() != 2.)
00278           {
00279             std::cerr << "Non-euclidean norms NYI" << std::endl;
00280             throw "NYI";
00281           }
00282           else
00283           {
00284             cinterval h = __data.coeffs[eval_data.n++]*__rval;
00285             eval_data.r += sqr(h);
00286           }
00287           if(eval_data.n == __data.n_children && __data.params.nd() == 2.)
00288             eval_data.r = sqrt(eval_data.r);
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           { cinterval 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           { cinterval 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           { cinterval 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           { cinterval 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 cinterval& 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 != cinterval(-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 = cinterval(-1.,0.);
00376                 else if(eval_data.r.sup() > 0)
00377                   eval_data.r = cinterval(-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 = cinterval(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 cinterval& i(__data.params.ni());
00403             if(i.superset(__x))      // always true
00404               eval_data.info = 0;
00405             else if(i.disjoint(__x)) // never true
00406             {
00407               eval_data.info = 1;
00408               ret = 1;               // skip if part
00409             }
00410             else                     // both is possible
00411               eval_data.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.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.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 cinterval& 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 = cinterval(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 cinterval& 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 = cinterval(0.,1.);
00457             }
00458           }
00459           eval_data.n++;
00460           break;
00461         case EXPRINFO_NOT:
00462           { __x = __data.coeffs[0]*__rval;
00463             const cinterval& 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 = cinterval(0.,1.);
00470           }
00471           break;
00472         case EXPRINFO_IMPLIES:
00473           { const cinterval& 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 = cinterval(0.,1.);
00484               else
00485                 eval_data.r = cinterval(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 = cinterval(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 cinterval& 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 += cinterval(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<cinterval>::const_iterator _b =
00511                         ((std::vector<cinterval>*)eval_data.p)->begin();
00512                 _b != ((std::vector<cinterval>*)eval_data.p)->end(); ++_b)
00513             {
00514               cinterval __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 = cinterval(0.,1.);
00523             }
00524             if(ret != -1)
00525               ((std::vector<cinterval>*) eval_data.p)->push_back(__x);
00526           }
00527           eval_data.n++;
00528           if(eval_data.n == __data.n_children || ret == -1)
00529             delete (std::vector<cinterval>*) eval_data.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             cinterval _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 = cinterval(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             cinterval 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 = cinterval(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 = cinterval(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   cinterval calculate_value(bool eval_all)
00675   {
00676     return eval_data.r;
00677   }
00678 };
00679 
00680 #endif /* _CINT_EVALUATOR_H_ */

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