GNU Octave  9.1.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-2024 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 #include <type_traits>
39 
41 
42 // equivalent to isvector.m
43 
44 template <typename T>
45 bool
46 isvector (const T& array)
47 {
48  const dim_vector dv = array.dims ();
49  return dv.ndims () == 2 && (dv(0) == 1 || dv(1) == 1);
50 }
51 
52 // lookup a value in a sorted table (lookup.m)
53 template <typename T>
55 lookup (const T *x, octave_idx_type n, T y)
56 {
58 
59  if (x[0] < x[n-1])
60  {
61  // increasing x
62 
63  if (y > x[n-1] || y < x[0])
64  return -1;
65 
66 #if defined (EXHAUSTIF)
67  for (j = 0; j < n - 1; j++)
68  {
69  if (x[j] <= y && y <= x[j+1])
70  return j;
71  }
72 #else
73  octave_idx_type j0 = 0;
74  octave_idx_type j1 = n - 1;
75 
76  while (true)
77  {
78  j = (j0+j1)/2;
79 
80  if (y <= x[j+1])
81  {
82  if (x[j] <= y)
83  return j;
84 
85  j1 = j;
86  }
87 
88  if (x[j] <= y)
89  j0 = j;
90  }
91 #endif
92  }
93  else
94  {
95  // decreasing x
96  // previous code with x -> -x and y -> -y
97 
98  if (y > x[0] || y < x[n-1])
99  return -1;
100 
101 #if defined (EXHAUSTIF)
102  for (j = 0; j < n - 1; j++)
103  {
104  if (x[j+1] <= y && y <= x[j])
105  return j;
106  }
107 #else
108  octave_idx_type j0 = 0;
109  octave_idx_type j1 = n - 1;
110 
111  while (true)
112  {
113  j = (j0+j1)/2;
114 
115  if (y >= x[j+1])
116  {
117  if (x[j] >= y)
118  return j;
119 
120  j1 = j;
121  }
122 
123  if (x[j] >= y)
124  j0 = j;
125  }
126 #endif
127  }
128 }
129 
130 // n-dimensional linear interpolation
131 
132 template <typename T, typename DT>
133 void
135  octave_idx_type Ni, DT extrapval, const T **x,
136  const DT *v, const T **y, DT *vi)
137 {
138  bool out = false;
139  int bit;
140 
141  OCTAVE_LOCAL_BUFFER (T, coef, 2*n);
143 
144  // loop over all points
145  for (octave_idx_type m = 0; m < Ni; m++)
146  {
147  // loop over all dimensions
148  for (int i = 0; i < n; i++)
149  {
150  index[i] = lookup (x[i], size[i], y[i][m]);
151  out = index[i] == -1;
152 
153  if (out)
154  break;
155  else
156  {
157  octave_idx_type j = index[i];
158  coef[2*i+1] = (y[i][m] - x[i][j])/(x[i][j+1] - x[i][j]);
159  coef[2*i] = 1 - coef[2*i+1];
160  }
161  }
162 
163  if (out)
164  vi[m] = extrapval;
165  else
166  {
167  vi[m] = 0;
168 
169  // loop over all corners of hypercube (1<<n = 2^n)
170  for (int i = 0; i < (1 << n); i++)
171  {
172  T c = 1;
173  octave_idx_type l = 0;
174 
175  // loop over all dimensions
176  for (int j = 0; j < n; j++)
177  {
178  // test if the jth bit in i is set
179  bit = i >> j & 1;
180  l += scale[j] * (index[j] + bit);
181  c *= coef[2*j+bit];
182  }
183 
184  vi[m] += c * v[l];
185  }
186  }
187  }
188 }
189 
190 template <typename MT, typename DMT, typename DT>
192 lin_interpn (int n, MT *X, const DMT V, MT *Y, DT extrapval)
193 {
194  static_assert(std::is_same<DT, typename DMT::element_type>::value,
195  "Type DMT must be an ArrayType with elements of type DT.");
196  using T = typename MT::element_type;
197 
198  octave_value retval;
199 
200  DMT Vi = DMT (Y[0].dims ());
201 
202  OCTAVE_LOCAL_BUFFER (const T *, y, n);
204 
205  for (int i = 0; i < n; i++)
206  {
207  y[i] = Y[i].data ();
208  size[i] = V.dims ()(i);
209  }
210 
211  OCTAVE_LOCAL_BUFFER (const T *, x, n);
213 
214  const DT *v = V.data ();
215  DT *vi = Vi.fortran_vec ();
216  octave_idx_type Ni = Vi.numel ();
217 
218  // offset in memory of each dimension
219 
220  scale[0] = 1;
221 
222  for (int i = 1; i < n; i++)
223  scale[i] = scale[i-1] * size[i-1];
224 
225  // tests if X[0] is a vector, if yes, assume that all elements of X are
226  // in the ndgrid format.
227 
228  if (! isvector (X[0]))
229  {
230  for (int i = 0; i < n; i++)
231  {
232  if (X[i].dims () != V.dims ())
233  error ("interpn: incompatible size of argument number %d", i+1);
234 
235  MT tmp = MT (dim_vector (size[i], 1));
236 
237  for (octave_idx_type j = 0; j < size[i]; j++)
238  tmp(j) = X[i](scale[i]*j);
239 
240  X[i] = tmp;
241  }
242  }
243 
244  for (int i = 0; i < n; i++)
245  {
246  if (! isvector (X[i]) && X[i].numel () != size[i])
247  error ("interpn: incompatible size of argument number %d", i+1);
248 
249  x[i] = X[i].data ();
250  }
251 
252  lin_interpn (n, size, scale, Ni, extrapval, x, v, y, vi);
253 
254  retval = Vi;
255 
256  return retval;
257 }
258 
259 // Perform @var{n}-dimensional interpolation. Each element of then
260 // @var{n}-dimensional array @var{v} represents a value at a location
261 // given by the parameters @var{x1}, @var{x2},...,@var{xn}. The parameters
262 // @var{x1}, @var{x2}, @dots{}, @var{xn} are either @var{n}-dimensional
263 // arrays of the same size as the array @var{v} in the "ndgrid" format
264 // or vectors. The parameters @var{y1}, @var{y2}, @dots{}, @var{yn} are
265 // all @var{n}-dimensional arrays of the same size and represent the
266 // points at which the array @var{vi} is interpolated.
267 //
268 //This function only performs linear interpolation.
269 
270 DEFUN (__lin_interpn__, args, ,
271  doc: /* -*- texinfo -*-
272 @deftypefn {} {@var{vi} =} __lin_interpn__ (@var{x1}, @var{x2}, @dots{}, @var{xn}, @var{v}, @var{y1}, @var{y2}, @dots{}, @var{yn})
273 Undocumented internal function.
274 @end deftypefn */)
275 {
276  int nargin = args.length ();
277 
278  if (nargin < 2 || nargin % 2 == 0)
279  print_usage ();
280 
281  octave_value retval;
282 
283  // dimension of the problem
284  int n = (nargin-1)/2;
285 
286  if (args(n).is_single_type ())
287  {
290 
291  for (int i = 0; i < n; i++)
292  {
293  X[i] = args(i).float_array_value ();
294  Y[i] = args(n+i+1).float_array_value ();
295 
296  if (Y[0].dims () != Y[i].dims ())
297  error ("interpn: incompatible size of argument number %d", n+i+2);
298  }
299 
300  if (args(n).iscomplex ())
301  {
302  const FloatComplexNDArray V = args(n).float_complex_array_value ();
303  FloatComplex extrapval (octave_NA, octave_NA);
304  retval = lin_interpn (n, X, V, Y, extrapval);
305  }
306  else
307  {
308  const FloatNDArray V = args(n).float_array_value ();
309  float extrapval = octave_NA;
310  retval = lin_interpn (n, X, V, Y, extrapval);
311  }
312  }
313  else
314  {
317 
318  for (int i = 0; i < n; i++)
319  {
320  X[i] = args(i).array_value ();
321  Y[i] = args(n+i+1).array_value ();
322 
323  if (Y[0].dims () != Y[i].dims ())
324  error ("interpn: incompatible size of argument number %d", n+i+2);
325  }
326 
327  if (args(n).iscomplex ())
328  {
329  const ComplexNDArray V = args(n).complex_array_value ();
330  Complex extrapval (octave_NA, octave_NA);
331  retval = lin_interpn (n, X, V, Y, extrapval);
332  }
333  else
334  {
335  const NDArray V = args(n).array_value ();
336  double extrapval = octave_NA;
337  retval = lin_interpn (n, X, V, Y, extrapval);
338  }
339  }
340 
341  return retval;
342 }
343 
344 /*
345 ## Test that real and imaginary parts are interpolated the same way
346 ## and outer points are set to NA + 1i*NA
347 %!test <*61907>
348 %! x1 = 1:3;
349 %! x2 = 1:4;
350 %! v = repmat(1:4, 3, 1) + 1i * repmat((1:3)', 1, 4);
351 %! [XI2, XI1] = meshgrid(1.5:3.5, 1.5:3.5);
352 %! vi_complex = __lin_interpn__ (x1, x2, v, XI1, XI2);
353 %! vi_real = __lin_interpn__ (x1, x2, real (v), XI1, XI2);
354 %! vi_imag = __lin_interpn__ (x1, x2, imag (v), XI1, XI2);
355 %! assert (real (vi_complex), vi_real);
356 %! assert (imag (vi_complex), vi_imag);
357 */
358 
359 OCTAVE_END_NAMESPACE(octave)
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, DT extrapval, const T **x, const DT *v, const T **y, DT *vi)
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type ndims() const
Number of dimensions.
Definition: dim-vector.h:257
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage(void)
Definition: defun-int.h:72
#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:988
void scale(Matrix &m, double x, double y, double z)
Definition: graphics.cc:5500
#define octave_NA
Definition: lo-ieee.h:43
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:781
octave_idx_type n
Definition: mx-inlines.cc:761
std::complex< double > Complex
Definition: oct-cmplx.h:33
std::complex< float > FloatComplex
Definition: oct-cmplx.h:34
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44