changeset 21309:7fbecef105ca

Allow statistics functions to work over non-existent dimension (bug #33523). * var.m, center.m, kurtosis.m, mean.m, meansq.m, median.m, moment.m, skewness.m, std.m: Remove check for input dimension being within the range of ndims (x). Add BIST tests for new behavior and update input validation tests.
author Rik <rik@octave.org>
date Fri, 19 Feb 2016 21:27:03 -0800
parents c53bfd6d8e08
children fc6a9bd59094
files scripts/statistics/base/center.m scripts/statistics/base/kurtosis.m scripts/statistics/base/mean.m scripts/statistics/base/meansq.m scripts/statistics/base/median.m scripts/statistics/base/moment.m scripts/statistics/base/skewness.m scripts/statistics/base/std.m scripts/statistics/base/var.m
diffstat 9 files changed, 71 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/statistics/base/center.m	Fri Feb 19 09:40:59 2016 -0800
+++ b/scripts/statistics/base/center.m	Fri Feb 19 21:27:03 2016 -0800
@@ -59,13 +59,12 @@
     ## Find the first non-singleton dimension.
     (dim = find (sz > 1, 1)) || (dim = 1);
   else
-    if (!(isscalar (dim) && dim == fix (dim))
-        || !(1 <= dim && dim <= nd))
+    if (! (isscalar (dim) && dim == fix (dim) && dim > 0))
       error ("center: DIM must be an integer and a valid dimension");
     endif
   endif
 
-  n = sz(dim);
+  n = size (x, dim);
 
   if (n == 0)
     retval = x;
@@ -84,12 +83,12 @@
 %!assert (center (ones (3,2,0,2, "single")), zeros (3,2,0,2, "single"))
 %!assert (center (magic (3)), [3,-4,1;-2,0,2;-1,4,-3])
 %!assert (center ([1 2 3; 6 5 4], 2), [-1 0 1; 1 0 -1])
+%!assert (center (1, 3), 0)
 
 ## Test input validation
 %!error center ()
 %!error center (1, 2, 3)
-%!error center (1, ones (2,2))
-%!error center (1, 1.5)
-%!error center (1, 0)
-%!error center (1, 3)
+%!error <DIM must be an integer> center (1, ones (2,2))
+%!error <DIM must be an integer> center (1, 1.5)
+%!error <DIM must be .* a valid dimension> center (1, 0)
 
--- a/scripts/statistics/base/kurtosis.m	Fri Feb 19 09:40:59 2016 -0800
+++ b/scripts/statistics/base/kurtosis.m	Fri Feb 19 21:27:03 2016 -0800
@@ -105,12 +105,12 @@
     ## Find the first non-singleton dimension.
     (dim = find (sz > 1, 1)) || (dim = 1);
   else
-    if (! (isscalar (dim) && dim == fix (dim)) || ! (1 <= dim && dim <= nd))
+    if (! (isscalar (dim) && dim == fix (dim) && dim > 0))
       error ("kurtosis: DIM must be an integer and a valid dimension");
     endif
   endif
 
-  n = sz(dim);
+  n = size (x, dim);
   sz(dim) = 1;
 
   x = center (x, dim);   # center also promotes integer, logical to double
@@ -140,6 +140,7 @@
 
 %!assert (kurtosis ([-3, 0, 1]) == kurtosis ([-1, 0, 3]))
 %!assert (kurtosis (ones (3, 5)), NaN (1, 5))
+%!assert (kurtosis (1, [], 3), NaN)
 
 %!assert (kurtosis ([1:5 10; 1:5 10],  0, 2), 5.4377317925288901 * [1; 1], 8 * eps)
 %!assert (kurtosis ([1:5 10; 1:5 10],  1, 2), 2.9786509002956195 * [1; 1], 8 * eps)
@@ -165,5 +166,4 @@
 %!error <DIM must be an integer> kurtosis (1, [], ones (2,2))
 %!error <DIM must be an integer> kurtosis (1, [], 1.5)
 %!error <DIM must be .* a valid dimension> kurtosis (1, [], 0)
-%!error <DIM must be .* a valid dimension> kurtosis (1, [], 3)
 
--- a/scripts/statistics/base/mean.m	Fri Feb 19 09:40:59 2016 -0800
+++ b/scripts/statistics/base/mean.m	Fri Feb 19 21:27:03 2016 -0800
@@ -105,13 +105,12 @@
     ## Find the first non-singleton dimension.
     (dim = find (sz > 1, 1)) || (dim = 1);
   else
-    if (!(isscalar (dim) && dim == fix (dim))
-      || !(1 <= dim && dim <= nd))
+    if (! (isscalar (dim) && dim == fix (dim) && dim > 0))
       error ("mean: DIM must be an integer and a valid dimension");
     endif
   endif
 
-  n = sz(dim);
+  n = size (x, dim);
 
   if (strcmp (opt, "a"))
     y = sum (x, dim) / n;
@@ -147,15 +146,16 @@
 %!assert (mean ([4 4 2], "h"), 3)
 %!assert (mean (logical ([1 0 1 1])), 0.75)
 %!assert (mean (single ([1 0 1 1])), single (0.75))
+%!assert (mean ([1 2], 3), [1 2])
 
 ## Test input validation
 %!error mean ()
 %!error mean (1, 2, 3, 4)
-%!error mean ({1:5})
-%!error mean (1, 2, 3)
-%!error mean (1, ones (2,2))
-%!error mean (1, 1.5)
-%!error mean (1, 0)
-%!error mean (1, 3)
-%!error mean (1, "b")
+%!error <X must be a numeric> mean ({1:5})
+%!error <OPT must be a string> mean (1, 2, 3)
+%!error <DIM must be an integer> mean (1, ones (2,2))
+%!error <DIM must be an integer> mean (1, 1.5)
+%!error <DIM must be .* a valid dimension> mean (1, 0)
+%!error <X must not contain any negative values> mean ([1 -1], "g")
+%!error <option 'b' not recognized> mean (1, "b")
 
--- a/scripts/statistics/base/meansq.m	Fri Feb 19 09:40:59 2016 -0800
+++ b/scripts/statistics/base/meansq.m	Fri Feb 19 21:27:03 2016 -0800
@@ -64,13 +64,12 @@
     ## Find the first non-singleton dimension.
     (dim = find (sz > 1, 1)) || (dim = 1);
   else
-    if (!(isscalar (dim) && dim == fix (dim))
-        || !(1 <= dim && dim <= nd))
+    if (! (isscalar (dim) && dim == fix (dim) && dim > 0))
       error ("mean: DIM must be an integer and a valid dimension");
     endif
   endif
 
-  y = sumsq (x, dim) / sz(dim);
+  y = sumsq (x, dim) / size (x, dim);
 
 endfunction
 
@@ -79,13 +78,13 @@
 %!assert (meansq (single (1:5)), single (11))
 %!assert (meansq (magic (4)), [94.5, 92.5, 92.5, 94.5])
 %!assert (meansq (magic (4), 2), [109.5; 77.5; 77.5; 109.5])
+%!assert (meansq ([1 2], 3), [1 4])
 
 ## Test input validation
 %!error meansq ()
 %!error meansq (1, 2, 3)
-%!error meansq (['A'; 'B'])
-%!error meansq (1, ones (2,2))
-%!error meansq (1, 1.5)
-%!error meansq (1, 0)
-%!error meansq (1, 3)
+%!error <X must be a numeric> meansq (['A'; 'B'])
+%!error <DIM must be an integer> meansq (1, ones (2,2))
+%!error <DIM must be an integer> meansq (1, 1.5)
+%!error <DIM must be .* a valid dimension> meansq (1, 0)
 
--- a/scripts/statistics/base/median.m	Fri Feb 19 09:40:59 2016 -0800
+++ b/scripts/statistics/base/median.m	Fri Feb 19 21:27:03 2016 -0800
@@ -70,13 +70,12 @@
     ## Find the first non-singleton dimension.
     (dim = find (sz > 1, 1)) || (dim = 1);
   else
-    if (!(isscalar (dim) && dim == fix (dim))
-        || !(1 <= dim && dim <= nd))
+    if (! (isscalar (dim) && dim == fix (dim) && dim > 0))
       error ("median: DIM must be an integer and a valid dimension");
     endif
   endif
 
-  n = sz(dim);
+  n = size (x, dim);
   k = floor ((n+1) / 2);
   if (mod (n, 2) == 1)
     retval = nth_element (x, k, dim);
@@ -102,6 +101,7 @@
 
 %!assert (median (single ([1,2,3])), single (2))
 %!assert (median ([1,2,NaN;4,5,6;NaN,8,9]), [NaN, 5, NaN])
+%!assert (median ([1,2], 3), [1,2])
 
 ## Test multidimensional arrays (bug #35679)
 %!shared a, b, x, y
@@ -116,9 +116,9 @@
 ## Test input validation
 %!error median ()
 %!error median (1, 2, 3)
-%!error median ({1:5})
-%!error median (['A'; 'B'])
-%!error median (1, ones (2,2))
-%!error median (1, 1.5)
-%!error median (1, 0)
+%!error <X must be a numeric> median ({1:5})
+%!error <X cannot be an empty matrix> median ([])
+%!error <DIM must be an integer> median (1, ones (2,2))
+%!error <DIM must be an integer> median (1, 1.5)
+%!error <DIM must be .* a valid dimension> median (1, 0)
 
--- a/scripts/statistics/base/moment.m	Fri Feb 19 09:40:59 2016 -0800
+++ b/scripts/statistics/base/moment.m	Fri Feb 19 21:27:03 2016 -0800
@@ -161,12 +161,12 @@
     ## Find the first non-singleton dimension.
     (dim = find (sz > 1, 1)) || (dim = 1);
   else
-    if (! (isscalar (dim) && dim == fix (dim)) || ! (1 <= dim && dim <= nd))
+    if (! (isscalar (dim) && dim == fix (dim) && dim > 0))
       error ("moment: DIM must be an integer and a valid dimension");
     endif
   endif
 
-  n = sz(dim);
+  n = size (x, dim);
 
   if (! any (type == "r"))
     x = center (x, dim);
@@ -191,6 +191,8 @@
 
 %!assert (moment (single ([1 2 3]), 1, "r"), single (2))
 
+%!assert (moment (1, 2, 4), 0)
+
 ## Test input validation
 %!error moment ()
 %!error moment (1)
@@ -202,5 +204,4 @@
 %!error <TYPE must be a string> moment (1, 2, 3, 4)
 %!error <DIM must be an integer and a valid dimension> moment (1, 2, ones (2,2))
 %!error <DIM must be an integer and a valid dimension> moment (1, 2, 1.5)
-%!error <DIM must be an integer and a valid dimension> moment (1, 2, 4)
 
--- a/scripts/statistics/base/skewness.m	Fri Feb 19 09:40:59 2016 -0800
+++ b/scripts/statistics/base/skewness.m	Fri Feb 19 21:27:03 2016 -0800
@@ -92,10 +92,8 @@
 
   if (nargin < 2 || isempty (flag))
     flag = 1;  # default: do not use the "bias corrected" version
-  else
-    if (! isscalar (flag) || (flag != 0 && flag != 1))
-      error ("skewness: FLAG must be 0 or 1");
-    endif
+  elseif (! isscalar (flag) || (flag != 0 && flag != 1))
+    error ("skewness: FLAG must be 0 or 1");
   endif
 
   nd = ndims (x);
@@ -104,12 +102,12 @@
     ## Find the first non-singleton dimension.
     (dim = find (sz > 1, 1)) || (dim = 1);
   else
-    if (!(isscalar (dim) && dim == fix (dim)) || !(1 <= dim && dim <= nd))
+    if (! (isscalar (dim) && dim == fix (dim) && dim > 0))
       error ("skewness: DIM must be an integer and a valid dimension");
     endif
   endif
 
-  n = sz(dim);
+  n = size (x, dim);
   sz(dim) = 1;
 
   x = center (x, dim);   # center also promotes integer, logical to double
@@ -136,6 +134,7 @@
 %!assert (skewness ([-1, 0, 2]) > 0)
 %!assert (skewness ([-3, 0, 1]) == -1 * skewness ([-1, 0, 3]))
 %!assert (skewness (ones (3, 5)), NaN (1, 5))
+%!assert (skewness (1, [], 3), NaN)
 
 %!test
 %! x = [0; 0; 0; 1];
@@ -166,5 +165,4 @@
 %!error <DIM must be an integer> skewness (1, [], ones (2,2))
 %!error <DIM must be an integer> skewness (1, [], 1.5)
 %!error <DIM must be .* a valid dimension> skewness (1, [], 0)
-%!error <DIM must be .* a valid dimension> skewness (1, [], 3)
 
--- a/scripts/statistics/base/std.m	Fri Feb 19 09:40:59 2016 -0800
+++ b/scripts/statistics/base/std.m	Fri Feb 19 21:27:03 2016 -0800
@@ -75,8 +75,7 @@
 
   if (isempty (opt))
     opt = 0;
-  endif
-  if (opt != 0 && opt != 1)
+  elseif (! isscalar (opt) || (opt != 0 && opt != 1))
     error ("std: normalization OPT must be 0 or 1");
   endif
 
@@ -86,13 +85,12 @@
     ## Find the first non-singleton dimension.
     (dim = find (sz > 1, 1)) || (dim = 1);
   else
-    if (!(isscalar (dim) && dim == fix (dim))
-        || !(1 <= dim && dim <= nd))
+    if (! (isscalar (dim) && dim == fix (dim) && dim > 0))
       error ("std: DIM must be an integer and a valid dimension");
     endif
   endif
 
-  n = sz(dim);
+  n = size (x, dim);
   if (n == 1 || isempty (x))
     if (isa (x, "single"))
       retval = zeros (sz, "single");
@@ -113,17 +111,21 @@
 %! assert (std (y), sqrt (2), sqrt (eps));
 %! assert (std (x, 0, 2), zeros (10, 1));
 
-%!assert (std (ones (3, 1, 2), 0, 2), zeros (3, 1, 2));
-%!assert (std ([1 2], 0), sqrt (2)/2, 5*eps);
-%!assert (std ([1 2], 1), 0.5, 5*eps);
-%!assert (std (1), 0);
-%!assert (std (single (1)), single (0));
-%!assert (std ([]), []);
-%!assert (std (ones (1,3,0,2)), ones (1,3,0,2));
+%!assert (std (ones (3, 1, 2), 0, 2), zeros (3, 1, 2))
+%!assert (std ([1 2], 0), sqrt (2)/2, 5*eps)
+%!assert (std ([1 2], 1), 0.5, 5*eps)
+%!assert (std (1), 0)
+%!assert (std (single (1)), single (0))
+%!assert (std ([]), [])
+%!assert (std (ones (1,3,0,2)), ones (1,3,0,2))
+%!assert (std ([1 2 3], [], 3), [0 0 0])
 
 ## Test input validation
 %!error std ()
 %!error std (1, 2, 3, 4)
-%!error std (['A'; 'B'])
-%!error std (1, -1)
+%!error <X must be a numeric> std (['A'; 'B'])
+%!error <OPT must be 0 or 1> std (1, 2)
+%!error <DIM must be an integer> std (1, [], ones (2,2))
+%!error <DIM must be an integer> std (1, [], 1.5)
+%!error <DIM must be .* a valid dimension> std (1, [], 0)
 
--- a/scripts/statistics/base/var.m	Fri Feb 19 09:40:59 2016 -0800
+++ b/scripts/statistics/base/var.m	Fri Feb 19 21:27:03 2016 -0800
@@ -75,8 +75,7 @@
 
   if (isempty (opt))
     opt = 0;
-  endif
-  if (opt != 0 && opt != 1)
+  elseif (opt != 0 && opt != 1)
     error ("var: normalization OPT must be 0 or 1");
   endif
 
@@ -86,13 +85,12 @@
     ## Find the first non-singleton dimension.
     (dim = find (sz > 1, 1)) || (dim = 1);
   else
-    if (!(isscalar (dim) && dim == fix (dim))
-        || !(1 <= dim && dim <= nd))
+    if (! (isscalar (dim) && dim == fix (dim) && dim > 0))
       error ("var: DIM must be an integer and a valid dimension");
     endif
   endif
 
-  n = sz(dim);
+  n = size (x, dim);
   if (n == 1)
     if (isa (x, "single"))
       retval = zeros (sz, "single");
@@ -113,11 +111,17 @@
 %!assert (var ([1,2,3]), 1)
 %!assert (var ([1,2,3], 1), 2/3, eps)
 %!assert (var ([1,2,3], [], 1), [0,0,0])
+%!assert (var ([1,2,3], [], 3), [0,0,0])
 
 ## Test input validation
 %!error var ()
 %!error var (1,2,3,4)
-%!error var (['A'; 'B'])
-%!error var (1, -1)
-%!error var ([], 1)
+%!error <X must be a numeric> var (['A'; 'B'])
+%!error <OPT must be 0 or 1> var (1, -1)
+%!error <FLAG must be 0 or 1> skewness (1, 2)
+%!error <FLAG must be 0 or 1> skewness (1, [1 0])
+%!error <DIM must be an integer> var (1, [], ones (2,2))
+%!error <DIM must be an integer> var (1, [], 1.5)
+%!error <DIM must be .* a valid dimension> var (1, [], 0)
+%!error <X must not be empty> var ([], 1)