GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
schur.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2018 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
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License 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 <https://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 
57 DEFUN (schur, args, nargout,
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 @nospell{Riccati}
124 equations 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.isnumeric ())
170  err_wrong_type_arg ("schur", arg);
171 
173 
174  if (arg.is_single_type ())
175  {
176  if (! force_complex && arg.isreal ())
177  {
179 
180  if (nargout <= 1)
181  {
183  retval = ovl (result.schur_matrix ());
184  }
185  else
186  {
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.isreal ())
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  {
223  retval = ovl (result.unitary_matrix (),
224  result.schur_matrix ());
225  }
226  }
227  else
228  {
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 
268 DEFUN (rsf2csf, args, nargout,
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).isnumeric ())
293  err_wrong_type_arg ("rsf2csf", args(0));
294  if (! args(1).isnumeric ())
295  err_wrong_type_arg ("rsf2csf", args(1));
296  if (args(0).iscomplex () || args(1).iscomplex ())
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 */
static octave_value mark_upper_triangular(const Matrix &a)
Definition: schur.cc:39
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$)
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:53
void error(const char *fmt,...)
Definition: error.cc:578
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:997
FloatMatrix float_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:837
void err_square_matrix_required(const char *fcn, const char *name)
Definition: errwarn.cc:118
octave_value arg
Definition: pr-output.cc:3244
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:400
FloatComplexMatrix float_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:856
octave::call_stack & cs
Definition: ov-class.cc:1752
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
double tmp
Definition: data.cc:6252
octave_value retval
Definition: data.cc:6246
Definition: dMatrix.h:36
schur< FloatComplexMatrix > rsf2csf< FloatComplexMatrix, FloatMatrix >(const FloatMatrix &s_arg, const FloatMatrix &u_arg)
Definition: schur.cc:463
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:162
With real return the complex result
Definition: data.cc:3260
Definition: mx-defs.h:73
void warning(const char *fmt,...)
Definition: error.cc:801
schur< ComplexMatrix > rsf2csf< ComplexMatrix, Matrix >(const Matrix &s_arg, const Matrix &u_arg)
Definition: schur.cc:355
bool isreal(void) const
Definition: ov.h:703
MatrixType matrix_type(void) const
Definition: ov.h:514
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).isinteger())
double element_type
Definition: Array.h:201
args.length() nargin
Definition: file-io.cc:589
for i
Definition: data.cc:5264
ComplexMatrix complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:852
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:888
bool isnumeric(void) const
Definition: ov.h:723
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:834