GNU Octave  8.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 Properties Friends Macros Pages
schur.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1994-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 "Array.h"
31 #include "CMatrix.h"
32 #include "dMatrix.h"
33 #include "fCMatrix.h"
34 #include "fMatrix.h"
35 #include "lo-error.h"
36 #include "lo-lapack-proto.h"
37 #include "oct-locbuf.h"
38 #include "schur.h"
39 
41 
43 
44 // For real types.
45 
46 static F77_INT
47 select_ana (const double& a, const double&)
48 {
49  return (a < 0.0);
50 }
51 
52 static F77_INT
53 select_dig (const double& a, const double& b)
54 {
55  return (hypot (a, b) < 1.0);
56 }
57 
58 static F77_INT
59 select_ana (const float& a, const float&)
60 {
61  return (a < 0.0);
62 }
63 
64 static F77_INT
65 select_dig (const float& a, const float& b)
66 {
67  return (hypot (a, b) < 1.0);
68 }
69 
70 // For complex types.
71 
72 static F77_INT
73 select_ana (const F77_DBLE_CMPLX& a_arg)
74 {
75  const Complex a = reinterpret_cast<const Complex&> (a_arg);
76  return a.real () < 0.0;
77 }
78 
79 static F77_INT
80 select_dig (const F77_DBLE_CMPLX& a_arg)
81 {
82  const Complex& a = reinterpret_cast<const Complex&> (a_arg);
83  return (abs (a) < 1.0);
84 }
85 
86 static F77_INT
87 select_ana (const F77_CMPLX& a_arg)
88 {
89  const FloatComplex& a = reinterpret_cast<const FloatComplex&> (a_arg);
90  return a.real () < 0.0;
91 }
92 
93 static F77_INT
94 select_dig (const F77_CMPLX& a_arg)
95 {
96  const FloatComplex& a = reinterpret_cast<const FloatComplex&> (a_arg);
97  return (abs (a) < 1.0);
98 }
99 
100 template <>
102 schur<Matrix>::init (const Matrix& a, const std::string& ord,
103  bool calc_unitary)
104 {
105  F77_INT a_nr = to_f77_int (a.rows ());
106  F77_INT a_nc = to_f77_int (a.cols ());
107 
108  if (a_nr != a_nc)
109  (*current_liboctave_error_handler) ("schur: requires square matrix");
110 
111  if (a_nr == 0)
112  {
113  m_schur_mat.clear ();
114  m_unitary_schur_mat.clear ();
115  return 0;
116  }
117 
118  // Workspace requirements may need to be fixed if any of the
119  // following change.
120 
121  char jobvs;
122  char sense = 'N';
123  char sort = 'N';
124 
125  if (calc_unitary)
126  jobvs = 'V';
127  else
128  jobvs = 'N';
129 
130  char ord_char = (ord.empty () ? 'U' : ord[0]);
131 
132  if (ord_char == 'A' || ord_char == 'D'
133  || ord_char == 'a' || ord_char == 'd')
134  sort = 'S';
135 
136  volatile double_selector selector = nullptr;
137  if (ord_char == 'A' || ord_char == 'a')
138  selector = select_ana;
139  else if (ord_char == 'D' || ord_char == 'd')
140  selector = select_dig;
141 
142  F77_INT n = a_nc;
143  F77_INT lwork = 8 * n;
144  F77_INT liwork = 1;
145  F77_INT info;
146  F77_INT sdim;
147  double rconde;
148  double rcondv;
149 
150  m_schur_mat = a;
151 
152  if (calc_unitary)
153  m_unitary_schur_mat.clear (n, n);
154 
155  double *s = m_schur_mat.fortran_vec ();
156  double *q = m_unitary_schur_mat.fortran_vec ();
157 
158  Array<double> wr (dim_vector (n, 1));
159  double *pwr = wr.fortran_vec ();
160 
161  Array<double> wi (dim_vector (n, 1));
162  double *pwi = wi.fortran_vec ();
163 
164  Array<double> work (dim_vector (lwork, 1));
165  double *pwork = work.fortran_vec ();
166 
167  // BWORK is not referenced for the non-ordered Schur routine.
168  F77_INT ntmp = (ord_char == 'N' || ord_char == 'n') ? 0 : n;
169  Array<F77_INT> bwork (dim_vector (ntmp, 1));
170  F77_INT *pbwork = bwork.fortran_vec ();
171 
172  Array<F77_INT> iwork (dim_vector (liwork, 1));
173  F77_INT *piwork = iwork.fortran_vec ();
174 
175  F77_XFCN (dgeesx, DGEESX, (F77_CONST_CHAR_ARG2 (&jobvs, 1),
176  F77_CONST_CHAR_ARG2 (&sort, 1),
177  selector,
178  F77_CONST_CHAR_ARG2 (&sense, 1),
179  n, s, n, sdim, pwr, pwi, q, n, rconde, rcondv,
180  pwork, lwork, piwork, liwork, pbwork, info
181  F77_CHAR_ARG_LEN (1)
182  F77_CHAR_ARG_LEN (1)
183  F77_CHAR_ARG_LEN (1)));
184 
185  return info;
186 }
187 
188 template <>
190 schur<FloatMatrix>::init (const FloatMatrix& a, const std::string& ord,
191  bool calc_unitary)
192 {
193  F77_INT a_nr = to_f77_int (a.rows ());
194  F77_INT a_nc = to_f77_int (a.cols ());
195 
196  if (a_nr != a_nc)
197  (*current_liboctave_error_handler) ("SCHUR requires square matrix");
198 
199  if (a_nr == 0)
200  {
201  m_schur_mat.clear ();
202  m_unitary_schur_mat.clear ();
203  return 0;
204  }
205 
206  // Workspace requirements may need to be fixed if any of the
207  // following change.
208 
209  char jobvs;
210  char sense = 'N';
211  char sort = 'N';
212 
213  if (calc_unitary)
214  jobvs = 'V';
215  else
216  jobvs = 'N';
217 
218  char ord_char = (ord.empty () ? 'U' : ord[0]);
219 
220  if (ord_char == 'A' || ord_char == 'D'
221  || ord_char == 'a' || ord_char == 'd')
222  sort = 'S';
223 
224  volatile float_selector selector = nullptr;
225  if (ord_char == 'A' || ord_char == 'a')
226  selector = select_ana;
227  else if (ord_char == 'D' || ord_char == 'd')
228  selector = select_dig;
229 
230  F77_INT n = a_nc;
231  F77_INT lwork = 8 * n;
232  F77_INT liwork = 1;
233  F77_INT info;
234  F77_INT sdim;
235  float rconde;
236  float rcondv;
237 
238  m_schur_mat = a;
239 
240  if (calc_unitary)
241  m_unitary_schur_mat.clear (n, n);
242 
243  float *s = m_schur_mat.fortran_vec ();
244  float *q = m_unitary_schur_mat.fortran_vec ();
245 
246  Array<float> wr (dim_vector (n, 1));
247  float *pwr = wr.fortran_vec ();
248 
249  Array<float> wi (dim_vector (n, 1));
250  float *pwi = wi.fortran_vec ();
251 
252  Array<float> work (dim_vector (lwork, 1));
253  float *pwork = work.fortran_vec ();
254 
255  // BWORK is not referenced for the non-ordered Schur routine.
256  F77_INT ntmp = (ord_char == 'N' || ord_char == 'n') ? 0 : n;
257  Array<F77_INT> bwork (dim_vector (ntmp, 1));
258  F77_INT *pbwork = bwork.fortran_vec ();
259 
260  Array<F77_INT> iwork (dim_vector (liwork, 1));
261  F77_INT *piwork = iwork.fortran_vec ();
262 
263  F77_XFCN (sgeesx, SGEESX, (F77_CONST_CHAR_ARG2 (&jobvs, 1),
264  F77_CONST_CHAR_ARG2 (&sort, 1),
265  selector,
266  F77_CONST_CHAR_ARG2 (&sense, 1),
267  n, s, n, sdim, pwr, pwi, q, n, rconde, rcondv,
268  pwork, lwork, piwork, liwork, pbwork, info
269  F77_CHAR_ARG_LEN (1)
270  F77_CHAR_ARG_LEN (1)
271  F77_CHAR_ARG_LEN (1)));
272 
273  return info;
274 }
275 
276 template <>
278 schur<ComplexMatrix>::init (const ComplexMatrix& a, const std::string& ord,
279  bool calc_unitary)
280 {
281  F77_INT a_nr = to_f77_int (a.rows ());
282  F77_INT a_nc = to_f77_int (a.cols ());
283 
284  if (a_nr != a_nc)
285  (*current_liboctave_error_handler) ("SCHUR requires square matrix");
286 
287  if (a_nr == 0)
288  {
289  m_schur_mat.clear ();
290  m_unitary_schur_mat.clear ();
291  return 0;
292  }
293 
294  // Workspace requirements may need to be fixed if any of the
295  // following change.
296 
297  char jobvs;
298  char sense = 'N';
299  char sort = 'N';
300 
301  if (calc_unitary)
302  jobvs = 'V';
303  else
304  jobvs = 'N';
305 
306  char ord_char = (ord.empty () ? 'U' : ord[0]);
307 
308  if (ord_char == 'A' || ord_char == 'D'
309  || ord_char == 'a' || ord_char == 'd')
310  sort = 'S';
311 
312  volatile complex_selector selector = nullptr;
313  if (ord_char == 'A' || ord_char == 'a')
314  selector = select_ana;
315  else if (ord_char == 'D' || ord_char == 'd')
316  selector = select_dig;
317 
318  F77_INT n = a_nc;
319  F77_INT lwork = 8 * n;
320  F77_INT info;
321  F77_INT sdim;
322  double rconde;
323  double rcondv;
324 
325  m_schur_mat = a;
326  if (calc_unitary)
327  m_unitary_schur_mat.clear (n, n);
328 
329  Complex *s = m_schur_mat.fortran_vec ();
330  Complex *q = m_unitary_schur_mat.fortran_vec ();
331 
332  Array<double> rwork (dim_vector (n, 1));
333  double *prwork = rwork.fortran_vec ();
334 
335  Array<Complex> w (dim_vector (n, 1));
336  Complex *pw = w.fortran_vec ();
337 
338  Array<Complex> work (dim_vector (lwork, 1));
339  Complex *pwork = work.fortran_vec ();
340 
341  // BWORK is not referenced for non-ordered Schur.
342  F77_INT ntmp = (ord_char == 'N' || ord_char == 'n') ? 0 : n;
343  Array<F77_INT> bwork (dim_vector (ntmp, 1));
344  F77_INT *pbwork = bwork.fortran_vec ();
345 
346  F77_XFCN (zgeesx, ZGEESX,
347  (F77_CONST_CHAR_ARG2 (&jobvs, 1),
348  F77_CONST_CHAR_ARG2 (&sort, 1),
349  selector,
350  F77_CONST_CHAR_ARG2 (&sense, 1),
351  n, F77_DBLE_CMPLX_ARG (s), n, sdim, F77_DBLE_CMPLX_ARG (pw),
352  F77_DBLE_CMPLX_ARG (q), n, rconde, rcondv,
353  F77_DBLE_CMPLX_ARG (pwork), lwork, prwork, pbwork, info
354  F77_CHAR_ARG_LEN (1)
355  F77_CHAR_ARG_LEN (1)
356  F77_CHAR_ARG_LEN (1)));
357 
358  return info;
359 }
360 
361 template <>
363 rsf2csf<ComplexMatrix, Matrix> (const Matrix& s_arg, const Matrix& u_arg)
364 {
365  ComplexMatrix s (s_arg);
366  ComplexMatrix u (u_arg);
367 
368  F77_INT n = to_f77_int (s.rows ());
369 
370  if (s.columns () != n || u.rows () != n || u.columns () != n)
371  (*current_liboctave_error_handler)
372  ("rsf2csf: inconsistent matrix dimensions");
373 
374  if (n > 0)
375  {
376  OCTAVE_LOCAL_BUFFER (double, c, n-1);
377  OCTAVE_LOCAL_BUFFER (double, sx, n-1);
378 
379  F77_XFCN (zrsf2csf, ZRSF2CSF,
381  F77_DBLE_CMPLX_ARG (u.fortran_vec ()), c, sx));
382  }
383 
384  return schur<ComplexMatrix> (s, u);
385 }
386 
387 template <>
390  const std::string& ord, bool calc_unitary)
391 {
392  F77_INT a_nr = to_f77_int (a.rows ());
393  F77_INT a_nc = to_f77_int (a.cols ());
394 
395  if (a_nr != a_nc)
396  (*current_liboctave_error_handler) ("SCHUR requires square matrix");
397 
398  if (a_nr == 0)
399  {
400  m_schur_mat.clear ();
401  m_unitary_schur_mat.clear ();
402  return 0;
403  }
404 
405  // Workspace requirements may need to be fixed if any of the
406  // following change.
407 
408  char jobvs;
409  char sense = 'N';
410  char sort = 'N';
411 
412  if (calc_unitary)
413  jobvs = 'V';
414  else
415  jobvs = 'N';
416 
417  char ord_char = (ord.empty () ? 'U' : ord[0]);
418 
419  if (ord_char == 'A' || ord_char == 'D'
420  || ord_char == 'a' || ord_char == 'd')
421  sort = 'S';
422 
423  volatile float_complex_selector selector = nullptr;
424  if (ord_char == 'A' || ord_char == 'a')
425  selector = select_ana;
426  else if (ord_char == 'D' || ord_char == 'd')
427  selector = select_dig;
428 
429  F77_INT n = a_nc;
430  F77_INT lwork = 8 * n;
431  F77_INT info;
432  F77_INT sdim;
433  float rconde;
434  float rcondv;
435 
436  m_schur_mat = a;
437  if (calc_unitary)
438  m_unitary_schur_mat.clear (n, n);
439 
440  FloatComplex *s = m_schur_mat.fortran_vec ();
441  FloatComplex *q = m_unitary_schur_mat.fortran_vec ();
442 
443  Array<float> rwork (dim_vector (n, 1));
444  float *prwork = rwork.fortran_vec ();
445 
447  FloatComplex *pw = w.fortran_vec ();
448 
449  Array<FloatComplex> work (dim_vector (lwork, 1));
450  FloatComplex *pwork = work.fortran_vec ();
451 
452  // BWORK is not referenced for non-ordered Schur.
453  F77_INT ntmp = (ord_char == 'N' || ord_char == 'n') ? 0 : n;
454  Array<F77_INT> bwork (dim_vector (ntmp, 1));
455  F77_INT *pbwork = bwork.fortran_vec ();
456 
457  F77_XFCN (cgeesx, CGEESX,
458  (F77_CONST_CHAR_ARG2 (&jobvs, 1),
459  F77_CONST_CHAR_ARG2 (&sort, 1),
460  selector,
461  F77_CONST_CHAR_ARG2 (&sense, 1),
462  n, F77_CMPLX_ARG (s), n, sdim, F77_CMPLX_ARG (pw),
463  F77_CMPLX_ARG (q), n,
464  rconde, rcondv,
465  F77_CMPLX_ARG (pwork), lwork, prwork, pbwork, info
466  F77_CHAR_ARG_LEN (1)
467  F77_CHAR_ARG_LEN (1)
468  F77_CHAR_ARG_LEN (1)));
469 
470  return info;
471 }
472 
473 template <>
476  const FloatMatrix& u_arg)
477 {
478  FloatComplexMatrix s (s_arg);
479  FloatComplexMatrix u (u_arg);
480 
481  F77_INT n = to_f77_int (s.rows ());
482 
483  if (s.columns () != n || u.rows () != n || u.columns () != n)
484  (*current_liboctave_error_handler)
485  ("rsf2csf: inconsistent matrix dimensions");
486 
487  if (n > 0)
488  {
489  OCTAVE_LOCAL_BUFFER (float, c, n-1);
490  OCTAVE_LOCAL_BUFFER (float, sx, n-1);
491 
492  F77_XFCN (crsf2csf, CRSF2CSF,
493  (n, F77_CMPLX_ARG (s.fortran_vec ()),
494  F77_CMPLX_ARG (u.fortran_vec ()), c, sx));
495  }
496 
497  return schur<FloatComplexMatrix> (s, u);
498 }
499 
500 // Instantiations we need.
501 
502 template class schur<ComplexMatrix>;
503 
504 template class schur<FloatComplexMatrix>;
505 
506 template class schur<FloatMatrix>;
507 
508 template class schur<Matrix>;
509 
OCTAVE_END_NAMESPACE(octave)
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type columns(void) const
Definition: Array.h:471
OCTARRAY_API void clear(void)
Definition: Array-base.cc:109
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type rows(void) const
Definition: Array.h:459
OCTARRAY_API T * fortran_vec(void)
Size of the specified dimension.
Definition: Array-base.cc:1766
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type cols(void) const
Definition: Array.h:469
Definition: dMatrix.h:42
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
Definition: schur.h:47
OCTAVE_API octave_f77_int_type init(const T &a, const std::string &ord, bool calc_unitary)
subroutine crsf2csf(n, t, u, c, s)
Definition: crsf2csf.f:24
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
#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
double _Complex F77_DBLE_CMPLX
Definition: f77-fcn.h:304
octave_f77_int_type F77_INT
Definition: f77-fcn.h:306
float _Complex F77_CMPLX
Definition: f77-fcn.h:305
OCTAVE_API schur< FloatComplexMatrix > rsf2csf< FloatComplexMatrix, FloatMatrix >(const FloatMatrix &s_arg, const FloatMatrix &u_arg)
Definition: schur.cc:475
static F77_INT select_dig(const double &a, const double &b)
Definition: schur.cc:53
OCTAVE_API schur< ComplexMatrix > rsf2csf< ComplexMatrix, Matrix >(const Matrix &s_arg, const Matrix &u_arg)
Definition: schur.cc:363
static F77_INT select_ana(const double &a, const double &)
Definition: schur.cc:47
F77_INT(* float_complex_selector)(const F77_CMPLX &)
F77_INT(* float_selector)(const F77_REAL &, const F77_REAL &)
F77_INT(* double_selector)(const F77_DBLE &, const F77_DBLE &)
F77_INT(* complex_selector)(const F77_DBLE_CMPLX &)
#define OCTAVE_API
Definition: main.in.cc:55
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 OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
static T abs(T x)
Definition: pr-output.cc:1678
static double wi[256]
Definition: randmtzig.cc:464
subroutine zrsf2csf(n, t, u, c, s)
Definition: zrsf2csf.f:24