function.cpp

00001 #include "function.h"
00002 
00003 #include <cassert>
00004 #include <QFile>
00005 #include <QTextStream>
00006 #include <stdio.h>
00007 #include <QString>
00008 #include <QStringList>
00009 
00010 #if defined(__APPLE__) || defined(linux)
00011 #  include <sys/file.h>
00012 #endif
00013 
00014 #define REPORT_ERROR(filename, line_nb, error) \
00015   error_occured = true; \
00016   err << "Error in file " << QString::fromStdString(filename) << " on line " << line_nb << error << endl
00017 
00018 static QTextStream err(stderr);
00019 
00020 namespace util
00021 {
00022 
00025   void Function::init()
00026   {
00027     samples = 100000;
00028     cache_valid = false;
00029     error_occured = false;
00030   }
00031 
00033   Function::Function() :
00034     pts(),
00035     max(),
00036     min(),
00037     scaling_x(1),
00038     scaling_y(1),
00039     shift_x(0),
00040     shift_y(0)
00041     {
00042       init();
00043     }
00044 
00052   Function::Function(std::string filename)
00053     : FileObject(filename)
00054     , pts()
00055     , max()
00056     , min()
00057     , scaling_x(1)
00058     , scaling_y(1)
00059     , shift_x(0)
00060     , shift_y(0)
00061     {
00062       init();
00063       reread();
00064     }
00065 
00066   Function::Function(const Function& copy)
00067     : FileObject(copy)
00068     , pts(copy.pts)
00069     , max(copy.max)
00070     , min(copy.min)
00071     , samples(copy.samples)
00072     , scaling_x(copy.scaling_x)
00073     , scaling_y(copy.scaling_y)
00074     , shift_x(copy.shift_x)
00075     , shift_y(copy.shift_y)
00076     , cache_valid(copy.cache_valid)
00077     , cache(copy.cache)
00078     , error_occured(copy.error_occured)
00079   {
00080   }
00081 
00083   Function& Function::operator=(const Function& f) {
00084     FileObject::operator=(f);
00085     pts = f.pts;
00086     max = f.max;
00087     min = f.min;
00088     samples = f.samples;
00089     cache_valid = f.cache_valid;
00090     cache = f.cache;
00091     error_occured = f.error_occured;
00092     scaling_x = f.scaling_x;
00093     scaling_y = f.scaling_y;
00094     shift_x = f.shift_x;
00095     shift_y = f.shift_y;
00096     return *this;
00097   }
00098 
00099   bool Function::error() {
00100     return error_occured;
00101   }
00102 
00103   void Function::reread() {
00104     QFile f(QString::fromStdString(filename));
00105     error_occured = false;
00106     if(!f.open(QIODevice::ReadOnly))
00107     {
00108       error_occured = true;
00109       err << "Error opening file " << QString::fromStdString(filename) << ": " << f.errorString() << endl;
00110       return;
00111     }
00112 #if defined(__APPLE__) || defined(linux)
00113     flock(f.handle(), LOCK_SH);
00114 #endif
00115     QTextStream ts(&f);
00116     int ptid = 0, line_nb = 0;
00117 
00118     max = Vector<2,double>(-HUGE_VAL,-HUGE_VAL);
00119     min = Vector<2,double>(HUGE_VAL,HUGE_VAL);
00120 
00121     while(!ts.atEnd())
00122     {
00123       QString line = ts.readLine().trimmed();
00124       line_nb++;
00125       if(line.startsWith("fver"))
00126       {
00127         QStringList fields = line.split(" ");
00128         if(fields.size() != 3)
00129         {
00130           REPORT_ERROR(filename, line_nb, "cannot find major and minor in function version (fver)");
00131           return;
00132         }
00133         bool ok;
00134         int major = fields[1].toInt(&ok);
00135         if(!ok)
00136         {
00137           REPORT_ERROR(filename, line_nb, "major version number (" << fields[1] << ") is not a valid integer");
00138           return;
00139         }
00140         int minor = fields[2].toInt(&ok);
00141         if(!ok)
00142         {
00143           REPORT_ERROR(filename, line_nb, "minor version number (" << fields[2] << ") is not a valid integer");
00144           return;
00145         }
00146         if(major != 1 or minor != 1)
00147         {
00148           err << "Warning, this version usually deals with fver 1 1. Processing will continue but may fail" << endl;
00149         }
00150       }
00151       else if(line.startsWith("points:"))
00152       {
00153         QStringList fields = line.split(":");
00154         if(fields.size() != 2)
00155         {
00156           REPORT_ERROR(filename, line_nb, "Invalid point number specification, there is more than one ':'");
00157           return;
00158         }
00159         bool ok;
00160         unsigned int nbpts = fields[1].toUInt(&ok);
00161         if(!ok)
00162         {
00163           REPORT_ERROR(filename, line_nb, "Number of points (" << fields[1] << ") is not a valid integer");
00164           return;
00165         }
00166         pts.resize(nbpts);
00167       }
00168       else if(!line.contains(":")) // specification of a points
00169       {
00170         if(ptid >= (int)pts.size())
00171         {
00172           REPORT_ERROR(filename, line_nb, "There are more points than specified");
00173           return;
00174         }
00175         QStringList coords = line.split(" ");
00176         if(coords.size() != 2)
00177         {
00178           REPORT_ERROR(filename, line_nb, "There are " << coords.size() << " coordinates instead of 2");
00179           return;
00180         }
00181         double x, y;
00182         bool ok;
00183         x = coords[0].toDouble(&ok);
00184         if(!ok)
00185         {
00186           REPORT_ERROR(filename, line_nb, coords[0] << "' is not a valid double");
00187           return;
00188         }
00189         y = coords[1].toDouble(&ok);
00190         if(!ok)
00191         {
00192           REPORT_ERROR(filename, line_nb, coords[1] << "' is not a valid double");
00193           return;
00194         }
00195         if(x < min.x()) min.x() = x;
00196         if(y < min.y()) min.y() = y;
00197         if(x > max.x()) max.x() = x;
00198         if(y > max.y()) max.y() = y;
00199         Vector<2,double> p(x, y);
00200         pts[ptid++] = p;
00201       }
00202       // Otherwise, just ignore the line
00203     }
00204     if(ptid != (int)pts.size())
00205     {
00206       error_occured = true;
00207       err << "Error in file " << QString::fromStdString(filename)
00208         << ", there was " << pts.size() << " points announced, but only " << ptid << " points declared" << endl;
00209       return;
00210     }
00211 
00212     cache_valid = false;
00213 #if defined(__APPLE__) || defined(linux)
00214     flock(f.handle(), LOCK_UN);
00215 #endif
00216     f.close();
00217     //  ifstream in(filename.c_str());
00218     //  string buffer;
00219 
00220     //  if (!in || !in.good() || in.eof()) {
00221     //    error_occured = true;
00222     //    std::cerr << "Function - Cannot open file '" << filename << "'\n";
00223     //    return;
00224     //  }
00225     //  error_occured = false;
00226 
00227     //  in >> ws >> buffer;
00228 
00229     //  if (buffer == string("range:")) {
00230     //    // old version
00231 
00232     //    double rmin, rmax;
00233     //    in >> rmin >> rmax;
00234     //  }
00235     //  else if (buffer == string("fver")) {
00236     //    int major, minor;
00237     //    in >> major >> minor >> ws;
00238 
00239     //    if (major == 1 && minor == 1) {
00240     //      getline(in, buffer); // name
00241     //      getline(in, buffer); // samples
00242     //      getline(in, buffer); // flip
00243     //    }
00244     //  }
00245 
00246     //  unsigned int num;
00247     //  in >> buffer >> num;
00248 
00249     //  pts.reserve(num);
00250 
00251     //  bool first = true;
00252     //  for (unsigned int i = 0; i < num; i++) {
00253     //    double x, y;
00254     //    in >> x >> y;
00255 
00256     //    if (first) {
00257     //      max.set(x, y);
00258     //      min.set(x, y);
00259     //      first = false;
00260     //    }
00261     //    else {
00262     //      if (x > max.x()) max.x(x);
00263     //      if (y > max.y()) max.y(y);
00264     //      if (x < min.x()) min.x(x);
00265     //      if (y < min.y()) min.y(y);
00266     //    }
00267 
00268     //    Vector<2,double> p(x, y);
00269     //    pts.push_back(p);
00270     //  }
00271 
00272     //  cache_valid = false;
00273   }
00274 
00280   void Function::setSamples (size_t n)
00281   {
00282     samples = (unsigned int)n;
00283     cache_valid = false;
00284   }
00285 
00295   double Function::operator()(double x) {
00296     x += shift_x;
00297     x *= scaling_x;
00298     if (x <= min.x()) return scaling_y*pts[0].y() + shift_y;
00299     if (x >= max.x()) return scaling_y*pts[pts.size() - 1].y() + shift_y;
00300 
00301     // check for cache
00302     if (! cache_valid) {
00303       cache_valid = true;
00304       cache.resize (samples+1);
00305       for (size_t i = 0 ; i < samples ; i ++)
00306         cache[i].valid = false;
00307     }
00308     // lower index
00309     double dx = (max.x() - min.x()) / samples;
00310     size_t lo = (size_t) ((x - min.x()) / dx);
00311     size_t hi = lo + 1;
00312     // make sure we have both lo and hi
00313     double lox = min.x() + dx * lo;
00314     double hix = lox + dx;
00315     if (! cache [lo].valid) {
00316       cache [lo].valid = true;
00317       cache [lo].val = getVal (lox);
00318     }
00319     if (! cache [hi].valid) {
00320       cache [hi].valid = true;
00321       cache [hi].val = getVal (hix);
00322     }
00323     // linearly interpolate
00324     double r = (x - lox) / dx;
00325     double ret = (1-r) * cache[lo].val + r * cache[hi].val;
00326 
00327     return scaling_y*ret + shift_y;
00328   }
00329 
00334   void Function::normalizeX(bool shift)
00335   {
00336     if(shift)
00337     {
00338       shift_x = min.x();
00339       scaling_x = max.x() - min.x();
00340     }
00341     else
00342     {
00343       scaling_x = max.x();
00344     }
00345   }
00346 
00351   void Function::normalizeY(bool shift)
00352   {
00353     double ymin = HUGE_VAL, ymax = -HUGE_VAL;
00354     double dx = (max.x() - min.x()) / samples;
00355     double x0 = min.x();
00356     if (! cache_valid) {
00357       cache_valid = true;
00358       cache.resize (samples+1);
00359       for (size_t i = 0 ; i < samples ; i ++)
00360         cache[i].valid = false;
00361     }
00362     for(size_t i = 0 ; i < samples+1 ; ++i)
00363     {
00364       double y;
00365       if(cache[i].valid)
00366       {
00367         y = cache[i].val;
00368       }
00369       else
00370       {
00371         y = getVal(x0+dx*i);
00372         cache[i].valid = true;
00373         cache[i].val = y;
00374       }
00375       if(y < ymin) ymin = y;
00376       if(y > ymax) ymax = y;
00377     }
00378     if(shift)
00379     {
00380       shift_y = -ymin;
00381       if(ymax > ymin)
00382         scaling_y = 1/(ymax-ymin);
00383       else
00384         scaling_y = 1;
00385     }
00386     else
00387     {
00388       if(ymax != 0)
00389       {
00390         scaling_y = 1/ymax;
00391       }
00392       else
00393       {
00394         scaling_y = 1;
00395       }
00396     }
00397   }
00398 
00405   double Function::getVal (double x) const {
00406     const double tofind = x;
00407     const double MaxError = 0.00001; // TBD: this should be user controlled
00408     double low = 0.0;
00409     double high = 1.0;
00410     double check = 0.5;
00411     Vector<2,double> tst;
00412     int counter = 0;
00413     do {
00414       check = (low + high) / 2.0;
00415       tst = P(check);
00416       if (tst.x() > tofind)
00417         high = check;
00418       else 
00419         low = check;
00420       counter++;
00421     } while (fabs(tst.x() - tofind) > MaxError);
00422     return tst.y();
00423   }
00424 
00426   Vector<2,double> Function::P(double x) const {
00427     const int n = (unsigned int)pts.size() - 1;
00428     const int t = 4;
00429     double u = x * (double(n - t) + 2.0);
00430 
00431     Vector<2,double> sum;
00432 
00433     for (int k = 0; k <= n; k++) {
00434       double coeff = N(k, t, u);
00435       sum += pts[k] * coeff;
00436     }
00437 
00438     return sum;
00439   }
00440 
00442   double Function::N(int k, int t, double u) const {
00443     double res = 0.0;
00444     if (1==t)
00445       res = Nk1(k, u);
00446     else
00447       res = Nkt(k, t, u);
00448     return res;
00449   }
00450 
00451 
00453   double Function::Nk1(int k, double u) const {
00454     if (Uk(k) <= u)
00455     {
00456       if (u < Uk(k + 1))
00457         return 1.0;
00458     }
00459     return 0.0;
00460   }
00461 
00463   double Function::Nkt(int k, int t, double u) const {
00464     double sum = 0.0;
00465     int div = Uk(k + t - 1) - Uk(k);
00466     if (0 != div)
00467       sum = (u - Uk(k)) / div * N(k, t - 1, u);
00468 
00469     div = Uk(k + t) - Uk(k + 1);
00470     if (0 != div)
00471       sum += (Uk(k + t) - u) / div * N(k + 1, t - 1, u);
00472 
00473     return sum;
00474   }
00475 
00477   int Function::Uk(int j) const {
00478     const int n = (unsigned int)pts.size() - 1;
00479     const int t = 4;
00480     if (j < t)
00481       return 0;
00482     if (j > n)
00483       return n - t + 2;
00484     return j - t + 1;
00485   }
00486 
00488   const Vector<2,double>& Function::getMax() const {
00489     return max;
00490   }
00491 
00493   const Vector<2,double>& Function::getMin() const {
00494     return min;
00495   }
00496 
00497 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Generated on Fri May 31 15:37:53 2013 for VVE by  doxygen 1.6.3