C++ Boost

Boost.Numeric.Bindings.LAPACK



Back to Bindings Library Synopsis

Contents

  1. Introduction
  2. Using LAPACK bindings
    1. Linear Equations
      1. General System
      2. Positive Definite System
      3. Positive Definite System with Coefficient Matrix in Packed Storage
      4. Symmetric (Real and Complex) Indefinite System
      5. Symmetric Indefinite System with Coefficient Matrix in Packed Storage
      6. Hermitian Indefinite System
      7. Hermitian Indefinite System with Coefficient Matrix in Packed Storage
    2. Singular Value Decomposition
      1. Simple Driver
      2. Divide and Conquer Driver
  3. Extending LAPACK bindings

1. Introduction

To introduce LAPACK, let us quote from the LAPACK Users' Guide:

``LAPACK is a library of Fortran 77 subroutines for solving the most commonly occurring problems in numerical linear algebra. It has been designed to be efficient on a wide range of modern high-performance computers. The name LAPACK is an acronym for Linear Algebra PACKage.

LAPACK can solve systems of linear equations, linear least squares problems, eigenvalue problems and singular value problems. LAPACK can also handle many associated computations such as matrix factorizations or estimating condition numbers.

LAPACK contains driver routines for solving standard types of problems, computational routines to perform a distinct computational task, and auxiliary routines to perform a certain subtask or common low-level computation. Each driver routine typically calls a sequence of computational routines. Taken as a whole, the computational routines can perform a wider range of tasks than are covered by the driver routines. [...]

Dense and band matrices are provided for, but not general sparse matrices. In all areas, similar functionality is provided for real and complex matrices.''

For a complete overview of the LAPACK routines see chapter Contents of LAPACK in the LAPACK Users' Guide.

There is also the C version of LAPACK, called CLAPACK. ``The CLAPACK library was built using a Fortran to C conversion utility called f2c. The entire Fortran 77 LAPACK library is run through f2c to obtain C code, and then modified to improve readability. CLAPACK's goal is to provide LAPACK for someone who does not have access to a Fortran compiler.'' [quote from CLAPACK readme]

LAPACK Bindings Library provides generic, higher level interface to LAPACK routines. By `generic' we mean that bindings are based on traits and therefore can be used with various (sparse) matrix and vector classes, and by `higher level' that some complexities of the Fortran or C interfaces and calling conventions are hidden from the user. But, as LAPACK was written in Fortran (and CLAPACK is a direct conversion to C), matrices must have column major storage order.

2. Using LAPACK bindings

All header files are in the directory boost/numeric/bindings/lapack.

All `public' functions are in the namespace boost::numeric::bindings::lapack.

Note: LAPACK bindings can be used with either LAPACK or CLAPACK libraries. We recommend to use bindings with genuine LAPACK. But if you use CLAPACK, define BOOST_NUMERIC_BINDINGS_USE_CLAPACK before the inclusion of LAPACK bindings files.

2.1 Linear Equations

We will write a system of simultaneous linear equations with several right-hand sides as

A X = B,

where A is the coefficient matrix, the columns of B are the individual right hand sides and the columns of X are corresponding unknown vectors.

To find the solution (i.e. determine X, given A and B), A is first factorised as a product of triangular matrices (and in some cases also a diagonal matrix or permutation matrix), and then a backward or forward substitution is carried out. The form of the factorisation depends on the structure and properties of the matrix A:

LAPACK bindings follow LAPACK's naming scheme, except for the first letter which denotes the type of the matrix elements as it is not needed (because of function overloading and templates). So, all function names have the form xxyyy (or xxyy), where xx denotes the structure/properties of the matrix, and yyy indicates the computation to be done:

Our convention is to group the functions which solve the same problem (or part of it) in separate files, named after the corresponding driver routine -- for example, gesv(), getrf() and getrs(), that is, functions for solving (perhaps in several steps) a system with general coefficient matrix, are defined in gesv.hpp.

2.1.1 General System

Defined in boost/numeric/bindings/lapack/gesv.hpp.

Namespace is boost::numeric::bindings::lapack.

In the following table A, B, L, U are matrices, ipiv is a vector of pivot indices representing premutation matrix P (for more details see description of the LU factorisation above), Trans can be 'N', 'T' or 'C', denoting A, AT or AH, respectively, and ierr is `diagnostic argument' INFO (as described in LAPACK Users' Guide).

