schur.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <string>
00028 
00029 #include "CmplxSCHUR.h"
00030 #include "dbleSCHUR.h"
00031 #include "fCmplxSCHUR.h"
00032 #include "floatSCHUR.h"
00033 
00034 #include "defun-dld.h"
00035 #include "error.h"
00036 #include "gripes.h"
00037 #include "oct-obj.h"
00038 #include "utils.h"
00039 
00040 template <class Matrix>
00041 static octave_value
00042 mark_upper_triangular (const Matrix& a)
00043 {
00044   octave_value retval = a;
00045 
00046   octave_idx_type n = a.rows ();
00047   assert (a.columns () == n);
00048 
00049   const typename Matrix::element_type zero = typename Matrix::element_type ();
00050 
00051   for (octave_idx_type i = 0; i < n; i++)
00052     if (a(i,i) == zero)
00053       return retval;
00054 
00055   retval.matrix_type (MatrixType::Upper);
00056 
00057   return retval;
00058 }
00059 
00060 DEFUN_DLD (schur, args, nargout,
00061   "-*- texinfo -*-\n\
00062 @deftypefn  {Loadable Function} {@var{S} =} schur (@var{A})\n\
00063 @deftypefnx {Loadable Function} {@var{S} =} schur (@var{A}, \"real\")\n\
00064 @deftypefnx {Loadable Function} {@var{S} =} schur (@var{A}, \"complex\")\n\
00065 @deftypefnx {Loadable Function} {@var{S} =} schur (@var{A}, @var{opt})\n\
00066 @deftypefnx {Loadable Function} {[@var{U}, @var{S}] =} schur (@var{A}, @dots{})\n\
00067 @cindex Schur decomposition\n\
00068 Compute the Schur@tie{}decomposition of @var{A}\n\
00069 @tex\n\
00070 $$\n\
00071  S = U^T A U\n\
00072 $$\n\
00073 @end tex\n\
00074 @ifnottex\n\
00075 \n\
00076 @example\n\
00077 @code{@var{S} = @var{U}' * @var{A} * @var{U}}\n\
00078 @end example\n\
00079 \n\
00080 @end ifnottex\n\
00081 where @var{U} is a unitary matrix\n\
00082 @tex\n\
00083 ($U^T U$ is identity)\n\
00084 @end tex\n\
00085 @ifnottex\n\
00086 (@code{@var{U}'* @var{U}} is identity)\n\
00087 @end ifnottex\n\
00088 and @var{S} is upper triangular.  The eigenvalues of @var{A} (and @var{S})\n\
00089 are the diagonal elements of @var{S}.  If the matrix @var{A}\n\
00090 is real, then the real Schur@tie{}decomposition is computed, in which the\n\
00091 matrix @var{U} is orthogonal and @var{S} is block upper triangular\n\
00092 with blocks of size at most\n\
00093 @tex\n\
00094 $2 \\times 2$\n\
00095 @end tex\n\
00096 @ifnottex\n\
00097 @code{2 x 2}\n\
00098 @end ifnottex\n\
00099 along the diagonal.  The diagonal elements of @var{S}\n\
00100 (or the eigenvalues of the\n\
00101 @tex\n\
00102 $2 \\times 2$\n\
00103 @end tex\n\
00104 @ifnottex\n\
00105 @code{2 x 2}\n\
00106 @end ifnottex\n\
00107 blocks, when appropriate) are the eigenvalues of @var{A} and @var{S}.\n\
00108 \n\
00109 The default for real matrices is a real Schur@tie{}decomposition.\n\
00110 A complex decomposition may be forced by passing the flag \"complex\".\n\
00111 \n\
00112 The eigenvalues are optionally ordered along the diagonal according to\n\
00113 the value of @var{opt}.  @code{@var{opt} = \"a\"} indicates that all\n\
00114 eigenvalues with negative real parts should be moved to the leading\n\
00115 block of @var{S}\n\
00116 (used in @code{are}), @code{@var{opt} = \"d\"} indicates that all eigenvalues\n\
00117 with magnitude less than one should be moved to the leading block of @var{S}\n\
00118 (used in @code{dare}), and @code{@var{opt} = \"u\"}, the default, indicates\n\
00119 that no ordering of eigenvalues should occur.  The leading @var{k}\n\
00120 columns of @var{U} always span the @var{A}-invariant\n\
00121 subspace corresponding to the @var{k} leading eigenvalues of @var{S}.\n\
00122 \n\
00123 The Schur@tie{}decomposition is used to compute eigenvalues of a\n\
00124 square matrix, and has applications in the solution of algebraic\n\
00125 Riccati equations in control (see @code{are} and @code{dare}).\n\
00126 @seealso{rsf2csf}\n\
00127 @end deftypefn")
00128 {
00129   octave_value_list retval;
00130 
00131   int nargin = args.length ();
00132 
00133   if (nargin < 1 || nargin > 2 || nargout > 2)
00134     {
00135       print_usage ();
00136       return retval;
00137     }
00138 
00139   octave_value arg = args(0);
00140 
00141   std::string ord;
00142 
00143   if (nargin == 2)
00144     {
00145       ord = args(1).string_value ();
00146 
00147       if (error_state)
00148         {
00149           error ("schur: second argument must be a string");
00150           return retval;
00151         }
00152     }
00153 
00154   bool force_complex = false;
00155 
00156   if (ord == "real")
00157     {
00158       ord = std::string ();
00159     }
00160   else if (ord == "complex")
00161     {
00162       force_complex = true;
00163       ord = std::string ();
00164     }
00165   else
00166     {
00167       char ord_char = ord.empty () ? 'U' : ord[0];
00168 
00169       if (ord_char != 'U' && ord_char != 'A' && ord_char != 'D'
00170           && ord_char != 'u' && ord_char != 'a' && ord_char != 'd')
00171         {
00172           warning ("schur: incorrect ordered schur argument '%c'",
00173                    ord.c_str ());
00174           return retval;
00175         }
00176     }
00177 
00178   octave_idx_type nr = arg.rows ();
00179   octave_idx_type nc = arg.columns ();
00180 
00181   if (nr != nc)
00182     {
00183       gripe_square_matrix_required ("schur");
00184       return retval;
00185     }
00186 
00187   if (! arg.is_numeric_type ())
00188     gripe_wrong_type_arg ("schur", arg);
00189   else if (arg.is_single_type ())
00190     {
00191       if (! force_complex && arg.is_real_type ())
00192         {
00193           FloatMatrix tmp = arg.float_matrix_value ();
00194 
00195           if (! error_state)
00196             {
00197               if (nargout == 0 || nargout == 1)
00198                 {
00199                   FloatSCHUR result (tmp, ord, false);
00200                   retval(0) = result.schur_matrix ();
00201                 }
00202               else
00203                 {
00204                   FloatSCHUR result (tmp, ord, true);
00205                   retval(1) = result.schur_matrix ();
00206                   retval(0) = result.unitary_matrix ();
00207                 }
00208             }
00209         }
00210       else
00211         {
00212           FloatComplexMatrix ctmp = arg.float_complex_matrix_value ();
00213 
00214           if (! error_state)
00215             {
00216 
00217               if (nargout == 0 || nargout == 1)
00218                 {
00219                   FloatComplexSCHUR result (ctmp, ord, false);
00220                   retval(0) = mark_upper_triangular (result.schur_matrix ());
00221                 }
00222               else
00223                 {
00224                   FloatComplexSCHUR result (ctmp, ord, true);
00225                   retval(1) = mark_upper_triangular (result.schur_matrix ());
00226                   retval(0) = result.unitary_matrix ();
00227                 }
00228             }
00229         }
00230     }
00231   else
00232     {
00233       if (! force_complex && arg.is_real_type ())
00234         {
00235           Matrix tmp = arg.matrix_value ();
00236 
00237           if (! error_state)
00238             {
00239               if (nargout == 0 || nargout == 1)
00240                 {
00241                   SCHUR result (tmp, ord, false);
00242                   retval(0) = result.schur_matrix ();
00243                 }
00244               else
00245                 {
00246                   SCHUR result (tmp, ord, true);
00247                   retval(1) = result.schur_matrix ();
00248                   retval(0) = result.unitary_matrix ();
00249                 }
00250             }
00251         }
00252       else
00253         {
00254           ComplexMatrix ctmp = arg.complex_matrix_value ();
00255 
00256           if (! error_state)
00257             {
00258 
00259               if (nargout == 0 || nargout == 1)
00260                 {
00261                   ComplexSCHUR result (ctmp, ord, false);
00262                   retval(0) = mark_upper_triangular (result.schur_matrix ());
00263                 }
00264               else
00265                 {
00266                   ComplexSCHUR result (ctmp, ord, true);
00267                   retval(1) = mark_upper_triangular (result.schur_matrix ());
00268                   retval(0) = result.unitary_matrix ();
00269                 }
00270             }
00271         }
00272     }
00273 
00274   return retval;
00275 }
00276 
00277 /*
00278 
00279 %!test
00280 %! a = [1, 2, 3; 4, 5, 9; 7, 8, 6];
00281 %! [u, s] = schur (a);
00282 %! assert(u' * a * u, s, sqrt (eps));
00283 
00284 %!test
00285 %! a = single([1, 2, 3; 4, 5, 9; 7, 8, 6]);
00286 %! [u, s] = schur (a);
00287 %! assert(u' * a * u, s, sqrt (eps('single')));
00288 
00289 %!test
00290 %! fail("schur ([1, 2; 3, 4], 2)","warning");
00291 
00292 %!error <Invalid call to schur> schur ();
00293 %!error schur ([1, 2, 3; 4, 5, 6]);
00294 
00295 */
00296 
00297 DEFUN_DLD (rsf2csf, args, nargout,
00298   "-*- texinfo -*-\n\
00299 @deftypefn {Function File} {[@var{U}, @var{T}] =} rsf2csf (@var{UR}, @var{TR})\n\
00300 Convert a real, upper quasi-triangular Schur@tie{}form @var{TR} to a complex,\n\
00301 upper triangular Schur@tie{}form @var{T}.\n\
00302 \n\
00303 Note that the following relations hold:\n\
00304 \n\
00305 @tex\n\
00306 $UR \\cdot TR \\cdot {UR}^T = U T U^{\\dagger}$ and\n\
00307 $U^{\\dagger} U$ is the identity matrix I.\n\
00308 @end tex\n\
00309 @ifnottex\n\
00310 @xcode{@var{UR} * @var{TR} * @var{UR}' = @var{U} * @var{T} * @var{U}'} and\n\
00311 @code{@var{U}' * @var{U}} is the identity matrix I.\n\
00312 @end ifnottex\n\
00313 \n\
00314 Note also that @var{U} and @var{T} are not unique.\n\
00315 @seealso{schur}\n\
00316 @end deftypefn")
00317 {
00318   octave_value_list retval;
00319 
00320   if (args.length () == 2 && nargout <= 2)
00321     {
00322       if (! args(0).is_numeric_type ())
00323         gripe_wrong_type_arg ("rsf2csf", args(0));
00324       else if (! args(1).is_numeric_type ())
00325         gripe_wrong_type_arg ("rsf2csf", args(1));
00326       else if (args(0).is_complex_type () || args(1).is_complex_type ())
00327         error ("rsf2csf: UR and TR must be real matrices");
00328       else
00329         {
00330 
00331           if (args(0).is_single_type () || args(1).is_single_type ())
00332             {
00333               FloatMatrix u = args(0).float_matrix_value ();
00334               FloatMatrix t = args(1).float_matrix_value ();
00335               if (! error_state)
00336                 {
00337                   FloatComplexSCHUR cs (FloatSCHUR (t, u));
00338 
00339                   retval(1) = cs.schur_matrix ();
00340                   retval(0) = cs.unitary_matrix ();
00341                 }
00342             }
00343           else
00344             {
00345               Matrix u = args(0).matrix_value ();
00346               Matrix t = args(1).matrix_value ();
00347               if (! error_state)
00348                 {
00349                   ComplexSCHUR cs (SCHUR (t, u));
00350 
00351                   retval(1) = cs.schur_matrix ();
00352                   retval(0) = cs.unitary_matrix ();
00353                 }
00354             }
00355         }
00356     }
00357   else
00358     print_usage ();
00359 
00360   return retval;
00361 }
00362 
00363 /*
00364 
00365 %!test
00366 %! A = [1, 1, 1, 2; 1, 2, 1, 1; 1, 1, 3, 1; -2, 1, 1, 1];
00367 %! [u, t] = schur (A);
00368 %! [U, T] = rsf2csf (u, t);
00369 %! assert (norm (u * t * u' - U * T * U'), 0, 1e-12)
00370 %! assert (norm (A - U * T * U'), 0, 1e-12)
00371 
00372 %!test
00373 %! A = rand (10);
00374 %! [u, t] = schur (A);
00375 %! [U, T] = rsf2csf (u, t);
00376 %! assert (norm (tril (T, -1)), 0)
00377 %! assert (norm (U * U'), 1, 1e-14)
00378 
00379 %!test
00380 %! A = [0, 1;-1, 0];
00381 %! [u, t] = schur (A);
00382 %! [U, T] = rsf2csf (u,t);
00383 %! assert (U * T * U', A, 1e-14)
00384 */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines