GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
schur.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1994-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 "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,
380  (n, F77_DBLE_CMPLX_ARG (s.fortran_vec ()),
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 
510 OCTAVE_END_NAMESPACE(math)
511 OCTAVE_END_NAMESPACE(octave)
T * fortran_vec()
Size of the specified dimension.
Definition: Array-base.cc:1764
void clear()
Definition: Array-base.cc:109
octave_idx_type rows() const
Definition: Array.h:459
octave_idx_type cols() 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
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
schur< FloatComplexMatrix > rsf2csf< FloatComplexMatrix, FloatMatrix >(const FloatMatrix &s_arg, const FloatMatrix &u_arg)
Definition: schur.cc:475
schur< ComplexMatrix > rsf2csf< ComplexMatrix, Matrix >(const Matrix &s_arg, const Matrix &u_arg)
Definition: schur.cc:363
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.cc:55
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 OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
subroutine zrsf2csf(n, t, u, c, s)
Definition: zrsf2csf.f:24