LAPACK++
LAPACK C++ API
util.hh
1 // Copyright (c) 2017-2020, University of Tennessee. All rights reserved.
2 // SPDX-License-Identifier: BSD-3-Clause
3 // This program is free software: you can redistribute it and/or modify it under
4 // the terms of the BSD 3-Clause license. See the accompanying LICENSE file.
5 
6 #ifndef LAPACK_UTIL_HH
7 #define LAPACK_UTIL_HH
8 
9 #include <exception>
10 #include <complex>
11 #include <ctype.h>
12 
13 #include <assert.h>
14 
15 #include "blas.hh"
16 
17 // from config, we need only lapack_logical for callback functions lapack_*_select*
18 #include "lapack/config.h"
19 
20 #if __cplusplus >= 201402 // C++14
21  //#pragma message "LAPACK_DEPRECATED: [[deprecated]]"
22  #define LAPACK_DEPRECATED(msg) [[deprecated(msg)]]
23 #elif defined(_MSC_VER)
24  //#pragma message "LAPACK_DEPRECATED: __declspec"
25  #define LAPACK_DEPRECATED(msg) __declspec(deprecated(msg))
26 #elif defined(__GNUC__)
27  //#pragma message "LAPACK_DEPRECATED: __attribute__"
28  #define LAPACK_DEPRECATED(msg) __attribute__((deprecated(msg)))
29 #else
30  //#pragma message "LAPACK_DEPRECATED: none"
31  #define LAPACK_DEPRECATED(msg)
32 #endif
33 
34 namespace lapack {
35 
36 // -----------------------------------------------------------------------------
38 class Error: public std::exception {
39 public:
41  Error():
42  std::exception()
43  {}
44 
46  Error( std::string const& msg ):
47  std::exception(),
48  msg_( msg )
49  {}
50 
52  Error( const char* msg, const char* func ):
53  std::exception(),
54  msg_( std::string(msg) + ", in function " + func )
55  {}
56 
58  virtual const char* what() const noexcept override
59  { return msg_.c_str(); }
60 
61 private:
62  std::string msg_;
63 };
64 
65 // =============================================================================
66 namespace internal {
67 
68 // -----------------------------------------------------------------------------
69 // internal helper function; throws Error if cond is true
70 // called by blas_error_if macro
71 inline void throw_if( bool cond, const char* condstr, const char* func )
72 {
73  if (cond) {
74  throw Error( condstr, func );
75  }
76 }
77 
78 // -----------------------------------------------------------------------------
79 // internal helper function; throws Error if cond is true
80 // uses printf-style format for error message
81 // called by lapack_error_if_msg macro
82 // condstr is ignored, but differentiates this from other version.
83 inline void throw_if( bool cond, const char* condstr, const char* func, const char* format, ... )
84  __attribute__((format( printf, 4, 5 )));
85 
86 inline void throw_if( bool cond, const char* condstr, const char* func, const char* format, ... )
87 {
88  if (cond) {
89  char buf[80];
90  va_list va;
91  va_start( va, format );
92  vsnprintf( buf, sizeof(buf), format, va );
93  throw Error( buf, func );
94  }
95 }
96 
97 // -----------------------------------------------------------------------------
98 // internal helper function; aborts if cond is true
99 // uses printf-style format for error message
100 // called by lapack_error_if_msg macro
101 inline void abort_if( bool cond, const char* func, const char* format, ... )
102  __attribute__((format( printf, 3, 4 )));
103 
104 inline void abort_if( bool cond, const char* func, const char* format, ... )
105 {
106  if (cond) {
107  char buf[80];
108  va_list va;
109  va_start( va, format );
110  vsnprintf( buf, sizeof(buf), format, va );
111 
112  fprintf( stderr, "Error: %s, in function %s\n", buf, func );
113  abort();
114  }
115 }
116 
117 } // namespace internal
118 
119 // -----------------------------------------------------------------------------
120 // internal macros to handle error checks
121 #if defined(LAPACK_ERROR_NDEBUG) || (defined(LAPACK_ERROR_ASSERT) && defined(NDEBUG))
122 
123  // lapackpp does no error checking;
124  // lower level LAPACK may still handle errors via xerbla
125  #define lapack_error_if( cond ) \
126  ((void)0)
127 
128  #define lapack_error_if_msg( cond, ... ) \
129  ((void)0)
130 
131 #elif defined(LAPACK_ERROR_ASSERT)
132 
133  // lapackpp aborts on error
134  #define lapack_error_if( cond ) \
135  lapack::internal::abort_if( cond, __func__, "%s", #cond )
136 
137  #define lapack_error_if_msg( cond, ... ) \
138  lapack::internal::abort_if( cond, __func__, __VA_ARGS__ )
139 
140 #else
141 
142  // lapackpp throws errors (default)
143  // internal macro to get string #cond; throws Error if cond is true
144  // ex: lapack_error_if( a < b );
145  #define lapack_error_if( cond ) \
146  lapack::internal::throw_if( cond, #cond, __func__ )
147 
148  // internal macro takes cond and printf-style format for error message.
149  // throws Error if cond is true.
150  // ex: lapack_error_if_msg( a < b, "a %d < b %d", a, b );
151  #define lapack_error_if_msg( cond, ... ) \
152  lapack::internal::throw_if( cond, #cond, __func__, __VA_ARGS__ )
153 
154 #endif
155 
156 // =============================================================================
157 // Callback logical functions of one, two, or three arguments are used
158 // to select eigenvalues to sort to the top left of the Schur form in gees and gges.
159 // The value is selected if function returns TRUE (non-zero).
160 
161 typedef lapack_logical (*lapack_s_select2) ( float const* omega_real, float const* omega_imag );
162 typedef lapack_logical (*lapack_s_select3) ( float const* alpha_real, float const* alpha_imag, float const* beta );
163 
164 typedef lapack_logical (*lapack_d_select2) ( double const* omega_real, double const* omega_imag );
165 typedef lapack_logical (*lapack_d_select3) ( double const* alpha_real, double const* alpha_imag, double const* beta );
166 
167 typedef lapack_logical (*lapack_c_select1) ( std::complex<float> const* omega );
168 typedef lapack_logical (*lapack_c_select2) ( std::complex<float> const* alpha, std::complex<float> const* beta );
169 
170 typedef lapack_logical (*lapack_z_select1) ( std::complex<double> const* omega );
171 typedef lapack_logical (*lapack_z_select2) ( std::complex<double> const* alpha, std::complex<double> const* beta );
172 
173 // =============================================================================
174 typedef blas::Layout Layout;
175 typedef blas::Op Op;
176 typedef blas::Uplo Uplo;
177 typedef blas::Diag Diag;
178 typedef blas::Side Side;
179 
180 // -----------------------------------------------------------------------------
181 // like blas::side, but adds Both for trevc
182 enum class Sides : char {
183  Left = 'L', L = 'L',
184  Right = 'R', R = 'R',
185  Both = 'B', B = 'B',
186 };
187 
188 inline char sides2char( Sides sides )
189 {
190  return char(sides);
191 }
192 
193 inline const char* sides2str( Sides sides )
194 {
195  switch (sides) {
196  case Sides::Left: return "left";
197  case Sides::Right: return "right";
198  case Sides::Both: return "both";
199  }
200  return "?";
201 }
202 
203 inline Sides char2sides( char sides )
204 {
205  sides = (char) toupper( sides );
206  assert( sides == 'L' || sides == 'R' || sides == 'B' );
207  return Sides( sides );
208 }
209 
210 // -----------------------------------------------------------------------------
211 enum class Norm {
212  One = '1', // or 'O'
213  Two = '2',
214  Inf = 'I',
215  Fro = 'F', // or 'E'
216  Max = 'M',
217 };
218 
219 inline char norm2char( lapack::Norm norm )
220 {
221  return char( norm );
222 }
223 
224 inline lapack::Norm char2norm( char norm )
225 {
226  norm = char( toupper( norm ));
227  if (norm == 'O')
228  norm = '1';
229  else if (norm == 'E')
230  norm = 'F';
231  lapack_error_if( norm != '1' && norm != '2' && norm != 'I' &&
232  norm != 'F' && norm != 'M' );
233  return lapack::Norm( norm );
234 }
235 
236 inline const char* norm2str( lapack::Norm norm )
237 {
238  switch (norm) {
239  case Norm::One: return "1";
240  case Norm::Two: return "2";
241  case Norm::Inf: return "inf";
242  case Norm::Fro: return "fro";
243  case Norm::Max: return "max";
244  }
245  return "?";
246 }
247 
248 // -----------------------------------------------------------------------------
249 // Job for computing eigenvectors and singular vectors
250 // # needs custom map
251 enum class Job {
252  NoVec = 'N',
253  Vec = 'V', // geev, syev, ...
254  UpdateVec = 'U', // gghrd#, hbtrd, hgeqz#, hseqr#, ... (many compq or compz)
255 
256  AllVec = 'A', // gesvd, gesdd, gejsv#
257  SomeVec = 'S', // gesvd, gesdd, gejsv#, gesvj#
258  OverwriteVec = 'O', // gesvd, gesdd
259 
260  CompactVec = 'P', // bdsdc
261  SomeVecTol = 'C', // gesvj
262  VecJacobi = 'J', // gejsv
263  Workspace = 'W', // gejsv
264 };
265 
266 inline char job2char( lapack::Job job )
267 {
268  return char( job );
269 }
270 
271 // custom maps
272 // bbcsd, orcsd2by1
273 inline char job_csd2char( lapack::Job job )
274 {
275  switch (job) {
276  case lapack::Job::Vec: return 'Y'; // orcsd
277  case lapack::Job::UpdateVec: return 'Y'; // bbcsd
278  default: return char( job );
279  }
280 }
281 
282 // bdsdc, gghrd, hgeqz, hseqr, pteqr, stedc, steqr, tgsja, trexc, trsen
283 inline char job_comp2char( lapack::Job job )
284 {
285  switch (job) {
286  case lapack::Job::Vec: return 'I';
287  case lapack::Job::UpdateVec: return 'V';
288  default: return char( job );
289  }
290 }
291 
292 // tgsja
293 inline char job_compu2char( lapack::Job job )
294 {
295  switch (job) {
296  case lapack::Job::Vec: return 'I';
297  case lapack::Job::UpdateVec: return 'U';
298  default: return char( job );
299  }
300 }
301 
302 // tgsja
303 inline char job_compq2char( lapack::Job job )
304 {
305  switch (job) {
306  case lapack::Job::Vec: return 'I';
307  case lapack::Job::UpdateVec: return 'Q';
308  default: return char( job );
309  }
310 }
311 
312 // ggsvd3, ggsvp3
313 inline char jobu2char( lapack::Job job )
314 {
315  switch (job) {
316  case lapack::Job::Vec: return 'U';
317  default: return char( job );
318  }
319 }
320 
321 // ggsvd3, ggsvp3
322 inline char jobq2char( lapack::Job job )
323 {
324  switch (job) {
325  case lapack::Job::Vec: return 'Q';
326  default: return char( job );
327  }
328 }
329 
330 // gejsva
331 inline char jobu_gejsv2char( lapack::Job job )
332 {
333  switch (job) {
334  case lapack::Job::SomeVec: return 'U';
335  case lapack::Job::AllVec: return 'F';
336  default: return char( job );
337  }
338 }
339 
340 // gesvj
341 inline char job_gesvj2char( lapack::Job job )
342 {
343  switch (job) {
344  case lapack::Job::SomeVec: return 'U'; // jobu
345  case lapack::Job::SomeVecTol: return 'C'; // jobu
346  case lapack::Job::UpdateVec: return 'U'; // jobv
347  default: return char( job );
348  }
349 }
350 
351 inline lapack::Job char2job( char job )
352 {
353  job = char( toupper( job ));
354  lapack_error_if( job != 'N' && job != 'V' && job != 'U' &&
355  job != 'A' && job != 'S' && job != 'O' &&
356  job != 'P' && job != 'C' && job != 'J' &&
357  job != 'W' );
358  return lapack::Job( job );
359 }
360 
361 inline const char* job2str( lapack::Job job )
362 {
363  switch (job) {
364  case lapack::Job::NoVec: return "novec";
365  case lapack::Job::Vec: return "vec";
366  case lapack::Job::UpdateVec: return "update";
367 
368  case lapack::Job::AllVec: return "all";
369  case lapack::Job::SomeVec: return "some";
370  case lapack::Job::OverwriteVec: return "overwrite";
371 
372  case lapack::Job::CompactVec: return "compact";
373  case lapack::Job::SomeVecTol: return "sometol";
374  case lapack::Job::VecJacobi: return "jacobi";
375  case lapack::Job::Workspace: return "work";
376  }
377  return "?";
378 }
379 
380 // -----------------------------------------------------------------------------
381 // hseqr
382 enum class JobSchur {
383  Eigenvalues = 'E',
384  Schur = 'S',
385 };
386 
387 inline char jobschur2char( lapack::JobSchur jobschur )
388 {
389  return char( jobschur );
390 }
391 
392 inline lapack::JobSchur char2jobschur( char jobschur )
393 {
394  jobschur = char( toupper( jobschur ));
395  lapack_error_if( jobschur != 'E' && jobschur != 'S' );
396  return lapack::JobSchur( jobschur );
397 }
398 
399 inline const char* jobschur2str( lapack::JobSchur jobschur )
400 {
401  switch (jobschur) {
402  case lapack::JobSchur::Eigenvalues: return "eigval";
403  case lapack::JobSchur::Schur: return "schur";
404  }
405  return "?";
406 }
407 
408 // -----------------------------------------------------------------------------
409 // gees
410 // todo: generic yes/no
411 enum class Sort {
412  NotSorted = 'N',
413  Sorted = 'S',
414 };
415 
416 inline char sort2char( lapack::Sort sort )
417 {
418  return char( sort );
419 }
420 
421 inline lapack::Sort char2sort( char sort )
422 {
423  sort = char( toupper( sort ));
424  lapack_error_if( sort != 'N' && sort != 'S' );
425  return lapack::Sort( sort );
426 }
427 
428 inline const char* sort2str( lapack::Sort sort )
429 {
430  switch (sort) {
431  case lapack::Sort::NotSorted: return "not-sorted";
432  case lapack::Sort::Sorted: return "sorted";
433  }
434  return "?";
435 }
436 
437 // -----------------------------------------------------------------------------
438 // syevx
439 enum class Range {
440  All = 'A',
441  Value = 'V',
442  Index = 'I',
443 };
444 
445 inline char range2char( lapack::Range range )
446 {
447  return char( range );
448 }
449 
450 inline lapack::Range char2range( char range )
451 {
452  range = char( toupper( range ));
453  lapack_error_if( range != 'A' && range != 'V' && range != 'I' );
454  return lapack::Range( range );
455 }
456 
457 inline const char* range2str( lapack::Range range )
458 {
459  switch (range) {
460  case lapack::Range::All: return "all";
461  case lapack::Range::Value: return "value";
462  case lapack::Range::Index: return "index";
463  }
464  return "?";
465 }
466 
467 // -----------------------------------------------------------------------------
468 enum class Vect {
469  Q = 'Q', // orgbr, ormbr
470  P = 'P', // orgbr, ormbr
471  None = 'N', // orgbr, ormbr, gbbrd
472  Both = 'B', // orgbr, ormbr, gbbrd
473 };
474 
475 inline char vect2char( lapack::Vect vect )
476 {
477  return char( vect );
478 }
479 
480 inline lapack::Vect char2vect( char vect )
481 {
482  vect = char( toupper( vect ));
483  lapack_error_if( vect != 'Q' && vect != 'P' && vect != 'N' && vect != 'B' );
484  return lapack::Vect( vect );
485 }
486 
487 inline const char* vect2str( lapack::Vect vect )
488 {
489  switch (vect) {
490  case lapack::Vect::P: return "p";
491  case lapack::Vect::Q: return "q";
492  case lapack::Vect::None: return "none";
493  case lapack::Vect::Both: return "both";
494  }
495  return "?";
496 }
497 
498 // -----------------------------------------------------------------------------
499 // larfb
500 enum class Direction {
501  Forward = 'F',
502  Backward = 'B',
503 };
504 
505 inline char direction2char( lapack::Direction direction )
506 {
507  return char( direction );
508 }
509 
510 inline lapack::Direction char2direction( char direction )
511 {
512  direction = char( toupper( direction ));
513  lapack_error_if( direction != 'F' && direction != 'B' );
514  return lapack::Direction( direction );
515 }
516 
517 inline const char* direction2str( lapack::Direction direction )
518 {
519  switch (direction) {
520  case lapack::Direction::Forward: return "forward";
521  case lapack::Direction::Backward: return "backward";
522  }
523  return "?";
524 }
525 
526 // Deprecated in 2020.03.00; remove after 2021.03.00.
527 LAPACK_DEPRECATED("Direct replaced with Direction")
528 typedef Direction Direct;
529 
530 LAPACK_DEPRECATED("direct2char replaced with direction2char")
531 inline char direct2char( lapack::Direction direction )
532 {
533  return direction2char( direction );
534 }
535 
536 LAPACK_DEPRECATED("direct2str replaced with direction2str")
537 inline const char* direct2str( lapack::Direction direction )
538 {
539  return direction2str( direction );
540 }
541 
542 LAPACK_DEPRECATED("char2direct replaced with char2direction")
543 inline lapack::Direction char2direct( char direction )
544 {
545  return char2direction( direction );
546 }
547 
548 // -----------------------------------------------------------------------------
549 // larfb
550 enum class StoreV {
551  Columnwise = 'C',
552  Rowwise = 'R',
553 };
554 
555 inline char storev2char( lapack::StoreV storev )
556 {
557  return char( storev );
558 }
559 
560 inline lapack::StoreV char2storev( char storev )
561 {
562  storev = char( toupper( storev ));
563  lapack_error_if( storev != 'C' && storev != 'R' );
564  return lapack::StoreV( storev );
565 }
566 
567 inline const char* storev2str( lapack::StoreV storev )
568 {
569  switch (storev) {
570  case lapack::StoreV::Columnwise: return "columnwise";
571  case lapack::StoreV::Rowwise: return "rowwise";
572  }
573  return "?";
574 }
575 
576 // -----------------------------------------------------------------------------
577 // lascl, laset
578 enum class MatrixType {
579  General = 'G',
580  Lower = 'L',
581  Upper = 'U',
582  Hessenberg = 'H',
583  LowerBand = 'B',
584  UpperBand = 'Q',
585  Band = 'Z',
586 };
587 
588 inline char matrixtype2char( lapack::MatrixType type )
589 {
590  return char( type );
591 }
592 
593 inline lapack::MatrixType char2matrixtype( char type )
594 {
595  type = char( toupper( type ));
596  lapack_error_if( type != 'G' && type != 'L' && type != 'U' &&
597  type != 'H' && type != 'B' && type != 'Q' && type != 'Z' );
598  return lapack::MatrixType( type );
599 }
600 
601 inline const char* matrixtype2str( lapack::MatrixType type )
602 {
603  switch (type) {
604  case lapack::MatrixType::General: return "general";
605  case lapack::MatrixType::Lower: return "lower";
606  case lapack::MatrixType::Upper: return "upper";
607  case lapack::MatrixType::Hessenberg: return "hessenberg";
608  case lapack::MatrixType::LowerBand: return "band-lower";
609  case lapack::MatrixType::UpperBand: return "q-band-upper";
610  case lapack::MatrixType::Band: return "z-band";
611  }
612  return "?";
613 }
614 
615 // -----------------------------------------------------------------------------
616 // trevc
617 enum class HowMany {
618  All = 'A',
619  Backtransform = 'B',
620  Select = 'S',
621 };
622 
623 inline char howmany2char( lapack::HowMany howmany )
624 {
625  return char( howmany );
626 }
627 
628 inline lapack::HowMany char2howmany( char howmany )
629 {
630  howmany = char( toupper( howmany ));
631  lapack_error_if( howmany != 'A' && howmany != 'B' && howmany != 'S' );
632  return lapack::HowMany( howmany );
633 }
634 
635 inline const char* howmany2str( lapack::HowMany howmany )
636 {
637  switch (howmany) {
638  case lapack::HowMany::All: return "all";
639  case lapack::HowMany::Backtransform: return "backtransform";
640  case lapack::HowMany::Select: return "select";
641  }
642  return "?";
643 }
644 
645 // -----------------------------------------------------------------------------
646 // *svx, *rfsx
647 enum class Equed {
648  None = 'N',
649  Row = 'R',
650  Col = 'C',
651  Both = 'B',
652  Yes = 'Y', // porfsx
653 };
654 
655 inline char equed2char( lapack::Equed equed )
656 {
657  return char( equed );
658 }
659 
660 inline lapack::Equed char2equed( char equed )
661 {
662  equed = char( toupper( equed ));
663  lapack_error_if( equed != 'N' && equed != 'R' && equed != 'C' &&
664  equed != 'B' && equed != 'Y' );
665  return lapack::Equed( equed );
666 }
667 
668 inline const char* equed2str( lapack::Equed equed )
669 {
670  switch (equed) {
671  case lapack::Equed::None: return "none";
672  case lapack::Equed::Row: return "row";
673  case lapack::Equed::Col: return "col";
674  case lapack::Equed::Both: return "both";
675  case lapack::Equed::Yes: return "yes";
676  }
677  return "?";
678 }
679 
680 // -----------------------------------------------------------------------------
681 // *svx
682 // todo: what's good name for this?
683 enum class Factored {
684  Factored = 'F',
685  NotFactored = 'N',
686  Equilibrate = 'E',
687 };
688 
689 inline char factored2char( lapack::Factored factored )
690 {
691  return char( factored );
692 }
693 
694 inline lapack::Factored char2factored( char factored )
695 {
696  factored = char( toupper( factored ));
697  lapack_error_if( factored != 'F' && factored != 'N' && factored != 'E' );
698  return lapack::Factored( factored );
699 }
700 
701 inline const char* factored2str( lapack::Factored factored )
702 {
703  switch (factored) {
704  case lapack::Factored::Factored: return "factored";
705  case lapack::Factored::NotFactored: return "notfactored";
706  case lapack::Factored::Equilibrate: return "equilibrate";
707  }
708  return "?";
709 }
710 
711 // -----------------------------------------------------------------------------
712 // geesx, trsen
713 enum class Sense {
714  None = 'N',
715  Eigenvalues = 'E',
716  Subspace = 'V',
717  Both = 'B',
718 };
719 
720 inline char sense2char( lapack::Sense sense )
721 {
722  return char( sense );
723 }
724 
725 inline lapack::Sense char2sense( char sense )
726 {
727  sense = char( toupper( sense ));
728  lapack_error_if( sense != 'N' && sense != 'E' && sense != 'V' &&
729  sense != 'B' );
730  return lapack::Sense( sense );
731 }
732 
733 inline const char* sense2str( lapack::Sense sense )
734 {
735  switch (sense) {
736  case lapack::Sense::None: return "none";
737  case lapack::Sense::Eigenvalues: return "eigval";
738  case lapack::Sense::Subspace: return "subspace";
739  case lapack::Sense::Both: return "both";
740  }
741  return "?";
742 }
743 
744 // -----------------------------------------------------------------------------
745 // disna
746 enum class JobCond {
747  EigenVec = 'E',
748  LeftSingularVec = 'L',
749  RightSingularVec = 'R',
750 };
751 
752 inline char jobcond2char( lapack::JobCond jobcond )
753 {
754  return char( jobcond );
755 }
756 
757 inline lapack::JobCond char2jobcond( char jobcond )
758 {
759  jobcond = char( toupper( jobcond ));
760  lapack_error_if( jobcond != 'N' && jobcond != 'E' && jobcond != 'V' &&
761  jobcond != 'B' );
762  return lapack::JobCond( jobcond );
763 }
764 
765 inline const char* jobcond2str( lapack::JobCond jobcond )
766 {
767  switch (jobcond) {
768  case lapack::JobCond::EigenVec: return "eigvec";
769  case lapack::JobCond::LeftSingularVec: return "left";
770  case lapack::JobCond::RightSingularVec: return "right";
771  }
772  return "?";
773 }
774 
775 // -----------------------------------------------------------------------------
776 // {ge,gg}{bak,bal}
777 enum class Balance {
778  None = 'N',
779  Permute = 'P',
780  Scale = 'S',
781  Both = 'B',
782 };
783 
784 inline char balance2char( lapack::Balance balance )
785 {
786  return char( balance );
787 }
788 
789 inline lapack::Balance char2balance( char balance )
790 {
791  balance = char( toupper( balance ));
792  lapack_error_if( balance != 'N' && balance != 'P' && balance != 'S' &&
793  balance != 'B' );
794  return lapack::Balance( balance );
795 }
796 
797 inline const char* balance2str( lapack::Balance balance )
798 {
799  switch (balance) {
800  case lapack::Balance::None: return "none";
801  case lapack::Balance::Permute: return "permute";
802  case lapack::Balance::Scale: return "scale";
803  case lapack::Balance::Both: return "both";
804  }
805  return "?";
806 }
807 
808 // -----------------------------------------------------------------------------
809 // stebz, larrd, stein docs
810 enum class Order {
811  Block = 'B',
812  Entire = 'E',
813 };
814 
815 inline char order2char( lapack::Order order )
816 {
817  return char( order );
818 }
819 
820 inline lapack::Order char2order( char order )
821 {
822  order = char( toupper( order ));
823  lapack_error_if( order != 'B' && order != 'E' );
824  return lapack::Order( order );
825 }
826 
827 inline const char* order2str( lapack::Order order )
828 {
829  switch (order) {
830  case lapack::Order::Block: return "block";
831  case lapack::Order::Entire: return "entire";
832  }
833  return "?";
834 }
835 
836 // -----------------------------------------------------------------------------
837 // check_ortho (LAPACK testing zunt01)
838 enum class RowCol {
839  Col = 'C',
840  Row = 'R',
841 };
842 
843 inline char rowcol2char( lapack::RowCol rowcol )
844 {
845  return char( rowcol );
846 }
847 
848 inline lapack::RowCol char2rowcol( char rowcol )
849 {
850  rowcol = char( toupper( rowcol ));
851  lapack_error_if( rowcol != 'C' && rowcol != 'R' );
852  return lapack::RowCol( rowcol );
853 }
854 
855 inline const char* rowcol2str( lapack::RowCol rowcol )
856 {
857  switch (rowcol) {
858  case lapack::RowCol::Col: return "col";
859  case lapack::RowCol::Row: return "row";
860  }
861  return "?";
862 }
863 
864 } // namespace lapack
865 
866 #endif // LAPACK_UTIL_HH
lapack::Error::what
virtual const char * what() const noexcept override
Returns LAPACK error message.
Definition: util.hh:58
lapack::Error::Error
Error(std::string const &msg)
Constructs BLAS error with message.
Definition: util.hh:46
lapack::Error
Exception class for LAPACK errors.
Definition: util.hh:38
lapack::Error::Error
Error()
Constructs LAPACK error.
Definition: util.hh:41
lapack::Error::Error
Error(const char *msg, const char *func)
Constructs LAPACK error with message: "func: msg".
Definition: util.hh:52