GNU Octave 11.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
filter.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1996-2026 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 <cmath>
39#include <type_traits>
40
41#include "quit.h"
42
43#include "defun.h"
44#include "error.h"
45#include "ovl.h"
46
48
49// Helper functions for fused multiply-add (FMA) operations
50// Use std::fma for real types, regular operations for complex types
51
52template <typename T>
53inline T
54fma_or_mul_add (const T& a, const T& b, const T& c)
55{
56 if constexpr (std::is_floating_point_v<T>)
57 return std::fma (a, b, c);
58 else
59 return a * b + c;
60}
61
62template <typename T>
65 int dim = 0)
66{
67 octave_idx_type a_len = a.numel ();
68 octave_idx_type b_len = b.numel ();
69 octave_idx_type ab_len = (a_len > b_len ? a_len : b_len);
70
71 // FIXME: The two lines below should be unnecessary because
72 // this template is called with a and b as column vectors
73 // already. However the a.resize line is currently (2011/04/26)
74 // necessary to stop bug #33164.
75 b.resize (dim_vector (ab_len, 1), 0.0);
76 if (a_len > 1)
77 a.resize (dim_vector (ab_len, 1), 0.0);
78
79 T norm = a (0);
80 const T zero = static_cast<T> (0);
81
82 if (norm == zero)
83 error ("filter: the first element of A must be nonzero");
84
85 const dim_vector& x_dims = x.dims ();
86 if (dim < 0 || dim > x_dims.ndims ())
87 error ("filter: DIM must be a valid dimension");
88
89 octave_idx_type x_len = x_dims(dim);
90
91 const dim_vector& si_dims = si.dims ();
92 octave_idx_type si_len = si_dims(0);
93
94 if (si_len != ab_len - 1)
95 error ("filter: first dimension of SI must be of length max (length (a), length (b)) - 1");
96
97 if (si_dims.ndims () != x_dims.ndims ())
98 error ("filter: dimensionality of SI and X must agree");
99
100 for (octave_idx_type i = 1; i < dim; i++)
101 {
102 if (si_dims(i) != x_dims(i-1))
103 error ("filter: dimensionality of SI and X must agree");
104 }
105 for (octave_idx_type i = dim+1; i < x_dims.ndims (); i++)
106 {
107 if (si_dims(i) != x_dims(i))
108 error ("filter: dimensionality of SI and X must agree");
109 }
110
111 if (x_len == 0)
112 return x;
113
114 if (norm != static_cast<T> (1.0))
115 {
116 a /= norm;
117 b /= norm;
118 }
119
120 if (a_len <= 1 && si_len <= 0)
121 return b(0) * x;
122
123 // Here onwards, either a_len > 1 or si_len >= 1 or both.
124
125 MArray<T> y;
126 y.resize (x_dims, 0.0);
127
128 octave_idx_type x_stride = 1;
129 for (int i = 0; i < dim; i++)
130 x_stride *= x_dims(i);
131
132 octave_idx_type x_num = x_dims.numel () / x_len;
133 // For deconv and fftfilt, x_num seems to always be 1.
134 // For directly calling filter, it can be more than 1.
135
136 for (octave_idx_type num = 0; num < x_num; num++)
137 {
138 octave_idx_type x_offset = (x_stride == 1) ? num * x_len
139 : num + (num / x_stride) * x_stride * (x_len - 1);
140
141 octave_idx_type si_offset = num * si_len;
142
143 octave_idx_type num_execs = si_len-1; // 0 to num_execs-1
144
145 // Define variables here that are common to both the if-block and
146 // the else-block.
147 T *py = y.rwdata ();
148 T *psi = si.rwdata ();
149 const T *pb = b.data ();
150 const T *px = x.data ();
151 psi += si_offset;
152
153 if (a_len > 1)
154 {
155 const T *pa = a.data ();
156
157 // Usually the last element to be written will be si_len-1
158 // but if si_len is 0, then we need the 0th element to be written.
159 // Pulling this check out of the for-loop makes it run faster.
160 octave_idx_type iidx = (si_len > 0) ? si_len-1 : 0;
161
162 for (octave_idx_type i = 0, idx = x_offset;
163 i < x_len;
164 i++, idx += x_stride)
165 {
166 // Use FMA for the output calculation: y = si[0] + b[0]*x
167 py[idx] = fma_or_mul_add (pb[0], px[idx], psi[0]);
168 const T px_val = px[idx];
169 const T py_val = py[idx];
170 const bool px_nonzero = (px_val != zero);
171 const bool py_nonzero = (py_val != zero);
172
173 // Split into cases based on zero/nonzero to avoid a long
174 // sequence of multiplying by zero values. See bug #67653.
175 // FIXME: Currently the loop is duplicated for performance.
176 // Can this be made fast without duplication? It was reported
177 // in bug #67653 that BLAS axpy is not as fast as these loops.
178 // Maybe test std::transform in future?
179 if (py_nonzero)
180 {
181 if (px_nonzero)
182 {
183 // Compute: psi[j] = psi[j+1] - pa[j+1]*py + pb[j+1]*px
184 // Use two FMAs: temp = psi[j+1] - pa*py, then result = temp + pb*px
185 for (octave_idx_type j = 0; j < num_execs; j++)
186 {
187 T temp = fma_or_mul_add (-pa[j+1], py_val, psi[j+1]);
188 psi[j] = fma_or_mul_add (pb[j+1], px_val, temp);
189 }
190 }
191 else
192 {
193 // Compute: psi[j] = psi[j+1] - pa[j+1]*py
194 for (octave_idx_type j = 0; j < num_execs; j++)
195 psi[j] = fma_or_mul_add (-pa[j+1], py_val, psi[j+1]);
196 }
197 }
198 else
199 {
200 if (px_nonzero)
201 {
202 // Compute: psi[j] = psi[j+1] + pb[j+1]*px
203 for (octave_idx_type j = 0; j < num_execs; j++)
204 psi[j] = fma_or_mul_add (pb[j+1], px_val, psi[j+1]);
205 }
206 else
207 for (octave_idx_type j = 0; j < num_execs; j++)
208 psi[j] = psi[j+1];
209 }
210
211 // Compute: psi[iidx] = pb[si_len]*px - pa[si_len]*py
212 T temp = fma_or_mul_add (-pa[si_len], py_val, zero);
213 psi[iidx] = fma_or_mul_add (pb[si_len], px_val, temp);
214
215 if ((i & 4095) == 0) // Check for interruptions every 4096 samples
216 octave_quit();
217 }
218 }
219 else // a_len <= 1 ==> si_len MUST be > 0
220 {
221 // This else-block is almost the same as the above if-block,
222 // except for the absence of variable pa.
223
224 for (octave_idx_type i = 0, idx = x_offset;
225 i < x_len;
226 i++, idx += x_stride)
227 {
228 const T px_val = px[idx];
229 const bool px_nonzero = (px_val != zero);
230
231 // Use FMA for: y = si[0] + b[0]*x
232 py[idx] = fma_or_mul_add (pb[0], px_val, psi[0]);
233
234 if (px_nonzero)
235 {
236 // Use FMA to compute: psi[j] = psi[j+1] + pb[j+1]*px
237 for (octave_idx_type j = 0; j < num_execs; j++)
238 psi[j] = fma_or_mul_add (pb[j+1], px_val, psi[j+1]);
239 }
240 else
241 {
242 for (octave_idx_type j = 0; j < num_execs; j++)
243 psi[j] = psi[j+1];
244 }
245
246 psi[si_len-1] = pb[si_len] * px_val;
247
248 if ((i & 4095) == 0) // Check for interruptions every 4096 samples
249 octave_quit();
250 }
251 }
252 }
253
254 return y;
255}
256
257template <typename T>
259filter (MArray<T>& b, MArray<T>& a, MArray<T>& x, int dim = -1)
260{
261 const dim_vector& x_dims = x.dims ();
262
263 if (dim < 0)
264 dim = x_dims.first_non_singleton ();
265 else if (dim > x_dims.ndims ())
266 error ("filter: DIM must be a valid dimension");
267
268 octave_idx_type a_len = a.numel ();
269 octave_idx_type b_len = b.numel ();
270
271 octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
272 dim_vector si_dims = x.dims ();
273 for (int i = dim; i > 0; i--)
274 si_dims(i) = si_dims(i-1);
275 si_dims(0) = si_len;
276
277 MArray<T> si (si_dims, T (0.0));
278
279 return filter (b, a, x, si, dim);
280}
281
282DEFUN (filter, args, nargout,
283 doc: /* -*- texinfo -*-
284@deftypefn {} {@var{y} =} filter (@var{b}, @var{a}, @var{x})
285@deftypefnx {} {[@var{y}, @var{sf}] =} filter (@var{b}, @var{a}, @var{x}, @var{si})
286@deftypefnx {} {[@var{y}, @var{sf}] =} filter (@var{b}, @var{a}, @var{x}, [], @var{dim})
287@deftypefnx {} {[@var{y}, @var{sf}] =} filter (@var{b}, @var{a}, @var{x}, @var{si}, @var{dim})
288Apply a 1-D digital filter to the data @var{x}.
289
290@code{filter} returns the solution to the following linear, time-invariant
291difference equation:
292@tex
293$$
294\sum_{k=0}^N a_{k+1} y_{n-k} = \sum_{k=0}^M b_{k+1} x_{n-k}, \qquad
295 1 \le n \le P
296$$
297@end tex
298@ifnottex
299@c Set example in small font to prevent overfull line
300
301@smallexample
302@group
303 N M
304SUM a(k+1) y(n-k) = SUM b(k+1) x(n-k) for 1<=n<=length(x)
305k=0 k=0
306@end group
307@end smallexample
308
309@end ifnottex
310
311@noindent
312where
313@ifnottex
314N=length(a)-1 and M=length(b)-1.
315@end ifnottex
316@tex
317$a \in \Re^{N-1}$, $b \in \Re^{M-1}$, and $x \in \Re^P$.
318@end tex
319The result is calculated over the first non-singleton dimension of @var{x}
320or over @var{dim} if supplied.
321
322An equivalent form of the equation is:
323@tex
324$$
325y_n = -\sum_{k=1}^N c_{k+1} y_{n-k} + \sum_{k=0}^M d_{k+1} x_{n-k}, \qquad
326 1 \le n \le P
327$$
328@end tex
329@ifnottex
330@c Set example in small font to prevent overfull line
331
332@smallexample
333@group
334 N M
335y(n) = - SUM c(k+1) y(n-k) + SUM d(k+1) x(n-k) for 1<=n<=length(x)
336 k=1 k=0
337@end group
338@end smallexample
339
340@end ifnottex
341
342@noindent
343where
344@ifnottex
345 c = a/a(1) and d = b/a(1).
346@end ifnottex
347@tex
348$c = a/a_1$ and $d = b/a_1$.
349@end tex
350
351If the fourth argument @var{si} is provided, it is taken as the
352initial state of the system and the final state is returned as
353@var{sf}. The state vector is a column vector whose length is
354equal to the length of the longest coefficient vector minus one.
355If @var{si} is not supplied, the initial state vector is set to all
356zeros.
357
358In terms of the Z Transform, @var{y} is the result of passing the
359discrete-time signal @var{x} through a system characterized by the following
360rational system function:
361@tex
362$$
363H(z) = {\displaystyle\sum_{k=0}^M d_{k+1} z^{-k}
364 \over 1 + \displaystyle\sum_{k+1}^N c_{k+1} z^{-k}}
365$$
366@end tex
367@ifnottex
368
369@example
370@group
371 M
372 SUM d(k+1) z^(-k)
373 k=0
374H(z) = ---------------------
375 N
376 1 + SUM c(k+1) z^(-k)
377 k=1
378@end group
379@end example
380
381@end ifnottex
382@seealso{filter2, fftfilt, freqz}
383@end deftypefn */)
384{
385 int nargin = args.length ();
386
387 if (nargin < 3 || nargin > 5 || nargout > 2)
388 print_usage ();
389
390 int dim;
391 const dim_vector& x_dims = args(2).dims ();
392
393 if (nargin == 5)
394 {
395 dim = args(4).strict_int_value () - 1;
396 if (dim < 0 || dim >= x_dims.ndims ())
397 error ("filter: DIM must be a valid dimension");
398 }
399 else
400 dim = x_dims.first_non_singleton ();
401
402 octave_value_list retval ((nargout <= 1) ? 1 : 2);
403
404 const char *a_b_errmsg = "filter: A and B must be vectors";
405 const char *x_si_errmsg = "filter: X and SI must be arrays";
406
407 bool isfloat = (args(0).is_single_type ()
408 || args(1).is_single_type ()
409 || args(2).is_single_type ()
410 || (nargin >= 4 && args(3).is_single_type ()));
411
412 if (args(0).iscomplex ()
413 || args(1).iscomplex ()
414 || args(2).iscomplex ()
415 || (nargin >= 4 && args(3).iscomplex ()))
416 {
417 if (isfloat)
418 {
419 FloatComplexColumnVector b = args(0).xfloat_complex_vector_value (a_b_errmsg);
420 FloatComplexColumnVector a = args(1).xfloat_complex_vector_value (a_b_errmsg);
421 FloatComplexNDArray x = args(2).xfloat_complex_array_value (x_si_errmsg);
422
424
425 if (nargin == 3 || args(3).isempty ())
426 {
427 octave_idx_type a_len = a.numel ();
428 octave_idx_type b_len = b.numel ();
429
430 octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
431
432 dim_vector si_dims = x.dims ();
433 for (int i = dim; i > 0; i--)
434 si_dims(i) = si_dims(i-1);
435 si_dims(0) = si_len;
436
437 si.resize (si_dims, 0.0);
438 }
439 else
440 {
441 si = args(3).xfloat_complex_array_value (x_si_errmsg);
442
443 if (si.isvector () && x.isvector ())
444 si = si.reshape (dim_vector (si.numel (), 1));
445 }
446
447 FloatComplexNDArray y (filter (b, a, x, si, dim));
448
449 retval(0) = y;
450 if (nargout > 1)
451 retval(1) = si;
452 }
453 else
454 {
455 ComplexColumnVector b = args(0).xcomplex_vector_value (a_b_errmsg);
456 ComplexColumnVector a = args(1).xcomplex_vector_value (a_b_errmsg);
457
458 ComplexNDArray x = args(2).xcomplex_array_value (x_si_errmsg);
459
461
462 if (nargin == 3 || args(3).isempty ())
463 {
464 octave_idx_type a_len = a.numel ();
465 octave_idx_type b_len = b.numel ();
466
467 octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
468
469 dim_vector si_dims = x.dims ();
470 for (int i = dim; i > 0; i--)
471 si_dims(i) = si_dims(i-1);
472 si_dims(0) = si_len;
473
474 si.resize (si_dims, 0.0);
475 }
476 else
477 {
478 si = args(3).xcomplex_array_value (x_si_errmsg);
479
480 if (si.isvector () && x.isvector ())
481 si = si.reshape (dim_vector (si.numel (), 1));
482 }
483
484 ComplexNDArray y (filter (b, a, x, si, dim));
485
486 retval(0) = y;
487 if (nargout > 1)
488 retval(1) = si;
489 }
490 }
491 else
492 {
493 if (isfloat)
494 {
495 FloatColumnVector b = args(0).xfloat_vector_value (a_b_errmsg);
496 FloatColumnVector a = args(1).xfloat_vector_value (a_b_errmsg);
497
498 FloatNDArray x = args(2).xfloat_array_value (x_si_errmsg);
499
500 FloatNDArray si;
501
502 if (nargin == 3 || args(3).isempty ())
503 {
504 octave_idx_type a_len = a.numel ();
505 octave_idx_type b_len = b.numel ();
506
507 octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
508
509 dim_vector si_dims = x.dims ();
510 for (int i = dim; i > 0; i--)
511 si_dims(i) = si_dims(i-1);
512 si_dims(0) = si_len;
513
514 si.resize (si_dims, 0.0);
515 }
516 else
517 {
518 si = args(3).xfloat_array_value (x_si_errmsg);
519
520 if (si.isvector () && x.isvector ())
521 si = si.reshape (dim_vector (si.numel (), 1));
522 }
523
524 FloatNDArray y (filter (b, a, x, si, dim));
525
526 retval(0) = y;
527 if (nargout > 1)
528 retval(1) = si;
529 }
530 else
531 {
532 ColumnVector b = args(0).xvector_value (a_b_errmsg);
533 ColumnVector a = args(1).xvector_value (a_b_errmsg);
534
535 NDArray x = args(2).xarray_value (x_si_errmsg);
536
537 NDArray si;
538
539 if (nargin == 3 || args(3).isempty ())
540 {
541 octave_idx_type a_len = a.numel ();
542 octave_idx_type b_len = b.numel ();
543
544 octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
545
546 dim_vector si_dims = x.dims ();
547 for (int i = dim; i > 0; i--)
548 si_dims(i) = si_dims(i-1);
549 si_dims(0) = si_len;
550
551 si.resize (si_dims, 0.0);
552 }
553 else
554 {
555 si = args(3).xarray_value (x_si_errmsg);
556
557 if (si.isvector () && x.isvector ())
558 si = si.reshape (dim_vector (si.numel (), 1));
559 }
560
561 NDArray y (filter (b, a, x, si, dim));
562
563 retval(0) = y;
564 if (nargout > 1)
565 retval(1) = si;
566 }
567 }
568
569 return retval;
570}
571
572/*
573%!shared a, b, x, r
574%!test
575%! a = [1 1];
576%! b = [1 1];
577%! x = zeros (1,10); x(1) = 1;
578%! assert (filter (b, [1], x ), [1 1 0 0 0 0 0 0 0 0]);
579%! assert (filter (b, [1], x.'), [1 1 0 0 0 0 0 0 0 0].');
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 ([1], a, x ), [+1 -1 +1 -1 +1 -1 +1 -1 +1 -1] );
583%! assert (filter ([1], a, x.'), [+1 -1 +1 -1 +1 -1 +1 -1 +1 -1].');
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 (b, a, x ), [1 0 0 0 0 0 0 0 0 0] );
587%! assert (filter (b.', a, x ), [1 0 0 0 0 0 0 0 0 0] );
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
595%!test
596%! r = sqrt (1/2) * (1+i);
597%! a = a*r;
598%! b = b*r;
599%! assert (filter (b, [1], x ), r*[1 1 0 0 0 0 0 0 0 0] , eps);
600%! assert (filter (b, [1], r*x ), r*r*[1 1 0 0 0 0 0 0 0 0], eps);
601%! assert (filter (b, [1], x.' ), r*[1 1 0 0 0 0 0 0 0 0].', eps);
602%! assert (filter (b, a, x ), [1 0 0 0 0 0 0 0 0 0], eps);
603%! assert (filter (b, a, r*x ), r*[1 0 0 0 0 0 0 0 0 0], eps);
604
605%!shared a, b, x, y, so
606%!test
607%! a = [1,1];
608%! b = [1,1];
609%! x = zeros (1,10); x(1) = 1;
610%! [y, so] = filter (b, [1], x, [-1]);
611%! assert (y, [0 1 0 0 0 0 0 0 0 0]);
612%! assert (so, 0);
613
614%!test
615%! x = zeros (10,3); x(1,1) = -1; x(1,2) = 1;
616%! y0 = zeros (10,3); y0(1:2,1) = -1; y0(1:2,2) = 1;
617%! y = filter (b, [1], x);
618%! assert (y, y0);
619
620%!test
621%! a = [1,1];
622%! b=[1,1];
623%! x = zeros (4,4,2); x(1,1:4,1) = +1; x(1,1:4,2) = -1;
624%! y0 = zeros (4,4,2); y0(1:2,1:4,1) = +1; y0(1:2,1:4,2) = -1;
625%! y = filter (b, [1], x);
626%! assert (y, y0);
627
628%!assert (filter (1, ones (10,1) / 10, []), [])
629%!assert (filter (1, ones (10,1) / 10, zeros (0,10)), zeros (0,10))
630%!assert (filter (1, ones (10,1) / 10, single (1:5)),
631%! repmat (single (10), 1, 5))
632
633## Test using initial conditions
634%!assert (filter ([1, 1, 1], [1, 1], [1 2], [1, 1]), [2 2])
635%!assert (filter ([1, 1, 1], [1, 1], [1 2], [1, 1]'), [2 2])
636%!assert (filter ([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]), [5 7; 6 10; 14 18])
637%!error filter ([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]')
638%!assert (filter ([1, 3, 2], [1], [1 2; 3 4; 5 6], [1 0 0; 1 0 0], 2),
639%! [2 6; 3 13; 5 21])
640
641## Test of DIM parameter
642%!test
643%! x = ones (2, 1, 3, 4);
644%! x(1,1,:,:) = [1 2 3 4; 5 6 7 8; 9 10 11 12];
645%! 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];
646%! y0 = reshape (y0, size (x));
647%! y = filter ([1 1 1], 1, x, [], 3);
648%! assert (y, y0);
649*/
650
651template MArray<double>
653 MArray<double>&, int dim);
654
655template MArray<double>
657
658template MArray<Complex>
660 MArray<Complex>&, int dim);
661
662template MArray<Complex>
664
665template MArray<float>
667 MArray<float>&, int dim);
668
669template MArray<float>
671
674 MArray<FloatComplex>&, int dim);
675
678 int dim);
679
680OCTAVE_END_NAMESPACE(octave)
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition Array-base.h:529
bool isvector() const
Size of the specified dimension.
Definition Array-base.h:677
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
const T * data() const
Size of the specified dimension.
Definition Array-base.h:687
T * rwdata()
Size of the specified dimension.
octave_idx_type numel() const
Number of elements in the array.
Definition Array-base.h:440
Template for N-dimensional array classes with like-type math operators.
Definition MArray.h:61
MArray< T > reshape(const dim_vector &new_dims) const
Definition MArray.h:91
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:92
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition dim-vector.h:341
octave_idx_type ndims() const
Number of dimensions.
Definition dim-vector.h:263
int first_non_singleton(int def=0) const
Definition dim-vector.h:481
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage()
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:1008
MArray< T > filter(MArray< T > &b, MArray< T > &a, MArray< T > &x, MArray< T > &si, int dim=0)
Definition filter.cc:64
T fma_or_mul_add(const T &a, const T &b, const T &c)
Definition filter.cc:54
double norm(const ColumnVector &v)
Definition graphics.cc:5788
double psi(double z)
F77_RET_T const F77_DBLE * x