GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
__lin_interpn__.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2007-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include "lo-ieee.h"
31 #include "dNDArray.h"
32 #include "oct-locbuf.h"
33 
34 #include "defun.h"
35 #include "error.h"
36 #include "ovl.h"
37 
38 // equivalent to isvector.m
39 
40 template <typename T>
41 bool
42 isvector (const T& array)
43 {
44  const dim_vector dv = array.dims ();
45  return dv.ndims () == 2 && (dv(0) == 1 || dv(1) == 1);
46 }
47 
48 // lookup a value in a sorted table (lookup.m)
49 template <typename T>
51 lookup (const T *x, octave_idx_type n, T y)
52 {
54 
55  if (x[0] < x[n-1])
56  {
57  // increasing x
58 
59  if (y > x[n-1] || y < x[0])
60  return -1;
61 
62 #if defined (EXHAUSTIF)
63  for (j = 0; j < n - 1; j++)
64  {
65  if (x[j] <= y && y <= x[j+1])
66  return j;
67  }
68 #else
69  octave_idx_type j0 = 0;
70  octave_idx_type j1 = n - 1;
71 
72  while (true)
73  {
74  j = (j0+j1)/2;
75 
76  if (y <= x[j+1])
77  {
78  if (x[j] <= y)
79  return j;
80 
81  j1 = j;
82  }
83 
84  if (x[j] <= y)
85  j0 = j;
86  }
87 #endif
88  }
89  else
90  {
91  // decreasing x
92  // previous code with x -> -x and y -> -y
93 
94  if (y > x[0] || y < x[n-1])
95  return -1;
96 
97 #if defined (EXHAUSTIF)
98  for (j = 0; j < n - 1; j++)
99  {
100  if (x[j+1] <= y && y <= x[j])
101  return j;
102  }
103 #else
104  octave_idx_type j0 = 0;
105  octave_idx_type j1 = n - 1;
106 
107  while (true)
108  {
109  j = (j0+j1)/2;
110 
111  if (y >= x[j+1])
112  {
113  if (x[j] >= y)
114  return j;
115 
116  j1 = j;
117  }
118 
119  if (x[j] >= y)
120  j0 = j;
121  }
122 #endif
123  }
124 }
125 
126 // n-dimensional linear interpolation
127 
128 template <typename T>
129 void
131  octave_idx_type Ni, T extrapval, const T **x,
132  const T *v, const T **y, T *vi)
133 {
134  bool out = false;
135  int bit;
136 
137  OCTAVE_LOCAL_BUFFER (T, coef, 2*n);
139 
140  // loop over all points
141  for (octave_idx_type m = 0; m < Ni; m++)
142  {
143  // loop over all dimensions
144  for (int i = 0; i < n; i++)
145  {
146  index[i] = lookup (x[i], size[i], y[i][m]);
147  out = index[i] == -1;
148 
149  if (out)
150  break;
151  else
152  {
153  octave_idx_type j = index[i];
154  coef[2*i+1] = (y[i][m] - x[i][j])/(x[i][j+1] - x[i][j]);
155  coef[2*i] = 1 - coef[2*i+1];
156  }
157  }
158 
159  if (out)
160  vi[m] = extrapval;
161  else
162  {
163  vi[m] = 0;
164 
165  // loop over all corners of hypercube (1<<n = 2^n)
166  for (int i = 0; i < (1 << n); i++)
167  {
168  T c = 1;
169  octave_idx_type l = 0;
170 
171  // loop over all dimensions
172  for (int j = 0; j < n; j++)
173  {
174  // test if the jth bit in i is set
175  bit = i >> j & 1;
176  l += scale[j] * (index[j] + bit);
177  c *= coef[2*j+bit];
178  }
179 
180  vi[m] += c * v[l];
181  }
182  }
183  }
184 }
185 
186 template <typename T, typename M>
188 lin_interpn (int n, M *X, const M V, M *Y)
189 {
191 
192  M Vi = M (Y[0].dims ());
193 
194  OCTAVE_LOCAL_BUFFER (const T *, y, n);
196 
197  for (int i = 0; i < n; i++)
198  {
199  y[i] = Y[i].data ();
200  size[i] = V.dims ()(i);
201  }
202 
203  OCTAVE_LOCAL_BUFFER (const T *, x, n);
205 
206  const T *v = V.data ();
207  T *vi = Vi.fortran_vec ();
208  octave_idx_type Ni = Vi.numel ();
209 
210  T extrapval = octave_NA;
211 
212  // offset in memory of each dimension
213 
214  scale[0] = 1;
215 
216  for (int i = 1; i < n; i++)
217  scale[i] = scale[i-1] * size[i-1];
218 
219  // tests if X[0] is a vector, if yes, assume that all elements of X are
220  // in the ndgrid format.
221 
222  if (! isvector (X[0]))
223  {
224  for (int i = 0; i < n; i++)
225  {
226  if (X[i].dims () != V.dims ())
227  error ("interpn: incompatible size of argument number %d", i+1);
228 
229  M tmp = M (dim_vector (size[i], 1));
230 
231  for (octave_idx_type j = 0; j < size[i]; j++)
232  tmp(j) = X[i](scale[i]*j);
233 
234  X[i] = tmp;
235  }
236  }
237 
238  for (int i = 0; i < n; i++)
239  {
240  if (! isvector (X[i]) && X[i].numel () != size[i])
241  error ("interpn: incompatible size of argument number %d", i+1);
242 
243  x[i] = X[i].data ();
244  }
245 
246  lin_interpn (n, size, scale, Ni, extrapval, x, v, y, vi);
247 
248  retval = Vi;
249 
250  return retval;
251 }
252 
253 // Perform @var{n}-dimensional interpolation. Each element of then
254 // @var{n}-dimensional array @var{v} represents a value at a location
255 // given by the parameters @var{x1}, @var{x2},...,@var{xn}. The parameters
256 // @var{x1}, @var{x2}, @dots{}, @var{xn} are either @var{n}-dimensional
257 // arrays of the same size as the array @var{v} in the "ndgrid" format
258 // or vectors. The parameters @var{y1}, @var{y2}, @dots{}, @var{yn} are
259 // all @var{n}-dimensional arrays of the same size and represent the
260 // points at which the array @var{vi} is interpolated.
261 //
262 //This function only performs linear interpolation.
263 
264 DEFUN (__lin_interpn__, args, ,
265  doc: /* -*- texinfo -*-
266 @deftypefn {} {@var{vi} =} __lin_interpn__ (@var{x1}, @var{x2}, @dots{}, @var{xn}, @var{v}, @var{y1}, @var{y2}, @dots{}, @var{yn})
267 Undocumented internal function.
268 @end deftypefn */)
269 {
270  int nargin = args.length ();
271 
272  if (nargin < 2 || nargin % 2 == 0)
273  print_usage ();
274 
276 
277  // dimension of the problem
278  int n = (nargin-1)/2;
279 
280  if (args(n).is_single_type ())
281  {
284 
285  const FloatNDArray V = args(n).float_array_value ();
286 
287  for (int i = 0; i < n; i++)
288  {
289  X[i] = args(i).float_array_value ();
290  Y[i] = args(n+i+1).float_array_value ();
291 
292  if (Y[0].dims () != Y[i].dims ())
293  error ("interpn: incompatible size of argument number %d", n+i+2);
294  }
295 
296  retval = lin_interpn<float, FloatNDArray> (n, X, V, Y);
297  }
298  else
299  {
302 
303  const NDArray V = args(n).array_value ();
304 
305  for (int i = 0; i < n; i++)
306  {
307  X[i] = args(i).array_value ();
308  Y[i] = args(n+i+1).array_value ();
309 
310  if (Y[0].dims () != Y[i].dims ())
311  error ("interpn: incompatible size of argument number %d", n+i+2);
312  }
313 
314  retval = lin_interpn<double, NDArray> (n, X, V, Y);
315  }
316 
317  return retval;
318 }
319 
320 /*
321 ## No test needed for internal helper function.
322 %!assert (1)
323 */
octave_idx_type lookup(const T *x, octave_idx_type n, T y)
bool isvector(const T &array)
void lin_interpn(int n, const octave_idx_type *size, const octave_idx_type *scale, octave_idx_type Ni, T extrapval, const T **x, const T *v, const T **y, T *vi)
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:334
OCTINTERP_API void print_usage(void)
Definition: defun.cc:53
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void error(const char *fmt,...)
Definition: error.cc:968
void scale(Matrix &m, double x, double y, double z)
Definition: graphics.cc:5846
#define octave_NA
Definition: lo-ieee.h:41
F77_RET_T const F77_INT const F77_INT const F77_INT const F77_DBLE const F77_DBLE F77_INT & M
F77_RET_T const F77_INT const F77_INT const F77_INT const F77_DBLE const F77_DBLE F77_INT F77_DBLE * V
F77_RET_T const F77_DBLE * x
T octave_idx_type m
Definition: mx-inlines.cc:773
octave_idx_type n
Definition: mx-inlines.cc:753
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811