changeset 26258:6cd1752f21e9

movslice.m, movfun.m: Eliminate duplicate input validation between these functions. * movfun.m: Remove input validation for WLEN argument. Call movslice which will validate WLEN and produce the output we need. * movfun.m (shrink_bc): eliminate '!' operator on logical index for 30% performance increase. * movslice.m: Add more input validation for WLEN argument. Add new BIST tests.
author Rik <rik@octave.org>
date Mon, 17 Dec 2018 13:06:10 -0800
parents 3f46b474d2bb
children 3a8094a70193
files scripts/signal/movfun.m scripts/signal/movslice.m
diffstat 2 files changed, 57 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/signal/movfun.m	Mon Dec 17 21:41:14 2018 +0100
+++ b/scripts/signal/movfun.m	Mon Dec 17 13:06:10 2018 -0800
@@ -168,13 +168,13 @@
     print_usage ();
   endif
 
-  valid_bc = {"shrink", "discard", "fill", "periodic", "same"};
+  valid_bc = {"shrink", "discard", "fill", "same", "periodic"};
 
   ## Parse input arguments
   parser = inputParser ();
   parser.FunctionName = "movfun";
   parser.addParamValue ("Endpoints", "shrink", ...
-    @(x) any (strcmpi (x, valid_bc)) || (isscalar (x) && isnumeric (x)));
+    @(x) any (strcmpi (x, valid_bc)) || (isnumeric (x) && isscalar (x)));
   parser.addParamValue ("dim", [], ...
     @(d) isempty (d) || (isscalar (d) && isindex (d, ndims (x))));
   parser.addParamValue ("nancond", "includenan", ...
@@ -190,55 +190,29 @@
   clear parser
   ## End parse input arguments
 
-  ## Window length validation
-  if (! (isnumeric (wlen) && all (wlen >= 0) && fix (wlen) == wlen))
-    error ("Octave:invalid-input-arg",
-           "movfun: WLEN must be a scalar or 2-element array of integers >= 0");
-  endif
-  if (isscalar (wlen))
-    ## Check for proper window length
-    if (wlen == 1)
-      error ("Octave:invalid-input-arg", "movfun: WLEN must be > 1");
-    endif
-  elseif (numel (wlen) == 2)
-    ## FIXME: Any further tests needed to validate form: wlen = [nb, na] ???
-  else
-    error ("Octave:invalid-input-arg",
-           "movfun: WLEN must be a scalar or 2-element array of integers >= 0");
-  endif
-
   ## If dim was not provided find the first non-singleton dimension.
   szx = size (x);
   if (isempty (dim))
     (dim = find (szx > 1, 1)) || (dim = 1);
   endif
 
-  ## Check that array is longer than WLEN at dimension DIM.  At least one full
-  ## window must fit.  Function max is used to include the case when WLEN is an
-  ## array.
-  ## FIXME: Consider using bc to decide what to do here.
-  if (max (wlen) > szx(dim))
-      error ("Octave:invalid-input-arg", ...
-             "movfun: window length WLEN (%d) must be shorter than length along DIM%d (%d)", ...
-             max (wlen), dim, szx(dim));
-  endif
+  N = szx(dim);  
+
+  ## Calculate slicing indices.  This call also validates WLEN input.
+  [slc, C, Cpre, Cpos, win] = movslice (N, wlen);
 
   omitnan = strcmpi (nancond, "omitnan");
   if (omitnan)
     warning ('movfun: "omitnan" is not yet implemented, using "includenan"');
   endif
 
-  ## Move the desired dim to the 1st dimension
+  ## Move the desired dim to be the 1st dimension (rows)
   nd    = length (szx);                  # number of dimensions
   dperm = [dim, 1:(dim-1), (dim+1):nd];  # permutation of dimensions
-  x     = permute (x, dperm);            # permute dim to first dimensions
-  ncols = prod (szx(dperm(2:end)));      # rest dimensions as single column
-  N     = szx(dperm(1));                 # length of dim
+  x     = permute (x, dperm);            # permute dims to first dimension
+  ncols = prod (szx(dperm(2:end)));      # rest of dimensions as single column
   x     = reshape (x, N, ncols);         # reshape input
 
-  ## Obtain slicer
-  [slc, C, Cpre, Cpos, win] = movslice (N, wlen);
-
   ## Obtain function for boundary conditions
   if (isnumeric (bc))
     bcfunc = @replaceval_bc;
@@ -259,11 +233,12 @@
         bcfunc = @replaceval_bc;
         bcfunc (true, NaN);
 
+      case "same"
+        bcfunc = @same_bc;
+
       case "periodic"
         bcfunc = @periodic_bc;
 
-      case "same"
-        bcfunc = @same_bc;
     endswitch
   endif
 
@@ -326,7 +301,7 @@
 function y = shrink_bc (fcn, x, idxp, win, wlen, odim)
   N   = length (x);
   idx = idxp + win;
-  tf  = ! ((idx < 1) | (idx > N));  # idx inside boundaries
+  tf  = (idx > 0) & (idx <= N);  # idx inside boundaries
 
   n   = length (idxp);
   y   = zeros (n, odim);
@@ -336,30 +311,6 @@
   endfor
 endfunction
 
-## Apply "periodic" boundary conditions
-## Data wraps around padding front of window with data from end of array and
-## vice versa.
-function y = periodic_bc (fcn, x, idxp, win)
-  N       = length (x);
-  idx     = idxp + win;
-  tf      = idx < 1;
-  idx(tf) = N + idx(tf);
-  tf      = idx > N;
-  idx(tf) = idx(tf) - N;
-  y       = fcn (x(idx));
-endfunction
-
-## Apply "same" boundary conditions
-## 'y' values outside window are set equal to 'x' values at the window
-## boundary.
-function y = same_bc (fcn, x, idxp, win)
-  idx          = idxp + win;
-  idx(idx < 1) = 1;
-  N            = length (x);
-  idx(idx > N) = N;
-  y            = fcn (x(idx));
-endfunction
-
 ## Apply replacement value boundary conditions
 ## Window is padded at beginning and end with user-specified value.
 function y = replaceval_bc (fcn, x, idxp, win, wlen)
@@ -389,6 +340,30 @@
 
 endfunction
 
+## Apply "same" boundary conditions
+## 'y' values outside window are replaced by value of 'x' at the window
+## boundary.
+function y = same_bc (fcn, x, idxp, win)
+  idx          = idxp + win;
+  idx(idx < 1) = 1;
+  N            = length (x);
+  idx(idx > N) = N;
+  y            = fcn (x(idx));
+endfunction
+
+## Apply "periodic" boundary conditions
+## Window wraps around.  Window values outside data array are replaced with
+## data from the other end of the array.
+function y = periodic_bc (fcn, x, idxp, win)
+  N       = length (x);
+  idx     = idxp + win;
+  tf      = idx < 1;
+  idx(tf) = N + idx(tf);
+  tf      = idx > N;
+  idx(tf) = idx(tf) - N;
+  y       = fcn (x(idx));
+endfunction
+
 
 %!demo
 %! clf;
@@ -620,11 +595,11 @@
 %!error <WLEN must be .* array of integers> movfun (@min, 1, 1.5)
 %!error <WLEN must be . 1> movfun (@min, 1, 1)
 %!error <WLEN must be a scalar or 2-element array> movfun (@min, 1, [1, 2, 3])
-%!error <WLEN \(3\) must be shorter than length along DIM1 \(1\)>
-%! movfun (@min, 1, 3);
-%!error <WLEN \(4\) must be shorter than length along DIM1 \(1\)>
+%!error <WLEN \(3\) must be shorter than length along DIM \(1\)>
+%! movfun (@min, 1, 3)
+%!error <WLEN \(4\) must be shorter than length along DIM \(1\)>
 %! movfun (@min, 1, [4, 1]);
-%!error <WLEN \(5\) must be shorter than length along DIM1 \(1\)>
+%!error <WLEN \(5\) must be shorter than length along DIM \(1\)>
 %! movfun (@min, 1, [1, 5]);
 %!warning <"omitnan" is not yet implemented>
 %! movfun (@min, 1:3, 3, "nancond", "omitnan");
--- a/scripts/signal/movslice.m	Mon Dec 17 21:41:14 2018 +0100
+++ b/scripts/signal/movslice.m	Mon Dec 17 13:06:10 2018 -0800
@@ -53,10 +53,15 @@
       error ("Octave:invalid-input-arg", "movslice: WLEN must be > 1");
     endif
   elseif (numel (wlen) == 2)
-    ## FIXME: Any further tests needed to validate form: wlen = [nb, na] ???
+    ## wlen = [nb, na].  No further validation here.
   else
     error ("Octave:invalid-input-arg",
-           "movfun: WLEN must be a scalar or 2-element array of integers >= 0");
+           "movslice: WLEN must be a scalar or 2-element array of integers >= 0");
+  endif
+  if (max (wlen) > N)
+    error ("Octave:invalid-input-arg", ...
+           "movslice: window length WLEN (%d) must be shorter than length along DIM (%d)", ...
+           max (wlen), N);
   endif
 
   if (isscalar (wlen))