ExpressionSemantics
gesv(A,ipiv,B)using AP=LU, B <- A-1B, A <- LU, ipiv <- P;   returns ierr
gesv(A,B)as above, with ipiv allocated and deallocated internally
getrf(A,ipiv)using AP=LU, A <- LU, ipiv <- P;   returns ierr
getrs(Trans,A,ipiv,B) B <- op(A)-1B assuming A <- LU and ipiv <- P,   op (A) == A || AT || AH;   returns ierr
getrs(A,ipiv,B)B <- A-1B assuming A <- LU and ipiv <- P;   returns ierr

2.1.2 Positive Definite System

Defined in boost/numeric/bindings/lapack/posv.hpp.

Namespace is boost::numeric::bindings::lapack.

In the following table A, B, L, U are matrices (for more details see description of the Cholesky factorisation above), Uplo can be 'U' or 'L', denoting that leading upper or lower, respectively, triangular part of A contains the upper or lower triangular part of the symmetric/Hermitian matrix (and that the lower or upper triangular part, respectively, is not referenced) and ierr is LAPACK's `diagnostic argument' INFO.

ExpressionSemantics
posv(Uplo,A,B) B <- A-1B, using A = UTU or A = LLT or A = UHU or A = LLH;   returns ierr
posv(A,B) B <- A-1B, using A = UTU or A = LLT or A = UHU or A = LLH;   returns ierr    [1]
potrf(Uplo,A) A = UTU or A = LLT or A = UHU or A = LLH;   returns ierr
potrf(A) A = UTU or A = LLT or A = UHU or A = LLH;   returns ierr    [1]
potrs(Uplo,A,B) B <- A-1B assuming A = UTU or A = LLT or A = UHU or A = LLH;   returns ierr
potrs(A,B) B <- A-1B assuming A = UTU or A = LLT or A = UHU or A = LLH;   returns ierr    [1]

[1] It is assumed that matrix traits class can determine whether upper or lower triangular part of A contains the corresponding part of the symmetric/Hermitian matrix (e.g. traits for ublas::symmetric_adaptor<> and ublas::hermitian_adaptor<>).

2.1.3 Positive Definite System with Coefficient Matrix in Packed Storage

Defined in boost/numeric/bindings/lapack/ppsv.hpp.

Namespace is boost::numeric::bindings::lapack.

In the following table A, B, L, U are matrices (for more details see description of the Cholesky factorisation above) and ierr is LAPACK's `diagnostic argument' INFO. Matrix A is stored in packed format (e.g. ublas::symmetric_matrix<> and ublas::hermitian_matrix<>).

ExpressionSemantics
ppsv(A,B) B <- A-1B, using A = UTU or A = LLT or A = UHU or A = LLH;   returns ierr
pptrf(A) A = UTU or A = LLT or A = UHU or A = LLH;   returns ierr
pptrs(A,B) B <- A-1B assuming A = UTU or A = LLT or A = UHU or A = LLH;   returns ierr

It is assumed that matrix traits class can determine whether or lower triangular part of the symmetric/Hermitian matrix is stored (e.g. traits for ublas::symmetric_matrix<> and ublas::hermitian_matrix<>).

2.1.4 Symmetric (Real and Complex) Indefinite System

Defined in boost/numeric/bindings/lapack/sysv.hpp.

Namespace is boost::numeric::bindings::lapack.

