uBlas Lapack binds from Sandbox - VC6 workaround
As an introduction; my goal is to link together the uBlas matrix/vector classes with the Intel MKL library (I looked at ATLAS, but the Lapack coverage was insufficient). I have tried the bindings code in the Boost Sandbox (on which Toon and Kresimir are working), but VC6 falls over. I managed to work around the partial template specialisation problem (see my previous postings), thanks to Kresimir's and Toon's feedback. There is however one remaining question I need some help with. First the question; after that I post all the code which I've hacked together to assist other interested users using VC6. Due to my ignorance, I am obliged to pass the orientation as a template parameter to the matrix_traits class. What I would like to do is to obtain this information from the matrix class directly. The issue is that matrix_type::functor_type does not exist for all matrix classes. For example, hermitian, triangular and symmetrix matrix use matrix_type::functor2_type to store the orientation of the matrix. With a good compiler (i.e. *NOT* VC6), one could specialise matrix_traits for these matrix classes (at least that is what I think - but this isn't done yet in the ublas_matrix.hpp file in the Sandbox), here however I'm stuck. As a hack, I allow the orientation to be passed as a template parameter. Is there a better way to do this (the matrix class M knows the orientation already)? // M is type of matrix, RC is the row/column orientation template <typename M, // type of matrix typename RC = boost::numeric::ublas::row_major> struct matrix_traits { public: typedef RC row_column_major; typedef M matrix_type; ... static int stride1 (matrix_type& m) { //return matrix_type::functor_type::one1 (m.size1(), m.size2 ()); return row_column_major::one1 (m.size1(), m.size2()); } ... }; Here is the code I wrote: ---------------------//---------------------- traits.h: // (-*- C++ -*- header) /* * * Copyright (c) Kresimir Fresl and Toon Knapen 2002 * * Permission to copy, modify, use and distribute this software * for any non-commercial or commercial purpose is granted provided * that this license appear on all copies of the software source code. * * Authors assume no responsibility whatsoever for its use and makes * no guarantees about its quality, correctness or reliability. * * First author acknowledges the support of the Faculty of Civil * Engineering, University of Zagreb, Croatia. * * --> Modified/simplified for VC6 */ #ifndef BOOST_NUMERIC_BINDINGS_TRAITS_TRAITS_HPP #define BOOST_NUMERIC_BINDINGS_TRAITS_TRAITS_HPP #include <cstddef> //namespace boost { namespace numeric { namespace bindings { namespace traits { // vector_traits<> base: // .. implementation -- do not use it directly template <typename V, typename T = typename V::value_type> struct default_vector_traits { typedef T value_type; typedef T* pointer; // assumption: iterator==pointer // .. e.g. ublas::(un)bounded_array static pointer storage (V& v) { return v.begin(); } static const T* storage (const V& v) { return v.begin(); } static int size (V& v) { return v.size(); } static int size (const V& v) { return v.size(); } static int stride (V& v) { return 1; } static int stride (const V& v) { return 1; } }; // vector_traits<> generic version: template <typename V> struct vector_traits : default_vector_traits<V> {}; // matrix structure tags: struct general_t {}; struct symmetric_t {}; struct symmetric_packed_t {}; struct hermitian_t {}; struct hermitian_packed_t {}; // triangular, banded etc. struct unknown_structure_t {}; /* // matrix_traits<> generic version: template <typename M> struct matrix_traits { // typedefs: // matrix_structure // value_type // pointer // ordering_type // static functions: // pointer storage() // int storage_size() // int size1() // int size2() // int leading_dimension() // not all matrix types // symmetric/hermitian typedefs: // uplo_type }; */ // storage ordering tags: struct row_major_t {}; struct column_major_t {}; // upper/lower tags: struct upper_t {}; struct lower_t {}; // free accessor functions: template <typename VectorT> inline typename vector_traits<VectorT>::pointer vector_storage (VectorT& v) { return vector_traits<VectorT>::storage (v); } template <typename VectorT> inline int vector_size (VectorT& v) { return vector_traits<VectorT>::size (v); } template <typename VectorT> inline int vector_stride (VectorT& v) { return vector_traits<VectorT>::stride (v); } // All the matrix_traits<MatrixT> code has been removed here ... }}}} #endif // BOOST_NUMERIC_BINDINGS_TRAITS_TRAITS_HPP ---------------------//---------------------- ublas_matrix.h: // (-*- C++ -*- header) /* * * Copyright (c) Kresimir Fresl and Toon Knapen 2002 * * Permission to copy, modify, use and distribute this software * for any non-commercial or commercial purpose is granted provided * that this license appear on all copies of the software source code. * * Authors assume no responsibility whatsoever for its use and makes * no guarantees about its quality, correctness or reliability. * * First author acknowledges the support of the Faculty of Civil * Engineering, University of Zagreb, Croatia. * * --> Modified/simplified for VC6 */ #ifndef BOOST_NUMERIC_BINDINGS_TRAITS_UBLAS_MATRIX_H #define BOOST_NUMERIC_BINDINGS_TRAITS_UBLAS_MATRIX_H #include <boost/numeric/ublas/matrix.hpp> #include "traits.h" namespace boost { namespace numeric { namespace bindings { namespace traits { // Need to find a way to extract the orientation class (row / column) template <typename M, // type of matrix typename RC = boost::numeric::ublas::row_major> // row or column major struct matrix_traits { public: typedef RC row_column_major; typedef general_t matrix_structure; typedef M::value_type value_type; typedef M::value_type *pointer; typedef M matrix_type; static pointer storage (matrix_type& m) { typedef typename matrix_type::array_type array_type; return vector_traits<array_type>::storage (m.data()); } static const value_type *storage (const matrix_type& m) { typedef typename matrix_type::array_type array_type; return vector_traits<array_type>::storage(m.data()); } static int size1 (matrix_type& m) { return m.size1(); } static int size1 (const matrix_type& m) { return m.size1(); } static int size2 (matrix_type& m) { return m.size2(); } static int size2 (const matrix_type& m) { return m.size2(); } static int storage_size (matrix_type& m) { return size1 (m) * size2 (m); } static int storage_size (const matrix_type& m) { return size1 (m) * size2 (m); } // stride1 == distance (m (i, j), m (i+1, j)) static int stride1 (matrix_type& m) { //return matrix_type::functor_type::one1 (m.size1(), m.size2 ()); return row_column_major::one1 (m.size1(), m.size2()); } static int stride1 (const matrix_type& m) { //return matrix_type::functor_type::one1 (m.size1(), m.size2 ()); return row_column_major::one1 (m.size1(), m.size2()); } // stride2 == distance (m (i, j), m (i, j+1)) static int stride2 (matrix_type& m) { //return matrix_type::functor_type::one2 (m.size1(), m.size2 ()); return row_column_major::one2 (m.size1(), m.size2()); } static int stride2 (const matrix_type& m) { //return matrix_type::functor_type::one2 (m.size1(), m.size2 ()); return row_column_major::one2 (m.size1(), m.size2()); } static int leading_dimension (matrix_type& m) { //return matrix_type::functor_type::size2 (m.size1(), m.size2 ()); return row_column_major::size2 (m.size1(), m.size2()); } static int leading_dimension (const matrix_type& m) { //return matrix_type::functor_type::size2 (m.size1(), m.size2 ()); return row_column_major::size2 (m.size1(), m.size2()); } }; }}}} #endif ---------------------//---------------------- boost_mkl_lapack.cpp: namespace ublas = boost::numeric::ublas; #ifdef BOOST_MSVC #pragma warning (disable: 4355) #pragma warning (disable: 4503) #pragma warning (disable: 4786) #endif #define BOOST_UBLAS_USE_EXCEPTIONS #include <iostream> #include <boost/numeric/ublas/matrix.hpp> #include <boost/numeric/ublas/symmetric.hpp> #include <vector> // Intel MKL Lapack #include <mkl/include/mkl_lapack64.h> #include "ublas_matrix.h" // To make life easiertypedef ublas::matrix<double,ublas::row_major> Matrix; typedef std::vector<int> IntVector; template<class M> int getrf(M& a, IntVector& ipiv) { typedef matrix_traits<M> mtraits; typedef vector_traits<IntVector> vtraits; int m = a.size1(); int n = a.size2(); assert(ipiv.size() == (m < n ? m : n)); double *aStorage = mtraits::storage(a); int lda = mtraits::leading_dimension(a); int *ipivStorage = vtraits::storage(ipiv); int info; // return status dgetrf(&m, &n, aStorage, &lda, ipivStorage, &info); return info; } template<class M> int getrs(const M& a, const IntVector& ipiv, M& b, char trans = 'N' ) { typedef matrix_traits<M> mtraits; typedef vector_traits<IntVector> vtraits; int m = a.size1(); int n = a.size1(); assert(ipiv.size() == (m < n ? m : n)); // Note: we need to cast away the const for a and ipiv double *aStorage = const_cast<double*>(mtraits::storage(a)); double *bStorage = mtraits::storage(b); int lda = mtraits::leading_dimension(a); int ldb = mtraits::leading_dimension(b); int *ipivStorage = const_cast<int*>(vtraits::storage(ipiv)); // if b is column major, take size2 (i.e. columns) int nrhs = mtraits::size1(b); int info; // return status dgetrs(&trans, &n, &nrhs, aStorage, &lda, ipivStorage, bStorage, &ldb, &info); return info; } template <typename M> void init_symm (M& m, char uplo = 'f') { size_t n = matrix_traits<M>::size1 (m); for (size_t i = 0; i < n; ++i) { m(i, i) = n; for (size_t j = i + 1; j < n; ++j) { if (uplo == 'u' || uplo == 'U') m(i, j) = n - (j - i); else if (uplo == 'l' || uplo == 'L') m(j, i) = n - (j - i); else m(i, j) = m(j, i) = n - (j - i); } } } // printing: template <typename M> void print_m (const M& m, char const* ch = 0) { if (ch) std::cout << ch << ":\n"; size_t sz1 = matrix_traits<M>::size1 (m); size_t sz2 = matrix_traits<M>::size2 (m); for (std::size_t i = 0 ; i < sz1 ; ++i) { for (std::size_t j = 0 ; j < sz2 ; ++j) std::cout << m(i, j) << " "; std::cout << std::endl; } // std::cout << std::endl; } // printing: template <typename V> void print_v (V const& v, char const* ch = 0) { if (ch) std::cout << ch << ": "; size_t sz = vector_traits<V>::size (v); for (std::size_t i = 0; i < sz; ++i) std::cout << v[i] << " "; std::cout << std::endl; } using std::size_t; void main(void) { size_t n = 3; Matrix a(n, n), acopy(n, n); IntVector ipiv(n); init_symm(a); acopy = a; print_m (a, "A"); // Now factor int status = getrf(a, ipiv); print_v(ipiv, "ipiv"); print_m (a, "A"); // The solution (and the right hand side) are row oriented size_t nrhs = 2; Matrix b(nrhs, n), x(nrhs, n); int i; for(i = 0; i < n; i++) { x(0,i) = (double)i + 1; x(1,i) = (double)i + 4.0; } b = ublas::trans(ublas::prod(acopy, ublas::trans(x))); print_m (b, "b original"); print_m (x, "x original"); status = getrs (a, ipiv, b); // solve from factorization print_m (b, "X"); std::cout << std::endl; // Now try the same for a symmetrix matrix ublas::symmetric_matrix<double, ublas::lower> ml(n, n); init_symm(ml); print_m(ml, "symmetric matrix"); status = getrf(ml, ipiv); print_v(ipiv, "ipiv"); print_m (a, "A"); } You will need your project settings to be such that you link with the Intel lib files and the DLL should be in your path (see Intel MKL documentation). Your link tab in project/settings should contain (the lib directory is set using tools/options, same for the include): mkl_c.lib mkl_p3.lib mkl_lapack.lib You may want to do this in a different namespace than the boost namespace (I actually commented out all the namespace stuff above, but reintroduced it in this posting - if it does not compile, than that's probably the reason). More binds to Lapack still need to be done, but this is a start already. Geert
On Wednesday 23 April 2003 17:48, geert_ceuppens wrote:
Due to my ignorance, I am obliged to pass the orientation as a template parameter to the matrix_traits class. What I would like to do is to obtain this information from the matrix class directly. The issue is that matrix_type::functor_type does not exist for all matrix classes. For example, hermitian, triangular and symmetrix matrix use matrix_type::functor2_type to store the orientation of the matrix. With a good compiler (i.e. *NOT* VC6), one could specialise matrix_traits for these matrix classes (at least that is what I think - but this isn't done yet in the ublas_matrix.hpp file in the Sandbox), here however I'm stuck.
Joerg, Indeed, is'nt there some better nested type to indicate if storage is row_major or column_major ? What about using major_type everywhere ? toon
participants (2)
-
geert_ceuppens
-
Toon Knapen