[shark] 60/79: made the matrix-vector prod a block expression which internally uses kernels::gemv. this required a lot of changes in vector_expression to be able to write stuff like 2*prod(A,v)+b efficiently. namely two new expressions vector_scalar_multiply which multiplies a vector by a scalar and vector_addition which adds two vectors. This is because scalar multiplication can be carried out by gemv efficiently so it makes sense to have plus_assign_to or assign_to take an additional scalar argument. adding two vectors in turn can be carried out by having a add_assign_to statement for each argument, e.g. a+=b+c -> b.add_assign_to(a); c.add_assign_to(a);

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Thu Nov 26 15:41:02 UTC 2015


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to branch master
in repository shark.

commit 1b43f7c5998c17b8d397a2f651e72cf4129fe98a
Author: Oswin <oswin.krause at di.ku.dk>
Date:   Mon Oct 26 08:36:08 2015 +0100

    made the matrix-vector prod a block expression which internally uses kernels::gemv. this required a lot of changes in vector_expression to be able to write stuff like 2*prod(A,v)+b efficiently. namely two new expressions vector_scalar_multiply which multiplies a vector by a scalar and vector_addition which adds two vectors. This is because scalar multiplication can be carried out by gemv efficiently so it makes sense to have plus_assign_to or assign_to take an additional scalar argume [...]
---
 include/shark/LinAlg/BLAS/assignment.hpp        |   2 +-
 include/shark/LinAlg/BLAS/matrix_expression.hpp | 151 +++++--------
 include/shark/LinAlg/BLAS/vector_expression.hpp | 276 ++++++++++++++++++++++--
 3 files changed, 322 insertions(+), 107 deletions(-)