In the following table A, B, L, U, D are matrices, ipiv is a vector of pivot indices (for more details see description of the Bunch-Kaufman factorisation above), w is a `work' vector, Uplo can be 'U' or 'L', denoting that leading upper or lower, respectively, triangular part of A contains the upper or lower triangular part of the symmetric matrix (and that the lower or upper triangular part, respectively, is not referenced), Spec can be 'O' or 'M', specifying whether optimal or minimum size is to be returned, and ierr is LAPACK's `diagnostic argument' INFO.

ExpressionSemantics
sysv(Uplo,A,ipiv,B,w) B <- A-1B, using A = UDUT or A = LDLT;   returns ierr
sysv(Uplo,A,B) as above, with ipiv and w allocated and deallocated internally
sysv(A,ipiv,B,w) B <- A-1B, using A = UDUT or A = LDLT;   returns ierr    [1]
sysv(A,B) as above, with ipiv and w allocated and deallocated internally    [1]
sysv_work(Spec,Uplo,A) returns optimal or minimum size of the vector w
sysv_work(Spec,A) returns optimal or minimum size of the vector w    [1]
sytrf(Uplo,A,ipiv,w) A = UDUT or A = LDLT;   returns ierr
sytrf(Uplo,A,ipiv) as above, with w allocated and deallocated internally
sytrf(A,ipiv,w) A = UDUT or A = LDLT;   returns ierr    [1]
sytrf(A,ipiv) as above, with w allocated and deallocated internally    [1]
sytrf_work(Spec,Uplo,A) returns optimal or minimum size of the vector w
sytrf_work(Spec,A) returns optimal or minimum size of the vector w    [1]
sytrf_block(Spec,Uplo,A) returns optimal or minimum block size    [2]
sytrf_block(Spec,A) returns optimal or minimum block size    [1][2]
sytrs(Uplo,A,ipiv,B) B <- A-1B assuming A = UDUT or A = LDLT;   returns ierr
sytrs(A,ipiv,B) B <- A-1B assuming A = UDUT or A = LDLT;   returns ierr    [1]

[1] It is assumed that matrix traits class can determine whether upper or lower triangular part of A contains the corresponding part of the symmetric matrix (e.g. traits for ublas::symmetric_adaptor<>).

[2] Optimal size of the `work' vector w is n*nb, where nb is optimal block size and n the order of matrix A.

2.1.5 Symmetric Indefinite System with Coefficient Matrix in Packed Storage

Defined in boost/numeric/bindings/lapack/spsv.hpp.

Namespace is boost::numeric::bindings::lapack.

In the following table A, B, L, U, D are matrices, ipiv is a vector of pivot indices (for more details see description of the Bunch-Kaufman factorisation above) and ierr is LAPACK's `diagnostic argument' INFO. Matrix A is stored in packed format (e.g. ublas::symmetric_matrix<>).

ExpressionSemantics
spsv(A,ipiv,B) B <- A-1B, using A = UDUT or A = LDLT;   returns ierr
spsv(A,B) as above, with ipiv allocated and deallocated internally
sptrf(A,ipiv) A = UDUT or A = LDLT;   returns ierr
sptrs(A,ipiv,B) B <- A-1B assuming A = UDUT or A = LDLT;   returns ierr

It is assumed that matrix traits class can determine whether upper or lower triangular part of the symmetric matrix is stored (e.g. traits for ublas::symmetric_matrix<>).

2.1.6 Hermitian Indefinite System

Defined in boost/numeric/bindings/lapack/hesv.hpp.

Namespace is boost::numeric::bindings::lapack.

In the following table A, B, L, U, D are matrices, ipiv is a vector of pivot indices (for more details see description of the Bunch-Kaufman factorisation above), w is a `work' vector, Uplo can be 'U' or 'L', denoting that leading upper or lower, respectively, triangular part of A contains the upper or lower triangular part of the Hermitian matrix (and that the lower or upper triangular part, respectively, is not referenced), Spec can be 'O' or 'M', specifying whether optimal or minimum size is to be returned, and ierr is LAPACK's `diagnostic argument' INFO.

