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

Dani AI

Generated

The thread shows two common routes: ad‑hoc parsing (as sketched) and deeper changes to uBLAS storage (as outlined). For practical, maintainable code there are two lower‑effort options that avoid invasive hacks.

A small factory that takes a flat container (or a vector-of-rows) and fills a uBLAS matrix keeps the logic local and explicit:

#include <boost/numeric/ublas/matrix.hpp>
#include <vector>
#include <stdexcept>

boost::numeric::ublas::matrix<double> make_matrix_from_flat(std::size_t rows,
                                                           std::size_t cols,
                                                           const std::vector<double>& v)
{
    if (v.size() != rows * cols) throw std::invalid_argument("size mismatch");
    boost::numeric::ublas::matrix<double> m(rows, cols);
    for (std::size_t i = 0, k = 0; i < rows; ++i)
        for (std::size_t j = 0; j < cols; ++j, ++k)
            m(i, j) = v[k];
    return m;
}

/* usage:
auto mat = make_matrix_from_flat(3, 3, std::vector<double>{1,1,1, 2,2,2, 3,3,3});
*/

If concise literal syntax is the main goal and changing libraries is acceptable, consider Eigen, which provides a compact initializer via operator<<:

#include <Eigen/Dense>

Eigen::MatrixXd m(3,3);
m << 1,1,1,
     2,2,2,
     3,3,3;

Notes and cautions:

  • Parsing strings (the route in ) works but is fragile for floats and large inputs.
  • Custom storage (the route in ) can be zero‑copy but is more invasive and harder to maintain.
  • For large matrices, measure whether element-wise assignment or bulk copy into contiguous storage is faster; pick row‑major storage if contiguous layout is required.
  • Check current Boost.uBLAS releases — newer convenience constructors or helper utilities may exist.

These approaches provide readable, testable ways to get literal-style initialization without modifying library internals.

Recommended Answers

All 3 Replies

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"];

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' ;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.