GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ordschur.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2016-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include "defun.h"
31 #include "error.h"
32 #include "lo-lapack-proto.h"
33 #include "ovl.h"
34 
35 DEFUN (ordschur, args, ,
36  doc: /* -*- texinfo -*-
37 @deftypefn {} {[@var{UR}, @var{SR}] =} ordschur (@var{U}, @var{S}, @var{select})
38 Reorders the real Schur factorization (@var{U},@var{S}) obtained with the
39 @code{schur} function, so that selected eigenvalues appear in the upper left
40 diagonal blocks of the quasi triangular Schur matrix.
41 
42 The logical vector @var{select} specifies the selected eigenvalues as they
43 appear along @var{S}'s diagonal.
44 
45 For example, given the matrix @code{@var{A} = [1, 2; 3, 4]}, and its Schur
46 decomposition
47 
48 @example
49 [@var{U}, @var{S}] = schur (@var{A})
50 @end example
51 
52 @noindent
53 which returns
54 
55 @example
56 @group
57 @var{U} =
58 
59  -0.82456 -0.56577
60  0.56577 -0.82456
61 
62 @var{S} =
63 
64  -0.37228 -1.00000
65  0.00000 5.37228
66 
67 @end group
68 @end example
69 
70 It is possible to reorder the decomposition so that the positive eigenvalue
71 is in the upper left corner, by doing:
72 
73 @example
74 [@var{U}, @var{S}] = ordschur (@var{U}, @var{S}, [0,1])
75 @end example
76 
77 @seealso{schur, ordeig}
78 @end deftypefn */)
79 {
80  if (args.length () != 3)
81  print_usage ();
82 
83  const Array<octave_idx_type> sel_arg = args(2).xoctave_idx_type_vector_value ("ordschur: SELECT must be an array of integers");
84 
85  const octave_idx_type sel_n = sel_arg.numel ();
86 
87  const dim_vector dimU = args(0).dims ();
88  const dim_vector dimS = args(1).dims ();
89 
90  if (sel_n != dimU(0))
91  error ("ordschur: SELECT must have same length as the sides of U and S");
92  else if (sel_n != dimU(0) || sel_n != dimS(0) || sel_n != dimU(1)
93  || sel_n != dimS(1))
94  error ("ordschur: U and S must be square and of equal sizes");
95 
97 
98  const bool double_type = args(0).is_double_type ()
99  || args(1).is_double_type ();
100  const bool complex_type = args(0).iscomplex ()
101  || args(1).iscomplex ();
102 
103 #define PREPARE_ARGS(TYPE, TYPE_M, TYPE_COND) \
104  TYPE ## Matrix U = args(0).x ## TYPE_M ## _value \
105  ("ordschur: U and S must be real or complex floating point matrices"); \
106  TYPE ## Matrix S = args(1).x ## TYPE_M ## _value \
107  ("ordschur: U and S must be real or complex floating point matrices"); \
108  TYPE ## Matrix w (dim_vector (n, 1)); \
109  TYPE ## Matrix work (dim_vector (n, 1)); \
110  F77_INT m; \
111  F77_INT info; \
112  TYPE_COND cond1, cond2;
113 
114 #define PREPARE_OUTPUT() \
115  if (info != 0) \
116  error ("ordschur: trsen failed"); \
117  \
118  retval = ovl (U, S);
119 
120  F77_INT n = octave::to_f77_int (sel_n);
121  Array<F77_INT> sel (dim_vector (n, 1));
122  for (F77_INT i = 0; i < n; i++)
123  sel.xelem (i) = octave::to_f77_int (sel_arg.xelem (i));
124 
125  if (double_type)
126  {
127  if (complex_type)
128  {
129  PREPARE_ARGS (Complex, complex_matrix, double)
130 
131  F77_XFCN (ztrsen, ztrsen,
132  (F77_CONST_CHAR_ARG ("N"), F77_CONST_CHAR_ARG ("V"),
133  sel.data (), n, F77_DBLE_CMPLX_ARG (S.fortran_vec ()), n,
134  F77_DBLE_CMPLX_ARG (U.fortran_vec ()), n,
135  F77_DBLE_CMPLX_ARG (w.fortran_vec ()), m, cond1, cond2,
136  F77_DBLE_CMPLX_ARG (work.fortran_vec ()), n,
137  info));
138 
140  }
141  else
142  {
143  PREPARE_ARGS (, matrix, double)
144  Matrix wi (dim_vector (n, 1));
145  Array<F77_INT> iwork (dim_vector (n, 1));
146 
147  F77_XFCN (dtrsen, dtrsen,
148  (F77_CONST_CHAR_ARG ("N"), F77_CONST_CHAR_ARG ("V"),
149  sel.data (), n, S.fortran_vec (), n, U.fortran_vec (), n,
150  w.fortran_vec (), wi.fortran_vec (), m, cond1, cond2,
151  work.fortran_vec (), n, iwork.fortran_vec (), n, info));
152 
153  PREPARE_OUTPUT ()
154  }
155  }
156  else
157  {
158  if (complex_type)
159  {
160  PREPARE_ARGS (FloatComplex, float_complex_matrix, float)
161 
162  F77_XFCN (ctrsen, ctrsen,
163  (F77_CONST_CHAR_ARG ("N"), F77_CONST_CHAR_ARG ("V"),
164  sel.data (), n, F77_CMPLX_ARG (S.fortran_vec ()), n,
165  F77_CMPLX_ARG (U.fortran_vec ()), n,
166  F77_CMPLX_ARG (w.fortran_vec ()), m, cond1, cond2,
167  F77_CMPLX_ARG (work.fortran_vec ()), n,
168  info));
169 
170  PREPARE_OUTPUT ()
171  }
172  else
173  {
174  PREPARE_ARGS (Float, float_matrix, float)
175  FloatMatrix wi (dim_vector (n, 1));
176  Array<F77_INT> iwork (dim_vector (n, 1));
177 
178  F77_XFCN (strsen, strsen,
179  (F77_CONST_CHAR_ARG ("N"), F77_CONST_CHAR_ARG ("V"),
180  sel.data (), n, S.fortran_vec (), n, U.fortran_vec (), n,
181  w.fortran_vec (), wi.fortran_vec (), m, cond1, cond2,
182  work.fortran_vec (), n, iwork.fortran_vec (), n, info));
183 
184  PREPARE_OUTPUT ()
185  }
186  }
187 
188 #undef PREPARE_ARGS
189 #undef PREPARE_OUTPUT
190 
191  return retval;
192 }
193 
194 /*
195 
196 %!test
197 %! A = [1, 2, 3, -2; 4, 5, 6, -5 ; 7, 8, 9, -5; 10, 11, 12, 4 ];
198 %! [U, T] = schur (A);
199 %! [US, TS] = ordschur (U, T, [ 0, 0, 1, 1 ]);
200 %! assert (US*TS*US', A, sqrt (eps));
201 %! assert (diag (T)(3:4), diag (TS)(1:2), sqrt (eps));
202 
203 %!test
204 %! A = [1, 2, 3, -2; 4, 5, 6, -5 ; 7, 8, 9, -5; 10, 11, 12, 4 ];
205 %! [U, T] = schur (A);
206 %! [US, TS] = ordschur (single (U), single (T), [ 0, 0, 1, 1 ]);
207 %! assert (US*TS*US', A, sqrt (eps ("single")));
208 %! assert (diag (T)(3:4), diag (TS)(1:2), sqrt (eps ("single")));
209 
210 %!test
211 %! A = [1, 2, 3, -2; 4, 5, 6, -5 ; 7, 8, 9, -5; 10, 11, 12, 4+3i ];
212 %! [U, T] = schur (A);
213 %! [US, TS] = ordschur (U, T, [ 0, 0, 1, 1 ]);
214 %! assert (US*TS*US', A, sqrt (eps));
215 %! assert (diag (T)(3:4), diag (TS)(1:2), sqrt (eps));
216 
217 %!test
218 %! A = [1, 2, 3, -2; 4, 5, 6, -5 ; 7, 8, 9, -5; 10, 11, 12, 4+3i ];
219 %! [U, T] = schur (A);
220 %! [US, TS] = ordschur (single (U), single (T), [ 0, 0, 1, 1 ]);
221 %! assert (US*TS*US', A, sqrt (eps ("single")));
222 %! assert (diag (T)(3:4), diag (TS)(1:2), sqrt (eps ("single")));
223 
224 */
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:469
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
const T * data(void) const
Size of the specified dimension.
Definition: Array.h:581
const T * fortran_vec(void) const
Size of the specified dimension.
Definition: Array.h:583
Definition: dMatrix.h:42
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
OCTINTERP_API void print_usage(void)
Definition: defun.cc:53
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void error(const char *fmt,...)
Definition: error.cc:968
#define F77_DBLE_CMPLX_ARG(x)
Definition: f77-fcn.h:315
#define F77_CMPLX_ARG(x)
Definition: f77-fcn.h:309
#define F77_XFCN(f, F, args)
Definition: f77-fcn.h:44
octave_f77_int_type F77_INT
Definition: f77-fcn.h:305
T octave_idx_type m
Definition: mx-inlines.cc:773
octave_idx_type n
Definition: mx-inlines.cc:753
std::complex< double > w(std::complex< double > z, double relerr=0)
static double wi[256]
Definition: randmtzig.cc:447
std::complex< double > Complex
Definition: oct-cmplx.h:33
std::complex< float > FloatComplex
Definition: oct-cmplx.h:34
#define PREPARE_OUTPUT()
#define PREPARE_ARGS(TYPE, TYPE_M, TYPE_COND)
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811