GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
filter.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-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 // Based on Tony Richardson's filter.m.
27 //
28 // Originally translated to C++ by KH (Kurt.Hornik@wu-wien.ac.at)
29 // with help from Fritz Leisch and Andreas Weingessel on Oct 20, 1994.
30 //
31 // Rewritten to use templates to handle both real and complex cases by
32 // jwe, Wed Nov 1 19:15:29 1995.
33 
34 #if defined (HAVE_CONFIG_H)
35 # include "config.h"
36 #endif
37 
38 #include "quit.h"
39 
40 #include "defun.h"
41 #include "error.h"
42 #include "ovl.h"
43 
45 
46 template <typename T>
49  int dim = 0)
50 {
51  MArray<T> y;
52 
53  octave_idx_type a_len = a.numel ();
54  octave_idx_type b_len = b.numel ();
55 
56  octave_idx_type ab_len = (a_len > b_len ? a_len : b_len);
57 
58  // FIXME: The two lines below should be unnecessary because
59  // this template is called with a and b as column vectors
60  // already. However the a.resize line is currently (2011/04/26)
61  // necessary to stop bug #33164.
62  b.resize (dim_vector (ab_len, 1), 0.0);
63  if (a_len > 1)
64  a.resize (dim_vector (ab_len, 1), 0.0);
65 
66  T norm = a (0);
67 
68  if (norm == static_cast<T> (0.0))
69  error ("filter: the first element of A must be nonzero");
70 
71  dim_vector x_dims = x.dims ();
72  if (dim < 0 || dim > x_dims.ndims ())
73  error ("filter: DIM must be a valid dimension");
74 
75  octave_idx_type x_len = x_dims(dim);
76 
77  dim_vector si_dims = si.dims ();
78  octave_idx_type si_len = si_dims(0);
79 
80  if (si_len != ab_len - 1)
81  error ("filter: first dimension of SI must be of length max (length (a), length (b)) - 1");
82 
83  if (si_dims.ndims () != x_dims.ndims ())
84  error ("filter: dimensionality of SI and X must agree");
85 
86  for (octave_idx_type i = 1; i < dim; i++)
87  {
88  if (si_dims(i) != x_dims(i-1))
89  error ("filter: dimensionality of SI and X must agree");
90  }
91  for (octave_idx_type i = dim+1; i < x_dims.ndims (); i++)
92  {
93  if (si_dims(i) != x_dims(i))
94  error ("filter: dimensionality of SI and X must agree");
95  }
96 
97  if (x_len == 0)
98  return x;
99 
100  if (norm != static_cast<T> (1.0))
101  {
102  a /= norm;
103  b /= norm;
104  }
105 
106  if (a_len <= 1 && si_len <= 0)
107  return b(0) * x;
108 
109  // Here onwards, either a_len > 1 or si_len >= 1 or both.
110 
111  y.resize (x_dims, 0.0);
112 
113  octave_idx_type x_stride = 1;
114  for (int i = 0; i < dim; i++)
115  x_stride *= x_dims(i);
116 
117  octave_idx_type x_num = x_dims.numel () / x_len;
118  // For deconv and fftfilt, x_num seems to always be 1.
119  // For directly calling filter, it can be more than 1.
120 
121  for (octave_idx_type num = 0; num < x_num; num++)
122  {
123  octave_idx_type x_offset = (x_stride == 1) ? num * x_len
124  : num + (num / x_stride) * x_stride * (x_len - 1);
125 
126  octave_idx_type si_offset = num * si_len;
127 
128  // Try to achieve a balance between speed and interruptibility.
129  //
130  // One extreme is to not check for interruptions at all, which gives
131  // good speed but the user cannot use Ctrl-C for the whole duration.
132  // The other end is to check frequently from inside an inner loop,
133  // which slows down performance by 5X or 6X.
134  //
135  // Putting any sort of check in an inner loop seems to prevent the
136  // compiler from optimizing the loop, so we cannot say "check for
137  // interruptions every M iterations" using an if-statement.
138  //
139  // This is a compromise approach to split the total numer of loop
140  // executions into num_outer and num_inner, to provide periodic checks
141  // for interruptions without writing a conditional inside a tight loop.
142  //
143  // To make it more interruptible and run more slowly, reduce num_inner.
144  // To speed it up but make it less interruptible, increase it.
145  // May need to increase it slowly over time as computers get faster.
146  // The aim is to not lose Ctrl-C ability for longer than about 2 seconds.
147  //
148  // In December 2021, num_inner = 100000 is acceptable.
149 
150  octave_idx_type num_execs = si_len-1; // 0 to num_execs-1
151  octave_idx_type num_inner = 100000;
152  octave_idx_type num_outer = num_execs / num_inner;
153 
154  // The following if-else block depends on a_len and si_len,
155  // both of which are loop invariants in this 0 <= num < x_num loop.
156  // But x_num is so small in practice that using the if-else inside
157  // the loop has more benefits than duplicating the outer for-loop,
158  // even though the checks are on loop invariants.
159 
160  // We cannot have a_len <= 1 AND si_len <= 0 because that case already
161  // returned above. This means exactly one of the following blocks
162  // inside the if-conditional will be obeyed: it is not possible for the
163  // if-block and the else-block to *both* skip. Therefore any code that
164  // is common to both branches can be pulled out here without affecting
165  // correctness or speed.
166 
167  T *py = y.fortran_vec ();
168  T *psi = si.fortran_vec ();
169  const T *pb = b.data ();
170  const T *px = x.data ();
171  psi += si_offset;
172 
173  if (a_len > 1)
174  {
175  const T *pa = a.data ();
176 
177  // Usually the last element to be written will be si_len-1
178  // but if si_len is 0, then we need the 0th element to be written.
179  // Pulling this check out of the for-loop makes it run faster.
180  octave_idx_type iidx = (si_len > 0) ? si_len-1 : 0;
181 
182  for (octave_idx_type i = 0, idx = x_offset;
183  i < x_len;
184  i++, idx += x_stride)
185  {
186  py[idx] = psi[0] + pb[0] * px[idx];
187 
188  // Outer and inner loops for interruption management
189  for (octave_idx_type u = 0; u <= num_outer; u++)
190  {
191  octave_idx_type lo = u * num_inner;
192  octave_idx_type hi = (lo + num_inner < num_execs-1)
193  ? lo + num_inner : num_execs-1;
194 
195  // Inner loop, no interruption
196  for (octave_idx_type j = lo; j <= hi; j++)
197  psi[j] = psi[j+1] - pa[j+1] * py[idx] + pb[j+1] * px[idx];
198 
199  octave_quit(); // Check for interruptions
200  }
201 
202  psi[iidx] = pb[si_len] * px[idx] - pa[si_len] * py[idx];
203  }
204  }
205  else // a_len <= 1 ==> si_len MUST be > 0
206  {
207  // This else-block is almost the same as the above if-block,
208  // except for the absence of variable pa.
209 
210  for (octave_idx_type i = 0, idx = x_offset;
211  i < x_len;
212  i++, idx += x_stride)
213  {
214  py[idx] = psi[0] + pb[0] * px[idx];
215 
216  // Outer and inner loops for interruption management
217  for (octave_idx_type u = 0; u <= num_outer; u++)
218  {
219  octave_idx_type lo = u * num_inner;
220  octave_idx_type hi = (lo + num_inner < num_execs-1)
221  ? lo + num_inner : num_execs-1;
222 
223  // Inner loop, no interruption
224  for (octave_idx_type j = lo; j <= hi; j++)
225  psi[j] = psi[j+1] + pb[j+1] * px[idx];
226 
227  octave_quit(); // Check for interruptions
228  }
229 
230  psi[si_len-1] = pb[si_len] * px[idx];
231  }
232  }
233  }
234 
235  return y;
236 }
237 
238 template <typename T>
239 MArray<T>
240 filter (MArray<T>& b, MArray<T>& a, MArray<T>& x, int dim = -1)
241 {
242  dim_vector x_dims = x.dims ();
243 
244  if (dim < 0)
245  dim = x_dims.first_non_singleton ();
246  else if (dim > x_dims.ndims ())
247  error ("filter: DIM must be a valid dimension");
248 
249  octave_idx_type a_len = a.numel ();
250  octave_idx_type b_len = b.numel ();
251 
252  octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
253  dim_vector si_dims = x.dims ();
254  for (int i = dim; i > 0; i--)
255  si_dims(i) = si_dims(i-1);
256  si_dims(0) = si_len;
257 
258  MArray<T> si (si_dims, T (0.0));
259 
260  return filter (b, a, x, si, dim);
261 }
262 
263 DEFUN (filter, args, ,
264  doc: /* -*- texinfo -*-
265 @deftypefn {} {@var{y} =} filter (@var{b}, @var{a}, @var{x})
266 @deftypefnx {} {[@var{y}, @var{sf}] =} filter (@var{b}, @var{a}, @var{x}, @var{si})
267 @deftypefnx {} {[@var{y}, @var{sf}] =} filter (@var{b}, @var{a}, @var{x}, [], @var{dim})
268 @deftypefnx {} {[@var{y}, @var{sf}] =} filter (@var{b}, @var{a}, @var{x}, @var{si}, @var{dim})
269 Apply a 1-D digital filter to the data @var{x}.
270 
271 @code{filter} returns the solution to the following linear, time-invariant
272 difference equation:
273 @tex
274 $$
275 \sum_{k=0}^N a_{k+1} y_{n-k} = \sum_{k=0}^M b_{k+1} x_{n-k}, \qquad
276  1 \le n \le P
277 $$
278 @end tex
279 @ifnottex
280 @c Set example in small font to prevent overfull line
281 
282 @smallexample
283 @group
284  N M
285 SUM a(k+1) y(n-k) = SUM b(k+1) x(n-k) for 1<=n<=length(x)
286 k=0 k=0
287 @end group
288 @end smallexample
289 
290 @end ifnottex
291 
292 @noindent
293 where
294 @ifnottex
295 N=length(a)-1 and M=length(b)-1.
296 @end ifnottex
297 @tex
298 $a \in \Re^{N-1}$, $b \in \Re^{M-1}$, and $x \in \Re^P$.
299 @end tex
300 The result is calculated over the first non-singleton dimension of @var{x}
301 or over @var{dim} if supplied.
302 
303 An equivalent form of the equation is:
304 @tex
305 $$
306 y_n = -\sum_{k=1}^N c_{k+1} y_{n-k} + \sum_{k=0}^M d_{k+1} x_{n-k}, \qquad
307  1 \le n \le P
308 $$
309 @end tex
310 @ifnottex
311 @c Set example in small font to prevent overfull line
312 
313 @smallexample
314 @group
315  N M
316 y(n) = - SUM c(k+1) y(n-k) + SUM d(k+1) x(n-k) for 1<=n<=length(x)
317  k=1 k=0
318 @end group
319 @end smallexample
320 
321 @end ifnottex
322 
323 @noindent
324 where
325 @ifnottex
326  c = a/a(1) and d = b/a(1).
327 @end ifnottex
328 @tex
329 $c = a/a_1$ and $d = b/a_1$.
330 @end tex
331 
332 If the fourth argument @var{si} is provided, it is taken as the
333 initial state of the system and the final state is returned as
334 @var{sf}. The state vector is a column vector whose length is
335 equal to the length of the longest coefficient vector minus one.
336 If @var{si} is not supplied, the initial state vector is set to all
337 zeros.
338 
339 In terms of the Z Transform, @var{y} is the result of passing the
340 discrete-time signal @var{x} through a system characterized by the following
341 rational system function:
342 @tex
343 $$
344 H(z) = {\displaystyle\sum_{k=0}^M d_{k+1} z^{-k}
345  \over 1 + \displaystyle\sum_{k+1}^N c_{k+1} z^{-k}}
346 $$
347 @end tex
348 @ifnottex
349 
350 @example
351 @group
352  M
353  SUM d(k+1) z^(-k)
354  k=0
355 H(z) = ---------------------
356  N
357  1 + SUM c(k+1) z^(-k)
358  k=1
359 @end group
360 @end example
361 
362 @end ifnottex
363 @seealso{filter2, fftfilt, freqz}
364 @end deftypefn */)
365 {
366  int nargin = args.length ();
367 
368  if (nargin < 3 || nargin > 5)
369  print_usage ();
370 
371  int dim;
372  dim_vector x_dims = args(2).dims ();
373 
374  if (nargin == 5)
375  {
376  dim = args(4).nint_value () - 1;
377  if (dim < 0 || dim >= x_dims.ndims ())
378  error ("filter: DIM must be a valid dimension");
379  }
380  else
381  dim = x_dims.first_non_singleton ();
382 
383  octave_value_list retval;
384 
385  const char *a_b_errmsg = "filter: A and B must be vectors";
386  const char *x_si_errmsg = "filter: X and SI must be arrays";
387 
388  bool isfloat = (args(0).is_single_type ()
389  || args(1).is_single_type ()
390  || args(2).is_single_type ()
391  || (nargin >= 4 && args(3).is_single_type ()));
392 
393  if (args(0).iscomplex ()
394  || args(1).iscomplex ()
395  || args(2).iscomplex ()
396  || (nargin >= 4 && args(3).iscomplex ()))
397  {
398  if (isfloat)
399  {
400  FloatComplexColumnVector b = args(0).xfloat_complex_vector_value (a_b_errmsg);
401  FloatComplexColumnVector a = args(1).xfloat_complex_vector_value (a_b_errmsg);
402  FloatComplexNDArray x = args(2).xfloat_complex_array_value (x_si_errmsg);
403 
405 
406  if (nargin == 3 || args(3).isempty ())
407  {
408  octave_idx_type a_len = a.numel ();
409  octave_idx_type b_len = b.numel ();
410 
411  octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
412 
413  dim_vector si_dims = x.dims ();
414  for (int i = dim; i > 0; i--)
415  si_dims(i) = si_dims(i-1);
416  si_dims(0) = si_len;
417 
418  si.resize (si_dims, 0.0);
419  }
420  else
421  {
422  si = args(3).xfloat_complex_array_value (x_si_errmsg);
423 
424  if (si.isvector () && x.isvector ())
425  si = si.reshape (dim_vector (si.numel (), 1));
426  }
427 
428  FloatComplexNDArray y (filter (b, a, x, si, dim));
429 
430  retval = ovl (y, si);
431  }
432  else
433  {
434  ComplexColumnVector b = args(0).xcomplex_vector_value (a_b_errmsg);
435  ComplexColumnVector a = args(1).xcomplex_vector_value (a_b_errmsg);
436 
437  ComplexNDArray x = args(2).xcomplex_array_value (x_si_errmsg);
438 
439  ComplexNDArray si;
440 
441  if (nargin == 3 || args(3).isempty ())
442  {
443  octave_idx_type a_len = a.numel ();
444  octave_idx_type b_len = b.numel ();
445 
446  octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
447 
448  dim_vector si_dims = x.dims ();
449  for (int i = dim; i > 0; i--)
450  si_dims(i) = si_dims(i-1);
451  si_dims(0) = si_len;
452 
453  si.resize (si_dims, 0.0);
454  }
455  else
456  {
457  si = args(3).xcomplex_array_value (x_si_errmsg);
458 
459  if (si.isvector () && x.isvector ())
460  si = si.reshape (dim_vector (si.numel (), 1));
461  }
462 
463  ComplexNDArray y (filter (b, a, x, si, dim));
464 
465  retval = ovl (y, si);
466  }
467  }
468  else
469  {
470  if (isfloat)
471  {
472  FloatColumnVector b = args(0).xfloat_vector_value (a_b_errmsg);
473  FloatColumnVector a = args(1).xfloat_vector_value (a_b_errmsg);
474 
475  FloatNDArray x = args(2).xfloat_array_value (x_si_errmsg);
476 
477  FloatNDArray si;
478 
479  if (nargin == 3 || args(3).isempty ())
480  {
481  octave_idx_type a_len = a.numel ();
482  octave_idx_type b_len = b.numel ();
483 
484  octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
485 
486  dim_vector si_dims = x.dims ();
487  for (int i = dim; i > 0; i--)
488  si_dims(i) = si_dims(i-1);
489  si_dims(0) = si_len;
490 
491  si.resize (si_dims, 0.0);
492  }
493  else
494  {
495  si = args(3).xfloat_array_value (x_si_errmsg);
496 
497  if (si.isvector () && x.isvector ())
498  si = si.reshape (dim_vector (si.numel (), 1));
499  }
500 
501  FloatNDArray y (filter (b, a, x, si, dim));
502 
503  retval = ovl (y, si);
504  }
505  else
506  {
507  ColumnVector b = args(0).xvector_value (a_b_errmsg);
508  ColumnVector a = args(1).xvector_value (a_b_errmsg);
509 
510  NDArray x = args(2).xarray_value (x_si_errmsg);
511 
512  NDArray si;
513 
514  if (nargin == 3 || args(3).isempty ())
515  {
516  octave_idx_type a_len = a.numel ();
517  octave_idx_type b_len = b.numel ();
518 
519  octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
520 
521  dim_vector si_dims = x.dims ();
522  for (int i = dim; i > 0; i--)
523  si_dims(i) = si_dims(i-1);
524  si_dims(0) = si_len;
525 
526  si.resize (si_dims, 0.0);
527  }
528  else
529  {
530  si = args(3).xarray_value (x_si_errmsg);
531 
532  if (si.isvector () && x.isvector ())
533  si = si.reshape (dim_vector (si.numel (), 1));
534  }
535 
536  NDArray y (filter (b, a, x, si, dim));
537 
538  retval = ovl (y, si);
539  }
540  }
541 
542  return retval;
543 }
544 
545 template MArray<double>
547  MArray<double>&, int dim);
548 
549 template MArray<double>
551 
552 template MArray<Complex>
554  MArray<Complex>&, int dim);
555 
556 template MArray<Complex>
558 
559 template MArray<float>
561  MArray<float>&, int dim);
562 
563 template MArray<float>
565 
566 template MArray<FloatComplex>
568  MArray<FloatComplex>&, int dim);
569 
570 template MArray<FloatComplex>
572  int dim);
573 
574 /*
575 %!shared a, b, x, r
576 %!test
577 %! a = [1 1];
578 %! b = [1 1];
579 %! x = zeros (1,10); x(1) = 1;
580 %! assert (filter (b, [1], x ), [1 1 0 0 0 0 0 0 0 0]);
581 %! assert (filter (b, [1], x.'), [1 1 0 0 0 0 0 0 0 0].');
582 %! assert (filter (b.', [1], x ), [1 1 0 0 0 0 0 0 0 0] );
583 %! assert (filter (b.', [1], x.'), [1 1 0 0 0 0 0 0 0 0].');
584 %! assert (filter ([1], a, x ), [+1 -1 +1 -1 +1 -1 +1 -1 +1 -1] );
585 %! assert (filter ([1], a, x.'), [+1 -1 +1 -1 +1 -1 +1 -1 +1 -1].');
586 %! assert (filter ([1], a.', x ), [+1 -1 +1 -1 +1 -1 +1 -1 +1 -1] );
587 %! assert (filter ([1], a.', x.'), [+1 -1 +1 -1 +1 -1 +1 -1 +1 -1].');
588 %! assert (filter (b, a, x ), [1 0 0 0 0 0 0 0 0 0] );
589 %! assert (filter (b.', a, x ), [1 0 0 0 0 0 0 0 0 0] );
590 %! assert (filter (b, a.', x ), [1 0 0 0 0 0 0 0 0 0] );
591 %! assert (filter (b.', a, x ), [1 0 0 0 0 0 0 0 0 0] );
592 %! assert (filter (b, a, x.'), [1 0 0 0 0 0 0 0 0 0].');
593 %! assert (filter (b.', a, x.'), [1 0 0 0 0 0 0 0 0 0].');
594 %! assert (filter (b, a.', x.'), [1 0 0 0 0 0 0 0 0 0].');
595 %! assert (filter (b.', a, x.'), [1 0 0 0 0 0 0 0 0 0].');
596 
597 %!test
598 %! r = sqrt (1/2) * (1+i);
599 %! a = a*r;
600 %! b = b*r;
601 %! assert (filter (b, [1], x ), r*[1 1 0 0 0 0 0 0 0 0] );
602 %! assert (filter (b, [1], r*x ), r*r*[1 1 0 0 0 0 0 0 0 0] );
603 %! assert (filter (b, [1], x.' ), r*[1 1 0 0 0 0 0 0 0 0].' );
604 %! assert (filter (b, a, x ), [1 0 0 0 0 0 0 0 0 0], eps);
605 %! assert (filter (b, a, r*x ), r*[1 0 0 0 0 0 0 0 0 0], eps);
606 
607 %!shared a, b, x, y, so
608 %!test
609 %! a = [1,1];
610 %! b = [1,1];
611 %! x = zeros (1,10); x(1) = 1;
612 %! [y, so] = filter (b, [1], x, [-1]);
613 %! assert (y, [0 1 0 0 0 0 0 0 0 0]);
614 %! assert (so, 0);
615 
616 %!test
617 %! x = zeros (10,3); x(1,1) = -1; x(1,2) = 1;
618 %! y0 = zeros (10,3); y0(1:2,1) = -1; y0(1:2,2) = 1;
619 %! y = filter (b, [1], x);
620 %! assert (y, y0);
621 
622 %!test
623 %! a = [1,1];
624 %! b=[1,1];
625 %! x = zeros (4,4,2); x(1,1:4,1) = +1; x(1,1:4,2) = -1;
626 %! y0 = zeros (4,4,2); y0(1:2,1:4,1) = +1; y0(1:2,1:4,2) = -1;
627 %! y = filter (b, [1], x);
628 %! assert (y, y0);
629 
630 %!assert (filter (1, ones (10,1) / 10, []), [])
631 %!assert (filter (1, ones (10,1) / 10, zeros (0,10)), zeros (0,10))
632 %!assert (filter (1, ones (10,1) / 10, single (1:5)),
633 %! repmat (single (10), 1, 5))
634 
635 ## Test using initial conditions
636 %!assert (filter ([1, 1, 1], [1, 1], [1 2], [1, 1]), [2 2])
637 %!assert (filter ([1, 1, 1], [1, 1], [1 2], [1, 1]'), [2 2])
638 %!assert (filter ([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]), [5 7; 6 10; 14 18])
639 %!error filter ([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]')
640 %!assert (filter ([1, 3, 2], [1], [1 2; 3 4; 5 6], [1 0 0; 1 0 0], 2),
641 %! [2 6; 3 13; 5 21])
642 
643 ## Test of DIM parameter
644 %!test
645 %! x = ones (2, 1, 3, 4);
646 %! x(1,1,:,:) = [1 2 3 4; 5 6 7 8; 9 10 11 12];
647 %! y0 = [1 1 6 2 15 3 2 1 8 2 18 3 3 1 10 2 21 3 4 1 12 2 24 3];
648 %! y0 = reshape (y0, size (x));
649 %! y = filter ([1 1 1], 1, x, [], 3);
650 %! assert (y, y0);
651 */
652 
653 OCTAVE_END_NAMESPACE(octave)
T * fortran_vec()
Size of the specified dimension.
Definition: Array-base.cc:1764
bool isvector() const
Size of the specified dimension.
Definition: Array.h:654
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array-base.cc:1023
const T * data() const
Size of the specified dimension.
Definition: Array.h:663
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:503
octave_idx_type numel() const
Number of elements in the array.
Definition: Array.h:414
Template for N-dimensional array classes with like-type math operators.
Definition: MArray.h:63
MArray< T > reshape(const dim_vector &new_dims) const
Definition: MArray.h:87
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:335
octave_idx_type ndims() const
Number of dimensions.
Definition: dim-vector.h:257
int first_non_singleton(int def=0) const
Definition: dim-vector.h:444
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
MArray< T > filter(MArray< T > &b, MArray< T > &a, MArray< T > &x, MArray< T > &si, int dim=0)
Definition: filter.cc:48
double norm(const ColumnVector &v)
Definition: graphics.cc:5547
F77_RET_T const F77_DBLE * x
double psi(double z)
Definition: lo-specfun.cc:2061
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:219