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
schur.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2017 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <string>
28 
29 #include "schur.h"
30 
31 #include "defun.h"
32 #include "error.h"
33 #include "errwarn.h"
34 #include "ovl.h"
35 #include "utils.h"
36 
37 template <typename Matrix>
38 static octave_value
40 {
42 
43  octave_idx_type n = a.rows ();
44  assert (a.columns () == n);
45 
46  const typename Matrix::element_type zero = typename Matrix::element_type ();
47 
48  for (octave_idx_type i = 0; i < n; i++)
49  if (a(i,i) == zero)
50  return retval;
51 
53 
54  return retval;
55 }
56 
58  doc: /* -*- texinfo -*-
59 @deftypefn {} {@var{S} =} schur (@var{A})
60 @deftypefnx {} {@var{S} =} schur (@var{A}, "real")
61 @deftypefnx {} {@var{S} =} schur (@var{A}, "complex")
62 @deftypefnx {} {@var{S} =} schur (@var{A}, @var{opt})
63 @deftypefnx {} {[@var{U}, @var{S}] =} schur (@dots{})
64 @cindex Schur decomposition
65 Compute the Schur@tie{}decomposition of @var{A}.
66 
67 The Schur@tie{}decomposition is defined as
68 @tex
69 $$
70  S = U^T A U
71 $$
72 @end tex
73 @ifnottex
74 
75 @example
76 @code{@var{S} = @var{U}' * @var{A} * @var{U}}
77 @end example
78 
79 @end ifnottex
80 where @var{U} is a unitary matrix
81 @tex
82 ($U^T U$ is identity)
83 @end tex
84 @ifnottex
85 (@code{@var{U}'* @var{U}} is identity)
86 @end ifnottex
87 and @var{S} is upper triangular. The eigenvalues of @var{A} (and @var{S})
88 are the diagonal elements of @var{S}. If the matrix @var{A} is real, then
89 the real Schur@tie{}decomposition is computed, in which the matrix @var{U}
90 is orthogonal and @var{S} is block upper triangular with blocks of size at
91 most
92 @tex
93 $2 \times 2$
94 @end tex
95 @ifnottex
96 @code{2 x 2}
97 @end ifnottex
98 along the diagonal. The diagonal elements of @var{S}
99 (or the eigenvalues of the
100 @tex
101 $2 \times 2$
102 @end tex
103 @ifnottex
104 @code{2 x 2}
105 @end ifnottex
106 blocks, when appropriate) are the eigenvalues of @var{A} and @var{S}.
107 
108 The default for real matrices is a real Schur@tie{}decomposition.
109 A complex decomposition may be forced by passing the flag
110 @qcode{"complex"}.
111 
112 The eigenvalues are optionally ordered along the diagonal according to the
113 value of @var{opt}. @code{@var{opt} = "a"} indicates that all eigenvalues
114 with negative real parts should be moved to the leading block of @var{S}
115 (used in @code{are}), @code{@var{opt} = "d"} indicates that all
116 eigenvalues with magnitude less than one should be moved to the leading
117 block of @var{S} (used in @code{dare}), and @code{@var{opt} = "u"}, the
118 default, indicates that no ordering of eigenvalues should occur. The
119 leading @var{k} columns of @var{U} always span the @var{A}-invariant
120 subspace corresponding to the @var{k} leading eigenvalues of @var{S}.
121 
122 The Schur@tie{}decomposition is used to compute eigenvalues of a square
123 matrix, and has applications in the solution of algebraic Riccati equations
124 in control (see @code{are} and @code{dare}).
125 @seealso{rsf2csf, ordschur, lu, chol, hess, qr, qz, svd}
126 @end deftypefn */)
127 {
128  int nargin = args.length ();
129 
130  if (nargin < 1 || nargin > 2 || nargout > 2)
131  print_usage ();
132 
133  octave_value arg = args(0);
134 
135  std::string ord;
136  if (nargin == 2)
137  ord = args(1).xstring_value ("schur: second argument must be a string");
138 
139  bool force_complex = false;
140 
141  if (ord == "real")
142  {
143  ord = "";
144  }
145  else if (ord == "complex")
146  {
147  force_complex = true;
148  ord = "";
149  }
150  else
151  {
152  char ord_char = ord.empty () ? 'U' : ord[0];
153 
154  if (ord_char != 'U' && ord_char != 'A' && ord_char != 'D'
155  && ord_char != 'u' && ord_char != 'a' && ord_char != 'd')
156  {
157  warning ("schur: incorrect ordered schur argument '%s'",
158  ord.c_str ());
159  return ovl ();
160  }
161  }
162 
163  octave_idx_type nr = arg.rows ();
164  octave_idx_type nc = arg.columns ();
165 
166  if (nr != nc)
167  err_square_matrix_required ("schur", "A");
168 
169  if (! arg.is_numeric_type ())
170  err_wrong_type_arg ("schur", arg);
171 
173 
174  if (arg.is_single_type ())
175  {
176  if (! force_complex && arg.is_real_type ())
177  {
179 
180  if (nargout <= 1)
181  {
182  octave::math::schur<FloatMatrix> result (tmp, ord, false);
183  retval = ovl (result.schur_matrix ());
184  }
185  else
186  {
187  octave::math::schur<FloatMatrix> result (tmp, ord, true);
188  retval = ovl (result.unitary_matrix (),
189  result.schur_matrix ());
190  }
191  }
192  else
193  {
195 
196  if (nargout <= 1)
197  {
199  retval = ovl (mark_upper_triangular (result.schur_matrix ()));
200  }
201  else
202  {
204  retval = ovl (result.unitary_matrix (),
205  mark_upper_triangular (result.schur_matrix ()));
206  }
207  }
208  }
209  else
210  {
211  if (! force_complex && arg.is_real_type ())
212  {
213  Matrix tmp = arg.matrix_value ();
214 
215  if (nargout <= 1)
216  {
217  octave::math::schur<Matrix> result (tmp, ord, false);
218  retval = ovl (result.schur_matrix ());
219  }
220  else
221  {
222  octave::math::schur<Matrix> result (tmp, ord, true);
223  retval = ovl (result.unitary_matrix (),
224  result.schur_matrix ());
225  }
226  }
227  else
228  {
229  ComplexMatrix ctmp = arg.complex_matrix_value ();
230 
231  if (nargout <= 1)
232  {
233  octave::math::schur<ComplexMatrix> result (ctmp, ord, false);
234  retval = ovl (mark_upper_triangular (result.schur_matrix ()));
235  }
236  else
237  {
238  octave::math::schur<ComplexMatrix> result (ctmp, ord, true);
239  retval = ovl (result.unitary_matrix (),
240  mark_upper_triangular (result.schur_matrix ()));
241  }
242  }
243  }
244 
245  return retval;
246 }
247 
248 /*
249 %!test
250 %! a = [1, 2, 3; 4, 5, 9; 7, 8, 6];
251 %! [u, s] = schur (a);
252 %! assert (u' * a * u, s, sqrt (eps));
253 
254 %!test
255 %! a = single ([1, 2, 3; 4, 5, 9; 7, 8, 6]);
256 %! [u, s] = schur (a);
257 %! assert (u' * a * u, s, sqrt (eps ("single")));
258 
259 %!error schur ()
260 %!error schur (1,2,3)
261 %!error [a,b,c] = schur (1)
262 %!error <must be a square matrix> schur ([1, 2, 3; 4, 5, 6])
263 %!error <wrong type argument 'cell'> schur ({1})
264 %!warning <incorrect ordered schur argument> schur ([1, 2; 3, 4], "bad_opt");
265 
266 */
267 
269  doc: /* -*- texinfo -*-
270 @deftypefn {} {[@var{U}, @var{T}] =} rsf2csf (@var{UR}, @var{TR})
271 Convert a real, upper quasi-triangular Schur@tie{}form @var{TR} to a
272 complex, upper triangular Schur@tie{}form @var{T}.
273 
274 Note that the following relations hold:
275 
276 @tex
277 $UR \cdot TR \cdot {UR}^T = U T U^{\dagger}$ and
278 $U^{\dagger} U$ is the identity matrix I.
279 @end tex
280 @ifnottex
281 @tcode{@var{UR} * @var{TR} * @var{UR}' = @var{U} * @var{T} * @var{U}'} and
282 @code{@var{U}' * @var{U}} is the identity matrix I.
283 @end ifnottex
284 
285 Note also that @var{U} and @var{T} are not unique.
286 @seealso{schur}
287 @end deftypefn */)
288 {
289  if (args.length () != 2 || nargout > 2)
290  print_usage ();
291 
292  if (! args(0).is_numeric_type ())
293  err_wrong_type_arg ("rsf2csf", args(0));
294  if (! args(1).is_numeric_type ())
295  err_wrong_type_arg ("rsf2csf", args(1));
296  if (args(0).is_complex_type () || args(1).is_complex_type ())
297  error ("rsf2csf: UR and TR must be real matrices");
298 
299  if (args(0).is_single_type () || args(1).is_single_type ())
300  {
301  FloatMatrix u = args(0).float_matrix_value ();
302  FloatMatrix t = args(1).float_matrix_value ();
303 
306 
307  return ovl (cs.unitary_matrix (), cs.schur_matrix ());
308  }
309  else
310  {
311  Matrix u = args(0).matrix_value ();
312  Matrix t = args(1).matrix_value ();
313 
316 
317  return ovl (cs.unitary_matrix (), cs.schur_matrix ());
318  }
319 }
320 
321 /*
322 %!test
323 %! A = [1, 1, 1, 2; 1, 2, 1, 1; 1, 1, 3, 1; -2, 1, 1, 1];
324 %! [u, t] = schur (A);
325 %! [U, T] = rsf2csf (u, t);
326 %! assert (norm (u * t * u' - U * T * U'), 0, 1e-12);
327 %! assert (norm (A - U * T * U'), 0, 1e-12);
328 
329 %!test
330 %! A = rand (10);
331 %! [u, t] = schur (A);
332 %! [U, T] = rsf2csf (u, t);
333 %! assert (norm (tril (T, -1)), 0);
334 %! assert (norm (U * U'), 1, 1e-14);
335 
336 %!test
337 %! A = [0, 1;-1, 0];
338 %! [u, t] = schur (A);
339 %! [U, T] = rsf2csf (u,t);
340 %! assert (U * T * U', A, 1e-14);
341 */
bool is_real_type(void) const
Definition: ov.h:667
octave_idx_type rows(void) const
Definition: ov.h:489
static octave_value mark_upper_triangular(const Matrix &a)
Definition: schur.cc:39
FloatComplexMatrix float_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:809
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).is_integer_type())
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
bool is_numeric_type(void) const
Definition: ov.h:679
T unitary_matrix(void) const
Definition: schur.h:87
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:46
Definition: mx-defs.h:71
void error(const char *fmt,...)
Definition: error.cc:570
is greater than zero
Definition: load-path.cc:2339
u
Definition: lu.cc:138
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function t
Definition: ov-usr-fcn.cc:935
void err_square_matrix_required(const char *fcn, const char *name)
Definition: errwarn.cc:112
octave_idx_type rows(void) const
Definition: Array.h:401
octave_value arg
Definition: pr-output.cc:3440
T schur_matrix(void) const
Definition: schur.h:85
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:398
JNIEnv void * args
Definition: ov-java.cc:67
octave_idx_type columns(void) const
Definition: ov.h:491
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
int nargin
Definition: graphics.cc:10115
double tmp
Definition: data.cc:6300
octave_value retval
Definition: data.cc:6294
Definition: dMatrix.h:37
schur< FloatComplexMatrix > rsf2csf< FloatComplexMatrix, FloatMatrix >(const FloatMatrix &s_arg, const FloatMatrix &u_arg)
Definition: schur.cc:437
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:787
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:156
With real return the complex result
Definition: data.cc:3375
MatrixType matrix_type(void) const
Definition: ov.h:527
void warning(const char *fmt,...)
Definition: error.cc:788
schur< ComplexMatrix > rsf2csf< ComplexMatrix, Matrix >(const Matrix &s_arg, const Matrix &u_arg)
Definition: schur.cc:329
double element_type
Definition: Array.h:199
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
ComplexMatrix complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:805
FloatMatrix float_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:790
bool is_single_type(void) const
Definition: ov.h:627
schur< RT > rsf2csf(const AT &s, const AT &u)
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
octave_idx_type columns(void) const
Definition: Array.h:410