ExpressionSemantics
hesv(Uplo,A,ipiv,B,w) B <- A-1B, using A = UDUH or A = LDLH;   returns ierr
hesv(Uplo,A,B) as above, with ipiv and w allocated and deallocated internally
hesv(A,ipiv,B,w) B <- A-1B, using A = UDUH or A = LDLH;   returns ierr    [1]
hesv(A,B) as above, with ipiv and w allocated and deallocated internally    [1]
hesv_work(Spec,Uplo,A) returns optimal or minimum size of the vector w
hesv_work(Spec,A) returns optimal or minimum size of the vector w    [1]
hetrf(Uplo,A,ipiv,w) A = UDUH or A = LDLH;   returns ierr
hetrf(Uplo,A,ipiv) as above, with w allocated and deallocated internally
hetrf(A,ipiv,w) A = UDUH or A = LDLH;   returns ierr    [1]
hetrf(A,ipiv) as above, with w allocated and deallocated internally    [1]
hetrf_work(Spec,Uplo,A) returns optimal or minimum size of the vector w
hetrf_work(Spec,A) returns optimal or minimum size of the vector w    [1]
hetrf_block(Spec,Uplo,A) returns optimal or minimal block size    [2]
hetrf_block(Spec,A) returns optimal or minimal block size    [1][2]
hetrs(Uplo,A,ipiv,B) B <- A-1B assuming A = UDUH or A = LDLH;   returns ierr
hetrs(A,ipiv,B) B <- A-1B assuming A = UDUH or A = LDLH;   returns ierr    [1]

[1] It is assumed that matrix traits class can determine whether upper or lower triangular part of A contains the corresponding part of the Hermitian matrix (e.g. traits for ublas::hermitian_adaptor<>).

[2] Optimal size of the `work' vector w is n*nb, where nb is optimal block size and n the order of matrix A.

2.1.7 Hermitian Indefinite System with Coefficient Matrix in Packed Storage

Defined in boost/numeric/bindings/lapack/hpsv.hpp.

Namespace is boost::numeric::bindings::lapack.

In the following table A, B, L, U, D are matrices, ipiv is a vector of pivot indices (for more details see description of the Bunch-Kaufman factorisation above) and ierr is LAPACK's `diagnostic argument' INFO. Matrix A is stored in packed format (e.g. ublas::hermitian_matrix<>).

ExpressionSemantics
hpsv(A,ipiv,B) B <- A-1B, using A = UDUH or A = LDLH;   returns ierr
hpsv(A,B) as above, with ipiv allocated and deallocated internally
hptrf(A,ipiv) A = UDUH or A = LDLH;   returns ierr
hptrs(A,ipiv,B) B <- A-1B assuming A = UDUH or A = LDLH;   returns ierr

It is assumed that matrix traits class can determine whether upper or lower triangular part of the Hermitian matrix is stored (e.g. traits for ublas::hermitian_matrix<>).

2.2 Singular Value Decomposition

The singular value decomposition (SVD) of an m-by-n matrix A is given by

A = U S VT

if A is real and by

A = U S VH

if A is complex matrix. U and V are ortogonal in real case and unitary in complex case; U is m-by-m and V is n-by-n. First min(m,n) columns of U and V are the left and right singular vectors of A. S is an m-by-n real matrix with non-negative elements sii and with sij==0 for i!=j. The sii are singular values of A. Matrix S is in LAPACK represented by a vector s (such that ii->i).

LAPACK Bindings Library currently provides bindings for LAPACK driver routines only.

2.2.1 Simple Driver

Simple driver gesvd() computes all the singular values and optionally left and/or right singular vectors.

Defined in boost/numeric/bindings/lapack/gesvd.hpp.

