Re: Matrix with vector interface.
"Oswin Krause" <[email protected]>
| Newsgroups | gmane.comp.lib.boost.ublas |
|---|---|
| Message-ID | <[email protected]> |
Hi, Here is my slightly adapted version of the range. I didn't find the boost coding guidelines so i just tried to fit it to other ublas headers(with limited success). Since i am not breathing standardese, I am not sure whether i am 100% correct in every aspect. Out of standard reasons, the implementation using proxy objects like matrix_row does not lead to a random_access_iterator even though it meets all traversal requirements. So algorithms like random_shuffle(and sort(?)) will work in practice but overeager compilers as for example MSVC will complain in debug mode. A solution to this is lying about the iterator category, but since i am a honest person, i don't ;) the implementation comes with a short test case, but i can also add a bit more if required. ---- Than maybe a note should be added to the documentation stating that uBLAS is outdated and should not be used for new projects. Maybe this leads to a bit of drive to the development ;). Even though i would volunteer to work on a new version and already have some ideas, uBLAS is just too big for me. It surpasses most BLAS Libraries in the amount features while calling itself "micro"-BLAS. (I think, this is one of the main sources of the problem. remove half of the features, call it nano-BLAS and ensure a good implementation). Gretings, Oswin On 2012-09-21 23:51, Gunter Winkler wrote: > Hello, > > Am Tuesday 18 September 2012 schrieb Oswin Krause: >> Hi, >> >> > Regarding uBlas: Long time ago there was a design decision to not >> > handle >> > a matrix as a set of vectors in order to avoid bad surprises when >> > playing with the storage layout and iteration order. However, I'd >> > gladly >> > accept a new matrix view as list of vectors using boost:range . >> >> So a matrix which also behaves as a range? or just a range adaptor >> which maps a matrix_expression to a range_of_vectors which isn't >> interpreted as matrix_expression anymore? > > 2nd option sounds good. > >> Having said that: are there any plans for an ublas2? Or something >> like that? At the moment the advise i hear a lot from people having >> looked at ublas is: "don't use it. There are many better libraries >> our there". I don't think that this is an ideal state for a boost >> library :/. > > Yes, you're right: > * The uBLAS code is more than 10 years old, and little progress was > made > during last 5 years. > * There is no active developer (just check the list of open issues > ^^) > * There is no active maintainer (There is a good chance that I > "disappear" again when 1.52 is done ...) > * There are really good alternatives out there which outperform uBLAS > by > far > > Thus we are stuck unless we find a university which develops yet > another > matrix library (compatible to uBLAS interface) or starts a full > rewrite > of uBLAS' internal logic. > > mfg > Gunter _______________________________________________ ublas mailing list [email protected] http://lists.boost.org/mailman/listinfo.cgi/ublas Sent to: [email protected]
matrix_vector_range.cpp
(text/x-c, 3.2 KB)
#define BOOST_TEST_MODULE UBLAS_MATRIX_VECTOR_RANGE_TEST
#include <boost/test/included/unit_test.hpp>
#include "matrix_vector_range.hpp"
#include <boost/numeric/ublas/matrix.hpp>
#include <iterator>
using namespace boost::numeric;
BOOST_AUTO_TEST_CASE( matrix_range_test ){
std::size_t const rows=5;
std::size_t columns=3;
ublas::matrix<int> int_matrix(rows,columns);
for(std::size_t i = 0; i != rows; ++i){
for(std::size_t j = 0; j != columns; ++j){
int_matrix(i,j)=i*rows+j;
}
}
ublas::matrix<int> const& const_int_matrix=int_matrix;
typedef ublas::matrix_row_range<ublas::matrix<int> > RR;
typedef ublas::matrix_row_range<ublas::matrix<int> const> CRR;
typedef ublas::matrix_column_range<ublas::matrix<int> > CR;
typedef ublas::matrix_column_range<ublas::matrix<int> const > CCR;
RR row_range = make_row_range(int_matrix);
CRR const_row_range = make_row_range(const_int_matrix);
CR column_range = make_column_range(int_matrix);
CCR const_column_range = make_column_range(const_int_matrix);
//check whether ranges have the correct sizes
BOOST_REQUIRE_EQUAL(row_range.size(),rows);
BOOST_REQUIRE_EQUAL(const_row_range.size(),rows);
BOOST_REQUIRE_EQUAL(column_range.size(),columns);
BOOST_REQUIRE_EQUAL(const_column_range.size(),columns);
//now test element access, this should entail everything else
std::size_t row = 0;
for(RR::iterator iter=row_range.begin(); iter != row_range.end();++iter,++row){
BOOST_REQUIRE_EQUAL(iter->size(),columns);
for(std::size_t j =0; j != columns; ++j){
BOOST_CHECK_EQUAL((*iter)(j),int_matrix(row,j));
}
}
row = 0;
for(CRR::iterator iter=const_row_range.begin(); iter != const_row_range.end();++iter,++row){
BOOST_REQUIRE_EQUAL(iter->size(),columns);
for(std::size_t j =0; j != columns; ++j){
BOOST_CHECK_EQUAL((*iter)(j),int_matrix(row,j));
}
}
std::size_t column = 0;
for(CR::iterator iter=column_range.begin(); iter != column_range.end();++iter,++column){
BOOST_REQUIRE_EQUAL(iter->size(),rows);
for(std::size_t i =0; i != rows; ++i){
BOOST_CHECK_EQUAL((*iter)(i),int_matrix(i,column));
}
}
column = 0;
for(CCR::iterator iter=const_column_range.begin(); iter != const_column_range.end();++iter,++column){
BOOST_REQUIRE_EQUAL(iter->size(),rows);
for(std::size_t i =0; i != rows; ++i){
BOOST_CHECK_EQUAL((*iter)(i),int_matrix(i,column));
}
}
}
//sanity test to ensure that std::iter_swap does not fail on the tested platform(burned child...)
BOOST_AUTO_TEST_CASE( matrix_range_sanity_iter_swap ){
ublas::matrix<int> int_matrix(2,2);
int_matrix(0,0) = 0; int_matrix(0,1) = 1;
int_matrix(1,0) = 2; int_matrix(1,1) = 3;
ublas::matrix_row_range<ublas::matrix<int> > row_range(int_matrix);
ublas::matrix_column_range<ublas::matrix<int> > column_range(int_matrix);
std::iter_swap(row_range.begin(),row_range.begin()+1);
BOOST_CHECK_EQUAL(int_matrix(0,0),2u);
BOOST_CHECK_EQUAL(int_matrix(0,1),3u);
BOOST_CHECK_EQUAL(int_matrix(1,0),0u);
BOOST_CHECK_EQUAL(int_matrix(1,1),1u);
std::iter_swap(column_range.begin(),column_range.begin()+1);
BOOST_CHECK_EQUAL(int_matrix(0,0),3u);
BOOST_CHECK_EQUAL(int_matrix(0,1),2u);
BOOST_CHECK_EQUAL(int_matrix(1,0),1u);
BOOST_CHECK_EQUAL(int_matrix(1,1),0u);
}
matrix_vector_range.hpp
(text/x-c++, 4.3 KB)
// Copyright (c) 2012
// Oswin Krause
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_UBLAS_MATRIX_VECTOR_RANGE_HPP
#define BOOST_UBLAS_MATRIX_VECTOR_RANGE_HPP
#include <boost/numeric/ublas/matrix_proxy.hpp>//for matrix_row, matrix_column and matrix_expression
#include <boost/numeric/ublas/vector.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/utility/enable_if.hpp>
namespace boost { namespace numeric { namespace ublas {
namespace detail{
/// \brief Iterator which represents a matrix as a range of row/column-vectors
///
/// The scond argument is the reference to a matrix_row/matrix_column.
/// Whatever type used, it must offer a constructor Reference(sequence,i)
/// which constructs a reference to the i-th proxy-element
/// This iterator is invalidated when the underlying matrix is resized.
template<class Matrix, class Reference>
struct matrix_vector_iterator: public boost::iterator_facade<
matrix_vector_iterator<Matrix,Reference>,
typename vector_temporary_traits<Reference>::type,
boost::random_access_traversal_tag,
Reference
>{
public:
matrix_vector_iterator(){}
///\brief constructs a matrix_vector_iterator as pointing to the i-th proxy
matrix_vector_iterator(Matrix& matrix, std::size_t position)
: matrix_(&matrix),position_(position) {}
template<class M, class R>
matrix_vector_iterator(matrix_vector_iterator<M,R> const& other)
: matrix_(other.matrix_),position_(other.position_) {}
private:
friend class boost::iterator_core_access;
template <class M,class R> friend class matrix_vector_iterator;
void increment() {
++position_;
}
void decrement() {
--position_;
}
void advance(std::ptrdiff_t n){
position_ += n;
}
template<class M,class R>
std::ptrdiff_t distance_to(matrix_vector_iterator<M,R> const& other) const{
BOOST_UBLAS_CHECK (matrix_ == other.matrix_, external_logic ());
return (std::ptrdiff_t)other.position_ - (std::ptrdiff_t)position_;
}
template<class M,class R>
bool equal(matrix_vector_iterator<M,R> const& other) const{
BOOST_UBLAS_CHECK (matrix_ == other.matrix_, external_logic ());
return (position_ == other.position_);
}
Reference dereference() const {
return Reference(*matrix_,position_);
}
Matrix* matrix_;//no matrix_closure here to ensure easy usage
std::size_t position_;
};
}
///\brief Represents a Matrix as range of row vectors.
template<class Matrix>
class matrix_row_range
: public boost::iterator_range<detail::matrix_vector_iterator<Matrix,matrix_row<Matrix> > >{
private:
typedef detail::matrix_vector_iterator<Matrix,matrix_row<Matrix> > iterator_type;
typedef boost::iterator_range<iterator_type> base_type;
public:
matrix_row_range(Matrix& matrix)
:base_type(iterator_type(matrix,0),iterator_type(matrix,matrix.size1())){}
};
///\brief convenience function to create matrix_row_ranges.
template<class Matrix>
matrix_row_range<Matrix> make_row_range(matrix_expression<Matrix>& matrix){
return matrix_row_range<Matrix>(matrix());
}
///\brief convenience function to create matrix_row_ranges.
template<class Matrix>
matrix_row_range<Matrix const> make_row_range(matrix_expression<Matrix> const& matrix){
return matrix_row_range<Matrix const>(matrix());
}
///\brief Represents a Matrix as range of column vectors.
template<class Matrix >
class matrix_column_range
: public boost::iterator_range<detail::matrix_vector_iterator<Matrix,matrix_column<Matrix> > >{
private:
typedef detail::matrix_vector_iterator<Matrix,matrix_column<Matrix> > iterator_type;
typedef boost::iterator_range<iterator_type> base_type;
public:
matrix_column_range(Matrix& matrix)
:base_type(iterator_type(matrix,0),iterator_type(matrix,matrix.size2())){}
};
///\brief convenience function to create matrix_row_ranges.
template<class Matrix>
matrix_column_range<Matrix> make_column_range(matrix_expression<Matrix>& matrix){
return matrix_column_range<Matrix>(matrix());
}
///\brief convenience function to create matrix_row_ranges.
template<class Matrix>
matrix_column_range<Matrix const> make_column_range(matrix_expression<Matrix> const& matrix){
return matrix_column_range<Matrix const>(matrix());
}
}}}
#endif