@@ -74,7 +79,7 @@
 
   Cpre  = 1:wlen(1);              # centers that can't fit the pre-window
   Cnf   = N - wlen(2) + 1;        # first center that can't fit the post-window
-  Cpost = Cnf:N;                  # centers that can't fit centered  post-window
+  Cpost = Cnf:N;                  # centers that can't fit centered post-window
   C     = (wlen(1) + 1):(Cnf - 1);
   win   = (-wlen(1):wlen(2)).';
   slcidx = C + win;
@@ -88,8 +93,16 @@
 %!error movslice ()
 %!error movslice (1)
 %!error movslice (1,2,3)
+%!error <N must be a positive integer> movslice ([1 2], 1)
+%!error <N must be a positive integer> movslice (0, 1)
 %!error <WLEN must be .* array of integers> movslice (1, {1})
 %!error <WLEN must be .* array of integers .= 0> movslice (1, -1)
 %!error <WLEN must be .* array of integers> movslice (1, 1.5)
 %!error <WLEN must be . 1> movslice (1, 1)
 %!error <WLEN must be a scalar or 2-element array> movslice (1, [1, 2, 3])
+%!error <WLEN \(3\) must be shorter than length along DIM \(1\)>
+%! movslice (1, 3);
+%!error <WLEN \(4\) must be shorter than length along DIM \(1\)>
+%! movslice (1, [4, 1]);
+%!error <WLEN \(5\) must be shorter than length along DIM \(1\)>
+%! movslice (1, [1, 5]);