GNU Octave  9.1.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-2024 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 
36 
37 DEFUN (ordschur, args, ,
38  doc: /* -*- texinfo -*-
39 @deftypefn {} {[@var{UR}, @var{SR}] =} ordschur (@var{U}, @var{S}, @var{select})
40 Reorder the real Schur factorization (@var{U},@var{S}) obtained with the
41 @code{schur} function, so that selected eigenvalues appear in the upper left
42 diagonal blocks of the quasi triangular Schur matrix.
43 
44 The logical vector @var{select} specifies the selected eigenvalues as they
45 appear along @var{S}'s diagonal.
46 
47 For example, given the matrix @code{@var{A} = [1, 2; 3, 4]}, and its Schur
48 decomposition
49 
50 @example
51 [@var{U}, @var{S}] = schur (@var{A})
52 @end example
53 
54 @noindent
55 which returns
56 
57 @example
58 @group
59 @var{U} =
60 
61  -0.82456 -0.56577
62  0.56577 -0.82456
63 
64 @var{S} =
65 
66  -0.37228 -1.00000
67  0.00000 5.37228
68 
69 @end group
70 @end example
71 
72 It is possible to reorder the decomposition so that the positive eigenvalue
73 is in the upper left corner, by doing:
74 
75 @example
76 [@var{U}, @var{S}] = ordschur (@var{U}, @var{S}, [0,1])
77 @end example
78 
79 @seealso{schur, ordeig, ordqz}
80 @end deftypefn */)
81 {
82  if (args.length () != 3)
83  print_usage ();
84 
85  const Array<octave_idx_type> sel_arg = args(2).xoctave_idx_type_vector_value ("ordschur: SELECT must be an array of integers");
86 
87  const octave_idx_type sel_n = sel_arg.numel ();
88 
89  const dim_vector dimU = args(0).dims ();
90  const dim_vector dimS = args(1).dims ();
91 
92  if (sel_n != dimU(0))
93  error ("ordschur: SELECT must have same length as the sides of U and S");
94  else if (sel_n != dimU(0) || sel_n != dimS(0) || sel_n != dimU(1)
95  || sel_n != dimS(1))
96  error ("ordschur: U and S must be square and of equal sizes");
97 
98  octave_value_list retval;
99 
100  const bool double_type = args(0).is_double_type () || args(1).is_double_type ();
101  const bool complex_type = args(0).iscomplex () || 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 = 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) = 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 */
225 
226 OCTAVE_END_NAMESPACE(octave)
T * fortran_vec()
Size of the specified dimension.
Definition: Array-base.cc:1764
const T * data() const
Size of the specified dimension.
Definition: Array.h:663
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:524
octave_idx_type numel() const
Number of elements in the array.
Definition: Array.h:414
Definition: dMatrix.h:42
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage(void)
Definition: defun-int.h:72
#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:988
#define F77_DBLE_CMPLX_ARG(x)
Definition: f77-fcn.h:316
#define F77_CMPLX_ARG(x)
Definition: f77-fcn.h:310
#define F77_XFCN(f, F, args)
Definition: f77-fcn.h:45
octave_f77_int_type F77_INT
Definition: f77-fcn.h:306
T octave_idx_type m
Definition: mx-inlines.cc:781
octave_idx_type n
Definition: mx-inlines.cc:761
std::complex< double > w(std::complex< double > z, double relerr=0)
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)