# HG changeset patch # User Rik # Date 1316545993 25200 # Node ID 19b9f17d22aff18feab1a2731c34cede2bb343a0 # Parent 078729410a0d62d9bdac77dc2ad279eb41073076 Overhaul of statistical distribution functions Support class "single" 75% reduction in memory usage More Matlab compatibility for corner cases * betacdf.m, betainv.m, betapdf.m, betarnd.m, binocdf.m, binoinv.m, binopdf.m, binornd.m, cauchy_cdf.m, cauchy_inv.m, cauchy_pdf.m, cauchy_rnd.m, chi2cdf.m, chi2inv.m, chi2pdf.m, chi2rnd.m, discrete_cdf.m, discrete_inv.m, discrete_pdf.m, discrete_rnd.m, empirical_cdf.m, empirical_inv.m, empirical_pdf.m, empirical_rnd.m, expcdf.m, expinv.m, exppdf.m, exprnd.m, fcdf.m, finv.m, fpdf.m, frnd.m, gamcdf.m, gaminv.m, gampdf.m, gamrnd.m, geocdf.m, geoinv.m, geopdf.m, geornd.m, hygecdf.m, hygeinv.m, hygepdf.m, hygernd.m, kolmogorov_smirnov_cdf.m, laplace_cdf.m, laplace_inv.m, laplace_pdf.m, laplace_rnd.m, logistic_cdf.m, logistic_inv.m, logistic_pdf.m, logistic_rnd.m, logncdf.m, logninv.m, lognpdf.m, lognrnd.m, nbincdf.m, nbininv.m, nbinpdf.m, nbinrnd.m, normcdf.m, norminv.m, normpdf.m, normrnd.m, poisscdf.m, poissinv.m, poisspdf.m, poissrnd.m, stdnormal_cdf.m, stdnormal_inv.m, stdnormal_pdf.m, stdnormal_rnd.m, tcdf.m, tinv.m, tpdf.m, trnd.m, unidcdf.m, unidinv.m, unidpdf.m, unidrnd.m, unifcdf.m, unifinv.m, unifpdf.m, unifrnd.m, wblcdf.m, wblinv.m, wblpdf.m, wblrnd.m: Return "single" outputs for "single" inputs, Use logical indexing rather than find() for 75% memory savings, Add tests for all functions, Use consistent documentation across all functions, More Matlab compatibilitcy for corner cases. diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -4,9 +4,27 @@ ** The PCRE library is now required to build Octave. ** Octave now features a profiler, thanks to the work of Daniel Kraft - under the Google Summer of Code mentorship program. The manual has + under the Google Summer of Code mentorship program. The manual has been updated to reflect this addition. + ** Overhaul of statistical distribution functions + + Functions now return "single" outputs for inputs of class "single". + + 75% reduction in memory usage through use of logical indexing. + + Random sample functions now use the same syntax as rand() and accept + a comma separated list of dimensions or a dimension vector. + + Functions have been made Matlab-compatible with regard to special + cases (probability on boundaries, probabilities for values outside + distribution, etc.). This may cause subtle changes to existing + scripts. + + negative binomial function has been extended to real, non-integer inputs. + discrete_inv() now returns v(1) for 0 instead of NaN. + nbincdf() recoded to use closed form solution with betainc(). + ** strread, textscan, and textread have been completely revamped. They now support nearly all Matlab functionality including: @@ -20,7 +38,7 @@ ** Certain string functions have been modified for greater Matlab compatibility and for 15X greater performance when operating on cell array of strings. - deblank : Now requires character or cellstr input + deblank : Now requires character or cellstr input. strtrim : Now requires character or cellstr input. No longer trims nulls ("\0") from string for ML compatibility. strmatch: Follows documentation precisely and ignores trailing spaces diff --git a/scripts/statistics/distributions/betacdf.m b/scripts/statistics/distributions/betacdf.m --- a/scripts/statistics/distributions/betacdf.m +++ b/scripts/statistics/distributions/betacdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,9 +19,9 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} betacdf (@var{x}, @var{a}, @var{b}) -## For each element of @var{x}, returns the CDF at @var{x} of the beta -## distribution with parameters @var{a} and @var{b}, i.e., -## PROB (beta (@var{a}, @var{b}) @leq{} @var{x}). +## For each element of @var{x}, compute the cumulative distribution function +## (CDF) at @var{x} of the Beta distribution with parameters @var{a} and +## @var{b}. ## @end deftypefn ## Author: KH @@ -32,33 +33,61 @@ print_usage (); endif - if (!isscalar (a) || !isscalar(b)) + if (!isscalar (a) || !isscalar (b)) [retval, x, a, b] = common_size (x, a, b); if (retval > 0) - error ("betacdf: X, A and B must be of common size or scalar"); + error ("betacdf: X, A, and B must be of common size or scalars"); endif endif - sz = size(x); - cdf = zeros (sz); + if (iscomplex (x) || iscomplex (a) || iscomplex (b)) + error ("betacdf: X, A, and B must not be complex"); + endif - k = find (!(a > 0) | !(b > 0) | isnan (x)); - if (any (k)) - cdf (k) = NaN; + if (isa (x, "single") || isa (a, "single") || isa (b, "single")) + cdf = zeros (size (x), "single"); + else + cdf = zeros (size (x)); endif - k = find ((x >= 1) & (a > 0) & (b > 0)); - if (any (k)) - cdf (k) = 1; - endif + k = isnan (x) | !(a > 0) | !(b > 0); + cdf(k) = NaN; + + k = (x >= 1) & (a > 0) & (b > 0); + cdf(k) = 1; - k = find ((x > 0) & (x < 1) & (a > 0) & (b > 0)); - if (any (k)) - if (isscalar (a) && isscalar(b)) - cdf (k) = betainc (x(k), a, b); - else - cdf (k) = betainc (x(k), a(k), b(k)); - endif + k = (x > 0) & (x < 1) & (a > 0) & (b > 0); + if (isscalar (a) && isscalar (b)) + cdf(k) = betainc (x(k), a, b); + else + cdf(k) = betainc (x(k), a(k), b(k)); endif endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 2]; +%! y = [0 0 0.75 1 1]; +%!assert(betacdf (x, ones(1,5), 2*ones(1,5)), y); +%!assert(betacdf (x, 1, 2*ones(1,5)), y); +%!assert(betacdf (x, ones(1,5), 2), y); +%!assert(betacdf (x, [0 1 NaN 1 1], 2), [NaN 0 NaN 1 1]); +%!assert(betacdf (x, 1, 2*[0 1 NaN 1 1]), [NaN 0 NaN 1 1]); +%!assert(betacdf ([x(1:2) NaN x(4:5)], 1, 2), [y(1:2) NaN y(4:5)]); + +%% Test class of input preserved +%!assert(betacdf ([x, NaN], 1, 2), [y, NaN]); +%!assert(betacdf (single([x, NaN]), 1, 2), single([y, NaN])); +%!assert(betacdf ([x, NaN], single(1), 2), single([y, NaN])); +%!assert(betacdf ([x, NaN], 1, single(2)), single([y, NaN])); + +%% Test input validation +%!error betacdf () +%!error betacdf (1) +%!error betacdf (1,2) +%!error betacdf (1,2,3,4) +%!error betacdf (ones(3),ones(2),ones(2)) +%!error betacdf (ones(2),ones(3),ones(2)) +%!error betacdf (ones(2),ones(2),ones(3)) + diff --git a/scripts/statistics/distributions/betainv.m b/scripts/statistics/distributions/betainv.m --- a/scripts/statistics/distributions/betainv.m +++ b/scripts/statistics/distributions/betainv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,7 +19,7 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} betainv (@var{x}, @var{a}, @var{b}) -## For each component of @var{x}, compute the quantile (the inverse of +## For each element of @var{x}, compute the quantile (the inverse of ## the CDF) at @var{x} of the Beta distribution with parameters @var{a} ## and @var{b}. ## @end deftypefn @@ -32,36 +33,39 @@ print_usage (); endif - if (!isscalar (a) || !isscalar(b)) + if (!isscalar (a) || !isscalar (b)) [retval, x, a, b] = common_size (x, a, b); if (retval > 0) - error ("betainv: X, A and B must be of common size or scalars"); + error ("betainv: X, A, and B must be of common size or scalars"); endif endif - sz = size (x); - inv = zeros (sz); - - k = find ((x < 0) | (x > 1) | !(a > 0) | !(b > 0) | isnan (x)); - if (any (k)) - inv (k) = NaN; + if (iscomplex (x) || iscomplex (a) || iscomplex (b)) + error ("betainv: X, A, and B must not be complex"); endif - k = find ((x == 1) & (a > 0) & (b > 0)); - if (any (k)) - inv (k) = 1; + if (isa (x, "single") || isa (a, "single") || isa (b, "single")) + inv = zeros (size (x), "single"); + else + inv = zeros (size (x)); endif + k = (x < 0) | (x > 1) | !(a > 0) | !(b > 0) | isnan (x); + inv(k) = NaN; + + k = (x == 1) & (a > 0) & (b > 0); + inv(k) = 1; + k = find ((x > 0) & (x < 1) & (a > 0) & (b > 0)); if (any (k)) - if (!isscalar(a) || !isscalar(b)) - a = a (k); - b = b (k); + if (!isscalar (a) || !isscalar (b)) + a = a(k); + b = b(k); y = a ./ (a + b); else y = a / (a + b) * ones (size (k)); endif - x = x (k); + x = x(k); if (isa (y, "single")) myeps = eps ("single"); @@ -97,7 +101,36 @@ y_old = y_new; endfor - inv (k) = y_new; + inv(k) = y_new; endif endfunction + + +%!shared x +%! x = [-1 0 0.75 1 2]; +%!assert(betainv (x, ones(1,5), 2*ones(1,5)), [NaN 0 0.5 1 NaN]); +%!assert(betainv (x, 1, 2*ones(1,5)), [NaN 0 0.5 1 NaN]); +%!assert(betainv (x, ones(1,5), 2), [NaN 0 0.5 1 NaN]); +%!assert(betainv (x, [1 0 NaN 1 1], 2), [NaN NaN NaN 1 NaN]); +%!assert(betainv (x, 1, 2*[1 0 NaN 1 1]), [NaN NaN NaN 1 NaN]); +%!assert(betainv ([x(1:2) NaN x(4:5)], 1, 2), [NaN 0 NaN 1 NaN]); + +%% Test class of input preserved +%!assert(betainv ([x, NaN], 1, 2), [NaN 0 0.5 1 NaN NaN]); +%!assert(betainv (single([x, NaN]), 1, 2), single([NaN 0 0.5 1 NaN NaN])); +%!assert(betainv ([x, NaN], single(1), 2), single([NaN 0 0.5 1 NaN NaN])); +%!assert(betainv ([x, NaN], 1, single(2)), single([NaN 0 0.5 1 NaN NaN])); + +%% Test input validation +%!error betainv () +%!error betainv (1) +%!error betainv (1,2) +%!error betainv (1,2,3,4) +%!error betainv (ones(3),ones(2),ones(2)) +%!error betainv (ones(2),ones(3),ones(2)) +%!error betainv (ones(2),ones(2),ones(3)) +%!error betainv (i, 2, 2) +%!error betainv (2, i, 2) +%!error betainv (2, 2, i) + diff --git a/scripts/statistics/distributions/betapdf.m b/scripts/statistics/distributions/betapdf.m --- a/scripts/statistics/distributions/betapdf.m +++ b/scripts/statistics/distributions/betapdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## Copyright (C) 2010 Christos Dimitrakakis ## @@ -19,8 +20,8 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} betapdf (@var{x}, @var{a}, @var{b}) -## For each element of @var{x}, returns the PDF at @var{x} of the beta -## distribution with parameters @var{a} and @var{b}. +## For each element of @var{x}, compute the probability density function (PDF) +## at @var{x} of the Beta distribution with parameters @var{a} and @var{b}. ## @end deftypefn ## Author: KH , CD @@ -32,70 +33,98 @@ print_usage (); endif - if (!isscalar (a) || !isscalar(b)) + if (!isscalar (a) || !isscalar (b)) [retval, x, a, b] = common_size (x, a, b); if (retval > 0) - error ("betapdf: X, A and B must be of common size or scalar"); + error ("betapdf: X, A, and B must be of common size or scalars"); endif endif - sz = size (x); - pdf = zeros (sz); + if (iscomplex (x) || iscomplex (a) || iscomplex (b)) + error ("betapdf: X, A, and B must not be complex"); + endif - k = find (!(a > 0) | !(b > 0) | isnan (x)); - if (any (k)) - pdf (k) = NaN; + if (isa (x, "single") || isa (a, "single") || isa (b, "single")); + pdf = zeros (size (x), "single"); + else + pdf = zeros (size (x)); endif - k = find ((x > 0) & (x < 1) & (a > 0) & (b > 0) & ((a != 1) | (b != 1))); - if (any (k)) - if (isscalar(a) && isscalar(b)) - pdf(k) = exp ((a - 1) .* log (x(k)) - + (b - 1) .* log (1 - x(k)) - + lgamma(a + b) - lgamma(a) - lgamma(b)); - else - pdf(k) = exp ((a(k) - 1) .* log (x(k)) - + (b(k) - 1) .* log (1 - x(k)) - + lgamma(a(k) + b(k)) - lgamma(a(k)) - lgamma(b(k))); - endif + k = !(a > 0) | !(b > 0) | isnan (x); + pdf(k) = NaN; + + k = (x > 0) & (x < 1) & (a > 0) & (b > 0) & ((a != 1) | (b != 1)); + if (isscalar (a) && isscalar (b)) + pdf(k) = exp ((a - 1) * log (x(k)) + + (b - 1) * log (1 - x(k)) + + lgamma (a + b) - lgamma (a) - lgamma (b)); + else + pdf(k) = exp ((a(k) - 1) .* log (x(k)) + + (b(k) - 1) .* log (1 - x(k)) + + lgamma (a(k) + b(k)) - lgamma (a(k)) - lgamma (b(k))); endif ## Most important special cases when the density is finite. - k = find ((x == 0) & (a == 1) & (b > 0) & (b != 1)); - if (any (k)) - if (isscalar(a) && isscalar(b)) - pdf(k) = exp(lgamma(a + b) - lgamma(a) - lgamma(b)); - else - pdf(k) = exp(lgamma(a(k) + b(k)) - lgamma(a(k)) - lgamma(b(k))); - endif + k = (x == 0) & (a == 1) & (b > 0) & (b != 1); + if (isscalar (a) && isscalar (b)) + pdf(k) = exp (lgamma (a + b) - lgamma (a) - lgamma (b)); + else + pdf(k) = exp (lgamma (a(k) + b(k)) - lgamma (a(k)) - lgamma (b(k))); endif - k = find ((x == 1) & (b == 1) & (a > 0) & (a != 1)); - if (any (k)) - if (isscalar(a) && isscalar(b)) - pdf(k) = exp(lgamma(a + b) - lgamma(a) - lgamma(b)); - else - pdf(k) = exp(lgamma(a(k) + b(k)) - lgamma(a(k)) - lgamma(b(k))); - endif + k = (x == 1) & (b == 1) & (a > 0) & (a != 1); + if (isscalar (a) && isscalar (b)) + pdf(k) = exp (lgamma (a + b) - lgamma (a) - lgamma (b)); + else + pdf(k) = exp (lgamma (a(k) + b(k)) - lgamma (a(k)) - lgamma (b(k))); endif - k = find ((x >= 0) & (x <= 1) & (a == 1) & (b == 1)); - if (any (k)) - pdf(k) = 1; - endif + k = (x >= 0) & (x <= 1) & (a == 1) & (b == 1); + pdf(k) = 1; ## Other special case when the density at the boundary is infinite. - k = find ((x == 0) & (a < 1)); - if (any (k)) - pdf(k) = Inf; - endif + k = (x == 0) & (a < 1); + pdf(k) = Inf; - k = find ((x == 1) & (b < 1)); - if (any (k)) - pdf(k) = Inf; - endif + k = (x == 1) & (b < 1); + pdf(k) = Inf; endfunction -%% Test large values for betapdf + +%!shared x,y +%! x = [-1 0 0.5 1 2]; +%! y = [0 2 1 0 0]; +%!assert(betapdf (x, ones(1,5), 2*ones(1,5)), y); +%!assert(betapdf (x, 1, 2*ones(1,5)), y); +%!assert(betapdf (x, ones(1,5), 2), y); +%!assert(betapdf (x, [0 NaN 1 1 1], 2), [NaN NaN y(3:5)]); +%!assert(betapdf (x, 1, 2*[0 NaN 1 1 1]), [NaN NaN y(3:5)]); +%!assert(betapdf ([x, NaN], 1, 2), [y, NaN]); + +%% Test class of input preserved +%!assert(betapdf (single([x, NaN]), 1, 2), single([y, NaN])); +%!assert(betapdf ([x, NaN], single(1), 2), single([y, NaN])); +%!assert(betapdf ([x, NaN], 1, single(2)), single([y, NaN])); + +%% Beta (1/2,1/2) == arcsine distribution +%!test +%! x = rand (10,1); +%! y = 1./(pi * sqrt (x.*(1-x))); +%! assert(betapdf (x, 1/2, 1/2), y, 50*eps); + +%% Test large input values to betapdf %!assert (betapdf(0.5, 1000, 1000), 35.678, 1e-3) + +%% Test input validation +%!error betapdf () +%!error betapdf (1) +%!error betapdf (1,2) +%!error betapdf (1,2,3,4) +%!error betapdf (ones(3),ones(2),ones(2)) +%!error betapdf (ones(2),ones(3),ones(2)) +%!error betapdf (ones(2),ones(2),ones(3)) +%!error betapdf (i, 2, 2) +%!error betapdf (2, i, 2) +%!error betapdf (2, 2, i) + diff --git a/scripts/statistics/distributions/betarnd.m b/scripts/statistics/distributions/betarnd.m --- a/scripts/statistics/distributions/betarnd.m +++ b/scripts/statistics/distributions/betarnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,83 +18,120 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} betarnd (@var{a}, @var{b}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} betarnd (@var{a}, @var{b}, @var{sz}) -## Return an @var{r} by @var{c} or @code{size (@var{sz})} matrix of -## random samples from the Beta distribution with parameters @var{a} and -## @var{b}. Both @var{a} and @var{b} must be scalar or of size @var{r} -## by @var{c}. +## @deftypefn {Function File} {} betarnd (@var{a}, @var{b}) +## @deftypefnx {Function File} {} betarnd (@var{a}, @var{b}, @var{r}) +## @deftypefnx {Function File} {} betarnd (@var{a}, @var{b}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} betarnd (@var{a}, @var{b}, [@var{sz}]) +## Return a matrix of random samples from the Beta distribution with parameters +## @var{a} and @var{b}. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the common size of @var{a} and @var{b}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the common size of +## @var{a} and @var{b}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the Beta distribution -function rnd = betarnd (a, b, r, c) +function rnd = betarnd (a, b, varargin) - if (nargin > 1) - if (!isscalar(a) || !isscalar(b)) - [retval, a, b] = common_size (a, b); - if (retval > 0) - error ("betarnd: A and B must be of common size or scalar"); - endif + if (nargin < 2) + print_usage (); + endif + + if (!isscalar (a) || !isscalar (b)) + [retval, a, b] = common_size (a, b); + if (retval > 0) + error ("betarnd: A and B must be of common size or scalars"); endif endif - if (nargin == 4) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("betarnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("betarnd: C must be a positive integer"); - endif - sz = [r, c]; + if (iscomplex (a) || iscomplex (b)) + error ("betarnd: A and B must not be complex"); + endif - if (any (size (a) != 1) - && (length (size (a)) != length (sz) || any (size (a) != sz))) - error ("betarnd: A and B must be scalar or of size [R,C]"); - endif + if (nargin == 2) + sz = size (a); elseif (nargin == 3) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; else - error ("betarnd: R must be a positive integer or vector"); + error ("betarnd: dimension vector must be row vector of non-negative integers"); endif - - if (any (size (a) != 1) - && (length (size (a)) != length (sz) || any (size (a) != sz))) - error ("betarnd: A and B must be scalar or of size SZ"); + elseif (nargin > 3) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("betarnd: dimensions must be non-negative integers"); endif - elseif (nargin == 2) - sz = size(a); - else - print_usage (); + sz = [varargin{:}]; endif - if (isscalar(a) && isscalar(b)) - if (find (!(a > 0) | !(a < Inf) | !(b > 0) | !(b < Inf))) - rnd = NaN (sz); + if (!isscalar (a) && !isequal (size (a), sz)) + error ("betarnd: A and B must be scalar or of size SZ"); + endif + + if (isa (a, "single") || isa (b, "single")) + cls = "single"; + else + cls = "double"; + endif + + if (isscalar (a) && isscalar (b)) + if ((a > 0) && (a < Inf) && (b > 0) && (b < Inf)) + r = randg (a, sz); + rnd = r ./ (r + randg (b, sz)); + if (strcmp (cls, "single")) + rnd = single (rnd); + endif else - r1 = randg(a,sz); - rnd = r1 ./ (r1 + randg(b,sz)); + rnd = NaN (sz, cls); endif else - rnd = zeros (sz); + rnd = NaN (sz, cls); - k = find (!(a > 0) | !(a < Inf) | !(b > 0) | !(b < Inf)); - if (any (k)) - rnd(k) = NaN (size (k)); - endif - - k = find ((a > 0) & (a < Inf) & (b > 0) & (b < Inf)); - if (any (k)) - r1 = randg(a(k),size(k)); - rnd(k) = r1 ./ (r1 + randg(b(k),size(k))); - endif + k = (a > 0) & (a < Inf) & (b > 0) & (b < Inf); + r = randg (a(k)); + rnd(k) = r ./ (r + randg (b(k))); endif endfunction + + +%!assert(size (betarnd (1,2)), [1, 1]); +%!assert(size (betarnd (ones(2,1), 2)), [2, 1]); +%!assert(size (betarnd (ones(2,2), 2)), [2, 2]); +%!assert(size (betarnd (1, 2*ones(2,1))), [2, 1]); +%!assert(size (betarnd (1, 2*ones(2,2))), [2, 2]); +%!assert(size (betarnd (1, 2, 3)), [3, 3]); +%!assert(size (betarnd (1, 2, [4 1])), [4, 1]); +%!assert(size (betarnd (1, 2, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (betarnd (1, 2)), "double"); +%!assert(class (betarnd (single(1), 2)), "single"); +%!assert(class (betarnd (single([1 1]), 2)), "single"); +%!assert(class (betarnd (1, single(2))), "single"); +%!assert(class (betarnd (1, single([2 2]))), "single"); + +%% Test input validation +%!error betarnd () +%!error betarnd (1) +%!error betarnd (ones(3),ones(2)) +%!error betarnd (ones(2),ones(3)) +%!error betarnd (i, 2) +%!error betarnd (2, i) +%!error betarnd (1,2, -1) +%!error betarnd (1,2, ones(2)) +%!error binornd (1,2, [2 -1 2]) +%!error betarnd (1,2, 1, ones(2)) +%!error betarnd (1,2, 1, -1) +%!error betarnd (ones(2,2), 2, 3) +%!error betarnd (ones(2,2), 2, [3, 2]) +%!error betarnd (ones(2,2), 2, 2, 3) + diff --git a/scripts/statistics/distributions/binocdf.m b/scripts/statistics/distributions/binocdf.m --- a/scripts/statistics/distributions/binocdf.m +++ b/scripts/statistics/distributions/binocdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,8 +19,9 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} binocdf (@var{x}, @var{n}, @var{p}) -## For each element of @var{x}, compute the CDF at @var{x} of the -## binomial distribution with parameters @var{n} and @var{p}. +## For each element of @var{x}, compute the cumulative distribution function +## (CDF) at @var{x} of the binomial distribution with parameters @var{n} and +## @var{p}. ## @end deftypefn ## Author: KH @@ -34,34 +36,62 @@ if (!isscalar (n) || !isscalar (p)) [retval, x, n, p] = common_size (x, n, p); if (retval > 0) - error ("binocdf: X, N and P must be of common size or scalar"); + error ("binocdf: X, N, and P must be of common size or scalars"); endif endif - sz = size (x); - cdf = zeros (sz); + if (iscomplex (x) || iscomplex (n) || iscomplex (p)) + error ("binocdf: X, N, and P must not be complex"); + endif - k = find (isnan (x) | !(n >= 0) | (n != round (n)) - | !(p >= 0) | !(p <= 1)); - if (any (k)) - cdf(k) = NaN; + if (isa (x, "single") || isa (n, "single") || isa (p, "single")); + cdf = zeros (size (x), "single"); + else + cdf = zeros (size (x)); endif - k = find ((x >= n) & (n >= 0) & (n == round (n)) - & (p >= 0) & (p <= 1)); - if (any (k)) - cdf(k) = 1; - endif + k = isnan (x) | !(n >= 0) | (n != fix (n)) | !(p >= 0) | !(p <= 1); + cdf(k) = NaN; + + k = (x >= n) & (n >= 0) & (n == fix (n) & (p >= 0) & (p <= 1)); + cdf(k) = 1; - k = find ((x >= 0) & (x < n) & (n == round (n)) - & (p >= 0) & (p <= 1)); - if (any (k)) - tmp = floor (x(k)); - if (isscalar (n) && isscalar (p)) - cdf(k) = 1 - betainc (p, tmp + 1, n - tmp); - else - cdf(k) = 1 - betainc (p(k), tmp + 1, n(k) - tmp); - endif + k = (x >= 0) & (x < n) & (n == fix (n)) & (p >= 0) & (p <= 1); + tmp = floor (x(k)); + if (isscalar (n) && isscalar (p)) + cdf(k) = 1 - betainc (p, tmp + 1, n - tmp); + else + cdf(k) = 1 - betainc (p(k), tmp + 1, n(k) - tmp); endif endfunction + + +%!shared x,y +%! x = [-1 0 1 2 3]; +%! y = [0 1/4 3/4 1 1]; +%!assert(binocdf (x, 2*ones(1,5), 0.5*ones(1,5)), y); +%!assert(binocdf (x, 2, 0.5*ones(1,5)), y); +%!assert(binocdf (x, 2*ones(1,5), 0.5), y); +%!assert(binocdf (x, 2*[0 -1 NaN 1.1 1], 0.5), [0 NaN NaN NaN 1]); +%!assert(binocdf (x, 2, 0.5*[0 -1 NaN 3 1]), [0 NaN NaN NaN 1]); +%!assert(binocdf ([x(1:2) NaN x(4:5)], 2, 0.5), [y(1:2) NaN y(4:5)]); + +%% Test class of input preserved +%!assert(binocdf ([x, NaN], 2, 0.5), [y, NaN]); +%!assert(binocdf (single([x, NaN]), 2, 0.5), single([y, NaN])); +%!assert(binocdf ([x, NaN], single(2), 0.5), single([y, NaN])); +%!assert(binocdf ([x, NaN], 2, single(0.5)), single([y, NaN])); + +%% Test input validation +%!error binocdf () +%!error binocdf (1) +%!error binocdf (1,2) +%!error binocdf (1,2,3,4) +%!error binocdf (ones(3),ones(2),ones(2)) +%!error binocdf (ones(2),ones(3),ones(2)) +%!error binocdf (ones(2),ones(2),ones(3)) +%!error binocdf (i, 2, 2) +%!error binocdf (2, i, 2) +%!error binocdf (2, 2, i) + diff --git a/scripts/statistics/distributions/binoinv.m b/scripts/statistics/distributions/binoinv.m --- a/scripts/statistics/distributions/binoinv.m +++ b/scripts/statistics/distributions/binoinv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,8 +19,9 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} binoinv (@var{x}, @var{n}, @var{p}) -## For each element of @var{x}, compute the quantile at @var{x} of the -## binomial distribution with parameters @var{n} and @var{p}. +## For each element of @var{x}, compute the quantile (the inverse of +## the CDF) at @var{x} of the binomial distribution with parameters +## @var{n} and @var{p}. ## @end deftypefn ## Author: KH @@ -34,24 +36,29 @@ if (!isscalar (n) || !isscalar (p)) [retval, x, n, p] = common_size (x, n, p); if (retval > 0) - error ("binoinv: X, N and P must be of common size or scalars"); + error ("binoinv: X, N, and P must be of common size or scalars"); endif endif - sz = size (x); - inv = zeros (sz); + if (iscomplex (x) || iscomplex (n) || iscomplex (p)) + error ("binoinv: X, N, and P must not be complex"); + endif - k = find (!(x >= 0) | !(x <= 1) | !(n >= 0) | (n != round (n)) - | !(p >= 0) | !(p <= 1)); - if (any (k)) - inv(k) = NaN; + if (isa (x, "single") || isa (n, "single") || isa (p, "single")); + inv = zeros (size (x), "single"); + else + inv = zeros (size (x)); endif - k = find ((x >= 0) & (x <= 1) & (n >= 0) & (n == round (n)) - & (p >= 0) & (p <= 1)); + k = (!(x >= 0) | !(x <= 1) | !(n >= 0) | (n != fix (n)) | + !(p >= 0) | !(p <= 1)); + inv(k) = NaN; + + k = find ((x >= 0) & (x <= 1) & (n >= 0) & (n == fix (n) + & (p >= 0) & (p <= 1))); if (any (k)) if (isscalar (n) && isscalar (p)) - cdf = binopdf (0, n, p) * ones (size(k)); + cdf = binopdf (0, n, p) * ones (size (k)); while (any (inv(k) < n)) m = find (cdf < x(k)); if (any (m)) @@ -76,3 +83,32 @@ endif endfunction + + +%!shared x +%! x = [-1 0 0.5 1 2]; +%!assert(binoinv (x, 2*ones(1,5), 0.5*ones(1,5)), [NaN 0 1 2 NaN]); +%!assert(binoinv (x, 2, 0.5*ones(1,5)), [NaN 0 1 2 NaN]); +%!assert(binoinv (x, 2*ones(1,5), 0.5), [NaN 0 1 2 NaN]); +%!assert(binoinv (x, 2*[0 -1 NaN 1.1 1], 0.5), [NaN NaN NaN NaN NaN]); +%!assert(binoinv (x, 2, 0.5*[0 -1 NaN 3 1]), [NaN NaN NaN NaN NaN]); +%!assert(binoinv ([x(1:2) NaN x(4:5)], 2, 0.5), [NaN 0 NaN 2 NaN]); + +%% Test class of input preserved +%!assert(binoinv ([x, NaN], 2, 0.5), [NaN 0 1 2 NaN NaN]); +%!assert(binoinv (single([x, NaN]), 2, 0.5), single([NaN 0 1 2 NaN NaN])); +%!assert(binoinv ([x, NaN], single(2), 0.5), single([NaN 0 1 2 NaN NaN])); +%!assert(binoinv ([x, NaN], 2, single(0.5)), single([NaN 0 1 2 NaN NaN])); + +%% Test input validation +%!error binoinv () +%!error binoinv (1) +%!error binoinv (1,2) +%!error binoinv (1,2,3,4) +%!error binoinv (ones(3),ones(2),ones(2)) +%!error binoinv (ones(2),ones(3),ones(2)) +%!error binoinv (ones(2),ones(2),ones(3)) +%!error binoinv (i, 2, 2) +%!error binoinv (2, i, 2) +%!error binoinv (2, 2, i) + diff --git a/scripts/statistics/distributions/binopdf.m b/scripts/statistics/distributions/binopdf.m --- a/scripts/statistics/distributions/binopdf.m +++ b/scripts/statistics/distributions/binopdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -35,26 +36,60 @@ if (! isscalar (n) || ! isscalar (p)) [retval, x, n, p] = common_size (x, n, p); if (retval > 0) - error ("binopdf: X, N and P must be of common size or scalar"); + error ("binopdf: X, N, and P must be of common size or scalars"); endif endif - k = ((x >= 0) & (x <= n) - & (x == round (x)) & (n == round (n)) - & (p >= 0) & (p <= 1)); + if (iscomplex (x) || iscomplex (n) || iscomplex (p)) + error ("binopdf: X, N, and P must not be complex"); + endif - pdf = zeros (size (x)); + if (isa (x, "single") || isa (n, "single") || isa (p, "single")); + pdf = zeros (size (x), "single"); + else + pdf = zeros (size (x)); + endif + + k = (x == fix (x)) & (n == fix (n)) & (n >= 0) & (p >= 0) & (p <= 1); + pdf(! k) = NaN; - if (any (k(:))) - x = x(k); - if (! isscalar (n)) - n = n(k); - endif - if (! isscalar (p)) - p = p(k); - endif - z = gammaln(n+1) - gammaln(x+1) - gammaln(n-x+1) + x.*log(p) + (n-x).*log(1-p); - pdf(k) = exp (z); + + k &= ((x >= 0) & (x <= n)); + if (isscalar (n) && isscalar (p)) + pdf(k) = exp (gammaln (n+1) - gammaln (x(k)+1) - gammaln (n-x(k)+1) + + x(k)*log (p) + (n-x(k))*log (1-p)); + else + pdf(k) = exp (gammaln (n(k)+1) - gammaln (x(k)+1) - gammaln (n(k)-x(k)+1) + + x(k).*log (p(k)) + (n(k)-x(k)).*log (1-p(k))); endif endfunction + + +%!shared x,y +%! x = [-1 0 1 2 3]; +%! y = [0 1/4 1/2 1/4 0]; +%!assert(binopdf (x, 2*ones(1,5), 0.5*ones(1,5)), y); +%!assert(binopdf (x, 2, 0.5*ones(1,5)), y); +%!assert(binopdf (x, 2*ones(1,5), 0.5), y); +%!assert(binopdf (x, 2*[0 -1 NaN 1.1 1], 0.5), [0 NaN NaN NaN 0]); +%!assert(binopdf (x, 2, 0.5*[0 -1 NaN 3 1]), [0 NaN NaN NaN 0]); +%!assert(binopdf ([x, NaN], 2, 0.5), [y, NaN]); + +%% Test class of input preserved +%!assert(binopdf (single([x, NaN]), 2, 0.5), single([y, NaN])); +%!assert(binopdf ([x, NaN], single(2), 0.5), single([y, NaN])); +%!assert(binopdf ([x, NaN], 2, single(0.5)), single([y, NaN])); + +%% Test input validation +%!error binopdf () +%!error binopdf (1) +%!error binopdf (1,2) +%!error binopdf (1,2,3,4) +%!error binopdf (ones(3),ones(2),ones(2)) +%!error binopdf (ones(2),ones(3),ones(2)) +%!error binopdf (ones(2),ones(2),ones(3)) +%!error binopdf (i, 2, 2) +%!error binopdf (2, i, 2) +%!error binopdf (2, 2, i) + diff --git a/scripts/statistics/distributions/binornd.m b/scripts/statistics/distributions/binornd.m --- a/scripts/statistics/distributions/binornd.m +++ b/scripts/statistics/distributions/binornd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,96 +18,136 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} binornd (@var{n}, @var{p}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} binornd (@var{n}, @var{p}, @var{sz}) -## Return an @var{r} by @var{c} or a @code{size (@var{sz})} matrix of -## random samples from the binomial distribution with parameters @var{n} -## and @var{p}. Both @var{n} and @var{p} must be scalar or of size -## @var{r} by @var{c}. +## @deftypefn {Function File} {} binornd (@var{n}, @var{p}) +## @deftypefnx {Function File} {} binornd (@var{n}, @var{p}, @var{r}) +## @deftypefnx {Function File} {} binornd (@var{n}, @var{p}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} binornd (@var{n}, @var{p}, [@var{sz}]) +## Return a matrix of random samples from the binonmial distribution with +## parameters @var{n} and @var{p}. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the common size of @var{n} and @var{p}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the common size of +## @var{n} and @var{p}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the binomial distribution -function rnd = binornd (n, p, r, c) +function rnd = binornd (n, p, varargin) - if (nargin > 1) - if (!isscalar(n) || !isscalar(p)) - [retval, n, p] = common_size (n, p); - if (retval > 0) - error ("binornd: N and P must be of common size or scalar"); - endif + if (nargin < 2) + print_usage (); + endif + + if (!isscalar (n) || !isscalar (p)) + [retval, n, p] = common_size (n, p); + if (retval > 0) + error ("binornd: N and P must be of common size or scalars"); endif endif - if (nargin == 4) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("binornd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("binornd: C must be a positive integer"); - endif - sz = [r, c]; + if (iscomplex (n) || iscomplex (p)) + error ("binornd: N and P must not be complex"); + endif - if (any (size (n) != 1) - && (length (size (n)) != length (sz) || any (size (n) != sz))) - error ("binornd: N and must be scalar or of size [R, C]"); - endif + if (nargin == 2) + sz = size (n); elseif (nargin == 3) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; else - error ("binornd: R must be a positive integer or vector"); + error ("binornd: dimension vector must be row vector of non-negative integers"); endif + elseif (nargin > 3) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("binornd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif - if (any (size (n) != 1) - && (length (size (n)) != length (sz) || any (size (n) != sz))) - error ("binornd: N and must be scalar or of size SZ"); - endif - elseif (nargin == 2) - sz = size(n); + if (!isscalar (n) && !isequal (size (n), sz)) + error ("binornd: N and P must be scalar or of size SZ"); + endif + + if (isa (n, "single") || isa (p, "single")) + cls = "single"; else - print_usage (); + cls = "double"; endif if (isscalar (n) && isscalar (p)) - if (find (!(n >= 0) | !(n < Inf) | !(n == round (n)) | - !(p >= 0) | !(p <= 1))) - rnd = NaN (sz); - elseif (n == 0) - rnd = zeros (sz); - else + if ((n > 0) && (n < Inf) && (n == fix (n)) && (p >= 0) && (p <= 1)) nel = prod (sz); tmp = rand (n, nel); - rnd = sum(tmp < ones (n, nel) * p, 1); - rnd = reshape(rnd, sz); + rnd = sum (tmp < p, 1); + rnd = reshape (rnd, sz); + if (strcmp (cls, "single")) + rnd = single (rnd); + endif + elseif ((n == 0) && (p >= 0) && (p <= 1)) + rnd = zeros (sz, cls); + else + rnd = NaN (sz, cls); endif else - rnd = zeros (sz); + rnd = zeros (sz, cls); - k = find (!(n >= 0) | !(n < Inf) | !(n == round (n)) | - !(p >= 0) | !(p <= 1)); - if (any (k)) - rnd(k) = NaN; - endif + k = !(n >= 0) | !(n < Inf) | !(n == fix (n)) | !(p >= 0) | !(p <= 1); + rnd(k) = NaN; - k = find ((n > 0) & (n < Inf) & (n == round (n)) & (p >= 0) & (p <= 1)); - if (any (k)) + k = (n > 0) & (n < Inf) & (n == fix (n)) & (p >= 0) & (p <= 1); + if (any (k(:))) N = max (n(k)); - L = length (k); + L = sum (k(:)); tmp = rand (N, L); - ind = (1 : N)' * ones (1, L); - rnd(k) = sum ((tmp < ones (N, 1) * p(k)(:)') & - (ind <= ones (N, 1) * n(k)(:)'),1); + ind = repmat ((1 : N)', 1, L); + rnd(k) = sum ((tmp < repmat (p(k)(:)', N, 1)) & + (ind <= repmat (n(k)(:)', N, 1)), 1); endif endif endfunction -%!assert (binornd(0, 0, 1), 0) -%!assert (binornd([0, 0], [0, 0], 1, 2), [0, 0]) + +%!assert (binornd (0, 0, 1), 0) +%!assert (binornd ([0, 0], [0, 0], 1, 2), [0, 0]) + +%!assert(size (binornd (2, 1/2)), [1, 1]); +%!assert(size (binornd (2*ones(2,1), 1/2)), [2, 1]); +%!assert(size (binornd (2*ones(2,2), 1/2)), [2, 2]); +%!assert(size (binornd (2, 1/2*ones(2,1))), [2, 1]); +%!assert(size (binornd (2, 1/2*ones(2,2))), [2, 2]); +%!assert(size (binornd (2, 1/2, 3)), [3, 3]); +%!assert(size (binornd (2, 1/2, [4 1])), [4, 1]); +%!assert(size (binornd (2, 1/2, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (binornd (2, 0.5)), "double"); +%!assert(class (binornd (single(2), 0.5)), "single"); +%!assert(class (binornd (single([2 2]), 0.5)), "single"); +%!assert(class (binornd (2, single(0.5))), "single"); +%!assert(class (binornd (2, single([0.5 0.5]))), "single"); + +%% Test input validation +%!error binornd () +%!error binornd (1) +%!error binornd (ones(3),ones(2)) +%!error binornd (ones(2),ones(3)) +%!error binornd (i, 2) +%!error binornd (2, i) +%!error binornd (1,2, -1) +%!error binornd (1,2, ones(2)) +%!error binornd (1,2, [2 -1 2]) +%!error binornd (1,2, 1, ones(2)) +%!error binornd (1,2, 1, -1) +%!error binornd (ones(2,2), 2, 3) +%!error binornd (ones(2,2), 2, [3, 2]) +%!error binornd (ones(2,2), 2, 2, 3) + diff --git a/scripts/statistics/distributions/cauchy_cdf.m b/scripts/statistics/distributions/cauchy_cdf.m --- a/scripts/statistics/distributions/cauchy_cdf.m +++ b/scripts/statistics/distributions/cauchy_cdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,7 +18,8 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} cauchy_cdf (@var{x}, @var{location}, @var{scale}) +## @deftypefn {Function File} {} cauchy_cdf (@var{x}) +## @deftypefnx {Function File} {} cauchy_cdf (@var{x}, @var{location}, @var{scale}) ## For each element of @var{x}, compute the cumulative distribution ## function (CDF) at @var{x} of the Cauchy distribution with location ## parameter @var{location} and scale parameter @var{scale}. Default @@ -27,35 +29,63 @@ ## Author: KH ## Description: CDF of the Cauchy distribution -function cdf = cauchy_cdf (x, location, scale) +function cdf = cauchy_cdf (x, location = 0, scale = 1) - if (! (nargin == 1 || nargin == 3)) + if (nargin != 1 && nargin != 3) print_usage (); endif - if (nargin == 1) - location = 0; - scale = 1; - endif - if (!isscalar (location) || !isscalar (scale)) [retval, x, location, scale] = common_size (x, location, scale); if (retval > 0) - error ("cauchy_cdf: X, LOCATION and SCALE must be of common size or scalar"); + error ("cauchy_cdf: X, LOCATION, and SCALE must be of common size or scalars"); endif endif - sz = size (x); - cdf = NaN (sz); + if (iscomplex (x) || iscomplex (location) || iscomplex (scale)) + error ("cauchy_cdf: X, LOCATION, and SCALE must not be complex"); + endif - k = find (ones (sz) & (location > -Inf) & (location < Inf) - & (scale > 0) & (scale < Inf)); - if (any (k)) - if (isscalar (location) && isscalar (scale)) - cdf(k) = 0.5 + atan ((x(k) - location) ./ scale) / pi; - else - cdf(k) = 0.5 + atan ((x(k) - location(k)) ./ scale(k)) / pi; - endif + if (isa (x, "single") || isa (location, "single") || isa (scale, "single")); + cdf = NaN (size (x), "single"); + else + cdf = NaN (size (x)); + endif + + k = !isinf (location) & (scale > 0) & (scale < Inf); + if (isscalar (location) && isscalar (scale)) + cdf = 0.5 + atan ((x - location) / scale) / pi; + else + cdf(k) = 0.5 + atan ((x(k) - location(k)) ./ scale(k)) / pi; endif endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 2]; +%! y = 1/pi * atan ((x-1) / 2) + 1/2; +%!assert(cauchy_cdf (x, ones(1,5), 2*ones(1,5)), y); +%!assert(cauchy_cdf (x, 1, 2*ones(1,5)), y); +%!assert(cauchy_cdf (x, ones(1,5), 2), y); +%!assert(cauchy_cdf (x, [-Inf 1 NaN 1 Inf], 2), [NaN y(2) NaN y(4) NaN]); +%!assert(cauchy_cdf (x, 1, 2*[0 1 NaN 1 Inf]), [NaN y(2) NaN y(4) NaN]); +%!assert(cauchy_cdf ([x(1:2) NaN x(4:5)], 1, 2), [y(1:2) NaN y(4:5)]); + +%% Test class of input preserved +%!assert(cauchy_cdf ([x, NaN], 1, 2), [y, NaN]); +%!assert(cauchy_cdf (single([x, NaN]), 1, 2), single([y, NaN]), eps("single")); +%!assert(cauchy_cdf ([x, NaN], single(1), 2), single([y, NaN]), eps("single")); +%!assert(cauchy_cdf ([x, NaN], 1, single(2)), single([y, NaN]), eps("single")); + +%% Test input validation +%!error cauchy_cdf () +%!error cauchy_cdf (1,2) +%!error cauchy_cdf (1,2,3,4) +%!error cauchy_cdf (ones(3),ones(2),ones(2)) +%!error cauchy_cdf (ones(2),ones(3),ones(2)) +%!error cauchy_cdf (ones(2),ones(2),ones(3)) +%!error cauchy_cdf (i, 2, 2) +%!error cauchy_cdf (2, i, 2) +%!error cauchy_cdf (2, 2, i) + diff --git a/scripts/statistics/distributions/cauchy_inv.m b/scripts/statistics/distributions/cauchy_inv.m --- a/scripts/statistics/distributions/cauchy_inv.m +++ b/scripts/statistics/distributions/cauchy_inv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,7 +18,8 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} cauchy_inv (@var{x}, @var{location}, @var{scale}) +## @deftypefn {Function File} {} cauchy_inv (@var{x}) +## @deftypefnx {Function File} {} cauchy_inv (@var{x}, @var{location}, @var{scale}) ## For each element of @var{x}, compute the quantile (the inverse of the ## CDF) at @var{x} of the Cauchy distribution with location parameter ## @var{location} and scale parameter @var{scale}. Default values are @@ -27,47 +29,70 @@ ## Author: KH ## Description: Quantile function of the Cauchy distribution -function inv = cauchy_inv (x, location, scale) +function inv = cauchy_inv (x, location = 0, scale = 1) - if (! (nargin == 1 || nargin == 3)) + if (nargin != 1 && nargin != 3) print_usage (); endif - if (nargin == 1) - location = 0; - scale = 1; - endif - if (!isscalar (location) || !isscalar (scale)) [retval, x, location, scale] = common_size (x, location, scale); if (retval > 0) - error ("cauchy_inv: X, LOCATION and SCALE must be of common size or scalar"); + error ("cauchy_inv: X, LOCATION, and SCALE must be of common size or scalars"); endif endif - sz = size (x); - inv = NaN (sz); + if (iscomplex (x) || iscomplex (location) || iscomplex (scale)) + error ("cauchy_inv: X, LOCATION, and SCALE must not be complex"); + endif - ok = ((location > -Inf) & (location < Inf) & - (scale > 0) & (scale < Inf)); - - k = find ((x == 0) & ok); - if (any (k)) - inv(k) = -Inf; + if (isa (x, "single") || isa (location, "single") || isa (scale, "single")) + inv = NaN (size (x), "single"); + else + inv = NaN (size (x)); endif - k = find ((x > 0) & (x < 1) & ok); - if (any (k)) - if (isscalar (location) && isscalar (scale)) - inv(k) = location - scale .* cot (pi * x(k)); - else - inv(k) = location(k) - scale(k) .* cot (pi * x(k)); - endif - endif + ok = !isinf (location) & (scale > 0) & (scale < Inf); + + k = (x == 0) & ok; + inv(k) = -Inf; - k = find ((x == 1) & ok); - if (any (k)) - inv(k) = Inf; + k = (x == 1) & ok; + inv(k) = Inf; + + k = (x > 0) & (x < 1) & ok; + if (isscalar (location) && isscalar (scale)) + inv(k) = location - scale * cot (pi * x(k)); + else + inv(k) = location(k) - scale(k) .* cot (pi * x(k)); endif endfunction + + +%!shared x +%! x = [-1 0 0.5 1 2]; +%!assert(cauchy_inv (x, ones(1,5), 2*ones(1,5)), [NaN -Inf 1 Inf NaN], eps); +%!assert(cauchy_inv (x, 1, 2*ones(1,5)), [NaN -Inf 1 Inf NaN], eps); +%!assert(cauchy_inv (x, ones(1,5), 2), [NaN -Inf 1 Inf NaN], eps); +%!assert(cauchy_inv (x, [1 -Inf NaN Inf 1], 2), [NaN NaN NaN NaN NaN]); +%!assert(cauchy_inv (x, 1, 2*[1 0 NaN Inf 1]), [NaN NaN NaN NaN NaN]); +%!assert(cauchy_inv ([x(1:2) NaN x(4:5)], 1, 2), [NaN -Inf NaN Inf NaN]); + +%% Test class of input preserved +%!assert(cauchy_inv ([x, NaN], 1, 2), [NaN -Inf 1 Inf NaN NaN], eps); +%!assert(cauchy_inv (single([x, NaN]), 1, 2), single([NaN -Inf 1 Inf NaN NaN]), eps("single")); +%!assert(cauchy_inv ([x, NaN], single(1), 2), single([NaN -Inf 1 Inf NaN NaN]), eps("single")); +%!assert(cauchy_inv ([x, NaN], 1, single(2)), single([NaN -Inf 1 Inf NaN NaN]), eps("single")); + +%% Test input validation +%!error cauchy_inv () +%!error cauchy_inv (1,2) +%!error cauchy_inv (1,2,3,4) +%!error cauchy_inv (ones(3),ones(2),ones(2)) +%!error cauchy_inv (ones(2),ones(3),ones(2)) +%!error cauchy_inv (ones(2),ones(2),ones(3)) +%!error cauchy_inv (i, 2, 2) +%!error cauchy_inv (2, i, 2) +%!error cauchy_inv (2, 2, i) + diff --git a/scripts/statistics/distributions/cauchy_pdf.m b/scripts/statistics/distributions/cauchy_pdf.m --- a/scripts/statistics/distributions/cauchy_pdf.m +++ b/scripts/statistics/distributions/cauchy_pdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,7 +18,8 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} cauchy_pdf (@var{x}, @var{location}, @var{scale}) +## @deftypefn {Function File} {} cauchy_pdf (@var{x}) +## @deftypefnx {Function File} {} cauchy_pdf (@var{x}, @var{location}, @var{scale}) ## For each element of @var{x}, compute the probability density function ## (PDF) at @var{x} of the Cauchy distribution with location parameter ## @var{location} and scale parameter @var{scale} > 0. Default values are @@ -27,37 +29,69 @@ ## Author: KH ## Description: PDF of the Cauchy distribution -function pdf = cauchy_pdf (x, location, scale) +function pdf = cauchy_pdf (x, location = 0, scale = 1) - if (! (nargin == 1 || nargin == 3)) + if (nargin != 1 && nargin != 3) print_usage (); endif - if (nargin == 1) - location = 0; - scale = 1; - endif - if (!isscalar (location) || !isscalar (scale)) [retval, x, location, scale] = common_size (x, location, scale); if (retval > 0) - error ("cauchy_pdf: X, LOCATION and SCALE must be of common size or scalar"); + error ("cauchy_pdf: X, LOCATION, and SCALE must be of common size or scalars"); endif endif - sz = size (x); - pdf = NaN (sz); + if (iscomplex (x) || iscomplex (location) || iscomplex (scale)) + error ("cauchy_pdf: X, LOCATION, and SCALE must not be complex"); + endif - k = find ((x > -Inf) & (x < Inf) & (location > -Inf) & - (location < Inf) & (scale > 0) & (scale < Inf)); - if (any (k)) - if (isscalar (location) && isscalar (scale)) - pdf(k) = ((1 ./ (1 + ((x(k) - location) ./ scale) .^ 2)) - / pi ./ scale); - else - pdf(k) = ((1 ./ (1 + ((x(k) - location(k)) ./ scale(k)) .^ 2)) - / pi ./ scale(k)); - endif + if (isa (x, "single") || isa (location, "single") || isa (scale, "single")) + pdf = NaN (size (x), "single"); + else + pdf = NaN (size (x)); + endif + + k = !isinf (location) & (scale > 0) & (scale < Inf); + if (isscalar (location) && isscalar (scale)) + pdf = ((1 ./ (1 + ((x - location) / scale) .^ 2)) + / pi / scale); + else + pdf(k) = ((1 ./ (1 + ((x(k) - location(k)) ./ scale(k)) .^ 2)) + / pi ./ scale(k)); endif endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 2]; +%! y = 1/pi * ( 2 ./ ((x-1).^2 + 2^2) ); +%!assert(cauchy_pdf (x, ones(1,5), 2*ones(1,5)), y); +%!assert(cauchy_pdf (x, 1, 2*ones(1,5)), y); +%!assert(cauchy_pdf (x, ones(1,5), 2), y); +%!assert(cauchy_pdf (x, [-Inf 1 NaN 1 Inf], 2), [NaN y(2) NaN y(4) NaN]); +%!assert(cauchy_pdf (x, 1, 2*[0 1 NaN 1 Inf]), [NaN y(2) NaN y(4) NaN]); +%!assert(cauchy_pdf ([x, NaN], 1, 2), [y, NaN]); + +%% Test class of input preserved +%!assert(cauchy_pdf (single([x, NaN]), 1, 2), single([y, NaN]), eps("single")); +%!assert(cauchy_pdf ([x, NaN], single(1), 2), single([y, NaN]), eps("single")); +%!assert(cauchy_pdf ([x, NaN], 1, single(2)), single([y, NaN]), eps("single")); + +%% Cauchy (0,1) == Student's T distribution with 1 DOF +%!test +%! x = rand (10, 1); +%! assert(cauchy_pdf (x, 0, 1), tpdf (x, 1), eps); + +%% Test input validation +%!error cauchy_pdf () +%!error cauchy_pdf (1,2) +%!error cauchy_pdf (1,2,3,4) +%!error cauchy_pdf (ones(3),ones(2),ones(2)) +%!error cauchy_pdf (ones(2),ones(3),ones(2)) +%!error cauchy_pdf (ones(2),ones(2),ones(3)) +%!error cauchy_pdf (i, 2, 2) +%!error cauchy_pdf (2, i, 2) +%!error cauchy_pdf (2, 2, i) + diff --git a/scripts/statistics/distributions/cauchy_rnd.m b/scripts/statistics/distributions/cauchy_rnd.m --- a/scripts/statistics/distributions/cauchy_rnd.m +++ b/scripts/statistics/distributions/cauchy_rnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,78 +18,115 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} cauchy_rnd (@var{location}, @var{scale}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} cauchy_rnd (@var{location}, @var{scale}, @var{sz}) -## Return an @var{r} by @var{c} or a @code{size (@var{sz})} matrix of -## random samples from the Cauchy distribution with parameters @var{location} -## and @var{scale} which must both be scalar or of size @var{r} by @var{c}. +## @deftypefn {Function File} {} cauchy_rnd (@var{location}, @var{scale}) +## @deftypefnx {Function File} {} cauchy_rnd (@var{location}, @var{scale}, @var{r}) +## @deftypefnx {Function File} {} cauchy_rnd (@var{location}, @var{scale}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} cauchy_rnd (@var{location}, @var{scale}, [@var{sz}]) +## Return a matrix of random samples from the Cauchy distribution with +## parameters @var{location} and @var{scale}. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the common size of @var{location} and @var{scale}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the common size of +## @var{location} and @var{scale}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the Cauchy distribution -function rnd = cauchy_rnd (location, scale, r, c) +function rnd = cauchy_rnd (location, scale, varargin) - if (nargin > 1) - if (!isscalar (location) || !isscalar (scale)) - [retval, location, scale] = common_size (location, scale); - if (retval > 0) - error ("cauchy_rnd: LOCATION and SCALE must be of common size or scalar"); - endif + if (nargin < 2) + print_usage (); + endif + + if (!isscalar (location) || !isscalar (scale)) + [retval, location, scale] = common_size (location, scale); + if (retval > 0) + error ("cauchy_rnd: LOCATION and SCALE must be of common size or scalars"); endif endif - if (nargin == 4) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("cauchy_rnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("cauchy_rnd: C must be a positive integer"); - endif - sz = [r, c]; + if (iscomplex (location) || iscomplex (scale)) + error ("cauchy_rnd: LOCATION and SCALE must not be complex"); + endif - if (any (size (location) != 1) - && (length (size (location)) != length (sz) - || any (size (location) != sz))) - error ("cauchy_rnd: LOCATION and SCALE must be scalar or of size [R, C]"); - endif + if (nargin == 2) + sz = size (location); elseif (nargin == 3) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; else - error ("cauchy_rnd: R must be a positive integer or vector"); + error ("cauchy_rnd: dimension vector must be row vector of non-negative integers"); endif + elseif (nargin > 3) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("cauchy_rnd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif - if (any (size (location) != 1) - && (length (size (location)) != length (sz) - || any (size (location) != sz))) - error ("cauchy_rnd: LOCATION and SCALE must be scalar or of size SZ"); - endif - elseif (nargin == 2) - sz = size(location); + if (!isscalar (location) && !isequal (size (location), sz)) + error ("cauchy_rnd: LOCATION and SCALE must be scalar or of size SZ"); + endif + + if (isa (location, "single") || isa (scale, "single")) + cls = "single"; else - print_usage (); + cls = "double"; endif if (isscalar (location) && isscalar (scale)) - if (find (!(location > -Inf) | !(location < Inf) - | !(scale > 0) | !(scale < Inf))) - rnd = NaN (sz); + if (!isinf (location) && (scale > 0) && (scale < Inf)) + rnd = location - cot (pi * rand (sz)) * scale; else - rnd = location - cot (pi * rand (sz)) .* scale; + rnd = NaN (sz, cls); endif else - rnd = NaN (sz); - k = find ((location > -Inf) & (location < Inf) - & (scale > 0) & (scale < Inf)); - if (any (k)) - rnd(k) = location(k)(:) - cot (pi * rand (size (k))) .* scale(k)(:); - endif + rnd = NaN (sz, cls); + + k = !isinf (location) & (scale > 0) & (scale < Inf); + rnd(k) = location(k)(:) - cot (pi * rand (sum (k(:)), 1)) .* scale(k)(:); endif endfunction + + +%!assert(size (cauchy_rnd (1,2)), [1, 1]); +%!assert(size (cauchy_rnd (ones(2,1), 2)), [2, 1]); +%!assert(size (cauchy_rnd (ones(2,2), 2)), [2, 2]); +%!assert(size (cauchy_rnd (1, 2*ones(2,1))), [2, 1]); +%!assert(size (cauchy_rnd (1, 2*ones(2,2))), [2, 2]); +%!assert(size (cauchy_rnd (1, 2, 3)), [3, 3]); +%!assert(size (cauchy_rnd (1, 2, [4 1])), [4, 1]); +%!assert(size (cauchy_rnd (1, 2, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (cauchy_rnd (1, 2)), "double"); +%!assert(class (cauchy_rnd (single(1), 2)), "single"); +%!assert(class (cauchy_rnd (single([1 1]), 2)), "single"); +%!assert(class (cauchy_rnd (1, single(2))), "single"); +%!assert(class (cauchy_rnd (1, single([2 2]))), "single"); + +%% Test input validation +%!error cauchy_rnd () +%!error cauchy_rnd (1) +%!error cauchy_rnd (ones(3),ones(2)) +%!error cauchy_rnd (ones(2),ones(3)) +%!error cauchy_rnd (i, 2) +%!error cauchy_rnd (2, i) +%!error cauchy_rnd (1,2, -1) +%!error cauchy_rnd (1,2, ones(2)) +%!error cauchy_rnd (1,2, [2 -1 2]) +%!error cauchy_rnd (1,2, 1, ones(2)) +%!error cauchy_rnd (1,2, 1, -1) +%!error cauchy_rnd (ones(2,2), 2, 3) +%!error cauchy_rnd (ones(2,2), 2, [3, 2]) +%!error cauchy_rnd (ones(2,2), 2, 2, 3) + diff --git a/scripts/statistics/distributions/chi2cdf.m b/scripts/statistics/distributions/chi2cdf.m --- a/scripts/statistics/distributions/chi2cdf.m +++ b/scripts/statistics/distributions/chi2cdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -19,7 +20,7 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} chi2cdf (@var{x}, @var{n}) ## For each element of @var{x}, compute the cumulative distribution -## function (CDF) at @var{x} of the chisquare distribution with @var{n} +## function (CDF) at @var{x} of the chi-square distribution with @var{n} ## degrees of freedom. ## @end deftypefn @@ -35,10 +36,38 @@ if (!isscalar (n)) [retval, x, n] = common_size (x, n); if (retval > 0) - error ("chi2cdf: X and N must be of common size or scalar"); + error ("chi2cdf: X and N must be of common size or scalars"); endif endif - cdf = gamcdf (x, n / 2, 2); + if (iscomplex (x) || iscomplex (n)) + error ("chi2cdf: X and N must not be complex"); + endif + + cdf = gamcdf (x, n/2, 2); endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 2]; +%! y = [0, 1 - exp(-x(2:end)/2)]; +%!assert(chi2cdf (x, 2*ones(1,5)), y, eps); +%!assert(chi2cdf (x, 2), y, eps); +%!assert(chi2cdf (x, 2*[1 0 NaN 1 1]), [y(1) NaN NaN y(4:5)], eps); +%!assert(chi2cdf ([x(1:2) NaN x(4:5)], 2), [y(1:2) NaN y(4:5)], eps); + +%% Test class of input preserved +%!assert(chi2cdf ([x, NaN], 2), [y, NaN], eps); +%!assert(chi2cdf (single([x, NaN]), 2), single([y, NaN]), eps("single")); +%!assert(chi2cdf ([x, NaN], single(2)), single([y, NaN]), eps("single")); + +%% Test input validation +%!error chi2cdf () +%!error chi2cdf (1) +%!error chi2cdf (1,2,3) +%!error chi2cdf (ones(3),ones(2)) +%!error chi2cdf (ones(2),ones(3)) +%!error chi2cdf (i, 2) +%!error chi2cdf (2, i) + diff --git a/scripts/statistics/distributions/chi2inv.m b/scripts/statistics/distributions/chi2inv.m --- a/scripts/statistics/distributions/chi2inv.m +++ b/scripts/statistics/distributions/chi2inv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -19,7 +20,7 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} chi2inv (@var{x}, @var{n}) ## For each element of @var{x}, compute the quantile (the inverse of the -## CDF) at @var{x} of the chisquare distribution with @var{n} degrees of +## CDF) at @var{x} of the chi-square distribution with @var{n} degrees of ## freedom. ## @end deftypefn @@ -35,10 +36,37 @@ if (!isscalar (n)) [retval, x, n] = common_size (x, n); if (retval > 0) - error ("chi2inv: X and N must be of common size or scalar"); + error ("chi2inv: X and N must be of common size or scalars"); endif endif - inv = gaminv (x, n / 2, 2); + if (iscomplex (x) || iscomplex (n)) + error ("chi2inv: X and N must not be complex"); + endif + + inv = gaminv (x, n/2, 2); endfunction + + +%!shared x +%! x = [-1 0 0.3934693402873666 1 2]; +%!assert(chi2inv (x, 2*ones(1,5)), [NaN 0 1 Inf NaN], 5*eps); +%!assert(chi2inv (x, 2), [NaN 0 1 Inf NaN], 5*eps); +%!assert(chi2inv (x, 2*[0 1 NaN 1 1]), [NaN 0 NaN Inf NaN], 5*eps); +%!assert(chi2inv ([x(1:2) NaN x(4:5)], 2), [NaN 0 NaN Inf NaN], 5*eps); + +%% Test class of input preserved +%!assert(chi2inv ([x, NaN], 2), [NaN 0 1 Inf NaN NaN], 5*eps); +%!assert(chi2inv (single([x, NaN]), 2), single([NaN 0 1 Inf NaN NaN]), 5*eps("single")); +%!assert(chi2inv ([x, NaN], single(2)), single([NaN 0 1 Inf NaN NaN]), 5*eps("single")); + +%% Test input validation +%!error chi2inv () +%!error chi2inv (1) +%!error chi2inv (1,2,3) +%!error chi2inv (ones(3),ones(2)) +%!error chi2inv (ones(2),ones(3)) +%!error chi2inv (i, 2) +%!error chi2inv (2, i) + diff --git a/scripts/statistics/distributions/chi2pdf.m b/scripts/statistics/distributions/chi2pdf.m --- a/scripts/statistics/distributions/chi2pdf.m +++ b/scripts/statistics/distributions/chi2pdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -19,7 +20,7 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} chi2pdf (@var{x}, @var{n}) ## For each element of @var{x}, compute the probability density function -## (PDF) at @var{x} of the chisquare distribution with @var{n} degrees +## (PDF) at @var{x} of the chi-square distribution with @var{n} degrees ## of freedom. ## @end deftypefn @@ -35,10 +36,37 @@ if (!isscalar (n)) [retval, x, n] = common_size (x, n); if (retval > 0) - error ("chi2pdf: X and N must be of common size or scalar"); + error ("chi2pdf: X and N must be of common size or scalars"); endif endif - pdf = gampdf (x, n / 2, 2); + if (iscomplex (x) || iscomplex (n)) + error ("chi2pdf: X and N must not be complex"); + endif + + pdf = gampdf (x, n/2, 2); endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 Inf]; +%! y = [0, 1/2 * exp(-x(2:5)/2)]; +%!assert(chi2pdf (x, 2*ones(1,5)), y); +%!assert(chi2pdf (x, 2), y); +%!assert(chi2pdf (x, 2*[1 0 NaN 1 1]), [y(1) NaN NaN y(4:5)]); +%!assert(chi2pdf ([x, NaN], 2), [y, NaN]); + +%% Test class of input preserved +%!assert(chi2pdf (single([x, NaN]), 2), single([y, NaN])); +%!assert(chi2pdf ([x, NaN], single(2)), single([y, NaN])); + +%% Test input validation +%!error chi2pdf () +%!error chi2pdf (1) +%!error chi2pdf (1,2,3) +%!error chi2pdf (ones(3),ones(2)) +%!error chi2pdf (ones(2),ones(3)) +%!error chi2pdf (i, 2) +%!error chi2pdf (2, i) + diff --git a/scripts/statistics/distributions/chi2rnd.m b/scripts/statistics/distributions/chi2rnd.m --- a/scripts/statistics/distributions/chi2rnd.m +++ b/scripts/statistics/distributions/chi2rnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,75 +18,103 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} chi2rnd (@var{n}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} chi2rnd (@var{n}, @var{sz}) -## Return an @var{r} by @var{c} or a @code{size (@var{sz})} matrix of -## random samples from the chisquare distribution with @var{n} degrees -## of freedom. @var{n} must be a scalar or of size @var{r} by @var{c}. +## @deftypefn {Function File} {} chi2rnd (@var{n}) +## @deftypefnx {Function File} {} chi2rnd (@var{n}, @var{r}) +## @deftypefnx {Function File} {} chi2rnd (@var{n}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} chi2rnd (@var{n}, [@var{sz}]) +## Return a matrix of random samples from the chi-square distribution with +## @var{n} degrees of freedom. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the size of @var{n}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the size of +## @var{n}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the chi-square distribution -function rnd = chi2rnd (n, r, c) - - if (nargin == 3) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("chi2rnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("chi2rnd: C must be a positive integer"); - endif - sz = [r, c]; +function rnd = chi2rnd (n, varargin) - if (any (size (n) != 1) - && (length (size (n)) != length (sz) || any (size (n) != sz))) - error ("chi2rnd: N must be scalar or of size [R, C]"); - endif - elseif (nargin == 2) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; - else - error ("chi2rnd: R must be a positive integer or vector"); - endif - - if (any (size (n) != 1) - && (length (size (n)) != length (sz) || any (size (n) != sz))) - error ("chi2rnd: N must be scalar or of size SZ"); - endif - elseif (nargin == 1) - sz = size(n); - else + if (nargin < 1) print_usage (); endif - if (isscalar (n)) - if (find (!(n > 0) | !(n < Inf))) - rnd = NaN (sz); - else - rnd = 2 * randg(n/2, sz); - endif - else - [retval, n, dummy] = common_size (n, ones (sz)); - if (retval > 0) - error ("chi2rnd: a and b must be of common size or scalar"); + if (nargin == 1) + sz = size (n); + elseif (nargin == 2) + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; + else + error ("chi2rnd: dimension vector must be row vector of non-negative integers"); + endif + elseif (nargin > 2) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("chi2rnd: dimensions must be non-negative integers"); endif + sz = [varargin{:}]; + endif - rnd = zeros (sz); - k = find (!(n > 0) | !(n < Inf)); - if (any (k)) - rnd(k) = NaN; + if (!isscalar (n) && !isequal (size (n), sz)) + error ("chi2rnd: N must be scalar or of size SZ"); + endif + + if (iscomplex (n)) + error ("chi2rnd: N must not be complex"); + endif + + if (isa (n, "single")) + cls = "single"; + else + cls = "double"; + endif + + if (isscalar (n)) + if ((n > 0) && (n < Inf)) + rnd = 2 * randg (n/2, sz); + if (strcmp (cls, "single")) + rnd = single (rnd); + endif + else + rnd = NaN (sz, cls); endif + else + rnd = NaN (sz, cls); - k = find ((n > 0) & (n < Inf)); - if (any (k)) - rnd(k) = 2 * randg(n(k)/2, size(k)); - endif + k = (n > 0) | (n < Inf); + rnd(k) = 2 * randg (n(k)/2); endif endfunction + + +%!assert(size (chi2rnd (2)), [1, 1]); +%!assert(size (chi2rnd (ones(2,1))), [2, 1]); +%!assert(size (chi2rnd (ones(2,2))), [2, 2]); +%!assert(size (chi2rnd (1, 3)), [3, 3]); +%!assert(size (chi2rnd (1, [4 1])), [4, 1]); +%!assert(size (chi2rnd (1, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (chi2rnd (2)), "double"); +%!assert(class (chi2rnd (single(2))), "single"); +%!assert(class (chi2rnd (single([2 2]))), "single"); + +%% Test input validation +%!error chi2rnd () +%!error chi2rnd (ones(3),ones(2)) +%!error chi2rnd (ones(2),ones(3)) +%!error chi2rnd (i) +%!error chi2rnd (1, -1) +%!error chi2rnd (1, ones(2)) +%!error chi2rnd (1, [2 -1 2]) +%!error chi2rnd (ones(2,2), 3) +%!error chi2rnd (ones(2,2), [3, 2]) +%!error chi2rnd (ones(2,2), 2, 3) + diff --git a/scripts/statistics/distributions/discrete_cdf.m b/scripts/statistics/distributions/discrete_cdf.m --- a/scripts/statistics/distributions/discrete_cdf.m +++ b/scripts/statistics/distributions/discrete_cdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 2010-2011 David Bateman ## ## This file is part of Octave. @@ -29,28 +30,52 @@ print_usage (); endif - sz = size (x); - if (! isvector (v)) error ("discrete_cdf: V must be a vector"); + elseif (any (isnan (v))) + error ("discrete_cdf: V must not have any NaN elements"); elseif (! isvector (p) || (length (p) != length (v))) error ("discrete_cdf: P must be a vector with length (V) elements"); elseif (! (all (p >= 0) && any (p))) - error ("discrete_cdf: P must be a nonzero, nonnegative vector"); + error ("discrete_cdf: P must be a nonzero, non-negative vector"); + endif + + p = p(:) / sum (p); # Reshape and normalize probability vector + + if (isa (x, "single") || isa (v, "single") || isa (p, "single")); + cdf = NaN (size (x), "single"); + else + cdf = NaN (size (x)); endif - n = numel (x); - m = length (v); - x = reshape (x, n, 1); - v = reshape (v, 1, m); - p = reshape (p / sum (p), m, 1); - - cdf = NaN (sz); - k = find (!isnan (x)); - if (any (k)) - n = length (k); - [vs, vi] = sort (v); - cdf(k) = [0 ; cumsum(p(vi))](lookup (vs, x(k)) + 1); - endif + k = !isnan (x); + [vs, vi] = sort (v); + cdf(k) = [0 ; cumsum(p(vi))](lookup (vs, x(k)) + 1); endfunction + + +%!shared x,v,p,y +%! x = [-1 0.1 1.1 1.9 3]; +%! v = 0.1:0.2:1.9; +%! p = 1/length(v) * ones(1, length(v)); +%! y = [0 0.1 0.6 1 1]; +%!assert(discrete_cdf ([x, NaN], v, p), [y, NaN], eps); + +%% Test class of input preserved +%!assert(discrete_cdf (single([x, NaN]), v, p), single([y, NaN]), 2*eps("single")); +%!assert(discrete_cdf ([x, NaN], single(v), p), single([y, NaN]), 2*eps("single")); +%!assert(discrete_cdf ([x, NaN], v, single(p)), single([y, NaN]), 2*eps("single")); + +%% Test input validation +%!error discrete_cdf () +%!error discrete_cdf (1) +%!error discrete_cdf (1,2) +%!error discrete_cdf (1,2,3,4) +%!error discrete_cdf (1, ones(2), ones(2,1)) +%!error discrete_cdf (1, [1 ; NaN], ones(2,1)) +%!error discrete_cdf (1, ones(2,1), ones(1,1)) +%!error discrete_cdf (1, ones(2,1), [1 -1]) +%!error discrete_cdf (1, ones(2,1), [1 NaN]) +%!error discrete_cdf (1, ones(2,1), [0 0]) + diff --git a/scripts/statistics/distributions/discrete_inv.m b/scripts/statistics/distributions/discrete_inv.m --- a/scripts/statistics/distributions/discrete_inv.m +++ b/scripts/statistics/distributions/discrete_inv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1996-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,7 +19,7 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} discrete_inv (@var{x}, @var{v}, @var{p}) -## For each component of @var{x}, compute the quantile (the inverse of +## For each element of @var{x}, compute the quantile (the inverse of ## the CDF) at @var{x} of the univariate distribution which assumes the ## values in @var{v} with probabilities @var{p}. ## @end deftypefn @@ -32,35 +33,63 @@ print_usage (); endif - sz = size (x); - if (! isvector (v)) error ("discrete_inv: V must be a vector"); elseif (! isvector (p) || (length (p) != length (v))) error ("discrete_inv: P must be a vector with length (V) elements"); + elseif (any (isnan (p))) + error ("discrete_rnd: P must not have any NaN elements"); elseif (! (all (p >= 0) && any (p))) - error ("discrete_inv: P must be a nonzero, nonnegative vector"); + error ("discrete_inv: P must be a nonzero, non-negative vector"); + endif + + if (isa (x, "single") || isa (v, "single") || isa (p, "single")); + inv = NaN (size (x), "single"); + else + inv = NaN (size (x)); endif - n = numel (x); - x = reshape (x, 1, n); - m = length (v); - [v, idx] = sort (v); - p = reshape (cumsum (p (idx) / sum (p)), m, 1); - - inv = NaN (sz); - if (any (k = find (x == 0))) - inv(k) = -Inf; - endif - if (any (k = find (x == 1))) - inv(k) = v(m) * ones (size (k)); + ## FIXME: This isn't elegant. But cumsum and lookup together produce + ## different results when called with a single or a double. + if (isa (p, "single")); + p = double (p); endif - if (any (k = find ((x > 0) & (x < 1)))) - n = length (k); - inv (k) = v(length (p) - lookup (sort (p,"descend"), x(k)) + 1); - endif + [v, idx] = sort (v); + p = cumsum (p(idx)(:)) / sum (p); # Reshape and normalize probability vector + + k = (x == 0); + inv(k) = v(1); + + k = (x == 1); + inv(k) = v(end); + + k = (x > 0) & (x < 1); + inv(k) = v(length (p) - lookup (sort (p, "descend"), x(k)) + 1); endfunction +%!shared x,v,p,y +%! x = [-1 0 0.1 0.5 1 2]; +%! v = 0.1:0.2:1.9; +%! p = 1/length(v) * ones(1, length(v)); +%! y = [NaN v(1) v(1) v(end/2) v(end) NaN]; +%!assert(discrete_inv ([x, NaN], v, p), [y, NaN], eps); + +%% Test class of input preserved +%!assert(discrete_inv (single([x, NaN]), v, p), single([y, NaN]), eps("single")); +%!assert(discrete_inv ([x, NaN], single(v), p), single([y, NaN]), eps("single")); +%!assert(discrete_inv ([x, NaN], v, single(p)), single([y, NaN]), eps("single")); + +%% Test input validation +%!error discrete_inv () +%!error discrete_inv (1) +%!error discrete_inv (1,2) +%!error discrete_inv (1,2,3,4) +%!error discrete_inv (1, ones(2), ones(2,1)) +%!error discrete_inv (1, ones(2,1), ones(1,1)) +%!error discrete_inv (1, ones(2,1), [1 NaN]) +%!error discrete_inv (1, ones(2,1), [1 -1]) +%!error discrete_inv (1, ones(2,1), [0 0]) + diff --git a/scripts/statistics/distributions/discrete_pdf.m b/scripts/statistics/distributions/discrete_pdf.m --- a/scripts/statistics/distributions/discrete_pdf.m +++ b/scripts/statistics/distributions/discrete_pdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1996-2011 Kurt Hornik ## ## This file is part of Octave. @@ -24,7 +25,7 @@ ## @end deftypefn ## Author: KH -## Description: pDF of a discrete distribution +## Description: PDF of a discrete distribution function pdf = discrete_pdf (x, v, p) @@ -32,28 +33,53 @@ print_usage (); endif - sz = size (x); - if (! isvector (v)) error ("discrete_pdf: V must be a vector"); + elseif (any (isnan (v))) + error ("discrete_pdf: V must not have any NaN elements"); elseif (! isvector (p) || (length (p) != length (v))) error ("discrete_pdf: P must be a vector with length (V) elements"); elseif (! (all (p >= 0) && any (p))) - error ("discrete_pdf: P must be a nonzero, nonnegative vector"); + error ("discrete_pdf: P must be a nonzero, non-negative vector"); + endif + + ## Reshape and normalize probability vector. Values not in table get 0 prob. + p = [0 ; p(:)/sum(p)]; + + if (isa (x, "single") || isa (v, "single") || isa (p, "single")) + pdf = NaN (size (x), "single"); + else + pdf = NaN (size (x)); endif - n = numel (x); - m = length (v); - x = reshape (x, n, 1); - v = reshape (v, 1, m); - p = reshape (p / sum (p), m, 1); - - pdf = NaN (sz); - k = find (!isnan (x)); - if (any (k)) - n = length (k); - [vs, vi] = sort (v); - pdf (k) = p (vi(lookup (vs, x(k), 'm'))); - endif + k = !isnan (x); + [vs, vi] = sort (v(:)); + pdf(k) = p([0 ; vi](lookup (vs, x(k), 'm') + 1) + 1); endfunction + + +%!shared x,v,p,y +%! x = [-1 0.1 1.1 1.9 3]; +%! v = 0.1:0.2:1.9; +%! p = 1/length(v) * ones(1, length(v)); +%! y = [0 0.1 0.1 0.1 0]; +%!assert(discrete_pdf ([x, NaN], v, p), [y, NaN], 5*eps); + +%% Test class of input preserved +%!assert(discrete_pdf (single([x, NaN]), v, p), single([y, NaN]), 5*eps("single")); +%!assert(discrete_pdf ([x, NaN], single(v), p), single([y, NaN]), 5*eps("single")); +%!assert(discrete_pdf ([x, NaN], v, single(p)), single([y, NaN]), 5*eps("single")); + +%% Test input validation +%!error discrete_pdf () +%!error discrete_pdf (1) +%!error discrete_pdf (1,2) +%!error discrete_pdf (1,2,3,4) +%!error discrete_pdf (1, ones(2), ones(2,1)) +%!error discrete_pdf (1, [1 ; NaN], ones(2,1)) +%!error discrete_pdf (1, ones(2,1), ones(1,1)) +%!error discrete_pdf (1, ones(2,1), [1 -1]) +%!error discrete_pdf (1, ones(2,1), [1 NaN]) +%!error discrete_pdf (1, ones(2,1), [0 0]) + diff --git a/scripts/statistics/distributions/discrete_rnd.m b/scripts/statistics/distributions/discrete_rnd.m --- a/scripts/statistics/distributions/discrete_rnd.m +++ b/scripts/statistics/distributions/discrete_rnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1996-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,51 +18,29 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} discrete_rnd (@var{n}, @var{v}, @var{p}) -## @deftypefnx {Function File} {} discrete_rnd (@var{v}, @var{p}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} discrete_rnd (@var{v}, @var{p}, @var{sz}) -## Generate a row vector containing a random sample of size @var{n} from -## the univariate distribution which assumes the values in @var{v} with -## probabilities @var{p}. @var{n} must be a scalar. +## @deftypefn {Function File} {} discrete_rnd (@var{v}, @var{p}) +## @deftypefnx {Function File} {} discrete_rnd (@var{v}, @var{p}, @var{r}) +## @deftypefnx {Function File} {} discrete_rnd (@var{v}, @var{p}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} discrete_rnd (@var{v}, @var{p}, [@var{sz}]) +## Return a matrix of random samples from the univariate distribution which +## assumes the values in @var{v} with probabilities @var{p}. ## -## If @var{r} and @var{c} are given create a matrix with @var{r} rows and -## @var{c} columns. Or if @var{sz} is a vector, create a matrix of size -## @var{sz}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the common size of +## @var{v} and @var{p}. ## @end deftypefn ## Author: KH ## Description: Random deviates from a discrete distribution -function rnd = discrete_rnd (v, p, r, c) +function rnd = discrete_rnd (v, p, varargin) - if (nargin == 4) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("discrete_rnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("discrete_rnd: C must be a positive integer"); - endif - sz = [r, c]; - elseif (nargin == 3) - ## A potential problem happens here if all args are scalar, as - ## we can't distiguish between the command syntax. Thankfully this - ## case doesn't make much sense. So we assume the first syntax - ## if the first arg is scalar - - if (isscalar (v)) - sz = [1, floor(v)]; - v = p; - p = r; - else - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; - else - error ("discrete_rnd: R must be a positive integer or vector"); - endif - endif - else + if (nargin < 2) print_usage (); endif @@ -69,9 +48,57 @@ error ("discrete_rnd: V must be a vector"); elseif (! isvector (p) || (length (p) != length (v))) error ("discrete_rnd: P must be a vector with length (V) elements"); + elseif (any (isnan (p))) + error ("discrete_rnd: P must not have any NaN elements"); elseif (! (all (p >= 0) && any (p))) - error ("discrete_rnd: P must be a nonzero, nonnegative vector"); + error ("discrete_rnd: P must be a nonzero, non-negative vector"); + endif + + if (nargin == 2) + sz = size (v); + elseif (nargin == 3) + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; + else + error ("discrete_rnd: dimension vector must be row vector of non-negative integers"); + endif + elseif (nargin > 3) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("discrete_rnd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; endif - rnd = v (lookup (cumsum (p (1 : end-1)) / sum(p), rand (sz)) + 1); + rnd = v(lookup (cumsum (p(1:end-1)) / sum (p), rand (sz)) + 1); + rnd = reshape (rnd, sz); + endfunction + + +%!assert(size (discrete_rnd (1:2, 1:2, 3)), [3, 3]); +%!assert(size (discrete_rnd (1:2, 1:2, [4 1])), [4, 1]); +%!assert(size (discrete_rnd (1:2, 1:2, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (discrete_rnd (1:2, 1:2)), "double"); +%!assert(class (discrete_rnd (single(1:2), 1:2)), "single"); +## FIXME: Maybe this should work, maybe it shouldn't. +#%!assert(class (discrete_rnd (1:2, single(1:2))), "single"); + +%% Test input validation +%!error discrete_rnd () +%!error discrete_rnd (1) +%!error discrete_rnd (1:2,1:2, -1) +%!error discrete_rnd (1:2,1:2, ones(2)) +%!error discrete_rnd (1:2,1:2, [2 -1 2]) +%!error discrete_rnd (1:2,1:2, 1, ones(2)) +%!error discrete_rnd (1:2,1:2, 1, -1) +%% test v,p verification +%!error discrete_rnd (1, ones(2), ones(2,1)) +%!error discrete_rnd (1, ones(2,1), ones(1,1)) +%!error discrete_rnd (1, ones(2,1), [1 -1]) +%!error discrete_rnd (1, ones(2,1), [1 NaN]) +%!error discrete_rnd (1, ones(2,1), [0 0]) + diff --git a/scripts/statistics/distributions/empirical_cdf.m b/scripts/statistics/distributions/empirical_cdf.m --- a/scripts/statistics/distributions/empirical_cdf.m +++ b/scripts/statistics/distributions/empirical_cdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1996-2011 Kurt Hornik ## ## This file is part of Octave. @@ -36,6 +37,26 @@ error ("empirical_cdf: DATA must be a vector"); endif - cdf = discrete_cdf (x, data, ones (size (data)) / length (data)); + cdf = discrete_cdf (x, data, ones (size (data))); endfunction + + +%!shared x,v,y +%! x = [-1 0.1 1.1 1.9 3]; +%! v = 0.1:0.2:1.9; +%! y = [0 0.1 0.6 1 1]; +%!assert(empirical_cdf (x, v), y, eps); +%!assert(empirical_cdf ([x(1) NaN x(3:5)], v), [0 NaN 0.6 1 1], eps); + +%% Test class of input preserved +%!assert(empirical_cdf ([x, NaN], v), [y, NaN], eps); +%!assert(empirical_cdf (single([x, NaN]), v), single([y, NaN]), eps); +%!assert(empirical_cdf ([x, NaN], single(v)), single([y, NaN]), eps); + +%% Test input validation +%!error empirical_cdf () +%!error empirical_cdf (1) +%!error empirical_cdf (1,2,3) +%!error empirical_cdf (1, ones(2)) + diff --git a/scripts/statistics/distributions/empirical_inv.m b/scripts/statistics/distributions/empirical_inv.m --- a/scripts/statistics/distributions/empirical_inv.m +++ b/scripts/statistics/distributions/empirical_inv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1996-2011 Kurt Hornik ## ## This file is part of Octave. @@ -36,6 +37,25 @@ error ("empirical_inv: DATA must be a vector"); endif - inv = discrete_inv (x, data, ones (size (data)) / length (data)); + inv = discrete_inv (x, data, ones (size (data))); endfunction + + +%!shared x,v,y +%! x = [-1 0 0.1 0.5 1 2]; +%! v = 0.1:0.2:1.9; +%! y = [NaN v(1) v(1) v(end/2) v(end) NaN]; +%!assert(empirical_inv (x, v), y, eps); + +%% Test class of input preserved +%!assert(empirical_inv ([x, NaN], v), [y, NaN], eps); +%!assert(empirical_inv (single([x, NaN]), v), single([y, NaN]), eps); +%!assert(empirical_inv ([x, NaN], single(v)), single([y, NaN]), eps); + +%% Test input validation +%!error empirical_inv () +%!error empirical_inv (1) +%!error empirical_inv (1,2,3) +%!error empirical_inv (1, ones(2)) + diff --git a/scripts/statistics/distributions/empirical_pdf.m b/scripts/statistics/distributions/empirical_pdf.m --- a/scripts/statistics/distributions/empirical_pdf.m +++ b/scripts/statistics/distributions/empirical_pdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1996-2011 Kurt Hornik ## ## This file is part of Octave. @@ -36,6 +37,24 @@ error ("empirical_pdf: DATA must be a vector"); endif - pdf = discrete_pdf (x, data, ones (size (data)) / length (data)); + pdf = discrete_pdf (x, data, ones (size (data))); endfunction + + +%!shared x,v,y +%! x = [-1 0.1 1.1 1.9 3]; +%! v = 0.1:0.2:1.9; +%! y = [0 0.1 0.1 0.1 0]; +%!assert(empirical_pdf (x, v), y); + +%% Test class of input preserved +%!assert(empirical_pdf (single(x), v), single (y)); +%!assert(empirical_pdf (x, single(v)), single (y)); + +%% Test input validation +%!error empirical_pdf () +%!error empirical_pdf (1) +%!error empirical_pdf (1,2,3) +%!error empirical_inv (1, ones(2)) + diff --git a/scripts/statistics/distributions/empirical_rnd.m b/scripts/statistics/distributions/empirical_rnd.m --- a/scripts/statistics/distributions/empirical_rnd.m +++ b/scripts/statistics/distributions/empirical_rnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1996-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,29 +18,29 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} empirical_rnd (@var{n}, @var{data}) -## @deftypefnx {Function File} {} empirical_rnd (@var{data}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} empirical_rnd (@var{data}, @var{sz}) -## Generate a bootstrap sample of size @var{n} from the empirical -## distribution obtained from the univariate sample @var{data}. +## @deftypefn {Function File} {} empirical_rnd (@var{data}) +## @deftypefnx {Function File} {} empirical_rnd (@var{data}, @var{r}) +## @deftypefnx {Function File} {} empirical_rnd (@var{data}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} empirical_rnd (@var{data}, [@var{sz}]) +## Return a matrix of random samples from the empirical distribution obtained +## from the univariate sample @var{data}. ## -## If @var{r} and @var{c} are given create a matrix with @var{r} rows and -## @var{c} columns. Or if @var{sz} is a vector, create a matrix of size -## @var{sz}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is a random ordering +## of the sample @var{data}. ## @end deftypefn ## Author: KH ## Description: Bootstrap samples from the empirical distribution -function rnd = empirical_rnd (data, r, c) +function rnd = empirical_rnd (data, varargin) - if (nargin == 2) - if (isscalar(data)) - c = data; - data = r; - r = 1; - endif - elseif (nargin != 3) + if (nargin < 1) print_usage (); endif @@ -47,6 +48,22 @@ error ("empirical_rnd: DATA must be a vector"); endif - rnd = discrete_rnd (data, ones (size (data)) / length (data), r, c); + rnd = discrete_rnd (data, ones (size (data)), varargin{:}); endfunction + + +%!assert(size (empirical_rnd (ones (3, 1))), [3, 1]); +%!assert(size (empirical_rnd (1:2, [4 1])), [4, 1]); +%!assert(size (empirical_rnd (1:2, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (empirical_rnd (1:2, 1)), "double"); +%!assert(class (empirical_rnd (single(1:2), 1)), "single"); + +%% Test input validation +%!error empirical_rnd () +%!error empirical_rnd (ones(2), 1) +%% test data verification +%!error empirical_rnd (ones(2), 1, 1) + diff --git a/scripts/statistics/distributions/expcdf.m b/scripts/statistics/distributions/expcdf.m --- a/scripts/statistics/distributions/expcdf.m +++ b/scripts/statistics/distributions/expcdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -22,7 +23,7 @@ ## function (CDF) at @var{x} of the exponential distribution with ## mean @var{lambda}. ## -## The arguments can be of common size or scalar. +## The arguments can be of common size or scalars. ## @end deftypefn ## Author: KH @@ -34,40 +35,57 @@ print_usage (); endif - if (!isscalar (x) && !isscalar(lambda)) + if (!isscalar (lambda)) [retval, x, lambda] = common_size (x, lambda); if (retval > 0) - error ("expcdf: X and LAMBDA must be of common size or scalar"); + error ("expcdf: X and LAMBDA must be of common size or scalars"); endif endif - if (isscalar (x)) - sz = size (lambda); - else - sz = size (x); + if (iscomplex (x) || iscomplex (lambda)) + error ("expcdf: X and LAMBDA must not be complex"); endif - cdf = zeros (sz); - - k = find (isnan (x) | !(lambda > 0)); - if (any (k)) - cdf(k) = NaN; + if (isa (x, "single") || isa (lambda, "single")) + cdf = zeros (size (x), "single"); + else + cdf = zeros (size (x)); endif - k = find ((x == Inf) & (lambda > 0)); - if (any (k)) - cdf(k) = 1; - endif + k = isnan (x) | !(lambda > 0); + cdf(k) = NaN; + + k = (x == Inf) & (lambda > 0); + cdf(k) = 1; - k = find ((x > 0) & (x < Inf) & (lambda > 0)); - if (any (k)) - if isscalar (lambda) - cdf (k) = 1 - exp (- x(k) ./ lambda); - elseif isscalar (x) - cdf (k) = 1 - exp (- x ./ lambda(k)); - else - cdf (k) = 1 - exp (- x(k) ./ lambda(k)); - endif + k = (x > 0) & (x < Inf) & (lambda > 0); + if isscalar (lambda) + cdf(k) = 1 - exp (- x(k) / lambda); + else + cdf(k) = 1 - exp (- x(k) ./ lambda(k)); endif endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 Inf]; +%! y = [0, 1 - exp(-x(2:end)/2)]; +%!assert(expcdf (x, 2*ones(1,5)), y); +%!assert(expcdf (x, 2), y); +%!assert(expcdf (x, 2*[1 0 NaN 1 1]), [y(1) NaN NaN y(4:5)]); + +%% Test class of input preserved +%!assert(expcdf ([x, NaN], 2), [y, NaN]); +%!assert(expcdf (single([x, NaN]), 2), single([y, NaN])); +%!assert(expcdf ([x, NaN], single(2)), single([y, NaN])); + +%% Test input validation +%!error expcdf () +%!error expcdf (1) +%!error expcdf (1,2,3) +%!error expcdf (ones(3),ones(2)) +%!error expcdf (ones(2),ones(3)) +%!error expcdf (i, 2) +%!error expcdf (2, i) + diff --git a/scripts/statistics/distributions/expinv.m b/scripts/statistics/distributions/expinv.m --- a/scripts/statistics/distributions/expinv.m +++ b/scripts/statistics/distributions/expinv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -19,8 +20,7 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} expinv (@var{x}, @var{lambda}) ## For each element of @var{x}, compute the quantile (the inverse of the -## CDF) at @var{x} of the exponential distribution with mean -## @var{lambda}. +## CDF) at @var{x} of the exponential distribution with mean @var{lambda}. ## @end deftypefn ## Author: KH @@ -32,41 +32,64 @@ print_usage (); endif - if (!isscalar (x) && !isscalar(lambda)) + if (!isscalar (lambda)) [retval, x, lambda] = common_size (x, lambda); if (retval > 0) - error ("expinv: X and LAMBDA must be of common size or scalar"); + error ("expinv: X and LAMBDA must be of common size or scalars"); endif endif - if (isscalar (x)) - sz = size (lambda); - else - sz = size (x); + if (iscomplex (x) || iscomplex (lambda)) + error ("expinv: X and LAMBDA must not be complex"); endif - inv = zeros (sz); + if (!isscalar (x)) + sz = size (x); + else + sz = size (lambda); + endif - k = find (!(lambda > 0) | (x < 0) | (x > 1) | isnan (x)); - if (any (k)) - inv(k) = NaN; + if (iscomplex (x) || iscomplex (lambda)) + error ("expinv: X and LAMBDA must not be complex"); endif - k = find ((x == 1) & (lambda > 0)); - if (any (k)) - inv(k) = Inf; + if (isa (x, "single") || isa (lambda, "single")) + inv = NaN (size (x), "single"); + else + inv = NaN (size (x)); endif - k = find ((x > 0) & (x < 1) & (lambda > 0)); - if (any (k)) - if isscalar (lambda) - inv(k) = - lambda .* log (1 - x(k)); - elseif isscalar (x) - inv(k) = - lambda(k) .* log (1 - x); - else - inv(k) = - lambda(k) .* log (1 - x(k)); - endif + k = (x == 1) & (lambda > 0); + inv(k) = Inf; + + k = (x >= 0) & (x < 1) & (lambda > 0); + if isscalar (lambda) + inv(k) = - lambda * log (1 - x(k)); + else + inv(k) = - lambda(k) .* log (1 - x(k)); endif endfunction + +%!shared x +%! x = [-1 0 0.3934693402873666 1 2]; +%!assert(expinv (x, 2*ones(1,5)), [NaN 0 1 Inf NaN], eps); +%!assert(expinv (x, 2), [NaN 0 1 Inf NaN], eps); +%!assert(expinv (x, 2*[1 0 NaN 1 1]), [NaN NaN NaN Inf NaN], eps); +%!assert(expinv ([x(1:2) NaN x(4:5)], 2), [NaN 0 NaN Inf NaN], eps); + +%% Test class of input preserved +%!assert(expinv ([x, NaN], 2), [NaN 0 1 Inf NaN NaN], eps); +%!assert(expinv (single([x, NaN]), 2), single([NaN 0 1 Inf NaN NaN]), eps); +%!assert(expinv ([x, NaN], single(2)), single([NaN 0 1 Inf NaN NaN]), eps); + +%% Test input validation +%!error expinv () +%!error expinv (1) +%!error expinv (1,2,3) +%!error expinv (ones(3),ones(2)) +%!error expinv (ones(2),ones(3)) +%!error expinv (i, 2) +%!error expinv (2, i) + diff --git a/scripts/statistics/distributions/exppdf.m b/scripts/statistics/distributions/exppdf.m --- a/scripts/statistics/distributions/exppdf.m +++ b/scripts/statistics/distributions/exppdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -19,7 +20,7 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} exppdf (@var{x}, @var{lambda}) ## For each element of @var{x}, compute the probability density function -## (PDF) of the exponential distribution with mean @var{lambda}. +## (PDF) at @var{x} of the exponential distribution with mean @var{lambda}. ## @end deftypefn ## Author: KH @@ -31,34 +32,53 @@ print_usage (); endif - if (!isscalar (x) && !isscalar(lambda)) + if (!isscalar (lambda)) [retval, x, lambda] = common_size (x, lambda); if (retval > 0) - error ("exppdf: X and LAMBDA must be of common size or scalar"); + error ("exppdf: X and LAMBDA must be of common size or scalars"); endif endif - if (isscalar (x)) - sz = size (lambda); - else - sz = size (x); - endif - pdf = zeros (sz); - - k = find (!(lambda > 0) | isnan (x)); - if (any (k)) - pdf(k) = NaN; + if (iscomplex (x) || iscomplex (lambda)) + error ("exppdf: X and LAMBDA must not be complex"); endif - k = find ((x >= 0) & (x < Inf) & (lambda > 0)); - if (any (k)) - if isscalar (lambda) - pdf(k) = exp (- x(k) ./ lambda) ./ lambda; - elseif isscalar (x) - pdf(k) = exp (- x ./ lambda(k)) ./ lambda(k); - else - pdf(k) = exp (- x(k) ./ lambda(k)) ./ lambda(k); - endif + if (isa (x, "single") || isa (lambda, "single")) + pdf = zeros (size (x), "single"); + else + pdf = zeros (size (x)); + endif + + k = isnan (x) | !(lambda > 0); + pdf(k) = NaN; + + k = (x >= 0) & (x < Inf) & (lambda > 0); + if isscalar (lambda) + pdf(k) = exp (- x(k) / lambda) / lambda; + else + pdf(k) = exp (- x(k) ./ lambda(k)) ./ lambda(k); endif endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 Inf]; +%! y = gampdf (x, 1, 2); +%!assert(exppdf (x, 2*ones(1,5)), y); +%!assert(exppdf (x, 2*[1 0 NaN 1 1]), [y(1) NaN NaN y(4:5)]); +%!assert(exppdf ([x, NaN], 2), [y, NaN]); + +%% Test class of input preserved +%!assert(exppdf (single([x, NaN]), 2), single([y, NaN])); +%!assert(exppdf ([x, NaN], single(2)), single([y, NaN])); + +%% Test input validation +%!error exppdf () +%!error exppdf (1) +%!error exppdf (1,2,3) +%!error exppdf (ones(3),ones(2)) +%!error exppdf (ones(2),ones(3)) +%!error exppdf (i, 2) +%!error exppdf (2, i) + diff --git a/scripts/statistics/distributions/exprnd.m b/scripts/statistics/distributions/exprnd.m --- a/scripts/statistics/distributions/exprnd.m +++ b/scripts/statistics/distributions/exprnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,71 +18,100 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} exprnd (@var{lambda}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} exprnd (@var{lambda}, @var{sz}) -## Return an @var{r} by @var{c} matrix of random samples from the -## exponential distribution with mean @var{lambda}, which must be a -## scalar or of size @var{r} by @var{c}. Or if @var{sz} is a vector, -## create a matrix of size @var{sz}. +## @deftypefn {Function File} {} exprnd (@var{lambda}) +## @deftypefnx {Function File} {} exprnd (@var{lambda}, @var{r}) +## @deftypefnx {Function File} {} exprnd (@var{lambda}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} exprnd (@var{lambda}, [@var{sz}]) +## Return a matrix of random samples from the exponential distribution with +## mean @var{lambda}. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the size of @var{lambda}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the size of +## @var{lambda}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the exponential distribution -function rnd = exprnd (lambda, r, c) - - if (nargin == 3) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("exprnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("exprnd: C must be a positive integer"); - endif - sz = [r, c]; +function rnd = exprnd (lambda, varargin) - if (any (size (lambda) != 1) - && (length (size (lambda)) != length (sz) || any (size (lambda) != sz))) - error ("exprnd: LAMBDA must be scalar or of size [R, C]"); - endif - elseif (nargin == 2) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; - else - error ("exprnd: R must be a positive integer or vector"); - endif - - if (any (size (lambda) != 1) - && ((length (size (lambda)) != length (sz)) || any (size (lambda) != sz))) - error ("exprnd: LAMBDA must be scalar or of size SZ"); - endif - elseif (nargin == 1) - sz = size (lambda); - else + if (nargin < 1) print_usage (); endif + if (nargin == 1) + sz = size (lambda); + elseif (nargin == 2) + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; + else + error ("exprnd: dimension vector must be row vector of non-negative integers"); + endif + elseif (nargin > 2) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("exprnd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif + + if (!isscalar (lambda) && !isequal (size (lambda), sz)) + error ("exprnd: LAMBDA must be scalar or of size SZ"); + endif + + if (iscomplex (lambda)) + error ("exprnd: LAMBDA must not be complex"); + endif + + if (isa (lambda, "single")) + cls = "single"; + else + cls = "double"; + endif if (isscalar (lambda)) if ((lambda > 0) && (lambda < Inf)) - rnd = rande(sz) * lambda; + rnd = rande (sz) * lambda; else - rnd = NaN (sz); + rnd = NaN (sz, cls); endif else - rnd = zeros (sz); - k = find (!(lambda > 0) | !(lambda < Inf)); - if (any (k)) - rnd(k) = NaN; - endif - k = find ((lambda > 0) & (lambda < Inf)); - if (any (k)) - rnd(k) = rande(size(k)) .* lambda(k); - endif + rnd = NaN (sz, cls); + + k = (lambda > 0) & (lambda < Inf); + rnd(k) = rande (sum (k(:)), 1) .* lambda(k)(:); endif endfunction + + +%!assert(size (exprnd (2)), [1, 1]); +%!assert(size (exprnd (ones(2,1))), [2, 1]); +%!assert(size (exprnd (ones(2,2))), [2, 2]); +%!assert(size (exprnd (1, 3)), [3, 3]); +%!assert(size (exprnd (1, [4 1])), [4, 1]); +%!assert(size (exprnd (1, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (exprnd (1)), "double"); +%!assert(class (exprnd (single(1))), "single"); +%!assert(class (exprnd (single([1 1]))), "single"); + +%% Test input validation +%!error exprnd () +%!error exprnd (1, -1) +%!error exprnd (1, ones(2)) +%!error exprnd (i) +%!error exprnd (1, [2 -1 2]) +%!error exprnd (1, 2, -1) +%!error exprnd (1, 2, ones(2)) +%!error exprnd (ones(2,2), 3) +%!error exprnd (ones(2,2), [3, 2]) +%!error exprnd (ones(2,2), 2, 3) + diff --git a/scripts/statistics/distributions/fcdf.m b/scripts/statistics/distributions/fcdf.m --- a/scripts/statistics/distributions/fcdf.m +++ b/scripts/statistics/distributions/fcdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,9 +19,9 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} fcdf (@var{x}, @var{m}, @var{n}) -## For each element of @var{x}, compute the CDF at @var{x} of the F -## distribution with @var{m} and @var{n} degrees of freedom, i.e., -## PROB (F (@var{m}, @var{n}) @leq{} @var{x}). +## For each element of @var{x}, compute the cumulative distribution function +## (CDF) at @var{x} of the F distribution with @var{m} and @var{n} degrees of +## freedom. ## @end deftypefn ## Author: KH @@ -35,31 +36,61 @@ if (!isscalar (m) || !isscalar (n)) [retval, x, m, n] = common_size (x, m, n); if (retval > 0) - error ("fcdf: X, M and N must be of common size or scalar"); + error ("fcdf: X, M, and N must be of common size or scalars"); endif endif - sz = size (x); - cdf = zeros (sz); + if (iscomplex (x) || iscomplex (m) || iscomplex (n)) + error ("fcdf: X, M, and N must not be complex"); + endif - k = find (!(m > 0) | !(n > 0) | isnan (x)); - if (any (k)) - cdf(k) = NaN; + if (isa (x, "single") || isa (m, "single") || isa (n, "single")) + cdf = zeros (size (x), "single"); + else + cdf = zeros (size (x)); endif - k = find ((x == Inf) & (m > 0) & (n > 0)); - if (any (k)) - cdf(k) = 1; - endif + k = isnan (x) | !(m > 0) | !(m < Inf) | !(n > 0) | !(n < Inf); + cdf(k) = NaN; + + k = (x == Inf) & (m > 0) & (m < Inf) & (n > 0) & (n < Inf); + cdf(k) = 1; - k = find ((x > 0) & (x < Inf) & (m > 0) & (n > 0)); - if (any (k)) - if (isscalar (m) && isscalar (n)) - cdf(k) = 1 - betainc (1 ./ (1 + m .* x(k) ./ n), n / 2, m / 2); - else - cdf(k) = 1 - betainc (1 ./ (1 + m(k) .* x(k) ./ n(k)), n(k) / 2, - m(k) / 2); - endif + k = (x > 0) & (x < Inf) & (m > 0) & (m < Inf) & (n > 0) & (n < Inf); + if (isscalar (m) && isscalar (n)) + cdf(k) = 1 - betainc (1 ./ (1 + m * x(k) / n), n/2, m/2); + else + cdf(k) = 1 - betainc (1 ./ (1 + m(k) .* x(k) ./ n(k)), n(k)/2, m(k)/2); endif endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 2 Inf]; +%! y = [0 0 1/3 1/2 2/3 1]; +%!assert(fcdf (x, 2*ones(1,6), 2*ones(1,6)), y, eps); +%!assert(fcdf (x, 2, 2*ones(1,6)), y, eps); +%!assert(fcdf (x, 2*ones(1,6), 2), y, eps); +%!assert(fcdf (x, [0 NaN Inf 2 2 2], 2), [NaN NaN NaN y(4:6)], eps); +%!assert(fcdf (x, 2, [0 NaN Inf 2 2 2]), [NaN NaN NaN y(4:6)], eps); +%!assert(fcdf ([x(1:2) NaN x(4:6)], 2, 2), [y(1:2) NaN y(4:6)], eps); + +%% Test class of input preserved +%!assert(fcdf ([x, NaN], 2, 2), [y, NaN], eps); +%!assert(fcdf (single([x, NaN]), 2, 2), single([y, NaN]), eps("single")); +%!assert(fcdf ([x, NaN], single(2), 2), single([y, NaN]), eps("single")); +%!assert(fcdf ([x, NaN], 2, single(2)), single([y, NaN]), eps("single")); + +%% Test input validation +%!error fcdf () +%!error fcdf (1) +%!error fcdf (1,2) +%!error fcdf (1,2,3,4) +%!error fcdf (ones(3),ones(2),ones(2)) +%!error fcdf (ones(2),ones(3),ones(2)) +%!error fcdf (ones(2),ones(2),ones(3)) +%!error fcdf (i, 2, 2) +%!error fcdf (2, i, 2) +%!error fcdf (2, 2, i) + diff --git a/scripts/statistics/distributions/finv.m b/scripts/statistics/distributions/finv.m --- a/scripts/statistics/distributions/finv.m +++ b/scripts/statistics/distributions/finv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,9 +19,9 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} finv (@var{x}, @var{m}, @var{n}) -## For each component of @var{x}, compute the quantile (the inverse of -## the CDF) at @var{x} of the F distribution with parameters @var{m} and -## @var{n}. +## For each element of @var{x}, compute the quantile (the inverse of +## the CDF) at @var{x} of the F distribution with @var{m} and @var{n} +## degrees of freedom. ## @end deftypefn ## Author: KH @@ -35,31 +36,58 @@ if (!isscalar (m) || !isscalar (n)) [retval, x, m, n] = common_size (x, m, n); if (retval > 0) - error ("finv: X, M and N must be of common size or scalar"); + error ("finv: X, M, and N must be of common size or scalars"); endif endif - sz = size (x); - inv = zeros (sz); + if (iscomplex (x) || iscomplex (m) || iscomplex (n)) + error ("finv: X, M, and N must not be complex"); + endif - k = find ((x < 0) | (x > 1) | isnan (x) | !(m > 0) | !(n > 0)); - if (any (k)) - inv(k) = NaN; + if (isa (x, "single") || isa (m, "single") || isa (n, "single")) + inv = NaN (size (x), "single"); + else + inv = NaN (size (x)); endif - k = find ((x == 1) & (m > 0) & (n > 0)); - if (any (k)) - inv(k) = Inf; - endif + k = (x == 1) & (m > 0) & (m < Inf) & (n > 0) & (n < Inf); + inv(k) = Inf; - k = find ((x > 0) & (x < 1) & (m > 0) & (n > 0)); - if (any (k)) - if (isscalar (m) && isscalar (n)) - inv(k) = ((1 ./ betainv (1 - x(k), n / 2, m / 2) - 1) .* n ./ m); - else - inv(k) = ((1 ./ betainv (1 - x(k), n(k) / 2, m(k) / 2) - 1) - .* n(k) ./ m(k)); - endif + k = (x >= 0) & (x < 1) & (m > 0) & (m < Inf) & (n > 0) & (n < Inf); + if (isscalar (m) && isscalar (n)) + inv(k) = ((1 ./ betainv (1 - x(k), n/2, m/2) - 1) * n / m); + else + inv(k) = ((1 ./ betainv (1 - x(k), n(k)/2, m(k)/2) - 1) + .* n(k) ./ m(k)); endif endfunction + + +%!shared x +%! x = [-1 0 0.5 1 2]; +%!assert(finv (x, 2*ones(1,5), 2*ones(1,5)), [NaN 0 1 Inf NaN]); +%!assert(finv (x, 2, 2*ones(1,5)), [NaN 0 1 Inf NaN]); +%!assert(finv (x, 2*ones(1,5), 2), [NaN 0 1 Inf NaN]); +%!assert(finv (x, [2 -Inf NaN Inf 2], 2), [NaN NaN NaN NaN NaN]); +%!assert(finv (x, 2, [2 -Inf NaN Inf 2]), [NaN NaN NaN NaN NaN]); +%!assert(finv ([x(1:2) NaN x(4:5)], 2, 2), [NaN 0 NaN Inf NaN]); + +%% Test class of input preserved +%!assert(finv ([x, NaN], 2, 2), [NaN 0 1 Inf NaN NaN]); +%!assert(finv (single([x, NaN]), 2, 2), single([NaN 0 1 Inf NaN NaN])); +%!assert(finv ([x, NaN], single(2), 2), single([NaN 0 1 Inf NaN NaN])); +%!assert(finv ([x, NaN], 2, single(2)), single([NaN 0 1 Inf NaN NaN])); + +%% Test input validation +%!error finv () +%!error finv (1) +%!error finv (1,2) +%!error finv (1,2,3,4) +%!error finv (ones(3),ones(2),ones(2)) +%!error finv (ones(2),ones(3),ones(2)) +%!error finv (ones(2),ones(2),ones(3)) +%!error finv (i, 2, 2) +%!error finv (2, i, 2) +%!error finv (2, 2, i) + diff --git a/scripts/statistics/distributions/fpdf.m b/scripts/statistics/distributions/fpdf.m --- a/scripts/statistics/distributions/fpdf.m +++ b/scripts/statistics/distributions/fpdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -35,31 +36,70 @@ if (!isscalar (m) || !isscalar (n)) [retval, x, m, n] = common_size (x, m, n); if (retval > 0) - error ("fpdf: X, M and N must be of common size or scalar"); + error ("fpdf: X, M, and N must be of common size or scalars"); endif endif - sz = size (x); - pdf = zeros (sz); + if (iscomplex (x) || iscomplex (m) || iscomplex (n)) + error ("fpdf: X, M, and N must not be complex"); + endif - k = find (isnan (x) | !(m > 0) | !(n > 0)); - if (any (k)) - pdf(k) = NaN; + if (isa (x, "single") || isa (m, "single") || isa (n, "single")) + pdf = zeros (size (x), "single"); + else + pdf = zeros (size (x)); endif - k = find ((x > 0) & (x < Inf) & (m > 0) & (n > 0)); - if (any (k)) - if (isscalar (m) && isscalar (n)) - tmp = m / n * x(k); - pdf(k) = (exp ((m / 2 - 1) .* log (tmp) - - ((m + n) / 2) .* log (1 + tmp)) - .* (m / n) ./ beta (m / 2, n / 2)); - else - tmp = m(k) .* x(k) ./ n(k); - pdf(k) = (exp ((m(k) / 2 - 1) .* log (tmp) - - ((m(k) + n(k)) / 2) .* log (1 + tmp)) - .* (m(k) ./ n(k)) ./ beta (m(k) / 2, n(k) / 2)); - endif + k = isnan (x) | !(m > 0) | !(m < Inf) | !(n > 0) | !(n < Inf); + pdf(k) = NaN; + + k = (x > 0) & (x < Inf) & (m > 0) & (m < Inf) & (n > 0) & (n < Inf); + if (isscalar (m) && isscalar (n)) + tmp = m / n * x(k); + pdf(k) = (exp ((m/2 - 1) * log (tmp) + - ((m + n) / 2) * log (1 + tmp)) + * (m / n) ./ beta (m/2, n/2)); + else + tmp = m(k) .* x(k) ./ n(k); + pdf(k) = (exp ((m(k)/2 - 1) .* log (tmp) + - ((m(k) + n(k)) / 2) .* log (1 + tmp)) + .* (m(k) ./ n(k)) ./ beta (m(k)/2, n(k)/2)); endif endfunction + + +%% F (x, 1, m) == T distribution (sqrt (x), m) / sqrt (x) +%!test +%! x = rand (10,1); +%! x = x(x > 0.1 & x < 0.9); +%! y = tpdf (sqrt (x), 2) ./ sqrt (x); +%! assert(fpdf (x, 1, 2), y, 5*eps); + +%!shared x,y +%! x = [-1 0 0.5 1 2]; +%! y = [0 0 4/9 1/4 1/9]; +%!assert(fpdf (x, 2*ones(1,5), 2*ones(1,5)), y, eps); +%!assert(fpdf (x, 2, 2*ones(1,5)), y, eps); +%!assert(fpdf (x, 2*ones(1,5), 2), y, eps); +%!assert(fpdf (x, [0 NaN Inf 2 2], 2), [NaN NaN NaN y(4:5)], eps); +%!assert(fpdf (x, 2, [0 NaN Inf 2 2]), [NaN NaN NaN y(4:5)], eps); +%!assert(fpdf ([x, NaN], 2, 2), [y, NaN], eps); + +%% Test class of input preserved +%!assert(fpdf (single([x, NaN]), 2, 2), single([y, NaN]), eps("single")); +%!assert(fpdf ([x, NaN], single(2), 2), single([y, NaN]), eps("single")); +%!assert(fpdf ([x, NaN], 2, single(2)), single([y, NaN]), eps("single")); + +%% Test input validation +%!error fpdf () +%!error fpdf (1) +%!error fpdf (1,2) +%!error fpdf (1,2,3,4) +%!error fpdf (ones(3),ones(2),ones(2)) +%!error fpdf (ones(2),ones(3),ones(2)) +%!error fpdf (ones(2),ones(2),ones(3)) +%!error fpdf (i, 2, 2) +%!error fpdf (2, i, 2) +%!error fpdf (2, 2, i) + diff --git a/scripts/statistics/distributions/frnd.m b/scripts/statistics/distributions/frnd.m --- a/scripts/statistics/distributions/frnd.m +++ b/scripts/statistics/distributions/frnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,103 +18,115 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} frnd (@var{m}, @var{n}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} frnd (@var{m}, @var{n}, @var{sz}) -## Return an @var{r} by @var{c} matrix of random samples from the F -## distribution with @var{m} and @var{n} degrees of freedom. Both -## @var{m} and @var{n} must be scalar or of size @var{r} by @var{c}. -## If @var{sz} is a vector the random samples are in a matrix of -## size @var{sz}. +## @deftypefn {Function File} {} frnd (@var{m}, @var{n}) +## @deftypefnx {Function File} {} frnd (@var{m}, @var{n}, @var{r}) +## @deftypefnx {Function File} {} frnd (@var{m}, @var{n}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} frnd (@var{m}, @var{n}, [@var{sz}]) +## Return a matrix of random samples from the F distribution with +## @var{m} and @var{n} degrees of freedom. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the common size of @var{m} and @var{n}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the common size of +## @var{m} and @var{n}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the F distribution -function rnd = frnd (m, n, r, c) +function rnd = frnd (m, n, varargin) - if (nargin > 1) - if (!isscalar(m) || !isscalar(n)) - [retval, m, n] = common_size (m, n); - if (retval > 0) - error ("frnd: M and N must be of common size or scalar"); - endif + if (nargin < 2) + print_usage (); + endif + + if (!isscalar (m) || !isscalar (n)) + [retval, m, n] = common_size (m, n); + if (retval > 0) + error ("frnd: M and N must be of common size or scalars"); endif endif - - if (nargin == 4) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("frnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("frnd: C must be a positive integer"); - endif - sz = [r, c]; - - if (any (size (m) != 1) - && ((length (size (m)) != length (sz)) || any (size (m) != sz))) - error ("frnd: M and N must be scalar or of size [R,C]"); - endif - elseif (nargin == 3) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; - else - error ("frnd: R must be a positive integer or vector"); - endif - - if (any (size (m) != 1) - && ((length (size (m)) != length (sz)) || any (size (m) != sz))) - error ("frnd: M and N must be scalar or of size SZ"); - endif - elseif (nargin == 2) - sz = size(m); - else - print_usage (); + if (iscomplex (m) || iscomplex (n)) + error ("frnd: M and N must not be complex"); endif + if (nargin == 2) + sz = size (m); + elseif (nargin == 3) + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; + else + error ("frnd: dimension vector must be row vector of non-negative integers"); + endif + elseif (nargin > 3) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("frnd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif + + if (!isscalar (m) && !isequal (size (m), sz)) + error ("frnd: M and N must be scalar or of size SZ"); + endif + + if (isa (m, "single") || isa (n, "single")) + cls = "single"; + else + cls = "double"; + endif if (isscalar (m) && isscalar (n)) - if (isinf (m) || isinf (n)) - if (isinf (m)) - rnd = ones (sz); - else - rnd = 2 ./ m .* randg(m / 2, sz); - endif - if (! isinf (n)) - rnd = 0.5 .* n .* rnd ./ randg (n / 2, sz); - endif - elseif ((m > 0) && (m < Inf) && (n > 0) && (n < Inf)) - rnd = n ./ m .* randg (m / 2, sz) ./ randg (n / 2, sz); + if ((m > 0) && (m < Inf) && (n > 0) && (n < Inf)) + rnd = n/m * randg (m/2, sz) ./ randg (n/2, sz); else - rnd = NaN (sz); + rnd = NaN (sz, cls); endif else - rnd = zeros (sz); - - k = find (isinf(m) | isinf(n)); - if (any (k)) - rnd (k) = 1; - k2 = find (!isinf(m) & isinf(n)); - rnd (k2) = 2 ./ m(k2) .* randg (m(k2) ./ 2, size(k2)); - k2 = find (isinf(m) & !isinf(n)); - rnd (k2) = 0.5 .* n(k2) .* rnd(k2) ./ randg (n(k2) ./ 2, size(k2)); - endif + rnd = NaN (sz, cls); - k = find (!(m > 0) | !(n > 0)); - if (any (k)) - rnd(k) = NaN; - endif - - k = find ((m > 0) & (m < Inf) & - (n > 0) & (n < Inf)); - if (any (k)) - rnd(k) = n(k) ./ m(k) .* randg(m(k)./2,size(k)) ./ randg(n(k)./2,size(k)); - endif + k = (m > 0) & (m < Inf) & (n > 0) & (n < Inf); + rnd(k) = n(k) ./ m(k) .* randg (m(k)/2) ./ randg (n(k)/2); endif endfunction + + +%!assert(size (frnd (1,2)), [1, 1]); +%!assert(size (frnd (ones(2,1), 2)), [2, 1]); +%!assert(size (frnd (ones(2,2), 2)), [2, 2]); +%!assert(size (frnd (1, 2*ones(2,1))), [2, 1]); +%!assert(size (frnd (1, 2*ones(2,2))), [2, 2]); +%!assert(size (frnd (1, 2, 3)), [3, 3]); +%!assert(size (frnd (1, 2, [4 1])), [4, 1]); +%!assert(size (frnd (1, 2, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (frnd (1, 2)), "double"); +%!assert(class (frnd (single(1), 2)), "single"); +%!assert(class (frnd (single([1 1]), 2)), "single"); +%!assert(class (frnd (1, single(2))), "single"); +%!assert(class (frnd (1, single([2 2]))), "single"); + +%% Test input validation +%!error frnd () +%!error frnd (1) +%!error frnd (ones(3),ones(2)) +%!error frnd (ones(2),ones(3)) +%!error frnd (i, 2) +%!error frnd (2, i) +%!error frnd (1,2, -1) +%!error frnd (1,2, ones(2)) +%!error frnd (1, 2, [2 -1 2]) +%!error frnd (1,2, 1, ones(2)) +%!error frnd (1,2, 1, -1) +%!error frnd (ones(2,2), 2, 3) +%!error frnd (ones(2,2), 2, [3, 2]) +%!error frnd (ones(2,2), 2, 2, 3) + diff --git a/scripts/statistics/distributions/gamcdf.m b/scripts/statistics/distributions/gamcdf.m --- a/scripts/statistics/distributions/gamcdf.m +++ b/scripts/statistics/distributions/gamcdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -21,7 +22,6 @@ ## For each element of @var{x}, compute the cumulative distribution ## function (CDF) at @var{x} of the Gamma distribution with parameters ## @var{a} and @var{b}. -## @seealso{gamma, gammaln, gammainc, gampdf, gaminv, gamrnd} ## @end deftypefn ## Author: TT @@ -33,28 +33,59 @@ print_usage (); endif - if (!isscalar (a) || !isscalar(b)) + if (!isscalar (a) || !isscalar (b)) [retval, x, a, b] = common_size (x, a, b); if (retval > 0) - error ("gamcdf: X, A and B must be of common size or scalars"); + error ("gamcdf: X, A, and B must be of common size or scalars"); endif endif - sz = size (x); - cdf = zeros (sz); - - k = find (!(a > 0) | !(b > 0) | isnan (x)); - if (any (k)) - cdf (k) = NaN; + if (iscomplex (x) || iscomplex (a) || iscomplex (b)) + error ("gamcdf: X, A, and B must not be complex"); endif - k = find ((x > 0) & (a > 0) & (b > 0)); - if (any (k)) - if (isscalar (a) && isscalar(b)) - cdf (k) = gammainc (x(k) ./ b, a); - else - cdf (k) = gammainc (x(k) ./ b(k), a(k)); - endif + if (isa (x, "single") || isa (a, "single") || isa (b, "single")) + cdf = zeros (size (x), "single"); + else + cdf = zeros (size (x)); + endif + + k = isnan (x) | !(a > 0) | !(a < Inf) | !(b > 0) | !(b < Inf); + cdf(k) = NaN; + + k = (x > 0) & (a > 0) & (a < Inf) & (b > 0) & (b < Inf); + if (isscalar (a) && isscalar (b)) + cdf(k) = gammainc (x(k) / b, a); + else + cdf(k) = gammainc (x(k) ./ b(k), a(k)); endif endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 2 Inf]; +%! y = [0, gammainc(x(2:end), 1)]; +%!assert(gamcdf (x, ones(1,6), ones(1,6)), y); +%!assert(gamcdf (x, 1, ones(1,6)), y); +%!assert(gamcdf (x, ones(1,6), 1), y); +%!assert(gamcdf (x, [0 -Inf NaN Inf 1 1], 1), [NaN NaN NaN NaN y(5:6)]); +%!assert(gamcdf (x, 1, [0 -Inf NaN Inf 1 1]), [NaN NaN NaN NaN y(5:6)]); +%!assert(gamcdf ([x(1:2) NaN x(4:6)], 1, 1), [y(1:2) NaN y(4:6)]); + +%% Test class of input preserved +%!assert(gamcdf ([x, NaN], 1, 1), [y, NaN]); +%!assert(gamcdf (single([x, NaN]), 1, 1), single([y, NaN]), eps("single")); + +%% Test input validation +%!error gamcdf () +%!error gamcdf (1) +%!error gamcdf (1,2) +%!error gamcdf (1,2,3,4) +%!error gamcdf (ones(3),ones(2),ones(2)) +%!error gamcdf (ones(2),ones(3),ones(2)) +%!error gamcdf (ones(2),ones(2),ones(3)) +%!error gamcdf (i, 2, 2) +%!error gamcdf (2, i, 2) +%!error gamcdf (2, 2, i) + diff --git a/scripts/statistics/distributions/gaminv.m b/scripts/statistics/distributions/gaminv.m --- a/scripts/statistics/distributions/gaminv.m +++ b/scripts/statistics/distributions/gaminv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,10 +19,9 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} gaminv (@var{x}, @var{a}, @var{b}) -## For each component of @var{x}, compute the quantile (the inverse of +## For each element of @var{x}, compute the quantile (the inverse of ## the CDF) at @var{x} of the Gamma distribution with parameters @var{a} ## and @var{b}. -## @seealso{gamma, gammaln, gammainc, gampdf, gamcdf, gamrnd} ## @end deftypefn ## Author: KH @@ -33,36 +33,40 @@ print_usage (); endif - if (!isscalar (a) || !isscalar(b)) + if (!isscalar (a) || !isscalar (b)) [retval, x, a, b] = common_size (x, a, b); if (retval > 0) - error ("gaminv: X, A and B must be of common size or scalars"); + error ("gaminv: X, A, and B must be of common size or scalars"); endif endif - sz = size (x); - inv = zeros (sz); + if (iscomplex (x) || iscomplex (a) || iscomplex (b)) + error ("gaminv: X, A, and B must not be complex"); + endif - k = find ((x < 0) | (x > 1) | isnan (x) | !(a > 0) | !(b > 0)); - if (any (k)) - inv (k) = NaN; + if (isa (x, "single") || isa (a, "single") || isa (b, "single")) + inv = zeros (size (x), "single"); + else + inv = zeros (size (x)); endif - k = find ((x == 1) & (a > 0) & (b > 0)); - if (any (k)) - inv (k) = Inf; - endif + k = ((x < 0) | (x > 1) | isnan (x) + | !(a > 0) | !(a < Inf) | !(b > 0) | !(b < Inf)); + inv(k) = NaN; - k = find ((x > 0) & (x < 1) & (a > 0) & (b > 0)); + k = (x == 1) & (a > 0) & (a < Inf) & (b > 0) & (b < Inf); + inv(k) = Inf; + + k = find ((x > 0) & (x < 1) & (a > 0) & (a < Inf) & (b > 0) & (b < Inf)); if (any (k)) - if (!isscalar(a) || !isscalar(b)) - a = a (k); - b = b (k); + if (!isscalar (a) || !isscalar (b)) + a = a(k); + b = b(k); y = a .* b; else y = a * b * ones (size (k)); endif - x = x (k); + x = x(k); if (isa (x, "single")) myeps = eps ("single"); @@ -90,7 +94,36 @@ y_old = y_new; endfor - inv (k) = y_new; + inv(k) = y_new; endif endfunction + + +%!shared x +%! x = [-1 0 0.63212055882855778 1 2]; +%!assert(gaminv (x, ones(1,5), ones(1,5)), [NaN 0 1 Inf NaN], eps); +%!assert(gaminv (x, 1, ones(1,5)), [NaN 0 1 Inf NaN], eps); +%!assert(gaminv (x, ones(1,5), 1), [NaN 0 1 Inf NaN], eps); +%!assert(gaminv (x, [1 -Inf NaN Inf 1], 1), [NaN NaN NaN NaN NaN]); +%!assert(gaminv (x, 1, [1 -Inf NaN Inf 1]), [NaN NaN NaN NaN NaN]); +%!assert(gaminv ([x(1:2) NaN x(4:5)], 1, 1), [NaN 0 NaN Inf NaN]); + +%% Test class of input preserved +%!assert(gaminv ([x, NaN], 1, 1), [NaN 0 1 Inf NaN NaN], eps); +%!assert(gaminv (single([x, NaN]), 1, 1), single([NaN 0 1 Inf NaN NaN]), eps("single")); +%!assert(gaminv ([x, NaN], single(1), 1), single([NaN 0 1 Inf NaN NaN]), eps("single")); +%!assert(gaminv ([x, NaN], 1, single(1)), single([NaN 0 1 Inf NaN NaN]), eps("single")); + +%% Test input validation +%!error gaminv () +%!error gaminv (1) +%!error gaminv (1,2) +%!error gaminv (1,2,3,4) +%!error gaminv (ones(3),ones(2),ones(2)) +%!error gaminv (ones(2),ones(3),ones(2)) +%!error gaminv (ones(2),ones(2),ones(3)) +%!error gaminv (i, 2, 2) +%!error gaminv (2, i, 2) +%!error gaminv (2, 2, i) + diff --git a/scripts/statistics/distributions/gampdf.m b/scripts/statistics/distributions/gampdf.m --- a/scripts/statistics/distributions/gampdf.m +++ b/scripts/statistics/distributions/gampdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -21,7 +22,6 @@ ## For each element of @var{x}, return the probability density function ## (PDF) at @var{x} of the Gamma distribution with parameters @var{a} ## and @var{b}. -## @seealso{gamma, gammaln, gammainc, gamcdf, gaminv, gamrnd} ## @end deftypefn ## Author: TT @@ -33,41 +33,71 @@ print_usage (); endif - if (!isscalar (a) || !isscalar(b)) + if (!isscalar (a) || !isscalar (b)) [retval, x, a, b] = common_size (x, a, b); if (retval > 0) - error ("gampdf: X, A and B must be of common size or scalars"); + error ("gampdf: X, A, and B must be of common size or scalars"); endif endif - sz = size(x); - pdf = zeros (sz); + if (iscomplex (x) || iscomplex (a) || iscomplex (b)) + error ("gampdf: X, A, and B must not be complex"); + endif - k = find (!(a > 0) | !(b > 0) | isnan (x)); - if (any (k)) - pdf (k) = NaN; + if (isa (x, "single") || isa (a, "single") || isa (b, "single")) + pdf = zeros (size (x), "single"); + else + pdf = zeros (size (x)); endif - k = find ((x >= 0) & (a > 0) & (a <= 1) & (b > 0)); - if (any (k)) - if (isscalar(a) && isscalar(b)) - pdf(k) = (x(k) .^ (a - 1)) ... - .* exp(- x(k) ./ b) ./ gamma (a) ./ (b .^ a); - else - pdf(k) = (x(k) .^ (a(k) - 1)) ... - .* exp(- x(k) ./ b(k)) ./ gamma (a(k)) ./ (b(k) .^ a(k)); - endif + k = !(a > 0) | !(b > 0) | isnan (x); + pdf(k) = NaN; + + k = (x >= 0) & (a > 0) & (a <= 1) & (b > 0); + if (isscalar (a) && isscalar (b)) + pdf(k) = (x(k) .^ (a - 1)) ... + .* exp (- x(k) / b) / gamma (a) / (b ^ a); + else + pdf(k) = (x(k) .^ (a(k) - 1)) ... + .* exp (- x(k) ./ b(k)) ./ gamma (a(k)) ./ (b(k) .^ a(k)); endif - k = find ((x >= 0) & (a > 1) & (b > 0)); - if (any (k)) - if (isscalar(a) && isscalar(b)) - pdf(k) = exp (- a .* log (b) + (a-1) .* log (x(k)) - - x(k) ./ b - gammaln (a)); - else - pdf(k) = exp (- a(k) .* log (b(k)) + (a(k)-1) .* log (x(k)) - - x(k) ./ b(k) - gammaln (a(k))); - endif + k = (x >= 0) & (a > 1) & (b > 0); + if (isscalar (a) && isscalar (b)) + pdf(k) = exp (- a * log (b) + (a-1) * log (x(k)) + - x(k) / b - gammaln (a)); + else + pdf(k) = exp (- a(k) .* log (b(k)) + (a(k)-1) .* log (x(k)) + - x(k) ./ b(k) - gammaln (a(k))); endif endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 Inf]; +%! y = [0 exp(-x(2:end))]; +%!assert(gampdf (x, ones(1,5), ones(1,5)), y); +%!assert(gampdf (x, 1, ones(1,5)), y); +%!assert(gampdf (x, ones(1,5), 1), y); +%!assert(gampdf (x, [0 -Inf NaN Inf 1], 1), [NaN NaN NaN NaN y(5)]); +%!assert(gampdf (x, 1, [0 -Inf NaN Inf 1]), [NaN NaN NaN 0 y(5)]); +%!assert(gampdf ([x, NaN], 1, 1), [y, NaN]); + +%% Test class of input preserved +%!assert(gampdf (single([x, NaN]), 1, 1), single([y, NaN])); +%!assert(gampdf ([x, NaN], single(1), 1), single([y, NaN])); +%!assert(gampdf ([x, NaN], 1, single(1)), single([y, NaN])); + +%% Test input validation +%!error gampdf () +%!error gampdf (1) +%!error gampdf (1,2) +%!error gampdf (1,2,3,4) +%!error gampdf (ones(3),ones(2),ones(2)) +%!error gampdf (ones(2),ones(3),ones(2)) +%!error gampdf (ones(2),ones(2),ones(3)) +%!error gampdf (i, 2, 2) +%!error gampdf (2, i, 2) +%!error gampdf (2, 2, i) + diff --git a/scripts/statistics/distributions/gamrnd.m b/scripts/statistics/distributions/gamrnd.m --- a/scripts/statistics/distributions/gamrnd.m +++ b/scripts/statistics/distributions/gamrnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,81 +18,118 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} gamrnd (@var{a}, @var{b}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} gamrnd (@var{a}, @var{b}, @var{sz}) -## Return an @var{r} by @var{c} or a @code{size (@var{sz})} matrix of -## random samples from the Gamma distribution with parameters @var{a} -## and @var{b}. Both @var{a} and @var{b} must be scalar or of size -## @var{r} by @var{c}. +## @deftypefn {Function File} {} gamrnd (@var{a}, @var{b}) +## @deftypefnx {Function File} {} gamrnd (@var{a}, @var{b}, @var{r}) +## @deftypefnx {Function File} {} gamrnd (@var{a}, @var{b}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} gamrnd (@var{a}, @var{b}, [@var{sz}]) +## Return a matrix of random samples from the Gamma distribution with +## parameters @var{a} and @var{b}. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the common size of @var{a} and @var{b}. -## @seealso{gamma, gammaln, gammainc, gampdf, gamcdf, gaminv} +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the common size of +## @var{a} and @var{b}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the Gamma distribution -function rnd = gamrnd (a, b, r, c) +function rnd = gamrnd (a, b, varargin) - if (nargin > 1) - if (!isscalar(a) || !isscalar(b)) - [retval, a, b] = common_size (a, b); - if (retval > 0) - error ("gamrnd: A and B must be of common size or scalar"); - endif + if (nargin < 2) + print_usage (); + endif + + if (!isscalar (a) || !isscalar (b)) + [retval, a, b] = common_size (a, b); + if (retval > 0) + error ("gamrnd: A and B must be of common size or scalars"); endif endif - if (nargin == 4) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("gamrnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("gamrnd: C must be a positive integer"); - endif - sz = [r, c]; + if (iscomplex (a) || iscomplex (b)) + error ("gamrnd: A and B must not be complex"); + endif - if (any (size (a) != 1) - && (length (size (a)) != length (sz) || any (size (a) != sz))) - error ("gamrnd: A and B must be scalar or of size [R, C]"); - endif + if (nargin == 2) + sz = size (a); elseif (nargin == 3) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; else - error ("gamrnd: R must be a positive integer or vector"); + error ("gamrnd: dimension vector must be row vector of non-negative integers"); endif - - if (any (size (a) != 1) - && (length (size (a)) != length (sz) || any (size (a) != sz))) - error ("gamrnd: A and B must be scalar or of size SZ"); + elseif (nargin > 3) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("gamrnd: dimensions must be non-negative integers"); endif - elseif (nargin == 2) - sz = size(a); - else - print_usage (); + sz = [varargin{:}]; endif - rnd = zeros (sz); + if (!isscalar (a) && !isequal (size (a), sz)) + error ("gamrnd: A and B must be scalar or of size SZ"); + endif - if (isscalar (a) && isscalar(b)) - if (find (!(a > 0) | !(a < Inf) | !(b > 0) | !(b < Inf))) - rnd = NaN (sz); - else - rnd = b .* randg(a, sz); + if (isa (a, "single") || isa (b, "single")) + cls = "single"; + else + cls = "double"; + endif + + if (isscalar (a) && isscalar (b)) + if ((a > 0) && (a < Inf) && (b > 0) && (b < Inf)) + rnd = b * randg (a, sz); + if (strcmp (cls, "single")) + rnd = single (rnd); + endif + else + rnd = NaN (sz, cls); endif else - k = find (!(a > 0) | !(a < Inf) | !(b > 0) | !(b < Inf)); - if (any (k)) - rnd(k) = NaN; - endif - k = find ((a > 0) & (a < Inf) & (b > 0) & (b < Inf)); - if (any (k)) - rnd(k) = b(k) .* randg(a(k), size(k)); - endif + rnd = NaN (sz, cls); + + k = (a > 0) & (a < Inf) & (b > 0) & (b < Inf); + rnd(k) = b(k) .* randg (a(k)); endif endfunction + + +%!assert(size (gamrnd (1,2)), [1, 1]); +%!assert(size (gamrnd (ones(2,1), 2)), [2, 1]); +%!assert(size (gamrnd (ones(2,2), 2)), [2, 2]); +%!assert(size (gamrnd (1, 2*ones(2,1))), [2, 1]); +%!assert(size (gamrnd (1, 2*ones(2,2))), [2, 2]); +%!assert(size (gamrnd (1, 2, 3)), [3, 3]); +%!assert(size (gamrnd (1, 2, [4 1])), [4, 1]); +%!assert(size (gamrnd (1, 2, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (gamrnd (1, 2)), "double"); +%!assert(class (gamrnd (single(1), 2)), "single"); +%!assert(class (gamrnd (single([1 1]), 2)), "single"); +%!assert(class (gamrnd (1, single(2))), "single"); +%!assert(class (gamrnd (1, single([2 2]))), "single"); + +%% Test input validation +%!error gamrnd () +%!error gamrnd (1) +%!error gamrnd (ones(3),ones(2)) +%!error gamrnd (ones(2),ones(3)) +%!error gamrnd (i, 2) +%!error gamrnd (2, i) +%!error gamrnd (1,2, -1) +%!error gamrnd (1,2, ones(2)) +%!error gamrnd (1, 2, [2 -1 2]) +%!error gamrnd (1,2, 1, ones(2)) +%!error gamrnd (1,2, 1, -1) +%!error gamrnd (ones(2,2), 2, 3) +%!error gamrnd (ones(2,2), 2, [3, 2]) +%!error gamrnd (ones(2,2), 2, 2, 3) + diff --git a/scripts/statistics/distributions/geocdf.m b/scripts/statistics/distributions/geocdf.m --- a/scripts/statistics/distributions/geocdf.m +++ b/scripts/statistics/distributions/geocdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,8 +19,8 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} geocdf (@var{x}, @var{p}) -## For each element of @var{x}, compute the CDF at @var{x} of the -## geometric distribution with parameter @var{p}. +## For each element of @var{x}, compute the cumulative distribution function +## (CDF) at @var{x} of the geometric distribution with parameter @var{p}. ## @end deftypefn ## Author: KH @@ -31,34 +32,58 @@ print_usage (); endif - if (!isscalar (x) && !isscalar (p)) + if (!isscalar (p)) [retval, x, p] = common_size (x, p); if (retval > 0) - error ("geocdf: X and P must be of common size or scalar"); + error ("geocdf: X and P must be of common size or scalars"); endif endif - cdf = zeros (size (x)); + if (iscomplex (x) || iscomplex (p)) + error ("geocdf: X and P must not be complex"); + endif - k = find (isnan (x) | !(p >= 0) | !(p <= 1)); - if (any (k)) - cdf(k) = NaN; + if (isa (x, "single") || isa (p, "single")) + cdf = zeros (size (x), "single"); + else + cdf = zeros (size (x)); endif - k = find ((x == Inf) & (p >= 0) & (p <= 1)); - if (any (k)) - cdf(k) = 1; - endif + k = isnan (x) | !(p >= 0) | !(p <= 1); + cdf(k) = NaN; + + k = (x == Inf) & (p >= 0) & (p <= 1); + cdf(k) = 1; - k = find ((x >= 0) & (x < Inf) & (x == round (x)) & (p > 0) & (p <= 1)); - if (any (k)) - if (isscalar (x)) - cdf(k) = 1 - ((1 - p(k)) .^ (x + 1)); - elseif (isscalar (p)) - cdf(k) = 1 - ((1 - p) .^ (x(k) + 1)); - else - cdf(k) = 1 - ((1 - p(k)) .^ (x(k) + 1)); - endif + k = (x >= 0) & (x < Inf) & (x == fix (x)) & (p > 0) & (p <= 1); + if (isscalar (p)) + cdf(k) = 1 - ((1 - p) .^ (x(k) + 1)); + else + cdf(k) = 1 - ((1 - p(k)) .^ (x(k) + 1)); endif endfunction + + +%!shared x,y +%! x = [-1 0 1 Inf]; +%! y = [0 0.5 0.75 1]; +%!assert(geocdf (x, 0.5*ones(1,4)), y); +%!assert(geocdf (x, 0.5), y); +%!assert(geocdf (x, 0.5*[-1 NaN 4 1]), [NaN NaN NaN y(4)]); +%!assert(geocdf ([x(1:2) NaN x(4)], 0.5), [y(1:2) NaN y(4)]); + +%% Test class of input preserved +%!assert(geocdf ([x, NaN], 0.5), [y, NaN]); +%!assert(geocdf (single([x, NaN]), 0.5), single([y, NaN])); +%!assert(geocdf ([x, NaN], single(0.5)), single([y, NaN])); + +%% Test input validation +%!error geocdf () +%!error geocdf (1) +%!error geocdf (1,2,3) +%!error geocdf (ones(3),ones(2)) +%!error geocdf (ones(2),ones(3)) +%!error geocdf (i, 2) +%!error geocdf (2, i) + diff --git a/scripts/statistics/distributions/geoinv.m b/scripts/statistics/distributions/geoinv.m --- a/scripts/statistics/distributions/geoinv.m +++ b/scripts/statistics/distributions/geoinv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,8 +19,8 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} geoinv (@var{x}, @var{p}) -## For each element of @var{x}, compute the quantile at @var{x} of the -## geometric distribution with parameter @var{p}. +## For each element of @var{x}, compute the quantile (the inverse of +## the CDF) at @var{x} of the geometric distribution with parameter @var{p}. ## @end deftypefn ## Author: KH @@ -31,34 +32,54 @@ print_usage (); endif - if (!isscalar (x) && !isscalar (p)) + if (!isscalar (p)) [retval, x, p] = common_size (x, p); if (retval > 0) - error ("geoinv: X and P must be of common size or scalar"); + error ("geoinv: X and P must be of common size or scalars"); endif endif - inv = zeros (size (x)); - - k = find (!(x >= 0) | !(x <= 1) | !(p >= 0) | !(p <= 1)); - if (any (k)) - inv(k) = NaN; + if (iscomplex (x) || iscomplex (p)) + error ("geoinv: X and P must not be complex"); endif - k = find ((x == 1) & (p >= 0) & (p <= 1)); - if (any (k)) - inv(k) = Inf; + if (isa (x, "single") || isa (p, "single")) + inv = NaN (size (x), "single"); + else + inv = NaN (size (x)); endif - k = find ((x > 0) & (x < 1) & (p > 0) & (p <= 1)); - if (any (k)) - if (isscalar (x)) - inv(k) = max (ceil (log (1 - x) ./ log (1 - p(k))) - 1, 0); - elseif (isscalar (p)) - inv(k) = max (ceil (log (1 - x(k)) / log (1 - p)) - 1, 0); - else - inv(k) = max (ceil (log (1 - x(k)) ./ log (1 - p(k))) - 1, 0); - endif + k = (x == 1) & (p >= 0) & (p <= 1); + inv(k) = Inf; + + k = (x >= 0) & (x < 1) & (p > 0) & (p <= 1); + if (isscalar (p)) + inv(k) = max (ceil (log (1 - x(k)) / log (1 - p)) - 1, 0); + else + inv(k) = max (ceil (log (1 - x(k)) ./ log (1 - p(k))) - 1, 0); endif endfunction + + +%!shared x +%! x = [-1 0 0.75 1 2]; +%!assert(geoinv (x, 0.5*ones(1,5)), [NaN 0 1 Inf NaN]); +%!assert(geoinv (x, 0.5), [NaN 0 1 Inf NaN]); +%!assert(geoinv (x, 0.5*[1 -1 NaN 4 1]), [NaN NaN NaN NaN NaN]); +%!assert(geoinv ([x(1:2) NaN x(4:5)], 0.5), [NaN 0 NaN Inf NaN]); + +%% Test class of input preserved +%!assert(geoinv ([x, NaN], 0.5), [NaN 0 1 Inf NaN NaN]); +%!assert(geoinv (single([x, NaN]), 0.5), single([NaN 0 1 Inf NaN NaN])); +%!assert(geoinv ([x, NaN], single(0.5)), single([NaN 0 1 Inf NaN NaN])); + +%% Test input validation +%!error geoinv () +%!error geoinv (1) +%!error geoinv (1,2,3) +%!error geoinv (ones(3),ones(2)) +%!error geoinv (ones(2),ones(3)) +%!error geoinv (i, 2) +%!error geoinv (2, i) + diff --git a/scripts/statistics/distributions/geopdf.m b/scripts/statistics/distributions/geopdf.m --- a/scripts/statistics/distributions/geopdf.m +++ b/scripts/statistics/distributions/geopdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -31,35 +32,54 @@ print_usage (); endif - if (!isscalar (x) && !isscalar (p)) + if (!isscalar (p)) [retval, x, p] = common_size (x, p); if (retval > 0) - error ("geopdf: X and P must be of common size or scalar"); + error ("geopdf: X and P must be of common size or scalars"); endif endif - pdf = zeros (size (x)); - - k = find (isnan (x) | !(p >= 0) | !(p <= 1)); - if (any (k)) - pdf(k) = NaN; + if (iscomplex (x) || iscomplex (p)) + error ("geopdf: X and P must not be complex"); endif - ## Just for the fun of it ... - k = find ((x == Inf) & (p == 0)); - if (any (k)) - pdf(k) = 1; + if (isa (x, "single") || isa (p, "single")) + pdf = zeros (size (x), "single"); + else + pdf = zeros (size (x)); endif - k = find ((x >= 0) & (x < Inf) & (x == round (x)) & (p > 0) & (p <= 1)); - if (any (k)) - if (isscalar (x)) - pdf(k) = p(k) .* ((1 - p(k)) .^ x); - elseif (isscalar (p)) - pdf(k) = p .* ((1 - p) .^ x(k)); - else - pdf(k) = p(k) .* ((1 - p(k)) .^ x(k)); - endif + k = isnan (x) | (x == Inf) | !(p >= 0) | !(p <= 1); + pdf(k) = NaN; + + k = (x >= 0) & (x < Inf) & (x == fix (x)) & (p > 0) & (p <= 1); + if (isscalar (p)) + pdf(k) = p * ((1 - p) .^ x(k)); + else + pdf(k) = p(k) .* ((1 - p(k)) .^ x(k)); endif endfunction + + +%!shared x,y +%! x = [-1 0 1 Inf]; +%! y = [0, 1/2, 1/4, NaN]; +%!assert(geopdf (x, 0.5*ones(1,4)), y); +%!assert(geopdf (x, 0.5), y); +%!assert(geopdf (x, 0.5*[-1 NaN 4 1]), [NaN NaN NaN y(4)]); +%!assert(geopdf ([x, NaN], 0.5), [y, NaN]); + +%% Test class of input preserved +%!assert(geopdf (single([x, NaN]), 0.5), single([y, NaN]), 5*eps("single")); +%!assert(geopdf ([x, NaN], single(0.5)), single([y, NaN]), 5*eps("single")); + +%% Test input validation +%!error geopdf () +%!error geopdf (1) +%!error geopdf (1,2,3) +%!error geopdf (ones(3),ones(2)) +%!error geopdf (ones(2),ones(3)) +%!error geopdf (i, 2) +%!error geopdf (2, i) + diff --git a/scripts/statistics/distributions/geornd.m b/scripts/statistics/distributions/geornd.m --- a/scripts/statistics/distributions/geornd.m +++ b/scripts/statistics/distributions/geornd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,77 +18,108 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} geornd (@var{p}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} geornd (@var{p}, @var{sz}) -## Return an @var{r} by @var{c} matrix of random samples from the -## geometric distribution with parameter @var{p}, which must be a scalar -## or of size @var{r} by @var{c}. +## @deftypefn {Function File} {} geornd (@var{p}) +## @deftypefnx {Function File} {} geornd (@var{p}, @var{r}) +## @deftypefnx {Function File} {} geornd (@var{p}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} geornd (@var{p}, [@var{sz}]) +## Return a matrix of random samples from the geometric distribution with +## parameter @var{p}. ## -## If @var{r} and @var{c} are given create a matrix with @var{r} rows and -## @var{c} columns. Or if @var{sz} is a vector, create a matrix of size -## @var{sz}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the size of +## @var{p}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the geometric distribution -function rnd = geornd (p, r, c) - - if (nargin == 3) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("geornd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("geornd: C must be a positive integer"); - endif - sz = [r, c]; +function rnd = geornd (p, varargin) - if (any (size (p) != 1) - && ((length (size (p)) != length (sz)) || any (size (p) != sz))) - error ("geornd: P must be scalar or of size [R, C]"); - endif - elseif (nargin == 2) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; - else - error ("geornd: R must be a positive integer or vector"); - endif - - if (any (size (p) != 1) - && ((length (size (p)) != length (sz)) || any (size (p) != sz))) - error ("geornd: n must be scalar or of size SZ"); - endif - elseif (nargin == 1) - sz = size(p); - elseif (nargin != 1) + if (nargin < 1) print_usage (); endif + if (nargin == 1) + sz = size (p); + elseif (nargin == 2) + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; + else + error ("geornd: dimension vector must be row vector of non-negative integers"); + endif + elseif (nargin > 2) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("geornd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif + + if (!isscalar (p) && !isequal (size (p), sz)) + error ("geornd: P must be scalar or of size SZ"); + endif + + if (iscomplex (p)) + error ("geornd: P must not be complex"); + endif + + if (isa (p, "single")) + cls = "single"; + else + cls = "double"; + endif if (isscalar (p)) - if (p < 0 || p > 1) - rnd = NaN (sz); + if (p > 0 && p < 1); + rnd = floor (- rande (sz) ./ log (1 - p)); elseif (p == 0) - rnd = Inf (sz); - elseif (p > 0 && p < 1); - rnd = floor (- rande(sz) ./ log (1 - p)); - else - rnd = zeros (sz); + rnd = Inf (sz, cls); + elseif (p == 1) + rnd = zeros (sz, cls); + elseif (p < 0 || p > 1) + rnd = NaN (sz, cls); endif else - rnd = floor (- rande(sz) ./ log (1 - p)); + rnd = floor (- rande (sz) ./ log (1 - p)); - k = find (!(p >= 0) | !(p <= 1)); - if (any (k)) - rnd(k) = NaN (1, length (k)); - endif + k = !(p >= 0) | !(p <= 1); + rnd(k) = NaN; - k = find (p == 0); - if (any (k)) - rnd(k) = Inf (1, length (k)); - endif + k = (p == 0); + rnd(k) = Inf; endif endfunction + + +%!assert(size (geornd (0.5)), [1, 1]); +%!assert(size (geornd (0.5*ones(2,1))), [2, 1]); +%!assert(size (geornd (0.5*ones(2,2))), [2, 2]); +%!assert(size (geornd (0.5, 3)), [3, 3]); +%!assert(size (geornd (0.5, [4 1])), [4, 1]); +%!assert(size (geornd (0.5, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (geornd (0.5)), "double"); +%!assert(class (geornd (single(0.5))), "single"); +%!assert(class (geornd (single([0.5 0.5]))), "single"); +%!assert(class (geornd (single(0))), "single"); +%!assert(class (geornd (single(1))), "single"); + +%% Test input validation +%!error geornd () +%!error geornd (ones(3),ones(2)) +%!error geornd (ones(2),ones(3)) +%!error geornd (i) +%!error geornd (1, -1) +%!error geornd (1, ones(2)) +%!error geornd (1, [2 -1 2]) +%!error geornd (ones(2,2), 2, 3) +%!error geornd (ones(2,2), 3, 2) + diff --git a/scripts/statistics/distributions/hygecdf.m b/scripts/statistics/distributions/hygecdf.m --- a/scripts/statistics/distributions/hygecdf.m +++ b/scripts/statistics/distributions/hygecdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1997-2011 Kurt Hornik ## ## This file is part of Octave. @@ -25,7 +26,7 @@ ## replacement from a population of total size @var{t} containing ## @var{m} marked items. ## -## The parameters @var{t}, @var{m}, and @var{n} must positive integers +## The parameters @var{t}, @var{m}, and @var{n} must be positive integers ## with @var{m} and @var{n} not greater than @var{t}. ## @end deftypefn @@ -39,14 +40,70 @@ endif if (!isscalar (t) || !isscalar (m) || !isscalar (n)) - error ("hygecdf: T, M and N must all be positive integers"); + [retval, x, t, m, n] = common_size (x, t, m, n); + if (retval > 0) + error ("hygecdf: X, T, M, and N must be of common size or scalars"); + endif + endif + + if (iscomplex (x) || iscomplex (t) || iscomplex (m) || iscomplex (n)) + error ("hygecdf: X, T, M, and N must not be complex"); endif - if (t < 0 || m < 0 || n <= 0 || t != round (t) || m != round (m) - || n != round (n) || m > t || n > t) + if (isa (x, "single") || isa (t, "single") || isa (m, "single") || isa (n, "single")) + cdf = NaN (size (x), "single"); + else cdf = NaN (size (x)); + endif + + ok = ((t >= 0) & (m >= 0) & (n > 0) & (m <= t) & (n <= t) & + (t == fix (t)) & (m == fix (m)) & (n == fix (n))); + + if (isscalar (t)) + if (ok) + cdf = discrete_cdf (x, 0 : n, hygepdf (0 : n, t, m, n)); + endif else - cdf = discrete_cdf (x, 0 : n, hygepdf (0 : n, t, m, n)); + for i = find (ok(:)') # Must be row vector arg to for loop + v = 0 : n(i); + cdf(i) = discrete_cdf (x(i), v, hygepdf (v, t(i), m(i), n(i))); + endfor endif endfunction + + +%!shared x,y +%! x = [-1 0 1 2 3]; +%! y = [0 1/6 5/6 1 1]; +%!assert(hygecdf (x, 4*ones(1,5), 2, 2), y, eps); +%!assert(hygecdf (x, 4, 2*ones(1,5), 2), y, eps); +%!assert(hygecdf (x, 4, 2, 2*ones(1,5)), y, eps); +%!assert(hygecdf (x, 4*[1 -1 NaN 1.1 1], 2, 2), [y(1) NaN NaN NaN y(5)], eps); +%!assert(hygecdf (x, 4, 2*[1 -1 NaN 1.1 1], 2), [y(1) NaN NaN NaN y(5)], eps); +%!assert(hygecdf (x, 4, 5, 2), [NaN NaN NaN NaN NaN]); +%!assert(hygecdf (x, 4, 2, 2*[1 -1 NaN 1.1 1]), [y(1) NaN NaN NaN y(5)], eps); +%!assert(hygecdf (x, 4, 2, 5), [NaN NaN NaN NaN NaN]); +%!assert(hygecdf ([x(1:2) NaN x(4:5)], 4, 2, 2), [y(1:2) NaN y(4:5)], eps); + +%% Test class of input preserved +%!assert(hygecdf ([x, NaN], 4, 2, 2), [y, NaN], eps); +%!assert(hygecdf (single([x, NaN]), 4, 2, 2), single([y, NaN]), eps("single")); +%!assert(hygecdf ([x, NaN], single(4), 2, 2), single([y, NaN]), eps("single")); +%!assert(hygecdf ([x, NaN], 4, single(2), 2), single([y, NaN]), eps("single")); +%!assert(hygecdf ([x, NaN], 4, 2, single(2)), single([y, NaN]), eps("single")); + +%% Test input validation +%!error hygecdf () +%!error hygecdf (1) +%!error hygecdf (1,2) +%!error hygecdf (1,2,3) +%!error hygecdf (1,2,3,4,5) +%!error hygecdf (ones(2), ones(3), 1, 1) +%!error hygecdf (1, ones(2), ones(3), 1) +%!error hygecdf (1, 1, ones(2), ones(3)) +%!error hygecdf (i, 2, 2, 2) +%!error hygecdf (2, i, 2, 2) +%!error hygecdf (2, 2, i, 2) +%!error hygecdf (2, 2, 2, i) + diff --git a/scripts/statistics/distributions/hygeinv.m b/scripts/statistics/distributions/hygeinv.m --- a/scripts/statistics/distributions/hygeinv.m +++ b/scripts/statistics/distributions/hygeinv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1997-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,11 +19,14 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} hygeinv (@var{x}, @var{t}, @var{m}, @var{n}) -## For each element of @var{x}, compute the quantile at @var{x} of the -## hypergeometric distribution with parameters @var{t}, @var{m}, and -## @var{n}. +## For each element of @var{x}, compute the quantile (the inverse of +## the CDF) at @var{x} of the hypergeometric distribution with parameters +## @var{t}, @var{m}, and @var{n}. This is the probability of obtaining @var{x} +## marked items when randomly drawing a sample of size @var{n} without +## replacement from a population of total size @var{t} containing @var{m} +## marked items. ## -## The parameters @var{t}, @var{m}, and @var{n} must positive integers +## The parameters @var{t}, @var{m}, and @var{n} must be positive integers ## with @var{m} and @var{n} not greater than @var{t}. ## @end deftypefn @@ -36,14 +40,75 @@ endif if (!isscalar (t) || !isscalar (m) || !isscalar (n)) - error ("hygeinv: T, M and N must all be positive integers"); + [retval, x, t, m, n] = common_size (x, t, m, n); + if (retval > 0) + error ("hygeinv: X, T, M, and N must be of common size or scalars"); + endif + endif + + if (iscomplex (x) || iscomplex (t) || iscomplex (m) || iscomplex (n)) + error ("hygeinv: X, T, M, and N must not be complex"); + endif + + if (isa (x, "single") || isa (t, "single") || isa (m, "single") || isa (n, "single")) + inv = NaN (size (x), "single"); + else + inv = NaN (size (x)); endif - if (t < 0 || m < 0 || n <= 0 || t != round (t) || m != round (m) - || n != round (n) || m > t || n > t) - inv = NaN (size (x)); + ok = ((t >= 0) & (m >= 0) & (n > 0) & (m <= t) & (n <= t) & + (t == fix (t)) & (m == fix (m)) & (n == fix (n))); + + if (isscalar (t)) + if (ok) + inv = discrete_inv (x, 0 : n, hygepdf (0 : n, t, m, n)); + inv(x == 0) = 0; # Hack to return correct value for start of distribution + endif else - inv = discrete_inv (x, 0 : n, hygepdf (0 : n, t, m, n)); + for i = find (ok(:)') # Must be row vector arg to for loop + v = 0 : n(i); + if (x(i) == 0) + inv(i) = 0; # Hack to return correct value for start of distribution + else + inv(i) = discrete_inv (x(i), v, hygepdf (v, t(i), m(i), n(i))); + endif + endfor endif endfunction + + +%!shared x +%! x = [-1 0 0.5 1 2]; +%!assert(hygeinv (x, 4*ones(1,5), 2*ones(1,5), 2*ones(1,5)), [NaN 0 1 2 NaN]); +%!assert(hygeinv (x, 4*ones(1,5), 2, 2), [NaN 0 1 2 NaN]); +%!assert(hygeinv (x, 4, 2*ones(1,5), 2), [NaN 0 1 2 NaN]); +%!assert(hygeinv (x, 4, 2, 2*ones(1,5)), [NaN 0 1 2 NaN]); +%!assert(hygeinv (x, 4*[1 -1 NaN 1.1 1], 2, 2), [NaN NaN NaN NaN NaN]); +%!assert(hygeinv (x, 4, 2*[1 -1 NaN 1.1 1], 2), [NaN NaN NaN NaN NaN]); +%!assert(hygeinv (x, 4, 5, 2), [NaN NaN NaN NaN NaN]); +%!assert(hygeinv (x, 4, 2, 2*[1 -1 NaN 1.1 1]), [NaN NaN NaN NaN NaN]); +%!assert(hygeinv (x, 4, 2, 5), [NaN NaN NaN NaN NaN]); +%!assert(hygeinv ([x(1:2) NaN x(4:5)], 4, 2, 2), [NaN 0 NaN 2 NaN]); + +%% Test class of input preserved +%!assert(hygeinv ([x, NaN], 4, 2, 2), [NaN 0 1 2 NaN NaN]); +%!assert(hygeinv (single([x, NaN]), 4, 2, 2), single([NaN 0 1 2 NaN NaN])); +%!assert(hygeinv ([x, NaN], single(4), 2, 2), single([NaN 0 1 2 NaN NaN])); +%!assert(hygeinv ([x, NaN], 4, single(2), 2), single([NaN 0 1 2 NaN NaN])); +%!assert(hygeinv ([x, NaN], 4, 2, single(2)), single([NaN 0 1 2 NaN NaN])); + +%% Test input validation +%!error hygeinv () +%!error hygeinv (1) +%!error hygeinv (1,2) +%!error hygeinv (1,2,3) +%!error hygeinv (1,2,3,4,5) +%!error hygeinv (ones(2), ones(3), 1, 1) +%!error hygeinv (1, ones(2), ones(3), 1) +%!error hygeinv (1, 1, ones(2), ones(3)) +%!error hygeinv (i, 2, 2, 2) +%!error hygeinv (2, i, 2, 2) +%!error hygeinv (2, 2, i, 2) +%!error hygeinv (2, 2, 2, i) + diff --git a/scripts/statistics/distributions/hygepdf.m b/scripts/statistics/distributions/hygepdf.m --- a/scripts/statistics/distributions/hygepdf.m +++ b/scripts/statistics/distributions/hygepdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1996-2011 Kurt Hornik ## ## This file is part of Octave. @@ -24,7 +25,8 @@ ## when randomly drawing a sample of size @var{n} without replacement ## from a population of total size @var{t} containing @var{m} marked items. ## -## The arguments must be of common size or scalar. +## The parameters @var{t}, @var{m}, and @var{n} must be positive integers +## with @var{m} and @var{n} not greater than @var{t}. ## @end deftypefn ## Author: KH @@ -39,34 +41,72 @@ if (!isscalar (t) || !isscalar (m) || !isscalar (n)) [retval, x, t, m, n] = common_size (x, t, m, n); if (retval > 0) - error ("hygepdf: X, T, M, and N must be of common size or scalar"); + error ("hygepdf: X, T, M, and N must be of common size or scalars"); endif endif - pdf = zeros (size (x)); + if (iscomplex (x) || iscomplex (t) || iscomplex (m) || iscomplex (n)) + error ("hygepdf: X, T, M, and N must not be complex"); + endif + + if (isa (x, "single") || isa (t, "single") || isa (m, "single") || isa (n, "single")) + pdf = zeros (size (x), "single"); + else + pdf = zeros (size (x)); + endif - ## everything in i1 gives NaN - i1 = ((t < 0) | (m < 0) | (n <= 0) | (t != round (t)) | - (m != round (m)) | (n != round (n)) | (m > t) | (n > t)); - ## everything in i2 gives 0 unless in i1 - i2 = ((x != round (x)) | (x < 0) | (x > m) | (n < x) | (n-x > t-m)); - k = find (i1); - if (any (k)) + ## everything in nel gives NaN + nel = (isnan (x) | (t < 0) | (m < 0) | (n <= 0) | (m > t) | (n > t) | + (t != fix (t)) | (m != fix (m)) | (n != fix (n))); + ## everything in zel gives 0 unless in nel + zel = ((x != fix (x)) | (x < 0) | (x > m) | (n < x) | (n-x > t-m)); + + pdf(nel) = NaN; + + k = !nel & !zel; + if (any (k(:))) if (isscalar (t) && isscalar (m) && isscalar (n)) - pdf = NaN (size (x)); + pdf(k) = (bincoeff (m, x(k)) .* bincoeff (t-m, n-x(k)) + / bincoeff (t, n)); else - pdf (k) = NaN; - endif - endif - k = find (!i1 & !i2); - if (any (k)) - if (isscalar (t) && isscalar (m) && isscalar (n)) - pdf (k) = (bincoeff (m, x(k)) .* bincoeff (t-m, n-x(k)) - / bincoeff (t, n)); - else - pdf (k) = (bincoeff (m(k), x(k)) .* bincoeff (t(k)-m(k), n(k)-x(k)) - ./ bincoeff (t(k), n(k))); + pdf(k) = (bincoeff (m(k), x(k)) .* bincoeff (t(k)-m(k), n(k)-x(k)) + ./ bincoeff (t(k), n(k))); endif endif endfunction + + +%!shared x,y +%! x = [-1 0 1 2 3]; +%! y = [0 1/6 4/6 1/6 0]; +%!assert(hygepdf (x, 4*ones(1,5), 2, 2), y); +%!assert(hygepdf (x, 4, 2*ones(1,5), 2), y); +%!assert(hygepdf (x, 4, 2, 2*ones(1,5)), y); +%!assert(hygepdf (x, 4*[1 -1 NaN 1.1 1], 2, 2), [0 NaN NaN NaN 0]); +%!assert(hygepdf (x, 4, 2*[1 -1 NaN 1.1 1], 2), [0 NaN NaN NaN 0]); +%!assert(hygepdf (x, 4, 5, 2), [NaN NaN NaN NaN NaN]); +%!assert(hygepdf (x, 4, 2, 2*[1 -1 NaN 1.1 1]), [0 NaN NaN NaN 0]); +%!assert(hygepdf (x, 4, 2, 5), [NaN NaN NaN NaN NaN]); +%!assert(hygepdf ([x, NaN], 4, 2, 2), [y, NaN], eps); + +%% Test class of input preserved +%!assert(hygepdf (single([x, NaN]), 4, 2, 2), single([y, NaN])); +%!assert(hygepdf ([x, NaN], single(4), 2, 2), single([y, NaN])); +%!assert(hygepdf ([x, NaN], 4, single(2), 2), single([y, NaN])); +%!assert(hygepdf ([x, NaN], 4, 2, single(2)), single([y, NaN])); + +%% Test input validation +%!error hygepdf () +%!error hygepdf (1) +%!error hygepdf (1,2) +%!error hygepdf (1,2,3) +%!error hygepdf (1,2,3,4,5) +%!error hygepdf (1, ones(3),ones(2),ones(2)) +%!error hygepdf (1, ones(2),ones(3),ones(2)) +%!error hygepdf (1, ones(2),ones(2),ones(3)) +%!error hygepdf (i, 2, 2, 2) +%!error hygepdf (2, i, 2, 2) +%!error hygepdf (2, 2, i, 2) +%!error hygepdf (2, 2, 2, i) + diff --git a/scripts/statistics/distributions/hygernd.m b/scripts/statistics/distributions/hygernd.m --- a/scripts/statistics/distributions/hygernd.m +++ b/scripts/statistics/distributions/hygernd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1997-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,81 +18,131 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} hygernd (@var{t}, @var{m}, @var{n}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} hygernd (@var{t}, @var{m}, @var{n}, @var{sz}) -## @deftypefnx {Function File} {} hygernd (@var{t}, @var{m}, @var{n}) -## Return an @var{r} by @var{c} matrix of random samples from the -## hypergeometric distribution with parameters @var{t}, @var{m}, -## and @var{n}. +## @deftypefn {Function File} {} hygernd (@var{t}, @var{m}, @var{n}) +## @deftypefnx {Function File} {} hygernd (@var{t}, @var{m}, @var{n}, @var{r}) +## @deftypefnx {Function File} {} hygernd (@var{t}, @var{m}, @var{n}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} hygernd (@var{t}, @var{m}, @var{n}, [@var{sz}]) +## Return a matrix of random samples from the hypergeometric distribution +## with parameters @var{t}, @var{m}, and @var{n}. ## -## The parameters @var{t}, @var{m}, and @var{n} must positive integers +## The parameters @var{t}, @var{m}, and @var{n} must be positive integers ## with @var{m} and @var{n} not greater than @var{t}. ## -## The parameter @var{sz} must be scalar or a vector of matrix -## dimensions. If @var{sz} is scalar, then a @var{sz} by @var{sz} -## matrix of random samples is generated. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the common size of +## @var{t}, @var{m}, and @var{n}. ## @end deftypefn -function rnd = hygernd (t, m, n, r, c) +function rnd = hygernd (t, m, n, varargin) - if (nargin == 5) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("hygernd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("hygernd: C must be a positive integer"); - endif - sz = [r, c]; - elseif (nargin == 4) - if (isvector (r) && all (r > 0) && all (r == round (r))) - if (isscalar (r)) - sz = [r, r]; - else - sz = r(:)'; - endif - else - error ("hygernd: R must be a vector of positive integers"); - endif - elseif (nargin != 3) + if (nargin < 3) print_usage (); endif if (! isscalar (t) || ! isscalar (m) || ! isscalar (n)) [retval, t, m, n] = common_size (t, m, n); if (retval > 0) - error ("hygernd: T, M and N must be of common size or scalar"); + error ("hygernd: T, M, and N must be of common size or scalars"); + endif + endif + + if (iscomplex (t) || iscomplex (m) || iscomplex (n)) + error ("hygernd: T, M, and N must not be complex"); + endif + + if (nargin == 3) + sz = size (t); + elseif (nargin == 4) + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; + else + error ("hygernd: dimension vector must be row vector of non-negative integers"); + endif + elseif (nargin > 4) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("hygernd: dimensions must be non-negative integers"); endif - if (nargin > 3) - if (any (sz != size (t))) - error ("hygernd: T, M and N must have the same size as implied by R and C or must be scalar"); + sz = [varargin{:}]; + endif + + if (!isscalar (t) && !isequal (size (t), sz)) + error ("hygernd: T, M, and N must be scalar or of size SZ"); + endif + + if (isa (t, "single") || isa (m, "single") || isa (n, "single")) + cls = "single"; + else + cls = "double"; + endif + + ok = ((t >= 0) & (m >= 0) & (n > 0) & (m <= t) & (n <= t) & + (t == fix (t)) & (m == fix (m)) & (n == fix (n))); + + if (isscalar (t)) + if (ok) + v = 0:n; + p = hygepdf (v, t, m, n); + rnd = v(lookup (cumsum (p(1:end-1)) / sum (p), rand (sz)) + 1); + rnd = reshape (rnd, sz); + if (strcmp (cls, "single")) + rnd = single (rnd); endif else - sz = size (t); + rnd = NaN (sz, cls); endif - elseif (nargin == 3) - sz = 1; - endif - - ## NaN elements - ne = (! (t >= 0) | ! (m >= 0) | ! (n > 0) | ! (t == round (t)) | ! (m == round (m)) | ! (n == round (n)) | ! (m <= t) | ! (n <= t)); - - if (! isscalar (t)) - rnd = zeros (sz); - rnd(ne) = NaN; + else + rnd = NaN (sz, cls); rn = rand (sz); - for i = find (! ne) + for i = find (ok(:)') # Must be row vector arg to for loop v = 0 : n(i); p = hygepdf (v, t(i), m(i), n(i)); rnd(i) = v(lookup (cumsum (p(1 : end-1)) / sum (p), rn(i)) + 1); endfor - else - if (ne) - rnd = NaN (sz); - else - v = 0:n; - p = hygepdf (v, t, m, n); - rnd = v(lookup (cumsum (p(1:end-1)) / sum (p), rand (sz)) + 1); - endif endif endfunction + + +%!assert(size (hygernd (4,2,2)), [1, 1]); +%!assert(size (hygernd (4*ones(2,1), 2,2)), [2, 1]); +%!assert(size (hygernd (4*ones(2,2), 2,2)), [2, 2]); +%!assert(size (hygernd (4, 2*ones(2,1), 2)), [2, 1]); +%!assert(size (hygernd (4, 2*ones(2,2), 2)), [2, 2]); +%!assert(size (hygernd (4, 2, 2*ones(2,1))), [2, 1]); +%!assert(size (hygernd (4, 2, 2*ones(2,2))), [2, 2]); +%!assert(size (hygernd (4, 2, 2, 3)), [3, 3]); +%!assert(size (hygernd (4, 2, 2, [4 1])), [4, 1]); +%!assert(size (hygernd (4, 2, 2, 4, 1)), [4, 1]); + +%!assert(class (hygernd (4,2,2)), "double"); +%!assert(class (hygernd (single(4),2,2)), "single"); +%!assert(class (hygernd (single([4 4]),2,2)), "single"); +%!assert(class (hygernd (4,single(2),2)), "single"); +%!assert(class (hygernd (4,single([2 2]),2)), "single"); +%!assert(class (hygernd (4,2,single(2))), "single"); +%!assert(class (hygernd (4,2,single([2 2]))), "single"); + +%% Test input validation +%!error hygernd () +%!error hygernd (1) +%!error hygernd (1,2) +%!error hygernd (ones(3),ones(2),ones(2), 2) +%!error hygernd (ones(2),ones(3),ones(2), 2) +%!error hygernd (ones(2),ones(2),ones(3), 2) +%!error hygernd (i, 2, 2) +%!error hygernd (2, i, 2) +%!error hygernd (2, 2, i) +%!error hygernd (4,2,2, -1) +%!error hygernd (4,2,2, ones(2)) +%!error hygernd (4,2,2, [2 -1 2]) +%!error hygernd (4*ones(2),2,2, 3) +%!error hygernd (4*ones(2),2,2, [3, 2]) +%!error hygernd (4*ones(2),2,2, 3, 2) + diff --git a/scripts/statistics/distributions/kolmogorov_smirnov_cdf.m b/scripts/statistics/distributions/kolmogorov_smirnov_cdf.m --- a/scripts/statistics/distributions/kolmogorov_smirnov_cdf.m +++ b/scripts/statistics/distributions/kolmogorov_smirnov_cdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,16 +19,17 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} kolmogorov_smirnov_cdf (@var{x}, @var{tol}) -## Return the CDF at @var{x} of the Kolmogorov-Smirnov distribution, +## Return the cumulative distribution function (CDF) at @var{x} of the +## Kolmogorov-Smirnov distribution, ## @tex -## $$ Q(x) = \sum_{k=-\infty}^\infty (-1)^k \exp(-2 k^2 x^2) $$ +## $$ Q(x) = \sum_{k=-\infty}^\infty (-1)^k \exp (-2 k^2 x^2) $$ ## @end tex ## @ifnottex ## ## @example ## @group ## Inf -## Q(x) = SUM (-1)^k exp(-2 k^2 x^2) +## Q(x) = SUM (-1)^k exp (-2 k^2 x^2) ## k = -Inf ## @end group ## @end example @@ -61,8 +63,7 @@ endif endif - n = numel (x); - if (n == 0) + if (numel (x) == 0) error ("kolmogorov_smirnov_cdf: X must not be empty"); endif @@ -70,10 +71,10 @@ ind = find (x > 0); if (length (ind) > 0) - if (size(ind,2) < size(ind,1)) + if (columns (ind) < rows (ind)) y = x(ind.'); else - y = x(ind); + y = x(ind); endif K = ceil (sqrt (- log (tol) / 2) / min (y)); k = (1:K)'; @@ -84,3 +85,11 @@ endif endfunction + + +%% Test input validation +%!error kolmogorov_smirnov_cdf () +%!error kolmogorov_smirnov_cdf (1,2,3) +%!error kolmogorov_smirnov_cdf (1, ones(2)) +%!error kolmogorov_smirnov_cdf ([], 1) + diff --git a/scripts/statistics/distributions/laplace_cdf.m b/scripts/statistics/distributions/laplace_cdf.m --- a/scripts/statistics/distributions/laplace_cdf.m +++ b/scripts/statistics/distributions/laplace_cdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -31,21 +32,25 @@ print_usage (); endif - cdf = zeros (size (x)); - - k = find (isnan (x)); - if (any (k)) - cdf(k) = NaN; + if (iscomplex (x)) + error ("laplace_cdf: X must not be complex"); endif - k = find (x == Inf); - if (any (k)) - cdf(k) = 1; - endif - - k = find ((x > -Inf) & (x < Inf)); - if (any (k)) - cdf(k) = (1 + sign (x(k)) .* (1 - exp (- abs (x(k))))) / 2; - endif + cdf = (1 + sign (x) .* (1 - exp (- abs (x)))) / 2; endfunction + + +%!shared x,y +%! x = [-Inf -log(2) 0 log(2) Inf]; +%! y = [0, 1/4, 1/2, 3/4, 1]; +%!assert(laplace_cdf ([x, NaN]), [y, NaN]); + +%% Test class of input preserved +%!assert(laplace_cdf (single([x, NaN])), single([y, NaN])); + +%% Test input validation +%!error laplace_cdf () +%!error laplace_cdf (1,2) +%!error laplace_cdf (i) + diff --git a/scripts/statistics/distributions/laplace_inv.m b/scripts/statistics/distributions/laplace_inv.m --- a/scripts/statistics/distributions/laplace_inv.m +++ b/scripts/statistics/distributions/laplace_inv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -31,22 +32,33 @@ print_usage (); endif - inv = -Inf (size (x)); + if (iscomplex (x)) + error ("laplace_inv: X must not be complex"); + endif - k = find (isnan (x) | (x < 0) | (x > 1)); - if (any (k)) - inv(k) = NaN; + if (isa (x, "single")) + inv = NaN (size (x), "single"); + else + inv = NaN (size (x)); endif - k = find (x == 1); - if (any (k)) - inv(k) = Inf; - endif - - k = find ((x > 0) & (x < 1)); - if (any (k)) - inv(k) = ((x(k) < 1/2) .* log (2 * x(k)) - - (x(k) > 1/2) .* log (2 * (1 - x(k)))); - endif + k = (x >= 0) & (x <= 1); + inv(k) = ((x(k) < 1/2) .* log (2 * x(k)) + - (x(k) > 1/2) .* log (2 * (1 - x(k)))); endfunction + + +%!shared x +%! x = [-1 0 0.5 1 2]; +%!assert(laplace_inv (x), [NaN -Inf 0 Inf NaN]); + +%% Test class of input preserved +%!assert(laplace_inv ([x, NaN]), [NaN -Inf 0 Inf NaN NaN]); +%!assert(laplace_inv (single([x, NaN])), single([NaN -Inf 0 Inf NaN NaN])); + +%% Test input validation +%!error laplace_inv () +%!error laplace_inv (1,2) +%!error laplace_inv (i) + diff --git a/scripts/statistics/distributions/laplace_pdf.m b/scripts/statistics/distributions/laplace_pdf.m --- a/scripts/statistics/distributions/laplace_pdf.m +++ b/scripts/statistics/distributions/laplace_pdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -30,17 +31,26 @@ if (nargin != 1) print_usage (); endif - - pdf = zeros (size (x)); - - k = find (isnan (x)); - if (any (k)) - pdf(k) = NaN; + + if (iscomplex (x)) + error ("laplace_pdf: X must not be complex"); endif - k = find ((x > -Inf) & (x < Inf)); - if (any (k)) - pdf(k) = exp (- abs (x(k))) / 2; - endif + pdf = exp (- abs (x)) / 2; endfunction + + +%!shared x,y +%! x = [-Inf -log(2) 0 log(2) Inf]; +%! y = [0, 1/4, 1/2, 1/4, 0]; +%!assert(laplace_pdf ([x, NaN]), [y, NaN]); + +%% Test class of input preserved +%!assert(laplace_pdf (single([x, NaN])), single([y, NaN])); + +%% Test input validation +%!error laplace_pdf () +%!error laplace_pdf (1,2) +%!error laplace_pdf (i) + diff --git a/scripts/statistics/distributions/laplace_rnd.m b/scripts/statistics/distributions/laplace_rnd.m --- a/scripts/statistics/distributions/laplace_rnd.m +++ b/scripts/statistics/distributions/laplace_rnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,40 +18,57 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} laplace_rnd (@var{r}, @var{c}) -## @deftypefnx {Function File} {} laplace_rnd (@var{sz}); -## Return an @var{r} by @var{c} matrix of random numbers from the -## Laplace distribution. Or if @var{sz} is a vector, create a matrix of -## @var{sz}. +## @deftypefn {Function File} {} laplace_rnd (@var{r}) +## @deftypefnx {Function File} {} laplace_rnd (@var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} laplace_rnd ([@var{sz}]) +## Return a matrix of random samples from the Laplace distribution. +## +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the Laplace distribution -function rnd = laplace_rnd (r, c) +function rnd = laplace_rnd (varargin) - if (nargin == 2) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("laplace_rnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("laplace_rnd: C must be a positive integer"); - endif - sz = [r, c]; - elseif (nargin == 1) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; - else - error ("laplace_rnd: R must be a positive integer or vector"); - endif - else + if (nargin < 1) print_usage (); endif + if (nargin == 1) + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}(:)'; + else + error ("laplace_rnd: dimension vector must be row vector of non-negative integers"); + endif + elseif (nargin > 1) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("laplace_rnd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif + tmp = rand (sz); - rnd = ((tmp < 1/2) .* log (2 * tmp) - - (tmp > 1/2) .* log (2 * (1 - tmp))); + rnd = (tmp < 1/2) .* log (2 * tmp) - (tmp > 1/2) .* log (2 * (1 - tmp)); endfunction + + +%!assert(size (laplace_rnd (3)), [3, 3]); +%!assert(size (laplace_rnd ([4 1])), [4, 1]); +%!assert(size (laplace_rnd (4,1)), [4, 1]); + +%% Test input validation +%!error laplace_rnd () +%!error laplace_rnd (-1) +%!error laplace_rnd (ones(2)) +%!error laplace_rnd ([2 -1 2]) +%!error laplace_rnd (1, ones(2)) +%!error laplace_rnd (1, -1) + diff --git a/scripts/statistics/distributions/logistic_cdf.m b/scripts/statistics/distributions/logistic_cdf.m --- a/scripts/statistics/distributions/logistic_cdf.m +++ b/scripts/statistics/distributions/logistic_cdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,8 +19,8 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} logistic_cdf (@var{x}) -## For each component of @var{x}, compute the CDF at @var{x} of the -## logistic distribution. +## For each element of @var{x}, compute the cumulative distribution function +## (CDF) at @var{x} of the logistic distribution. ## @end deftypefn ## Author: KH @@ -31,6 +32,25 @@ print_usage (); endif - cdf = 1 ./ (1 + exp (- x)); + if (iscomplex (x)) + error ("logistic_cdf: X must not be complex"); + endif + + cdf = 1 ./ (1 + exp (-x)); endfunction + + +%!shared x,y +%! x = [-Inf -log(3) 0 log(3) Inf]; +%! y = [0, 1/4, 1/2, 3/4, 1]; +%!assert(logistic_cdf ([x, NaN]), [y, NaN], eps); + +%% Test class of input preserved +%!assert(logistic_cdf (single([x, NaN])), single([y, NaN]), eps ("single")); + +%% Test input validation +%!error logistic_cdf () +%!error logistic_cdf (1,2) +%!error logistic_cdf (i) + diff --git a/scripts/statistics/distributions/logistic_inv.m b/scripts/statistics/distributions/logistic_inv.m --- a/scripts/statistics/distributions/logistic_inv.m +++ b/scripts/statistics/distributions/logistic_inv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,7 +19,7 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} logistic_inv (@var{x}) -## For each component of @var{x}, compute the quantile (the inverse of +## For each element of @var{x}, compute the quantile (the inverse of ## the CDF) at @var{x} of the logistic distribution. ## @end deftypefn @@ -31,30 +32,38 @@ print_usage (); endif - if (isa (x, 'single')) - inv = zeros (size (x), 'single'); - else - inv = zeros (size (x)); + if (iscomplex (x)) + error ("logistic_inv: X must not be complex"); endif - k = find ((x < 0) | (x > 1) | isnan (x)); - if (any (k)) - inv(k) = NaN; + if (isa (x, "single")) + inv = NaN (size (x), "single"); + else + inv = NaN (size (x)); endif - k = find (x == 0); - if (any (k)) - inv(k) = -Inf; - endif + k = (x == 0); + inv(k) = -Inf; - k = find (x == 1); - if (any (k)) - inv(k) = Inf; - endif + k = (x == 1); + inv(k) = Inf; - k = find ((x > 0) & (x < 1)); - if (any (k)) - inv (k) = - log (1 ./ x(k) - 1); - endif + k = (x > 0) & (x < 1); + inv(k) = - log (1 ./ x(k) - 1); endfunction + + +%!shared x +%! x = [-1 0 0.5 1 2]; +%!assert(logistic_inv (x), [NaN -Inf 0 Inf NaN]); + +%% Test class of input preserved +%!assert(logistic_inv ([x, NaN]), [NaN -Inf 0 Inf NaN NaN]); +%!assert(logistic_inv (single([x, NaN])), single([NaN -Inf 0 Inf NaN NaN])); + +%% Test input validation +%!error logistic_inv () +%!error logistic_inv (1,2) +%!error logistic_inv (i) + diff --git a/scripts/statistics/distributions/logistic_pdf.m b/scripts/statistics/distributions/logistic_pdf.m --- a/scripts/statistics/distributions/logistic_pdf.m +++ b/scripts/statistics/distributions/logistic_pdf.m @@ -18,7 +18,7 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} logistic_pdf (@var{x}) -## For each component of @var{x}, compute the PDF at @var{x} of the +## For each element of @var{x}, compute the PDF at @var{x} of the ## logistic distribution. ## @end deftypefn @@ -31,7 +31,26 @@ print_usage (); endif + if (iscomplex (x)) + error ("logistic_pdf: X must not be complex"); + endif + cdf = logistic_cdf (x); pdf = cdf .* (1 - cdf); endfunction + + +%!shared x,y +%! x = [-Inf -log(4) 0 log(4) Inf]; +%! y = [0, 0.16, 1/4, 0.16, 0]; +%!assert(logistic_pdf ([x, NaN]), [y, NaN], eps); + +%% Test class of input preserved +%!assert(logistic_pdf (single([x, NaN])), single([y, NaN]), eps ("single")); + +%% Test input validation +%!error logistic_pdf () +%!error logistic_pdf (1,2) +%!error logistic_pdf (i) + diff --git a/scripts/statistics/distributions/logistic_rnd.m b/scripts/statistics/distributions/logistic_rnd.m --- a/scripts/statistics/distributions/logistic_rnd.m +++ b/scripts/statistics/distributions/logistic_rnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,39 +18,56 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} logistic_rnd (@var{r}, @var{c}) -## @deftypefnx {Function File} {} logistic_rnd (@var{sz}) -## Return an @var{r} by @var{c} matrix of random numbers from the -## logistic distribution. Or if @var{sz} is a vector, create a matrix of -## @var{sz}. +## @deftypefn {Function File} {} logistic_rnd (@var{r}) +## @deftypefnx {Function File} {} logistic_rnd (@var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} logistic_rnd ([@var{sz}]) +## Return a matrix of random samples from the logistic distribution. +## +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the logistic distribution -function rnd = logistic_rnd (r, c) +function rnd = logistic_rnd (varargin) + if (nargin < 1) + print_usage (); + endif - if (nargin == 2) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("logistic_rnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("logistic_rnd: C must be a positive integer"); + if (nargin == 1) + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; + else + error ("logistic_rnd: dimension vector must be row vector of non-negative integers"); endif - sz = [r, c]; - elseif (nargin == 1) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; - else - error ("logistic_rnd: R must be a positive integer or vector"); + elseif (nargin > 1) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("logistic_rnd: dimensions must be non-negative integers"); endif - else - print_usage (); + sz = [varargin{:}]; endif rnd = - log (1 ./ rand (sz) - 1); endfunction + + +%!assert(size (logistic_rnd (3)), [3, 3]); +%!assert(size (logistic_rnd ([4 1])), [4, 1]); +%!assert(size (logistic_rnd (4,1)), [4, 1]); + +%% Test input validation +%!error logistic_rnd () +%!error logistic_rnd (-1) +%!error logistic_rnd (ones(2)) +%!error logistic_rnd ([2 -1 2]) +%!error logistic_rnd (1, ones(2)) +%!error logistic_rnd (1, -1) + diff --git a/scripts/statistics/distributions/logncdf.m b/scripts/statistics/distributions/logncdf.m --- a/scripts/statistics/distributions/logncdf.m +++ b/scripts/statistics/distributions/logncdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,7 +18,8 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} logncdf (@var{x}, @var{mu}, @var{sigma}) +## @deftypefn {Function File} {} logncdf (@var{x}) +## @deftypefnx {Function File} {} logncdf (@var{x}, @var{mu}, @var{sigma}) ## For each element of @var{x}, compute the cumulative distribution ## function (CDF) at @var{x} of the lognormal distribution with ## parameters @var{mu} and @var{sigma}. If a random variable follows this @@ -30,48 +32,69 @@ ## Author: KH ## Description: CDF of the log normal distribution -function cdf = logncdf (x, mu, sigma) +function cdf = logncdf (x, mu = 0, sigma = 1) - if (! ((nargin == 1) || (nargin == 3))) + if (nargin != 1 && nargin != 3) print_usage (); endif - if (nargin == 1) - mu = 0; - sigma = 1; - endif - - ## The following "straightforward" implementation unfortunately does - ## not work (because exp (Inf) -> NaN etc): - ## cdf = normal_cdf (log (x), log (mu), sigma); - ## Hence ... - if (!isscalar (mu) || !isscalar (sigma)) [retval, x, mu, sigma] = common_size (x, mu, sigma); if (retval > 0) - error ("logncdf: X, MU and SIGMA must be of common size or scalars"); + error ("logncdf: X, MU, and SIGMA must be of common size or scalars"); endif endif - cdf = zeros (size (x)); + if (iscomplex (x) || iscomplex (mu) || iscomplex (sigma)) + error ("logncdf: X, MU, and SIGMA must not be complex"); + endif - k = find (isnan (x) | !(sigma > 0) | !(sigma < Inf)); - if (any (k)) - cdf(k) = NaN; + if (isa (x, "single") || isa (mu, "single") || isa (sigma, "single")) + cdf = zeros (size (x), "single"); + else + cdf = zeros (size (x)); endif - k = find ((x == Inf) & (sigma > 0) & (sigma < Inf)); - if (any (k)) - cdf(k) = 1; - endif + k = isnan (x) | !(sigma > 0) | !(sigma < Inf); + cdf(k) = NaN; + + k = (x == Inf) & (sigma > 0) & (sigma < Inf); + cdf(k) = 1; - k = find ((x > 0) & (x < Inf) & (sigma > 0) & (sigma < Inf)); - if (any (k)) - if (isscalar (mu) && isscalar (sigma)) - cdf(k) = stdnormal_cdf ((log (x(k)) - mu) / sigma); - else - cdf(k) = stdnormal_cdf ((log (x(k)) - mu(k)) ./ sigma(k)); - endif + k = (x > 0) & (x < Inf) & (sigma > 0) & (sigma < Inf); + if (isscalar (mu) && isscalar (sigma)) + cdf(k) = stdnormal_cdf ((log (x(k)) - mu) / sigma); + else + cdf(k) = stdnormal_cdf ((log (x(k)) - mu(k)) ./ sigma(k)); endif endfunction + + +%!shared x,y +%! x = [-1 0 1 e Inf]; +%! y = [0, 0, 0.5, 1/2+1/2*erf(1/2), 1]; +%!assert(logncdf (x, zeros(1,5), sqrt(2)*ones(1,5)), y); +%!assert(logncdf (x, 0, sqrt(2)*ones(1,5)), y); +%!assert(logncdf (x, zeros(1,5), sqrt(2)), y); +%!assert(logncdf (x, [0 1 NaN 0 1], sqrt(2)), [0 0 NaN y(4:5)]); +%!assert(logncdf (x, 0, sqrt(2)*[0 NaN Inf 1 1]), [NaN NaN NaN y(4:5)]); +%!assert(logncdf ([x(1:3) NaN x(5)], 0, sqrt(2)), [y(1:3) NaN y(5)]); + +%% Test class of input preserved +%!assert(logncdf ([x, NaN], 0, sqrt(2)), [y, NaN]); +%!assert(logncdf (single([x, NaN]), 0, sqrt(2)), single([y, NaN]), eps("single")); +%!assert(logncdf ([x, NaN], single(0), sqrt(2)), single([y, NaN]), eps("single")); +%!assert(logncdf ([x, NaN], 0, single(sqrt(2))), single([y, NaN]), eps("single")); + +%% Test input validation +%!error logncdf () +%!error logncdf (1,2) +%!error logncdf (1,2,3,4) +%!error logncdf (ones(3),ones(2),ones(2)) +%!error logncdf (ones(2),ones(3),ones(2)) +%!error logncdf (ones(2),ones(2),ones(3)) +%!error logncdf (i, 2, 2) +%!error logncdf (2, i, 2) +%!error logncdf (2, 2, i) + diff --git a/scripts/statistics/distributions/logninv.m b/scripts/statistics/distributions/logninv.m --- a/scripts/statistics/distributions/logninv.m +++ b/scripts/statistics/distributions/logninv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,7 +18,8 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} logninv (@var{x}, @var{mu}, @var{sigma}) +## @deftypefn {Function File} {} logninv (@var{x}) +## @deftypefnx {Function File} {} logninv (@var{x}, @var{mu}, @var{sigma}) ## For each element of @var{x}, compute the quantile (the inverse of the ## CDF) at @var{x} of the lognormal distribution with parameters @var{mu} ## and @var{sigma}. If a random variable follows this distribution, its @@ -30,48 +32,68 @@ ## Author: KH ## Description: Quantile function of the log normal distribution -function inv = logninv (x, mu, sigma) +function inv = logninv (x, mu = 0, sigma = 1) - if (! ((nargin == 1) || (nargin == 3))) + if (nargin != 1 && nargin != 3) print_usage (); endif - if (nargin == 1) - mu = 0; - sigma = 1; - endif - - ## The following "straightforward" implementation unfortunately does - ## not work (because exp (Inf) -> NaN): - ## inv = exp (norminv (x, mu, sigma)); - ## Hence ... - if (!isscalar (mu) || !isscalar (sigma)) [retval, x, mu, sigma] = common_size (x, mu, sigma); if (retval > 0) - error ("logninv: X, MU and SIGMA must be of common size or scalars"); + error ("logninv: X, MU, and SIGMA must be of common size or scalars"); endif endif - inv = zeros (size (x)); + if (iscomplex (x) || iscomplex (mu) || iscomplex (sigma)) + error ("logninv: X, MU, and SIGMA must not be complex"); + endif - k = find (!(x >= 0) | !(x <= 1) | !(sigma > 0) | !(sigma < Inf)); - if (any (k)) - inv(k) = NaN; + if (isa (x, "single") || isa (mu, "single") || isa (sigma, "single")) + inv = NaN (size (x), "single"); + else + inv = NaN (size (x)); endif - k = find ((x == 1) & (sigma > 0) & (sigma < Inf)); - if (any (k)) - inv(k) = Inf; - endif + k = !(x >= 0) | !(x <= 1) | !(sigma > 0) | !(sigma < Inf); + inv(k) = NaN; + + k = (x == 1) & (sigma > 0) & (sigma < Inf); + inv(k) = Inf; - k = find ((x > 0) & (x < 1) & (sigma > 0) & (sigma < Inf)); - if (any (k)) - if (isscalar (mu) && isscalar (sigma)) - inv(k) = exp (mu) .* exp (sigma .* stdnormal_inv (x(k))); - else - inv(k) = exp (mu(k)) .* exp (sigma(k) .* stdnormal_inv (x(k))); - endif + k = (x >= 0) & (x < 1) & (sigma > 0) & (sigma < Inf); + if (isscalar (mu) && isscalar (sigma)) + inv(k) = exp (mu) .* exp (sigma .* stdnormal_inv (x(k))); + else + inv(k) = exp (mu(k)) .* exp (sigma(k) .* stdnormal_inv (x(k))); endif endfunction + + +%!shared x +%! x = [-1 0 0.5 1 2]; +%!assert(logninv (x, ones(1,5), ones(1,5)), [NaN 0 e Inf NaN]); +%!assert(logninv (x, 1, ones(1,5)), [NaN 0 e Inf NaN]); +%!assert(logninv (x, ones(1,5), 1), [NaN 0 e Inf NaN]); +%!assert(logninv (x, [1 1 NaN 0 1], 1), [NaN 0 NaN Inf NaN]); +%!assert(logninv (x, 1, [1 0 NaN Inf 1]), [NaN NaN NaN NaN NaN]); +%!assert(logninv ([x(1:2) NaN x(4:5)], 1, 2), [NaN 0 NaN Inf NaN]); + +%% Test class of input preserved +%!assert(logninv ([x, NaN], 1, 1), [NaN 0 e Inf NaN NaN]); +%!assert(logninv (single([x, NaN]), 1, 1), single([NaN 0 e Inf NaN NaN])); +%!assert(logninv ([x, NaN], single(1), 1), single([NaN 0 e Inf NaN NaN])); +%!assert(logninv ([x, NaN], 1, single(1)), single([NaN 0 e Inf NaN NaN])); + +%% Test input validation +%!error logninv () +%!error logninv (1,2) +%!error logninv (1,2,3,4) +%!error logninv (ones(3),ones(2),ones(2)) +%!error logninv (ones(2),ones(3),ones(2)) +%!error logninv (ones(2),ones(2),ones(3)) +%!error logninv (i, 2, 2) +%!error logninv (2, i, 2) +%!error logninv (2, 2, i) + diff --git a/scripts/statistics/distributions/lognpdf.m b/scripts/statistics/distributions/lognpdf.m --- a/scripts/statistics/distributions/lognpdf.m +++ b/scripts/statistics/distributions/lognpdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,7 +18,8 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} lognpdf (@var{x}, @var{mu}, @var{sigma}) +## @deftypefn {Function File} {} lognpdf (@var{x}) +## @deftypefnx {Function File} {} lognpdf (@var{x}, @var{mu}, @var{sigma}) ## For each element of @var{x}, compute the probability density function ## (PDF) at @var{x} of the lognormal distribution with parameters ## @var{mu} and @var{sigma}. If a random variable follows this distribution, @@ -30,43 +32,65 @@ ## Author: KH ## Description: PDF of the log normal distribution -function pdf = lognpdf (x, mu, sigma) +function pdf = lognpdf (x, mu = 0, sigma = 1) - if (! ((nargin == 1) || (nargin == 3))) + if (nargin != 1 && nargin != 3) print_usage (); endif - if (nargin == 1) - mu = 0; - sigma = 1; - endif - - ## The following "straightforward" implementation unfortunately does - ## not work for the special cases (Inf, ...) - ## pdf = (x > 0) ./ x .* normpdf (log (x), mu, sigma); - ## Hence ... - if (!isscalar (mu) || !isscalar (sigma)) [retval, x, mu, sigma] = common_size (x, mu, sigma); if (retval > 0) - error ("lognpdf: X, MU and SIGMA must be of common size or scalars"); + error ("lognpdf: X, MU, and SIGMA must be of common size or scalars"); endif endif - pdf = zeros (size (x)); - - k = find (isnan (x) | !(sigma > 0) | !(sigma < Inf)); - if (any (k)) - pdf(k) = NaN; + if (iscomplex (x) || iscomplex (mu) || iscomplex (sigma)) + error ("lognpdf: X, MU, and SIGMA must not be complex"); endif - k = find ((x > 0) & (x < Inf) & (sigma > 0) & (sigma < Inf)); - if (any (k)) - if (isscalar (mu) && isscalar (sigma)) - pdf(k) = normpdf (log (x(k)), mu, sigma) ./ x(k); - else - pdf(k) = normpdf (log (x(k)), mu(k), sigma(k)) ./ x(k); - endif + if (isa (x, "single") || isa (mu, "single") || isa (sigma, "single")) + pdf = zeros (size (x), "single"); + else + pdf = zeros (size (x)); + endif + + k = isnan (x) | !(sigma > 0) | !(sigma < Inf); + pdf(k) = NaN; + + k = (x > 0) & (x < Inf) & (sigma > 0) & (sigma < Inf); + if (isscalar (mu) && isscalar (sigma)) + pdf(k) = normpdf (log (x(k)), mu, sigma) ./ x(k); + else + pdf(k) = normpdf (log (x(k)), mu(k), sigma(k)) ./ x(k); endif endfunction + + +%!shared x,y +%! x = [-1 0 e Inf]; +%! y = [0, 0, 1/(e*sqrt(2*pi)) * exp(-1/2), 0]; +%!assert(lognpdf (x, zeros(1,4), ones(1,4)), y, eps); +%!assert(lognpdf (x, 0, ones(1,4)), y, eps); +%!assert(lognpdf (x, zeros(1,4), 1), y, eps); +%!assert(lognpdf (x, [0 1 NaN 0], 1), [0 0 NaN y(4)], eps); +%!assert(lognpdf (x, 0, [0 NaN Inf 1]), [NaN NaN NaN y(4)], eps); +%!assert(lognpdf ([x, NaN], 0, 1), [y, NaN], eps); + +%% Test class of input preserved +%!assert(lognpdf (single([x, NaN]), 0, 1), single([y, NaN]), eps("single")); +%!assert(lognpdf ([x, NaN], single(0), 1), single([y, NaN]), eps("single")); +%!assert(lognpdf ([x, NaN], 0, single(1)), single([y, NaN]), eps("single")); + +%% Test input validation +%!error lognpdf () +%!error lognpdf (1,2) +%!error lognpdf (1,2,3,4) +%!error lognpdf (ones(3),ones(2),ones(2)) +%!error lognpdf (ones(2),ones(3),ones(2)) +%!error lognpdf (ones(2),ones(2),ones(3)) +%!error lognpdf (i, 2, 2) +%!error lognpdf (2, i, 2) +%!error lognpdf (2, 2, i) + diff --git a/scripts/statistics/distributions/lognrnd.m b/scripts/statistics/distributions/lognrnd.m --- a/scripts/statistics/distributions/lognrnd.m +++ b/scripts/statistics/distributions/lognrnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,76 +18,115 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} lognrnd (@var{mu}, @var{sigma}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} lognrnd (@var{mu}, @var{sigma}, @var{sz}) -## Return an @var{r} by @var{c} matrix of random samples from the -## lognormal distribution with parameters @var{mu} and @var{sigma}. Both -## @var{mu} and @var{sigma} must be scalar or of size @var{r} by @var{c}. -## Or if @var{sz} is a vector, create a matrix of size @var{sz}. +## @deftypefn {Function File} {} lognrnd (@var{mu}, @var{sigma}) +## @deftypefnx {Function File} {} lognrnd (@var{mu}, @var{sigma}, @var{r}) +## @deftypefnx {Function File} {} lognrnd (@var{mu}, @var{sigma}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} lognrnd (@var{mu}, @var{sigma}, [@var{sz}]) +## Return a matrix of random samples from the lognormal distribution with +## parameters @var{mu} and @var{sigma}. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the common size of @var{mu} and @var{sigma}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the common size of +## @var{mu} and @var{sigma}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the log normal distribution -function rnd = lognrnd (mu, sigma, r, c) +function rnd = lognrnd (mu, sigma, varargin) - if (nargin > 1) - if (!isscalar(mu) || !isscalar(sigma)) - [retval, mu, sigma] = common_size (mu, sigma); - if (retval > 0) - error ("lognrnd: MU and SIGMA must be of common size or scalar"); - endif + if (nargin < 2) + print_usage (); + endif + + if (!isscalar (mu) || !isscalar (sigma)) + [retval, mu, sigma] = common_size (mu, sigma); + if (retval > 0) + error ("lognrnd: MU and SIGMA must be of common size or scalars"); endif endif - if (nargin == 4) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("lognrnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("lognrnd: C must be a positive integer"); - endif - sz = [r, c]; + if (iscomplex (mu) || iscomplex (sigma)) + error ("lognrnd: MU and SIGMA must not be complex"); + endif - if (any (size (mu) != 1) - && ((length (size (mu)) != length (sz)) || any (size (mu) != sz))) - error ("lognrnd: MU and SIGMA must be scalar or of size [R, C]"); - endif - + if (nargin == 2) + sz = size (mu); elseif (nargin == 3) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; else - error ("lognrnd: R must be a positive integer or vector"); + error ("lognrnd: dimension vector must be row vector of non-negative integers"); endif + elseif (nargin > 3) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("lognrnd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif - if (any (size (mu) != 1) - && ((length (size (mu)) != length (sz)) || any (size (mu) != sz))) - error ("lognrnd: MU and SIGMA must be scalar or of size SZ"); - endif - elseif (nargin == 2) - sz = size(mu); + if (!isscalar (mu) && !isequal (size (mu), sz)) + error ("lognrnd: MU and SIGMA must be scalar or of size SZ"); + endif + + if (isa (mu, "single") || isa (sigma, "single")) + cls = "single"; else - print_usage (); + cls = "double"; endif if (isscalar (mu) && isscalar (sigma)) - if (!(sigma > 0) || !(sigma < Inf)) - rnd = NaN (sz); + if ((sigma > 0) && (sigma < Inf)) + rnd = exp (mu + sigma * randn (sz)); else - rnd = exp(mu + sigma .* randn (sz)); + rnd = NaN (sz, cls); endif else rnd = exp (mu + sigma .* randn (sz)); - k = find ((sigma < 0) | (sigma == Inf)); - if (any (k)) - rnd(k) = NaN; - endif + + k = (sigma < 0) | (sigma == Inf); + rnd(k) = NaN; endif endfunction + + +%!assert(size (lognrnd (1,2)), [1, 1]); +%!assert(size (lognrnd (ones(2,1), 2)), [2, 1]); +%!assert(size (lognrnd (ones(2,2), 2)), [2, 2]); +%!assert(size (lognrnd (1, 2*ones(2,1))), [2, 1]); +%!assert(size (lognrnd (1, 2*ones(2,2))), [2, 2]); +%!assert(size (lognrnd (1, 2, 3)), [3, 3]); +%!assert(size (lognrnd (1, 2, [4 1])), [4, 1]); +%!assert(size (lognrnd (1, 2, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (lognrnd (1, 2)), "double"); +%!assert(class (lognrnd (single(1), 2)), "single"); +%!assert(class (lognrnd (single([1 1]), 2)), "single"); +%!assert(class (lognrnd (1, single(2))), "single"); +%!assert(class (lognrnd (1, single([2 2]))), "single"); + +%% Test input validation +%!error lognrnd () +%!error lognrnd (1) +%!error lognrnd (ones(3),ones(2)) +%!error lognrnd (ones(2),ones(3)) +%!error lognrnd (i, 2) +%!error lognrnd (2, i) +%!error lognrnd (1,2, -1) +%!error lognrnd (1,2, ones(2)) +%!error lognrnd (1, 2, [2 -1 2]) +%!error lognrnd (1,2, 1, ones(2)) +%!error lognrnd (1,2, 1, -1) +%!error lognrnd (ones(2,2), 2, 3) +%!error lognrnd (ones(2,2), 2, [3, 2]) +%!error lognrnd (ones(2,2), 2, 2, 3) + diff --git a/scripts/statistics/distributions/nbincdf.m b/scripts/statistics/distributions/nbincdf.m --- a/scripts/statistics/distributions/nbincdf.m +++ b/scripts/statistics/distributions/nbincdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,9 +19,13 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} nbincdf (@var{x}, @var{n}, @var{p}) -## For each element of @var{x}, compute the CDF at x of the Pascal -## (negative binomial) distribution with parameters @var{n} and @var{p}. +## For each element of @var{x}, compute the cumulative distribution function +## (CDF) at @var{x} of the negative binomial distribution with +## parameters @var{n} and @var{p}. ## +## When @var{n} is integer this is the Pascal distribution. When +## @var{n} is extended to real numbers this is the Polya distribution. +## ## The number of failures in a Bernoulli experiment with success ## probability @var{p} before the @var{n}-th success follows this ## distribution. @@ -35,58 +40,66 @@ print_usage (); endif - if (!isscalar(n) || !isscalar(p)) + if (!isscalar (n) || !isscalar (p)) [retval, x, n, p] = common_size (x, n, p); if (retval > 0) - error ("nbincdf: X, N and P must be of common size or scalar"); + error ("nbincdf: X, N, and P must be of common size or scalars"); endif endif - cdf = zeros (size (x)); - - k = find (isnan (x) | (n < 1) | (n == Inf) | (n != round (n)) - | (p < 0) | (p > 1)); - if (any (k)) - cdf(k) = NaN; + if (iscomplex (x) || iscomplex (n) || iscomplex (p)) + error ("nbincdf: X, N, and P must not be complex"); endif - k = find ((x == Inf) & (n > 0) & (n < Inf) & (n == round (n)) - & (p >= 0) & (p <= 1)); - if (any (k)) - cdf(k) = 1; + if (isa (x, "single") || isa (n, "single") || isa (p, "single")) + cdf = zeros (size (x), "single"); + else + cdf = zeros (size (x)); endif - k = find ((x >= 0) & (x < Inf) & (x == round (x)) & (n > 0) - & (n < Inf) & (n == round (n)) & (p > 0) & (p <= 1)); - if (any (k)) - ## Does anyone know a better way to do the summation? - m = zeros (size (k)); - x = floor (x(k)); - y = cdf(k); - if (isscalar (n) && isscalar (p)) - while (1) - l = find (m <= x); - if (any (l)) - y(l) = y(l) + nbinpdf (m(l), n, p); - m(l) = m(l) + 1; - else - break; - endif - endwhile - else - n = n(k); - p = p(k); - while (1) - l = find (m <= x); - if (any (l)) - y(l) = y(l) + nbinpdf (m(l), n(l), p(l)); - m(l) = m(l) + 1; - else - break; - endif - endwhile - endif - cdf(k) = y; + k = (isnan (x) | isnan (n) | (n < 1) | (n == Inf) + | (p < 0) | (p > 1) | isnan (p)); + cdf(k) = NaN; + + k = (x == Inf) & (n > 0) & (n < Inf) & (p >= 0) & (p <= 1); + cdf(k) = 1; + + k = ((x >= 0) & (x < Inf) & (x == fix (x)) + & (n > 0) & (n < Inf) & (p > 0) & (p <= 1)); + if (isscalar (n) && isscalar (p)) + cdf(k) = 1 - betainc (1-p, x(k)+1, n); + else + cdf(k) = 1 - betainc (1-p(k), x(k)+1, n(k)); endif endfunction + + +%!shared x,y +%! x = [-1 0 1 2 Inf]; +%! y = [0 1/2 3/4 7/8 1]; +%!assert(nbincdf (x, ones(1,5), 0.5*ones(1,5)), y); +%!assert(nbincdf (x, 1, 0.5*ones(1,5)), y); +%!assert(nbincdf (x, ones(1,5), 0.5), y); +%!assert(nbincdf ([x(1:3) 0 x(5)], [0 1 NaN 1.5 Inf], 0.5), [NaN 1/2 NaN nbinpdf(0,1.5,0.5) NaN], eps); +%!assert(nbincdf (x, 1, 0.5*[-1 NaN 4 1 1]), [NaN NaN NaN y(4:5)]); +%!assert(nbincdf ([x(1:2) NaN x(4:5)], 1, 0.5), [y(1:2) NaN y(4:5)]); + +%% Test class of input preserved +%!assert(nbincdf ([x, NaN], 1, 0.5), [y, NaN]); +%!assert(nbincdf (single([x, NaN]), 1, 0.5), single([y, NaN])); +%!assert(nbincdf ([x, NaN], single(1), 0.5), single([y, NaN])); +%!assert(nbincdf ([x, NaN], 1, single(0.5)), single([y, NaN])); + +%% Test input validation +%!error nbincdf () +%!error nbincdf (1) +%!error nbincdf (1,2) +%!error nbincdf (1,2,3,4) +%!error nbincdf (ones(3),ones(2),ones(2)) +%!error nbincdf (ones(2),ones(3),ones(2)) +%!error nbincdf (ones(2),ones(2),ones(3)) +%!error nbincdf (i, 2, 2) +%!error nbincdf (2, i, 2) +%!error nbincdf (2, 2, i) + diff --git a/scripts/statistics/distributions/nbininv.m b/scripts/statistics/distributions/nbininv.m --- a/scripts/statistics/distributions/nbininv.m +++ b/scripts/statistics/distributions/nbininv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,10 +19,13 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} nbininv (@var{x}, @var{n}, @var{p}) -## For each element of @var{x}, compute the quantile at @var{x} of the -## Pascal (negative binomial) distribution with parameters @var{n} and -## @var{p}. +## For each element of @var{x}, compute the quantile (the inverse of +## the CDF) at @var{x} of the negative binomial distribution +## with parameters @var{n} and @var{p}. ## +## When @var{n} is integer this is the Pascal distribution. When +## @var{n} is extended to real numbers this is the Polya distribution. +## ## The number of failures in a Bernoulli experiment with success ## probability @var{p} before the @var{n}-th success follows this ## distribution. @@ -36,58 +40,89 @@ print_usage (); endif - if (!isscalar(n) || !isscalar(p)) + if (!isscalar (n) || !isscalar (p)) [retval, x, n, p] = common_size (x, n, p); if (retval > 0) - error ("nbininv: X, N and P must be of common size or scalar"); + error ("nbininv: X, N, and P must be of common size or scalars"); endif endif - inv = zeros (size (x)); - - k = find (isnan (x) | (x < 0) | (x > 1) | (n < 1) | (n == Inf) - | (n != round (n)) | (p < 0) | (p > 1)); - if (any (k)) - inv(k) = NaN; + if (iscomplex (x) || iscomplex (n) || iscomplex (p)) + error ("nbininv: X, N, and P must not be complex"); endif - k = find ((x == 1) & (n > 0) & (n < Inf) & (n == round (n)) - & (p >= 0) & (p <= 1)); - if (any (k)) - inv(k) = Inf; + if (isa (x, "single") || isa (n, "single") || isa (p, "single")) + inv = zeros (size (x), "single"); + else + inv = zeros (size (x)); endif + k = (isnan (x) | (x < 0) | (x > 1) | isnan (n) | (n < 1) | (n == Inf) + | isnan (p) | (p < 0) | (p > 1)); + inv(k) = NaN; + + k = (x == 1) & (n > 0) & (n < Inf) & (p >= 0) & (p <= 1); + inv(k) = Inf; + k = find ((x >= 0) & (x < 1) & (n > 0) & (n < Inf) - & (n == round (n)) & (p > 0) & (p <= 1)); - if (any (k)) - m = zeros (size (k)); - x = x(k); - if (isscalar (n) && isscalar (p)) - s = p ^ n * ones (size(k)); - while (1) - l = find (s < x); - if (any (l)) - m(l) = m(l) + 1; - s(l) = s(l) + nbinpdf (m(l), n, p); - else - break; - endif - endwhile - else - n = n(k); - p = p(k); - s = p .^ n; - while (1) - l = find (s < x); - if (any (l)) - m(l) = m(l) + 1; - s(l) = s(l) + nbinpdf (m(l), n(l), p(l)); - else - break; - endif - endwhile - endif - inv(k) = m; + & (p > 0) & (p <= 1)); + m = zeros (size (k)); + x = x(k); + if (isscalar (n) && isscalar (p)) + s = p ^ n * ones (size (k)); + while (1) + l = find (s < x); + if (any (l)) + m(l) = m(l) + 1; + s(l) = s(l) + nbinpdf (m(l), n, p); + else + break; + endif + endwhile + else + n = n(k); + p = p(k); + s = p .^ n; + while (1) + l = find (s < x); + if (any (l)) + m(l) = m(l) + 1; + s(l) = s(l) + nbinpdf (m(l), n(l), p(l)); + else + break; + endif + endwhile endif + inv(k) = m; endfunction + + +%!shared x +%! x = [-1 0 3/4 1 2]; +%!assert(nbininv (x, ones(1,5), 0.5*ones(1,5)), [NaN 0 1 Inf NaN]); +%!assert(nbininv (x, 1, 0.5*ones(1,5)), [NaN 0 1 Inf NaN]); +%!assert(nbininv (x, ones(1,5), 0.5), [NaN 0 1 Inf NaN]); +%!assert(nbininv (x, [1 0 NaN Inf 1], 0.5), [NaN NaN NaN NaN NaN]); +%!assert(nbininv (x, [1 0 1.5 Inf 1], 0.5), [NaN NaN 2 NaN NaN]); +%!assert(nbininv (x, 1, 0.5*[1 -Inf NaN Inf 1]), [NaN NaN NaN NaN NaN]); +%!assert(nbininv ([x(1:2) NaN x(4:5)], 1, 0.5), [NaN 0 NaN Inf NaN]); + +%% Test class of input preserved +%!assert(nbininv ([x, NaN], 1, 0.5), [NaN 0 1 Inf NaN NaN]); +%!assert(nbininv (single([x, NaN]), 1, 0.5), single([NaN 0 1 Inf NaN NaN])); +%!assert(nbininv ([x, NaN], single(1), 0.5), single([NaN 0 1 Inf NaN NaN])); +%!assert(nbininv ([x, NaN], 1, single(0.5)), single([NaN 0 1 Inf NaN NaN])); + +%% Test input validation +%!error nbininv () +%!error nbininv (1) +%!error nbininv (1,2) +%!error nbininv (1,2,3,4) +%!error nbininv (ones(3),ones(2),ones(2)) +%!error nbininv (ones(2),ones(3),ones(2)) +%!error nbininv (ones(2),ones(2),ones(3)) +%!error nbininv (i, 2, 2) +%!error nbininv (2, i, 2) +%!error nbininv (2, 2, i) + diff --git a/scripts/statistics/distributions/nbinpdf.m b/scripts/statistics/distributions/nbinpdf.m --- a/scripts/statistics/distributions/nbinpdf.m +++ b/scripts/statistics/distributions/nbinpdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -19,9 +20,12 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} nbinpdf (@var{x}, @var{n}, @var{p}) ## For each element of @var{x}, compute the probability density function -## (PDF) at @var{x} of the Pascal (negative binomial) distribution with +## (PDF) at @var{x} of the negative binomial distribution with ## parameters @var{n} and @var{p}. ## +## When @var{n} is integer this is the Pascal distribution. When +## @var{n} is extended to real numbers this is the Polya distribution. +## ## The number of failures in a Bernoulli experiment with success ## probability @var{p} before the @var{n}-th success follows this ## distribution. @@ -36,36 +40,63 @@ print_usage (); endif - if (!isscalar(n) || !isscalar(p)) + if (!isscalar (n) || !isscalar (p)) [retval, x, n, p] = common_size (x, n, p); if (retval > 0) - error ("nbinpdf: X, N and P must be of common size or scalar"); + error ("nbinpdf: X, N, and P must be of common size or scalars"); endif endif - pdf = zeros (size (x)); + if (iscomplex (x) || iscomplex (n) || iscomplex (p)) + error ("nbinpdf: X, N, and P must not be complex"); + endif - k = find (isnan (x) | (n < 1) | (n == Inf) | (n != round (n)) - | (p < 0) | (p > 1)); - if (any (k)) - pdf(k) = NaN; + if (isa (x, "single") || isa (n, "single") || isa (p, "single")) + pdf = NaN (size (x), "single"); + else + pdf = NaN (size (x)); endif - ## Just for the fun of it ... - k = find ((x == Inf) & (n > 0) & (n < Inf) & (n == round (n)) - & (p == 0)); - if (any (k)) - pdf(k) = 1; - endif + ok = (x < Inf) & (x == fix (x)) & (n > 0) & (n < Inf) & (p >= 0) & (p <= 1); + + k = (x < 0) & ok; + pdf(k) = 0; - k = find ((x >= 0) & (x < Inf) & (x == round (x)) & (n > 0) - & (n < Inf) & (n == round (n)) & (p > 0) & (p <= 1)); - if (any (k)) - if (isscalar (n) && isscalar (p)) - pdf(k) = bincoeff (-n, x(k)) .* (p ^ n) .* ((p - 1) .^ x(k)); - else - pdf(k) = bincoeff (-n(k), x(k)) .* (p(k) .^ n(k)) .* ((p(k) - 1) .^ x(k)); - endif + k = (x >= 0) & ok; + if (isscalar (n) && isscalar (p)) + pdf(k) = bincoeff (-n, x(k)) .* (p ^ n) .* ((p - 1) .^ x(k)); + else + pdf(k) = bincoeff (-n(k), x(k)) .* (p(k) .^ n(k)) .* ((p(k) - 1) .^ x(k)); endif + endfunction + + +%!shared x,y +%! x = [-1 0 1 2 Inf]; +%! y = [0 1/2 1/4 1/8 NaN]; +%!assert(nbinpdf (x, ones(1,5), 0.5*ones(1,5)), y); +%!assert(nbinpdf (x, 1, 0.5*ones(1,5)), y); +%!assert(nbinpdf (x, ones(1,5), 0.5), y); +%!assert(nbinpdf (x, [0 1 NaN 1.5 Inf], 0.5), [NaN 1/2 NaN 1.875*0.5^1.5/4 NaN], eps); +%!assert(nbinpdf (x, 1, 0.5*[-1 NaN 4 1 1]), [NaN NaN NaN y(4:5)]); +%!assert(nbinpdf ([x, NaN], 1, 0.5), [y, NaN]); + +%% Test class of input preserved +%!assert(nbinpdf (single([x, NaN]), 1, 0.5), single([y, NaN])); +%!assert(nbinpdf ([x, NaN], single(1), 0.5), single([y, NaN])); +%!assert(nbinpdf ([x, NaN], 1, single(0.5)), single([y, NaN])); + +%% Test input validation +%!error nbinpdf () +%!error nbinpdf (1) +%!error nbinpdf (1,2) +%!error nbinpdf (1,2,3,4) +%!error nbinpdf (ones(3),ones(2),ones(2)) +%!error nbinpdf (ones(2),ones(3),ones(2)) +%!error nbinpdf (ones(2),ones(2),ones(3)) +%!error nbinpdf (i, 2, 2) +%!error nbinpdf (2, i, 2) +%!error nbinpdf (2, 2, i) + diff --git a/scripts/statistics/distributions/nbinrnd.m b/scripts/statistics/distributions/nbinrnd.m --- a/scripts/statistics/distributions/nbinrnd.m +++ b/scripts/statistics/distributions/nbinrnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,85 +18,123 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} nbinrnd (@var{n}, @var{p}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} nbinrnd (@var{n}, @var{p}, @var{sz}) -## Return an @var{r} by @var{c} matrix of random samples from the Pascal -## (negative binomial) distribution with parameters @var{n} and @var{p}. -## Both @var{n} and @var{p} must be scalar or of size @var{r} by @var{c}. +## @deftypefn {Function File} {} nbinrnd (@var{n}, @var{p}) +## @deftypefnx {Function File} {} nbinrnd (@var{n}, @var{p}, @var{r}) +## @deftypefnx {Function File} {} nbinrnd (@var{n}, @var{p}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} nbinrnd (@var{n}, @var{p}, [@var{sz}]) +## Return a matrix of random samples from the negative binomial +## distribution with parameters @var{n} and @var{p}. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the common size of @var{n} and @var{p}. Or if @var{sz} is a vector, -## create a matrix of size @var{sz}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the common size of +## @var{n} and @var{p}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the Pascal distribution -function rnd = nbinrnd (n, p, r, c) +function rnd = nbinrnd (n, p, varargin) - if (nargin > 1) - if (!isscalar(n) || !isscalar(p)) - [retval, n, p] = common_size (n, p); - if (retval > 0) - error ("nbinrnd: N and P must be of common size or scalar"); - endif + if (nargin < 2) + print_usage (); + endif + + if (!isscalar (n) || !isscalar (p)) + [retval, n, p] = common_size (n, p); + if (retval > 0) + error ("nbinrnd: N and P must be of common size or scalars"); endif endif - if (nargin == 4) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("nbinrnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("nbinrnd: C must be a positive integer"); - endif - sz = [r, c]; + if (iscomplex (n) || iscomplex (p)) + error ("nbinrnd: N and P must not be complex"); + endif - if (any (size (n) != 1) - && ((length (size (n)) != length (sz)) || any (size (n) != sz))) - error ("nbinrnd: N and P must be scalar or of size [R, C]"); - endif - + if (nargin == 2) + sz = size (n); elseif (nargin == 3) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; else - error ("nbinrnd: R must be a positive integer or vector"); + error ("nbinrnd: dimension vector must be row vector of non-negative integers"); endif + elseif (nargin > 3) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("nbinrnd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif - if (any (size (n) != 1) - && ((length (size (n)) != length (sz)) || any (size (n) != sz))) - error ("nbinrnd: N and P must be scalar or of size SZ"); - endif - elseif (nargin == 2) - sz = size(n); + if (!isscalar (n) && !isequal (size (n), sz)) + error ("nbinrnd: N and P must be scalar or of size SZ"); + endif + + if (isa (n, "single") || isa (p, "single")) + cls = "single"; else - print_usage (); + cls = "double"; endif if (isscalar (n) && isscalar (p)) - if ((n < 1) || (n == Inf) || (n != round (n)) || (p <= 0) || (p > 1)); - rnd = NaN (sz); - elseif ((n > 0) && (n < Inf) && (n == round (n)) - && (p > 0) && (p <= 1)) + if ((n > 0) && (n < Inf) && (p > 0) && (p <= 1)) rnd = randp ((1 - p) ./ p .* randg (n, sz)); + if (strcmp (cls, "single")) + rnd = single (rnd); + endif + elseif ((n > 0) && (n < Inf) && (p == 0)) + rnd = zeros (sz, cls); else - rnd = zeros (sz); + rnd = NaN (sz, cls); endif else - rnd = zeros (sz); + rnd = NaN (sz, cls); - k = find ((n < 1) | (n == Inf) | (n != round (n)) | (p <= 0) | (p > 1)); - if (any (k)) - rnd(k) = NaN; - endif + k = (n > 0) & (n < Inf) & (p == 0); + rnd(k) = 0; - k = find ((n > 0) & (n < Inf) & (n == round (n)) & (p > 0) & (p <= 1)); - if (any (k)) - rnd(k) = randp ((1 - p(k)) ./ p(k) .* randg (n(k), size(k))); - endif + k = (n > 0) & (n < Inf) & (p > 0) & (p <= 1); + rnd(k) = randp ((1 - p(k)) ./ p(k) .* randg (n(k))); endif endfunction + + +%!assert(size (nbinrnd (2, 1/2)), [1, 1]); +%!assert(size (nbinrnd (2*ones(2,1), 1/2)), [2, 1]); +%!assert(size (nbinrnd (2*ones(2,2), 1/2)), [2, 2]); +%!assert(size (nbinrnd (2, 1/2*ones(2,1))), [2, 1]); +%!assert(size (nbinrnd (2, 1/2*ones(2,2))), [2, 2]); +%!assert(size (nbinrnd (2, 1/2, 3)), [3, 3]); +%!assert(size (nbinrnd (2, 1/2, [4 1])), [4, 1]); +%!assert(size (nbinrnd (2, 1/2, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (nbinrnd (2, 1/2)), "double"); +%!assert(class (nbinrnd (single(2), 1/2)), "single"); +%!assert(class (nbinrnd (single([2 2]), 1/2)), "single"); +%!assert(class (nbinrnd (2, single(1/2))), "single"); +%!assert(class (nbinrnd (2, single([1/2 1/2]))), "single"); + +%% Test input validation +%!error nbinrnd () +%!error nbinrnd (1) +%!error nbinrnd (ones(3),ones(2)) +%!error nbinrnd (ones(2),ones(3)) +%!error nbinrnd (i, 2) +%!error nbinrnd (2, i) +%!error nbinrnd (1,2, -1) +%!error nbinrnd (1,2, ones(2)) +%!error nbinrnd (1, 2, [2 -1 2]) +%!error nbinrnd (1,2, 1, ones(2)) +%!error nbinrnd (1,2, 1, -1) +%!error nbinrnd (ones(2,2), 2, 3) +%!error nbinrnd (ones(2,2), 2, [3, 2]) +%!error nbinrnd (ones(2,2), 2, 2, 3) + diff --git a/scripts/statistics/distributions/normcdf.m b/scripts/statistics/distributions/normcdf.m --- a/scripts/statistics/distributions/normcdf.m +++ b/scripts/statistics/distributions/normcdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,56 +18,82 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} normcdf (@var{x}, @var{m}, @var{s}) +## @deftypefn {Function File} {} normcdf (@var{x}) +## @deftypefnx {Function File} {} normcdf (@var{x}, @var{mu}, @var{sigma}) ## For each element of @var{x}, compute the cumulative distribution ## function (CDF) at @var{x} of the normal distribution with mean -## @var{m} and standard deviation @var{s}. +## @var{mu} and standard deviation @var{sigma}. ## -## Default values are @var{m} = 0, @var{s} = 1. +## Default values are @var{mu} = 0, @var{sigma} = 1. ## @end deftypefn ## Author: TT ## Description: CDF of the normal distribution -function cdf = normcdf (x, m, s) +function cdf = normcdf (x, mu = 0, sigma = 1) - if (! ((nargin == 1) || (nargin == 3))) + if (nargin != 1 && nargin != 3) print_usage (); endif - if (nargin == 1) - m = 0; - s = 1; - endif - - if (!isscalar (m) || !isscalar (s)) - [retval, x, m, s] = common_size (x, m, s); + if (!isscalar (mu) || !isscalar (sigma)) + [retval, x, mu, sigma] = common_size (x, mu, sigma); if (retval > 0) - error ("normcdf: X, M and S must be of common size or scalar"); + error ("normcdf: X, MU, and SIGMA must be of common size or scalars"); endif endif - sz = size (x); - cdf = zeros (sz); + if (iscomplex (x) || iscomplex (mu) || iscomplex (sigma)) + error ("normcdf: X, MU, and SIGMA must not be complex"); + endif - if (isscalar (m) && isscalar(s)) - if (find (isinf (m) | isnan (m) | !(s > 0) | !(s < Inf))) - cdf = NaN (sz); + if (isa (x, "single") || isa (mu, "single") || isa (sigma, "single")); + cdf = zeros (size (x), "single"); + else + cdf = zeros (size (x)); + endif + + if (isscalar (mu) && isscalar (sigma)) + if (!isinf (mu) && !isnan (mu) && (sigma > 0) && (sigma < Inf)) + cdf = stdnormal_cdf ((x - mu) / sigma); else - cdf = stdnormal_cdf ((x - m) ./ s); + cdf = NaN (size (x), class (cdf)); endif else - k = find (isinf (m) | isnan (m) | !(s > 0) | !(s < Inf)); - if (any (k)) - cdf(k) = NaN; - endif + k = isinf (mu) | isnan (mu) | !(sigma > 0) | !(sigma < Inf); + cdf(k) = NaN; - k = find (!isinf (m) & !isnan (m) & (s > 0) & (s < Inf)); - if (any (k)) - cdf(k) = stdnormal_cdf ((x(k) - m(k)) ./ s(k)); - endif + k = ! k; + cdf(k) = stdnormal_cdf ((x(k) - mu(k)) ./ sigma(k)); endif - cdf((s == 0) & (x == m)) = 0.5; +endfunction + + +%!shared x,y +%! x = [-Inf 1 2 Inf]; +%! y = [0, 0.5, 1/2*(1+erf(1/sqrt(2))), 1]; +%!assert(normcdf (x, ones(1,4), ones(1,4)), y); +%!assert(normcdf (x, 1, ones(1,4)), y); +%!assert(normcdf (x, ones(1,4), 1), y); +%!assert(normcdf (x, [0 -Inf NaN Inf], 1), [y(1) NaN NaN NaN]); +%!assert(normcdf (x, 1, [Inf NaN -1 0]), [NaN NaN NaN NaN]); +%!assert(normcdf ([x(1:2) NaN x(4)], 1, 1), [y(1:2) NaN y(4)]); -endfunction +%% Test class of input preserved +%!assert(normcdf ([x, NaN], 1, 1), [y, NaN]); +%!assert(normcdf (single([x, NaN]), 1, 1), single([y, NaN]), eps("single")); +%!assert(normcdf ([x, NaN], single(1), 1), single([y, NaN]), eps("single")); +%!assert(normcdf ([x, NaN], 1, single(1)), single([y, NaN]), eps("single")); + +%% Test input validation +%!error normcdf () +%!error normcdf (1,2) +%!error normcdf (1,2,3,4) +%!error normcdf (ones(3),ones(2),ones(2)) +%!error normcdf (ones(2),ones(3),ones(2)) +%!error normcdf (ones(2),ones(2),ones(3)) +%!error normcdf (i, 2, 2) +%!error normcdf (2, i, 2) +%!error normcdf (2, 2, i) + diff --git a/scripts/statistics/distributions/norminv.m b/scripts/statistics/distributions/norminv.m --- a/scripts/statistics/distributions/norminv.m +++ b/scripts/statistics/distributions/norminv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,62 +18,76 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} norminv (@var{x}, @var{m}, @var{s}) +## @deftypefn {Function File} {} norminv (@var{x}) +## @deftypefnx {Function File} {} norminv (@var{x}, @var{mu}, @var{sigma}) ## For each element of @var{x}, compute the quantile (the inverse of the -## CDF) at @var{x} of the normal distribution with mean @var{m} and -## standard deviation @var{s}. +## CDF) at @var{x} of the normal distribution with mean @var{mu} and +## standard deviation @var{sigma}. ## -## Default values are @var{m} = 0, @var{s} = 1. +## Default values are @var{mu} = 0, @var{sigma} = 1. ## @end deftypefn ## Author: KH ## Description: Quantile function of the normal distribution -function inv = norminv (x, m, s) +function inv = norminv (x, mu = 0, sigma = 1) if (nargin != 1 && nargin != 3) print_usage (); endif - if (nargin == 1) - m = 0; - s = 1; - endif - - if (!isscalar (m) || !isscalar (s)) - [retval, x, m, s] = common_size (x, m, s); + if (!isscalar (mu) || !isscalar (sigma)) + [retval, x, mu, sigma] = common_size (x, mu, sigma); if (retval > 0) - error ("norminv: X, M and S must be of common size or scalars"); + error ("norminv: X, MU, and SIGMA must be of common size or scalars"); endif endif - sz = size (x); - inv = zeros (sz); + if (iscomplex (x) || iscomplex (mu) || iscomplex (sigma)) + error ("norminv: X, MU, and SIGMA must not be complex"); + endif - if (isscalar (m) && isscalar (s)) - if (find (isinf (m) | isnan (m) | !(s > 0) | !(s < Inf))) - inv = NaN (sz); - else - inv = m + s .* stdnormal_inv (x); + if (isa (x, "single") || isa (mu, "single") || isa (sigma, "single")) + inv = NaN (size (x), "single"); + else + inv = NaN (size (x)); + endif + + if (isscalar (mu) && isscalar (sigma)) + if (!isinf (mu) && !isnan (mu) && (sigma > 0) && (sigma < Inf)) + inv = mu + sigma * stdnormal_inv (x); endif else - k = find (isinf (m) | isnan (m) | !(s > 0) | !(s < Inf)); - if (any (k)) - inv(k) = NaN; - endif - - k = find (!isinf (m) & !isnan (m) & (s > 0) & (s < Inf)); - if (any (k)) - inv(k) = m(k) + s(k) .* stdnormal_inv (x(k)); - endif + k = !isinf (mu) & !isnan (mu) & (sigma > 0) & (sigma < Inf); + inv(k) = mu(k) + sigma(k) .* stdnormal_inv (x(k)); endif - k = find ((s == 0) & (x > 0) & (x < 1)); - if (any (k)) - inv(k) = m(k); - endif +endfunction + + +%!shared x +%! x = [-1 0 0.5 1 2]; +%!assert(norminv (x, ones(1,5), ones(1,5)), [NaN -Inf 1 Inf NaN]); +%!assert(norminv (x, 1, ones(1,5)), [NaN -Inf 1 Inf NaN]); +%!assert(norminv (x, ones(1,5), 1), [NaN -Inf 1 Inf NaN]); +%!assert(norminv (x, [1 -Inf NaN Inf 1], 1), [NaN NaN NaN NaN NaN]); +%!assert(norminv (x, 1, [1 0 NaN Inf 1]), [NaN NaN NaN NaN NaN]); +%!assert(norminv ([x(1:2) NaN x(4:5)], 1, 1), [NaN -Inf NaN Inf NaN]); - inv((s == 0) & (x == 0)) = -Inf; - inv((s == 0) & (x == 1)) = Inf; +%% Test class of input preserved +%!assert(norminv ([x, NaN], 1, 1), [NaN -Inf 1 Inf NaN NaN]); +%!assert(norminv (single([x, NaN]), 1, 1), single([NaN -Inf 1 Inf NaN NaN])); +%!assert(norminv ([x, NaN], single(1), 1), single([NaN -Inf 1 Inf NaN NaN])); +%!assert(norminv ([x, NaN], 1, single(1)), single([NaN -Inf 1 Inf NaN NaN])); -endfunction +%% Test input validation +%!error norminv () +%!error norminv (1,2) +%!error norminv (1,2,3,4) +%!error norminv (ones(3),ones(2),ones(2)) +%!error norminv (ones(2),ones(3),ones(2)) +%!error norminv (ones(2),ones(2),ones(3)) +%!error norminv (i, 2, 2) +%!error norminv (2, i, 2) +%!error norminv (2, 2, i) + diff --git a/scripts/statistics/distributions/normpdf.m b/scripts/statistics/distributions/normpdf.m --- a/scripts/statistics/distributions/normpdf.m +++ b/scripts/statistics/distributions/normpdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,57 +18,81 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} normpdf (@var{x}, @var{m}, @var{s}) +## @deftypefn {Function File} {} normpdf (@var{x}) +## @deftypefnx {Function File} {} normpdf (@var{x}, @var{mu}, @var{sigma}) ## For each element of @var{x}, compute the probability density function -## (PDF) at @var{x} of the normal distribution with mean @var{m} and -## standard deviation @var{s}. +## (PDF) at @var{x} of the normal distribution with mean @var{mu} and +## standard deviation @var{sigma}. ## -## Default values are @var{m} = 0, @var{s} = 1. +## Default values are @var{mu} = 0, @var{sigma} = 1. ## @end deftypefn ## Author: TT ## Description: PDF of the normal distribution -function pdf = normpdf (x, m, s) +function pdf = normpdf (x, mu = 0, sigma = 1) if (nargin != 1 && nargin != 3) print_usage (); endif - if (nargin == 1) - m = 0; - s = 1; - endif - - if (!isscalar (m) || !isscalar (s)) - [retval, x, m, s] = common_size (x, m, s); + if (!isscalar (mu) || !isscalar (sigma)) + [retval, x, mu, sigma] = common_size (x, mu, sigma); if (retval > 0) - error ("normpdf: X, M and S must be of common size or scalars"); + error ("normpdf: X, MU, and SIGMA must be of common size or scalars"); endif endif - sz = size (x); - pdf = zeros (sz); + if (iscomplex (x) || iscomplex (mu) || iscomplex (sigma)) + error ("normpdf: X, MU, and SIGMA must not be complex"); + endif - if (isscalar (m) && isscalar (s)) - if (find (isinf (m) | isnan (m) | !(s > 0) | !(s < Inf))) - pdf = NaN (sz); + if (isa (x, "single") || isa (mu, "single") || isa (sigma, "single")) + pdf = zeros (size (x), "single"); + else + pdf = zeros (size (x)); + endif + + if (isscalar (mu) && isscalar (sigma)) + if (!isinf (mu) && !isnan (mu) && (sigma > 0) && (sigma < Inf)) + pdf = stdnormal_pdf ((x - mu) / sigma) / sigma; else - pdf = stdnormal_pdf ((x - m) ./ s) ./ s; + pdf = NaN (size (x), class (pdf)); endif else - k = find (isinf (m) | isnan (m) | !(s > 0) | !(s < Inf)); - if (any (k)) - pdf(k) = NaN; - endif + k = isinf (mu) | !(sigma > 0) | !(sigma < Inf); + pdf(k) = NaN; - k = find (!isinf (m) & !isnan (m) & (s > 0) & (s < Inf)); - if (any (k)) - pdf(k) = stdnormal_pdf ((x(k) - m(k)) ./ s(k)) ./ s(k); - endif + k = !isinf (mu) & (sigma > 0) & (sigma < Inf); + pdf(k) = stdnormal_pdf ((x(k) - mu(k)) ./ sigma(k)) ./ sigma(k); endif - pdf((s == 0) & (x == m)) = Inf; - pdf((s == 0) & ((x < m) | (x > m))) = 0; +endfunction + + +%!shared x,y +%! x = [-Inf 1 2 Inf]; +%! y = 1/sqrt(2*pi)*exp (-(x-1).^2/2); +%!assert(normpdf (x, ones(1,4), ones(1,4)), y); +%!assert(normpdf (x, 1, ones(1,4)), y); +%!assert(normpdf (x, ones(1,4), 1), y); +%!assert(normpdf (x, [0 -Inf NaN Inf], 1), [y(1) NaN NaN NaN]); +%!assert(normpdf (x, 1, [Inf NaN -1 0]), [NaN NaN NaN NaN]); +%!assert(normpdf ([x, NaN], 1, 1), [y, NaN]); -endfunction +%% Test class of input preserved +%!assert(normpdf (single([x, NaN]), 1, 1), single([y, NaN]), eps("single")); +%!assert(normpdf ([x, NaN], single(1), 1), single([y, NaN]), eps("single")); +%!assert(normpdf ([x, NaN], 1, single(1)), single([y, NaN]), eps("single")); + +%% Test input validation +%!error normpdf () +%!error normpdf (1,2) +%!error normpdf (1,2,3,4) +%!error normpdf (ones(3),ones(2),ones(2)) +%!error normpdf (ones(2),ones(3),ones(2)) +%!error normpdf (ones(2),ones(2),ones(3)) +%!error normpdf (i, 2, 2) +%!error normpdf (2, i, 2) +%!error normpdf (2, 2, i) + diff --git a/scripts/statistics/distributions/normrnd.m b/scripts/statistics/distributions/normrnd.m --- a/scripts/statistics/distributions/normrnd.m +++ b/scripts/statistics/distributions/normrnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,75 +18,114 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} normrnd (@var{m}, @var{s}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} normrnd (@var{m}, @var{s}, @var{sz}) -## Return an @var{r} by @var{c} or @code{size (@var{sz})} matrix of -## random samples from the normal distribution with parameters mean @var{m} -## and standard deviation @var{s}. Both @var{m} and @var{s} must be scalar -## or of size @var{r} by @var{c}. +## @deftypefn {Function File} {} normrnd (@var{mu}, @var{sigma}) +## @deftypefnx {Function File} {} normrnd (@var{mu}, @var{sigma}, @var{r}) +## @deftypefnx {Function File} {} normrnd (@var{mu}, @var{sigma}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} normrnd (@var{mu}, @var{sigma}, [@var{sz}]) +## Return a matrix of random samples from the normal distribution with +## parameters mean @var{mu} and standard deviation @var{sigma}. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the common size of @var{m} and @var{s}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the common size of +## @var{mu} and @var{sigma}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the normal distribution -function rnd = normrnd (m, s, r, c) +function rnd = normrnd (mu, sigma, varargin) - if (nargin > 1) - if (!isscalar (m) || !isscalar (s)) - [retval, m, s] = common_size (m, s); - if (retval > 0) - error ("normrnd: M and S must be of common size or scalar"); - endif + if (nargin < 2) + print_usage (); + endif + + if (!isscalar (mu) || !isscalar (sigma)) + [retval, mu, sigma] = common_size (mu, sigma); + if (retval > 0) + error ("normrnd: mu and sigma must be of common size or scalars"); endif endif - if (nargin == 4) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("normrnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("normrnd: C must be a positive integer"); - endif - sz = [r, c]; + if (iscomplex (mu) || iscomplex (sigma)) + error ("normrnd: MU and SIGMA must not be complex"); + endif - if (any (size (m) != 1) - && (length (size (m)) != length (sz) || any (size (m) != sz))) - error ("normrnd: M and S must be scalar or of size [R, C]"); - endif + if (nargin == 2) + sz = size (mu); elseif (nargin == 3) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; else - error ("normrnd: R must be a positive integer or vector"); + error ("normrnd: dimension vector must be row vector of non-negative integers"); endif - - if (any (size (m) != 1) - && (length (size (m)) != length (sz) || any (size (m) != sz))) - error ("normrnd: M and S must be scalar or of size SZ"); + elseif (nargin > 3) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("normrnd: dimensions must be non-negative integers"); endif - elseif (nargin == 2) - sz = size(m); - else - print_usage (); + sz = [varargin{:}]; endif - if (isscalar (m) && isscalar (s)) - if (find (isnan (m) | isinf (m) | !(s > 0) | !(s < Inf))) - rnd = NaN (sz); + if (!isscalar (mu) && !isequal (size (mu), sz)) + error ("normrnd: mu and sigma must be scalar or of size SZ"); + endif + + if (isa (mu, "single") || isa (sigma, "single")) + cls = "single"; + else + cls = "double"; + endif + + if (isscalar (mu) && isscalar (sigma)) + if (!isnan (mu) && !isinf (mu) && (sigma > 0) && (sigma < Inf)) + rnd = mu + sigma * randn (sz); else - rnd = m + s .* randn (sz); + rnd = NaN (sz, cls); endif else - rnd = m + s .* randn (sz); - k = find (isnan (m) | isinf (m) | !(s > 0) | !(s < Inf)); - if (any (k)) - rnd(k) = NaN; - endif + rnd = mu + sigma .* randn (sz); + k = isnan (mu) | isinf (mu) | !(sigma > 0) | !(sigma < Inf); + rnd(k) = NaN; endif endfunction + + +%!assert(size (normrnd (1,2)), [1, 1]); +%!assert(size (normrnd (ones(2,1), 2)), [2, 1]); +%!assert(size (normrnd (ones(2,2), 2)), [2, 2]); +%!assert(size (normrnd (1, 2*ones(2,1))), [2, 1]); +%!assert(size (normrnd (1, 2*ones(2,2))), [2, 2]); +%!assert(size (normrnd (1, 2, 3)), [3, 3]); +%!assert(size (normrnd (1, 2, [4 1])), [4, 1]); +%!assert(size (normrnd (1, 2, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (normrnd (1, 2)), "double"); +%!assert(class (normrnd (single(1), 2)), "single"); +%!assert(class (normrnd (single([1 1]), 2)), "single"); +%!assert(class (normrnd (1, single(2))), "single"); +%!assert(class (normrnd (1, single([2 2]))), "single"); + +%% Test input validation +%!error normrnd () +%!error normrnd (1) +%!error normrnd (ones(3),ones(2)) +%!error normrnd (ones(2),ones(3)) +%!error normrnd (i, 2) +%!error normrnd (2, i) +%!error normrnd (1,2, -1) +%!error normrnd (1,2, ones(2)) +%!error normrnd (1, 2, [2 -1 2]) +%!error normrnd (1,2, 1, ones(2)) +%!error normrnd (1,2, 1, -1) +%!error normrnd (ones(2,2), 2, 3) +%!error normrnd (ones(2,2), 2, [3, 2]) +%!error normrnd (ones(2,2), 2, 2, 3) + diff --git a/scripts/statistics/distributions/poisscdf.m b/scripts/statistics/distributions/poisscdf.m --- a/scripts/statistics/distributions/poisscdf.m +++ b/scripts/statistics/distributions/poisscdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -35,29 +36,55 @@ if (!isscalar (lambda)) [retval, x, lambda] = common_size (x, lambda); if (retval > 0) - error ("poisscdf: X and LAMBDA must be of common size or scalar"); + error ("poisscdf: X and LAMBDA must be of common size or scalars"); endif endif - cdf = zeros (size (x)); + if (iscomplex (x) || iscomplex (lambda)) + error ("poisscdf: X and LAMBDA must not be complex"); + endif - k = find (isnan (x) | !(lambda > 0)); - if (any (k)) - cdf(k) = NaN; + if (isa (x, "single") || isa (lambda, "single")) + cdf = zeros (size (x), "single"); + else + cdf = zeros (size (x)); endif - k = find ((x == Inf) & (lambda > 0)); - if (any (k)) - cdf(k) = 1; - endif + k = isnan (x) | !(lambda > 0); + cdf(k) = NaN; + + k = (x == Inf) & (lambda > 0); + cdf(k) = 1; - k = find ((x >= 0) & (x < Inf) & (lambda > 0)); - if (any (k)) - if (isscalar (lambda)) - cdf(k) = 1 - gammainc (lambda, floor (x(k)) + 1); - else - cdf(k) = 1 - gammainc (lambda(k), floor (x(k)) + 1); - endif + k = (x >= 0) & (x < Inf) & (lambda > 0); + if (isscalar (lambda)) + cdf(k) = 1 - gammainc (lambda, floor (x(k)) + 1); + else + cdf(k) = 1 - gammainc (lambda(k), floor (x(k)) + 1); endif endfunction + + +%!shared x,y +%! x = [-1 0 1 2 Inf]; +%! y = [0, gammainc(1, (x(2:4) +1), 'upper'), 1]; +%!assert(poisscdf (x, ones(1,5)), y); +%!assert(poisscdf (x, 1), y); +%!assert(poisscdf (x, [1 0 NaN 1 1]), [y(1) NaN NaN y(4:5)]); +%!assert(poisscdf ([x(1:2) NaN Inf x(5)], 1), [y(1:2) NaN 1 y(5)]); + +%% Test class of input preserved +%!assert(poisscdf ([x, NaN], 1), [y, NaN]); +%!assert(poisscdf (single([x, NaN]), 1), single([y, NaN]), eps("single")); +%!assert(poisscdf ([x, NaN], single(1)), single([y, NaN]), eps("single")); + +%% Test input validation +%!error poisscdf () +%!error poisscdf (1) +%!error poisscdf (1,2,3) +%!error poisscdf (ones(3),ones(2)) +%!error poisscdf (ones(2),ones(3)) +%!error poisscdf (i, 2) +%!error poisscdf (2, i) + diff --git a/scripts/statistics/distributions/poissinv.m b/scripts/statistics/distributions/poissinv.m --- a/scripts/statistics/distributions/poissinv.m +++ b/scripts/statistics/distributions/poissinv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,7 +19,7 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} poissinv (@var{x}, @var{lambda}) -## For each component of @var{x}, compute the quantile (the inverse of +## For each element of @var{x}, compute the quantile (the inverse of ## the CDF) at @var{x} of the Poisson distribution with parameter ## @var{lambda}. ## @end deftypefn @@ -35,42 +36,68 @@ if (!isscalar (lambda)) [retval, x, lambda] = common_size (x, lambda); if (retval > 0) - error ("poissinv: X and LAMBDA must be of common size or scalar"); + error ("poissinv: X and LAMBDA must be of common size or scalars"); endif endif - inv = zeros (size (x)); - - k = find ((x < 0) | (x > 1) | isnan (x) | !(lambda > 0)); - if (any (k)) - inv(k) = NaN; + if (iscomplex (x) || iscomplex (lambda)) + error ("poissinv: X and LAMBDA must not be complex"); endif - k = find ((x == 1) & (lambda > 0)); - if (any (k)) - inv(k) = Inf; + if (isa (x, "single") || isa (lambda, "single")) + inv = zeros (size (x), "single"); + else + inv = zeros (size (x)); endif + k = (x < 0) | (x > 1) | isnan (x) | !(lambda > 0); + inv(k) = NaN; + + k = (x == 1) & (lambda > 0); + inv(k) = Inf; + k = find ((x > 0) & (x < 1) & (lambda > 0)); - if (any (k)) - if (isscalar (lambda)) - cdf = exp (-lambda) * ones (size (k)); + if (isscalar (lambda)) + cdf = exp (-lambda) * ones (size (k)); + else + cdf = exp (-lambda(k)); + endif + + while (1) + m = find (cdf < x(k)); + if (any (m)) + inv(k(m)) += 1; + if (isscalar (lambda)) + cdf(m) = cdf(m) + poisspdf (inv(k(m)), lambda); + else + cdf(m) = cdf(m) + poisspdf (inv(k(m)), lambda(k(m))); + endif else - cdf = exp (-lambda(k)); + break; endif - while (1) - m = find (cdf < x(k)); - if (any (m)) - inv(k(m)) = inv(k(m)) + 1; - if (isscalar (lambda)) - cdf(m) = cdf(m) + poisspdf (inv(k(m)), lambda); - else - cdf(m) = cdf(m) + poisspdf (inv(k(m)), lambda(k(m))); - endif - else - break; - endif - endwhile - endif + endwhile endfunction + + +%!shared x +%! x = [-1 0 0.5 1 2]; +%!assert(poissinv (x, ones(1,5)), [NaN 0 1 Inf NaN]); +%!assert(poissinv (x, 1), [NaN 0 1 Inf NaN]); +%!assert(poissinv (x, [1 0 NaN 1 1]), [NaN NaN NaN Inf NaN]); +%!assert(poissinv ([x(1:2) NaN x(4:5)], 1), [NaN 0 NaN Inf NaN]); + +%% Test class of input preserved +%!assert(poissinv ([x, NaN], 1), [NaN 0 1 Inf NaN NaN]); +%!assert(poissinv (single([x, NaN]), 1), single([NaN 0 1 Inf NaN NaN])); +%!assert(poissinv ([x, NaN], single(1)), single([NaN 0 1 Inf NaN NaN])); + +%% Test input validation +%!error poissinv () +%!error poissinv (1) +%!error poissinv (1,2,3) +%!error poissinv (ones(3),ones(2)) +%!error poissinv (ones(2),ones(3)) +%!error poissinv (i, 2) +%!error poissinv (2, i) + diff --git a/scripts/statistics/distributions/poisspdf.m b/scripts/statistics/distributions/poisspdf.m --- a/scripts/statistics/distributions/poisspdf.m +++ b/scripts/statistics/distributions/poisspdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -34,24 +35,51 @@ if (!isscalar (lambda)) [retval, x, lambda] = common_size (x, lambda); if (retval > 0) - error ("poisspdf: X and LAMBDA must be of common size or scalar"); + error ("poisspdf: X and LAMBDA must be of common size or scalars"); endif endif - pdf = zeros (size (x)); - - k = find (!(lambda > 0) | isnan (x)); - if (any (k)) - pdf(k) = NaN; + if (iscomplex (x) || iscomplex (lambda)) + error ("poisspdf: X and LAMBDA must not be complex"); endif - k = find ((x >= 0) & (x < Inf) & (x == round (x)) & (lambda > 0)); - if (any (k)) - if (isscalar (lambda)) - pdf(k) = exp (x(k) .* log (lambda) - lambda - gammaln (x(k) + 1)); - else - pdf(k) = exp (x(k) .* log (lambda(k)) - lambda(k) - gammaln (x(k) + 1)); - endif + if (isa (x, "single") || isa (lambda, "single")) + pdf = zeros (size (x), "single"); + else + pdf = zeros (size (x)); + endif + + k = isnan (x) | !(lambda > 0); + pdf(k) = NaN; + + k = (x >= 0) & (x < Inf) & (x == fix (x)) & (lambda > 0); + if (isscalar (lambda)) + pdf(k) = exp (x(k) * log (lambda) - lambda - gammaln (x(k) + 1)); + else + pdf(k) = exp (x(k) .* log (lambda(k)) - lambda(k) - gammaln (x(k) + 1)); endif endfunction + + +%!shared x,y +%! x = [-1 0 1 2 Inf]; +%! y = [0, exp(-1)*[1 1 0.5], 0]; +%!assert(poisspdf (x, ones(1,5)), y, eps); +%!assert(poisspdf (x, 1), y, eps); +%!assert(poisspdf (x, [1 0 NaN 1 1]), [y(1) NaN NaN y(4:5)], eps); +%!assert(poisspdf ([x, NaN], 1), [y, NaN], eps); + +%% Test class of input preserved +%!assert(poisspdf (single([x, NaN]), 1), single([y, NaN]), eps("single")); +%!assert(poisspdf ([x, NaN], single(1)), single([y, NaN]), eps("single")); + +%% Test input validation +%!error poisspdf () +%!error poisspdf (1) +%!error poisspdf (1,2,3) +%!error poisspdf (ones(3),ones(2)) +%!error poisspdf (ones(2),ones(3)) +%!error poisspdf (i, 2) +%!error poisspdf (2, i) + diff --git a/scripts/statistics/distributions/poissrnd.m b/scripts/statistics/distributions/poissrnd.m --- a/scripts/statistics/distributions/poissrnd.m +++ b/scripts/statistics/distributions/poissrnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,73 +18,103 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} poissrnd (@var{lambda}, @var{r}, @var{c}) -## Return an @var{r} by @var{c} matrix of random samples from the -## Poisson distribution with parameter @var{lambda}, which must be a -## scalar or of size @var{r} by @var{c}. +## @deftypefn {Function File} {} poissrnd (@var{lambda}) +## @deftypefnx {Function File} {} poissrnd (@var{lambda}, @var{r}) +## @deftypefnx {Function File} {} poissrnd (@var{lambda}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} poissrnd (@var{lambda}, [@var{sz}]) +## Return a matrix of random samples from the Poisson distribution with +## parameter @var{lambda}. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the size of @var{lambda}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the size of +## @var{lambda}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the Poisson distribution -function rnd = poissrnd (lambda, r, c) - - if (nargin == 3) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("poissrnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("poissrnd: C must be a positive integer"); - endif - sz = [r, c]; +function rnd = poissrnd (lambda, varargin) - if (any (size (lambda) != 1) - && ((length (size (lambda)) != length (sz)) || any (size (lambda) != sz))) - error ("poissrnd: LAMBDA must be scalar or of size [R, C]"); - endif - elseif (nargin == 2) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; - else - error ("poissrnd: R must be a positive integer or vector"); - endif - - if (any (size (lambda) != 1) - && ((length (size (lambda)) != length (sz)) || any (size (lambda) != sz))) - error ("poissrnd: LAMBDA must be scalar or of size sz"); - endif - elseif (nargin == 1) - sz = size (lambda); - else + if (nargin < 1) print_usage (); endif - if (isscalar (lambda)) + if (nargin == 1) + sz = size (lambda); + elseif (nargin == 2) + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; + else + error ("poissrnd: dimension vector must be row vector of non-negative integers"); + endif + elseif (nargin > 2) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("poissrnd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif - if (!(lambda >= 0) || !(lambda < Inf)) - rnd = NaN (sz); - elseif (lambda > 0 && lambda < Inf) - rnd = randp(lambda, sz); + if (!isscalar (lambda) && !isequal (size (lambda), sz)) + error ("poissrnd: LAMBDA must be scalar or of size SZ"); + endif + + if (iscomplex (lambda)) + error ("poissrnd: LAMBDA must not be complex"); + endif + + if (isa (lambda, "single")) + cls = "single"; + else + cls = "double"; + endif + + if (isscalar (lambda)) + if (lambda > 0 && lambda < Inf) + rnd = randp (lambda, sz); + if (strcmp (cls, "single")) + rnd = single (rnd); + endif else - rnd = zeros (sz); + rnd = NaN (sz, cls); endif else - rnd = zeros (sz); + rnd = NaN (sz, cls); - k = find (!(lambda >= 0) | !(lambda < Inf)); - if (any (k)) - rnd(k) = NaN; - endif - - k = find ((lambda > 0) & (lambda < Inf)); - if (any (k)) - rnd(k) = randp(lambda(k), size(k)); - endif + k = (lambda > 0) & (lambda < Inf); + rnd(k) = randp (lambda(k)); endif endfunction + + +%!assert(size (poissrnd (2)), [1, 1]); +%!assert(size (poissrnd (ones(2,1))), [2, 1]); +%!assert(size (poissrnd (ones(2,2))), [2, 2]); +%!assert(size (poissrnd (1, 3)), [3, 3]); +%!assert(size (poissrnd (1, [4 1])), [4, 1]); +%!assert(size (poissrnd (1, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (poissrnd (2)), "double"); +%!assert(class (poissrnd (single(2))), "single"); +%!assert(class (poissrnd (single([2 2]))), "single"); + +%% Test input validation +%!error poissrnd () +%!error poissrnd (1, -1) +%!error poissrnd (1, ones(2)) +%!error poissrnd (1, 2, ones(2)) +%!error poissrnd (i) +%!error poissrnd (1, 2, -1) +%!error poissrnd (1, [2 -1 2]) +%!error poissrnd (ones(2,2), 3) +%!error poissrnd (ones(2,2), [3, 2]) +%!error poissrnd (ones(2,2), 2, 3) + diff --git a/scripts/statistics/distributions/stdnormal_cdf.m b/scripts/statistics/distributions/stdnormal_cdf.m --- a/scripts/statistics/distributions/stdnormal_cdf.m +++ b/scripts/statistics/distributions/stdnormal_cdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,8 +19,9 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} stdnormal_cdf (@var{x}) -## For each component of @var{x}, compute the CDF of the standard normal -## distribution at @var{x}. +## For each element of @var{x}, compute the cumulative distribution +## function (CDF) at @var{x} of the standard normal distribution +## (mean = 0, standard deviation = 1). ## @end deftypefn ## Author: KH @@ -31,9 +33,8 @@ print_usage (); endif - sz = size (x); - if (numel(x) == 0) - error ("stdnormal_cdf: X must not be empty"); + if (iscomplex (x)) + error ("stdnormal_cdf: X must not be complex"); endif cdf = erfc (x / (-sqrt(2))) / 2; @@ -41,5 +42,16 @@ endfunction +%!shared x,y +%! x = [-Inf 0 1 Inf]; +%! y = [0, 0.5, 1/2*(1+erf(1/sqrt(2))), 1]; +%!assert(stdnormal_cdf ([x, NaN]), [y, NaN]); +%% Test class of input preserved +%!assert(stdnormal_cdf (single([x, NaN])), single([y, NaN]), eps("single")); +%% Test input validation +%!error stdnormal_cdf () +%!error stdnormal_cdf (1,2) +%!error stdnormal_cdf (i) + diff --git a/scripts/statistics/distributions/stdnormal_inv.m b/scripts/statistics/distributions/stdnormal_inv.m --- a/scripts/statistics/distributions/stdnormal_inv.m +++ b/scripts/statistics/distributions/stdnormal_inv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,8 +19,9 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} stdnormal_inv (@var{x}) -## For each component of @var{x}, compute the quantile (the -## inverse of the CDF) at @var{x} of the standard normal distribution. +## For each element of @var{x}, compute the quantile (the +## inverse of the CDF) at @var{x} of the standard normal distribution +## (mean = 0, standard deviation = 1). ## @end deftypefn ## Author: KH @@ -31,6 +33,25 @@ print_usage (); endif + if (iscomplex (x)) + error ("stdnormal_inv: X must not be complex"); + endif + inv = sqrt (2) * erfinv (2 * x - 1); endfunction + + +%!shared x +%! x = [-1 0 0.5 1 2]; +%!assert(stdnormal_inv (x), [NaN -Inf 0 Inf NaN]); + +%% Test class of input preserved +%!assert(stdnormal_inv ([x, NaN]), [NaN -Inf 0 Inf NaN NaN]); +%!assert(stdnormal_inv (single([x, NaN])), single([NaN -Inf 0 Inf NaN NaN])); + +%% Test input validation +%!error stdnormal_inv () +%!error stdnormal_inv (1,2) +%!error stdnormal_inv (i) + diff --git a/scripts/statistics/distributions/stdnormal_pdf.m b/scripts/statistics/distributions/stdnormal_pdf.m --- a/scripts/statistics/distributions/stdnormal_pdf.m +++ b/scripts/statistics/distributions/stdnormal_pdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -19,7 +20,8 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} stdnormal_pdf (@var{x}) ## For each element of @var{x}, compute the probability density function -## (PDF) of the standard normal distribution at @var{x}. +## (PDF) at @var{x} of the standard normal distribution (mean = 0, +## standard deviation = 1). ## @end deftypefn ## Author: TT @@ -31,17 +33,25 @@ print_usage (); endif - sz = size(x); - pdf = zeros (sz); - - k = find (isnan (x)); - if (any (k)) - pdf(k) = NaN; + if (iscomplex (x)) + error ("stdnormal_pdf: X must not be complex"); endif - k = find (!isinf (x)); - if (any (k)) - pdf (k) = (2 * pi)^(- 1/2) * exp (- x(k) .^ 2 / 2); - endif + pdf = (2 * pi)^(- 1/2) * exp (- x .^ 2 / 2); endfunction + + +%!shared x,y +%! x = [-Inf 0 1 Inf]; +%! y = 1/sqrt(2*pi)*exp (-x.^2/2); +%!assert(stdnormal_pdf ([x, NaN]), [y, NaN], eps); + +%% Test class of input preserved +%!assert(stdnormal_pdf (single([x, NaN])), single([y, NaN]), eps("single")); + +%% Test input validation +%!error stdnormal_pdf () +%!error stdnormal_pdf (1,2) +%!error stdnormal_pdf (i) + diff --git a/scripts/statistics/distributions/stdnormal_rnd.m b/scripts/statistics/distributions/stdnormal_rnd.m --- a/scripts/statistics/distributions/stdnormal_rnd.m +++ b/scripts/statistics/distributions/stdnormal_rnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,39 +18,57 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} stdnormal_rnd (@var{r}, @var{c}) -## @deftypefnx {Function File} {} stdnormal_rnd (@var{sz}) -## Return an @var{r} by @var{c} or @code{size (@var{sz})} matrix of -## random numbers from the standard normal distribution. +## @deftypefn {Function File} {} stdnormal_rnd (@var{r}) +## @deftypefnx {Function File} {} stdnormal_rnd (@var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} stdnormal_rnd ([@var{sz}]) +## Return a matrix of random samples from the standard normal distribution +## (mean = 0, standard deviation = 1). +## +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the standard normal distribution -function rnd = stdnormal_rnd (r, c) +function rnd = stdnormal_rnd (varargin) - if (nargin != 1 && nargin != 2) + if (nargin < 1) print_usage (); endif - if (nargin == 2) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("stdnormal_rnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("stdnormal_rnd: C must be a positive integer"); + if (nargin == 1) + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; + else + error ("stdnormal_rnd: dimension vector must be row vector of non-negative integers"); endif - sz = [r, c]; - else - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; - else - error ("stdnormal_rnd: R must be a positive integer or vector"); + elseif (nargin > 1) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("stdnormal_rnd: dimensions must be non-negative integers"); endif + sz = [varargin{:}]; endif rnd = randn (sz); endfunction + + +%!assert(size (stdnormal_rnd (3)), [3, 3]); +%!assert(size (stdnormal_rnd ([4 1])), [4, 1]); +%!assert(size (stdnormal_rnd (4,1)), [4, 1]); + +%% Test input validation +%!error stdnormal_rnd () +%!error stdnormal_rnd (-1) +%!error stdnormal_rnd (ones(2)) +%!error stdnormal_rnd ([2 -1 2]) +%!error stdnormal_rnd (1, ones(2)) +%!error stdnormal_rnd (1, -1) + diff --git a/scripts/statistics/distributions/tcdf.m b/scripts/statistics/distributions/tcdf.m --- a/scripts/statistics/distributions/tcdf.m +++ b/scripts/statistics/distributions/tcdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -35,33 +36,59 @@ if (!isscalar (n)) [retval, x, n] = common_size (x, n); if (retval > 0) - error ("tcdf: X and N must be of common size or scalar"); + error ("tcdf: X and N must be of common size or scalars"); endif endif - cdf = zeros (size (x)); + if (iscomplex (x) || iscomplex (n)) + error ("tcdf: X and N must not be complex"); + endif - k = find (isnan (x) | !(n > 0)); - if (any (k)) - cdf(k) = NaN; + if (isa (x, "single") || isa (n, "single")) + cdf = zeros (size (x), "single"); + else + cdf = zeros (size (x)); endif - k = find ((x == Inf) & (n > 0)); - if (any (k)) - cdf(k) = 1; + k = !isinf (x) & (n > 0); + if (isscalar (n)) + cdf(k) = betainc (1 ./ (1 + x(k) .^ 2 / n), n/2, 1/2) / 2; + else + cdf(k) = betainc (1 ./ (1 + x(k) .^ 2 ./ n(k)), n(k)/2, 1/2) / 2; + endif + k &= (x > 0); + if (any (k(:))) + cdf(k) = 1 - cdf(k); endif - k = find ((x > -Inf) & (x < Inf) & (n > 0)); - if (any (k)) - if (isscalar (n)) - cdf(k) = betainc (1 ./ (1 + x(k) .^ 2 ./ n), n / 2, 1 / 2) / 2; - else - cdf(k) = betainc (1 ./ (1 + x(k) .^ 2 ./ n(k)), n(k) / 2, 1 / 2) / 2; - endif - ind = find (x(k) > 0); - if (any (ind)) - cdf(k(ind)) = 1 - cdf(k(ind)); - endif - endif + k = isnan (x) | !(n > 0); + cdf(k) = NaN; + + k = (x == Inf) & (n > 0); + cdf(k) = 1; endfunction + + +%!shared x,y +%! x = [-Inf 0 1 Inf]; +%! y = [0 1/2 3/4 1]; +%!assert(tcdf (x, ones(1,4)), y, eps); +%!assert(tcdf (x, 1), y, eps); +%!assert(tcdf (x, [0 1 NaN 1]), [NaN 1/2 NaN 1], eps); +%!assert(tcdf ([x(1:2) NaN x(4)], 1), [y(1:2) NaN y(4)], eps); + +%% Test class of input preserved +%!assert(tcdf ([x, NaN], 1), [y, NaN], eps); +%!assert(tcdf (single([x, NaN]), 1), single([y, NaN]), eps("single")); +%!assert(tcdf ([x, NaN], single(1)), single([y, NaN]), eps("single")); + +%% Test input validation +%!error tcdf () +%!error tcdf (1) +%!error tcdf (1,2,3) +%!error tcdf (ones(3),ones(2)) +%!error tcdf (ones(2),ones(3)) +%!error tcdf (i, 2) +%!error tcdf (2, i) + diff --git a/scripts/statistics/distributions/tinv.m b/scripts/statistics/distributions/tinv.m --- a/scripts/statistics/distributions/tinv.m +++ b/scripts/statistics/distributions/tinv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -18,11 +19,10 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} tinv (@var{x}, @var{n}) -## For each probability value @var{x}, compute the inverse of the -## cumulative distribution function (CDF) of the t (Student) -## distribution with degrees of freedom @var{n}. This function is -## analogous to looking in a table for the t-value of a single-tailed -## distribution. +## For each element of @var{x}, compute the quantile (the inverse of +## the CDF) at @var{x} of the t (Student) distribution with @var{n} +## degrees of freedom. This function is analogous to looking in a table +## for the t-value of a single-tailed distribution. ## @end deftypefn ## For very large n, the "correct" formula does not really work well, @@ -41,44 +41,68 @@ if (!isscalar (n)) [retval, x, n] = common_size (x, n); if (retval > 0) - error ("tinv: X and N must be of common size or scalar"); + error ("tinv: X and N must be of common size or scalars"); endif endif - inv = zeros (size (x)); - - k = find ((x < 0) | (x > 1) | isnan (x) | !(n > 0)); - if (any (k)) - inv(k) = NaN; + if (iscomplex (x) || iscomplex (n)) + error ("tinv: X and N must not be complex"); endif - k = find ((x == 0) & (n > 0)); - if (any (k)) - inv(k) = -Inf; - endif - - k = find ((x == 1) & (n > 0)); - if (any (k)) - inv(k) = Inf; + if (isa (x, "single") || isa (n, "single")) + inv = NaN (size (x), "single"); + else + inv = NaN (size (x)); endif - k = find ((x > 0) & (x < 1) & (n > 0) & (n < 10000)); - if (any (k)) - if (isscalar (n)) - inv(k) = (sign (x(k) - 1/2) - .* sqrt (n .* (1 ./ betainv (2*min (x(k), 1 - x(k)), - n/2, 1/2) - 1))); - else + k = (x == 0) & (n > 0); + inv(k) = -Inf; + + k = (x == 1) & (n > 0); + inv(k) = Inf; + + if (isscalar (n)) + k = (x > 0) & (x < 1); + if ((n > 0) && (n < 10000)) inv(k) = (sign (x(k) - 1/2) - .* sqrt (n(k) .* (1 ./ betainv (2*min (x(k), 1 - x(k)), - n(k)/2, 1/2) - 1))); + .* sqrt (n * (1 ./ betainv (2*min (x(k), 1 - x(k)), + n/2, 1/2) - 1))); + elseif (n >= 10000) + ## For large n, use the quantiles of the standard normal + inv(k) = stdnormal_inv (x(k)); endif - endif + else + k = (x > 0) & (x < 1) & (n > 0) & (n < 10000); + inv(k) = (sign (x(k) - 1/2) + .* sqrt (n(k) .* (1 ./ betainv (2*min (x(k), 1 - x(k)), + n(k)/2, 1/2) - 1))); - ## For large n, use the quantiles of the standard normal - k = find ((x > 0) & (x < 1) & (n >= 10000)); - if (any (k)) + ## For large n, use the quantiles of the standard normal + k = (x > 0) & (x < 1) & (n >= 10000); inv(k) = stdnormal_inv (x(k)); endif endfunction + + +%!shared x +%! x = [-1 0 0.5 1 2]; +%!assert(tinv (x, ones(1,5)), [NaN -Inf 0 Inf NaN]); +%!assert(tinv (x, 1), [NaN -Inf 0 Inf NaN], eps); +%!assert(tinv (x, [1 0 NaN 1 1]), [NaN NaN NaN Inf NaN], eps); +%!assert(tinv ([x(1:2) NaN x(4:5)], 1), [NaN -Inf NaN Inf NaN]); + +%% Test class of input preserved +%!assert(tinv ([x, NaN], 1), [NaN -Inf 0 Inf NaN NaN], eps); +%!assert(tinv (single([x, NaN]), 1), single([NaN -Inf 0 Inf NaN NaN]), eps("single")); +%!assert(tinv ([x, NaN], single(1)), single([NaN -Inf 0 Inf NaN NaN]), eps("single")); + +%% Test input validation +%!error tinv () +%!error tinv (1) +%!error tinv (1,2,3) +%!error tinv (ones(3),ones(2)) +%!error tinv (ones(2),ones(3)) +%!error tinv (i, 2) +%!error tinv (2, i) + diff --git a/scripts/statistics/distributions/tpdf.m b/scripts/statistics/distributions/tpdf.m --- a/scripts/statistics/distributions/tpdf.m +++ b/scripts/statistics/distributions/tpdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -35,26 +36,58 @@ if (!isscalar (n)) [retval, x, n] = common_size (x, n); if (retval > 0) - error ("tpdf: X and N must be of common size or scalar"); + error ("tpdf: X and N must be of common size or scalars"); endif endif - pdf = zeros (size (x)); + if (iscomplex (x) || iscomplex (n)) + error ("tpdf: X and N must not be complex"); + endif - k = find (isnan (x) | !(n > 0) | !(n < Inf)); - if (any (k)) - pdf(k) = NaN; + if (isa (x, "single") || isa (n, "single")) + pdf = zeros (size (x), "single"); + else + pdf = zeros (size (x)); endif - k = find (!isinf (x) & !isnan (x) & (n > 0) & (n < Inf)); - if (any (k)) - if (isscalar (n)) - pdf(k) = (exp (- (n + 1) .* log (1 + x(k) .^ 2 ./ n)/2) - / (sqrt (n) * beta (n/2, 1/2))); - else - pdf(k) = (exp (- (n(k) + 1) .* log (1 + x(k) .^ 2 ./ n(k))/2) - ./ (sqrt (n(k)) .* beta (n(k)/2, 1/2))); - endif + k = isnan (x) | !(n > 0) | !(n < Inf); + pdf(k) = NaN; + + k = !isinf (x) & !isnan (x) & (n > 0) & (n < Inf); + if (isscalar (n)) + pdf(k) = (exp (- (n + 1) * log (1 + x(k) .^ 2 / n)/2) + / (sqrt (n) * beta (n/2, 1/2))); + else + pdf(k) = (exp (- (n(k) + 1) .* log (1 + x(k) .^ 2 ./ n(k))/2) + ./ (sqrt (n(k)) .* beta (n(k)/2, 1/2))); endif endfunction + + +%!test +%! x = rand (10,1); +%! y = 1./(pi * (1 + x.^2)); +%! assert(tpdf (x, 1), y, 5*eps); + +%!shared x,y +%! x = [-Inf 0 0.5 1 Inf]; +%! y = 1./(pi * (1 + x.^2)); +%!assert(tpdf (x, ones(1,5)), y, eps); +%!assert(tpdf (x, 1), y, eps); +%!assert(tpdf (x, [0 NaN 1 1 1]), [NaN NaN y(3:5)], eps); + +%% Test class of input preserved +%!assert(tpdf ([x, NaN], 1), [y, NaN]); +%!assert(tpdf (single([x, NaN]), 1), single([y, NaN]), eps("single")); +%!assert(tpdf ([x, NaN], single(1)), single([y, NaN]), eps("single")); + +%% Test input validation +%!error tpdf () +%!error tpdf (1) +%!error tpdf (1,2,3) +%!error tpdf (ones(3),ones(2)) +%!error tpdf (ones(2),ones(3)) +%!error tpdf (i, 2) +%!error tpdf (2, i) + diff --git a/scripts/statistics/distributions/trnd.m b/scripts/statistics/distributions/trnd.m --- a/scripts/statistics/distributions/trnd.m +++ b/scripts/statistics/distributions/trnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,74 +18,100 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} trnd (@var{n}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} trnd (@var{n}, @var{sz}) -## Return an @var{r} by @var{c} matrix of random samples from the t -## (Student) distribution with @var{n} degrees of freedom. @var{n} must -## be a scalar or of size @var{r} by @var{c}. Or if @var{sz} is a -## vector create a matrix of size @var{sz}. +## @deftypefn {Function File} {} trnd (@var{n}) +## @deftypefnx {Function File} {} trnd (@var{n}, @var{r}) +## @deftypefnx {Function File} {} trnd (@var{n}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} trnd (@var{n}, [@var{sz}]) +## Return a matrix of random samples from the t (Student) distribution with +## @var{n} degrees of freedom. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the size of @var{n}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the size of +## @var{n}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the t distribution -function rnd = trnd (n, r, c) - - if (nargin == 3) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("trnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("trnd: C must be a positive integer"); - endif - sz = [r, c]; +function rnd = trnd (n, varargin) - if (any (size (n) != 1) - && ((length (size (n)) != length (sz)) || any (size (n) != sz))) - error ("trnd: N must be scalar or of size SZ"); - endif - elseif (nargin == 2) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; - else - error ("trnd: R must be a positive integer or vector"); - endif - - if (any (size (n) != 1) - && ((length (size (n)) != length (sz)) || any (size (n) != sz))) - error ("trnd: N must be scalar or of size SZ"); - endif - elseif (nargin == 1) - sz = size (n); - else + if (nargin < 1) print_usage (); endif + if (nargin == 1) + sz = size (n); + elseif (nargin == 2) + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; + else + error ("trnd: dimension vector must be row vector of non-negative integers"); + endif + elseif (nargin > 2) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("trnd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif + + if (!isscalar (n) && !isequal (size (n), sz)) + error ("trnd: N must be scalar or of size SZ"); + endif + + if (iscomplex (n)) + error ("trnd: N must not be complex"); + endif + + if (isa (n, "single")) + cls = "single"; + else + cls = "double"; + endif + if (isscalar (n)) - if (!(n > 0) || !(n < Inf)) - rnd = NaN (sz); - elseif ((n > 0) && (n < Inf)) - rnd = randn(sz) ./ sqrt(2*randg(n/2,sz)./n); + if ((n > 0) && (n < Inf)) + rnd = randn (sz) ./ sqrt (2*randg (n/2, sz) / n); else - rnd = zeros (size (n)); + rnd = NaN (sz, cls); endif else - rnd = zeros (size (n)); + rnd = NaN (sz, cls); - k = find (!(n > 0) | !(n < Inf)); - if (any (k)) - rnd(k) = NaN; - endif - - k = find ((n > 0) & (n < Inf)); - if (any (k)) - rnd(k) = randn(size(k)) ./ sqrt(2*randg(n(k)/2,size(k))./n(k)); - endif + k = (n > 0) & (n < Inf); + rnd(k) = randn (sum (k(:)), 1) ./ sqrt (2*randg (n(k)/2) ./ n(k))(:); endif endfunction + + +%!assert(size (trnd (2)), [1, 1]); +%!assert(size (trnd (ones(2,1))), [2, 1]); +%!assert(size (trnd (ones(2,2))), [2, 2]); +%!assert(size (trnd (1, 3)), [3, 3]); +%!assert(size (trnd (1, [4 1])), [4, 1]); +%!assert(size (trnd (1, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (trnd (1)), "double"); +%!assert(class (trnd (single(1))), "single"); +%!assert(class (trnd (single([1 1]))), "single"); + +%% Test input validation +%!error trnd () +%!error trnd (1, -1) +%!error trnd (1, ones(2)) +%!error trnd (i) +%!error trnd (1, [2 -1 2]) +%!error trnd (1, 2, ones(2)) +%!error trnd (1, 2, -1) +%!error trnd (ones(2,2), 3) +%!error trnd (ones(2,2), [3, 2]) +%!error trnd (ones(2,2), 2, 3) + diff --git a/scripts/statistics/distributions/unidcdf.m b/scripts/statistics/distributions/unidcdf.m --- a/scripts/statistics/distributions/unidcdf.m +++ b/scripts/statistics/distributions/unidcdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 2007-2011 David Bateman ## ## This file is part of Octave. @@ -17,26 +18,72 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} unidcdf (@var{x}, @var{v}) +## @deftypefn {Function File} {} unidcdf (@var{x}, @var{n}) ## For each element of @var{x}, compute the cumulative distribution -## function (CDF) at @var{x} of a discrete uniform distribution which -## assumes the values in @var{v} with equal probability. -## If @var{v} is a scalar then @code{1/@var{v}} is the probability of a -## single element. +## function (CDF) at @var{x} of a discrete uniform distribution which assumes +## the integer values 1--@var{n} with equal probability. ## @end deftypefn -function cdf = unidcdf (x, v) +function cdf = unidcdf (x, n) if (nargin != 2) print_usage (); endif - if (isscalar(v)) - v = [1:v].'; + if (! isscalar (n)) + [retval, x, n] = common_size (x, n); + if (retval > 0) + error ("unidcdf: X and N must be of common size or scalars"); + endif + endif + + if (iscomplex (x) || iscomplex (n)) + error ("unidcdf: X and N must not be complex"); + endif + + if (isa (x, "single") || isa (n, "single")) + cdf = zeros (size (x), "single"); else - v = v(:); + cdf = zeros (size (x)); + endif + + knan = isnan (x) | ! (n > 0 & n == fix (n)); + if (any (knan(:))) + cdf(knan) = NaN; endif - cdf = discrete_cdf (x, v, ones(size(v))); + k = (x >= n) & !knan; + cdf(k) = 1; + + k = (x >= 1) & (x < n) & !knan; + if (isscalar (n)) + cdf(k) = floor (x(k)) / n; + else + cdf(k) = floor (x(k)) ./ n(k); + endif endfunction + + +%!shared x,y +%! x = [0 1 2.5 10 11]; +%! y = [0, 0.1 0.2 1.0 1.0]; +%!assert(unidcdf (x, 10*ones(1,5)), y); +%!assert(unidcdf (x, 10), y); +%!assert(unidcdf (x, 10*[0 1 NaN 1 1]), [NaN 0.1 NaN y(4:5)]); +%!assert(unidcdf ([x(1:2) NaN Inf x(5)], 10), [y(1:2) NaN 1 y(5)]); + +%% Test class of input preserved +%!assert(unidcdf ([x, NaN], 10), [y, NaN]); +%!assert(unidcdf (single([x, NaN]), 10), single([y, NaN])); +%!assert(unidcdf ([x, NaN], single(10)), single([y, NaN])); + +%% Test input validation +%!error unidcdf () +%!error unidcdf (1) +%!error unidcdf (1,2,3) +%!error unidcdf (ones(3),ones(2)) +%!error unidcdf (ones(2),ones(3)) +%!error unidcdf (i, 2) +%!error unidcdf (2, i) + diff --git a/scripts/statistics/distributions/unidinv.m b/scripts/statistics/distributions/unidinv.m --- a/scripts/statistics/distributions/unidinv.m +++ b/scripts/statistics/distributions/unidinv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 2007-2011 David Bateman ## ## This file is part of Octave. @@ -17,25 +18,64 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} unidinv (@var{x}, @var{v}) -## For each component of @var{x}, compute the quantile (the inverse of -## the CDF) at @var{x} of the discrete uniform distribution which assumes the -## values in @var{v} with equal probability. -## If @var{v} is a scalar then @code{1/@var{v}} is the probability of a -## single element. +## @deftypefn {Function File} {} unidinv (@var{x}, @var{n}) +## For each element of @var{x}, compute the quantile (the inverse of +## the CDF) at @var{x} of the discrete uniform distribution which assumes +## the integer values 1--@var{n} with equal probability. ## @end deftypefn -function inv = unidinv (x, v) +function inv = unidinv (x, n) if (nargin != 2) print_usage (); endif - if (isscalar(v)) - v = [1:v].'; + if (! isscalar (n)) + [retval, x, n] = common_size (x, n); + if (retval > 0) + error ("unidcdf: X and N must be of common size or scalars"); + endif + endif + + if (iscomplex (x) || iscomplex (n)) + error ("unidinv: X and N must not be complex"); + endif + + if (isa (x, "single") || isa (n, "single")) + inv = NaN (size (x), "single"); else - v = v(:); + inv = NaN (size (x)); + endif + + ## For Matlab compatibility, unidinv(0) = NaN + k = (x > 0) & (x <= 1) & (n > 0 & n == fix (n)); + if (isscalar (n)) + inv(k) = floor (x(k) * n); + else + inv(k) = floor (x(k) .* n(k)); endif - inv = discrete_inv (x, v, ones(size(v))); endfunction + + +%!shared x +%! x = [-1 0 0.5 1 2]; +%!assert(unidinv (x, 10*ones(1,5)), [NaN NaN 5 10 NaN], eps); +%!assert(unidinv (x, 10), [NaN NaN 5 10 NaN], eps); +%!assert(unidinv (x, 10*[0 1 NaN 1 1]), [NaN NaN NaN 10 NaN], eps); +%!assert(unidinv ([x(1:2) NaN x(4:5)], 10), [NaN NaN NaN 10 NaN], eps); + +%% Test class of input preserved +%!assert(unidinv ([x, NaN], 10), [NaN NaN 5 10 NaN NaN], eps); +%!assert(unidinv (single([x, NaN]), 10), single([NaN NaN 5 10 NaN NaN]), eps); +%!assert(unidinv ([x, NaN], single(10)), single([NaN NaN 5 10 NaN NaN]), eps); + +%% Test input validation +%!error unidinv () +%!error unidinv (1) +%!error unidinv (1,2,3) +%!error unidinv (ones(3),ones(2)) +%!error unidinv (ones(2),ones(3)) +%!error unidinv (i, 2) +%!error unidinv (2, i) + diff --git a/scripts/statistics/distributions/unidpdf.m b/scripts/statistics/distributions/unidpdf.m --- a/scripts/statistics/distributions/unidpdf.m +++ b/scripts/statistics/distributions/unidpdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 2007-2011 David Bateman ## ## This file is part of Octave. @@ -17,25 +18,70 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} unidpdf (@var{x}, @var{v}) +## @deftypefn {Function File} {} unidpdf (@var{x}, @var{n}) ## For each element of @var{x}, compute the probability density function ## (PDF) at @var{x} of a discrete uniform distribution which assumes -## the values in @var{v} with equal probability. -## If @var{v} is a scalar then @code{1/@var{v}} is the probability of a -## single element. +## the integer values 1--@var{n} with equal probability. +## +## Warning: The underlying implementation uses the double class and +## will only be accurate for @var{n} @leq{} @code{bitmax} +## (@w{@math{2^{53} - 1}} on IEEE-754 compatible systems). ## @end deftypefn -function pdf = unidpdf (x, v) +function pdf = unidpdf (x, n) if (nargin != 2) print_usage (); endif - if (isscalar(v)) - v = [1:v].'; + if (! isscalar (n)) + [retval, x, n] = common_size (x, n); + if (retval > 0) + error ("unidpdf: X and N must be of common size or scalars"); + endif + endif + + if (iscomplex (x) || iscomplex (n)) + error ("unidpdf: X and N must not be complex"); + endif + + if (isa (x, "single") || isa (n, "single")) + pdf = zeros (size (x), "single"); else - v = v(:); + pdf = zeros (size (x)); endif - pdf = discrete_pdf (x, v, ones(size(v))); + k = isnan (x) | ! (n > 0 & n == fix (n)); + pdf(k) = NaN; + + k = !k & (x >= 1) & (x <= n) & (x == fix (x)); + if (isscalar (n)) + pdf(k) = 1 / n; + else + pdf(k) = 1 ./ n(k); + endif + endfunction + + +%!shared x,y +%! x = [-1 0 1 2 10 11]; +%! y = [0 0 0.1 0.1 0.1 0]; +%!assert(unidpdf (x, 10*ones(1,6)), y); +%!assert(unidpdf (x, 10), y); +%!assert(unidpdf (x, 10*[0 NaN 1 1 1 1]), [NaN NaN y(3:6)]); +%!assert(unidpdf ([x, NaN], 10), [y, NaN]); + +%% Test class of input preserved +%!assert(unidpdf (single([x, NaN]), 10), single([y, NaN])); +%!assert(unidpdf ([x, NaN], single(10)), single([y, NaN])); + +%% Test input validation +%!error unidpdf () +%!error unidpdf (1) +%!error unidpdf (1,2,3) +%!error unidpdf (ones(3),ones(2)) +%!error unidpdf (ones(2),ones(3)) +%!error unidpdf (i, 2) +%!error unidpdf (2, i) + diff --git a/scripts/statistics/distributions/unidrnd.m b/scripts/statistics/distributions/unidrnd.m --- a/scripts/statistics/distributions/unidrnd.m +++ b/scripts/statistics/distributions/unidrnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 2005-2011 John W. Eaton ## ## This file is part of Octave. @@ -17,44 +18,94 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} unidrnd (@var{mx}); -## @deftypefnx {Function File} {} unidrnd (@var{mx}, @var{v}); -## @deftypefnx {Function File} {} unidrnd (@var{mx}, @var{m}, @var{n}, @dots{}); -## Return random values from a discrete uniform distribution with maximum -## value(s) given by the integer @var{mx} (which may be a scalar or -## multi-dimensional array). +## @deftypefn {Function File} {} unidrnd (@var{n}) +## @deftypefnx {Function File} {} unidrnd (@var{n}, @var{r}) +## @deftypefnx {Function File} {} unidrnd (@var{n}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} unidrnd (@var{n}, [@var{sz}]) +## Return a matrix of random samples from the discrete uniform distribution +## which assumes the integer values 1--@var{n} with equal probability. +## @var{n} may be a scalar or a multi-dimensional array. ## -## If @var{mx} is a scalar, the size of the result is specified by -## the vector @var{v}, or by the optional arguments @var{m}, @var{n}, -## @dots{}. Otherwise, the size of the result is the same as the size -## of @var{mx}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the size of +## @var{n}. ## @end deftypefn ## Author: jwe -function retval = unidrnd (n, varargin) +function rnd = unidrnd (n, varargin) + + if (nargin < 1) + print_usage (); + endif + if (nargin == 1) - dims = size (n); + sz = size (n); elseif (nargin == 2) - if (rows (varargin{1}) == 1 && columns (varargin{1}) > 1) - dims = varargin{1}; + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; else - error ("unidrnd: invalid dimension vector"); + error ("unidrnd: dimension vector must be row vector of non-negative integers"); endif elseif (nargin > 2) - for i = 1:nargin-1 - if (! isscalar (varargin{i})) - error ("unidrnd: expecting scalar dimensions"); - endif - endfor - dims = [varargin{:}]; + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("unidrnd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif + + if (!isscalar (n) && !isequal (size (n), sz)) + error ("unidrnd: N must be scalar or of size SZ"); + endif + + if (iscomplex (n)) + error ("unidrnd: N must not be complex"); + endif + + if (isa (n, "single")) + cls = "single"; + else + cls = "double"; + endif + + if (isscalar (n)) + if (n > 0 && n == fix (n)) + rnd = ceil (rand (sz) * n); + else + rnd = NaN (sz, cls); + endif else - print_usage (); + rnd = ceil (rand (sz) .* n); + + k = ! (n > 0 & n == fix (n)); + rnd(k) = NaN; endif - if (isscalar (n) - || (length (size (n)) == length (dims) && all (size (n) == dims))) - retval = ceil (rand (dims) .* n); - else - error ("unidrnd: dimension mismatch"); - endif + endfunction + + +%!assert(size (unidrnd (2)), [1, 1]); +%!assert(size (unidrnd (ones(2,1))), [2, 1]); +%!assert(size (unidrnd (ones(2,2))), [2, 2]); +%!assert(size (unidrnd (10, [4 1])), [4, 1]); +%!assert(size (unidrnd (10, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (unidrnd (2)), "double"); +%!assert(class (unidrnd (single(2))), "single"); +%!assert(class (unidrnd (single([2 2]))), "single"); + +%% Test input validation +%!error unidrnd () +%!error unidrnd (10, [1;2;3]) +%!error unidrnd (10, 2, ones(2)) +%!error unidrnd (10*ones(2), 2, 1) +%!error unidrnd (i) + diff --git a/scripts/statistics/distributions/unifcdf.m b/scripts/statistics/distributions/unifcdf.m --- a/scripts/statistics/distributions/unifcdf.m +++ b/scripts/statistics/distributions/unifcdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,9 +18,11 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} unifcdf (@var{x}, @var{a}, @var{b}) -## Return the CDF at @var{x} of the uniform distribution on [@var{a}, -## @var{b}], i.e., PROB (uniform (@var{a}, @var{b}) @leq{} x). +## @deftypefn {Function File} {} unifcdf (@var{x}) +## @deftypefnx {Function File} {} unifcdf (@var{x}, @var{a}, @var{b}) +## For each element of @var{x}, compute the cumulative distribution +## function (CDF) at @var{x} of the uniform distribution on the interval +## [@var{a}, @var{b}]. ## ## Default values are @var{a} = 0, @var{b} = 1. ## @end deftypefn @@ -27,44 +30,69 @@ ## Author: KH ## Description: CDF of the uniform distribution -function cdf = unifcdf (x, a, b) +function cdf = unifcdf (x, a = 0, b = 1) if (nargin != 1 && nargin != 3) print_usage (); endif - if (nargin == 1) - a = 0; - b = 1; - endif - - if (!isscalar (a) || !isscalar(b)) + if (!isscalar (a) || !isscalar (b)) [retval, x, a, b] = common_size (x, a, b); if (retval > 0) - error ("unifcdf: X, A and B must be of common size or scalar"); + error ("unifcdf: X, A, and B must be of common size or scalars"); endif endif - sz = size (x); - cdf = zeros (sz); + if (iscomplex (x) || iscomplex (a) || iscomplex (b)) + error ("unifcdf: X, A, and B must not be complex"); + endif - k = find (isnan (x) | !(a < b)); - if (any (k)) - cdf(k) = NaN; + if (isa (x, "single") || isa (a, "single") || isa (b, "single")) + cdf = zeros (size (x), "single"); + else + cdf = zeros (size (x)); endif - k = find ((x >= b) & (a < b)); - if (any (k)) - cdf(k) = 1; - endif + k = isnan (x) | !(a < b); + cdf(k) = NaN; + + k = (x >= b) & (a < b); + cdf(k) = 1; - k = find ((x > a) & (x < b)); - if (any (k)) - if (isscalar (a) && isscalar(b)) - cdf(k) = (x(k) < b) .* (x(k) - a) ./ (b - a); - else - cdf(k) = (x(k) < b(k)) .* (x(k) - a(k)) ./ (b(k) - a(k)); - endif + k = (x > a) & (x < b); + if (isscalar (a) && isscalar (b)) + cdf(k) = (x(k) < b) .* (x(k) - a) / (b - a); + else + cdf(k) = (x(k) < b(k)) .* (x(k) - a(k)) ./ (b(k) - a(k)); endif endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 2] + 1; +%! y = [0 0 0.5 1 1]; +%!assert(unifcdf (x, ones(1,5), 2*ones(1,5)), y); +%!assert(unifcdf (x, 1, 2*ones(1,5)), y); +%!assert(unifcdf (x, ones(1,5), 2), y); +%!assert(unifcdf (x, [2 1 NaN 1 1], 2), [NaN 0 NaN 1 1]); +%!assert(unifcdf (x, 1, 2*[0 1 NaN 1 1]), [NaN 0 NaN 1 1]); +%!assert(unifcdf ([x(1:2) NaN x(4:5)], 1, 2), [y(1:2) NaN y(4:5)]); + +%% Test class of input preserved +%!assert(unifcdf ([x, NaN], 1, 2), [y, NaN]); +%!assert(unifcdf (single([x, NaN]), 1, 2), single([y, NaN])); +%!assert(unifcdf ([x, NaN], single(1), 2), single([y, NaN])); +%!assert(unifcdf ([x, NaN], 1, single(2)), single([y, NaN])); + +%% Test input validation +%!error unifcdf () +%!error unifcdf (1,2) +%!error unifcdf (1,2,3,4) +%!error unifcdf (ones(3),ones(2),ones(2)) +%!error unifcdf (ones(2),ones(3),ones(2)) +%!error unifcdf (ones(2),ones(2),ones(3)) +%!error unifcdf (i, 2, 2) +%!error unifcdf (2, i, 2) +%!error unifcdf (2, 2, i) + diff --git a/scripts/statistics/distributions/unifinv.m b/scripts/statistics/distributions/unifinv.m --- a/scripts/statistics/distributions/unifinv.m +++ b/scripts/statistics/distributions/unifinv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,9 +18,11 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} unifinv (@var{x}, @var{a}, @var{b}) +## @deftypefn {Function File} {} unifinv (@var{x}) +## @deftypefnx {Function File} {} unifinv (@var{x}, @var{a}, @var{b}) ## For each element of @var{x}, compute the quantile (the inverse of the -## CDF) at @var{x} of the uniform distribution on [@var{a}, @var{b}]. +## CDF) at @var{x} of the uniform distribution on the interval +## [@var{a}, @var{b}]. ## ## Default values are @var{a} = 0, @var{b} = 1. ## @end deftypefn @@ -27,39 +30,62 @@ ## Author: KH ## Description: Quantile function of the uniform distribution -function inv = unifinv (x, a, b) +function inv = unifinv (x, a = 0, b = 1) if (nargin != 1 && nargin != 3) print_usage (); endif - if (nargin == 1) - a = 0; - b = 1; - endif - - if (!isscalar (a) || !isscalar(b)) + if (!isscalar (a) || !isscalar (b)) [retval, x, a, b] = common_size (x, a, b); if (retval > 0) - error ("unifinv: X, A and B must be of common size or scalar"); + error ("unifinv: X, A, and B must be of common size or scalars"); endif endif - sz = size (x); - inv = zeros (sz); - - k = find ((x < 0) | (x > 1) | isnan (x) | !(a < b)); - if (any (k)) - inv(k) = NaN; + if (iscomplex (x) || iscomplex (a) || iscomplex (b)) + error ("unifinv: X, A, and B must not be complex"); endif - k = find ((x >= 0) & (x <= 1) & (a < b)); - if (any (k)) - if (isscalar (a) && isscalar(b)) - inv(k) = a + x(k) .* (b - a); - else - inv(k) = a(k) + x(k) .* (b(k) - a(k)); - endif + if (isa (x, "single") || isa (a, "single") || isa (b, "single")) + inv = NaN (size (x), "single"); + else + inv = NaN (size (x)); + endif + + k = (x >= 0) & (x <= 1) & (a < b); + if (isscalar (a) && isscalar (b)) + inv(k) = a + x(k) * (b - a); + else + inv(k) = a(k) + x(k) .* (b(k) - a(k)); endif endfunction + + +%!shared x +%! x = [-1 0 0.5 1 2]; +%!assert(unifinv (x, ones(1,5), 2*ones(1,5)), [NaN 1 1.5 2 NaN]); +%!assert(unifinv (x, 1, 2*ones(1,5)), [NaN 1 1.5 2 NaN]); +%!assert(unifinv (x, ones(1,5), 2), [NaN 1 1.5 2 NaN]); +%!assert(unifinv (x, [1 2 NaN 1 1], 2), [NaN NaN NaN 2 NaN]); +%!assert(unifinv (x, 1, 2*[1 0 NaN 1 1]), [NaN NaN NaN 2 NaN]); +%!assert(unifinv ([x(1:2) NaN x(4:5)], 1, 2), [NaN 1 NaN 2 NaN]); + +%% Test class of input preserved +%!assert(unifinv ([x, NaN], 1, 2), [NaN 1 1.5 2 NaN NaN]); +%!assert(unifinv (single([x, NaN]), 1, 2), single([NaN 1 1.5 2 NaN NaN])); +%!assert(unifinv ([x, NaN], single(1), 2), single([NaN 1 1.5 2 NaN NaN])); +%!assert(unifinv ([x, NaN], 1, single(2)), single([NaN 1 1.5 2 NaN NaN])); + +%% Test input validation +%!error unifinv () +%!error unifinv (1,2) +%!error unifinv (1,2,3,4) +%!error unifinv (ones(3),ones(2),ones(2)) +%!error unifinv (ones(2),ones(3),ones(2)) +%!error unifinv (ones(2),ones(2),ones(3)) +%!error unifinv (i, 2, 2) +%!error unifinv (2, i, 2) +%!error unifinv (2, 2, i) + diff --git a/scripts/statistics/distributions/unifpdf.m b/scripts/statistics/distributions/unifpdf.m --- a/scripts/statistics/distributions/unifpdf.m +++ b/scripts/statistics/distributions/unifpdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,9 +18,10 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} unifpdf (@var{x}, @var{a}, @var{b}) -## For each element of @var{x}, compute the PDF at @var{x} of the uniform -## distribution on [@var{a}, @var{b}]. +## @deftypefn {Function File} {} unifpdf (@var{x}) +## @deftypefnx {Function File} {} unifpdf (@var{x}, @var{a}, @var{b}) +## For each element of @var{x}, compute the probability density function (PDF) +## at @var{x} of the uniform distribution on the interval [@var{a}, @var{b}]. ## ## Default values are @var{a} = 0, @var{b} = 1. ## @end deftypefn @@ -27,39 +29,65 @@ ## Author: KH ## Description: PDF of the uniform distribution -function pdf = unifpdf (x, a, b) +function pdf = unifpdf (x, a = 0, b = 1) if (nargin != 1 && nargin != 3) print_usage (); endif - if (nargin == 1) - a = 0; - b = 1; - endif - - if (!isscalar (a) || !isscalar(b)) + if (!isscalar (a) || !isscalar (b)) [retval, x, a, b] = common_size (x, a, b); if (retval > 0) - error ("unifpdf: X, A and B must be of common size or scalars"); + error ("unifpdf: X, A, and B must be of common size or scalars"); endif endif - sz = size (x); - pdf = zeros (sz); - - k = find (isnan (x) | !(a < b)); - if (any (k)) - pdf(k) = NaN; + if (iscomplex (x) || iscomplex (a) || iscomplex (b)) + error ("unifpdf: X, A, and B must not be complex"); endif - k = find ((x >= a) & (x <= b)); - if (any (k)) - if (isscalar (a) && isscalar(b)) - pdf(k) = 1 ./ (b - a); - else - pdf(k) = 1 ./ (b(k) - a(k)); - endif + if (isa (x, "single") || isa (a, "single") || isa (b, "single")) + pdf = zeros (size (x), "single"); + else + pdf = zeros (size (x)); + endif + + k = isnan (x) | !(a < b); + pdf(k) = NaN; + + k = (x >= a) & (x <= b) & (a < b); + if (isscalar (a) && isscalar (b)) + pdf(k) = 1 / (b - a); + else + pdf(k) = 1 ./ (b(k) - a(k)); endif endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 2] + 1; +%! y = [0 1 1 1 0]; +%!assert(unifpdf (x, ones(1,5), 2*ones(1,5)), y); +%!assert(unifpdf (x, 1, 2*ones(1,5)), y); +%!assert(unifpdf (x, ones(1,5), 2), y); +%!assert(unifpdf (x, [2 NaN 1 1 1], 2), [NaN NaN y(3:5)]); +%!assert(unifpdf (x, 1, 2*[0 NaN 1 1 1]), [NaN NaN y(3:5)]); +%!assert(unifpdf ([x, NaN], 1, 2), [y, NaN]); + +%% Test class of input preserved +%!assert(unifpdf (single([x, NaN]), 1, 2), single([y, NaN])); +%!assert(unifpdf (single([x, NaN]), single(1), 2), single([y, NaN])); +%!assert(unifpdf ([x, NaN], 1, single(2)), single([y, NaN])); + +%% Test input validation +%!error unifpdf () +%!error unifpdf (1,2) +%!error unifpdf (1,2,3,4) +%!error unifpdf (ones(3),ones(2),ones(2)) +%!error unifpdf (ones(2),ones(3),ones(2)) +%!error unifpdf (ones(2),ones(2),ones(3)) +%!error unifpdf (i, 2, 2) +%!error unifpdf (2, i, 2) +%!error unifpdf (2, 2, i) + diff --git a/scripts/statistics/distributions/unifrnd.m b/scripts/statistics/distributions/unifrnd.m --- a/scripts/statistics/distributions/unifrnd.m +++ b/scripts/statistics/distributions/unifrnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,75 +18,115 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} unifrnd (@var{a}, @var{b}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} unifrnd (@var{a}, @var{b}, @var{sz}) -## Return an @var{r} by @var{c} or a @code{size (@var{sz})} matrix of -## random samples from the uniform distribution on [@var{a}, @var{b}]. -## Both @var{a} and @var{b} must be scalar or of size @var{r} by @var{c}. +## @deftypefn {Function File} {} unifrnd (@var{a}, @var{b}) +## @deftypefnx {Function File} {} unifrnd (@var{a}, @var{b}, @var{r}) +## @deftypefnx {Function File} {} unifrnd (@var{a}, @var{b}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} unifrnd (@var{a}, @var{b}, [@var{sz}]) +## Return a matrix of random samples from the uniform distribution on +## [@var{a}, @var{b}]. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the common size of @var{a} and @var{b}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the common size of +## @var{a} and @var{b}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the uniform distribution -function rnd = unifrnd (a, b, r, c) +function rnd = unifrnd (a, b, varargin) - if (nargin > 1) - if (!isscalar(a) || !isscalar(b)) - [retval, a, b] = common_size (a, b); - if (retval > 0) - error ("unifrnd: A and B must be of common size or scalar"); - endif + if (nargin < 2) + print_usage (); + endif + + if (!isscalar (a) || !isscalar (b)) + [retval, a, b] = common_size (a, b); + if (retval > 0) + error ("unifrnd: A and B must be of common size or scalars"); endif endif - if (nargin == 4) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("unifrnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("unifrnd: C must be a positive integer"); - endif - sz = [r, c]; - - if (any (size (a) != 1) - && (length (size (a)) != length (sz) || any (size (a) != sz))) - error ("unifrnd: A and B must be scalar or of size [R, C]"); - endif - elseif (nargin == 3) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; - else - error ("unifrnd: R must be a positive integer or vector"); - endif - - if (any (size (a) != 1) - && (length (size (a)) != length (sz) || any (size (a) != sz))) - error ("unifrnd: A and B must be scalar or of size SZ"); - endif - elseif (nargin == 2) - sz = size(a); - else - print_usage (); + if (iscomplex (a) || iscomplex (b)) + error ("unifrnd: A and B must not be complex"); endif - if (isscalar(a) && isscalar(b)) - if (find (!(-Inf < a) | !(a < b) | !(b < Inf))) - rnd = NaN(sz); + if (nargin == 2) + sz = size (a); + elseif (nargin == 3) + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; else - rnd = a + (b - a) .* rand (sz); + error ("unifrnd: dimension vector must be row vector of non-negative integers"); + endif + elseif (nargin > 3) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("unifrnd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif + + if (!isscalar (a) && !isequal (size (a), sz)) + error ("unifrnd: A and B must be scalar or of size SZ"); + endif + + if (isa (a, "single") || isa (b, "single")) + cls = "single"; + else + cls = "double"; + endif + + if (isscalar (a) && isscalar (b)) + if ((-Inf < a) && (a < b) && (b < Inf)) + rnd = a + (b - a) * rand (sz); + else + rnd = NaN (sz, cls); endif else rnd = a + (b - a) .* rand (sz); - k = find (!(-Inf < a) | !(a < b) | !(b < Inf)); - if (any (k)) - rnd(k) = NaN; - endif + k = !(-Inf < a) | !(a < b) | !(b < Inf); + rnd(k) = NaN; endif endfunction + + +%!assert(size (unifrnd (1,2)), [1, 1]); +%!assert(size (unifrnd (ones(2,1), 2)), [2, 1]); +%!assert(size (unifrnd (ones(2,2), 2)), [2, 2]); +%!assert(size (unifrnd (1, 2*ones(2,1))), [2, 1]); +%!assert(size (unifrnd (1, 2*ones(2,2))), [2, 2]); +%!assert(size (unifrnd (1, 2, 3)), [3, 3]); +%!assert(size (unifrnd (1, 2, [4 1])), [4, 1]); +%!assert(size (unifrnd (1, 2, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (unifrnd (1, 2)), "double"); +%!assert(class (unifrnd (single(1), 2)), "single"); +%!assert(class (unifrnd (single([1 1]), 2)), "single"); +%!assert(class (unifrnd (1, single(2))), "single"); +%!assert(class (unifrnd (1, single([2 2]))), "single"); + +%% Test input validation +%!error unifrnd () +%!error unifrnd (1) +%!error unifrnd (ones(3),ones(2)) +%!error unifrnd (ones(2),ones(3)) +%!error unifrnd (i, 2) +%!error unifrnd (2, i) +%!error unifrnd (1,2, -1) +%!error unifrnd (1,2, ones(2)) +%!error unifrnd (1, 2, [2 -1 2]) +%!error unifrnd (1,2, 1, ones(2)) +%!error unifrnd (1,2, 1, -1) +%!error unifrnd (ones(2,2), 2, 3) +%!error unifrnd (ones(2,2), 2, [3, 2]) +%!error unifrnd (ones(2,2), 2, 2, 3) + diff --git a/scripts/statistics/distributions/wblcdf.m b/scripts/statistics/distributions/wblcdf.m --- a/scripts/statistics/distributions/wblcdf.m +++ b/scripts/statistics/distributions/wblcdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,7 +18,9 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} wblcdf (@var{x}, @var{scale}, @var{shape}) +## @deftypefn {Function File} {} wblcdf (@var{x}) +## @deftypefnx {Function File} {} wblcdf (@var{x}, @var{scale}) +## @deftypefnx {Function File} {} wblcdf (@var{x}, @var{scale}, @var{shape}) ## Compute the cumulative distribution function (CDF) at @var{x} of the ## Weibull distribution with scale parameter @var{scale} and shape ## parameter @var{shape}, which is @@ -28,59 +31,83 @@ ## @ifnottex ## ## @example -## 1 - exp(-(x/scale)^shape) +## 1 - exp (-(x/scale)^shape) ## @end example ## ## @noindent ## for @var{x} @geq{} 0. +## +## Default values are @var{scale} = 1, @var{shape} = 1. ## @end ifnottex ## @end deftypefn ## Author: KH ## Description: CDF of the Weibull distribution -function cdf = wblcdf (x, scale, shape) +function cdf = wblcdf (x, scale = 1, shape = 1) if (nargin < 1 || nargin > 3) print_usage (); endif - if (nargin < 3) - shape = 1; - endif - - if (nargin < 2) - scale = 1; - endif - if (!isscalar (shape) || !isscalar (scale)) [retval, x, shape, scale] = common_size (x, shape, scale); if (retval > 0) - error ("wblcdf: X, SCALE and SHAPE must be of common size or scalar"); + error ("wblcdf: X, SCALE, and SHAPE must be of common size or scalars"); endif endif - cdf = NaN (size (x)); - - ok = ((shape > 0) & (shape < Inf) & (scale > 0) & (scale < Inf)); + if (iscomplex (x) || iscomplex (scale) || iscomplex (shape)) + error ("wblcdf: X, SCALE, and SHAPE must not be complex"); + endif - k = find ((x <= 0) & ok); - if (any (k)) - cdf(k) = 0; + if (isa (x, "single") || isa (scale, "single") || isa (shape, "single")) + cdf = NaN (size (x), "single"); + else + cdf = NaN (size (x)); endif - k = find ((x > 0) & (x < Inf) & ok); - if (any (k)) - if (isscalar (shape) && isscalar (scale)) - cdf(k) = 1 - exp (- (x(k) / scale) .^ shape); - else - cdf(k) = 1 - exp (- (x(k) ./ scale(k)) .^ shape(k)); - endif - endif + ok = (shape > 0) & (shape < Inf) & (scale > 0) & (scale < Inf); + + k = (x <= 0) & ok; + cdf(k) = 0; - k = find ((x == Inf) & ok); - if (any (k)) - cdf(k) = 1; + k = (x == Inf) & ok; + cdf(k) = 1; + + k = (x > 0) & (x < Inf) & ok; + if (isscalar (shape) && isscalar (scale)) + cdf(k) = 1 - exp (- (x(k) / scale) .^ shape); + else + cdf(k) = 1 - exp (- (x(k) ./ scale(k)) .^ shape(k)); endif endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 Inf]; +%! y = [0, 1-exp(-x(2:4)), 1]; +%!assert(wblcdf (x, ones(1,5), ones(1,5)), y); +%!assert(wblcdf (x, 1, ones(1,5)), y); +%!assert(wblcdf (x, ones(1,5), 1), y); +%!assert(wblcdf (x, [0 1 NaN Inf 1], 1), [NaN 0 NaN NaN 1]); +%!assert(wblcdf (x, 1, [0 1 NaN Inf 1]), [NaN 0 NaN NaN 1]); +%!assert(wblcdf ([x(1:2) NaN x(4:5)], 1, 1), [y(1:2) NaN y(4:5)]); + +%% Test class of input preserved +%!assert(wblcdf ([x, NaN], 1, 1), [y, NaN]); +%!assert(wblcdf (single([x, NaN]), 1, 1), single([y, NaN])); +%!assert(wblcdf ([x, NaN], single(1), 1), single([y, NaN])); +%!assert(wblcdf ([x, NaN], 1, single(1)), single([y, NaN])); + +%% Test input validation +%!error wblcdf () +%!error wblcdf (1,2,3,4) +%!error wblcdf (ones(3),ones(2),ones(2)) +%!error wblcdf (ones(2),ones(3),ones(2)) +%!error wblcdf (ones(2),ones(2),ones(3)) +%!error wblcdf (i, 2, 2) +%!error wblcdf (2, i, 2) +%!error wblcdf (2, 2, i) + diff --git a/scripts/statistics/distributions/wblinv.m b/scripts/statistics/distributions/wblinv.m --- a/scripts/statistics/distributions/wblinv.m +++ b/scripts/statistics/distributions/wblinv.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,57 +18,82 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} wblinv (@var{x}, @var{scale}, @var{shape}) +## @deftypefn {Function File} {} wblinv (@var{x}) +## @deftypefnx {Function File} {} wblinv (@var{x}, @var{scale}) +## @deftypefnx {Function File} {} wblinv (@var{x}, @var{scale}, @var{shape}) ## Compute the quantile (the inverse of the CDF) at @var{x} of the ## Weibull distribution with scale parameter @var{scale} and shape ## parameter @var{shape}. +## +## Default values are @var{scale} = 1, @var{shape} = 1. ## @end deftypefn ## Author: KH ## Description: Quantile function of the Weibull distribution -function inv = wblinv (x, scale, shape) +function inv = wblinv (x, scale = 1, shape = 1) if (nargin < 1 || nargin > 3) print_usage (); endif - if (nargin < 3) - shape = 1; - endif - - if (nargin < 2) - scale = 1; - endif - if (!isscalar (scale) || !isscalar (shape)) [retval, x, scale, shape] = common_size (x, scale, shape); if (retval > 0) - error ("wblinv: X, SCALE and SHAPE must be of common size or scalar"); + error ("wblinv: X, SCALE, and SHAPE must be of common size or scalars"); endif endif - inv = NaN (size (x)); - - ok = ((scale > 0) & (scale < Inf) & (shape > 0) & (shape < Inf)); + if (iscomplex (x) || iscomplex (scale) || iscomplex (shape)) + error ("wblinv: X, SCALE, and SHAPE must not be complex"); + endif - k = find ((x == 0) & ok); - if (any (k)) - inv(k) = 0; + if (isa (x, "single") || isa (scale, "single") || isa (shape, "single")) + inv = NaN (size (x), "single"); + else + inv = NaN (size (x)); endif - k = find ((x > 0) & (x < 1) & ok); - if (any (k)) - if (isscalar (scale) && isscalar (shape)) - inv(k) = scale * (- log (1 - x(k))) .^ (1 / shape); - else - inv(k) = scale(k) .* (- log (1 - x(k))) .^ (1 ./ shape(k)); - endif - endif + ok = (scale > 0) & (scale < Inf) & (shape > 0) & (shape < Inf); + + k = (x == 0) & ok; + inv(k) = 0; - k = find ((x == 1) & ok); - if (any (k)) - inv(k) = Inf; + k = (x == 1) & ok; + inv(k) = Inf; + + k = (x > 0) & (x < 1) & ok; + if (isscalar (scale) && isscalar (shape)) + inv(k) = scale * (- log (1 - x(k))) .^ (1 / shape); + else + inv(k) = scale(k) .* (- log (1 - x(k))) .^ (1 ./ shape(k)); endif endfunction + + +%!shared x +%! x = [-1 0 0.63212055882855778 1 2]; +%!assert(wblinv (x, ones(1,5), ones(1,5)), [NaN 0 1 Inf NaN], eps); +%!assert(wblinv (x, 1, ones(1,5)), [NaN 0 1 Inf NaN], eps); +%!assert(wblinv (x, ones(1,5), 1), [NaN 0 1 Inf NaN], eps); +%!assert(wblinv (x, [1 -1 NaN Inf 1], 1), [NaN NaN NaN NaN NaN]); +%!assert(wblinv (x, 1, [1 -1 NaN Inf 1]), [NaN NaN NaN NaN NaN]); +%!assert(wblinv ([x(1:2) NaN x(4:5)], 1, 1), [NaN 0 NaN Inf NaN]); + +%% Test class of input preserved +%!assert(wblinv ([x, NaN], 1, 1), [NaN 0 1 Inf NaN NaN], eps); +%!assert(wblinv (single([x, NaN]), 1, 1), single([NaN 0 1 Inf NaN NaN]), eps("single")); +%!assert(wblinv ([x, NaN], single(1), 1), single([NaN 0 1 Inf NaN NaN]), eps("single")); +%!assert(wblinv ([x, NaN], 1, single(1)), single([NaN 0 1 Inf NaN NaN]), eps("single")); + +%% Test input validation +%!error wblinv () +%!error wblinv (1,2,3,4) +%!error wblinv (ones(3),ones(2),ones(2)) +%!error wblinv (ones(2),ones(3),ones(2)) +%!error wblinv (ones(2),ones(2),ones(3)) +%!error wblinv (i, 2, 2) +%!error wblinv (2, i, 2) +%!error wblinv (2, 2, i) + diff --git a/scripts/statistics/distributions/wblpdf.m b/scripts/statistics/distributions/wblpdf.m --- a/scripts/statistics/distributions/wblpdf.m +++ b/scripts/statistics/distributions/wblpdf.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,7 +18,9 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} wblpdf (@var{x}, @var{scale}, @var{shape}) +## @deftypefn {Function File} {} wblpdf (@var{x}) +## @deftypefnx {Function File} {} wblpdf (@var{x}, @var{scale}) +## @deftypefnx {Function File} {} wblpdf (@var{x}, @var{scale}, @var{shape}) ## Compute the probability density function (PDF) at @var{x} of the ## Weibull distribution with scale parameter @var{scale} and shape ## parameter @var{shape} which is given by @@ -27,57 +30,83 @@ ## @ifnottex ## ## @example -## shape * scale^(-shape) * x^(shape-1) * exp(-(x/scale)^shape) +## shape * scale^(-shape) * x^(shape-1) * exp (-(x/scale)^shape) ## @end example ## ## @end ifnottex ## @noindent ## for @var{x} @geq{} 0. +## +## Default values are @var{scale} = 1, @var{shape} = 1. ## @end deftypefn ## Author: KH ## Description: PDF of the Weibull distribution -function pdf = wblpdf (x, scale, shape) +function pdf = wblpdf (x, scale = 1, shape = 1) if (nargin < 1 || nargin > 3) print_usage (); endif - if (nargin < 3) - shape = 1; - endif - - if (nargin < 2) - scale = 1; - endif - if (!isscalar (scale) || !isscalar (shape)) [retval, x, scale, shape] = common_size (x, scale, shape); if (retval > 0) - error ("wblpdf: X, SCALE and SHAPE must be of common size or scalar"); + error ("wblpdf: X, SCALE, and SHAPE must be of common size or scalars"); endif endif - pdf = NaN (size (x)); - ok = ((scale > 0) & (scale < Inf) & (shape > 0) & (shape < Inf)); + if (iscomplex (x) || iscomplex (scale) || iscomplex (shape)) + error ("wblpdf: X, SCALE, and SHAPE must not be complex"); + endif - k = find ((x > -Inf) & (x < 0) & ok); - if (any (k)) - pdf(k) = 0; + if (isa (x, "single") || isa (scale, "single") || isa (shape, "single")) + pdf = NaN (size (x), "single"); + else + pdf = NaN (size (x)); endif - k = find ((x >= 0) & (x < Inf) & ok); - if (any (k)) - if (isscalar (scale) && isscalar (shape)) - pdf(k) = (shape .* (scale .^ -shape) - .* (x(k) .^ (shape - 1)) - .* exp(- (x(k) / scale) .^ shape)); - else - pdf(k) = (shape(k) .* (scale(k) .^ -shape(k)) - .* (x(k) .^ (shape(k) - 1)) - .* exp(- (x(k) ./ scale(k)) .^ shape(k))); - endif + ok = ((scale > 0) & (scale < Inf) & (shape > 0) & (shape < Inf)); + + k = (x < 0) & ok; + pdf(k) = 0; + + k = (x >= 0) & (x < Inf) & ok; + if (isscalar (scale) && isscalar (shape)) + pdf(k) = (shape * (scale .^ -shape) + .* (x(k) .^ (shape - 1)) + .* exp (- (x(k) / scale) .^ shape)); + else + pdf(k) = (shape(k) .* (scale(k) .^ -shape(k)) + .* (x(k) .^ (shape(k) - 1)) + .* exp (- (x(k) ./ scale(k)) .^ shape(k))); endif endfunction + + +%!shared x,y +%! x = [-1 0 0.5 1 Inf]; +%! y = [0, exp(-x(2:4)), NaN]; +%!assert(wblpdf (x, ones(1,5), ones(1,5)), y); +%!assert(wblpdf (x, 1, ones(1,5)), y); +%!assert(wblpdf (x, ones(1,5), 1), y); +%!assert(wblpdf (x, [0 NaN Inf 1 1], 1), [NaN NaN NaN y(4:5)]); +%!assert(wblpdf (x, 1, [0 NaN Inf 1 1]), [NaN NaN NaN y(4:5)]); +%!assert(wblpdf ([x, NaN], 1, 1), [y, NaN]); + +%% Test class of input preserved +%!assert(wblpdf (single([x, NaN]), 1, 1), single([y, NaN])); +%!assert(wblpdf ([x, NaN], single(1), 1), single([y, NaN])); +%!assert(wblpdf ([x, NaN], 1, single(1)), single([y, NaN])); + +%% Test input validation +%!error wblpdf () +%!error wblpdf (1,2,3,4) +%!error wblpdf (ones(3),ones(2),ones(2)) +%!error wblpdf (ones(2),ones(3),ones(2)) +%!error wblpdf (ones(2),ones(2),ones(3)) +%!error wblpdf (i, 2, 2) +%!error wblpdf (2, i, 2) +%!error wblpdf (2, 2, i) + diff --git a/scripts/statistics/distributions/wblrnd.m b/scripts/statistics/distributions/wblrnd.m --- a/scripts/statistics/distributions/wblrnd.m +++ b/scripts/statistics/distributions/wblrnd.m @@ -1,3 +1,4 @@ +## Copyright (C) 2011 Rik Wehbring ## Copyright (C) 1995-2011 Kurt Hornik ## ## This file is part of Octave. @@ -17,78 +18,115 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} wblrnd (@var{scale}, @var{shape}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} wblrnd (@var{scale}, @var{shape}, @var{sz}) -## Return an @var{r} by @var{c} matrix of random samples from the -## Weibull distribution with parameters @var{scale} and @var{shape} -## which must be scalar or of size @var{r} by @var{c}. Or if @var{sz} -## is a vector return a matrix of size @var{sz}. +## @deftypefn {Function File} {} wblrnd (@var{scale}, @var{shape}) +## @deftypefnx {Function File} {} wblrnd (@var{scale}, @var{shape}, @var{r}) +## @deftypefnx {Function File} {} wblrnd (@var{scale}, @var{shape}, @var{r}, @var{c}, @dots{}) +## @deftypefnx {Function File} {} wblrnd (@var{scale}, @var{shape}, [@var{sz}]) +## Return a matrix of random samples from the Weibull distribution with +## parameters @var{scale} and @var{shape}. ## -## If @var{r} and @var{c} are omitted, the size of the result matrix is -## the common size of @var{alpha} and @var{sigma}. +## When called with a single size argument, return a square matrix with +## the dimension specified. When called with more than one scalar argument the +## first two arguments are taken as the number of rows and columns and any +## further arguments specify additional matrix dimensions. The size may also +## be specified with a vector of dimensions @var{sz}. +## +## If no size arguments are given then the result matrix is the common size of +## @var{scale} and @var{shape}. ## @end deftypefn ## Author: KH ## Description: Random deviates from the Weibull distribution -function rnd = wblrnd (scale, shape, r, c) +function rnd = wblrnd (scale, shape, varargin) - if (nargin > 1) - if (!isscalar(scale) || !isscalar(shape)) - [retval, scale, shape] = common_size (scale, shape); - if (retval > 0) - error ("wblrnd: SCALE and SHAPE must be of common size or scalar"); - endif + if (nargin < 2) + print_usage (); + endif + + if (!isscalar (scale) || !isscalar (shape)) + [retval, scale, shape] = common_size (scale, shape); + if (retval > 0) + error ("wblrnd: SCALE and SHAPE must be of common size or scalars"); endif endif - if (nargin == 4) - if (! (isscalar (r) && (r > 0) && (r == round (r)))) - error ("wblrnd: R must be a positive integer"); - endif - if (! (isscalar (c) && (c > 0) && (c == round (c)))) - error ("wblrnd: C must be a positive integer"); - endif - sz = [r, c]; + if (iscomplex (scale) || iscomplex (shape)) + error ("wblrnd: SCALE and SHAPE must not be complex"); + endif - if (any (size (scale) != 1) - && ((length (size (scale)) != length (sz)) - || any (size (scale) != sz))) - error ("wblrnd: SCALE and SHAPE must be scalar or of size [R, C]"); - endif + if (nargin == 2) + sz = size (scale); elseif (nargin == 3) - if (isscalar (r) && (r > 0)) - sz = [r, r]; - elseif (isvector(r) && all (r > 0)) - sz = r(:)'; + if (isscalar (varargin{1}) && varargin{1} >= 0) + sz = [varargin{1}, varargin{1}]; + elseif (isrow (varargin{1}) && all (varargin{1} >= 0)) + sz = varargin{1}; else - error ("wblrnd: R must be a positive integer or vector"); + error ("wblrnd: dimension vector must be row vector of non-negative integers"); endif + elseif (nargin > 3) + if (any (cellfun (@(x) (!isscalar (x) || x < 0), varargin))) + error ("wblrnd: dimensions must be non-negative integers"); + endif + sz = [varargin{:}]; + endif - if (any (size (scale) != 1) - && ((length (size (scale)) != length (sz)) - || any (size (scale) != sz))) - error ("wblrnd: SCALE and SHAPE must be scalar or of size SZ"); - endif - elseif (nargin == 2) - sz = size(scale); + if (!isscalar (scale) && !isequal (size (scale), sz)) + error ("wblrnd: SCALE and SHAPE must be scalar or of size SZ"); + endif + + if (isa (scale, "single") || isa (shape, "single")) + cls = "single"; else - print_usage (); + cls = "double"; endif if (isscalar (scale) && isscalar (shape)) - if (scale > 0 && scale < Inf && shape > 0 && shape < Inf) - rnd = scale .* rande(sz) .^ (1./shape); + if ((scale > 0) && (scale < Inf) && (shape > 0) && (shape < Inf)) + rnd = scale * rande (sz) .^ (1/shape); else - rnd = NaN (sz); + rnd = NaN (sz, cls); endif else - rnd = scale .* rande(sz) .^ (1./shape); - k = find ((scale <= 0) | (scale == Inf) | ((shape <= 0) & (shape == Inf))); - if (any(k)) - rnd(k) = NaN; - endif + rnd = scale .* rande (sz) .^ (1./shape); + + k = (scale <= 0) | (scale == Inf) | (shape <= 0) | (shape == Inf); + rnd(k) = NaN; endif endfunction + +%!assert(size (wblrnd (1,2)), [1, 1]); +%!assert(size (wblrnd (ones(2,1), 2)), [2, 1]); +%!assert(size (wblrnd (ones(2,2), 2)), [2, 2]); +%!assert(size (wblrnd (1, 2*ones(2,1))), [2, 1]); +%!assert(size (wblrnd (1, 2*ones(2,2))), [2, 2]); +%!assert(size (wblrnd (1, 2, 3)), [3, 3]); +%!assert(size (wblrnd (1, 2, [4 1])), [4, 1]); +%!assert(size (wblrnd (1, 2, 4, 1)), [4, 1]); + +%% Test class of input preserved +%!assert(class (wblrnd (1, 2)), "double"); +%!assert(class (wblrnd (single(1), 2)), "single"); +%!assert(class (wblrnd (single([1 1]), 2)), "single"); +%!assert(class (wblrnd (1, single(2))), "single"); +%!assert(class (wblrnd (1, single([2 2]))), "single"); + +%% Test input validation +%!error wblrnd () +%!error wblrnd (1) +%!error wblrnd (ones(3),ones(2)) +%!error wblrnd (ones(2),ones(3)) +%!error wblrnd (i, 2) +%!error wblrnd (2, i) +%!error wblrnd (1,2, -1) +%!error wblrnd (1,2, ones(2)) +%!error wblrnd (1, 2, [2 -1 2]) +%!error wblrnd (1,2, 1, ones(2)) +%!error wblrnd (1,2, 1, -1) +%!error wblrnd (ones(2,2), 2, 3) +%!error wblrnd (ones(2,2), 2, [3, 2]) +%!error wblrnd (ones(2,2), 2, 2, 3) +