__lin_interpn__.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2007-2012 Alexander Barth
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include "lo-ieee.h"
00028 #include "dNDArray.h"
00029 #include "oct-locbuf.h"
00030 
00031 #include "defun-dld.h"
00032 #include "error.h"
00033 #include "oct-obj.h"
00034 
00035 // equivalent to isvector.m
00036 
00037 template <class T>
00038 bool
00039 isvector (const T& array)
00040 {
00041   const dim_vector dv = array.dims ();
00042   return dv.length () == 2 && (dv(0) == 1 || dv(1) == 1);
00043 }
00044 
00045 // lookup a value in a sorted table (lookup.m)
00046 template <class T>
00047 octave_idx_type
00048 lookup (const T *x, octave_idx_type n, T y)
00049 {
00050   octave_idx_type j;
00051 
00052   if (x[0] < x[n-1])
00053     {
00054       // increasing x
00055 
00056       if (y > x[n-1] || y < x[0])
00057         return -1;
00058 
00059 #ifdef EXHAUSTIF
00060       for (j = 0; j < n - 1; j++)
00061         {
00062           if (x[j] <= y && y <= x[j+1])
00063             return j;
00064         }
00065 #else
00066       octave_idx_type j0 = 0;
00067       octave_idx_type j1 = n - 1;
00068 
00069       while (true)
00070         {
00071           j = (j0+j1)/2;
00072 
00073           if (y <= x[j+1])
00074             {
00075               if (x[j] <= y)
00076                 return j;
00077 
00078               j1 = j;
00079             }
00080 
00081           if (x[j] <= y)
00082             j0 = j;
00083         }
00084 #endif
00085     }
00086   else
00087     {
00088       // decreasing x
00089       // previous code with x -> -x and y -> -y
00090 
00091       if (y > x[0] || y < x[n-1])
00092         return -1;
00093 
00094 #ifdef EXHAUSTIF
00095       for (j = 0; j < n - 1; j++)
00096         {
00097           if (x[j+1] <= y && y <= x[j])
00098             return j;
00099         }
00100 #else
00101       octave_idx_type j0 = 0;
00102       octave_idx_type j1 = n - 1;
00103 
00104       while (true)
00105         {
00106           j = (j0+j1)/2;
00107 
00108           if (y >= x[j+1])
00109             {
00110               if (x[j] >= y)
00111                 return j;
00112 
00113               j1 = j;
00114             }
00115 
00116           if (x[j] >= y)
00117             j0 = j;
00118         }
00119 #endif
00120     }
00121 }
00122 
00123 // n-dimensional linear interpolation
00124 
00125 template <class T>
00126 void
00127 lin_interpn (int n, const octave_idx_type *size, const octave_idx_type *scale,
00128              octave_idx_type Ni, T extrapval, const T **x,
00129              const T *v, const T **y, T *vi)
00130 {
00131   bool out = false;
00132   int bit;
00133 
00134   OCTAVE_LOCAL_BUFFER (T, coef, 2*n);
00135   OCTAVE_LOCAL_BUFFER (octave_idx_type, index, n);
00136 
00137   // loop over all points
00138   for (octave_idx_type m = 0; m < Ni; m++)
00139     {
00140       // loop over all dimensions
00141       for (int i = 0; i < n; i++)
00142         {
00143           index[i] = lookup (x[i], size[i], y[i][m]);
00144           out = index[i] == -1;
00145 
00146           if (out)
00147             break;
00148           else
00149             {
00150               octave_idx_type j = index[i];
00151               coef[2*i+1] = (y[i][m] - x[i][j])/(x[i][j+1] - x[i][j]);
00152               coef[2*i] = 1 - coef[2*i+1];
00153             }
00154         }
00155 
00156 
00157       if (out)
00158         vi[m] = extrapval;
00159       else
00160         {
00161           vi[m] = 0;
00162 
00163           // loop over all corners of hypercube (1<<n = 2^n)
00164           for (int i = 0; i < (1 << n); i++)
00165             {
00166               T c = 1;
00167               octave_idx_type l = 0;
00168 
00169               // loop over all dimensions
00170               for (int j = 0; j < n; j++)
00171                 {
00172                   // test if the jth bit in i is set
00173                   bit = i >> j & 1;
00174                   l += scale[j] * (index[j] + bit);
00175                   c *= coef[2*j+bit];
00176                 }
00177 
00178               vi[m] += c * v[l];
00179             }
00180         }
00181     }
00182 }
00183 
00184 template <class T, class M>
00185 octave_value
00186 lin_interpn (int n, M *X, const M V, M *Y)
00187 {
00188   octave_value retval;
00189 
00190   M Vi = M (Y[0].dims ());
00191 
00192   OCTAVE_LOCAL_BUFFER (const T *, y, n);
00193   OCTAVE_LOCAL_BUFFER (octave_idx_type, size, n);
00194 
00195   for (int i = 0; i < n; i++)
00196     {
00197       y[i] = Y[i].data ();
00198       size[i] =  V.dims()(i);
00199     }
00200 
00201   OCTAVE_LOCAL_BUFFER (const T *, x, n);
00202   OCTAVE_LOCAL_BUFFER (octave_idx_type, scale, n);
00203 
00204   const T *v = V.data ();
00205   T *vi = Vi.fortran_vec ();
00206   octave_idx_type Ni = Vi.numel ();
00207 
00208   T extrapval = octave_NA;
00209 
00210   // offset in memory of each dimension
00211 
00212   scale[0] = 1;
00213 
00214   for (int i = 1; i < n; i++)
00215     scale[i] = scale[i-1] * size[i-1];
00216 
00217   // tests if X[0] is a vector, if yes, assume that all elements of X are
00218   // in the ndgrid format.
00219 
00220   if (! isvector (X[0]))
00221     {
00222       for (int i = 0; i < n; i++)
00223         {
00224           if (X[i].dims () != V.dims ())
00225             {
00226               error ("interpn: incompatible size of argument number %d", i+1);
00227               return retval;
00228             }
00229           else
00230             {
00231               M tmp = M (dim_vector (size[i], 1));
00232 
00233               for (octave_idx_type j = 0; j < size[i]; j++)
00234                 tmp(j) =  X[i](scale[i]*j);
00235 
00236               X[i] = tmp;
00237             }
00238         }
00239     }
00240 
00241   for (int i = 0; i < n; i++)
00242     {
00243       if (! isvector (X[i]) && X[i].numel () != size[i])
00244         {
00245           error ("interpn: incompatible size of argument number %d", i+1);
00246           return retval;
00247         }
00248       else
00249         x[i] = X[i].data ();
00250     }
00251 
00252   lin_interpn (n, size, scale, Ni, extrapval, x, v, y, vi);
00253 
00254   retval = Vi;
00255 
00256   return retval;
00257 }
00258 
00259 // Perform @var{n}-dimensional interpolation.  Each element of then
00260 // @var{n}-dimensional array @var{v} represents a value at a location
00261 // given by the parameters @var{x1}, @var{x2},...,@var{xn}. The parameters
00262 // @var{x1}, @var{x2}, @dots{}, @var{xn} are either @var{n}-dimensional
00263 // arrays of the same size as the array @var{v} in the \"ndgrid\" format
00264 // or vectors.  The parameters @var{y1}, @var{y2}, @dots{}, @var{yn} are
00265 // all @var{n}-dimensional arrays of the same size and represent the
00266 // points at which the array @var{vi} is interpolated.
00267 //
00268 //This function only performs linear interpolation.
00269 
00270 DEFUN_DLD (__lin_interpn__, args, ,
00271   "-*- texinfo -*-\n\
00272 @deftypefn {Loadable Function} {@var{vi} =} __lin_interpn__ (@var{x1}, @var{x2}, @dots{}, @var{xn}, @var{v}, @var{y1}, @var{y2}, @dots{}, @var{yn})\n\
00273 Undocumented internal function.\n\
00274 @end deftypefn")
00275 {
00276   octave_value retval;
00277 
00278   int nargin = args.length ();
00279 
00280   if (nargin < 2 ||  nargin % 2 == 0)
00281     {
00282       print_usage ();
00283       return retval;
00284     }
00285 
00286   // dimension of the problem
00287   int n = (nargin-1)/2;
00288 
00289   if (args(n).is_single_type())
00290     {
00291       OCTAVE_LOCAL_BUFFER (FloatNDArray, X, n);
00292       OCTAVE_LOCAL_BUFFER (FloatNDArray, Y, n);
00293 
00294       const FloatNDArray V = args(n).float_array_value ();
00295 
00296       if (error_state)
00297         {
00298           print_usage ();
00299           return retval;
00300         }
00301 
00302       for (int i = 0; i < n; i++)
00303         {
00304           X[i] = args(i).float_array_value ();
00305           Y[i] = args(n+i+1).float_array_value ();
00306 
00307           if (error_state)
00308             {
00309               print_usage ();
00310               return retval;
00311             }
00312 
00313           if (Y[0].dims () != Y[i].dims ())
00314             {
00315               error ("interpn: incompatible size of argument number %d", n+i+2);
00316               return retval;
00317             }
00318         }
00319 
00320       retval = lin_interpn<float, FloatNDArray> (n, X, V, Y);
00321     }
00322   else
00323     {
00324       OCTAVE_LOCAL_BUFFER (NDArray, X, n);
00325       OCTAVE_LOCAL_BUFFER (NDArray, Y, n);
00326 
00327       const NDArray V = args(n).array_value ();
00328 
00329       if (error_state)
00330         {
00331           print_usage ();
00332           return retval;
00333         }
00334 
00335       for (int i = 0; i < n; i++)
00336         {
00337           X[i] = args(i).array_value ();
00338           Y[i] = args(n+i+1).array_value ();
00339 
00340           if (error_state)
00341             {
00342               print_usage ();
00343               return retval;
00344             }
00345 
00346           if (Y[0].dims () != Y[i].dims ())
00347             {
00348               error ("interpn: incompatible size of argument number %d", n+i+2);
00349               return retval;
00350             }
00351         }
00352 
00353       retval = lin_interpn<double, NDArray> (n, X, V, Y);
00354     }
00355 
00356   return retval;
00357 }
00358 
00359 /*
00360 
00361 ## No test needed for internal helper function.
00362 %!assert (1)
00363 
00364 */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines