Hi!

I am using the Boost uBlas interface for matrices and I'd like to be able to create matrices with the following syntax (or similar):

typedef boost::numeric::ublas::matrix<double> Matrix;  //for clarity

Matrix mat = {[1,1,1],[2,2,2],[3,3,3]};

The actual matrix should be 3x3 and look like the following -
1,1,1
2,2,2
3,3,3


Anything along the same lines would be great, say, {1,1,1; 2,2,2; 3,3,3}. Out of curiosity, is this even possible?

The only way I know how to create a matrix at the moment is by assigning each element individually, which is a bit if a faff even with loops.

Thank you for reading :)

Patrick

Edited 6 Years Ago by pc0019: n/a

Here is the closest solution I can think of (although it's really just string processing as opposed to overloading):

void operator[](char i[]) {
                  int size = strlen(i);
                  int s=0;
                  for(int y=0;y<size;y++) {
                         char num[] = {i[y], '\0'};
                         if(!strcmp(num, ",")) {
                                s++;
                         } else {
                                //puts numbers into an array which is a
                                //member of the class but you can change 
                                //this to put the numbers into the matrix
                                a[s][y%3]=atoi(num);
                         }
                         }

and then you can create a matrix by calling:

myMatrix["123,456,789"];

Edited 6 Years Ago by burgercho: n/a

I guess that would work, but it's not ideal, I might be using floating point numbers. Say,

{1.34345E7,0.0002424;1.01,4.5332323225342}

In which case a string processing method wouldn't be great. And for bigger matrices, rather inefficient. I suppose I could define the size of the matrix first, say,

Matrix mat(2,3);

And then fill the matrix row by row:

mat = {1,1,1,2,2,2,3,3,3};

Again, I don't know how I would do this :(

> Out of curiosity, is this even possible?

Something like this would be possible in C++0x (after a constructor that takes a std::initializer_list<> is added to the ublas matrix). boost::numeric::ublas::matrix mtx { {1,1,1}, {2,2,2}, {3,3,3} } ; Right now, one work around would be to put the initializers for the matrix in a text file and write a function void load_from_stream( boost::numeric::ublas::matrix& mtx, std::istream& stm ) ; This is a very flexible approach; you can run your program on many different data sets by specifying different input files, without having to modify and recompile the code each time.

To enable initialization akin to that for C-style arrays, you have to customize the storage for the matrix. For example,

#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/exception.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <iterator>

using boost::numeric::ublas::matrix ;

// custom ublas storage_array (immutable);
// implemented using a user-supplied c-style 2d array for storage
template< typename T, std::size_t M, std::size_t N >
struct c_array_2d : boost::numeric::ublas::storage_array< c_array_2d<T,M,N> >
{
    typedef std::size_t size_type ;
    typedef std::ptrdiff_t difference_type ;
    typedef const T value_type ;
    typedef const T& reference ;
    typedef const T* pointer ;
    typedef const T& const_reference ;
    typedef const T* const_pointer ;
    typedef const_pointer iterator ;
    typedef const_pointer const_iterator ;
    typedef std::reverse_iterator<iterator> reverse_iterator ;
    typedef std::reverse_iterator<const_iterator> const_reverse_iterator ;

    explicit inline c_array_2d( T(&a)[M][N] ) : array(a) {}

    inline size_type max_size () const { return size() ; }
    inline bool empty() const { return false ; }
    inline size_type size() const { return M*N ; }

    inline const_reference operator [] ( size_type i ) const
    {
        if( i >= size() ) throw boost::numeric::ublas::bad_index() ;
        return array[0][i] ;
    }

    inline iterator begin() { return array[0] ; }
    inline iterator end() { return array[0] + M*N ; }
    inline const_iterator begin() const { return array[0] ; }
    inline const_iterator end() const { return array[0] + M*N ; }
    inline reverse_iterator rbegin() { return reverse_iterator(end()) ; }
    inline reverse_iterator rend() { return reverse_iterator(begin()) ; }
    inline const_reverse_iterator rbegin() const
    { return const_reverse_iterator(end()) ; }
    inline const_reverse_iterator rend() const
    { return const_reverse_iterator(begin()) ; }

    private : T(&array)[M][N] ;
};

// syntactic sugar to enable deduction of template parameters
template< typename T, std::size_t M, std::size_t N > inline
matrix< const T, boost::numeric::ublas::row_major, c_array_2d<T,M,N> >
array2matrix( T(&a)[M][N] )
{
    return matrix< const T, boost::numeric::ublas::row_major,
                   c_array_2d<T,M,N> >( M, N, c_array_2d<T,M,N>(a) ) ;
}

int main()
{
    const double data[][4] =
    { { 1.2, 3.4, 5.6, 7.8 }, { 9.8, 7.6, 5.4, 3.2 }, { 0, 0, 0, 0 } } ;

    matrix<double> mx = array2matrix(data) ;
    std::cout << mx << '\n' ;
}
This article has been dead for over six months. Start a new discussion instead.