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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.