Namespace is boost::numeric::bindings::lapack.

In the following table A, U, VT (denoting VT or VH -- namely, routine returns VT or VH, not V) are matrices; s is a vector representing matrix S; w, rw, are `work' vectors (elements of w can be real or complex, elements of rw are real). Jobu specifies options for computing U:

Jobvt specifies options for computing VT: Note that Jobu and Jobvt cannot both be 'O'. Lw can be 'O' or 'M', specifying whether optimal or minimum size of the `work' vector is to be used or calculated; 'O' can be used with LAPACK version 3.0 only. And finally, ierr is LAPACK's `diagnostic argument' INFO.

ExpressionSemantics
gesvd(Jobu,Jobvt,A,s,U,VT,w) SVD of real A;   returns ierr
gesvd(Jobu,Jobvt,A,s,U,VT,w,rw) SVD of complex A;   returns ierr
gesvd(Lw,Jobu,Jobvt,A,s,U,VT) SVD of real or complex A, with `internal' work space;   returns ierr
gesvd(Jobu,Jobvt,A,s,U,VT) same as gesvd('O',Jobu,Jobvt,A,s,U,VT);   returns ierr
gesvd(A,s,U,VT) same as gesvd('O','S','S',A,s,U,VT);   returns ierr
gesvd(A,s) same as gesvd('O','N','N',A,s,U,VT);   returns ierr    [1]
gesvd_work(Lw,Jobu,Jobvt,A) returns optimal or minimum size of the vector w
gesvd_rwork(A) returns minimum size of the vector rw

[1] U and VT are not referenced.

2.2.2 Divide and Conquer Driver

Divide and conquer driver gesdd() solves the same as the simple driver. It is much faster than the simple driver for large matrices, but uses more workspace.

Defined in boost/numeric/bindings/lapack/gesdd.hpp.

Namespace is boost::numeric::bindings::lapack.

In the following table A, U, VT (denoting VT or VH) are matrices; s is a vector representing matrix S; w, rw, iw, are `work' vectors (elements of w can be real or complex, elements of rw are real, elements of rw are ints). Jobz specifies options for computing U and VT:

Lw can be 'O' or 'M', specifying whether optimal or minimum size of the `work' vector is to be used or calculated; 'O' can be used with LAPACK version 3.0 only. Finally, ierr is LAPACK's `diagnostic argument' INFO.

ExpressionSemantics
gesdd(Jobz,A,s,U,VT,w,iw) SVD of real A;   returns ierr
gesdd(Jobz,A,s,U,VT,w,rw,iw) SVD of complex A;   returns ierr
gesdd(Lw,Jobz,A,s,U,VT) SVD of real or complex A, with `internal' work space;   returns ierr
gesdd(Jobz,A,s,U,VT) same as gesdd('O',Jobz,A,s,U,VT);   returns ierr
gesdd(A,s,U,VT) same as gesdd('O','S',A,s,U,VT);   returns ierr
gesdd(A,s) same as gesdd('O','N',A,s,U,VT);   returns ierr    [1]
gesdd_work(Lw,Jobz,A) returns optimal or minimum size of the vector w
gesdd_rwork(Jobz,A) returns minimum size of the vector rw
gesdd_iwork(A) returns minimum size of the vector iw

[1] U and VT are not referenced.

3. Extending LAPACK bindings

LAPACK is a huge library and LAPACK Bindings Library does not contain bindings for all LAPACK routines. In this section we will describe the implementation of function getrs to provide guidelines for user's additions and extensions.

Implementation will be described in two stages:

  1. core implementation, i.e. binding to Fortran routine;
  2. some workarounds for broken compilers.

1. There are four versions of almost all LAPACK routines for matrices with single and double precision real and complex elements. Type of the matrix elements is encoded as the first letter of the routine's name:

Thus, there are sgetrs, dgetrs, cgetrs and zgetrs.

