Mercurial > octave
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]);