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