GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
sqrtm.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2001-2013 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 the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 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 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <float.h>
29 
30 #include "CmplxSCHUR.h"
31 #include "fCmplxSCHUR.h"
32 #include "lo-ieee.h"
33 #include "lo-mappers.h"
34 #include "oct-norm.h"
35 
36 #include "defun.h"
37 #include "error.h"
38 #include "gripes.h"
39 #include "utils.h"
40 #include "xnorm.h"
41 
42 template <class Matrix>
43 static void
45 {
46  typedef typename Matrix::element_type element_type;
47 
48  const element_type zero = element_type ();
49 
50  bool singular = false;
51 
52  // The following code is equivalent to this triple loop:
53  //
54  // n = rows (T);
55  // for j = 1:n
56  // T(j,j) = sqrt (T(j,j));
57  // for i = j-1:-1:1
58  // T(i,j) /= (T(i,i) + T(j,j));
59  // k = 1:i-1;
60  // T(k,j) -= T(k,i) * T(i,j);
61  // endfor
62  // endfor
63  //
64  // this is an in-place, cache-aligned variant of the code
65  // given in Higham's paper.
66 
67  const octave_idx_type n = T.rows ();
68  element_type *Tp = T.fortran_vec ();
69  for (octave_idx_type j = 0; j < n; j++)
70  {
71  element_type *colj = Tp + n*j;
72  if (colj[j] != zero)
73  colj[j] = sqrt (colj[j]);
74  else
75  singular = true;
76 
77  for (octave_idx_type i = j-1; i >= 0; i--)
78  {
79  const element_type *coli = Tp + n*i;
80  const element_type colji = colj[i] /= (coli[i] + colj[j]);
81  for (octave_idx_type k = 0; k < i; k++)
82  colj[k] -= coli[k] * colji;
83  }
84  }
85 
86  if (singular)
87  warning_with_id ("Octave:sqrtm:SingularMatrix",
88  "sqrtm: matrix is singular, may not have a square root");
89 }
90 
91 template <class Matrix, class ComplexMatrix, class ComplexSCHUR>
92 static octave_value
94 {
95 
96  octave_value retval;
97 
98  MatrixType mt = arg.matrix_type ();
99 
100  bool iscomplex = arg.is_complex_type ();
101 
102  typedef typename Matrix::element_type real_type;
103 
104  real_type cutoff = 0, one = 1;
105  real_type eps = std::numeric_limits<real_type>::epsilon ();
106 
107  if (! iscomplex)
108  {
110 
111  if (mt.is_unknown ()) // if type is not known, compute it now.
112  arg.matrix_type (mt = MatrixType (x));
113 
114  switch (mt.type ())
115  {
116  case MatrixType::Upper:
118  if (! x.diag ().any_element_is_negative ())
119  {
120  // Do it in real arithmetic.
121  sqrtm_utri_inplace (x);
122  retval = x;
123  retval.matrix_type (mt);
124  }
125  else
126  iscomplex = true;
127  break;
128 
129  case MatrixType::Lower:
130  if (! x.diag ().any_element_is_negative ())
131  {
132  x = x.transpose ();
133  sqrtm_utri_inplace (x);
134  retval = x.transpose ();
135  retval.matrix_type (mt);
136  }
137  else
138  iscomplex = true;
139  break;
140 
141  default:
142  iscomplex = true;
143  break;
144  }
145 
146  if (iscomplex)
147  cutoff = 10 * x.rows () * eps * xnorm (x, one);
148  }
149 
150  if (iscomplex)
151  {
153 
154  if (mt.is_unknown ()) // if type is not known, compute it now.
155  arg.matrix_type (mt = MatrixType (x));
156 
157  switch (mt.type ())
158  {
159  case MatrixType::Upper:
161  sqrtm_utri_inplace (x);
162  retval = x;
163  retval.matrix_type (mt);
164  break;
165 
166  case MatrixType::Lower:
167  x = x.transpose ();
168  sqrtm_utri_inplace (x);
169  retval = x.transpose ();
170  retval.matrix_type (mt);
171  break;
172 
173  default:
174  {
175  ComplexMatrix u;
176 
177  do
178  {
179  ComplexSCHUR schur (x, std::string (), true);
180  x = schur.schur_matrix ();
181  u = schur.unitary_matrix ();
182  }
183  while (0); // schur no longer needed.
184 
185  sqrtm_utri_inplace (x);
186 
187  x = u * x; // original x no longer needed.
189 
190  if (cutoff > 0 && xnorm (imag (res), one) <= cutoff)
191  retval = real (res);
192  else
193  retval = res;
194  }
195  break;
196  }
197  }
198 
199  return retval;
200 }
201 
202 DEFUN (sqrtm, args, nargout,
203  "-*- texinfo -*-\n\
204 @deftypefn {Built-in Function} {@var{s} =} sqrtm (@var{A})\n\
205 @deftypefnx {Built-in Function} {[@var{s}, @var{error_estimate}] =} sqrtm (@var{A})\n\
206 Compute the matrix square root of the square matrix @var{A}.\n\
207 \n\
208 Ref: N.J. Higham. @cite{A New sqrtm for @sc{matlab}}. Numerical\n\
209 Analysis Report No. 336, Manchester @nospell{Centre} for Computational\n\
210 Mathematics, Manchester, England, January 1999.\n\
211 @seealso{expm, logm}\n\
212 @end deftypefn")
213 {
214  octave_value_list retval;
215 
216  int nargin = args.length ();
217 
218  if (nargin != 1)
219  {
220  print_usage ();
221  return retval;
222  }
223 
224  octave_value arg = args(0);
225 
226  octave_idx_type n = arg.rows ();
227  octave_idx_type nc = arg.columns ();
228 
229  if (n != nc || arg.ndims () > 2)
230  {
232  return retval;
233  }
234 
235  if (nargout > 1)
236  {
237  retval.resize (1, 2);
238  retval(2) = -1.0;
239  }
240 
241  if (arg.is_diag_matrix ())
242  // sqrtm of a diagonal matrix is just sqrt.
243  retval(0) = arg.sqrt ();
244  else if (arg.is_single_type ())
245  retval(0) = do_sqrtm<FloatMatrix, FloatComplexMatrix, FloatComplexSCHUR>
246  (arg);
247  else if (arg.is_numeric_type ())
248  retval(0) = do_sqrtm<Matrix, ComplexMatrix, ComplexSCHUR> (arg);
249 
250  if (nargout > 1 && ! error_state)
251  {
252  // This corresponds to generic code
253  //
254  // norm (s*s - x, "fro") / norm (x, "fro");
255 
256  octave_value s = retval(0);
257  retval(1) = xfrobnorm (s*s - arg) / xfrobnorm (arg);
258  }
259 
260  return retval;
261 }
262 
263 /*
264 %!assert (sqrtm (2*ones (2)), ones (2), 3*eps)
265 
266 ## The following two tests are from the reference in the docstring above.
267 %!test
268 %! x = [0 1; 0 0];
269 %! assert (any (isnan (sqrtm (x))(:)));
270 
271 %!test
272 %! x = eye (4); x(2,2) = x(3,3) = 2^-26; x(1,4) = 1;
273 %! z = eye (4); z(2,2) = z(3,3) = 2^-13; z(1,4) = 0.5;
274 %! [y, err] = sqrtm (x);
275 %! assert (y, z);
276 %! assert (err, 0); # Yes, this one has to hold exactly
277 */