GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
sqrtm.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2001-2018 Ross Lippert and Paul Kienzle
4 Copyright (C) 2010 VZLU Prague
5 
6 This file is part of Octave.
7 
8 Octave is free software: you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <https://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if defined (HAVE_CONFIG_H)
25 # include "config.h"
26 #endif
27 
28 #include "schur.h"
29 #include "lo-ieee.h"
30 #include "lo-mappers.h"
31 #include "oct-norm.h"
32 
33 #include "defun.h"
34 #include "error.h"
35 #include "errwarn.h"
36 #include "utils.h"
37 #include "xnorm.h"
38 
39 template <typename Matrix>
40 static void
42 {
43  typedef typename Matrix::element_type element_type;
44 
45  const element_type zero = element_type ();
46 
47  bool singular = false;
48 
49  // The following code is equivalent to this triple loop:
50  //
51  // n = rows (T);
52  // for j = 1:n
53  // T(j,j) = sqrt (T(j,j));
54  // for i = j-1:-1:1
55  // T(i,j) /= (T(i,i) + T(j,j));
56  // k = 1:i-1;
57  // T(k,j) -= T(k,i) * T(i,j);
58  // endfor
59  // endfor
60  //
61  // this is an in-place, cache-aligned variant of the code
62  // given in Higham's paper.
63 
64  const octave_idx_type n = T.rows ();
65  element_type *Tp = T.fortran_vec ();
66  for (octave_idx_type j = 0; j < n; j++)
67  {
68  element_type *colj = Tp + n*j;
69  if (colj[j] != zero)
70  colj[j] = sqrt (colj[j]);
71  else
72  singular = true;
73 
74  for (octave_idx_type i = j-1; i >= 0; i--)
75  {
76  const element_type *coli = Tp + n*i;
77  const element_type colji = colj[i] /= (coli[i] + colj[j]);
78  for (octave_idx_type k = 0; k < i; k++)
79  colj[k] -= coli[k] * colji;
80  }
81  }
82 
83  if (singular)
84  warning_with_id ("Octave:sqrtm:SingularMatrix",
85  "sqrtm: matrix is singular, may not have a square root");
86 }
87 
88 template <typename Matrix, typename ComplexMatrix, typename ComplexSCHUR>
89 static octave_value
91 {
92 
94 
95  MatrixType mt = arg.matrix_type ();
96 
97  bool iscomplex = arg.iscomplex ();
98 
99  typedef typename Matrix::element_type real_type;
100 
101  real_type cutoff = 0;
102  real_type one = 1;
103  real_type eps = std::numeric_limits<real_type>::epsilon ();
104 
105  if (! iscomplex)
106  {
108 
109  if (mt.is_unknown ()) // if type is not known, compute it now.
110  arg.matrix_type (mt = MatrixType (x));
111 
112  switch (mt.type ())
113  {
114  case MatrixType::Upper:
116  if (! x.diag ().any_element_is_negative ())
117  {
118  // Do it in real arithmetic.
120  retval = x;
121  retval.matrix_type (mt);
122  }
123  else
124  iscomplex = true;
125  break;
126 
127  case MatrixType::Lower:
128  if (! x.diag ().any_element_is_negative ())
129  {
130  x = x.transpose ();
132  retval = x.transpose ();
133  retval.matrix_type (mt);
134  }
135  else
136  iscomplex = true;
137  break;
138 
139  default:
140  iscomplex = true;
141  break;
142  }
143 
144  if (iscomplex)
145  cutoff = 10 * x.rows () * eps * xnorm (x, one);
146  }
147 
148  if (iscomplex)
149  {
151 
152  if (mt.is_unknown ()) // if type is not known, compute it now.
153  arg.matrix_type (mt = MatrixType (x));
154 
155  switch (mt.type ())
156  {
157  case MatrixType::Upper:
160  retval = x;
161  retval.matrix_type (mt);
162  break;
163 
164  case MatrixType::Lower:
165  x = x.transpose ();
167  retval = x.transpose ();
168  retval.matrix_type (mt);
169  break;
170 
171  default:
172  {
174 
175  do
176  {
177  ComplexSCHUR schur_fact (x, "", true);
178  x = schur_fact.schur_matrix ();
179  u = schur_fact.unitary_matrix ();
180  }
181  while (0); // schur no longer needed.
182 
184 
185  x = u * x; // original x no longer needed.
187 
188  if (cutoff > 0 && xnorm (imag (res), one) <= cutoff)
189  retval = real (res);
190  else
191  retval = res;
192  }
193  break;
194  }
195  }
196 
197  return retval;
198 }
199 
200 DEFUN (sqrtm, args, nargout,
201  doc: /* -*- texinfo -*-
202 @deftypefn {} {@var{s} =} sqrtm (@var{A})
203 @deftypefnx {} {[@var{s}, @var{error_estimate}] =} sqrtm (@var{A})
204 Compute the matrix square root of the square matrix @var{A}.
205 
206 Ref: @nospell{N.J. Higham}. @cite{A New sqrtm for @sc{matlab}}. Numerical
207 Analysis Report No. 336, Manchester @nospell{Centre} for Computational
208 Mathematics, Manchester, England, January 1999.
209 @seealso{expm, logm}
210 @end deftypefn */)
211 {
212  if (args.length () != 1)
213  print_usage ();
214 
215  octave_value arg = args(0);
216 
217  octave_idx_type n = arg.rows ();
218  octave_idx_type nc = arg.columns ();
219 
220  if (n != nc || arg.ndims () > 2)
221  err_square_matrix_required ("sqrtm", "A");
222 
223  octave_value_list retval (nargout > 1 ? 3 : 1);
224 
225  if (nargout > 1)
226  {
227  // FIXME: Octave does not calculate a condition number with respect to
228  // sqrtm. Should this return NaN instead of -1?
229  retval(2) = -1.0;
230  }
231 
232  if (arg.is_diag_matrix ())
233  // sqrtm of a diagonal matrix is just sqrt.
234  retval(0) = arg.sqrt ();
235  else if (arg.is_single_type ())
238  else if (arg.isnumeric ())
241 
242  if (nargout > 1)
243  {
244  // This corresponds to generic code
245  //
246  // norm (s*s - x, "fro") / norm (x, "fro");
247 
248  octave_value s = retval(0);
249  retval(1) = xfrobnorm (s*s - arg) / xfrobnorm (arg);
250  }
251 
252  return retval;
253 }
254 
255 /*
256 %!assert (sqrtm (2*ones (2)), ones (2), 3*eps)
257 
258 ## The following two tests are from the reference in the docstring above.
259 %!test
260 %! warning ("off", "Octave:sqrtm:SingularMatrix", "local");
261 %! x = [0 1; 0 0];
262 %! assert (any (isnan (sqrtm (x))(:)));
263 
264 %!test
265 %! x = eye (4); x(2,2) = x(3,3) = 2^-26; x(1,4) = 1;
266 %! z = eye (4); z(2,2) = z(3,3) = 2^-13; z(1,4) = 0.5;
267 %! [y, err] = sqrtm (x);
268 %! assert (y, z);
269 %! assert (err, 0); # Yes, this one has to hold exactly
270 */
octave_value sqrt(void) const
Definition: ov.h:1449
octave_idx_type rows(void) const
Definition: Array.h:404
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:816
static octave_value do_sqrtm(const octave_value &arg)
Definition: sqrtm.cc:90
OCTINTERP_API void print_usage(void)
Definition: defun.cc:54
OCTAVE_EXPORT octave_value_list or N dimensional array whose elements are all equal to the IEEE symbol zero divided by zero($0/0$)
for large enough k
Definition: lu.cc:617
const T * fortran_vec(void) const
Definition: Array.h:584
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:53
bool is_unknown(void) const
Definition: MatrixType.h:155
u
Definition: lu.cc:138
void err_square_matrix_required(const char *fcn, const char *name)
Definition: errwarn.cc:118
int ndims(void) const
Definition: ov.h:478
s
Definition: file-io.cc:2729
octave_value arg
Definition: pr-output.cc:3244
int type(bool quiet=true)
Definition: MatrixType.cc:650
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function xample nargout(@histc)
Definition: ov-usr-fcn.cc:997
octave_idx_type columns(void) const
Definition: ov.h:474
bool is_single_type(void) const
Definition: ov.h:651
octave_idx_type rows(void) const
Definition: ov.h:472
octave_value retval
Definition: data.cc:6246
OCTAVE_API double xnorm(const ColumnVector &x, double p)
Definition: oct-norm.cc:550
Definition: dMatrix.h:36
#define eps(C)
ComplexMatrix xgemm(const ComplexMatrix &a, const ComplexMatrix &b, blas_trans_type transa, blas_trans_type transb)
Definition: CMatrix.cc:3515
MatrixType matrix_type(void) const
Definition: ov.h:514
OCTAVE_API double xfrobnorm(const Matrix &x)
Definition: oct-norm.cc:550
bool iscomplex(void) const
Definition: ov.h:710
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:141
for i
Definition: data.cc:5264
bool is_diag_matrix(void) const
Definition: ov.h:571
static void sqrtm_utri_inplace(Matrix &T)
Definition: sqrtm.cc:41
ComplexMatrix octave_value_extract< ComplexMatrix >(const octave_value &v)
Definition: ov.h:1686
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:135
Matrix octave_value_extract< Matrix >(const octave_value &v)
Definition: ov.h:1684
bool isnumeric(void) const
Definition: ov.h:723
F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE * x