GNU Octave  8.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-2023 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(
86  2).xoctave_idx_type_vector_value ("ordschur: SELECT must be an array of integers");
87 
88  const octave_idx_type sel_n = sel_arg.numel ();
89 
90  const dim_vector dimU = args(0).dims ();
91  const dim_vector dimS = args(1).dims ();
92 
93  if (sel_n != dimU(0))
94  error ("ordschur: SELECT must have same length as the sides of U and S");
95  else if (sel_n != dimU(0) || sel_n != dimS(0) || sel_n != dimU(1)
96  || sel_n != dimS(1))
97  error ("ordschur: U and S must be square and of equal sizes");
98 
99  octave_value_list retval;
100 
101  const bool double_type = args(0).is_double_type ()
102  || args(1).is_double_type ();
103  const bool complex_type = args(0).iscomplex ()
104  || args(1).iscomplex ();
105 
106 #define PREPARE_ARGS(TYPE, TYPE_M, TYPE_COND) \
107  TYPE ## Matrix U = args(0).x ## TYPE_M ## _value \
108  ("ordschur: U and S must be real or complex floating point matrices"); \
109  TYPE ## Matrix S = args(1).x ## TYPE_M ## _value \
110  ("ordschur: U and S must be real or complex floating point matrices"); \
111  TYPE ## Matrix w (dim_vector (n, 1)); \
112  TYPE ## Matrix work (dim_vector (n, 1)); \
113  F77_INT m; \
114  F77_INT info; \
115  TYPE_COND cond1, cond2;
116 
117 #define PREPARE_OUTPUT() \
118  if (info != 0) \
119  error ("ordschur: trsen failed"); \
120  \
121  retval = ovl (U, S);
122 
123  F77_INT n = to_f77_int (sel_n);
124  Array<F77_INT> sel (dim_vector (n, 1));
125  for (F77_INT i = 0; i < n; i++)
126  sel.xelem (i) = to_f77_int (sel_arg.xelem (i));
127 
128  if (double_type)
129  {
130  if (complex_type)
131  {
132  PREPARE_ARGS (Complex, complex_matrix, double)
133 
134  F77_XFCN (ztrsen, ztrsen,
135  (F77_CONST_CHAR_ARG ("N"), F77_CONST_CHAR_ARG ("V"),
136  sel.data (), n, F77_DBLE_CMPLX_ARG (S.fortran_vec ()), n,
137  F77_DBLE_CMPLX_ARG (U.fortran_vec ()), n,
138  F77_DBLE_CMPLX_ARG (w.fortran_vec ()), m, cond1, cond2,
139  F77_DBLE_CMPLX_ARG (work.fortran_vec ()), n,
140  info));
141 
143  }
144  else
145  {
146  PREPARE_ARGS (, matrix, double)
147  Matrix wi (dim_vector (n, 1));
148  Array<F77_INT> iwork (dim_vector (n, 1));
149 
150  F77_XFCN (dtrsen, dtrsen,
151  (F77_CONST_CHAR_ARG ("N"), F77_CONST_CHAR_ARG ("V"),
152  sel.data (), n, S.fortran_vec (), n, U.fortran_vec (), n,
153  w.fortran_vec (), wi.fortran_vec (), m, cond1, cond2,
154  work.fortran_vec (), n, iwork.fortran_vec (), n, info));
155 
156  PREPARE_OUTPUT ()
157  }
158  }
159  else
160  {
161  if (complex_type)
162  {
163  PREPARE_ARGS (FloatComplex, float_complex_matrix, float)
164 
165  F77_XFCN (ctrsen, ctrsen,
166  (F77_CONST_CHAR_ARG ("N"), F77_CONST_CHAR_ARG ("V"),
167  sel.data (), n, F77_CMPLX_ARG (S.fortran_vec ()), n,
168  F77_CMPLX_ARG (U.fortran_vec ()), n,
169  F77_CMPLX_ARG (w.fortran_vec ()), m, cond1, cond2,
170  F77_CMPLX_ARG (work.fortran_vec ()), n,
171  info));
172 
173  PREPARE_OUTPUT ()
174  }
175  else
176  {
177  PREPARE_ARGS (Float, float_matrix, float)
178  FloatMatrix wi (dim_vector (n, 1));
179  Array<F77_INT> iwork (dim_vector (n, 1));
180 
181  F77_XFCN (strsen, strsen,
182  (F77_CONST_CHAR_ARG ("N"), F77_CONST_CHAR_ARG ("V"),
183  sel.data (), n, S.fortran_vec (), n, U.fortran_vec (), n,
184  w.fortran_vec (), wi.fortran_vec (), m, cond1, cond2,
185  work.fortran_vec (), n, iwork.fortran_vec (), n, info));
186 
187  PREPARE_OUTPUT ()
188  }
189  }
190 
191 #undef PREPARE_ARGS
192 #undef PREPARE_OUTPUT
193 
194  return retval;
195 }
196 
197 /*
198 
199 %!test
200 %! A = [1, 2, 3, -2; 4, 5, 6, -5 ; 7, 8, 9, -5; 10, 11, 12, 4 ];
201 %! [U, T] = schur (A);
202 %! [US, TS] = ordschur (U, T, [ 0, 0, 1, 1 ]);
203 %! assert (US*TS*US', A, sqrt (eps));
204 %! assert (diag (T)(3:4), diag (TS)(1:2), sqrt (eps));
205 
206 %!test
207 %! A = [1, 2, 3, -2; 4, 5, 6, -5 ; 7, 8, 9, -5; 10, 11, 12, 4 ];
208 %! [U, T] = schur (A);
209 %! [US, TS] = ordschur (single (U), single (T), [ 0, 0, 1, 1 ]);
210 %! assert (US*TS*US', A, sqrt (eps ("single")));
211 %! assert (diag (T)(3:4), diag (TS)(1:2), sqrt (eps ("single")));
212 
213 %!test
214 %! A = [1, 2, 3, -2; 4, 5, 6, -5 ; 7, 8, 9, -5; 10, 11, 12, 4+3i ];
215 %! [U, T] = schur (A);
216 %! [US, TS] = ordschur (U, T, [ 0, 0, 1, 1 ]);
217 %! assert (US*TS*US', A, sqrt (eps));
218 %! assert (diag (T)(3:4), diag (TS)(1:2), sqrt (eps));
219 
220 %!test
221 %! A = [1, 2, 3, -2; 4, 5, 6, -5 ; 7, 8, 9, -5; 10, 11, 12, 4+3i ];
222 %! [U, T] = schur (A);
223 %! [US, TS] = ordschur (single (U), single (T), [ 0, 0, 1, 1 ]);
224 %! assert (US*TS*US', A, sqrt (eps ("single")));
225 %! assert (diag (T)(3:4), diag (TS)(1:2), sqrt (eps ("single")));
226 
227 */
228 
OCTAVE_END_NAMESPACE(octave)
OCTARRAY_OVERRIDABLE_FUNC_API const T * data(void) const
Size of the specified dimension.
Definition: Array.h:663
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:414
OCTARRAY_API T * fortran_vec(void)
Size of the specified dimension.
Definition: Array-base.cc:1766
OCTARRAY_OVERRIDABLE_FUNC_API T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:524
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
OCTINTERP_API 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:979
#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:773
octave_idx_type n
Definition: mx-inlines.cc:753
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)
static double wi[256]
Definition: randmtzig.cc:464