GNU Octave  4.2.1
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-2017 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 #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.is_complex_type ();
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.
119  sqrtm_utri_inplace (x);
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 ();
131  sqrtm_utri_inplace (x);
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:
159  sqrtm_utri_inplace (x);
160  retval = x;
161  retval.matrix_type (mt);
162  break;
163 
164  case MatrixType::Lower:
165  x = x.transpose ();
166  sqrtm_utri_inplace (x);
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 
183  sqrtm_utri_inplace (x);
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.is_numeric_type ())
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 */
Matrix diag(octave_idx_type k=0) const
Definition: dMatrix.cc:2471
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:803
bool any_element_is_negative(bool=false) const
Definition: dNDArray.cc:541
int ndims(void) const
Definition: ov.h:495
octave_idx_type rows(void) const
Definition: ov.h:489
static octave_value do_sqrtm(const octave_value &arg)
Definition: sqrtm.cc:90
bool is_unknown(void) const
Definition: MatrixType.h:135
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
bool is_numeric_type(void) const
Definition: ov.h:679
for large enough k
Definition: lu.cc:606
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:46
is greater than zero
Definition: load-path.cc:2339
u
Definition: lu.cc:138
void err_square_matrix_required(const char *fcn, const char *name)
Definition: errwarn.cc:112
s
Definition: file-io.cc:2682
octave_idx_type rows(void) const
Definition: Array.h:401
octave_value arg
Definition: pr-output.cc:3440
JNIEnv void * args
Definition: ov-java.cc:67
octave_idx_type columns(void) const
Definition: ov.h:491
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:935
bool is_complex_type(void) const
Definition: ov.h:670
octave_value retval
Definition: data.cc:6294
Matrix transpose(void) const
Definition: dMatrix.h:129
OCTAVE_API double xnorm(const ColumnVector &x, double p)
Definition: oct-norm.cc:549
Definition: dMatrix.h:37
ComplexMatrix transpose(void) const
Definition: CMatrix.h:165
#define eps(C)
MatrixType matrix_type(void) const
Definition: ov.h:527
ComplexMatrix xgemm(const ComplexMatrix &a, const ComplexMatrix &b, blas_trans_type transa, blas_trans_type transb)
Definition: CMatrix.cc:3396
OCTAVE_API double xfrobnorm(const Matrix &x)
Definition: oct-norm.cc:549
double element_type
Definition: Array.h:199
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:142
static void sqrtm_utri_inplace(Matrix &T)
Definition: sqrtm.cc:41
ComplexMatrix octave_value_extract< ComplexMatrix >(const octave_value &v)
Definition: ov.h:1597
const T * fortran_vec(void) const
Definition: Array.h:584
bool is_single_type(void) const
Definition: ov.h:627
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:136
Matrix octave_value_extract< Matrix >(const octave_value &v)
Definition: ov.h:1595
octave_value sqrt(void) const
Definition: ov.h:1388
bool is_diag_matrix(void) const
Definition: ov.h:572
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &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 F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE * x