00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
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
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384