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
schur.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2013 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 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <string>
28 
29 #include "CmplxSCHUR.h"
30 #include "dbleSCHUR.h"
31 #include "fCmplxSCHUR.h"
32 #include "floatSCHUR.h"
33 
34 #include "defun.h"
35 #include "error.h"
36 #include "gripes.h"
37 #include "oct-obj.h"
38 #include "utils.h"
39 
40 template <class Matrix>
41 static octave_value
43 {
44  octave_value retval = a;
45 
46  octave_idx_type n = a.rows ();
47  assert (a.columns () == n);
48 
49  const typename Matrix::element_type zero = typename Matrix::element_type ();
50 
51  for (octave_idx_type i = 0; i < n; i++)
52  if (a(i,i) == zero)
53  return retval;
54 
56 
57  return retval;
58 }
59 
60 DEFUN (schur, args, nargout,
61  "-*- texinfo -*-\n\
62 @deftypefn {Built-in Function} {@var{S} =} schur (@var{A})\n\
63 @deftypefnx {Built-in Function} {@var{S} =} schur (@var{A}, \"real\")\n\
64 @deftypefnx {Built-in Function} {@var{S} =} schur (@var{A}, \"complex\")\n\
65 @deftypefnx {Built-in Function} {@var{S} =} schur (@var{A}, @var{opt})\n\
66 @deftypefnx {Built-in Function} {[@var{U}, @var{S}] =} schur (@var{A}, @dots{})\n\
67 @cindex Schur decomposition\n\
68 Compute the Schur@tie{}decomposition of @var{A}\n\
69 @tex\n\
70 $$\n\
71  S = U^T A U\n\
72 $$\n\
73 @end tex\n\
74 @ifnottex\n\
75 \n\
76 @example\n\
77 @code{@var{S} = @var{U}' * @var{A} * @var{U}}\n\
78 @end example\n\
79 \n\
80 @end ifnottex\n\
81 where @var{U} is a unitary matrix\n\
82 @tex\n\
83 ($U^T U$ is identity)\n\
84 @end tex\n\
85 @ifnottex\n\
86 (@code{@var{U}'* @var{U}} is identity)\n\
87 @end ifnottex\n\
88 and @var{S} is upper triangular. The eigenvalues of @var{A} (and @var{S})\n\
89 are the diagonal elements of @var{S}. If the matrix @var{A}\n\
90 is real, then the real Schur@tie{}decomposition is computed, in which the\n\
91 matrix @var{U} is orthogonal and @var{S} is block upper triangular\n\
92 with blocks of size at most\n\
93 @tex\n\
94 $2 \\times 2$\n\
95 @end tex\n\
96 @ifnottex\n\
97 @code{2 x 2}\n\
98 @end ifnottex\n\
99 along the diagonal. The diagonal elements of @var{S}\n\
100 (or the eigenvalues of the\n\
101 @tex\n\
102 $2 \\times 2$\n\
103 @end tex\n\
104 @ifnottex\n\
105 @code{2 x 2}\n\
106 @end ifnottex\n\
107 blocks, when appropriate) are the eigenvalues of @var{A} and @var{S}.\n\
108 \n\
109 The default for real matrices is a real Schur@tie{}decomposition.\n\
110 A complex decomposition may be forced by passing the flag\n\
111 @qcode{\"complex\"}.\n\
112 \n\
113 The eigenvalues are optionally ordered along the diagonal according to\n\
114 the value of @var{opt}. @code{@var{opt} = \"a\"} indicates that all\n\
115 eigenvalues with negative real parts should be moved to the leading\n\
116 block of @var{S}\n\
117 (used in @code{are}), @code{@var{opt} = \"d\"} indicates that all eigenvalues\n\
118 with magnitude less than one should be moved to the leading block of @var{S}\n\
119 (used in @code{dare}), and @code{@var{opt} = \"u\"}, the default, indicates\n\
120 that no ordering of eigenvalues should occur. The leading @var{k}\n\
121 columns of @var{U} always span the @var{A}-invariant\n\
122 subspace corresponding to the @var{k} leading eigenvalues of @var{S}.\n\
123 \n\
124 The Schur@tie{}decomposition is used to compute eigenvalues of a\n\
125 square matrix, and has applications in the solution of algebraic\n\
126 Riccati equations in control (see @code{are} and @code{dare}).\n\
127 @seealso{rsf2csf, lu, chol, hess, qr, qz, svd}\n\
128 @end deftypefn")
129 {
130  octave_value_list retval;
131 
132  int nargin = args.length ();
133 
134  if (nargin < 1 || nargin > 2 || nargout > 2)
135  {
136  print_usage ();
137  return retval;
138  }
139 
140  octave_value arg = args(0);
141 
142  std::string ord;
143 
144  if (nargin == 2)
145  {
146  ord = args(1).string_value ();
147 
148  if (error_state)
149  {
150  error ("schur: second argument must be a string");
151  return retval;
152  }
153  }
154 
155  bool force_complex = false;
156 
157  if (ord == "real")
158  {
159  ord = std::string ();
160  }
161  else if (ord == "complex")
162  {
163  force_complex = true;
164  ord = std::string ();
165  }
166  else
167  {
168  char ord_char = ord.empty () ? 'U' : ord[0];
169 
170  if (ord_char != 'U' && ord_char != 'A' && ord_char != 'D'
171  && ord_char != 'u' && ord_char != 'a' && ord_char != 'd')
172  {
173  warning ("schur: incorrect ordered schur argument '%c'",
174  ord.c_str ());
175  return retval;
176  }
177  }
178 
179  octave_idx_type nr = arg.rows ();
180  octave_idx_type nc = arg.columns ();
181 
182  if (nr != nc)
183  {
185  return retval;
186  }
187 
188  if (! arg.is_numeric_type ())
189  gripe_wrong_type_arg ("schur", arg);
190  else if (arg.is_single_type ())
191  {
192  if (! force_complex && arg.is_real_type ())
193  {
194  FloatMatrix tmp = arg.float_matrix_value ();
195 
196  if (! error_state)
197  {
198  if (nargout == 0 || nargout == 1)
199  {
200  FloatSCHUR result (tmp, ord, false);
201  retval(0) = result.schur_matrix ();
202  }
203  else
204  {
205  FloatSCHUR result (tmp, ord, true);
206  retval(1) = result.schur_matrix ();
207  retval(0) = result.unitary_matrix ();
208  }
209  }
210  }
211  else
212  {
214 
215  if (! error_state)
216  {
217 
218  if (nargout == 0 || nargout == 1)
219  {
220  FloatComplexSCHUR result (ctmp, ord, false);
221  retval(0) = mark_upper_triangular (result.schur_matrix ());
222  }
223  else
224  {
225  FloatComplexSCHUR result (ctmp, ord, true);
226  retval(1) = mark_upper_triangular (result.schur_matrix ());
227  retval(0) = result.unitary_matrix ();
228  }
229  }
230  }
231  }
232  else
233  {
234  if (! force_complex && arg.is_real_type ())
235  {
236  Matrix tmp = arg.matrix_value ();
237 
238  if (! error_state)
239  {
240  if (nargout == 0 || nargout == 1)
241  {
242  SCHUR result (tmp, ord, false);
243  retval(0) = result.schur_matrix ();
244  }
245  else
246  {
247  SCHUR result (tmp, ord, true);
248  retval(1) = result.schur_matrix ();
249  retval(0) = result.unitary_matrix ();
250  }
251  }
252  }
253  else
254  {
255  ComplexMatrix ctmp = arg.complex_matrix_value ();
256 
257  if (! error_state)
258  {
259 
260  if (nargout == 0 || nargout == 1)
261  {
262  ComplexSCHUR result (ctmp, ord, false);
263  retval(0) = mark_upper_triangular (result.schur_matrix ());
264  }
265  else
266  {
267  ComplexSCHUR result (ctmp, ord, true);
268  retval(1) = mark_upper_triangular (result.schur_matrix ());
269  retval(0) = result.unitary_matrix ();
270  }
271  }
272  }
273  }
274 
275  return retval;
276 }
277 
278 /*
279 %!test
280 %! a = [1, 2, 3; 4, 5, 9; 7, 8, 6];
281 %! [u, s] = schur (a);
282 %! assert (u' * a * u, s, sqrt (eps));
283 
284 %!test
285 %! a = single ([1, 2, 3; 4, 5, 9; 7, 8, 6]);
286 %! [u, s] = schur (a);
287 %! assert (u' * a * u, s, sqrt (eps ("single")));
288 
289 %!test
290 %! fail ("schur ([1, 2; 3, 4], 2)", "warning");
291 
292 %!error schur ()
293 %!error <argument must be a square matrix> schur ([1, 2, 3; 4, 5, 6])
294 */
295 
296 DEFUN (rsf2csf, args, nargout,
297  "-*- texinfo -*-\n\
298 @deftypefn {Function File} {[@var{U}, @var{T}] =} rsf2csf (@var{UR}, @var{TR})\n\
299 Convert a real, upper quasi-triangular Schur@tie{}form @var{TR} to a complex,\n\
300 upper triangular Schur@tie{}form @var{T}.\n\
301 \n\
302 Note that the following relations hold:\n\
303 \n\
304 @tex\n\
305 $UR \\cdot TR \\cdot {UR}^T = U T U^{\\dagger}$ and\n\
306 $U^{\\dagger} U$ is the identity matrix I.\n\
307 @end tex\n\
308 @ifnottex\n\
309 @tcode{@var{UR} * @var{TR} * @var{UR}' = @var{U} * @var{T} * @var{U}'} and\n\
310 @code{@var{U}' * @var{U}} is the identity matrix I.\n\
311 @end ifnottex\n\
312 \n\
313 Note also that @var{U} and @var{T} are not unique.\n\
314 @seealso{schur}\n\
315 @end deftypefn")
316 {
317  octave_value_list retval;
318 
319  if (args.length () == 2 && nargout <= 2)
320  {
321  if (! args(0).is_numeric_type ())
322  gripe_wrong_type_arg ("rsf2csf", args(0));
323  else if (! args(1).is_numeric_type ())
324  gripe_wrong_type_arg ("rsf2csf", args(1));
325  else if (args(0).is_complex_type () || args(1).is_complex_type ())
326  error ("rsf2csf: UR and TR must be real matrices");
327  else
328  {
329 
330  if (args(0).is_single_type () || args(1).is_single_type ())
331  {
332  FloatMatrix u = args(0).float_matrix_value ();
333  FloatMatrix t = args(1).float_matrix_value ();
334  if (! error_state)
335  {
336  FloatComplexSCHUR cs (FloatSCHUR (t, u));
337 
338  retval(1) = cs.schur_matrix ();
339  retval(0) = cs.unitary_matrix ();
340  }
341  }
342  else
343  {
344  Matrix u = args(0).matrix_value ();
345  Matrix t = args(1).matrix_value ();
346  if (! error_state)
347  {
348  ComplexSCHUR cs (SCHUR (t, u));
349 
350  retval(1) = cs.schur_matrix ();
351  retval(0) = cs.unitary_matrix ();
352  }
353  }
354  }
355  }
356  else
357  print_usage ();
358 
359  return retval;
360 }
361 
362 /*
363 %!test
364 %! A = [1, 1, 1, 2; 1, 2, 1, 1; 1, 1, 3, 1; -2, 1, 1, 1];
365 %! [u, t] = schur (A);
366 %! [U, T] = rsf2csf (u, t);
367 %! assert (norm (u * t * u' - U * T * U'), 0, 1e-12);
368 %! assert (norm (A - U * T * U'), 0, 1e-12);
369 
370 %!test
371 %! A = rand (10);
372 %! [u, t] = schur (A);
373 %! [U, T] = rsf2csf (u, t);
374 %! assert (norm (tril (T, -1)), 0);
375 %! assert (norm (U * U'), 1, 1e-14);
376 
377 %!test
378 %! A = [0, 1;-1, 0];
379 %! [u, t] = schur (A);
380 %! [U, T] = rsf2csf (u,t);
381 %! assert (U * T * U', A, 1e-14);
382 */