There are several conventions for calling Fortran from C/C++: some compilers require trailing underscore in function names, some don't, etc. So, the first step is to define `portable' function names in lapack_names.h using the macro FORTRAN_ID (defined in traits/fortran.h):

     #define LAPACK_SGETRS FORTRAN_ID( sgetrs )
     #define LAPACK_DGETRS FORTRAN_ID( dgetrs )
     #define LAPACK_CGETRS FORTRAN_ID( cgetrs )
     #define LAPACK_ZGETRS FORTRAN_ID( zgetrs )

Next step is to declare interfaces of LAPACK routines in lapack.h. Only dgetrs and zgetrs are shown below; sgetrs and cgetrs differ only in the type of array parameters:

     void LAPACK_DGETRS (char const* trans, int const* n, int const* nrhs,
                         double const* a, int const* lda, int const* ipiv, double* b, int const* ldb, int* info);
     void LAPACK_ZGETRS (char const* trans, int const* n, int const* nrhs,
                         dcomplex_t const* a, int const* lda, int const* ipiv, dcomplex_t* b, int const* ldb, int* info);
All parameters, including scalars like n and nrhs, are defined as pointers; input parameters, i.e. those which are not modified inside the routine, are pointers to const. Functions have C linkage (extern "C" { ... }) and are in the global namespace.

Using function overloading, we can remove array parameters type from the function name:

     void getrs (char const trans, int const n, int const nrhs, double const* a, int const lda, 
                 int const* ipiv, double* b, int const ldb, int* info) 
     {
        LAPACK_DGETRS (&trans, &n, &nrhs, a, &lda, ipiv, b, &ldb, info);
     }

     void getrs (char const trans, int const n, int const nrhs, traits::complex_d const* a, int const lda,
                 int const* ipiv, traits::complex_d* b, int const ldb, int* info)
     {
        LAPACK_ZGETRS (&trans, &n, &nrhs, traits::complex_ptr (a), &lda, ipiv, traits::complex_ptr (b), &ldb, info);
     }
(and there are two more functions which call sgetrs and cgetrs). Now we are closer to C/C++ calling convention: array parameters are pointers and scalars are passed by value.

As these overloads are not intended for direct use, they are in the subnamespace detail of boost::numeric::bindings::lapack.

Finally, we can define higher level, generic C++ interface.

Higher level interfaces (bindings) are written in terms of traits classes which are the interface between LAPACK routines and vector and matrix classes. Namely, the idea is to make bindings independent of the concrete vector/matrix libraries as much as possible. LAPACK routines usually require the starting address of the matrix, number of rows and columns and the so-called leading dimension. So, matrix_traits<> class and its specializations for various matrix classes provide these functions and some typedefs. Note that bindings don't know and need not know anything about traits specializations -- e.g. boost/numeric/bindings/traits/ublas_matrix.hpp must be included in your program (if it uses ublas::matrix<>), but not in bindings headers, which include only boost/numeric/bindings/traits/matrix_traits.hpp.

To simplify the use of traits classes, some free accessor functions were introduced, so instead of writing e.g.

     traits::matrix_traits<matrix_type const>::size1 (m)
you can write just
     traits::matrix_size1 (m)

As matrix objects (usually) know about their sizes, we can reduce the number parameters from nine to four[2] (and a return value):

     template <typename MatrA, typename MatrB, typename IVec>
     int getrs (char const trans, MatrA const& a, IVec const& ipiv, MatrB& b)

The heart of this generic function is the call of the one of the functions (depending on the type of array pointers) from the overloaded set:

     int info;
     detail::getrs (trans,  
                    traits::matrix_size1 (a),
                    traits::matrix_size2 (b),
                    traits::matrix_storage (a),
                    traits::leading_dimension (a),
                    traits::vector_storage (ipiv),
                    traits::matrix_storage (b),
                    traits::leading_dimension (b),
                    &info);