diff --git a/include/shark/LinAlg/BLAS/assignment.hpp b/include/shark/LinAlg/BLAS/assignment.hpp
index 30ccf97..eb95297 100644
--- a/include/shark/LinAlg/BLAS/assignment.hpp
+++ b/include/shark/LinAlg/BLAS/assignment.hpp
@@ -45,7 +45,7 @@ namespace blas {
 ////////////////////////////////////////////////////////////////////////////////////
 	
 namespace detail{
-	template<class VecX, class VecV>
+	template<class VecX, class VecV, class T>
 	void assign(vector_expression<VecX>& x, vector_expression<VecV> const& v,elementwise_tag){
 		kernels::assign(x,v);
 	}
diff --git a/include/shark/LinAlg/BLAS/matrix_expression.hpp b/include/shark/LinAlg/BLAS/matrix_expression.hpp
index 88b1593..5061838 100644
--- a/include/shark/LinAlg/BLAS/matrix_expression.hpp
+++ b/include/shark/LinAlg/BLAS/matrix_expression.hpp
@@ -513,120 +513,85 @@ safe_div(
 	return matrix_binary<E1, E2, functor_type>(e1,e2, functor_type(defaultValue));
 }
 
-template<class E1, class E2, class F>
-class matrix_vector_binary1:
-	public vector_expression<matrix_vector_binary1<E1, E2, F> > {
-
+template<class MatA, class VecV>
+class matrix_vector_prod:
+	public vector_expression<matrix_vector_prod<MatA, VecV> > {
 public:
-	typedef E1 expression1_type;
-	typedef E2 expression2_type;
-	typedef F functor_type;
-	typedef typename E1::const_closure_type expression1_closure_type;
-	typedef typename E2::const_closure_type expression2_closure_type;
-private:
-	typedef matrix_vector_binary1<E1, E2, F> self_type;
+	typedef typename MatA::const_closure_type matrix_closure_type;
+	typedef typename VecV::const_closure_type vector_closure_type;
 public:
 	typedef typename promote_traits<
-		typename E1::size_type, typename E2::size_type
-	>::promote_type size_type;
-	typedef typename promote_traits<
-		typename E1::difference_type, typename E2::difference_type
-	>::promote_type difference_type;
-	typedef typename F::result_type value_type;
-	typedef value_type scalar_type;
-	typedef value_type const_reference;
-	typedef const_reference reference;
-	typedef value_type const* const_pointer;
-	typedef const_pointer pointer;
-
-	typedef typename E1::index_type index_type;
-	typedef typename E1::const_index_pointer const_index_pointer;
-	typedef typename index_pointer<E1>::type index_pointer;
-
-	typedef const self_type const_closure_type;
+		typename MatA::scalar_type,
+		typename VecV::scalar_type
+	>::promote_type scalar_type;
+	typedef scalar_type value_type;
+	typedef typename MatA::size_type size_type;
+	typedef typename MatA::difference_type difference_type;
+	typedef typename MatA::index_type index_type;
+	typedef typename MatA::index_pointer index_pointer;
+	typedef typename MatA::const_index_pointer const_index_pointer;
+
+	typedef matrix_vector_prod<MatA, VecV> const_closure_type;
 	typedef const_closure_type closure_type;
 	typedef unknown_storage_tag storage_category;
-	typedef elementwise_tag evaluation_category;
+	typedef blockwise_tag evaluation_category;
+
+
+	//FIXME: This workaround is required to be able to generate
+	// temporary vectors
+	typedef typename MatA::const_row_iterator const_iterator;
+	typedef const_iterator iterator;
 
 	// Construction and destruction
-	matrix_vector_binary1(const expression1_type &e1, const expression2_type &e2):
-		m_expression1(e1), m_expression2(e2) {}
+	matrix_vector_prod(
+		matrix_closure_type const& matrix,
+		vector_closure_type  const& vector
+	):m_matrix(matrix), m_vector(vector) {}
 
-	// Accessors
 	size_type size() const {
-		return m_expression1.size1();
+		return m_matrix.size1();
 	}
-
-	// Expression accessors
-	const expression1_closure_type &expression1() const {
-		return m_expression1;
+	
+	matrix_closure_type const& matrix() const {
+		return m_matrix;
 	}
-	const expression2_closure_type &expression2() const {
-		return m_expression2;
+	vector_closure_type const& vector() const {
+		return m_vector;
 	}
-
-	// Element access
-	const_reference operator()(index_type i) const {
-		return functor_type::apply(m_expression1, m_expression2, i);
+	
+	//computation kernels
+	template<class VecX>
+	void assign_to(vector_expression<VecX>& x, scalar_type alpha = scalar_type(1) )const{
+		x().clear();
+		plus_assign_to(x,alpha);
 	}
-
-	// Iterator types
-private:
-	typedef typename E1::const_row_iterator const_subrow_iterator_type;
-public:
-	typedef indexed_iterator<const_closure_type> const_iterator;
-	typedef const_iterator iterator;
-
-	const_iterator begin() const {
-		return const_iterator(*this,0);
+	template<class VecX>
+	void plus_assign_to(vector_expression<VecX>& x, scalar_type alpha = scalar_type(1) )const{
+		kernels::gemv(eval_block(m_matrix), eval_block(m_vector), x, alpha);
 	}
-	const_iterator end() const {
-		return const_iterator(*this,size());
+	
+	template<class VecX>
+	void minus_assign_to(vector_expression<VecX>& x, scalar_type alpha = scalar_type(1) )const{
+		kernels::gemv(eval_block(m_matrix), eval_block(m_vector), x, -alpha);
 	}
+	
 private:
-	expression1_closure_type m_expression1;
-	expression2_closure_type m_expression2;
+	matrix_closure_type m_matrix;
+	vector_closure_type m_vector;
 };
 
-template<class E1, class E2>
-struct matrix_vector_binary_traits {
-private:
-	template<class T>
-	struct matrix_vector_prod{
-		typedef T value_type;
-		typedef T result_type;
-
-		template<class U,class V>
-		static result_type apply(
-			const matrix_expression<U> &e1,
-			const vector_expression<V> &e2,
-			std::size_t i
-		) {
-			return inner_prod(row(e1,i),e2);
-		}
-	};
-public:
-	typedef typename E1::value_type T1;
-	typedef typename E2::value_type T2;
-	typedef unknown_storage_tag storage_category;
-	typedef row_major orientation;
-	typedef typename promote_traits<T1, T2>::promote_type promote_type;
-	typedef matrix_vector_binary1<E1, E2, matrix_vector_prod<promote_type> > expression_type;
-	typedef expression_type result_type;
-};
 
-template<class M, class V>
-typename matrix_vector_binary_traits<M,V>::result_type
-prod(matrix_expression<M> const& matrix,vector_expression<V> const& vector){
-	typedef typename matrix_vector_binary_traits<M,V>::expression_type expression;
-	return expression(matrix(),vector());
+/// \brief computes the matrix-vector product x+=Av
+template<class MatA, class VecV>
+matrix_vector_prod<MatA,VecV> prod(matrix_expression<MatA> const& A,vector_expression<VecV> const& v) {
+	return matrix_vector_prod<MatA,VecV>(A(),v());
 }
 
-template<class V, class M>
-typename matrix_vector_binary_traits<matrix_transpose<M const>,V>::result_type
-prod(vector_expression<V> const& vector,matrix_expression<M> const& matrix){
-	typedef typename matrix_vector_binary_traits<matrix_transpose<M const>,V>::expression_type expression;
-	return expression(trans(matrix),vector());
+/// \brief computes the matrix-vector product x+=v^TA
+template<class MatA, class VecV>
+matrix_vector_prod<matrix_transpose<MatA>,VecV> prod(vector_expression<VecV> const& v,matrix_expression<MatA> const& A) {
+	//compute it using the identity (v^TA)^T= A^Tv
+	return matrix_vector_prod<matrix_transpose<MatA>,VecV>(trans(A),v());
 }
 
 //matrix-matrix prod
diff --git a/include/shark/LinAlg/BLAS/vector_expression.hpp b/include/shark/LinAlg/BLAS/vector_expression.hpp
index ad6f39a..f0c0b00 100644
--- a/include/shark/LinAlg/BLAS/vector_expression.hpp
+++ b/include/shark/LinAlg/BLAS/vector_expression.hpp
@@ -9,6 +9,114 @@
 namespace shark {
 namespace blas {
 	
+///\brief Implements multiplications of a vector by a scalar
+template<class E>
+class vector_scalar_multiply:
+	public vector_expression<vector_scalar_multiply <E> > {
+	typedef vector_scalar_multiply<E> self_type;
+public:
+	typedef typename E::const_closure_type expression_closure_type;
+	typedef typename E::size_type size_type;
+	typedef typename E::difference_type difference_type;
+	typedef typename E::value_type value_type;
+	typedef typename E::scalar_type scalar_type;
+	typedef value_type const_reference;
+	typedef value_type reference;
+	typedef value_type const * const_pointer;
+	typedef value_type const*  pointer;
+
+	typedef typename E::index_type index_type;
+	typedef typename E::const_index_pointer const_index_pointer;
+	typedef typename index_pointer<E>::type index_pointer;
+
+	typedef self_type const const_closure_type;
+	typedef self_type closure_type;
+	typedef unknown_storage_tag storage_category;
+	typedef typename E::evaluation_category evaluation_category;
+
+	// Construction and destruction
+	// May be used as mutable expression.
+	vector_scalar_multiply(vector_expression<E> const &e, scalar_type scalar):
+		m_expression(e()), m_scalar(scalar) {}
+
+	// Accessors
+	size_type size() const {
+		return m_expression.size();
+	}
+
+	// Expression accessors
+	expression_closure_type const &expression() const {
+		return m_expression;
+	}
+
+public:
+	// Element access
+	const_reference operator()(index_type i) const {
+		return m_scalar * m_expression(i);
+	}
+
+	const_reference operator[](index_type i) const {
+		return m_scalar * m_expression(i);
+	}
+	
+	
+	//computation kernels
+	template<class VecX>
+	void assign_to(vector_expression<VecX>& x, scalar_type alpha = scalar_type(1) )const{
+		m_expression.assign_to(x,m_scalar*alpha);
+	}
+	template<class VecX>
+	void plus_assign_to(vector_expression<VecX>& x, scalar_type alpha = scalar_type(1) )const{
+		m_expression.plus_assign_to(x,m_scalar*alpha);
+	}
+	
+	template<class VecX>
+	void minus_assign_to(vector_expression<VecX>& x, scalar_type alpha = scalar_type(1) )const{
+		m_expression.minus_assign_to(x,m_scalar*alpha);
+	}
+
+	
+	//iterators
+	typedef transform_iterator<typename E::const_iterator,scalar_multiply1<value_type, scalar_type> > const_iterator;
+	typedef const_iterator iterator;
+	
+	const_iterator begin() const {
+		return const_iterator(m_expression.begin(),scalar_multiply1<value_type, scalar_type>(m_scalar));
+	}
+	const_iterator end() const {
+		return const_iterator(m_expression.end(),scalar_multiply1<value_type, scalar_type>(m_scalar));
+	}
+private:
+	expression_closure_type m_expression;
+	scalar_type m_scalar;
+};
+
+
+template<class T, class E>
+typename boost::enable_if<
+	boost::is_convertible<T, typename E::scalar_type >,
+        vector_scalar_multiply<E>
+>::type
+operator* (vector_expression<E> const& e, T scalar){
+	typedef typename E::scalar_type scalar_type;
+	return vector_scalar_multiply<E>(e, scalar_type(scalar));
+}
+template<class T, class E>
+typename boost::enable_if<
+	boost::is_convertible<T, typename E::scalar_type >,
+        vector_scalar_multiply<E>
+>::type
+operator* (T scalar, vector_expression<E> const& e){
+	typedef typename E::scalar_type scalar_type;
+	return vector_scalar_multiply<E>(e, scalar_type(scalar));//explicit cast prevents warning, alternative would be to template vector_scalar_multiply on T as well
+}
+
+template<class E>
+vector_scalar_multiply<E> operator-(vector_expression<E> const& e){
+	typedef typename E::scalar_type scalar_type;
+	return vector_scalar_multiply<E>(e, scalar_type(-1));//explicit cast prevents warning, alternative would be to template vector_scalar_multiply on T as well
+}
+	
 /// \brief Vector expression representing a constant valued vector.
 template<class T>
 class scalar_vector:public vector_expression<scalar_vector<T> > {
@@ -96,8 +204,6 @@ template<class E, class F>
 class vector_unary:
 	public vector_expression<vector_unary<E, F> > {
 	typedef vector_unary<E, F> self_type;
-	typedef E const expression_type;
-
 public:
 	typedef F functor_type;
 	typedef typename E::const_closure_type expression_closure_type;
@@ -133,6 +239,33 @@ public:
 	expression_closure_type const &expression() const {
 		return m_expression;
 	}
+	
+	//computation kernels
+	template<class VecX>
+	void assign_to(vector_expression<VecX>& x, scalar_type alpha = scalar_type(1) )const{
+		//compute this by first assigning the result of the argument and then applying
+		//the function to every element
+		assign(x,m_expression);
+		typename VecX::iterator end=x().end();
+		for(typename VecX::iterator pos =x().begin(); pos != end; ++pos){
+			*pos= alpha * m_functor(*pos);
+		}
+	}
+	template<class VecX>
+	void plus_assign_to(vector_expression<VecX>& x, scalar_type alpha = scalar_type(1) )const{
+		//First assign result of this expression to a temporary and then perform plus_assignment to x
+		typename vector_temporary<self_type>::type temporary(size());
+		assign_to(temporary,alpha);
+		plus_assign_to(x,temporary);
+	}
+	
+	template<class VecX>
+	void minus_assign_to(vector_expression<VecX>& x, scalar_type alpha = scalar_type(1) )const{
+		//First assign result of this expression to a temporary and then perform minus_assignment to x
+		typename vector_temporary<self_type>::type temporary(size());
+		assign_to(temporary,alpha);
+		minus_assign_to(x,temporary);
+	}
 
 public:
 	// Element access
@@ -168,7 +301,6 @@ name(vector_expression<E> const& e){\
 	typedef F<typename E::value_type> functor_type;\
 	return vector_unary<E, functor_type>(e, functor_type());\
 }
-SHARK_UNARY_VECTOR_TRANSFORMATION(operator-, scalar_negate)
 SHARK_UNARY_VECTOR_TRANSFORMATION(abs, scalar_abs)
 SHARK_UNARY_VECTOR_TRANSFORMATION(log, scalar_log)
 SHARK_UNARY_VECTOR_TRANSFORMATION(exp, scalar_exp)
@@ -198,7 +330,6 @@ name (vector_expression<E> const& e, T scalar){ \
 }
 SHARK_VECTOR_SCALAR_TRANSFORMATION(operator+, scalar_add)
 SHARK_VECTOR_SCALAR_TRANSFORMATION(operator-, scalar_subtract2)
-SHARK_VECTOR_SCALAR_TRANSFORMATION(operator*, scalar_multiply2)
 SHARK_VECTOR_SCALAR_TRANSFORMATION(operator/, scalar_divide)
 SHARK_VECTOR_SCALAR_TRANSFORMATION(operator<, scalar_less_than)
 SHARK_VECTOR_SCALAR_TRANSFORMATION(operator<=, scalar_less_equal_than)
@@ -224,11 +355,130 @@ name (T scalar, vector_expression<E> const& e){ \
 }
 SHARK_VECTOR_SCALAR_TRANSFORMATION_2(operator+, scalar_add)
 SHARK_VECTOR_SCALAR_TRANSFORMATION_2(operator-, scalar_subtract1)
-SHARK_VECTOR_SCALAR_TRANSFORMATION_2(operator*, scalar_multiply1)
 SHARK_VECTOR_SCALAR_TRANSFORMATION_2(min, scalar_min)
 SHARK_VECTOR_SCALAR_TRANSFORMATION_2(max, scalar_max)
 #undef SHARK_VECTOR_SCALAR_TRANSFORMATION_2
 
+template<class E1, class E2>
+class vector_addition: public vector_expression<vector_addition<E1,E2> > {
+private:
+	typedef scalar_binary_plus<
+		typename E1::value_type,
+		typename E2::value_type
+	> functor_type;
+public:
+	typedef std::size_t size_type;
+	typedef std::ptrdiff_t difference_type;
+	typedef typename functor_type::result_type value_type;
+	typedef value_type scalar_type;
+	typedef value_type const_reference;
+	typedef value_type reference;
+	typedef value_type const * const_pointer;
+	typedef value_type const*  pointer;
+
+	typedef typename E1::index_type index_type;
+	typedef typename E1::const_index_pointer const_index_pointer;
+	typedef typename index_pointer<E1>::type index_pointer;
+
+	typedef typename E1::const_closure_type expression_closure1_type;
+	typedef typename E2::const_closure_type expression_closure2_type;
+	
+	typedef vector_addition<E1,E2> const_closure_type;
+	typedef const_closure_type closure_type;
+	typedef unknown_storage_tag storage_category;
+	typedef typename evaluation_restrict_traits<E1,E2>::type evaluation_category;
+
+	// Construction and destruction
+	explicit vector_addition (
+		expression_closure1_type e1, 
+		expression_closure2_type e2
+	):m_expression1(e1),m_expression2(e2){
+		SIZE_CHECK(e1.size() == e2.size());
+	}
+
+	// Accessors
+	size_type size() const {
+		return m_expression1.size();
+	}
+
+	// Expression accessors
+	expression_closure1_type const& expression1() const {
+		return m_expression1;
+	}
+	expression_closure2_type const& expression2() const {
+		return m_expression2;
+	}
+
+	// Element access
+	const_reference operator() (index_type i) const {
+		SIZE_CHECK(i < size());
+		return m_expression1(i) + m_expression2(i);
+	}
+
+	const_reference operator[] (index_type i) const {
+		SIZE_CHECK(i < size());
+		return m_expression1(i) + m_expression2(i);
+	}
+	
+	//computation kernels
+	template<class VecX>
+	void assign_to(vector_expression<VecX>& x, scalar_type alpha = scalar_type(1) )const{
+		assign(x,alpha*m_expression1);
+		plus_assign(x,alpha*m_expression2);
+	}
+	template<class VecX>
+	void plus_assign_to(vector_expression<VecX>& x, scalar_type alpha = scalar_type(1) )const{
+		plus_assign(x,alpha*m_expression1);
+		plus_assign(x,alpha*m_expression2);
+	}
+	
+	template<class VecX>
+	void minus_assign_to(vector_expression<VecX>& x, scalar_type alpha = scalar_type(1) )const{
+		minus_assign(x,alpha*m_expression1);
+		minus_assign(x,alpha*m_expression2);
+	}
+
+	// Iterator types
+	typedef binary_transform_iterator<
+		typename E1::const_iterator,
+		typename E2::const_iterator,
+		functor_type
+	> const_iterator;
+	typedef const_iterator iterator;
+
+	const_iterator begin () const {
+		return const_iterator(functor_type(),
+			m_expression1.begin(),m_expression1.end(),
+			m_expression2.begin(),m_expression2.end()
+		);
+	}
+	const_iterator end() const {
+		return const_iterator(functor_type(),
+			m_expression1.end(),m_expression1.end(),
+			m_expression2.end(),m_expression2.end()
+		);
+	}
+
+private:
+	expression_closure1_type m_expression1;
+	expression_closure2_type m_expression2;
+};
+
+template<class E1, class E2>
+vector_addition<E1, E2 > operator+ (
+	vector_expression<E1> const& e1,
+	vector_expression<E2> const& e2
+){
+	return vector_addition<E1, E2>(e1(),e2());
+}
+template<class E1, class E2>
+vector_addition<E1, vector_scalar_multiply<E2> > operator- (
+	vector_expression<E1> const& e1,
+	vector_expression<E2> const& e2
+){
+	return vector_addition<E1, vector_scalar_multiply<E2> >(e1(),-e2());
+}
+
 
 template<class E1, class E2, class F>
 class vector_binary:
@@ -297,7 +547,9 @@ public:
 	// Iterator enhances the iterator of the referenced expressions
 	// with the unary functor.
 	typedef binary_transform_iterator<
-		typename E1::const_iterator,typename E2::const_iterator,functor_type
+		typename E1::const_iterator,
+		typename E2::const_iterator,
+		functor_type
 	> const_iterator;
 	typedef const_iterator iterator;
 
@@ -327,8 +579,6 @@ name(vector_expression<E1> const& e1, vector_expression<E2> const& e2){\
 	typedef F<typename E1::value_type, typename E2::value_type> functor_type;\
 	return vector_binary<E1, E2, functor_type>(e1(),e2(), functor_type());\
 }
-SHARK_BINARY_VECTOR_EXPRESSION(operator+, scalar_binary_plus)
-SHARK_BINARY_VECTOR_EXPRESSION(operator-, scalar_binary_minus)
 SHARK_BINARY_VECTOR_EXPRESSION(operator*, scalar_binary_multiply)
 SHARK_BINARY_VECTOR_EXPRESSION(element_prod, scalar_binary_multiply)
 SHARK_BINARY_VECTOR_EXPRESSION(operator/, scalar_binary_divide)
@@ -417,14 +667,14 @@ soft_max(const vector_expression<E> &e) {
 template<class E>
 typename real_traits<typename E::value_type >::type
 norm_1(const vector_expression<E> &e) {
-	return sum(abs(e));
+	return sum(abs(eval_block(e)));
 }
 
 /// \brief norm_2 v = sum_i |v_i|^2
 template<class E>
 typename real_traits<typename E::value_type >::type
 norm_sqr(const vector_expression<E> &e) {
-	return sum(abs_sqr(e));
+	return sum(abs_sqr(eval_block(e)));
 }
 
 /// \brief norm_2 v = sqrt (sum_i |v_i|^2 )
@@ -439,13 +689,13 @@ norm_2(const vector_expression<E> &e) {
 template<class E>
 typename real_traits<typename E::value_type >::type
 norm_inf(vector_expression<E> const &e){
-	return max(abs(e));
+	return max(abs(eval_block(e)));
 }
 
 /// \brief index_norm_inf v = arg max_i |v_i|
 template<class E>
 std::size_t index_norm_inf(vector_expression<E> const &e){
-	return arg_max(abs(e));
+	return arg_max(abs(eval_block(e)));
 }
 
 // inner_prod (v1, v2) = sum_i v1_i * v2_i
@@ -463,7 +713,7 @@ inner_prod(
 		typename E2::value_type
 	>::promote_type value_type;
 	value_type result = value_type();
-	kernels::dot(e1,e2,result);
+	kernels::dot(eval_block(e1),eval_block(e2),result);
 	return result;
 }
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/shark.git



More information about the debian-science-commits mailing list