changeset 26231:c36b6e371f5d

isdefinite.m: Return only true or false, not -1, 0, +1 (bug #51270). * NEWS: Announce change * isdefinite.m: Rewrite documentation. Add input validation for TOL. Remove code to check for semi-definite matrix (return value of 0 previously). Update BIST tests and add new ones.
author Rik <rik@octave.org>
date Thu, 13 Dec 2018 17:04:01 -0800
parents b2f806601d30
children 90487d5431cc
files NEWS scripts/linear-algebra/isdefinite.m
diffstat 2 files changed, 51 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Thu Dec 13 15:01:29 2018 -0800
+++ b/NEWS	Thu Dec 13 17:04:01 2018 -0800
@@ -12,6 +12,13 @@
     or "skew" to calculate the symmetric or skew-symmetric property
     of a matrix.  Performance has also been increased.
 
+ ** The function isdefinite now returns true or false rather than
+    -1, 0, 1.  To test for a positive semi-definite matrix (old output
+    of 0) check whether the following two conditions hold:
+
+      isdefinite (A) => 0
+      isdefinite (A + 5*TOL, TOL) => 1
+
  ** The issorted function now uses a direction option of "ascend" or
     "descend" to make it compatible with both the sort function and
     with Matlab.  Change all uses of "ascending" and "descending" in
--- a/scripts/linear-algebra/isdefinite.m	Thu Dec 13 15:01:29 2018 -0800
+++ b/scripts/linear-algebra/isdefinite.m	Thu Dec 13 17:04:01 2018 -0800
@@ -19,12 +19,24 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {} isdefinite (@var{A})
 ## @deftypefnx {} {} isdefinite (@var{A}, @var{tol})
-## Return 1 if @var{A} is symmetric positive definite within the
-## tolerance specified by @var{tol} or 0 if @var{A} is symmetric
-## positive semi-definite.  Otherwise, return -1.
+## Return true if @var{A} is symmetric positive definite matrix within the
+## tolerance specified by @var{tol}.
 ##
 ## If @var{tol} is omitted, use a tolerance of
-## @code{100 * eps * norm (@var{A}, "fro")}
+## @code{100 * eps * norm (@var{A}, "fro")}.
+##
+## Background: A positive definite matrix has eigenvalues which are all
+## greater than zero.  A positive semi-definite matrix has eigenvalues which
+## are all greater than or equal to zero.  The matrix @var{A} is very likely to
+## be positive semi-definite if the following two conditions hold for a
+## suitably small tolerance @var{tol}.
+##
+## @example
+## @group
+## isdefinite (@var{A}) @result{} 0
+## isdefinite (@var{A} + 5*@var{tol}, @var{tol}) @result{} 1
+## @end group
+## @end example
 ## @seealso{issymmetric, ishermitian}
 ## @end deftypefn
 
@@ -38,50 +50,58 @@
     print_usage ();
   endif
 
+  ## Validate inputs
+  retval = false;
+  if (! isnumeric (A))
+    return;
+  endif
+
   if (! isfloat (A))
     A = double (A);
   endif
 
   if (nargin == 1)
     tol = 100 * eps (class (A)) * norm (A, "fro");
+  elseif (! (isnumeric (tol) && isscalar (tol) && tol >= 0))
+    error ("isdefinite: TOL must be a scalar >= 0");
   endif
 
   if (! ishermitian (A, tol))
-    error ("isdefinite: A must be a Hermitian matrix");
+    return;
   endif
 
   e = tol * eye (rows (A));
-  [r, p] = chol (A - e);
+  [~, p] = chol (A - e);
   if (p == 0)
-    retval = 1;
-  else
-    [r, p] = chol (A + e);
-    if (p == 0)
-      retval = 0;
-    else
-      retval = -1;
-    endif
+    retval = true;
   endif
 
 endfunction
 
 
 %!test
-%! A = [-1 0; 0 -1];
-%! assert (isdefinite (A), -1);
+%! A = [-1, 0; 0, -1];
+%! assert (isdefinite (A), false);
+
+%!test
+%! A = [1, 0; 0, 1];
+%! assert (isdefinite (A), true);
 
 %!test
-%! A = [1 0; 0 1];
-%! assert (isdefinite (A), 1);
+%! A = [2, -1,  0; -1, 2, -1; 0, -1, 2];
+%! assert (isdefinite (A), true);
 
+## Test for positive semi-definite matrix
 %!test
-%! A = [2 -1 0; -1 2 -1; 0 -1 2];
-%! assert (isdefinite (A), 1);
+%! A = [1, 0; 0, 0];
+%! assert (isdefinite (A), false);
+%! tol = 100*eps;
+%! assert (isdefinite (A+5*tol, tol), true);
 
-%!test
-%! A = [1 0; 0 0];
-%! assert (isdefinite (A), 0);
+%!assert (! isdefinite (magic (3)))
 
 %!error isdefinite ()
 %!error isdefinite (1,2,3)
-%!error <A must be a Hermitian matrix> isdefinite ([1 2; 3 4])
+%!error <TOL must be a scalar .= 0> isdefinite (1, {1})
+%!error <TOL must be a scalar .= 0> isdefinite (1, [1 1])
+%!error <TOL must be a scalar .= 0> isdefinite (1, -1)