using accessor function which through matrix and vector traits classes extract appropriate data (storage addresses and sizes) from matrix and vector objects a, b and ipiv. Function returns info.

Before the call we made some compile-time (matrix structure) and run-time (matching sizes) checks.

Overloaded set and the generic function are defined in gesv.hpp.

In short, addition of a new binding is done in four steps:

  1. using the macro FORTRAN_ID, define names to be used to refer to LAPACK subroutines in C/C++ code;
  2. declare interfaces of LAPACK routines; interfaces are written in terms of pointers to matrix and vector storage and pointers to corresponding sizes;
  3. define a set of overloaded functions which call LAPACK routines (overload resolution is based on the type of matrix elements); parameters are pointers to storage and sizes (their values now, not pointers);
  4. using traits classes and/or free accessor functions to extract storage and size data from matrix and vector objects, define generic function(s) which forward the job to the overloaded functions.

Although not shown (and not needed) in the example, some type names must be known in certain cases. They can be obtained through traits classes, e.g.:

     typedef typename traits::matrix_traits<MatrA>::value_type val_t;
     typedef typename traits::matrix_traits<MatrA>::pointer ptr_t;
     typedef typename traits::matrix_traits<MatrA>::matrix_structure mstruct_t;

2. On compilers which do not support partial template specialisation, traits classes cannot be used. Accessor functions are then (i.e. when macro BOOST_NUMERIC_BINDINGS_POOR_MANS_TRAITS is defined) simple set of overloaded functions (defined in traits/vector_raw.hpp and traits/matrix_raw.hpp). Unfortunately, some of these compilers cannot distinguish functions

     template <typename T, typename F, typename A>
     typename ublas::matrix<T,F,A>::const_pointer matrix_storage (ublas::matrix<T,F,A> const& m); 
and
     template <typename T, typename F, typename A>
     typename ublas::matrix<T,F,A>::pointer matrix_storage (ublas::matrix<T,F,A>& m); 
(boost macro BOOST_NO_FUNCTION_TEMPLATE_ORDERING covers this case).

Therefore we introduced additional function

     template <typename T, typename F, typename A>
     typename ublas::matrix<T,F,A>::const_pointer matrix_storage_const (ublas::matrix<T,F,A> const& m); 
and the call in the generic getrs() is now :o(
         detail::getrs (trans,  
                        traits::matrix_size1 (a),
                        traits::matrix_size2 (b),
     #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
                        traits::matrix_storage (a),
     #else 
                        traits::matrix_storage_const (a),
     #endif
                        traits::leading_dimension (a),
     #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
                        traits::vector_storage (ipiv),
     #else 
                        traits::vector_storage_const (ipiv),
     #endif
                        traits::matrix_storage (b),
                        traits::leading_dimension (b),
                        &info);

If some type name is needed, workaround is e.g.:

         template <typename MatrA>
         void func (M const&l m) {
            // ...
     #ifndef BOOST_NUMERIC_BINDINGS_POOR_MANS_TRAITS
            typedef typename traits::matrix_traits<MatrA>::value_type val_t;
     #else
            typedef typename MatrA::value_type val_t;
     #endif
            // ...
         }
Prerequisite is, of course, that MatrA has value_type defined.


[1] These are thorny issues; see C++ Standards Committee Papers:

    G. Dos Reis: Enhancing Numerical Support

    R. W. Grosse-Kunstleve and D. Abrahams: Predictable Data Layout for Certain Non-Pod Types

[2] First parameter of getrs, char const trans, specifies the form of the system of equations: AX = B, ATX = B or AHX = B. As the form AX = B is the most common, LAPACK Bindings Library also provides version with three parameters:

     template 
     int getrs (MatrA const& a, IVec const& ipiv, MatrB& b) {
        char const no_transpose = 'N';
        return getrs (no_transpose, a, ipiv, b);
     }