GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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)