1########################################################################
2##
3## Copyright (C) 2003-2021 The Octave Project Developers
4##
5## See the file COPYRIGHT.md in the top-level directory of this
6## distribution or <https://octave.org/copyright/>.
7##
8## This file is part of Octave.
9##
10## Octave is free software: you can redistribute it and/or modify it
11## under the terms of the GNU General Public License as published by
12## the Free Software Foundation, either version 3 of the License, or
13## (at your option) any later version.
14##
15## Octave is distributed in the hope that it will be useful, but
16## WITHOUT ANY WARRANTY; without even the implied warranty of
17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18## GNU General Public License for more details.
19##
20## You should have received a copy of the GNU General Public License
21## along with Octave; see the file COPYING.  If not, see
22## <https://www.gnu.org/licenses/>.
23##
24########################################################################
25
26## -*- texinfo -*-
27## @deftypefn  {} {} isdefinite (@var{A})
28## @deftypefnx {} {} isdefinite (@var{A}, @var{tol})
29## Return true if @var{A} is symmetric positive definite matrix within the
30## tolerance specified by @var{tol}.
31##
32## If @var{tol} is omitted, use a tolerance of
33## @code{100 * eps * norm (@var{A}, "fro")}.
34##
35## Background: A positive definite matrix has eigenvalues which are all
36## greater than zero.  A positive semi-definite matrix has eigenvalues which
37## are all greater than or equal to zero.  The matrix @var{A} is very likely to
38## be positive semi-definite if the following two conditions hold for a
39## suitably small tolerance @var{tol}.
40##
41## @example
42## @group
43## isdefinite (@var{A}) @result{} 0
44## isdefinite (@var{A} + 5*@var{tol}, @var{tol}) @result{} 1
45## @end group
46## @end example
47## @seealso{issymmetric, ishermitian}
48## @end deftypefn
49
50function retval = isdefinite (A, tol)
51
52  if (nargin < 1 || nargin > 2)
53    print_usage ();
54  endif
55
56  ## Validate inputs
57  retval = false;
58  if (! isnumeric (A))
59    return;
60  endif
61
62  if (! isfloat (A))
63    A = double (A);
64  endif
65
66  if (nargin == 1)
67    tol = 100 * eps (class (A)) * norm (A, "fro");
68  elseif (! (isnumeric (tol) && isscalar (tol) && tol >= 0))
69    error ("isdefinite: TOL must be a scalar >= 0");
70  endif
71
72  if (! ishermitian (A, tol))
73    return;
74  endif
75
76  e = tol * eye (rows (A));
77  [~, p] = chol (A - e);
78  if (p == 0)
79    retval = true;
80  endif
81
82endfunction
83
84
85%!test
86%! A = [-1, 0; 0, -1];
87%! assert (isdefinite (A), false);
88
89%!test
90%! A = [1, 0; 0, 1];
91%! assert (isdefinite (A), true);
92
93%!test
94%! A = [2, -1,  0; -1, 2, -1; 0, -1, 2];
95%! assert (isdefinite (A), true);
96
97## Test for positive semi-definite matrix
98%!test
99%! A = [1, 0; 0, 0];
100%! assert (isdefinite (A), false);
101%! tol = 100*eps;
102%! assert (isdefinite (A+5*tol, tol), true);
103
104%!assert (! isdefinite (magic (3)))
105
106%!error isdefinite ()
107%!error isdefinite (1,2,3)
108%!error <TOL must be a scalar .= 0> isdefinite (1, {1})
109%!error <TOL must be a scalar .= 0> isdefinite (1, [1 1])
110%!error <TOL must be a scalar .= 0> isdefinite (1, -1)
111