整理
This commit is contained in:
1288
include/boost/numeric/ublas/assignment.hpp
Normal file
1288
include/boost/numeric/ublas/assignment.hpp
Normal file
File diff suppressed because it is too large
Load Diff
2372
include/boost/numeric/ublas/banded.hpp
Normal file
2372
include/boost/numeric/ublas/banded.hpp
Normal file
File diff suppressed because it is too large
Load Diff
499
include/boost/numeric/ublas/blas.hpp
Normal file
499
include/boost/numeric/ublas/blas.hpp
Normal file
@@ -0,0 +1,499 @@
|
||||
// Copyright (c) 2000-2011 Joerg Walter, Mathias Koch, David Bellot
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
|
||||
#ifndef _BOOST_UBLAS_BLAS_
|
||||
#define _BOOST_UBLAS_BLAS_
|
||||
|
||||
#include <boost/numeric/ublas/traits.hpp>
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
|
||||
/** Interface and implementation of BLAS level 1
|
||||
* This includes functions which perform \b vector-vector operations.
|
||||
* More information about BLAS can be found at
|
||||
* <a href="http://en.wikipedia.org/wiki/BLAS">http://en.wikipedia.org/wiki/BLAS</a>
|
||||
*/
|
||||
namespace blas_1 {
|
||||
|
||||
/** 1-Norm: \f$\sum_i |x_i|\f$ (also called \f$\mathcal{L}_1\f$ or Manhattan norm)
|
||||
*
|
||||
* \param v a vector or vector expression
|
||||
* \return the 1-Norm with type of the vector's type
|
||||
*
|
||||
* \tparam V type of the vector (not needed by default)
|
||||
*/
|
||||
template<class V>
|
||||
typename type_traits<typename V::value_type>::real_type
|
||||
asum (const V &v) {
|
||||
return norm_1 (v);
|
||||
}
|
||||
|
||||
/** 2-Norm: \f$\sum_i |x_i|^2\f$ (also called \f$\mathcal{L}_2\f$ or Euclidean norm)
|
||||
*
|
||||
* \param v a vector or vector expression
|
||||
* \return the 2-Norm with type of the vector's type
|
||||
*
|
||||
* \tparam V type of the vector (not needed by default)
|
||||
*/
|
||||
template<class V>
|
||||
typename type_traits<typename V::value_type>::real_type
|
||||
nrm2 (const V &v) {
|
||||
return norm_2 (v);
|
||||
}
|
||||
|
||||
/** Infinite-norm: \f$\max_i |x_i|\f$ (also called \f$\mathcal{L}_\infty\f$ norm)
|
||||
*
|
||||
* \param v a vector or vector expression
|
||||
* \return the Infinite-Norm with type of the vector's type
|
||||
*
|
||||
* \tparam V type of the vector (not needed by default)
|
||||
*/
|
||||
template<class V>
|
||||
typename type_traits<typename V::value_type>::real_type
|
||||
amax (const V &v) {
|
||||
return norm_inf (v);
|
||||
}
|
||||
|
||||
/** Inner product of vectors \f$v_1\f$ and \f$v_2\f$
|
||||
*
|
||||
* \param v1 first vector of the inner product
|
||||
* \param v2 second vector of the inner product
|
||||
* \return the inner product of the type of the most generic type of the 2 vectors
|
||||
*
|
||||
* \tparam V1 type of first vector (not needed by default)
|
||||
* \tparam V2 type of second vector (not needed by default)
|
||||
*/
|
||||
template<class V1, class V2>
|
||||
typename promote_traits<typename V1::value_type, typename V2::value_type>::promote_type
|
||||
dot (const V1 &v1, const V2 &v2) {
|
||||
return inner_prod (v1, v2);
|
||||
}
|
||||
|
||||
/** Copy vector \f$v_2\f$ to \f$v_1\f$
|
||||
*
|
||||
* \param v1 target vector
|
||||
* \param v2 source vector
|
||||
* \return a reference to the target vector
|
||||
*
|
||||
* \tparam V1 type of first vector (not needed by default)
|
||||
* \tparam V2 type of second vector (not needed by default)
|
||||
*/
|
||||
template<class V1, class V2>
|
||||
V1 & copy (V1 &v1, const V2 &v2)
|
||||
{
|
||||
return v1.assign (v2);
|
||||
}
|
||||
|
||||
/** Swap vectors \f$v_1\f$ and \f$v_2\f$
|
||||
*
|
||||
* \param v1 first vector
|
||||
* \param v2 second vector
|
||||
*
|
||||
* \tparam V1 type of first vector (not needed by default)
|
||||
* \tparam V2 type of second vector (not needed by default)
|
||||
*/
|
||||
template<class V1, class V2>
|
||||
void swap (V1 &v1, V2 &v2)
|
||||
{
|
||||
v1.swap (v2);
|
||||
}
|
||||
|
||||
/** scale vector \f$v\f$ with scalar \f$t\f$
|
||||
*
|
||||
* \param v vector to be scaled
|
||||
* \param t the scalar
|
||||
* \return \c t*v
|
||||
*
|
||||
* \tparam V type of the vector (not needed by default)
|
||||
* \tparam T type of the scalar (not needed by default)
|
||||
*/
|
||||
template<class V, class T>
|
||||
V & scal (V &v, const T &t)
|
||||
{
|
||||
return v *= t;
|
||||
}
|
||||
|
||||
/** Compute \f$v_1= v_1 + t.v_2\f$
|
||||
*
|
||||
* \param v1 target and first vector
|
||||
* \param t the scalar
|
||||
* \param v2 second vector
|
||||
* \return a reference to the first and target vector
|
||||
*
|
||||
* \tparam V1 type of the first vector (not needed by default)
|
||||
* \tparam T type of the scalar (not needed by default)
|
||||
* \tparam V2 type of the second vector (not needed by default)
|
||||
*/
|
||||
template<class V1, class T, class V2>
|
||||
V1 & axpy (V1 &v1, const T &t, const V2 &v2)
|
||||
{
|
||||
return v1.plus_assign (t * v2);
|
||||
}
|
||||
|
||||
/** Performs rotation of points in the plane and assign the result to the first vector
|
||||
*
|
||||
* Each point is defined as a pair \c v1(i) and \c v2(i), being respectively
|
||||
* the \f$x\f$ and \f$y\f$ coordinates. The parameters \c t1 and \t2 are respectively
|
||||
* the cosine and sine of the angle of the rotation.
|
||||
* Results are not returned but directly written into \c v1.
|
||||
*
|
||||
* \param t1 cosine of the rotation
|
||||
* \param v1 vector of \f$x\f$ values
|
||||
* \param t2 sine of the rotation
|
||||
* \param v2 vector of \f$y\f$ values
|
||||
*
|
||||
* \tparam T1 type of the cosine value (not needed by default)
|
||||
* \tparam V1 type of the \f$x\f$ vector (not needed by default)
|
||||
* \tparam T2 type of the sine value (not needed by default)
|
||||
* \tparam V2 type of the \f$y\f$ vector (not needed by default)
|
||||
*/
|
||||
template<class T1, class V1, class T2, class V2>
|
||||
void rot (const T1 &t1, V1 &v1, const T2 &t2, V2 &v2)
|
||||
{
|
||||
typedef typename promote_traits<typename V1::value_type, typename V2::value_type>::promote_type promote_type;
|
||||
vector<promote_type> vt (t1 * v1 + t2 * v2);
|
||||
v2.assign (- t2 * v1 + t1 * v2);
|
||||
v1.assign (vt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** \brief Interface and implementation of BLAS level 2
|
||||
* This includes functions which perform \b matrix-vector operations.
|
||||
* More information about BLAS can be found at
|
||||
* <a href="http://en.wikipedia.org/wiki/BLAS">http://en.wikipedia.org/wiki/BLAS</a>
|
||||
*/
|
||||
namespace blas_2 {
|
||||
|
||||
/** \brief multiply vector \c v with triangular matrix \c m
|
||||
*
|
||||
* \param v a vector
|
||||
* \param m a triangular matrix
|
||||
* \return the result of the product
|
||||
*
|
||||
* \tparam V type of the vector (not needed by default)
|
||||
* \tparam M type of the matrix (not needed by default)
|
||||
*/
|
||||
template<class V, class M>
|
||||
V & tmv (V &v, const M &m)
|
||||
{
|
||||
return v = prod (m, v);
|
||||
}
|
||||
|
||||
/** \brief solve \f$m.x = v\f$ in place, where \c m is a triangular matrix
|
||||
*
|
||||
* \param v a vector
|
||||
* \param m a matrix
|
||||
* \param C (this parameter is not needed)
|
||||
* \return a result vector from the above operation
|
||||
*
|
||||
* \tparam V type of the vector (not needed by default)
|
||||
* \tparam M type of the matrix (not needed by default)
|
||||
* \tparam C n/a
|
||||
*/
|
||||
template<class V, class M, class C>
|
||||
V & tsv (V &v, const M &m, C)
|
||||
{
|
||||
return v = solve (m, v, C ());
|
||||
}
|
||||
|
||||
/** \brief compute \f$ v_1 = t_1.v_1 + t_2.(m.v_2)\f$, a general matrix-vector product
|
||||
*
|
||||
* \param v1 a vector
|
||||
* \param t1 a scalar
|
||||
* \param t2 another scalar
|
||||
* \param m a matrix
|
||||
* \param v2 another vector
|
||||
* \return the vector \c v1 with the result from the above operation
|
||||
*
|
||||
* \tparam V1 type of first vector (not needed by default)
|
||||
* \tparam T1 type of first scalar (not needed by default)
|
||||
* \tparam T2 type of second scalar (not needed by default)
|
||||
* \tparam M type of matrix (not needed by default)
|
||||
* \tparam V2 type of second vector (not needed by default)
|
||||
*/
|
||||
template<class V1, class T1, class T2, class M, class V2>
|
||||
V1 & gmv (V1 &v1, const T1 &t1, const T2 &t2, const M &m, const V2 &v2)
|
||||
{
|
||||
return v1 = t1 * v1 + t2 * prod (m, v2);
|
||||
}
|
||||
|
||||
/** \brief Rank 1 update: \f$ m = m + t.(v_1.v_2^T)\f$
|
||||
*
|
||||
* \param m a matrix
|
||||
* \param t a scalar
|
||||
* \param v1 a vector
|
||||
* \param v2 another vector
|
||||
* \return a matrix with the result from the above operation
|
||||
*
|
||||
* \tparam M type of matrix (not needed by default)
|
||||
* \tparam T type of scalar (not needed by default)
|
||||
* \tparam V1 type of first vector (not needed by default)
|
||||
* \tparam V2type of second vector (not needed by default)
|
||||
*/
|
||||
template<class M, class T, class V1, class V2>
|
||||
M & gr (M &m, const T &t, const V1 &v1, const V2 &v2)
|
||||
{
|
||||
#ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
|
||||
return m += t * outer_prod (v1, v2);
|
||||
#else
|
||||
return m = m + t * outer_prod (v1, v2);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \brief symmetric rank 1 update: \f$m = m + t.(v.v^T)\f$
|
||||
*
|
||||
* \param m a matrix
|
||||
* \param t a scalar
|
||||
* \param v a vector
|
||||
* \return a matrix with the result from the above operation
|
||||
*
|
||||
* \tparam M type of matrix (not needed by default)
|
||||
* \tparam T type of scalar (not needed by default)
|
||||
* \tparam V type of vector (not needed by default)
|
||||
*/
|
||||
template<class M, class T, class V>
|
||||
M & sr (M &m, const T &t, const V &v)
|
||||
{
|
||||
#ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
|
||||
return m += t * outer_prod (v, v);
|
||||
#else
|
||||
return m = m + t * outer_prod (v, v);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \brief hermitian rank 1 update: \f$m = m + t.(v.v^H)\f$
|
||||
*
|
||||
* \param m a matrix
|
||||
* \param t a scalar
|
||||
* \param v a vector
|
||||
* \return a matrix with the result from the above operation
|
||||
*
|
||||
* \tparam M type of matrix (not needed by default)
|
||||
* \tparam T type of scalar (not needed by default)
|
||||
* \tparam V type of vector (not needed by default)
|
||||
*/
|
||||
template<class M, class T, class V>
|
||||
M & hr (M &m, const T &t, const V &v)
|
||||
{
|
||||
#ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
|
||||
return m += t * outer_prod (v, conj (v));
|
||||
#else
|
||||
return m = m + t * outer_prod (v, conj (v));
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \brief symmetric rank 2 update: \f$ m=m+ t.(v_1.v_2^T + v_2.v_1^T)\f$
|
||||
*
|
||||
* \param m a matrix
|
||||
* \param t a scalar
|
||||
* \param v1 a vector
|
||||
* \param v2 another vector
|
||||
* \return a matrix with the result from the above operation
|
||||
*
|
||||
* \tparam M type of matrix (not needed by default)
|
||||
* \tparam T type of scalar (not needed by default)
|
||||
* \tparam V1 type of first vector (not needed by default)
|
||||
* \tparam V2type of second vector (not needed by default)
|
||||
*/
|
||||
template<class M, class T, class V1, class V2>
|
||||
M & sr2 (M &m, const T &t, const V1 &v1, const V2 &v2)
|
||||
{
|
||||
#ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
|
||||
return m += t * (outer_prod (v1, v2) + outer_prod (v2, v1));
|
||||
#else
|
||||
return m = m + t * (outer_prod (v1, v2) + outer_prod (v2, v1));
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \brief hermitian rank 2 update: \f$m=m+t.(v_1.v_2^H) + v_2.(t.v_1)^H)\f$
|
||||
*
|
||||
* \param m a matrix
|
||||
* \param t a scalar
|
||||
* \param v1 a vector
|
||||
* \param v2 another vector
|
||||
* \return a matrix with the result from the above operation
|
||||
*
|
||||
* \tparam M type of matrix (not needed by default)
|
||||
* \tparam T type of scalar (not needed by default)
|
||||
* \tparam V1 type of first vector (not needed by default)
|
||||
* \tparam V2type of second vector (not needed by default)
|
||||
*/
|
||||
template<class M, class T, class V1, class V2>
|
||||
M & hr2 (M &m, const T &t, const V1 &v1, const V2 &v2)
|
||||
{
|
||||
#ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
|
||||
return m += t * outer_prod (v1, conj (v2)) + type_traits<T>::conj (t) * outer_prod (v2, conj (v1));
|
||||
#else
|
||||
return m = m + t * outer_prod (v1, conj (v2)) + type_traits<T>::conj (t) * outer_prod (v2, conj (v1));
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** \brief Interface and implementation of BLAS level 3
|
||||
* This includes functions which perform \b matrix-matrix operations.
|
||||
* More information about BLAS can be found at
|
||||
* <a href="http://en.wikipedia.org/wiki/BLAS">http://en.wikipedia.org/wiki/BLAS</a>
|
||||
*/
|
||||
namespace blas_3 {
|
||||
|
||||
/** \brief triangular matrix multiplication \f$m_1=t.m_2.m_3\f$ where \f$m_2\f$ and \f$m_3\f$ are triangular
|
||||
*
|
||||
* \param m1 a matrix for storing result
|
||||
* \param t a scalar
|
||||
* \param m2 a triangular matrix
|
||||
* \param m3 a triangular matrix
|
||||
* \return the matrix \c m1
|
||||
*
|
||||
* \tparam M1 type of the result matrix (not needed by default)
|
||||
* \tparam T type of the scalar (not needed by default)
|
||||
* \tparam M2 type of the first triangular matrix (not needed by default)
|
||||
* \tparam M3 type of the second triangular matrix (not needed by default)
|
||||
*
|
||||
*/
|
||||
template<class M1, class T, class M2, class M3>
|
||||
M1 & tmm (M1 &m1, const T &t, const M2 &m2, const M3 &m3)
|
||||
{
|
||||
return m1 = t * prod (m2, m3);
|
||||
}
|
||||
|
||||
/** \brief triangular solve \f$ m_2.x = t.m_1\f$ in place, \f$m_2\f$ is a triangular matrix
|
||||
*
|
||||
* \param m1 a matrix
|
||||
* \param t a scalar
|
||||
* \param m2 a triangular matrix
|
||||
* \param C (not used)
|
||||
* \return the \f$m_1\f$ matrix
|
||||
*
|
||||
* \tparam M1 type of the first matrix (not needed by default)
|
||||
* \tparam T type of the scalar (not needed by default)
|
||||
* \tparam M2 type of the triangular matrix (not needed by default)
|
||||
* \tparam C (n/a)
|
||||
*/
|
||||
template<class M1, class T, class M2, class C>
|
||||
M1 & tsm (M1 &m1, const T &t, const M2 &m2, C)
|
||||
{
|
||||
return m1 = solve (m2, t * m1, C ());
|
||||
}
|
||||
|
||||
/** \brief general matrix multiplication \f$m_1=t_1.m_1 + t_2.m_2.m_3\f$
|
||||
*
|
||||
* \param m1 first matrix
|
||||
* \param t1 first scalar
|
||||
* \param t2 second scalar
|
||||
* \param m2 second matrix
|
||||
* \param m3 third matrix
|
||||
* \return the matrix \c m1
|
||||
*
|
||||
* \tparam M1 type of the first matrix (not needed by default)
|
||||
* \tparam T1 type of the first scalar (not needed by default)
|
||||
* \tparam T2 type of the second scalar (not needed by default)
|
||||
* \tparam M2 type of the second matrix (not needed by default)
|
||||
* \tparam M3 type of the third matrix (not needed by default)
|
||||
*/
|
||||
template<class M1, class T1, class T2, class M2, class M3>
|
||||
M1 & gmm (M1 &m1, const T1 &t1, const T2 &t2, const M2 &m2, const M3 &m3)
|
||||
{
|
||||
return m1 = t1 * m1 + t2 * prod (m2, m3);
|
||||
}
|
||||
|
||||
/** \brief symmetric rank \a k update: \f$m_1=t.m_1+t_2.(m_2.m_2^T)\f$
|
||||
*
|
||||
* \param m1 first matrix
|
||||
* \param t1 first scalar
|
||||
* \param t2 second scalar
|
||||
* \param m2 second matrix
|
||||
* \return matrix \c m1
|
||||
*
|
||||
* \tparam M1 type of the first matrix (not needed by default)
|
||||
* \tparam T1 type of the first scalar (not needed by default)
|
||||
* \tparam T2 type of the second scalar (not needed by default)
|
||||
* \tparam M2 type of the second matrix (not needed by default)
|
||||
* \todo use opb_prod()
|
||||
*/
|
||||
template<class M1, class T1, class T2, class M2>
|
||||
M1 & srk (M1 &m1, const T1 &t1, const T2 &t2, const M2 &m2)
|
||||
{
|
||||
return m1 = t1 * m1 + t2 * prod (m2, trans (m2));
|
||||
}
|
||||
|
||||
/** \brief hermitian rank \a k update: \f$m_1=t.m_1+t_2.(m_2.m2^H)\f$
|
||||
*
|
||||
* \param m1 first matrix
|
||||
* \param t1 first scalar
|
||||
* \param t2 second scalar
|
||||
* \param m2 second matrix
|
||||
* \return matrix \c m1
|
||||
*
|
||||
* \tparam M1 type of the first matrix (not needed by default)
|
||||
* \tparam T1 type of the first scalar (not needed by default)
|
||||
* \tparam T2 type of the second scalar (not needed by default)
|
||||
* \tparam M2 type of the second matrix (not needed by default)
|
||||
* \todo use opb_prod()
|
||||
*/
|
||||
template<class M1, class T1, class T2, class M2>
|
||||
M1 & hrk (M1 &m1, const T1 &t1, const T2 &t2, const M2 &m2)
|
||||
{
|
||||
return m1 = t1 * m1 + t2 * prod (m2, herm (m2));
|
||||
}
|
||||
|
||||
/** \brief generalized symmetric rank \a k update: \f$m_1=t_1.m_1+t_2.(m_2.m3^T)+t_2.(m_3.m2^T)\f$
|
||||
*
|
||||
* \param m1 first matrix
|
||||
* \param t1 first scalar
|
||||
* \param t2 second scalar
|
||||
* \param m2 second matrix
|
||||
* \param m3 third matrix
|
||||
* \return matrix \c m1
|
||||
*
|
||||
* \tparam M1 type of the first matrix (not needed by default)
|
||||
* \tparam T1 type of the first scalar (not needed by default)
|
||||
* \tparam T2 type of the second scalar (not needed by default)
|
||||
* \tparam M2 type of the second matrix (not needed by default)
|
||||
* \tparam M3 type of the third matrix (not needed by default)
|
||||
* \todo use opb_prod()
|
||||
*/
|
||||
template<class M1, class T1, class T2, class M2, class M3>
|
||||
M1 & sr2k (M1 &m1, const T1 &t1, const T2 &t2, const M2 &m2, const M3 &m3)
|
||||
{
|
||||
return m1 = t1 * m1 + t2 * (prod (m2, trans (m3)) + prod (m3, trans (m2)));
|
||||
}
|
||||
|
||||
/** \brief generalized hermitian rank \a k update: * \f$m_1=t_1.m_1+t_2.(m_2.m_3^H)+(m_3.(t_2.m_2)^H)\f$
|
||||
*
|
||||
* \param m1 first matrix
|
||||
* \param t1 first scalar
|
||||
* \param t2 second scalar
|
||||
* \param m2 second matrix
|
||||
* \param m3 third matrix
|
||||
* \return matrix \c m1
|
||||
*
|
||||
* \tparam M1 type of the first matrix (not needed by default)
|
||||
* \tparam T1 type of the first scalar (not needed by default)
|
||||
* \tparam T2 type of the second scalar (not needed by default)
|
||||
* \tparam M2 type of the second matrix (not needed by default)
|
||||
* \tparam M3 type of the third matrix (not needed by default)
|
||||
* \todo use opb_prod()
|
||||
*/
|
||||
template<class M1, class T1, class T2, class M2, class M3>
|
||||
M1 & hr2k (M1 &m1, const T1 &t1, const T2 &t2, const M2 &m2, const M3 &m3)
|
||||
{
|
||||
return m1 =
|
||||
t1 * m1
|
||||
+ t2 * prod (m2, herm (m3))
|
||||
+ type_traits<T2>::conj (t2) * prod (m3, herm (m2));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
1465
include/boost/numeric/ublas/detail/concepts.hpp
Normal file
1465
include/boost/numeric/ublas/detail/concepts.hpp
Normal file
File diff suppressed because it is too large
Load Diff
304
include/boost/numeric/ublas/detail/config.hpp
Normal file
304
include/boost/numeric/ublas/detail/config.hpp
Normal file
@@ -0,0 +1,304 @@
|
||||
//
|
||||
// Copyright (c) 2000-2002
|
||||
// Joerg Walter, Mathias Koch
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
#ifndef _BOOST_UBLAS_CONFIG_
|
||||
#define _BOOST_UBLAS_CONFIG_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/mpl/and.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_const.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
|
||||
// C++11
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
||||
|
||||
#define BOOST_UBLAS_CPP_GE_2011
|
||||
|
||||
#elif BOOST_MSVC >= 1800
|
||||
|
||||
#define BOOST_UBLAS_CPP_GE_2011
|
||||
|
||||
#else
|
||||
|
||||
#undef BOOST_UBLAS_CPP_GE_2011 // Make sure no one defined it
|
||||
|
||||
#endif
|
||||
|
||||
// Microsoft Visual C++
|
||||
#if defined (BOOST_MSVC) && ! defined (BOOST_STRICT_CONFIG)
|
||||
|
||||
// Version 7.1
|
||||
#if BOOST_MSVC == 1310
|
||||
// One of these workarounds is needed for MSVC 7.1 AFAIK
|
||||
// (thanks to John Maddock and Martin Lauer).
|
||||
#if !(defined(BOOST_UBLAS_NO_NESTED_CLASS_RELATION) || defined(BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION))
|
||||
#define BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// GNU Compiler Collection
|
||||
#if defined (__GNUC__) && ! defined (BOOST_STRICT_CONFIG)
|
||||
|
||||
#if __GNUC__ >= 4 || (__GNUC__ >= 3 && __GNUC_MINOR__ >= 4)
|
||||
// Specified by ABI definition see GCC bug id 9982
|
||||
#define BOOST_UBLAS_USEFUL_ARRAY_PLACEMENT_NEW
|
||||
#endif
|
||||
|
||||
#if __GNUC__ < 3
|
||||
#define BOOST_UBLAS_UNSUPPORTED_COMPILER 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Intel Compiler
|
||||
#if defined (BOOST_INTEL) && ! defined (BOOST_STRICT_CONFIG)
|
||||
|
||||
#if defined (BOOST_INTEL_LINUX) && (BOOST_INTEL_LINUX >= 800)
|
||||
// By inspection of compiler results
|
||||
#define BOOST_UBLAS_USEFUL_ARRAY_PLACEMENT_NEW
|
||||
#endif
|
||||
|
||||
#if (BOOST_INTEL < 700)
|
||||
#define BOOST_UBLAS_UNSUPPORTED_COMPILER 1
|
||||
#endif
|
||||
|
||||
// Define swap for index_pair and triple.
|
||||
#if (BOOST_INTEL <= 800)
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
template<class C, class IC>
|
||||
class indexed_iterator;
|
||||
|
||||
template<class V>
|
||||
class index_pair;
|
||||
template<class M>
|
||||
class index_triple;
|
||||
}}}
|
||||
|
||||
namespace std {
|
||||
template<class V>
|
||||
inline
|
||||
void swap (boost::numeric::ublas::index_pair<V> i1, boost::numeric::ublas::index_pair<V> i2) {
|
||||
i1.swap (i2);
|
||||
}
|
||||
template<class M>
|
||||
inline
|
||||
void swap (boost::numeric::ublas::index_triple<M> i1, boost::numeric::ublas::index_triple<M> i2) {
|
||||
i1.swap (i2);
|
||||
}
|
||||
// iter_swap also needed for ICC on Itanium?
|
||||
template<class C, class IC>
|
||||
inline
|
||||
void iter_swap (boost::numeric::ublas::indexed_iterator<C, IC> it1,
|
||||
boost::numeric::ublas::indexed_iterator<C, IC> it2) {
|
||||
swap (*it1, *it2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Comeau compiler - thanks to Kresimir Fresl
|
||||
#if defined (__COMO__) && ! defined (BOOST_STRICT_CONFIG)
|
||||
|
||||
// Missing std::abs overloads for float types in <cmath> are in <cstdlib>
|
||||
#if defined(__LIBCOMO__) && (__LIBCOMO_VERSION__ <= 31)
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// PGI compiler
|
||||
#ifdef __PGIC__
|
||||
#define BOOST_UBLAS_UNSUPPORTED_COMPILER 0
|
||||
#endif
|
||||
|
||||
// HP aCC C++ compiler
|
||||
#if defined (__HP_aCC) && ! defined (BOOST_STRICT_CONFIG)
|
||||
# if (__HP_aCC >= 60000 )
|
||||
# define BOOST_UBLAS_USEFUL_ARRAY_PLACEMENT_NEW
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// SGI MIPSpro C++ compiler
|
||||
#if defined (__sgi) && ! defined (BOOST_STRICT_CONFIG)
|
||||
|
||||
// Missing std::abs overloads for float types in <cmath> are in <cstdlib>
|
||||
// This test should be library version specific.
|
||||
#include <cstdlib>
|
||||
|
||||
#if __COMPILER_VERSION >=650
|
||||
// By inspection of compiler results - thanks to Peter Schmitteckert
|
||||
#define BOOST_UBLAS_USEFUL_ARRAY_PLACEMENT_NEW
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Metrowerks Codewarrior
|
||||
#if defined (__MWERKS__) && ! defined (BOOST_STRICT_CONFIG)
|
||||
|
||||
// 8.x
|
||||
#if __MWERKS__ <= 0x3003
|
||||
#define BOOST_UBLAS_UNSUPPORTED_COMPILER 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Detect other compilers with serious defects - override by defineing BOOST_UBLAS_UNSUPPORTED_COMPILER=0
|
||||
#ifndef BOOST_UBLAS_UNSUPPORTED_COMPILER
|
||||
#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) || defined(BOOST_NO_SFINAE) || defined(BOOST_NO_STDC_NAMESPACE)
|
||||
#define BOOST_UBLAS_UNSUPPORTED_COMPILER 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Cannot continue with an unsupported compiler
|
||||
#if defined(BOOST_UBLAS_UNSUPPORTED_COMPILER) && (BOOST_UBLAS_UNSUPPORTED_COMPILER != 0)
|
||||
#error Your compiler and/or configuration is unsupported by this verions of uBLAS. Define BOOST_UBLAS_UNSUPPORTED_COMPILER=0 to override this message. Boost 1.32.0 includes uBLAS with support for many older compilers.
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Enable performance options in RELEASE mode
|
||||
#if defined (NDEBUG) || defined (BOOST_UBLAS_NDEBUG)
|
||||
|
||||
#ifndef BOOST_UBLAS_INLINE
|
||||
#define BOOST_UBLAS_INLINE inline
|
||||
#endif
|
||||
|
||||
// Do not check sizes!
|
||||
#define BOOST_UBLAS_USE_FAST_SAME
|
||||
|
||||
// NO runtime error checks with BOOST_UBLAS_CHECK macro
|
||||
#ifndef BOOST_UBLAS_CHECK_ENABLE
|
||||
#define BOOST_UBLAS_CHECK_ENABLE 0
|
||||
#endif
|
||||
|
||||
// NO type compatibility numeric checks
|
||||
#ifndef BOOST_UBLAS_TYPE_CHECK
|
||||
#define BOOST_UBLAS_TYPE_CHECK 0
|
||||
#endif
|
||||
|
||||
|
||||
// Disable performance options in DEBUG mode
|
||||
#else
|
||||
|
||||
#ifndef BOOST_UBLAS_INLINE
|
||||
#define BOOST_UBLAS_INLINE
|
||||
#endif
|
||||
|
||||
// Enable runtime error checks with BOOST_UBLAS_CHECK macro. Check bounds etc
|
||||
#ifndef BOOST_UBLAS_CHECK_ENABLE
|
||||
#define BOOST_UBLAS_CHECK_ENABLE 1
|
||||
#endif
|
||||
|
||||
// Type compatibiltity numeric checks
|
||||
#ifndef BOOST_UBLAS_TYPE_CHECK
|
||||
#define BOOST_UBLAS_TYPE_CHECK 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Type compatibility checks
|
||||
* Control type compatibility numeric runtime checks for non dense matrices.
|
||||
* Require additional storage and complexity
|
||||
*/
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
template <class Dummy>
|
||||
struct disable_type_check
|
||||
{
|
||||
static bool value;
|
||||
};
|
||||
template <class Dummy>
|
||||
bool disable_type_check<Dummy>::value = false;
|
||||
#endif
|
||||
#ifndef BOOST_UBLAS_TYPE_CHECK_EPSILON
|
||||
#define BOOST_UBLAS_TYPE_CHECK_EPSILON (type_traits<real_type>::type_sqrt (std::numeric_limits<real_type>::epsilon ()))
|
||||
#endif
|
||||
#ifndef BOOST_UBLAS_TYPE_CHECK_MIN
|
||||
#define BOOST_UBLAS_TYPE_CHECK_MIN (type_traits<real_type>::type_sqrt ( (std::numeric_limits<real_type>::min) ()))
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* General Configuration
|
||||
*/
|
||||
|
||||
// Proxy shortcuts overload the alreadly heavily over used operator ()
|
||||
//#define BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
|
||||
|
||||
// In order to simplify debugging is is possible to simplify expression template
|
||||
// so they are restricted to a single operation
|
||||
// #define BOOST_UBLAS_SIMPLE_ET_DEBUG
|
||||
|
||||
// Use invariant hoisting.
|
||||
// #define BOOST_UBLAS_USE_INVARIANT_HOISTING
|
||||
|
||||
// Use Duff's device in element access loops
|
||||
// #define BOOST_UBLAS_USE_DUFF_DEVICE
|
||||
|
||||
// Choose evaluation method for dense vectors and matrices
|
||||
#if !(defined(BOOST_UBLAS_USE_INDEXING) || defined(BOOST_UBLAS_USE_ITERATING))
|
||||
#define BOOST_UBLAS_USE_INDEXING
|
||||
#endif
|
||||
// #define BOOST_UBLAS_ITERATOR_THRESHOLD 0
|
||||
|
||||
// Use indexed iterators - unsupported implementation experiment
|
||||
// #define BOOST_UBLAS_USE_INDEXED_ITERATOR
|
||||
|
||||
// Alignment of bounded_array type
|
||||
#ifndef BOOST_UBLAS_BOUNDED_ARRAY_ALIGN
|
||||
#define BOOST_UBLAS_BOUNDED_ARRAY_ALIGN
|
||||
#endif
|
||||
|
||||
// Enable different sparse element proxies
|
||||
#ifndef BOOST_UBLAS_NO_ELEMENT_PROXIES
|
||||
// Sparse proxies prevent reference invalidation problems in expressions such as:
|
||||
// a [1] = a [0] = 1 Thanks to Marc Duflot for spotting this.
|
||||
// #define BOOST_UBLAS_STRICT_MAP_ARRAY
|
||||
#define BOOST_UBLAS_STRICT_VECTOR_SPARSE
|
||||
#define BOOST_UBLAS_STRICT_MATRIX_SPARSE
|
||||
// Hermitian matrices use element proxies to allow assignment to conjugate triangle
|
||||
#define BOOST_UBLAS_STRICT_HERMITIAN
|
||||
#endif
|
||||
|
||||
// Define to configure special settings for reference returning members
|
||||
// #define BOOST_UBLAS_REFERENCE_CONST_MEMBER
|
||||
// #define BOOST_UBLAS_PROXY_CONST_MEMBER
|
||||
|
||||
|
||||
// Include type declerations and functions
|
||||
#include <boost/numeric/ublas/fwd.hpp>
|
||||
#include <boost/numeric/ublas/detail/definitions.hpp>
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
212
include/boost/numeric/ublas/detail/definitions.hpp
Normal file
212
include/boost/numeric/ublas/detail/definitions.hpp
Normal file
@@ -0,0 +1,212 @@
|
||||
//
|
||||
// Copyright (c) 2000-2002
|
||||
// Joerg Walter, Mathias Koch
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
#ifndef _BOOST_UBLAS_DEFINITIONS_
|
||||
#define _BOOST_UBLAS_DEFINITIONS_
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
namespace detail {
|
||||
/* Borrowed from boost/concept_checks.hpp
|
||||
"inline" is used for ignore_unused_variable_warning()
|
||||
to make sure there is no overhead with g++.
|
||||
*/
|
||||
template <class T> inline
|
||||
void ignore_unused_variable_warning(const T&) {}
|
||||
} // namespace detail
|
||||
|
||||
// Borrowed from Dave Abraham's noncopyable.
|
||||
// I believe this should be part of utility.hpp one day...
|
||||
namespace nonassignable_ // protection from unintended ADL
|
||||
{
|
||||
class nonassignable {
|
||||
protected:
|
||||
nonassignable () {}
|
||||
~nonassignable () {}
|
||||
private: // emphasize the following members are private
|
||||
const nonassignable& operator= (const nonassignable &);
|
||||
}; // nonassignable
|
||||
}
|
||||
typedef nonassignable_::nonassignable nonassignable;
|
||||
|
||||
|
||||
// Assignment proxy.
|
||||
// Provides temporary free assigment when LHS has no alias on RHS
|
||||
template<class C>
|
||||
class noalias_proxy:
|
||||
private nonassignable {
|
||||
public:
|
||||
typedef typename C::closure_type closure_type;
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
noalias_proxy (C& lval):
|
||||
nonassignable (), lval_ (lval) {}
|
||||
BOOST_UBLAS_INLINE
|
||||
noalias_proxy (const noalias_proxy& p):
|
||||
nonassignable (), lval_ (p.lval_) {}
|
||||
|
||||
template <class E>
|
||||
BOOST_UBLAS_INLINE
|
||||
closure_type &operator= (const E& e) {
|
||||
lval_.assign (e);
|
||||
return lval_;
|
||||
}
|
||||
|
||||
template <class E>
|
||||
BOOST_UBLAS_INLINE
|
||||
closure_type &operator+= (const E& e) {
|
||||
lval_.plus_assign (e);
|
||||
return lval_;
|
||||
}
|
||||
|
||||
template <class E>
|
||||
BOOST_UBLAS_INLINE
|
||||
closure_type &operator-= (const E& e) {
|
||||
lval_.minus_assign (e);
|
||||
return lval_;
|
||||
}
|
||||
|
||||
private:
|
||||
closure_type lval_;
|
||||
};
|
||||
|
||||
// Improve syntax of efficient assignment where no aliases of LHS appear on the RHS
|
||||
// noalias(lhs) = rhs_expression
|
||||
template <class C>
|
||||
BOOST_UBLAS_INLINE
|
||||
noalias_proxy<C> noalias (C& lvalue) {
|
||||
return noalias_proxy<C> (lvalue);
|
||||
}
|
||||
template <class C>
|
||||
BOOST_UBLAS_INLINE
|
||||
noalias_proxy<const C> noalias (const C& lvalue) {
|
||||
return noalias_proxy<const C> (lvalue);
|
||||
}
|
||||
|
||||
// Possible future compatible syntax where lvalue possible has an unsafe alias on the RHS
|
||||
// safe(lhs) = rhs_expression
|
||||
template <class C>
|
||||
BOOST_UBLAS_INLINE
|
||||
C& safe (C& lvalue) {
|
||||
return lvalue;
|
||||
}
|
||||
template <class C>
|
||||
BOOST_UBLAS_INLINE
|
||||
const C& safe (const C& lvalue) {
|
||||
return lvalue;
|
||||
}
|
||||
|
||||
|
||||
// Dimension accessors
|
||||
namespace dimension {
|
||||
|
||||
// Generic accessors
|
||||
template<unsigned dimension>
|
||||
struct dimension_properties {};
|
||||
|
||||
template<>
|
||||
struct dimension_properties<1> {
|
||||
template <class E>
|
||||
BOOST_UBLAS_INLINE static
|
||||
typename E::size_type size (const vector_expression<E> &e) {
|
||||
return e ().size ();
|
||||
}
|
||||
template <class E>
|
||||
BOOST_UBLAS_INLINE static
|
||||
typename E::size_type size (const matrix_expression<E> &e) {
|
||||
return e ().size1 ();
|
||||
}
|
||||
// Note: Index functions cannot deduce dependant template parameter V or M from i
|
||||
template <class V>
|
||||
BOOST_UBLAS_INLINE static
|
||||
typename V::size_type index (const typename V::iterator &i) {
|
||||
return i.index ();
|
||||
}
|
||||
template <class M>
|
||||
BOOST_UBLAS_INLINE static
|
||||
typename M::size_type index (const typename M::iterator1 &i) {
|
||||
return i.index1 ();
|
||||
}
|
||||
template <class M>
|
||||
BOOST_UBLAS_INLINE static
|
||||
typename M::size_type index (const typename M::iterator2 &i) {
|
||||
return i.index1 ();
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct dimension_properties<2> {
|
||||
template <class E>
|
||||
BOOST_UBLAS_INLINE static
|
||||
typename E::size_type size (const vector_expression<E> &) {
|
||||
return 1;
|
||||
}
|
||||
template <class E>
|
||||
BOOST_UBLAS_INLINE static
|
||||
typename E::size_type size (const matrix_expression<E> &e) {
|
||||
return e ().size2 ();
|
||||
}
|
||||
template <class V>
|
||||
BOOST_UBLAS_INLINE static
|
||||
typename V::size_type index (const typename V::iterator &) {
|
||||
return 1;
|
||||
}
|
||||
template <class M>
|
||||
BOOST_UBLAS_INLINE static
|
||||
typename M::size_type index (const typename M::iterator1 &i) {
|
||||
return i.index2 ();
|
||||
}
|
||||
template <class M>
|
||||
BOOST_UBLAS_INLINE static
|
||||
typename M::size_type index (const typename M::iterator2 &i) {
|
||||
return i.index2 ();
|
||||
}
|
||||
};
|
||||
|
||||
template<unsigned dimension, class E>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename E::size_type size (const E& e) {
|
||||
return dimension_properties<dimension>::size (e);
|
||||
}
|
||||
|
||||
template<unsigned dimension, class I>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename I::container_type::size_type
|
||||
index (const I& i) {
|
||||
typedef typename I::container_type container_type;
|
||||
return dimension_properties<dimension>::template index<container_type> (i);
|
||||
}
|
||||
|
||||
|
||||
// Named accessors - just syntactic sugar
|
||||
template<class V>
|
||||
typename V::size_type num_elements (const V &v) {
|
||||
return v.size ();
|
||||
}
|
||||
template<class M>
|
||||
typename M::size_type num_rows (const M &m) {
|
||||
return m.size1 ();
|
||||
}
|
||||
template<class M>
|
||||
typename M::size_type num_columns (const M &m) {
|
||||
return m.size2 ();
|
||||
}
|
||||
template<class MV>
|
||||
typename MV::size_type num_non_zeros (const MV &mv) {
|
||||
return mv.non_zeros ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
33
include/boost/numeric/ublas/detail/documentation.hpp
Normal file
33
include/boost/numeric/ublas/detail/documentation.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// Copyright (c) 2000-2004
|
||||
// Joerg Walter, Mathias Koch
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
// this file should not contain any code, but the documentation
|
||||
// global to all files
|
||||
|
||||
/** \namespace boost::numeric::ublas
|
||||
\brief contains all important classes and functions of uBLAS
|
||||
|
||||
all ublas definitions ...
|
||||
\todo expand this section
|
||||
*/
|
||||
|
||||
/** \defgroup blas1 Level 1 BLAS
|
||||
\brief level 1 basic linear algebra subroutines
|
||||
*/
|
||||
|
||||
/** \defgroup blas2 Level 2 BLAS
|
||||
\brief level 2 basic linear algebra subroutines
|
||||
*/
|
||||
|
||||
/** \defgroup blas3 Level 3 BLAS
|
||||
\brief level 3 basic linear algebra subroutines
|
||||
*/
|
||||
56
include/boost/numeric/ublas/detail/duff.hpp
Normal file
56
include/boost/numeric/ublas/detail/duff.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// Copyright (c) 2000-2002
|
||||
// Joerg Walter, Mathias Koch
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
#ifndef _BOOST_UBLAS_DUFF_
|
||||
#define _BOOST_UBLAS_DUFF_
|
||||
|
||||
#define DD_SWITCH(n, d, r, expr) \
|
||||
{ \
|
||||
unsigned r = ((n) + (d) - 1) / (d); \
|
||||
switch ((n) % (d)) { \
|
||||
case 0: do { expr;
|
||||
#define DD_CASE_I(i, expr) \
|
||||
case (i): expr;
|
||||
#define DD_WHILE(r) \
|
||||
} while (-- (r) > 0); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DD_1T(n, d, r, expr) \
|
||||
DD_WHILE(r)
|
||||
#define DD_2T(n, d, r, expr) \
|
||||
DD_CASE_I(1, expr) \
|
||||
DD_1T(n, d, r, expr)
|
||||
#define DD_3T(n, d, r, expr) \
|
||||
DD_CASE_I(2, expr) \
|
||||
DD_2T(n, d, r, expr)
|
||||
#define DD_4T(n, d, r, expr) \
|
||||
DD_CASE_I(3, expr) \
|
||||
DD_3T(n, d, r, expr)
|
||||
#define DD_5T(n, d, r, expr) \
|
||||
DD_CASE_I(4, expr) \
|
||||
DD_4T(n, d, r, expr)
|
||||
#define DD_6T(n, d, r, expr) \
|
||||
DD_CASE_I(5, expr) \
|
||||
DD_5T(n, d, r, expr)
|
||||
#define DD_7T(n, d, r, expr) \
|
||||
DD_CASE_I(6, expr) \
|
||||
DD_6T(n, d, r, expr)
|
||||
#define DD_8T(n, d, r, expr) \
|
||||
DD_CASE_I(7, expr) \
|
||||
DD_7T(n, d, r, expr)
|
||||
|
||||
#define DD(n, d, r, expr) \
|
||||
DD_SWITCH(n, d, r, expr) \
|
||||
DD_##d##T(n, d, r, expr)
|
||||
|
||||
#endif
|
||||
1448
include/boost/numeric/ublas/detail/iterator.hpp
Normal file
1448
include/boost/numeric/ublas/detail/iterator.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1785
include/boost/numeric/ublas/detail/matrix_assign.hpp
Normal file
1785
include/boost/numeric/ublas/detail/matrix_assign.hpp
Normal file
File diff suppressed because it is too large
Load Diff
878
include/boost/numeric/ublas/detail/raw.hpp
Normal file
878
include/boost/numeric/ublas/detail/raw.hpp
Normal file
@@ -0,0 +1,878 @@
|
||||
//
|
||||
// Copyright (c) 2002-2003
|
||||
// Toon Knapen, Kresimir Fresl, Joerg Walter
|
||||
//
|
||||
// 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_RAW_
|
||||
#define _BOOST_UBLAS_RAW_
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas { namespace raw {
|
||||
|
||||
// We need data_const() mostly due to MSVC 6.0.
|
||||
// But how shall we write portable code otherwise?
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
int size( const V &v ) ;
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
int size( const vector_reference<V> &v ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int size1( const M &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int size2( const M &m ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int size1( const matrix_reference<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int size2( const matrix_reference<M> &m ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int leading_dimension( const M &m, row_major_tag ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int leading_dimension( const M &m, column_major_tag ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int leading_dimension( const M &m ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int leading_dimension( const matrix_reference<M> &m ) ;
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride( const V &v ) ;
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride( const vector_range<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride( const vector_slice<V> &v ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride( const matrix_row<M> &v ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride( const matrix_column<M> &v ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride1( const M &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride2( const M &m ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride1( const matrix_reference<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride2( const matrix_reference<M> &m ) ;
|
||||
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride1( const c_matrix<T, M, N> &m ) ;
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride2( const c_matrix<T, M, N> &m ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride1( const matrix_range<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride1( const matrix_slice<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride2( const matrix_range<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride2( const matrix_slice<M> &m ) ;
|
||||
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::array_type::array_type::const_pointer data( const MV &mv ) ;
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::array_type::array_type::const_pointer data_const( const MV &mv ) ;
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::array_type::pointer data( MV &mv ) ;
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer data( const vector_reference<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer data_const( const vector_reference<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::pointer data( vector_reference<V> &v ) ;
|
||||
|
||||
template < typename T, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_vector<T, N>::array_type::array_type::const_pointer data( const c_vector<T, N> &v ) ;
|
||||
template < typename T, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_vector<T, N>::array_type::array_type::const_pointer data_const( const c_vector<T, N> &v ) ;
|
||||
template < typename T, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_vector<T, N>::pointer data( c_vector<T, N> &v ) ;
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer data( const vector_range<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer data( const vector_slice<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer data_const( const vector_range<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer data_const( const vector_slice<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::pointer data( vector_range<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::pointer data( vector_slice<V> &v ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer data( const matrix_reference<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer data_const( const matrix_reference<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer data( matrix_reference<M> &m ) ;
|
||||
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_matrix<T, M, N>::array_type::array_type::const_pointer data( const c_matrix<T, M, N> &m ) ;
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_matrix<T, M, N>::array_type::array_type::const_pointer data_const( const c_matrix<T, M, N> &m ) ;
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_matrix<T, M, N>::pointer data( c_matrix<T, M, N> &m ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer data( const matrix_row<M> &v ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer data( const matrix_column<M> &v ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer data_const( const matrix_row<M> &v ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer data_const( const matrix_column<M> &v ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer data( matrix_row<M> &v ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer data( matrix_column<M> &v ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer data( const matrix_range<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer data( const matrix_slice<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer data_const( const matrix_range<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer data_const( const matrix_slice<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer data( matrix_range<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer data( matrix_slice<M> &m ) ;
|
||||
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::array_type::array_type::const_pointer base( const MV &mv ) ;
|
||||
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::array_type::array_type::const_pointer base_const( const MV &mv ) ;
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::array_type::pointer base( MV &mv ) ;
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer base( const vector_reference<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer base_const( const vector_reference<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::pointer base( vector_reference<V> &v ) ;
|
||||
|
||||
template < typename T, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_vector<T, N>::array_type::array_type::const_pointer base( const c_vector<T, N> &v ) ;
|
||||
template < typename T, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_vector<T, N>::array_type::array_type::const_pointer base_const( const c_vector<T, N> &v ) ;
|
||||
template < typename T, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_vector<T, N>::pointer base( c_vector<T, N> &v ) ;
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer base( const vector_range<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer base( const vector_slice<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer base_const( const vector_range<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer base_const( const vector_slice<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::pointer base( vector_range<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::pointer base( vector_slice<V> &v ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer base( const matrix_reference<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer base_const( const matrix_reference<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer base( matrix_reference<M> &m ) ;
|
||||
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_matrix<T, M, N>::array_type::array_type::const_pointer base( const c_matrix<T, M, N> &m ) ;
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_matrix<T, M, N>::array_type::array_type::const_pointer base_const( const c_matrix<T, M, N> &m ) ;
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_matrix<T, M, N>::pointer base( c_matrix<T, M, N> &m ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer base( const matrix_row<M> &v ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer base( const matrix_column<M> &v ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer base_const( const matrix_row<M> &v ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer base_const( const matrix_column<M> &v ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer base( matrix_row<M> &v ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer base( matrix_column<M> &v ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer base( const matrix_range<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer base( const matrix_slice<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer base_const( const matrix_range<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::array_type::const_pointer base_const( const matrix_slice<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer base( matrix_range<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer base( matrix_slice<M> &m ) ;
|
||||
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::size_type start( const MV &mv ) ;
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::size_type start( const vector_range<V> &v ) ;
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::size_type start( const vector_slice<V> &v ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::size_type start( const matrix_row<M> &v ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::size_type start( const matrix_column<M> &v ) ;
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::size_type start( const matrix_range<M> &m ) ;
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::size_type start( const matrix_slice<M> &m ) ;
|
||||
|
||||
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
int size( const V &v ) {
|
||||
return v.size() ;
|
||||
}
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
int size( const vector_reference<V> &v ) {
|
||||
return size( v ) ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int size1( const M &m ) {
|
||||
return m.size1() ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int size2( const M &m ) {
|
||||
return m.size2() ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int size1( const matrix_reference<M> &m ) {
|
||||
return size1( m.expression() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int size2( const matrix_reference<M> &m ) {
|
||||
return size2( m.expression() ) ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int leading_dimension( const M &m, row_major_tag ) {
|
||||
return m.size2() ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int leading_dimension( const M &m, column_major_tag ) {
|
||||
return m.size1() ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int leading_dimension( const M &m ) {
|
||||
return leading_dimension( m, typename M::orientation_category() ) ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int leading_dimension( const matrix_reference<M> &m ) {
|
||||
return leading_dimension( m.expression() ) ;
|
||||
}
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride( const V &v ) {
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride( const vector_range<V> &v ) {
|
||||
return stride( v.data() ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride( const vector_slice<V> &v ) {
|
||||
return v.stride() * stride( v.data() ) ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride( const matrix_row<M> &v ) {
|
||||
return stride2( v.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride( const matrix_column<M> &v ) {
|
||||
return stride1( v.data() ) ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride1( const M &m ) {
|
||||
typedef typename M::functor_type functor_type;
|
||||
return functor_type::one1( m.size1(), m.size2() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride2( const M &m ) {
|
||||
typedef typename M::functor_type functor_type;
|
||||
return functor_type::one2( m.size1(), m.size2() ) ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride1( const matrix_reference<M> &m ) {
|
||||
return stride1( m.expression() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride2( const matrix_reference<M> &m ) {
|
||||
return stride2( m.expression() ) ;
|
||||
}
|
||||
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride1( const c_matrix<T, M, N> &m ) {
|
||||
return N ;
|
||||
}
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride2( const c_matrix<T, M, N> &m ) {
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride1( const matrix_range<M> &m ) {
|
||||
return stride1( m.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride1( const matrix_slice<M> &m ) {
|
||||
return m.stride1() * stride1( m.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride2( const matrix_range<M> &m ) {
|
||||
return stride2( m.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
int stride2( const matrix_slice<M> &m ) {
|
||||
return m.stride2() * stride2( m.data() ) ;
|
||||
}
|
||||
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::array_type::array_type::array_type::const_pointer data( const MV &mv ) {
|
||||
return &mv.data().begin()[0] ;
|
||||
}
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::array_type::array_type::const_pointer data_const( const MV &mv ) {
|
||||
return &mv.data().begin()[0] ;
|
||||
}
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::array_type::pointer data( MV &mv ) {
|
||||
return &mv.data().begin()[0] ;
|
||||
}
|
||||
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer data( const vector_reference<V> &v ) {
|
||||
return data( v.expression () ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer data_const( const vector_reference<V> &v ) {
|
||||
return data_const( v.expression () ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::pointer data( vector_reference<V> &v ) {
|
||||
return data( v.expression () ) ;
|
||||
}
|
||||
|
||||
template < typename T, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_vector<T, N>::array_type::array_type::const_pointer data( const c_vector<T, N> &v ) {
|
||||
return v.data() ;
|
||||
}
|
||||
template < typename T, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_vector<T, N>::array_type::array_type::const_pointer data_const( const c_vector<T, N> &v ) {
|
||||
return v.data() ;
|
||||
}
|
||||
template < typename T, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_vector<T, N>::pointer data( c_vector<T, N> &v ) {
|
||||
return v.data() ;
|
||||
}
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer data( const vector_range<V> &v ) {
|
||||
return data( v.data() ) + v.start() * stride (v.data() ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer data( const vector_slice<V> &v ) {
|
||||
return data( v.data() ) + v.start() * stride (v.data() ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::array_type::const_pointer data_const( const vector_range<V> &v ) {
|
||||
return data_const( v.data() ) + v.start() * stride (v.data() ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::const_pointer data_const( const vector_slice<V> &v ) {
|
||||
return data_const( v.data() ) + v.start() * stride (v.data() ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::pointer data( vector_range<V> &v ) {
|
||||
return data( v.data() ) + v.start() * stride (v.data() ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::pointer data( vector_slice<V> &v ) {
|
||||
return data( v.data() ) + v.start() * stride (v.data() ) ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer data( const matrix_reference<M> &m ) {
|
||||
return data( m.expression () ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer data_const( const matrix_reference<M> &m ) {
|
||||
return data_const( m.expression () ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer data( matrix_reference<M> &m ) {
|
||||
return data( m.expression () ) ;
|
||||
}
|
||||
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_matrix<T, M, N>::array_type::const_pointer data( const c_matrix<T, M, N> &m ) {
|
||||
return m.data() ;
|
||||
}
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_matrix<T, M, N>::array_type::const_pointer data_const( const c_matrix<T, M, N> &m ) {
|
||||
return m.data() ;
|
||||
}
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_matrix<T, M, N>::pointer data( c_matrix<T, M, N> &m ) {
|
||||
return m.data() ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer data( const matrix_row<M> &v ) {
|
||||
return data( v.data() ) + v.index() * stride1( v.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer data( const matrix_column<M> &v ) {
|
||||
return data( v.data() ) + v.index() * stride2( v.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer data_const( const matrix_row<M> &v ) {
|
||||
return data_const( v.data() ) + v.index() * stride1( v.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer data_const( const matrix_column<M> &v ) {
|
||||
return data_const( v.data() ) + v.index() * stride2( v.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer data( matrix_row<M> &v ) {
|
||||
return data( v.data() ) + v.index() * stride1( v.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer data( matrix_column<M> &v ) {
|
||||
return data( v.data() ) + v.index() * stride2( v.data() ) ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer data( const matrix_range<M> &m ) {
|
||||
return data( m.data() ) + m.start1() * stride1( m.data () ) + m.start2() * stride2( m.data () ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer data( const matrix_slice<M> &m ) {
|
||||
return data( m.data() ) + m.start1() * stride1( m.data () ) + m.start2() * stride2( m.data () ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer data_const( const matrix_range<M> &m ) {
|
||||
return data_const( m.data() ) + m.start1() * stride1( m.data () ) + m.start2() * stride2( m.data () ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer data_const( const matrix_slice<M> &m ) {
|
||||
return data_const( m.data() ) + m.start1() * stride1( m.data () ) + m.start2() * stride2( m.data () ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer data( matrix_range<M> &m ) {
|
||||
return data( m.data() ) + m.start1() * stride1( m.data () ) + m.start2() * stride2( m.data () ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer data( matrix_slice<M> &m ) {
|
||||
return data( m.data() ) + m.start1() * stride1( m.data () ) + m.start2() * stride2( m.data () ) ;
|
||||
}
|
||||
|
||||
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::array_type::const_pointer base( const MV &mv ) {
|
||||
return &mv.data().begin()[0] ;
|
||||
}
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::array_type::const_pointer base_const( const MV &mv ) {
|
||||
return &mv.data().begin()[0] ;
|
||||
}
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::array_type::pointer base( MV &mv ) {
|
||||
return &mv.data().begin()[0] ;
|
||||
}
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::const_pointer base( const vector_reference<V> &v ) {
|
||||
return base( v.expression () ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::const_pointer base_const( const vector_reference<V> &v ) {
|
||||
return base_const( v.expression () ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::pointer base( vector_reference<V> &v ) {
|
||||
return base( v.expression () ) ;
|
||||
}
|
||||
|
||||
template < typename T, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_vector<T, N>::array_type::const_pointer base( const c_vector<T, N> &v ) {
|
||||
return v.data() ;
|
||||
}
|
||||
template < typename T, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_vector<T, N>::array_type::const_pointer base_const( const c_vector<T, N> &v ) {
|
||||
return v.data() ;
|
||||
}
|
||||
template < typename T, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_vector<T, N>::pointer base( c_vector<T, N> &v ) {
|
||||
return v.data() ;
|
||||
}
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::const_pointer base( const vector_range<V> &v ) {
|
||||
return base( v.data() ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::const_pointer base( const vector_slice<V> &v ) {
|
||||
return base( v.data() ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::const_pointer base_const( const vector_range<V> &v ) {
|
||||
return base_const( v.data() ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::const_pointer base_const( const vector_slice<V> &v ) {
|
||||
return base_const( v.data() ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::pointer base( vector_range<V> &v ) {
|
||||
return base( v.data() ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::array_type::pointer base( vector_slice<V> &v ) {
|
||||
return base( v.data() ) ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer base( const matrix_reference<M> &m ) {
|
||||
return base( m.expression () ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer base_const( const matrix_reference<M> &m ) {
|
||||
return base_const( m.expression () ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer base( matrix_reference<M> &m ) {
|
||||
return base( m.expression () ) ;
|
||||
}
|
||||
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_matrix<T, M, N>::array_type::const_pointer base( const c_matrix<T, M, N> &m ) {
|
||||
return m.data() ;
|
||||
}
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_matrix<T, M, N>::array_type::const_pointer base_const( const c_matrix<T, M, N> &m ) {
|
||||
return m.data() ;
|
||||
}
|
||||
template < typename T, std::size_t M, std::size_t N >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename c_matrix<T, M, N>::pointer base( c_matrix<T, M, N> &m ) {
|
||||
return m.data() ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer base( const matrix_row<M> &v ) {
|
||||
return base( v.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer base( const matrix_column<M> &v ) {
|
||||
return base( v.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer base_const( const matrix_row<M> &v ) {
|
||||
return base_const( v.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer base_const( const matrix_column<M> &v ) {
|
||||
return base_const( v.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer base( matrix_row<M> &v ) {
|
||||
return base( v.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer base( matrix_column<M> &v ) {
|
||||
return base( v.data() ) ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer base( const matrix_range<M> &m ) {
|
||||
return base( m.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer base( const matrix_slice<M> &m ) {
|
||||
return base( m.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer base_const( const matrix_range<M> &m ) {
|
||||
return base_const( m.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::const_pointer base_const( const matrix_slice<M> &m ) {
|
||||
return base_const( m.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer base( matrix_range<M> &m ) {
|
||||
return base( m.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::array_type::pointer base( matrix_slice<M> &m ) {
|
||||
return base( m.data() ) ;
|
||||
}
|
||||
|
||||
template < typename MV >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename MV::size_type start( const MV &mv ) {
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::size_type start( const vector_range<V> &v ) {
|
||||
return v.start() * stride (v.data() ) ;
|
||||
}
|
||||
template < typename V >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename V::size_type start( const vector_slice<V> &v ) {
|
||||
return v.start() * stride (v.data() ) ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::size_type start( const matrix_row<M> &v ) {
|
||||
return v.index() * stride1( v.data() ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::size_type start( const matrix_column<M> &v ) {
|
||||
return v.index() * stride2( v.data() ) ;
|
||||
}
|
||||
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::size_type start( const matrix_range<M> &m ) {
|
||||
return m.start1() * stride1( m.data () ) + m.start2() * stride2( m.data () ) ;
|
||||
}
|
||||
template < typename M >
|
||||
BOOST_UBLAS_INLINE
|
||||
typename M::size_type start( const matrix_slice<M> &m ) {
|
||||
return m.start1() * stride1( m.data () ) + m.start2() * stride2( m.data () ) ;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
174
include/boost/numeric/ublas/detail/returntype_deduction.hpp
Normal file
174
include/boost/numeric/ublas/detail/returntype_deduction.hpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 Joel de Guzman
|
||||
*
|
||||
* Use, modification and distribution is subject to 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_NUMERICTYPE_DEDUCTION_
|
||||
#define _BOOST_UBLAS_NUMERICTYPE_DEDUCTION_
|
||||
|
||||
// See original in boost-sandbox/boost/utility/type_deduction.hpp for comments
|
||||
|
||||
#include <boost/mpl/vector/vector20.hpp>
|
||||
#include <boost/mpl/at.hpp>
|
||||
#include <boost/mpl/or.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
struct error_cant_deduce_type {};
|
||||
|
||||
namespace type_deduction_detail
|
||||
{
|
||||
typedef char(&bool_value_type)[1];
|
||||
typedef char(&float_value_type)[2];
|
||||
typedef char(&double_value_type)[3];
|
||||
typedef char(&long_double_value_type)[4];
|
||||
typedef char(&char_value_type)[5];
|
||||
typedef char(&schar_value_type)[6];
|
||||
typedef char(&uchar_value_type)[7];
|
||||
typedef char(&short_value_type)[8];
|
||||
typedef char(&ushort_value_type)[9];
|
||||
typedef char(&int_value_type)[10];
|
||||
typedef char(&uint_value_type)[11];
|
||||
typedef char(&long_value_type)[12];
|
||||
typedef char(&ulong_value_type)[13];
|
||||
|
||||
typedef char(&x_value_type)[14];
|
||||
typedef char(&y_value_type)[15];
|
||||
|
||||
typedef char(&cant_deduce_type)[16];
|
||||
|
||||
template <typename T, typename PlainT = typename remove_cv<T>::type>
|
||||
struct is_basic
|
||||
: mpl::or_<
|
||||
typename mpl::or_<
|
||||
is_same<PlainT, bool>
|
||||
, is_same<PlainT, float>
|
||||
, is_same<PlainT, double>
|
||||
, is_same<PlainT, long double>
|
||||
> ::type,
|
||||
typename mpl::or_<
|
||||
is_same<PlainT, char>
|
||||
, is_same<PlainT, signed char>
|
||||
, is_same<PlainT, unsigned char>
|
||||
, is_same<PlainT, short>
|
||||
, is_same<PlainT, unsigned short>
|
||||
> ::type,
|
||||
typename mpl::or_<
|
||||
is_same<PlainT, int>
|
||||
, is_same<PlainT, unsigned int>
|
||||
, is_same<PlainT, long>
|
||||
, is_same<PlainT, unsigned long>
|
||||
> ::type
|
||||
> {};
|
||||
|
||||
struct asymmetric;
|
||||
|
||||
template <typename X, typename Y>
|
||||
cant_deduce_type
|
||||
test(...); // The black hole !!!
|
||||
|
||||
template <typename X, typename Y>
|
||||
bool_value_type
|
||||
test(bool const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
float_value_type
|
||||
test(float const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
double_value_type
|
||||
test(double const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
long_double_value_type
|
||||
test(long double const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
char_value_type
|
||||
test(char const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
schar_value_type
|
||||
test(signed char const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
uchar_value_type
|
||||
test(unsigned char const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
short_value_type
|
||||
test(short const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
ushort_value_type
|
||||
test(unsigned short const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
int_value_type
|
||||
test(int const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
uint_value_type
|
||||
test(unsigned int const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
long_value_type
|
||||
test(long const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
ulong_value_type
|
||||
test(unsigned long const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
typename boost::disable_if<
|
||||
is_basic<X>, x_value_type
|
||||
>::type
|
||||
test(X const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
typename boost::disable_if<
|
||||
mpl::or_<
|
||||
is_basic<Y>
|
||||
, is_same<Y, asymmetric>
|
||||
, is_same<const X, const Y>
|
||||
>
|
||||
, y_value_type
|
||||
>::type
|
||||
test(Y const&);
|
||||
|
||||
template <typename X, typename Y>
|
||||
struct base_result_of
|
||||
{
|
||||
typedef typename remove_cv<X>::type x_type;
|
||||
typedef typename remove_cv<Y>::type y_type;
|
||||
|
||||
typedef mpl::vector16<
|
||||
mpl::identity<bool>
|
||||
, mpl::identity<float>
|
||||
, mpl::identity<double>
|
||||
, mpl::identity<long double>
|
||||
, mpl::identity<char>
|
||||
, mpl::identity<signed char>
|
||||
, mpl::identity<unsigned char>
|
||||
, mpl::identity<short>
|
||||
, mpl::identity<unsigned short>
|
||||
, mpl::identity<int>
|
||||
, mpl::identity<unsigned int>
|
||||
, mpl::identity<long>
|
||||
, mpl::identity<unsigned long>
|
||||
, mpl::identity<x_type>
|
||||
, mpl::identity<y_type>
|
||||
, mpl::identity<error_cant_deduce_type>
|
||||
>
|
||||
types;
|
||||
};
|
||||
|
||||
}}} } // namespace boost::numeric::ublas ::type_deduction_detail
|
||||
|
||||
#endif
|
||||
33
include/boost/numeric/ublas/detail/temporary.hpp
Normal file
33
include/boost/numeric/ublas/detail/temporary.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// Copyright (c) 2000-2002
|
||||
// Joerg Walter, Mathias Koch
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
#ifndef _BOOST_UBLAS_TEMPORARY_
|
||||
#define _BOOST_UBLAS_TEMPORARY_
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
/// For the creation of temporary vectors in the assignment of proxies
|
||||
template <class M>
|
||||
struct vector_temporary_traits {
|
||||
typedef typename M::vector_temporary_type type ;
|
||||
};
|
||||
|
||||
/// For the creation of temporary vectors in the assignment of proxies
|
||||
template <class M>
|
||||
struct matrix_temporary_traits {
|
||||
typedef typename M::matrix_temporary_type type ;
|
||||
};
|
||||
|
||||
} } }
|
||||
|
||||
#endif
|
||||
609
include/boost/numeric/ublas/detail/vector_assign.hpp
Normal file
609
include/boost/numeric/ublas/detail/vector_assign.hpp
Normal file
@@ -0,0 +1,609 @@
|
||||
//
|
||||
// Copyright (c) 2000-2002
|
||||
// Joerg Walter, Mathias Koch
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
#ifndef _BOOST_UBLAS_VECTOR_ASSIGN_
|
||||
#define _BOOST_UBLAS_VECTOR_ASSIGN_
|
||||
|
||||
#include <boost/numeric/ublas/functional.hpp> // scalar_assign
|
||||
// Required for make_conformant storage
|
||||
#include <vector>
|
||||
|
||||
// Iterators based on ideas of Jeremy Siek
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
namespace detail {
|
||||
|
||||
// Weak equality check - useful to compare equality two arbitary vector expression results.
|
||||
// Since the actual expressions are unknown, we check for and arbitary error bound
|
||||
// on the relative error.
|
||||
// For a linear expression the infinity norm makes sense as we do not know how the elements will be
|
||||
// combined in the expression. False positive results are inevitable for arbirary expressions!
|
||||
template<class E1, class E2, class S>
|
||||
BOOST_UBLAS_INLINE
|
||||
bool equals (const vector_expression<E1> &e1, const vector_expression<E2> &e2, S epsilon, S min_norm) {
|
||||
return norm_inf (e1 - e2) <= epsilon *
|
||||
std::max<S> (std::max<S> (norm_inf (e1), norm_inf (e2)), min_norm);
|
||||
}
|
||||
|
||||
template<class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
bool expression_type_check (const vector_expression<E1> &e1, const vector_expression<E2> &e2) {
|
||||
typedef typename type_traits<typename promote_traits<typename E1::value_type,
|
||||
typename E2::value_type>::promote_type>::real_type real_type;
|
||||
return equals (e1, e2, BOOST_UBLAS_TYPE_CHECK_EPSILON, BOOST_UBLAS_TYPE_CHECK_MIN);
|
||||
}
|
||||
|
||||
|
||||
// Make sparse proxies conformant
|
||||
template<class V, class E>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void make_conformant (V &v, const vector_expression<E> &e) {
|
||||
BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
|
||||
typedef typename V::size_type size_type;
|
||||
typedef typename V::difference_type difference_type;
|
||||
typedef typename V::value_type value_type;
|
||||
// FIXME unbounded_array with push_back maybe better
|
||||
std::vector<size_type> index;
|
||||
typename V::iterator it (v.begin ());
|
||||
typename V::iterator it_end (v.end ());
|
||||
typename E::const_iterator ite (e ().begin ());
|
||||
typename E::const_iterator ite_end (e ().end ());
|
||||
if (it != it_end && ite != ite_end) {
|
||||
size_type it_index = it.index (), ite_index = ite.index ();
|
||||
for (;;) {
|
||||
difference_type compare = it_index - ite_index;
|
||||
if (compare == 0) {
|
||||
++ it, ++ ite;
|
||||
if (it != it_end && ite != ite_end) {
|
||||
it_index = it.index ();
|
||||
ite_index = ite.index ();
|
||||
} else
|
||||
break;
|
||||
} else if (compare < 0) {
|
||||
increment (it, it_end, - compare);
|
||||
if (it != it_end)
|
||||
it_index = it.index ();
|
||||
else
|
||||
break;
|
||||
} else if (compare > 0) {
|
||||
if (*ite != value_type/*zero*/())
|
||||
index.push_back (ite.index ());
|
||||
++ ite;
|
||||
if (ite != ite_end)
|
||||
ite_index = ite.index ();
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (ite != ite_end) {
|
||||
if (*ite != value_type/*zero*/())
|
||||
index.push_back (ite.index ());
|
||||
++ ite;
|
||||
}
|
||||
for (size_type k = 0; k < index.size (); ++ k)
|
||||
v (index [k]) = value_type/*zero*/();
|
||||
}
|
||||
|
||||
}//namespace detail
|
||||
|
||||
|
||||
// Explicitly iterating
|
||||
template<template <class T1, class T2> class F, class V, class T>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void iterating_vector_assign_scalar (V &v, const T &t) {
|
||||
typedef F<typename V::iterator::reference, T> functor_type;
|
||||
typedef typename V::difference_type difference_type;
|
||||
difference_type size (v.size ());
|
||||
typename V::iterator it (v.begin ());
|
||||
BOOST_UBLAS_CHECK (v.end () - it == size, bad_size ());
|
||||
#ifndef BOOST_UBLAS_USE_DUFF_DEVICE
|
||||
while (-- size >= 0)
|
||||
functor_type::apply (*it, t), ++ it;
|
||||
#else
|
||||
DD (size, 4, r, (functor_type::apply (*it, t), ++ it));
|
||||
#endif
|
||||
}
|
||||
// Explicitly case
|
||||
template<template <class T1, class T2> class F, class V, class T>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void indexing_vector_assign_scalar (V &v, const T &t) {
|
||||
typedef F<typename V::reference, T> functor_type;
|
||||
typedef typename V::size_type size_type;
|
||||
size_type size (v.size ());
|
||||
#ifndef BOOST_UBLAS_USE_DUFF_DEVICE
|
||||
for (size_type i = 0; i < size; ++ i)
|
||||
functor_type::apply (v (i), t);
|
||||
#else
|
||||
size_type i (0);
|
||||
DD (size, 4, r, (functor_type::apply (v (i), t), ++ i));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Dense (proxy) case
|
||||
template<template <class T1, class T2> class F, class V, class T>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void vector_assign_scalar (V &v, const T &t, dense_proxy_tag) {
|
||||
#ifdef BOOST_UBLAS_USE_INDEXING
|
||||
indexing_vector_assign_scalar<F> (v, t);
|
||||
#elif BOOST_UBLAS_USE_ITERATING
|
||||
iterating_vector_assign_scalar<F> (v, t);
|
||||
#else
|
||||
typedef typename V::size_type size_type;
|
||||
size_type size (v.size ());
|
||||
if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
|
||||
iterating_vector_assign_scalar<F> (v, t);
|
||||
else
|
||||
indexing_vector_assign_scalar<F> (v, t);
|
||||
#endif
|
||||
}
|
||||
// Packed (proxy) case
|
||||
template<template <class T1, class T2> class F, class V, class T>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void vector_assign_scalar (V &v, const T &t, packed_proxy_tag) {
|
||||
typedef F<typename V::iterator::reference, T> functor_type;
|
||||
typedef typename V::difference_type difference_type;
|
||||
typename V::iterator it (v.begin ());
|
||||
difference_type size (v.end () - it);
|
||||
while (-- size >= 0)
|
||||
functor_type::apply (*it, t), ++ it;
|
||||
}
|
||||
// Sparse (proxy) case
|
||||
template<template <class T1, class T2> class F, class V, class T>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void vector_assign_scalar (V &v, const T &t, sparse_proxy_tag) {
|
||||
typedef F<typename V::iterator::reference, T> functor_type;
|
||||
typename V::iterator it (v.begin ());
|
||||
typename V::iterator it_end (v.end ());
|
||||
while (it != it_end)
|
||||
functor_type::apply (*it, t), ++ it;
|
||||
}
|
||||
|
||||
// Dispatcher
|
||||
template<template <class T1, class T2> class F, class V, class T>
|
||||
BOOST_UBLAS_INLINE
|
||||
void vector_assign_scalar (V &v, const T &t) {
|
||||
typedef typename V::storage_category storage_category;
|
||||
vector_assign_scalar<F> (v, t, storage_category ());
|
||||
}
|
||||
|
||||
template<class SC, bool COMPUTED, class RI>
|
||||
struct vector_assign_traits {
|
||||
typedef SC storage_category;
|
||||
};
|
||||
|
||||
template<bool COMPUTED>
|
||||
struct vector_assign_traits<dense_tag, COMPUTED, packed_random_access_iterator_tag> {
|
||||
typedef packed_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct vector_assign_traits<dense_tag, false, sparse_bidirectional_iterator_tag> {
|
||||
typedef sparse_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct vector_assign_traits<dense_tag, true, sparse_bidirectional_iterator_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
|
||||
template<bool COMPUTED>
|
||||
struct vector_assign_traits<dense_proxy_tag, COMPUTED, packed_random_access_iterator_tag> {
|
||||
typedef packed_proxy_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct vector_assign_traits<dense_proxy_tag, false, sparse_bidirectional_iterator_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct vector_assign_traits<dense_proxy_tag, true, sparse_bidirectional_iterator_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct vector_assign_traits<packed_tag, false, sparse_bidirectional_iterator_tag> {
|
||||
typedef sparse_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct vector_assign_traits<packed_tag, true, sparse_bidirectional_iterator_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
|
||||
template<bool COMPUTED>
|
||||
struct vector_assign_traits<packed_proxy_tag, COMPUTED, sparse_bidirectional_iterator_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct vector_assign_traits<sparse_tag, true, dense_random_access_iterator_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct vector_assign_traits<sparse_tag, true, packed_random_access_iterator_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct vector_assign_traits<sparse_tag, true, sparse_bidirectional_iterator_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
|
||||
// Explicitly iterating
|
||||
template<template <class T1, class T2> class F, class V, class E>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void iterating_vector_assign (V &v, const vector_expression<E> &e) {
|
||||
typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
|
||||
typedef typename V::difference_type difference_type;
|
||||
difference_type size (BOOST_UBLAS_SAME (v.size (), e ().size ()));
|
||||
typename V::iterator it (v.begin ());
|
||||
BOOST_UBLAS_CHECK (v.end () - it == size, bad_size ());
|
||||
typename E::const_iterator ite (e ().begin ());
|
||||
BOOST_UBLAS_CHECK (e ().end () - ite == size, bad_size ());
|
||||
#ifndef BOOST_UBLAS_USE_DUFF_DEVICE
|
||||
while (-- size >= 0)
|
||||
functor_type::apply (*it, *ite), ++ it, ++ ite;
|
||||
#else
|
||||
DD (size, 2, r, (functor_type::apply (*it, *ite), ++ it, ++ ite));
|
||||
#endif
|
||||
}
|
||||
// Explicitly indexing
|
||||
template<template <class T1, class T2> class F, class V, class E>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void indexing_vector_assign (V &v, const vector_expression<E> &e) {
|
||||
typedef F<typename V::reference, typename E::value_type> functor_type;
|
||||
typedef typename V::size_type size_type;
|
||||
size_type size (BOOST_UBLAS_SAME (v.size (), e ().size ()));
|
||||
#ifndef BOOST_UBLAS_USE_DUFF_DEVICE
|
||||
for (size_type i = 0; i < size; ++ i)
|
||||
functor_type::apply (v (i), e () (i));
|
||||
#else
|
||||
size_type i (0);
|
||||
DD (size, 2, r, (functor_type::apply (v (i), e () (i)), ++ i));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Dense (proxy) case
|
||||
template<template <class T1, class T2> class F, class V, class E>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void vector_assign (V &v, const vector_expression<E> &e, dense_proxy_tag) {
|
||||
#ifdef BOOST_UBLAS_USE_INDEXING
|
||||
indexing_vector_assign<F> (v, e);
|
||||
#elif BOOST_UBLAS_USE_ITERATING
|
||||
iterating_vector_assign<F> (v, e);
|
||||
#else
|
||||
typedef typename V::size_type size_type;
|
||||
size_type size (BOOST_UBLAS_SAME (v.size (), e ().size ()));
|
||||
if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
|
||||
iterating_vector_assign<F> (v, e);
|
||||
else
|
||||
indexing_vector_assign<F> (v, e);
|
||||
#endif
|
||||
}
|
||||
// Packed (proxy) case
|
||||
template<template <class T1, class T2> class F, class V, class E>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void vector_assign (V &v, const vector_expression<E> &e, packed_proxy_tag) {
|
||||
BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
|
||||
typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
|
||||
typedef typename V::difference_type difference_type;
|
||||
typedef typename V::value_type value_type;
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
vector<value_type> cv (v.size ());
|
||||
indexing_vector_assign<scalar_assign> (cv, v);
|
||||
indexing_vector_assign<F> (cv, e);
|
||||
#endif
|
||||
typename V::iterator it (v.begin ());
|
||||
typename V::iterator it_end (v.end ());
|
||||
typename E::const_iterator ite (e ().begin ());
|
||||
typename E::const_iterator ite_end (e ().end ());
|
||||
difference_type it_size (it_end - it);
|
||||
difference_type ite_size (ite_end - ite);
|
||||
if (it_size > 0 && ite_size > 0) {
|
||||
difference_type size ((std::min) (difference_type (it.index () - ite.index ()), ite_size));
|
||||
if (size > 0) {
|
||||
ite += size;
|
||||
ite_size -= size;
|
||||
}
|
||||
}
|
||||
if (it_size > 0 && ite_size > 0) {
|
||||
difference_type size ((std::min) (difference_type (ite.index () - it.index ()), it_size));
|
||||
if (size > 0) {
|
||||
it_size -= size;
|
||||
//Disabled warning C4127 because the conditional expression is constant
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127)
|
||||
#endif
|
||||
if (!functor_type::computed) {
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
while (-- size >= 0) // zeroing
|
||||
functor_type::apply (*it, value_type/*zero*/()), ++ it;
|
||||
} else {
|
||||
it += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
difference_type size ((std::min) (it_size, ite_size));
|
||||
it_size -= size;
|
||||
ite_size -= size;
|
||||
while (-- size >= 0)
|
||||
functor_type::apply (*it, *ite), ++ it, ++ ite;
|
||||
size = it_size;
|
||||
//Disabled warning C4127 because the conditional expression is constant
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127)
|
||||
#endif
|
||||
if (!functor_type::computed) {
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
while (-- size >= 0) // zeroing
|
||||
functor_type::apply (*it, value_type/*zero*/()), ++ it;
|
||||
} else {
|
||||
it += size;
|
||||
}
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
if (! disable_type_check<bool>::value)
|
||||
BOOST_UBLAS_CHECK (detail::expression_type_check (v, cv),
|
||||
external_logic ("external logic or bad condition of inputs"));
|
||||
#endif
|
||||
}
|
||||
// Sparse case
|
||||
template<template <class T1, class T2> class F, class V, class E>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void vector_assign (V &v, const vector_expression<E> &e, sparse_tag) {
|
||||
BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
|
||||
typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
|
||||
//Disabled warning C4127 because the conditional expression is constant
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127)
|
||||
#endif
|
||||
BOOST_STATIC_ASSERT ((!functor_type::computed));
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
typedef typename V::value_type value_type;
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
vector<value_type> cv (v.size ());
|
||||
indexing_vector_assign<scalar_assign> (cv, v);
|
||||
indexing_vector_assign<F> (cv, e);
|
||||
#endif
|
||||
v.clear ();
|
||||
typename E::const_iterator ite (e ().begin ());
|
||||
typename E::const_iterator ite_end (e ().end ());
|
||||
while (ite != ite_end) {
|
||||
value_type t (*ite);
|
||||
if (t != value_type/*zero*/())
|
||||
v.insert_element (ite.index (), t);
|
||||
++ ite;
|
||||
}
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
if (! disable_type_check<bool>::value)
|
||||
BOOST_UBLAS_CHECK (detail::expression_type_check (v, cv),
|
||||
external_logic ("external logic or bad condition of inputs"));
|
||||
#endif
|
||||
}
|
||||
// Sparse proxy or functional case
|
||||
template<template <class T1, class T2> class F, class V, class E>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void vector_assign (V &v, const vector_expression<E> &e, sparse_proxy_tag) {
|
||||
BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
|
||||
typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
|
||||
typedef typename V::size_type size_type;
|
||||
typedef typename V::difference_type difference_type;
|
||||
typedef typename V::value_type value_type;
|
||||
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
vector<value_type> cv (v.size ());
|
||||
indexing_vector_assign<scalar_assign> (cv, v);
|
||||
indexing_vector_assign<F> (cv, e);
|
||||
#endif
|
||||
detail::make_conformant (v, e);
|
||||
|
||||
typename V::iterator it (v.begin ());
|
||||
typename V::iterator it_end (v.end ());
|
||||
typename E::const_iterator ite (e ().begin ());
|
||||
typename E::const_iterator ite_end (e ().end ());
|
||||
if (it != it_end && ite != ite_end) {
|
||||
size_type it_index = it.index (), ite_index = ite.index ();
|
||||
for (;;) {
|
||||
difference_type compare = it_index - ite_index;
|
||||
if (compare == 0) {
|
||||
functor_type::apply (*it, *ite);
|
||||
++ it, ++ ite;
|
||||
if (it != it_end && ite != ite_end) {
|
||||
it_index = it.index ();
|
||||
ite_index = ite.index ();
|
||||
} else
|
||||
break;
|
||||
} else if (compare < 0) {
|
||||
//Disabled warning C4127 because the conditional expression is constant
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127)
|
||||
#endif
|
||||
if (!functor_type::computed) {
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
functor_type::apply (*it, value_type/*zero*/());
|
||||
++ it;
|
||||
} else
|
||||
increment (it, it_end, - compare);
|
||||
if (it != it_end)
|
||||
it_index = it.index ();
|
||||
else
|
||||
break;
|
||||
} else if (compare > 0) {
|
||||
increment (ite, ite_end, compare);
|
||||
if (ite != ite_end)
|
||||
ite_index = ite.index ();
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Disabled warning C4127 because the conditional expression is constant
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127)
|
||||
#endif
|
||||
if (!functor_type::computed) {
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
while (it != it_end) { // zeroing
|
||||
functor_type::apply (*it, value_type/*zero*/());
|
||||
++ it;
|
||||
}
|
||||
} else {
|
||||
it = it_end;
|
||||
}
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
if (! disable_type_check<bool>::value)
|
||||
BOOST_UBLAS_CHECK (detail::expression_type_check (v, cv),
|
||||
external_logic ("external logic or bad condition of inputs"));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Dispatcher
|
||||
template<template <class T1, class T2> class F, class V, class E>
|
||||
BOOST_UBLAS_INLINE
|
||||
void vector_assign (V &v, const vector_expression<E> &e) {
|
||||
typedef typename vector_assign_traits<typename V::storage_category,
|
||||
F<typename V::reference, typename E::value_type>::computed,
|
||||
typename E::const_iterator::iterator_category>::storage_category storage_category;
|
||||
vector_assign<F> (v, e, storage_category ());
|
||||
}
|
||||
|
||||
template<class SC, class RI>
|
||||
struct vector_swap_traits {
|
||||
typedef SC storage_category;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct vector_swap_traits<dense_proxy_tag, sparse_bidirectional_iterator_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct vector_swap_traits<packed_proxy_tag, sparse_bidirectional_iterator_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
|
||||
// Dense (proxy) case
|
||||
template<template <class T1, class T2> class F, class V, class E>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void vector_swap (V &v, vector_expression<E> &e, dense_proxy_tag) {
|
||||
typedef F<typename V::iterator::reference, typename E::iterator::reference> functor_type;
|
||||
typedef typename V::difference_type difference_type;
|
||||
difference_type size (BOOST_UBLAS_SAME (v.size (), e ().size ()));
|
||||
typename V::iterator it (v.begin ());
|
||||
typename E::iterator ite (e ().begin ());
|
||||
while (-- size >= 0)
|
||||
functor_type::apply (*it, *ite), ++ it, ++ ite;
|
||||
}
|
||||
// Packed (proxy) case
|
||||
template<template <class T1, class T2> class F, class V, class E>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void vector_swap (V &v, vector_expression<E> &e, packed_proxy_tag) {
|
||||
typedef F<typename V::iterator::reference, typename E::iterator::reference> functor_type;
|
||||
typedef typename V::difference_type difference_type;
|
||||
typename V::iterator it (v.begin ());
|
||||
typename V::iterator it_end (v.end ());
|
||||
typename E::iterator ite (e ().begin ());
|
||||
typename E::iterator ite_end (e ().end ());
|
||||
difference_type it_size (it_end - it);
|
||||
difference_type ite_size (ite_end - ite);
|
||||
if (it_size > 0 && ite_size > 0) {
|
||||
difference_type size ((std::min) (difference_type (it.index () - ite.index ()), ite_size));
|
||||
if (size > 0) {
|
||||
ite += size;
|
||||
ite_size -= size;
|
||||
}
|
||||
}
|
||||
if (it_size > 0 && ite_size > 0) {
|
||||
difference_type size ((std::min) (difference_type (ite.index () - it.index ()), it_size));
|
||||
if (size > 0)
|
||||
it_size -= size;
|
||||
}
|
||||
difference_type size ((std::min) (it_size, ite_size));
|
||||
it_size -= size;
|
||||
ite_size -= size;
|
||||
while (-- size >= 0)
|
||||
functor_type::apply (*it, *ite), ++ it, ++ ite;
|
||||
}
|
||||
// Sparse proxy case
|
||||
template<template <class T1, class T2> class F, class V, class E>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void vector_swap (V &v, vector_expression<E> &e, sparse_proxy_tag) {
|
||||
BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
|
||||
typedef F<typename V::iterator::reference, typename E::iterator::reference> functor_type;
|
||||
typedef typename V::size_type size_type;
|
||||
typedef typename V::difference_type difference_type;
|
||||
|
||||
detail::make_conformant (v, e);
|
||||
// FIXME should be a seperate restriction for E
|
||||
detail::make_conformant (e (), v);
|
||||
|
||||
typename V::iterator it (v.begin ());
|
||||
typename V::iterator it_end (v.end ());
|
||||
typename E::iterator ite (e ().begin ());
|
||||
typename E::iterator ite_end (e ().end ());
|
||||
if (it != it_end && ite != ite_end) {
|
||||
size_type it_index = it.index (), ite_index = ite.index ();
|
||||
for (;;) {
|
||||
difference_type compare = it_index - ite_index;
|
||||
if (compare == 0) {
|
||||
functor_type::apply (*it, *ite);
|
||||
++ it, ++ ite;
|
||||
if (it != it_end && ite != ite_end) {
|
||||
it_index = it.index ();
|
||||
ite_index = ite.index ();
|
||||
} else
|
||||
break;
|
||||
} else if (compare < 0) {
|
||||
increment (it, it_end, - compare);
|
||||
if (it != it_end)
|
||||
it_index = it.index ();
|
||||
else
|
||||
break;
|
||||
} else if (compare > 0) {
|
||||
increment (ite, ite_end, compare);
|
||||
if (ite != ite_end)
|
||||
ite_index = ite.index ();
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
increment (ite, ite_end);
|
||||
increment (it, it_end);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Dispatcher
|
||||
template<template <class T1, class T2> class F, class V, class E>
|
||||
BOOST_UBLAS_INLINE
|
||||
void vector_swap (V &v, vector_expression<E> &e) {
|
||||
typedef typename vector_swap_traits<typename V::storage_category,
|
||||
typename E::const_iterator::iterator_category>::storage_category storage_category;
|
||||
vector_swap<F> (v, e, storage_category ());
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
58
include/boost/numeric/ublas/doxydoc.hpp
Normal file
58
include/boost/numeric/ublas/doxydoc.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2010-2011 David Bellot
|
||||
//
|
||||
// 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)
|
||||
|
||||
/** \mainpage BOOST uBLAS: a Linear Algebra Library
|
||||
*
|
||||
* This is the API Reference Documentation.
|
||||
*
|
||||
* \section main_classes Main classes
|
||||
*
|
||||
* \subsection listvector Vectors
|
||||
* - \link #boost::numeric::ublas::vector vector \endlink
|
||||
* - \link #boost::numeric::ublas::bounded_vector bounded_vector \endlink
|
||||
* - \link #boost::numeric::ublas::zero_vector zero_vector \endlink
|
||||
* - \link #boost::numeric::ublas::unit_vector unit_vector \endlink
|
||||
* - \link #boost::numeric::ublas::scalar_vector scalar_vector \endlink
|
||||
* - \link #boost::numeric::ublas::c_vector c_vector \endlink
|
||||
* - \link #boost::numeric::ublas::vector_slice vector_slice \endlink
|
||||
* - \link #boost::numeric::ublas::vector_range vector_range \endlink
|
||||
* - \link #boost::numeric::ublas::vector_indirect vector_indirect \endlink
|
||||
* - \link #boost::numeric::ublas::mapped_vector mapped_vector \endlink
|
||||
* - \link #boost::numeric::ublas::compressed_vector compressed_vector \endlink
|
||||
* - \link #boost::numeric::ublas::coordinate_vector coordinate_vector \endlink
|
||||
* - \link #boost::numeric::ublas::matrix_row matrix_row \endlink
|
||||
* - \link #boost::numeric::ublas::matrix_column matrix_column \endlink
|
||||
*
|
||||
* \subsection listmatrix Matrices
|
||||
* - \link #boost::numeric::ublas::matrix matrix \endlink
|
||||
* - \link #boost::numeric::ublas::banded_matrix banded_matrix \endlink
|
||||
* - \link #boost::numeric::ublas::diagonal_matrix diagonal_matrix \endlink
|
||||
* - \link #boost::numeric::ublas::banded_adaptor banded_adaptor \endlink
|
||||
* - \link #boost::numeric::ublas::diagonal_adaptor diagonal_adaptor \endlink
|
||||
* - \link #boost::numeric::ublas::hermitian_matrix hermitian_matrix \endlink
|
||||
* - \link #boost::numeric::ublas::hermitian_adaptor hermitian_adaptor \endlink
|
||||
* - \link #boost::numeric::ublas::symmetric_matrix symmetric_matrix \endlink
|
||||
* - \link #boost::numeric::ublas::symmetric_adaptor symmetric_adaptor \endlink
|
||||
* - \link #boost::numeric::ublas::triangular_matrix triangular_matrix \endlink
|
||||
* - \link #boost::numeric::ublas::triangular_adaptor triangular_adaptor \endlink
|
||||
* - \link #boost::numeric::ublas::vector_of_vector vector_of_vector \endlink
|
||||
* - \link #boost::numeric::ublas::bounded_matrix bounded_matrix \endlink
|
||||
* - \link #boost::numeric::ublas::zero_matrix zero_matrix \endlink
|
||||
* - \link #boost::numeric::ublas::identity_matrix identity_matrix \endlink
|
||||
* - \link #boost::numeric::ublas::scalar_matrix scalar_matrix \endlink
|
||||
* - \link #boost::numeric::ublas::c_matrix c_matrix \endlink
|
||||
* - \link #boost::numeric::ublas::matrix_vector_range matrix_vector_range \endlink
|
||||
* - \link #boost::numeric::ublas::matrix_vector_slice matrix_vector_slice \endlink
|
||||
* - \link #boost::numeric::ublas::matrix_vector_indirect matrix_vector_indirect \endlink
|
||||
* - \link #boost::numeric::ublas::matrix_range matrix_range \endlink
|
||||
* - \link #boost::numeric::ublas::matrix_slice matrix_slice \endlink
|
||||
* - \link #boost::numeric::ublas::matrix_indirect matrix_indirect \endlink
|
||||
* - \link #boost::numeric::ublas::mapped_matrix mapped_matrix \endlink
|
||||
* - \link #boost::numeric::ublas::mapped_vector_of_mapped_vector mapped_vector_of_mapped_vector \endlink
|
||||
* - \link #boost::numeric::ublas::compressed_matrix compressed_matrix \endlink
|
||||
* - \link #boost::numeric::ublas::coordinate_matrix coordinate_matrix \endlink
|
||||
* - \link #boost::numeric::ublas::generalized_vector_of_vector generalized_vector_of_vector \endlink
|
||||
*/
|
||||
297
include/boost/numeric/ublas/exception.hpp
Normal file
297
include/boost/numeric/ublas/exception.hpp
Normal file
@@ -0,0 +1,297 @@
|
||||
// Copyright (c) 2000-2011 Joerg Walter, Mathias Koch, David Bellot
|
||||
//
|
||||
// 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_EXCEPTION_
|
||||
#define _BOOST_UBLAS_EXCEPTION_
|
||||
|
||||
#if ! defined (BOOST_NO_EXCEPTIONS) && ! defined (BOOST_UBLAS_NO_EXCEPTIONS)
|
||||
#include <stdexcept>
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
#ifndef BOOST_UBLAS_NO_STD_CERR
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
#include <boost/numeric/ublas/detail/config.hpp>
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
/** \brief Exception raised when a division by zero occurs
|
||||
*/
|
||||
struct divide_by_zero
|
||||
#if ! defined (BOOST_NO_EXCEPTIONS) && ! defined (BOOST_UBLAS_NO_EXCEPTIONS)
|
||||
// Inherit from standard exceptions as requested during review.
|
||||
: public std::runtime_error
|
||||
{
|
||||
explicit divide_by_zero (const char *s = "divide by zero") :
|
||||
std::runtime_error (s) {}
|
||||
void raise () {
|
||||
throw *this;
|
||||
}
|
||||
#else
|
||||
{
|
||||
divide_by_zero ()
|
||||
{}
|
||||
explicit divide_by_zero (const char *)
|
||||
{}
|
||||
void raise () {
|
||||
std::abort ();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/** \brief Expception raised when some interal errors occurs like computations errors, zeros values where you should not have zeros, etc...
|
||||
*/
|
||||
struct internal_logic
|
||||
#if ! defined (BOOST_NO_EXCEPTIONS) && ! defined (BOOST_UBLAS_NO_EXCEPTIONS)
|
||||
// Inherit from standard exceptions as requested during review.
|
||||
: public std::logic_error {
|
||||
explicit internal_logic (const char *s = "internal logic") :
|
||||
std::logic_error (s) {}
|
||||
void raise () {
|
||||
throw *this;
|
||||
}
|
||||
#else
|
||||
{
|
||||
internal_logic ()
|
||||
{}
|
||||
explicit internal_logic (const char *)
|
||||
{}
|
||||
void raise () {
|
||||
std::abort ();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct external_logic
|
||||
#if ! defined (BOOST_NO_EXCEPTIONS) && ! defined (BOOST_UBLAS_NO_EXCEPTIONS)
|
||||
// Inherit from standard exceptions as requested during review.
|
||||
: public std::logic_error {
|
||||
explicit external_logic (const char *s = "external logic") :
|
||||
std::logic_error (s) {}
|
||||
// virtual const char *what () const throw () {
|
||||
// return "exception: external logic";
|
||||
// }
|
||||
void raise () {
|
||||
throw *this;
|
||||
}
|
||||
#else
|
||||
{
|
||||
external_logic ()
|
||||
{}
|
||||
explicit external_logic (const char *)
|
||||
{}
|
||||
void raise () {
|
||||
std::abort ();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct bad_argument
|
||||
#if ! defined (BOOST_NO_EXCEPTIONS) && ! defined (BOOST_UBLAS_NO_EXCEPTIONS)
|
||||
// Inherit from standard exceptions as requested during review.
|
||||
: public std::invalid_argument {
|
||||
explicit bad_argument (const char *s = "bad argument") :
|
||||
std::invalid_argument (s) {}
|
||||
void raise () {
|
||||
throw *this;
|
||||
}
|
||||
#else
|
||||
{
|
||||
bad_argument ()
|
||||
{}
|
||||
explicit bad_argument (const char *)
|
||||
{}
|
||||
void raise () {
|
||||
std::abort ();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
*/
|
||||
struct bad_size
|
||||
#if ! defined (BOOST_NO_EXCEPTIONS) && ! defined (BOOST_UBLAS_NO_EXCEPTIONS)
|
||||
// Inherit from standard exceptions as requested during review.
|
||||
: public std::domain_error {
|
||||
explicit bad_size (const char *s = "bad size") :
|
||||
std::domain_error (s) {}
|
||||
void raise () {
|
||||
throw *this;
|
||||
}
|
||||
#else
|
||||
{
|
||||
bad_size ()
|
||||
{}
|
||||
explicit bad_size (const char *)
|
||||
{}
|
||||
void raise () {
|
||||
std::abort ();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct bad_index
|
||||
#if ! defined (BOOST_NO_EXCEPTIONS) && ! defined (BOOST_UBLAS_NO_EXCEPTIONS)
|
||||
// Inherit from standard exceptions as requested during review.
|
||||
: public std::out_of_range {
|
||||
explicit bad_index (const char *s = "bad index") :
|
||||
std::out_of_range (s) {}
|
||||
void raise () {
|
||||
throw *this;
|
||||
}
|
||||
#else
|
||||
{
|
||||
bad_index ()
|
||||
{}
|
||||
explicit bad_index (const char *)
|
||||
{}
|
||||
void raise () {
|
||||
std::abort ();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct singular
|
||||
#if ! defined (BOOST_NO_EXCEPTIONS) && ! defined (BOOST_UBLAS_NO_EXCEPTIONS)
|
||||
// Inherit from standard exceptions as requested during review.
|
||||
: public std::runtime_error {
|
||||
explicit singular (const char *s = "singular") :
|
||||
std::runtime_error (s) {}
|
||||
void raise () {
|
||||
throw *this;
|
||||
}
|
||||
#else
|
||||
{
|
||||
singular ()
|
||||
{}
|
||||
explicit singular (const char *)
|
||||
{}
|
||||
void raise () {
|
||||
std::abort ();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct non_real
|
||||
#if ! defined (BOOST_NO_EXCEPTIONS) && ! defined (BOOST_UBLAS_NO_EXCEPTIONS)
|
||||
// Inherit from standard exceptions as requested during review.
|
||||
: public std::domain_error {
|
||||
explicit non_real (const char *s = "exception: non real") :
|
||||
std::domain_error (s) {}
|
||||
void raise () {
|
||||
throw *this;
|
||||
}
|
||||
#else
|
||||
{
|
||||
non_real ()
|
||||
{}
|
||||
explicit non_real (const char *)
|
||||
{}
|
||||
void raise () {
|
||||
std::abort ();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#if BOOST_UBLAS_CHECK_ENABLE
|
||||
// Macros are equivilent to
|
||||
// template<class E>
|
||||
// BOOST_UBLAS_INLINE
|
||||
// void check (bool expression, const E &e) {
|
||||
// if (! expression)
|
||||
// e.raise ();
|
||||
// }
|
||||
// template<class E>
|
||||
// BOOST_UBLAS_INLINE
|
||||
// void check_ex (bool expression, const char *file, int line, const E &e) {
|
||||
// if (! expression)
|
||||
// e.raise ();
|
||||
// }
|
||||
#ifndef BOOST_UBLAS_NO_STD_CERR
|
||||
#define BOOST_UBLAS_CHECK_FALSE(e) \
|
||||
std::cerr << "Check failed in file " << __FILE__ << " at line " << __LINE__ << ":" << std::endl; \
|
||||
e.raise ();
|
||||
#define BOOST_UBLAS_CHECK(expression, e) \
|
||||
if (! (expression)) { \
|
||||
std::cerr << "Check failed in file " << __FILE__ << " at line " << __LINE__ << ":" << std::endl; \
|
||||
std::cerr << #expression << std::endl; \
|
||||
e.raise (); \
|
||||
}
|
||||
#define BOOST_UBLAS_CHECK_EX(expression, file, line, e) \
|
||||
if (! (expression)) { \
|
||||
std::cerr << "Check failed in file " << (file) << " at line " << (line) << ":" << std::endl; \
|
||||
std::cerr << #expression << std::endl; \
|
||||
e.raise (); \
|
||||
}
|
||||
#else
|
||||
#define BOOST_UBLAS_CHECK_FALSE(e) \
|
||||
e.raise ();
|
||||
#define BOOST_UBLAS_CHECK(expression, e) \
|
||||
if (! (expression)) { \
|
||||
e.raise (); \
|
||||
}
|
||||
#define BOOST_UBLAS_CHECK_EX(expression, file, line, e) \
|
||||
if (! (expression)) { \
|
||||
e.raise (); \
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
// Macros are equivilent to
|
||||
// template<class E>
|
||||
// BOOST_UBLAS_INLINE
|
||||
// void check (bool expression, const E &e) {}
|
||||
// template<class E>
|
||||
// BOOST_UBLAS_INLINE
|
||||
// void check_ex (bool expression, const char *file, int line, const E &e) {}
|
||||
#define BOOST_UBLAS_CHECK_FALSE(e)
|
||||
#define BOOST_UBLAS_CHECK(expression, e)
|
||||
#define BOOST_UBLAS_CHECK_EX(expression, file, line, e)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BOOST_UBLAS_USE_FAST_SAME
|
||||
// Macro is equivilent to
|
||||
// template<class T>
|
||||
// BOOST_UBLAS_INLINE
|
||||
// const T &same_impl (const T &size1, const T &size2) {
|
||||
// BOOST_UBLAS_CHECK (size1 == size2, bad_argument ());
|
||||
// return (std::min) (size1, size2);
|
||||
// }
|
||||
// #define BOOST_UBLAS_SAME(size1, size2) same_impl ((size1), (size2))
|
||||
// need two types here because different containers can have
|
||||
// different size_types (especially sparse types)
|
||||
template<class T1, class T2>
|
||||
BOOST_UBLAS_INLINE
|
||||
// Kresimir Fresl and Dan Muller reported problems with COMO.
|
||||
// We better change the signature instead of libcomo ;-)
|
||||
// const T &same_impl_ex (const T &size1, const T &size2, const char *file, int line) {
|
||||
T1 same_impl_ex (const T1 &size1, const T2 &size2, const char *file, int line) {
|
||||
BOOST_UBLAS_CHECK_EX (size1 == size2, file, line, bad_argument ());
|
||||
return (size1 < size2)?(size1):(size2);
|
||||
}
|
||||
template<class T>
|
||||
BOOST_UBLAS_INLINE
|
||||
T same_impl_ex (const T &size1, const T &size2, const char *file, int line) {
|
||||
BOOST_UBLAS_CHECK_EX (size1 == size2, file, line, bad_argument ());
|
||||
return (std::min) (size1, size2);
|
||||
}
|
||||
#define BOOST_UBLAS_SAME(size1, size2) same_impl_ex ((size1), (size2), __FILE__, __LINE__)
|
||||
#else
|
||||
// Macros are equivilent to
|
||||
// template<class T>
|
||||
// BOOST_UBLAS_INLINE
|
||||
// const T &same_impl (const T &size1, const T &size2) {
|
||||
// return size1;
|
||||
// }
|
||||
// #define BOOST_UBLAS_SAME(size1, size2) same_impl ((size1), (size2))
|
||||
#define BOOST_UBLAS_SAME(size1, size2) (size1)
|
||||
#endif
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
317
include/boost/numeric/ublas/experimental/sparse_view.hpp
Normal file
317
include/boost/numeric/ublas/experimental/sparse_view.hpp
Normal file
@@ -0,0 +1,317 @@
|
||||
//
|
||||
// Copyright (c) 2009
|
||||
// Gunter Winkler
|
||||
//
|
||||
// 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_SPARSE_VIEW_
|
||||
#define _BOOST_UBLAS_SPARSE_VIEW_
|
||||
|
||||
#include <boost/numeric/ublas/matrix_expression.hpp>
|
||||
#include <boost/numeric/ublas/detail/matrix_assign.hpp>
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
#include <boost/numeric/ublas/matrix.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/next_prior.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/numeric/ublas/storage.hpp>
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
// view a chunk of memory as ublas array
|
||||
|
||||
template < class T >
|
||||
class c_array_view
|
||||
: public storage_array< c_array_view<T> > {
|
||||
private:
|
||||
typedef c_array_view<T> self_type;
|
||||
typedef T * pointer;
|
||||
|
||||
public:
|
||||
// TODO: think about a const pointer
|
||||
typedef const pointer array_type;
|
||||
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
typedef T value_type;
|
||||
typedef const T &const_reference;
|
||||
typedef const T *const_pointer;
|
||||
|
||||
typedef const_pointer const_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
//
|
||||
// typedefs required by vector concept
|
||||
//
|
||||
|
||||
typedef dense_tag storage_category;
|
||||
typedef const vector_reference<const self_type> const_closure_type;
|
||||
|
||||
c_array_view(size_type size, array_type data) :
|
||||
size_(size), data_(data)
|
||||
{}
|
||||
|
||||
~c_array_view()
|
||||
{}
|
||||
|
||||
//
|
||||
// immutable methods of container concept
|
||||
//
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
size_type size () const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reference operator [] (size_type i) const {
|
||||
BOOST_UBLAS_CHECK (i < size_, bad_index ());
|
||||
return data_ [i];
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator begin () const {
|
||||
return data_;
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator end () const {
|
||||
return data_ + size_;
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator rbegin () const {
|
||||
return const_reverse_iterator (end ());
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator rend () const {
|
||||
return const_reverse_iterator (begin ());
|
||||
}
|
||||
|
||||
private:
|
||||
size_type size_;
|
||||
array_type data_;
|
||||
};
|
||||
|
||||
|
||||
/** \brief Present existing arrays as compressed array based
|
||||
* sparse matrix.
|
||||
* This class provides CRS / CCS storage layout.
|
||||
*
|
||||
* see also http://www.netlib.org/utk/papers/templates/node90.html
|
||||
*
|
||||
* \param L layout type, either row_major or column_major
|
||||
* \param IB index base, use 0 for C indexing and 1 for
|
||||
* FORTRAN indexing of the internal index arrays. This
|
||||
* does not affect the operator()(int,int) where the first
|
||||
* row/column has always index 0.
|
||||
* \param IA index array type, e.g., int[]
|
||||
* \param TA value array type, e.g., double[]
|
||||
*/
|
||||
template<class L, std::size_t IB, class IA, class JA, class TA>
|
||||
class compressed_matrix_view:
|
||||
public matrix_expression<compressed_matrix_view<L, IB, IA, JA, TA> > {
|
||||
|
||||
public:
|
||||
typedef typename vector_view_traits<TA>::value_type value_type;
|
||||
|
||||
private:
|
||||
typedef value_type &true_reference;
|
||||
typedef value_type *pointer;
|
||||
typedef const value_type *const_pointer;
|
||||
typedef L layout_type;
|
||||
typedef compressed_matrix_view<L, IB, IA, JA, TA> self_type;
|
||||
|
||||
public:
|
||||
#ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
|
||||
using matrix_expression<self_type>::operator ();
|
||||
#endif
|
||||
// ISSUE require type consistency check
|
||||
// is_convertable (IA::size_type, TA::size_type)
|
||||
typedef typename boost::remove_cv<typename vector_view_traits<JA>::value_type>::type index_type;
|
||||
// for compatibility, should be removed some day ...
|
||||
typedef index_type size_type;
|
||||
// size_type for the data arrays.
|
||||
typedef typename vector_view_traits<JA>::size_type array_size_type;
|
||||
typedef typename vector_view_traits<JA>::difference_type difference_type;
|
||||
typedef const value_type & const_reference;
|
||||
|
||||
// do NOT define reference type, because class is read only
|
||||
// typedef value_type & reference;
|
||||
|
||||
typedef IA rowptr_array_type;
|
||||
typedef JA index_array_type;
|
||||
typedef TA value_array_type;
|
||||
typedef const matrix_reference<const self_type> const_closure_type;
|
||||
typedef matrix_reference<self_type> closure_type;
|
||||
|
||||
// FIXME: define a corresponding temporary type
|
||||
// typedef compressed_vector<T, IB, IA, TA> vector_temporary_type;
|
||||
|
||||
// FIXME: define a corresponding temporary type
|
||||
// typedef self_type matrix_temporary_type;
|
||||
|
||||
typedef sparse_tag storage_category;
|
||||
typedef typename L::orientation_category orientation_category;
|
||||
|
||||
//
|
||||
// private types for internal use
|
||||
//
|
||||
|
||||
private:
|
||||
typedef typename vector_view_traits<index_array_type>::const_iterator const_subiterator_type;
|
||||
|
||||
//
|
||||
// Construction and destruction
|
||||
//
|
||||
private:
|
||||
/// private default constructor because data must be filled by caller
|
||||
BOOST_UBLAS_INLINE
|
||||
compressed_matrix_view () { }
|
||||
|
||||
public:
|
||||
BOOST_UBLAS_INLINE
|
||||
compressed_matrix_view (index_type n_rows, index_type n_cols, array_size_type nnz
|
||||
, const rowptr_array_type & iptr
|
||||
, const index_array_type & jptr
|
||||
, const value_array_type & values):
|
||||
matrix_expression<self_type> (),
|
||||
size1_ (n_rows), size2_ (n_cols),
|
||||
nnz_ (nnz),
|
||||
index1_data_ (iptr),
|
||||
index2_data_ (jptr),
|
||||
value_data_ (values) {
|
||||
storage_invariants ();
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
compressed_matrix_view(const compressed_matrix_view& o) :
|
||||
size1_(o.size1_), size2_(o.size2_),
|
||||
nnz_(o.nnz_),
|
||||
index1_data_(o.index1_data_),
|
||||
index2_data_(o.index2_data_),
|
||||
value_data_(o.value_data_)
|
||||
{}
|
||||
|
||||
//
|
||||
// implement immutable iterator types
|
||||
//
|
||||
|
||||
class const_iterator1 {};
|
||||
class const_iterator2 {};
|
||||
|
||||
typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
|
||||
typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
|
||||
|
||||
//
|
||||
// implement all read only methods for the matrix expression concept
|
||||
//
|
||||
|
||||
//! return the number of rows
|
||||
index_type size1() const {
|
||||
return size1_;
|
||||
}
|
||||
|
||||
//! return the number of columns
|
||||
index_type size2() const {
|
||||
return size2_;
|
||||
}
|
||||
|
||||
//! return value at position (i,j)
|
||||
value_type operator()(index_type i, index_type j) const {
|
||||
const_pointer p = find_element(i,j);
|
||||
if (!p) {
|
||||
return zero_;
|
||||
} else {
|
||||
return *p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
//
|
||||
// private helper functions
|
||||
//
|
||||
|
||||
const_pointer find_element (index_type i, index_type j) const {
|
||||
index_type element1 (layout_type::index_M (i, j));
|
||||
index_type element2 (layout_type::index_m (i, j));
|
||||
|
||||
const array_size_type itv = zero_based( index1_data_[element1] );
|
||||
const array_size_type itv_next = zero_based( index1_data_[element1+1] );
|
||||
|
||||
const_subiterator_type it_start = boost::next(vector_view_traits<index_array_type>::begin(index2_data_),itv);
|
||||
const_subiterator_type it_end = boost::next(vector_view_traits<index_array_type>::begin(index2_data_),itv_next);
|
||||
const_subiterator_type it = find_index_in_row(it_start, it_end, element2) ;
|
||||
|
||||
if (it == it_end || *it != k_based (element2))
|
||||
return 0;
|
||||
return &value_data_ [it - vector_view_traits<index_array_type>::begin(index2_data_)];
|
||||
}
|
||||
|
||||
const_subiterator_type find_index_in_row(const_subiterator_type it_start
|
||||
, const_subiterator_type it_end
|
||||
, index_type index) const {
|
||||
return std::lower_bound( it_start
|
||||
, it_end
|
||||
, k_based (index) );
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void storage_invariants () const {
|
||||
BOOST_UBLAS_CHECK (index1_data_ [layout_type::size_M (size1_, size2_)] == k_based (nnz_), external_logic ());
|
||||
}
|
||||
|
||||
index_type size1_;
|
||||
index_type size2_;
|
||||
|
||||
array_size_type nnz_;
|
||||
|
||||
const rowptr_array_type & index1_data_;
|
||||
const index_array_type & index2_data_;
|
||||
const value_array_type & value_data_;
|
||||
|
||||
static const value_type zero_;
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
static index_type zero_based (index_type k_based_index) {
|
||||
return k_based_index - IB;
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
static index_type k_based (index_type zero_based_index) {
|
||||
return zero_based_index + IB;
|
||||
}
|
||||
|
||||
friend class iterator1;
|
||||
friend class iterator2;
|
||||
friend class const_iterator1;
|
||||
friend class const_iterator2;
|
||||
};
|
||||
|
||||
template<class L, std::size_t IB, class IA, class JA, class TA >
|
||||
const typename compressed_matrix_view<L,IB,IA,JA,TA>::value_type
|
||||
compressed_matrix_view<L,IB,IA,JA,TA>::zero_ = value_type/*zero*/();
|
||||
|
||||
|
||||
template<class L, std::size_t IB, class IA, class JA, class TA >
|
||||
compressed_matrix_view<L,IB,IA,JA,TA>
|
||||
make_compressed_matrix_view(typename vector_view_traits<JA>::value_type n_rows
|
||||
, typename vector_view_traits<JA>::value_type n_cols
|
||||
, typename vector_view_traits<JA>::size_type nnz
|
||||
, const IA & ia
|
||||
, const JA & ja
|
||||
, const TA & ta) {
|
||||
|
||||
return compressed_matrix_view<L,IB,IA,JA,TA>(n_rows, n_cols, nnz, ia, ja, ta);
|
||||
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
506
include/boost/numeric/ublas/expression_types.hpp
Normal file
506
include/boost/numeric/ublas/expression_types.hpp
Normal file
@@ -0,0 +1,506 @@
|
||||
// Copyright (c) 2000-2013
|
||||
// Joerg Walter, Mathias Koch. David Bellot
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
#ifndef _BOOST_UBLAS_EXPRESSION_TYPE_
|
||||
#define _BOOST_UBLAS_EXPRESSION_TYPE_
|
||||
|
||||
#include <boost/numeric/ublas/exception.hpp>
|
||||
#include <boost/numeric/ublas/traits.hpp>
|
||||
#include <boost/numeric/ublas/functional.hpp>
|
||||
|
||||
|
||||
// Expression templates based on ideas of Todd Veldhuizen and Geoffrey Furnish
|
||||
// Iterators based on ideas of Jeremy Siek
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
/** \brief Base class for uBLAS statically derived expressions using the the Barton Nackman trick
|
||||
*
|
||||
* This is a NonAssignable class
|
||||
* Directly implement nonassignable - simplifes debugging call trace!
|
||||
*
|
||||
* \tparam E an expression type
|
||||
*/
|
||||
template<class E>
|
||||
class ublas_expression {
|
||||
public:
|
||||
typedef E expression_type;
|
||||
/* E can be an incomplete type - to define the following we would need more template arguments
|
||||
typedef typename E::type_category type_category;
|
||||
typedef typename E::value_type value_type;
|
||||
*/
|
||||
|
||||
protected:
|
||||
ublas_expression () {}
|
||||
~ublas_expression () {}
|
||||
private:
|
||||
const ublas_expression& operator= (const ublas_expression &);
|
||||
};
|
||||
|
||||
|
||||
/** \brief Base class for Scalar Expression models
|
||||
*
|
||||
* It does not model the Scalar Expression concept but all derived types should.
|
||||
* The class defines a common base type and some common interface for all statically
|
||||
* derived Scalar Expression classes.
|
||||
*
|
||||
* We implement the casts to the statically derived type.
|
||||
*
|
||||
* \tparam E an expression type
|
||||
*/
|
||||
template<class E>
|
||||
class scalar_expression:
|
||||
public ublas_expression<E> {
|
||||
public:
|
||||
typedef E expression_type;
|
||||
typedef scalar_tag type_category;
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const expression_type &operator () () const {
|
||||
return *static_cast<const expression_type *> (this);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
expression_type &operator () () {
|
||||
return *static_cast<expression_type *> (this);
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class scalar_reference:
|
||||
public scalar_expression<scalar_reference<T> > {
|
||||
|
||||
typedef scalar_reference<T> self_type;
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef const value_type &const_reference;
|
||||
typedef typename boost::mpl::if_<boost::is_const<T>,
|
||||
const_reference,
|
||||
value_type &>::type reference;
|
||||
typedef const self_type const_closure_type;
|
||||
typedef const_closure_type closure_type;
|
||||
|
||||
// Construction and destruction
|
||||
BOOST_UBLAS_INLINE
|
||||
explicit scalar_reference (reference t):
|
||||
t_ (t) {}
|
||||
|
||||
// Conversion
|
||||
BOOST_UBLAS_INLINE
|
||||
operator value_type () const {
|
||||
return t_;
|
||||
}
|
||||
|
||||
// Assignment
|
||||
BOOST_UBLAS_INLINE
|
||||
scalar_reference &operator = (const scalar_reference &s) {
|
||||
t_ = s.t_;
|
||||
return *this;
|
||||
}
|
||||
template<class AE>
|
||||
BOOST_UBLAS_INLINE
|
||||
scalar_reference &operator = (const scalar_expression<AE> &ae) {
|
||||
t_ = ae;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Closure comparison
|
||||
BOOST_UBLAS_INLINE
|
||||
bool same_closure (const scalar_reference &sr) const {
|
||||
return &t_ == &sr.t_;
|
||||
}
|
||||
|
||||
private:
|
||||
reference t_;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class scalar_value:
|
||||
public scalar_expression<scalar_value<T> > {
|
||||
|
||||
typedef scalar_value<T> self_type;
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef const value_type &const_reference;
|
||||
typedef typename boost::mpl::if_<boost::is_const<T>,
|
||||
const_reference,
|
||||
value_type &>::type reference;
|
||||
typedef const scalar_reference<const self_type> const_closure_type;
|
||||
typedef scalar_reference<self_type> closure_type;
|
||||
|
||||
// Construction and destruction
|
||||
BOOST_UBLAS_INLINE
|
||||
scalar_value ():
|
||||
t_ () {}
|
||||
BOOST_UBLAS_INLINE
|
||||
scalar_value (const value_type &t):
|
||||
t_ (t) {}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
operator value_type () const {
|
||||
return t_;
|
||||
}
|
||||
|
||||
// Assignment
|
||||
BOOST_UBLAS_INLINE
|
||||
scalar_value &operator = (const scalar_value &s) {
|
||||
t_ = s.t_;
|
||||
return *this;
|
||||
}
|
||||
template<class AE>
|
||||
BOOST_UBLAS_INLINE
|
||||
scalar_value &operator = (const scalar_expression<AE> &ae) {
|
||||
t_ = ae;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Closure comparison
|
||||
BOOST_UBLAS_INLINE
|
||||
bool same_closure (const scalar_value &sv) const {
|
||||
return this == &sv; // self closing on instances value
|
||||
}
|
||||
|
||||
private:
|
||||
value_type t_;
|
||||
};
|
||||
|
||||
|
||||
/** \brief Base class for Vector Expression models
|
||||
*
|
||||
* it does not model the Vector Expression concept but all derived types should.
|
||||
* The class defines a common base type and some common interface for all
|
||||
* statically derived Vector Expression classes.
|
||||
* We implement the casts to the statically derived type.
|
||||
*/
|
||||
template<class E>
|
||||
class vector_expression:
|
||||
public ublas_expression<E> {
|
||||
public:
|
||||
static const unsigned complexity = 0;
|
||||
typedef E expression_type;
|
||||
typedef vector_tag type_category;
|
||||
/* E can be an incomplete type - to define the following we would need more template arguments
|
||||
typedef typename E::size_type size_type;
|
||||
*/
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const expression_type &operator () () const {
|
||||
return *static_cast<const expression_type *> (this);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
expression_type &operator () () {
|
||||
return *static_cast<expression_type *> (this);
|
||||
}
|
||||
|
||||
#ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
|
||||
private:
|
||||
// projection types
|
||||
typedef vector_range<E> vector_range_type;
|
||||
typedef vector_range<const E> const_vector_range_type;
|
||||
typedef vector_slice<E> vector_slice_type;
|
||||
typedef vector_slice<const E> const_vector_slice_type;
|
||||
// vector_indirect_type will depend on the A template parameter
|
||||
typedef basic_range<> default_range; // required to avoid range/slice name confusion
|
||||
typedef basic_slice<> default_slice;
|
||||
public:
|
||||
BOOST_UBLAS_INLINE
|
||||
const_vector_range_type operator () (const default_range &r) const {
|
||||
return const_vector_range_type (operator () (), r);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
vector_range_type operator () (const default_range &r) {
|
||||
return vector_range_type (operator () (), r);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_vector_slice_type operator () (const default_slice &s) const {
|
||||
return const_vector_slice_type (operator () (), s);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
vector_slice_type operator () (const default_slice &s) {
|
||||
return vector_slice_type (operator () (), s);
|
||||
}
|
||||
template<class A>
|
||||
BOOST_UBLAS_INLINE
|
||||
const vector_indirect<const E, indirect_array<A> > operator () (const indirect_array<A> &ia) const {
|
||||
return vector_indirect<const E, indirect_array<A> > (operator () (), ia);
|
||||
}
|
||||
template<class A>
|
||||
BOOST_UBLAS_INLINE
|
||||
vector_indirect<E, indirect_array<A> > operator () (const indirect_array<A> &ia) {
|
||||
return vector_indirect<E, indirect_array<A> > (operator () (), ia);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_vector_range_type project (const default_range &r) const {
|
||||
return const_vector_range_type (operator () (), r);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
vector_range_type project (const default_range &r) {
|
||||
return vector_range_type (operator () (), r);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_vector_slice_type project (const default_slice &s) const {
|
||||
return const_vector_slice_type (operator () (), s);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
vector_slice_type project (const default_slice &s) {
|
||||
return vector_slice_type (operator () (), s);
|
||||
}
|
||||
template<class A>
|
||||
BOOST_UBLAS_INLINE
|
||||
const vector_indirect<const E, indirect_array<A> > project (const indirect_array<A> &ia) const {
|
||||
return vector_indirect<const E, indirect_array<A> > (operator () (), ia);
|
||||
}
|
||||
template<class A>
|
||||
BOOST_UBLAS_INLINE
|
||||
vector_indirect<E, indirect_array<A> > project (const indirect_array<A> &ia) {
|
||||
return vector_indirect<E, indirect_array<A> > (operator () (), ia);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/** \brief Base class for Vector container models
|
||||
*
|
||||
* it does not model the Vector concept but all derived types should.
|
||||
* The class defines a common base type and some common interface for all
|
||||
* statically derived Vector classes
|
||||
* We implement the casts to the statically derived type.
|
||||
*/
|
||||
template<class C>
|
||||
class vector_container:
|
||||
public vector_expression<C> {
|
||||
public:
|
||||
static const unsigned complexity = 0;
|
||||
typedef C container_type;
|
||||
typedef vector_tag type_category;
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const container_type &operator () () const {
|
||||
return *static_cast<const container_type *> (this);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
container_type &operator () () {
|
||||
return *static_cast<container_type *> (this);
|
||||
}
|
||||
|
||||
#ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
|
||||
using vector_expression<C>::operator ();
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/** \brief Base class for Matrix Expression models
|
||||
*
|
||||
* it does not model the Matrix Expression concept but all derived types should.
|
||||
* The class defines a common base type and some common interface for all
|
||||
* statically derived Matrix Expression classes
|
||||
* We implement the casts to the statically derived type.
|
||||
*/
|
||||
template<class E>
|
||||
class matrix_expression:
|
||||
public ublas_expression<E> {
|
||||
private:
|
||||
typedef matrix_expression<E> self_type;
|
||||
public:
|
||||
static const unsigned complexity = 0;
|
||||
typedef E expression_type;
|
||||
typedef matrix_tag type_category;
|
||||
/* E can be an incomplete type - to define the following we would need more template arguments
|
||||
typedef typename E::size_type size_type;
|
||||
*/
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const expression_type &operator () () const {
|
||||
return *static_cast<const expression_type *> (this);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
expression_type &operator () () {
|
||||
return *static_cast<expression_type *> (this);
|
||||
}
|
||||
|
||||
#ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
|
||||
private:
|
||||
// projection types
|
||||
typedef vector_range<E> vector_range_type;
|
||||
typedef const vector_range<const E> const_vector_range_type;
|
||||
typedef vector_slice<E> vector_slice_type;
|
||||
typedef const vector_slice<const E> const_vector_slice_type;
|
||||
typedef matrix_row<E> matrix_row_type;
|
||||
typedef const matrix_row<const E> const_matrix_row_type;
|
||||
typedef matrix_column<E> matrix_column_type;
|
||||
typedef const matrix_column<const E> const_matrix_column_type;
|
||||
typedef matrix_range<E> matrix_range_type;
|
||||
typedef const matrix_range<const E> const_matrix_range_type;
|
||||
typedef matrix_slice<E> matrix_slice_type;
|
||||
typedef const matrix_slice<const E> const_matrix_slice_type;
|
||||
// matrix_indirect_type will depend on the A template parameter
|
||||
typedef basic_range<> default_range; // required to avoid range/slice name confusion
|
||||
typedef basic_slice<> default_slice;
|
||||
|
||||
public:
|
||||
BOOST_UBLAS_INLINE
|
||||
const_matrix_row_type operator [] (std::size_t i) const {
|
||||
return const_matrix_row_type (operator () (), i);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_row_type operator [] (std::size_t i) {
|
||||
return matrix_row_type (operator () (), i);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_matrix_row_type row (std::size_t i) const {
|
||||
return const_matrix_row_type (operator () (), i);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_row_type row (std::size_t i) {
|
||||
return matrix_row_type (operator () (), i);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_matrix_column_type column (std::size_t j) const {
|
||||
return const_matrix_column_type (operator () (), j);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_column_type column (std::size_t j) {
|
||||
return matrix_column_type (operator () (), j);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_matrix_range_type operator () (const default_range &r1, const default_range &r2) const {
|
||||
return const_matrix_range_type (operator () (), r1, r2);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_range_type operator () (const default_range &r1, const default_range &r2) {
|
||||
return matrix_range_type (operator () (), r1, r2);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_matrix_slice_type operator () (const default_slice &s1, const default_slice &s2) const {
|
||||
return const_matrix_slice_type (operator () (), s1, s2);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_slice_type operator () (const default_slice &s1, const default_slice &s2) {
|
||||
return matrix_slice_type (operator () (), s1, s2);
|
||||
}
|
||||
template<class A>
|
||||
BOOST_UBLAS_INLINE
|
||||
const matrix_indirect<const E, indirect_array<A> > operator () (const indirect_array<A> &ia1, const indirect_array<A> &ia2) const {
|
||||
return matrix_indirect<const E, indirect_array<A> > (operator () (), ia1, ia2);
|
||||
}
|
||||
template<class A>
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_indirect<E, indirect_array<A> > operator () (const indirect_array<A> &ia1, const indirect_array<A> &ia2) {
|
||||
return matrix_indirect<E, indirect_array<A> > (operator () (), ia1, ia2);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_matrix_range_type project (const default_range &r1, const default_range &r2) const {
|
||||
return const_matrix_range_type (operator () (), r1, r2);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_range_type project (const default_range &r1, const default_range &r2) {
|
||||
return matrix_range_type (operator () (), r1, r2);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_matrix_slice_type project (const default_slice &s1, const default_slice &s2) const {
|
||||
return const_matrix_slice_type (operator () (), s1, s2);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_slice_type project (const default_slice &s1, const default_slice &s2) {
|
||||
return matrix_slice_type (operator () (), s1, s2);
|
||||
}
|
||||
template<class A>
|
||||
BOOST_UBLAS_INLINE
|
||||
const matrix_indirect<const E, indirect_array<A> > project (const indirect_array<A> &ia1, const indirect_array<A> &ia2) const {
|
||||
return matrix_indirect<const E, indirect_array<A> > (operator () (), ia1, ia2);
|
||||
}
|
||||
template<class A>
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_indirect<E, indirect_array<A> > project (const indirect_array<A> &ia1, const indirect_array<A> &ia2) {
|
||||
return matrix_indirect<E, indirect_array<A> > (operator () (), ia1, ia2);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
||||
struct iterator1_tag {};
|
||||
struct iterator2_tag {};
|
||||
|
||||
template<class I>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename I::dual_iterator_type begin (const I &it, iterator1_tag) {
|
||||
return it ().find2 (1, it.index1 (), 0);
|
||||
}
|
||||
template<class I>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename I::dual_iterator_type end (const I &it, iterator1_tag) {
|
||||
return it ().find2 (1, it.index1 (), it ().size2 ());
|
||||
}
|
||||
template<class I>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename I::dual_reverse_iterator_type rbegin (const I &it, iterator1_tag) {
|
||||
return typename I::dual_reverse_iterator_type (end (it, iterator1_tag ()));
|
||||
}
|
||||
template<class I>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename I::dual_reverse_iterator_type rend (const I &it, iterator1_tag) {
|
||||
return typename I::dual_reverse_iterator_type (begin (it, iterator1_tag ()));
|
||||
}
|
||||
|
||||
template<class I>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename I::dual_iterator_type begin (const I &it, iterator2_tag) {
|
||||
return it ().find1 (1, 0, it.index2 ());
|
||||
}
|
||||
template<class I>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename I::dual_iterator_type end (const I &it, iterator2_tag) {
|
||||
return it ().find1 (1, it ().size1 (), it.index2 ());
|
||||
}
|
||||
template<class I>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename I::dual_reverse_iterator_type rbegin (const I &it, iterator2_tag) {
|
||||
return typename I::dual_reverse_iterator_type (end (it, iterator2_tag ()));
|
||||
}
|
||||
template<class I>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename I::dual_reverse_iterator_type rend (const I &it, iterator2_tag) {
|
||||
return typename I::dual_reverse_iterator_type (begin (it, iterator2_tag ()));
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \brief Base class for Matrix container models
|
||||
*
|
||||
* it does not model the Matrix concept but all derived types should.
|
||||
* The class defines a common base type and some common interface for all
|
||||
* statically derived Matrix classes
|
||||
* We implement the casts to the statically derived type.
|
||||
*/
|
||||
template<class C>
|
||||
class matrix_container:
|
||||
public matrix_expression<C> {
|
||||
public:
|
||||
static const unsigned complexity = 0;
|
||||
typedef C container_type;
|
||||
typedef matrix_tag type_category;
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const container_type &operator () () const {
|
||||
return *static_cast<const container_type *> (this);
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
container_type &operator () () {
|
||||
return *static_cast<container_type *> (this);
|
||||
}
|
||||
|
||||
#ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
|
||||
using matrix_expression<C>::operator ();
|
||||
#endif
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
2112
include/boost/numeric/ublas/functional.hpp
Normal file
2112
include/boost/numeric/ublas/functional.hpp
Normal file
File diff suppressed because it is too large
Load Diff
229
include/boost/numeric/ublas/fwd.hpp
Normal file
229
include/boost/numeric/ublas/fwd.hpp
Normal file
@@ -0,0 +1,229 @@
|
||||
//
|
||||
// Copyright (c) 2000-2010
|
||||
// Joerg Walter, Mathias Koch, David Bellot
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
/// \file fwd.hpp is essentially used to forward declare the main types
|
||||
|
||||
#ifndef BOOST_UBLAS_FWD_H
|
||||
#define BOOST_UBLAS_FWD_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef BOOST_UBLAS_CPP_GE_2011
|
||||
#include <array>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
// Storage types
|
||||
template<class T, class ALLOC = std::allocator<T> >
|
||||
class unbounded_array;
|
||||
|
||||
template<class T, std::size_t N, class ALLOC = std::allocator<T> >
|
||||
class bounded_array;
|
||||
|
||||
template <class Z = std::size_t, class D = std::ptrdiff_t>
|
||||
class basic_range;
|
||||
template <class Z = std::size_t, class D = std::ptrdiff_t>
|
||||
class basic_slice;
|
||||
typedef basic_range<> range;
|
||||
typedef basic_slice<> slice;
|
||||
template<class A = unbounded_array<std::size_t> >
|
||||
class indirect_array;
|
||||
|
||||
template<class I, class T, class ALLOC = std::allocator<std::pair<const I, T> > >
|
||||
class map_std;
|
||||
template<class I, class T, class ALLOC = std::allocator<std::pair<I, T> > >
|
||||
class map_array;
|
||||
|
||||
// Expression types
|
||||
struct scalar_tag {};
|
||||
|
||||
struct vector_tag {};
|
||||
template<class E>
|
||||
class vector_expression;
|
||||
template<class C>
|
||||
class vector_container;
|
||||
|
||||
template<class E>
|
||||
class vector_reference;
|
||||
|
||||
struct matrix_tag {};
|
||||
|
||||
template<class E>
|
||||
class matrix_expression;
|
||||
template<class C>
|
||||
class matrix_container;
|
||||
|
||||
template<class E>
|
||||
class matrix_reference;
|
||||
|
||||
template<class V>
|
||||
class vector_range;
|
||||
template<class V>
|
||||
class vector_slice;
|
||||
template<class V, class IA = indirect_array<> >
|
||||
class vector_indirect;
|
||||
|
||||
template<class M>
|
||||
class matrix_row;
|
||||
template<class M>
|
||||
class matrix_column;
|
||||
template<class M>
|
||||
class matrix_vector_range;
|
||||
template<class M>
|
||||
class matrix_vector_slice;
|
||||
template<class M, class IA = indirect_array<> >
|
||||
class matrix_vector_indirect;
|
||||
template<class M>
|
||||
class matrix_range;
|
||||
template<class M>
|
||||
class matrix_slice;
|
||||
template<class M, class IA = indirect_array<> >
|
||||
class matrix_indirect;
|
||||
|
||||
template<class T, class A = unbounded_array<T> >
|
||||
class vector;
|
||||
#ifdef BOOST_UBLAS_CPP_GE_2011
|
||||
template<class T, std::size_t N, class A = std::array<T, N> >
|
||||
class fixed_vector;
|
||||
#endif
|
||||
template<class T, std::size_t N>
|
||||
class bounded_vector;
|
||||
|
||||
template<class T = int, class ALLOC = std::allocator<T> >
|
||||
class unit_vector;
|
||||
template<class T = int, class ALLOC = std::allocator<T> >
|
||||
class zero_vector;
|
||||
template<class T = int, class ALLOC = std::allocator<T> >
|
||||
class scalar_vector;
|
||||
|
||||
template<class T, std::size_t N>
|
||||
class c_vector;
|
||||
|
||||
// Sparse vectors
|
||||
template<class T, class A = map_std<std::size_t, T> >
|
||||
class mapped_vector;
|
||||
template<class T, std::size_t IB = 0, class IA = unbounded_array<std::size_t>, class TA = unbounded_array<T> >
|
||||
class compressed_vector;
|
||||
template<class T, std::size_t IB = 0, class IA = unbounded_array<std::size_t>, class TA = unbounded_array<T> >
|
||||
class coordinate_vector;
|
||||
|
||||
// Matrix orientation type
|
||||
struct unknown_orientation_tag {};
|
||||
struct row_major_tag {};
|
||||
struct column_major_tag {};
|
||||
|
||||
// Matrix storage layout parameterisation
|
||||
template <class Z = std::size_t, class D = std::ptrdiff_t>
|
||||
struct basic_row_major;
|
||||
typedef basic_row_major<> row_major;
|
||||
|
||||
template <class Z = std::size_t, class D = std::ptrdiff_t>
|
||||
struct basic_column_major;
|
||||
typedef basic_column_major<> column_major;
|
||||
|
||||
template<class T, class L = row_major, class A = unbounded_array<T> >
|
||||
class matrix;
|
||||
#ifdef BOOST_UBLAS_CPP_GE_2011
|
||||
template<class T, std::size_t M, std::size_t N, class L = row_major, class A = std::array<T, M*N> >
|
||||
class fixed_matrix;
|
||||
#endif
|
||||
template<class T, std::size_t M, std::size_t N, class L = row_major>
|
||||
class bounded_matrix;
|
||||
|
||||
template<class T = int, class ALLOC = std::allocator<T> >
|
||||
class identity_matrix;
|
||||
template<class T = int, class ALLOC = std::allocator<T> >
|
||||
class zero_matrix;
|
||||
template<class T = int, class ALLOC = std::allocator<T> >
|
||||
class scalar_matrix;
|
||||
|
||||
template<class T, std::size_t M, std::size_t N>
|
||||
class c_matrix;
|
||||
|
||||
template<class T, class L = row_major, class A = unbounded_array<unbounded_array<T> > >
|
||||
class vector_of_vector;
|
||||
|
||||
template<class T, class L = row_major, class A = vector<compressed_vector<T> > >
|
||||
class generalized_vector_of_vector;
|
||||
|
||||
// Triangular matrix type
|
||||
struct lower_tag {};
|
||||
struct upper_tag {};
|
||||
struct unit_lower_tag : public lower_tag {};
|
||||
struct unit_upper_tag : public upper_tag {};
|
||||
struct strict_lower_tag : public lower_tag {};
|
||||
struct strict_upper_tag : public upper_tag {};
|
||||
|
||||
// Triangular matrix parameterisation
|
||||
template <class Z = std::size_t>
|
||||
struct basic_full;
|
||||
typedef basic_full<> full;
|
||||
|
||||
template <class Z = std::size_t>
|
||||
struct basic_lower;
|
||||
typedef basic_lower<> lower;
|
||||
|
||||
template <class Z = std::size_t>
|
||||
struct basic_upper;
|
||||
typedef basic_upper<> upper;
|
||||
|
||||
template <class Z = std::size_t>
|
||||
struct basic_unit_lower;
|
||||
typedef basic_unit_lower<> unit_lower;
|
||||
|
||||
template <class Z = std::size_t>
|
||||
struct basic_unit_upper;
|
||||
typedef basic_unit_upper<> unit_upper;
|
||||
|
||||
template <class Z = std::size_t>
|
||||
struct basic_strict_lower;
|
||||
typedef basic_strict_lower<> strict_lower;
|
||||
|
||||
template <class Z = std::size_t>
|
||||
struct basic_strict_upper;
|
||||
typedef basic_strict_upper<> strict_upper;
|
||||
|
||||
// Special matrices
|
||||
template<class T, class L = row_major, class A = unbounded_array<T> >
|
||||
class banded_matrix;
|
||||
template<class T, class L = row_major, class A = unbounded_array<T> >
|
||||
class diagonal_matrix;
|
||||
|
||||
template<class T, class TRI = lower, class L = row_major, class A = unbounded_array<T> >
|
||||
class triangular_matrix;
|
||||
template<class M, class TRI = lower>
|
||||
class triangular_adaptor;
|
||||
|
||||
template<class T, class TRI = lower, class L = row_major, class A = unbounded_array<T> >
|
||||
class symmetric_matrix;
|
||||
template<class M, class TRI = lower>
|
||||
class symmetric_adaptor;
|
||||
|
||||
template<class T, class TRI = lower, class L = row_major, class A = unbounded_array<T> >
|
||||
class hermitian_matrix;
|
||||
template<class M, class TRI = lower>
|
||||
class hermitian_adaptor;
|
||||
|
||||
// Sparse matrices
|
||||
template<class T, class L = row_major, class A = map_std<std::size_t, T> >
|
||||
class mapped_matrix;
|
||||
template<class T, class L = row_major, class A = map_std<std::size_t, map_std<std::size_t, T> > >
|
||||
class mapped_vector_of_mapped_vector;
|
||||
template<class T, class L = row_major, std::size_t IB = 0, class IA = unbounded_array<std::size_t>, class TA = unbounded_array<T> >
|
||||
class compressed_matrix;
|
||||
template<class T, class L = row_major, std::size_t IB = 0, class IA = unbounded_array<std::size_t>, class TA = unbounded_array<T> >
|
||||
class coordinate_matrix;
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
2633
include/boost/numeric/ublas/hermitian.hpp
Normal file
2633
include/boost/numeric/ublas/hermitian.hpp
Normal file
File diff suppressed because it is too large
Load Diff
355
include/boost/numeric/ublas/io.hpp
Normal file
355
include/boost/numeric/ublas/io.hpp
Normal file
@@ -0,0 +1,355 @@
|
||||
//
|
||||
// Copyright (c) 2000-2010
|
||||
// Joerg Walter, Mathias Koch, David Bellot
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
#ifndef _BOOST_UBLAS_IO_
|
||||
#define _BOOST_UBLAS_IO_
|
||||
|
||||
// Only forward definition required to define stream operations
|
||||
#include <iosfwd>
|
||||
#include <sstream>
|
||||
#include <boost/numeric/ublas/matrix_expression.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
/** \brief output stream operator for vector expressions
|
||||
*
|
||||
* Any vector expressions can be written to a standard output stream
|
||||
* as defined in the C++ standard library. For example:
|
||||
* \code
|
||||
* vector<float> v1(3),v2(3);
|
||||
* for(size_t i=0; i<3; i++)
|
||||
* {
|
||||
* v1(i) = i+0.2;
|
||||
* v2(i) = i+0.3;
|
||||
* }
|
||||
* cout << v1+v2 << endl;
|
||||
* \endcode
|
||||
* will display the some of the 2 vectors like this:
|
||||
* \code
|
||||
* [3](0.5,2.5,4.5)
|
||||
* \endcode
|
||||
*
|
||||
* \param os is a standard basic output stream
|
||||
* \param v is a vector expression
|
||||
* \return a reference to the resulting output stream
|
||||
*/
|
||||
template<class E, class T, class VE>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
std::basic_ostream<E, T> &operator << (std::basic_ostream<E, T> &os,
|
||||
const vector_expression<VE> &v) {
|
||||
typedef typename VE::size_type size_type;
|
||||
size_type size = v ().size ();
|
||||
std::basic_ostringstream<E, T, std::allocator<E> > s;
|
||||
s.flags (os.flags ());
|
||||
s.imbue (os.getloc ());
|
||||
s.precision (os.precision ());
|
||||
s << '[' << size << "](";
|
||||
if (size > 0)
|
||||
s << v () (0);
|
||||
for (size_type i = 1; i < size; ++ i)
|
||||
s << ',' << v () (i);
|
||||
s << ')';
|
||||
return os << s.str ().c_str ();
|
||||
}
|
||||
|
||||
/** \brief input stream operator for vectors
|
||||
*
|
||||
* This is used to feed in vectors with data stored as an ASCII representation
|
||||
* from a standard input stream.
|
||||
*
|
||||
* From a file or any valid stream, the format is:
|
||||
* \c [<vector size>](<data1>,<data2>,...<dataN>) like for example:
|
||||
* \code
|
||||
* [5](1,2.1,3.2,3.14,0.2)
|
||||
* \endcode
|
||||
*
|
||||
* You can use it like this
|
||||
* \code
|
||||
* my_input_stream >> my_vector;
|
||||
* \endcode
|
||||
*
|
||||
* You can only put data into a valid \c vector<> not a \c vector_expression
|
||||
*
|
||||
* \param is is a standard basic input stream
|
||||
* \param v is a vector
|
||||
* \return a reference to the resulting input stream
|
||||
*/
|
||||
template<class E, class T, class VT, class VA>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
std::basic_istream<E, T> &operator >> (std::basic_istream<E, T> &is,
|
||||
vector<VT, VA> &v) {
|
||||
typedef typename vector<VT, VA>::size_type size_type;
|
||||
E ch;
|
||||
size_type size;
|
||||
if (is >> ch && ch != '[') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
} else if (is >> size >> ch && ch != ']') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
} else if (! is.fail ()) {
|
||||
vector<VT, VA> s (size);
|
||||
if (is >> ch && ch != '(') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
} else if (! is.fail ()) {
|
||||
for (size_type i = 0; i < size; i ++) {
|
||||
if (is >> s (i) >> ch && ch != ',') {
|
||||
is.putback (ch);
|
||||
if (i < size - 1)
|
||||
is.setstate (std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is >> ch && ch != ')') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
}
|
||||
}
|
||||
if (! is.fail ())
|
||||
v.swap (s);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
/** \brief output stream operator for matrix expressions
|
||||
*
|
||||
* it outpus the content of a \f$(M \times N)\f$ matrix to a standard output
|
||||
* stream using the following format:
|
||||
* \c[<rows>,<columns>]((<m00>,<m01>,...,<m0N>),...,(<mM0>,<mM1>,...,<mMN>))
|
||||
*
|
||||
* For example:
|
||||
* \code
|
||||
* matrix<float> m(3,3) = scalar_matrix<float>(3,3,1.0) - diagonal_matrix<float>(3,3,1.0);
|
||||
* cout << m << endl;
|
||||
* \encode
|
||||
* will display
|
||||
* \code
|
||||
* [3,3]((0,1,1),(1,0,1),(1,1,0))
|
||||
* \endcode
|
||||
* This output is made for storing and retrieving matrices in a simple way but you can
|
||||
* easily recognize the following:
|
||||
* \f[ \left( \begin{array}{ccc} 1 & 1 & 1\\ 1 & 1 & 1\\ 1 & 1 & 1 \end{array} \right) - \left( \begin{array}{ccc} 1 & 0 & 0\\ 0 & 1 & 0\\ 0 & 0 & 1 \end{array} \right) = \left( \begin{array}{ccc} 0 & 1 & 1\\ 1 & 0 & 1\\ 1 & 1 & 0 \end{array} \right) \f]
|
||||
*
|
||||
* \param os is a standard basic output stream
|
||||
* \param m is a matrix expression
|
||||
* \return a reference to the resulting output stream
|
||||
*/
|
||||
template<class E, class T, class ME>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
std::basic_ostream<E, T> &operator << (std::basic_ostream<E, T> &os,
|
||||
const matrix_expression<ME> &m) {
|
||||
typedef typename ME::size_type size_type;
|
||||
size_type size1 = m ().size1 ();
|
||||
size_type size2 = m ().size2 ();
|
||||
std::basic_ostringstream<E, T, std::allocator<E> > s;
|
||||
s.flags (os.flags ());
|
||||
s.imbue (os.getloc ());
|
||||
s.precision (os.precision ());
|
||||
s << '[' << size1 << ',' << size2 << "](";
|
||||
if (size1 > 0) {
|
||||
s << '(' ;
|
||||
if (size2 > 0)
|
||||
s << m () (0, 0);
|
||||
for (size_type j = 1; j < size2; ++ j)
|
||||
s << ',' << m () (0, j);
|
||||
s << ')';
|
||||
}
|
||||
for (size_type i = 1; i < size1; ++ i) {
|
||||
s << ",(" ;
|
||||
if (size2 > 0)
|
||||
s << m () (i, 0);
|
||||
for (size_type j = 1; j < size2; ++ j)
|
||||
s << ',' << m () (i, j);
|
||||
s << ')';
|
||||
}
|
||||
s << ')';
|
||||
return os << s.str ().c_str ();
|
||||
}
|
||||
|
||||
/** \brief input stream operator for matrices
|
||||
*
|
||||
* This is used to feed in matrices with data stored as an ASCII representation
|
||||
* from a standard input stream.
|
||||
*
|
||||
* From a file or any valid standard stream, the format is:
|
||||
* \c[<rows>,<columns>]((<m00>,<m01>,...,<m0N>),...,(<mM0>,<mM1>,...,<mMN>))
|
||||
*
|
||||
* You can use it like this
|
||||
* \code
|
||||
* my_input_stream >> my_matrix;
|
||||
* \endcode
|
||||
*
|
||||
* You can only put data into a valid \c matrix<> not a \c matrix_expression
|
||||
*
|
||||
* \param is is a standard basic input stream
|
||||
* \param m is a matrix
|
||||
* \return a reference to the resulting input stream
|
||||
*/
|
||||
template<class E, class T, class MT, class MF, class MA>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
std::basic_istream<E, T> &operator >> (std::basic_istream<E, T> &is,
|
||||
matrix<MT, MF, MA> &m) {
|
||||
typedef typename matrix<MT, MF, MA>::size_type size_type;
|
||||
E ch;
|
||||
size_type size1, size2;
|
||||
if (is >> ch && ch != '[') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
} else if (is >> size1 >> ch && ch != ',') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
} else if (is >> size2 >> ch && ch != ']') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
} else if (! is.fail ()) {
|
||||
matrix<MT, MF, MA> s (size1, size2);
|
||||
if (is >> ch && ch != '(') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
} else if (! is.fail ()) {
|
||||
for (size_type i = 0; i < size1; i ++) {
|
||||
if (is >> ch && ch != '(') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
for (size_type j = 0; j < size2; j ++) {
|
||||
if (is >> s (i, j) >> ch && ch != ',') {
|
||||
is.putback (ch);
|
||||
if (j < size2 - 1) {
|
||||
is.setstate (std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is >> ch && ch != ')') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
if (is >> ch && ch != ',') {
|
||||
is.putback (ch);
|
||||
if (i < size1 - 1) {
|
||||
is.setstate (std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is >> ch && ch != ')') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
}
|
||||
}
|
||||
if (! is.fail ())
|
||||
m.swap (s);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
/** \brief special input stream operator for symmetric matrices
|
||||
*
|
||||
* This is used to feed in symmetric matrices with data stored as an ASCII
|
||||
* representation from a standard input stream.
|
||||
*
|
||||
* You can simply write your matrices in a file or any valid stream and read them again
|
||||
* at a later time with this function. The format is the following:
|
||||
* \code [<rows>,<columns>]((<m00>,<m01>,...,<m0N>),...,(<mM0>,<mM1>,...,<mMN>)) \endcode
|
||||
*
|
||||
* You can use it like this
|
||||
* \code
|
||||
* my_input_stream >> my_symmetric_matrix;
|
||||
* \endcode
|
||||
*
|
||||
* You can only put data into a valid \c symmetric_matrix<>, not in a \c matrix_expression
|
||||
* This function also checks that input data form a valid symmetric matrix
|
||||
*
|
||||
* \param is is a standard basic input stream
|
||||
* \param m is a \c symmetric_matrix
|
||||
* \return a reference to the resulting input stream
|
||||
*/
|
||||
template<class E, class T, class MT, class MF1, class MF2, class MA>
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
std::basic_istream<E, T> &operator >> (std::basic_istream<E, T> &is,
|
||||
symmetric_matrix<MT, MF1, MF2, MA> &m) {
|
||||
typedef typename symmetric_matrix<MT, MF1, MF2, MA>::size_type size_type;
|
||||
E ch;
|
||||
size_type size1, size2;
|
||||
MT value;
|
||||
if (is >> ch && ch != '[') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
} else if (is >> size1 >> ch && ch != ',') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
} else if (is >> size2 >> ch && (size2 != size1 || ch != ']')) { // symmetric matrix must be square
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
} else if (! is.fail ()) {
|
||||
symmetric_matrix<MT, MF1, MF2, MA> s (size1, size2);
|
||||
if (is >> ch && ch != '(') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
} else if (! is.fail ()) {
|
||||
for (size_type i = 0; i < size1; i ++) {
|
||||
if (is >> ch && ch != '(') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
for (size_type j = 0; j < size2; j ++) {
|
||||
if (is >> value >> ch && ch != ',') {
|
||||
is.putback (ch);
|
||||
if (j < size2 - 1) {
|
||||
is.setstate (std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i <= j) {
|
||||
// this is the first time we read this element - set the value
|
||||
s(i,j) = value;
|
||||
}
|
||||
else if ( s(i,j) != value ) {
|
||||
// matrix is not symmetric
|
||||
is.setstate (std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is >> ch && ch != ')') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
if (is >> ch && ch != ',') {
|
||||
is.putback (ch);
|
||||
if (i < size1 - 1) {
|
||||
is.setstate (std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is >> ch && ch != ')') {
|
||||
is.putback (ch);
|
||||
is.setstate (std::ios_base::failbit);
|
||||
}
|
||||
}
|
||||
if (! is.fail ())
|
||||
m.swap (s);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
350
include/boost/numeric/ublas/lu.hpp
Normal file
350
include/boost/numeric/ublas/lu.hpp
Normal file
@@ -0,0 +1,350 @@
|
||||
//
|
||||
// Copyright (c) 2000-2002
|
||||
// Joerg Walter, Mathias Koch
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
#ifndef _BOOST_UBLAS_LU_
|
||||
#define _BOOST_UBLAS_LU_
|
||||
|
||||
#include <boost/numeric/ublas/operation.hpp>
|
||||
#include <boost/numeric/ublas/vector_proxy.hpp>
|
||||
#include <boost/numeric/ublas/matrix_proxy.hpp>
|
||||
#include <boost/numeric/ublas/vector.hpp>
|
||||
#include <boost/numeric/ublas/triangular.hpp>
|
||||
|
||||
// LU factorizations in the spirit of LAPACK and Golub & van Loan
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
/** \brief
|
||||
*
|
||||
* \tparam T
|
||||
* \tparam A
|
||||
*/
|
||||
template<class T = std::size_t, class A = unbounded_array<T> >
|
||||
class permutation_matrix:
|
||||
public vector<T, A> {
|
||||
public:
|
||||
typedef vector<T, A> vector_type;
|
||||
typedef typename vector_type::size_type size_type;
|
||||
|
||||
// Construction and destruction
|
||||
BOOST_UBLAS_INLINE
|
||||
explicit
|
||||
permutation_matrix (size_type size):
|
||||
vector<T, A> (size) {
|
||||
for (size_type i = 0; i < size; ++ i)
|
||||
(*this) (i) = i;
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
explicit
|
||||
permutation_matrix (const vector_type & init)
|
||||
: vector_type(init)
|
||||
{ }
|
||||
BOOST_UBLAS_INLINE
|
||||
~permutation_matrix () {}
|
||||
|
||||
// Assignment
|
||||
BOOST_UBLAS_INLINE
|
||||
permutation_matrix &operator = (const permutation_matrix &m) {
|
||||
vector_type::operator = (m);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<class PM, class MV>
|
||||
BOOST_UBLAS_INLINE
|
||||
void swap_rows (const PM &pm, MV &mv, vector_tag) {
|
||||
typedef typename PM::size_type size_type;
|
||||
|
||||
size_type size = pm.size ();
|
||||
for (size_type i = 0; i < size; ++ i) {
|
||||
if (i != pm (i))
|
||||
std::swap (mv (i), mv (pm (i)));
|
||||
}
|
||||
}
|
||||
template<class PM, class MV>
|
||||
BOOST_UBLAS_INLINE
|
||||
void swap_rows (const PM &pm, MV &mv, matrix_tag) {
|
||||
typedef typename PM::size_type size_type;
|
||||
|
||||
size_type size = pm.size ();
|
||||
for (size_type i = 0; i < size; ++ i) {
|
||||
if (i != pm (i))
|
||||
row (mv, i).swap (row (mv, pm (i)));
|
||||
}
|
||||
}
|
||||
// Dispatcher
|
||||
template<class PM, class MV>
|
||||
BOOST_UBLAS_INLINE
|
||||
void swap_rows (const PM &pm, MV &mv) {
|
||||
swap_rows (pm, mv, typename MV::type_category ());
|
||||
}
|
||||
|
||||
// LU factorization without pivoting
|
||||
template<class M>
|
||||
typename M::size_type lu_factorize (M &m) {
|
||||
|
||||
typedef typename M::size_type size_type;
|
||||
typedef typename M::value_type value_type;
|
||||
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
typedef M matrix_type;
|
||||
matrix_type cm (m);
|
||||
#endif
|
||||
size_type singular = 0;
|
||||
size_type size1 = m.size1 ();
|
||||
size_type size2 = m.size2 ();
|
||||
size_type size = (std::min) (size1, size2);
|
||||
for (size_type i = 0; i < size; ++ i) {
|
||||
matrix_column<M> mci (column (m, i));
|
||||
matrix_row<M> mri (row (m, i));
|
||||
if (m (i, i) != value_type/*zero*/()) {
|
||||
value_type m_inv = value_type (1) / m (i, i);
|
||||
project (mci, range (i + 1, size1)) *= m_inv;
|
||||
} else if (singular == 0) {
|
||||
singular = i + 1;
|
||||
}
|
||||
project (m, range (i + 1, size1), range (i + 1, size2)).minus_assign (
|
||||
outer_prod (project (mci, range (i + 1, size1)),
|
||||
project (mri, range (i + 1, size2))));
|
||||
}
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (singular != 0 ||
|
||||
detail::expression_type_check (prod (triangular_adaptor<matrix_type, unit_lower> (m),
|
||||
triangular_adaptor<matrix_type, upper> (m)),
|
||||
cm), internal_logic ());
|
||||
#endif
|
||||
return singular;
|
||||
}
|
||||
|
||||
// LU factorization with partial pivoting
|
||||
template<class M, class PM>
|
||||
typename M::size_type lu_factorize (M &m, PM &pm) {
|
||||
typedef typename M::size_type size_type;
|
||||
typedef typename M::value_type value_type;
|
||||
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
typedef M matrix_type;
|
||||
matrix_type cm (m);
|
||||
#endif
|
||||
size_type singular = 0;
|
||||
size_type size1 = m.size1 ();
|
||||
size_type size2 = m.size2 ();
|
||||
size_type size = (std::min) (size1, size2);
|
||||
for (size_type i = 0; i < size; ++ i) {
|
||||
matrix_column<M> mci (column (m, i));
|
||||
matrix_row<M> mri (row (m, i));
|
||||
size_type i_norm_inf = i + index_norm_inf (project (mci, range (i, size1)));
|
||||
BOOST_UBLAS_CHECK (i_norm_inf < size1, external_logic ());
|
||||
if (m (i_norm_inf, i) != value_type/*zero*/()) {
|
||||
if (i_norm_inf != i) {
|
||||
pm (i) = i_norm_inf;
|
||||
row (m, i_norm_inf).swap (mri);
|
||||
} else {
|
||||
BOOST_UBLAS_CHECK (pm (i) == i_norm_inf, external_logic ());
|
||||
}
|
||||
value_type m_inv = value_type (1) / m (i, i);
|
||||
project (mci, range (i + 1, size1)) *= m_inv;
|
||||
} else if (singular == 0) {
|
||||
singular = i + 1;
|
||||
}
|
||||
project (m, range (i + 1, size1), range (i + 1, size2)).minus_assign (
|
||||
outer_prod (project (mci, range (i + 1, size1)),
|
||||
project (mri, range (i + 1, size2))));
|
||||
}
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
swap_rows (pm, cm);
|
||||
BOOST_UBLAS_CHECK (singular != 0 ||
|
||||
detail::expression_type_check (prod (triangular_adaptor<matrix_type, unit_lower> (m),
|
||||
triangular_adaptor<matrix_type, upper> (m)), cm), internal_logic ());
|
||||
#endif
|
||||
return singular;
|
||||
}
|
||||
|
||||
template<class M, class PM>
|
||||
typename M::size_type axpy_lu_factorize (M &m, PM &pm) {
|
||||
typedef M matrix_type;
|
||||
typedef typename M::size_type size_type;
|
||||
typedef typename M::value_type value_type;
|
||||
typedef vector<value_type> vector_type;
|
||||
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
matrix_type cm (m);
|
||||
#endif
|
||||
size_type singular = 0;
|
||||
size_type size1 = m.size1 ();
|
||||
size_type size2 = m.size2 ();
|
||||
size_type size = (std::min) (size1, size2);
|
||||
#ifndef BOOST_UBLAS_LU_WITH_INPLACE_SOLVE
|
||||
matrix_type mr (m);
|
||||
mr.assign (zero_matrix<value_type> (size1, size2));
|
||||
vector_type v (size1);
|
||||
for (size_type i = 0; i < size; ++ i) {
|
||||
matrix_range<matrix_type> lrr (project (mr, range (0, i), range (0, i)));
|
||||
vector_range<matrix_column<matrix_type> > urr (project (column (mr, i), range (0, i)));
|
||||
urr.assign (solve (lrr, project (column (m, i), range (0, i)), unit_lower_tag ()));
|
||||
project (v, range (i, size1)).assign (
|
||||
project (column (m, i), range (i, size1)) -
|
||||
axpy_prod<vector_type> (project (mr, range (i, size1), range (0, i)), urr));
|
||||
size_type i_norm_inf = i + index_norm_inf (project (v, range (i, size1)));
|
||||
BOOST_UBLAS_CHECK (i_norm_inf < size1, external_logic ());
|
||||
if (v (i_norm_inf) != value_type/*zero*/()) {
|
||||
if (i_norm_inf != i) {
|
||||
pm (i) = i_norm_inf;
|
||||
std::swap (v (i_norm_inf), v (i));
|
||||
project (row (m, i_norm_inf), range (i + 1, size2)).swap (project (row (m, i), range (i + 1, size2)));
|
||||
} else {
|
||||
BOOST_UBLAS_CHECK (pm (i) == i_norm_inf, external_logic ());
|
||||
}
|
||||
project (column (mr, i), range (i + 1, size1)).assign (
|
||||
project (v, range (i + 1, size1)) / v (i));
|
||||
if (i_norm_inf != i) {
|
||||
project (row (mr, i_norm_inf), range (0, i)).swap (project (row (mr, i), range (0, i)));
|
||||
}
|
||||
} else if (singular == 0) {
|
||||
singular = i + 1;
|
||||
}
|
||||
mr (i, i) = v (i);
|
||||
}
|
||||
m.assign (mr);
|
||||
#else
|
||||
matrix_type lr (m);
|
||||
matrix_type ur (m);
|
||||
lr.assign (identity_matrix<value_type> (size1, size2));
|
||||
ur.assign (zero_matrix<value_type> (size1, size2));
|
||||
vector_type v (size1);
|
||||
for (size_type i = 0; i < size; ++ i) {
|
||||
matrix_range<matrix_type> lrr (project (lr, range (0, i), range (0, i)));
|
||||
vector_range<matrix_column<matrix_type> > urr (project (column (ur, i), range (0, i)));
|
||||
urr.assign (project (column (m, i), range (0, i)));
|
||||
inplace_solve (lrr, urr, unit_lower_tag ());
|
||||
project (v, range (i, size1)).assign (
|
||||
project (column (m, i), range (i, size1)) -
|
||||
axpy_prod<vector_type> (project (lr, range (i, size1), range (0, i)), urr));
|
||||
size_type i_norm_inf = i + index_norm_inf (project (v, range (i, size1)));
|
||||
BOOST_UBLAS_CHECK (i_norm_inf < size1, external_logic ());
|
||||
if (v (i_norm_inf) != value_type/*zero*/()) {
|
||||
if (i_norm_inf != i) {
|
||||
pm (i) = i_norm_inf;
|
||||
std::swap (v (i_norm_inf), v (i));
|
||||
project (row (m, i_norm_inf), range (i + 1, size2)).swap (project (row (m, i), range (i + 1, size2)));
|
||||
} else {
|
||||
BOOST_UBLAS_CHECK (pm (i) == i_norm_inf, external_logic ());
|
||||
}
|
||||
project (column (lr, i), range (i + 1, size1)).assign (
|
||||
project (v, range (i + 1, size1)) / v (i));
|
||||
if (i_norm_inf != i) {
|
||||
project (row (lr, i_norm_inf), range (0, i)).swap (project (row (lr, i), range (0, i)));
|
||||
}
|
||||
} else if (singular == 0) {
|
||||
singular = i + 1;
|
||||
}
|
||||
ur (i, i) = v (i);
|
||||
}
|
||||
m.assign (triangular_adaptor<matrix_type, strict_lower> (lr) +
|
||||
triangular_adaptor<matrix_type, upper> (ur));
|
||||
#endif
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
swap_rows (pm, cm);
|
||||
BOOST_UBLAS_CHECK (singular != 0 ||
|
||||
detail::expression_type_check (prod (triangular_adaptor<matrix_type, unit_lower> (m),
|
||||
triangular_adaptor<matrix_type, upper> (m)), cm), internal_logic ());
|
||||
#endif
|
||||
return singular;
|
||||
}
|
||||
|
||||
// LU substitution
|
||||
template<class M, class E>
|
||||
void lu_substitute (const M &m, vector_expression<E> &e) {
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
typedef const M const_matrix_type;
|
||||
typedef vector<typename E::value_type> vector_type;
|
||||
|
||||
vector_type cv1 (e);
|
||||
#endif
|
||||
inplace_solve (m, e, unit_lower_tag ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor<const_matrix_type, unit_lower> (m), e), cv1), internal_logic ());
|
||||
vector_type cv2 (e);
|
||||
#endif
|
||||
inplace_solve (m, e, upper_tag ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor<const_matrix_type, upper> (m), e), cv2), internal_logic ());
|
||||
#endif
|
||||
}
|
||||
template<class M, class E>
|
||||
void lu_substitute (const M &m, matrix_expression<E> &e) {
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
typedef const M const_matrix_type;
|
||||
typedef matrix<typename E::value_type> matrix_type;
|
||||
|
||||
matrix_type cm1 (e);
|
||||
#endif
|
||||
inplace_solve (m, e, unit_lower_tag ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor<const_matrix_type, unit_lower> (m), e), cm1), internal_logic ());
|
||||
matrix_type cm2 (e);
|
||||
#endif
|
||||
inplace_solve (m, e, upper_tag ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (detail::expression_type_check (prod (triangular_adaptor<const_matrix_type, upper> (m), e), cm2), internal_logic ());
|
||||
#endif
|
||||
}
|
||||
template<class M, class PMT, class PMA, class MV>
|
||||
void lu_substitute (const M &m, const permutation_matrix<PMT, PMA> &pm, MV &mv) {
|
||||
swap_rows (pm, mv);
|
||||
lu_substitute (m, mv);
|
||||
}
|
||||
template<class E, class M>
|
||||
void lu_substitute (vector_expression<E> &e, const M &m) {
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
typedef const M const_matrix_type;
|
||||
typedef vector<typename E::value_type> vector_type;
|
||||
|
||||
vector_type cv1 (e);
|
||||
#endif
|
||||
inplace_solve (e, m, upper_tag ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor<const_matrix_type, upper> (m)), cv1), internal_logic ());
|
||||
vector_type cv2 (e);
|
||||
#endif
|
||||
inplace_solve (e, m, unit_lower_tag ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor<const_matrix_type, unit_lower> (m)), cv2), internal_logic ());
|
||||
#endif
|
||||
}
|
||||
template<class E, class M>
|
||||
void lu_substitute (matrix_expression<E> &e, const M &m) {
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
typedef const M const_matrix_type;
|
||||
typedef matrix<typename E::value_type> matrix_type;
|
||||
|
||||
matrix_type cm1 (e);
|
||||
#endif
|
||||
inplace_solve (e, m, upper_tag ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor<const_matrix_type, upper> (m)), cm1), internal_logic ());
|
||||
matrix_type cm2 (e);
|
||||
#endif
|
||||
inplace_solve (e, m, unit_lower_tag ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (detail::expression_type_check (prod (e, triangular_adaptor<const_matrix_type, unit_lower> (m)), cm2), internal_logic ());
|
||||
#endif
|
||||
}
|
||||
template<class MV, class M, class PMT, class PMA>
|
||||
void lu_substitute (MV &mv, const M &m, const permutation_matrix<PMT, PMA> &pm) {
|
||||
swap_rows (pm, mv);
|
||||
lu_substitute (mv, m);
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
6013
include/boost/numeric/ublas/matrix.hpp
Normal file
6013
include/boost/numeric/ublas/matrix.hpp
Normal file
File diff suppressed because it is too large
Load Diff
5693
include/boost/numeric/ublas/matrix_expression.hpp
Normal file
5693
include/boost/numeric/ublas/matrix_expression.hpp
Normal file
File diff suppressed because it is too large
Load Diff
5457
include/boost/numeric/ublas/matrix_proxy.hpp
Normal file
5457
include/boost/numeric/ublas/matrix_proxy.hpp
Normal file
File diff suppressed because it is too large
Load Diff
5773
include/boost/numeric/ublas/matrix_sparse.hpp
Normal file
5773
include/boost/numeric/ublas/matrix_sparse.hpp
Normal file
File diff suppressed because it is too large
Load Diff
406
include/boost/numeric/ublas/matrix_vector.hpp
Normal file
406
include/boost/numeric/ublas/matrix_vector.hpp
Normal file
@@ -0,0 +1,406 @@
|
||||
// Copyright (c) 2012 Oswin Krause
|
||||
// Copyright (c) 2013 Joaquim Duran
|
||||
//
|
||||
// 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_HPP
|
||||
#define BOOST_UBLAS_MATRIX_VECTOR_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 used in the represention of a matrix as a vector of rows or columns
|
||||
*
|
||||
* Iterator used in the represention of a matrix as a vector of rows/columns. It refers
|
||||
* to the i-th element of the matrix, a column or a row depending of Reference type.
|
||||
*
|
||||
* The type of Reference should provide a constructor Reference(matrix, i)
|
||||
*
|
||||
* This iterator is invalidated when the underlying matrix is resized.
|
||||
*
|
||||
* \tparameter Matrix type of matrix that is represented as a vector of row/column
|
||||
* \tparameter Reference Matrix row or matrix column type.
|
||||
*/
|
||||
template<class Matrix, class Reference>
|
||||
class 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
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_vector_iterator(Matrix& matrix, std::size_t position)
|
||||
: matrix_(&matrix),position_(position) {}
|
||||
|
||||
template<class M, class R>
|
||||
BOOST_UBLAS_INLINE
|
||||
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;
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
void increment() {
|
||||
++position_;
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
void decrement() {
|
||||
--position_;
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
void advance(std::ptrdiff_t n){
|
||||
position_ += n;
|
||||
}
|
||||
|
||||
template<class M,class R>
|
||||
BOOST_UBLAS_INLINE
|
||||
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>
|
||||
BOOST_UBLAS_INLINE
|
||||
bool equal(matrix_vector_iterator<M,R> const& other) const{
|
||||
BOOST_UBLAS_CHECK (matrix_ == other.matrix_, external_logic ());
|
||||
return (position_ == other.position_);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
Reference dereference() const {
|
||||
return Reference(*matrix_,position_);
|
||||
}
|
||||
|
||||
Matrix* matrix_;//no matrix_closure here to ensure easy usage
|
||||
std::size_t position_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/** \brief Represents a \c Matrix as a vector of rows.
|
||||
*
|
||||
* Implements an interface to Matrix that the underlaying matrix is represented as a
|
||||
* vector of rows.
|
||||
*
|
||||
* The vector could be resized which causes the resize of the number of rows of
|
||||
* the underlaying matrix.
|
||||
*/
|
||||
template<class Matrix>
|
||||
class matrix_row_vector {
|
||||
public:
|
||||
typedef ublas::matrix_row<Matrix> value_type;
|
||||
typedef ublas::matrix_row<Matrix> reference;
|
||||
typedef ublas::matrix_row<Matrix const> const_reference;
|
||||
|
||||
typedef ublas::detail::matrix_vector_iterator<Matrix, ublas::matrix_row<Matrix> > iterator;
|
||||
typedef ublas::detail::matrix_vector_iterator<Matrix const, ublas::matrix_row<Matrix const> const> const_iterator;
|
||||
typedef boost::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
typedef typename boost::iterator_difference<iterator>::type difference_type;
|
||||
typedef typename Matrix::size_type size_type;
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
explicit matrix_row_vector(Matrix& matrix) :
|
||||
matrix_(&matrix) {
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
iterator begin(){
|
||||
return iterator(*matrix_, 0);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator begin() const {
|
||||
return const_iterator(*matrix_, 0);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator cbegin() const {
|
||||
return begin();
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
iterator end() {
|
||||
return iterator(*matrix_, matrix_->size1());
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator end() const {
|
||||
return const_iterator(*matrix_, matrix_->size1());
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator cend() const {
|
||||
return end();
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
reverse_iterator rbegin() {
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator crbegin() const {
|
||||
return rbegin();
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
reverse_iterator rend() {
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator crend() const {
|
||||
return end();
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
value_type operator()(size_type index) {
|
||||
return value_type(*matrix_, index);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
value_type operator()(size_type index) const {
|
||||
return value_type(*matrix_, index);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
reference operator[](size_type index){
|
||||
return (*this) (index);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reference operator[](size_type index) const {
|
||||
return (*this) (index);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
size_type size() const {
|
||||
return matrix_->size1();
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
void resize(size_type size, bool preserve = true) {
|
||||
matrix_->resize(size, matrix_->size2(), preserve);
|
||||
}
|
||||
|
||||
private:
|
||||
Matrix* matrix_;
|
||||
};
|
||||
|
||||
|
||||
/** \brief Convenience function to create \c matrix_row_vector.
|
||||
*
|
||||
* Function to create \c matrix_row_vector objects.
|
||||
* \param matrix the \c matrix_expression that generates the matrix that \c matrix_row_vector is referring.
|
||||
* \return Created \c matrix_row_vector object.
|
||||
*
|
||||
* \tparam Matrix the type of matrix that \c matrix_row_vector is referring.
|
||||
*/
|
||||
template<class Matrix>
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_row_vector<Matrix> make_row_vector(matrix_expression<Matrix>& matrix){
|
||||
return matrix_row_vector<Matrix>(matrix());
|
||||
}
|
||||
|
||||
|
||||
/** \brief Convenience function to create \c matrix_row_vector.
|
||||
*
|
||||
* Function to create \c matrix_row_vector objects.
|
||||
* \param matrix the \c matrix_expression that generates the matrix that \c matrix_row_vector is referring.
|
||||
* \return Created \c matrix_row_vector object.
|
||||
*
|
||||
* \tparam Matrix the type of matrix that \c matrix_row_vector is referring.
|
||||
*/
|
||||
template<class Matrix>
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_row_vector<Matrix const> make_row_vector(matrix_expression<Matrix> const& matrix){
|
||||
return matrix_row_vector<Matrix const>(matrix());
|
||||
}
|
||||
|
||||
|
||||
/** \brief Represents a \c Matrix as a vector of columns.
|
||||
*
|
||||
* Implements an interface to Matrix that the underlaying matrix is represented as a
|
||||
* vector of columns.
|
||||
*
|
||||
* The vector could be resized which causes the resize of the number of columns of
|
||||
* the underlaying matrix.
|
||||
*/
|
||||
template<class Matrix>
|
||||
class matrix_column_vector {
|
||||
public:
|
||||
typedef ublas::matrix_column<Matrix> value_type;
|
||||
typedef ublas::matrix_column<Matrix> reference;
|
||||
typedef const ublas::matrix_column<Matrix const> const_reference;
|
||||
|
||||
typedef ublas::detail::matrix_vector_iterator<Matrix, ublas::matrix_column<Matrix> > iterator;
|
||||
typedef ublas::detail::matrix_vector_iterator<Matrix const, ublas::matrix_column<Matrix const> const > const_iterator;
|
||||
typedef boost::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
typedef typename boost::iterator_difference<iterator>::type difference_type;
|
||||
typedef typename Matrix::size_type size_type;
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
explicit matrix_column_vector(Matrix& matrix) :
|
||||
matrix_(&matrix){
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
iterator begin() {
|
||||
return iterator(*matrix_, 0);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator begin() const {
|
||||
return const_iterator(*matrix_, 0);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator cbegin() const {
|
||||
return begin();
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
iterator end() {
|
||||
return iterator(*matrix_, matrix_->size2());
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator end() const {
|
||||
return const_iterator(*matrix_, matrix_->size2());
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator cend() const {
|
||||
return end();
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
reverse_iterator rbegin() {
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator crbegin() const {
|
||||
return rbegin();
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
reverse_iterator rend() {
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator crend() const {
|
||||
return rend();
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
value_type operator()(size_type index) {
|
||||
return value_type(*matrix_, index);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
value_type operator()(size_type index) const {
|
||||
return value_type(*matrix_, index);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
reference operator[](size_type index) {
|
||||
return (*this) (index);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reference operator[](size_type index) const {
|
||||
return (*this) (index);
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
size_type size() const {
|
||||
return matrix_->size2();
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
void resize(size_type size, bool preserve = true) {
|
||||
matrix_->resize(matrix_->size1(), size, preserve);
|
||||
}
|
||||
|
||||
private:
|
||||
Matrix* matrix_;
|
||||
};
|
||||
|
||||
|
||||
/** \brief Convenience function to create \c matrix_column_vector.
|
||||
*
|
||||
* Function to create \c matrix_column_vector objects.
|
||||
* \param matrix the \c matrix_expression that generates the matrix that \c matrix_column_vector is referring.
|
||||
* \return Created \c matrix_column_vector object.
|
||||
*
|
||||
* \tparam Matrix the type of matrix that \c matrix_column_vector is referring.
|
||||
*/
|
||||
template<class Matrix>
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_column_vector<Matrix> make_column_vector(matrix_expression<Matrix>& matrix){
|
||||
return matrix_column_vector<Matrix>(matrix());
|
||||
}
|
||||
|
||||
|
||||
/** \brief Convenience function to create \c matrix_column_vector.
|
||||
*
|
||||
* Function to create \c matrix_column_vector objects.
|
||||
* \param matrix the \c matrix_expression that generates the matrix that \c matrix_column_vector is referring.
|
||||
* \return Created \c matrix_column_vector object.
|
||||
*
|
||||
* \tparam Matrix the type of matrix that \c matrix_column_vector is referring.
|
||||
*/
|
||||
template<class Matrix>
|
||||
BOOST_UBLAS_INLINE
|
||||
matrix_column_vector<Matrix const> make_column_vector(matrix_expression<Matrix> const& matrix){
|
||||
return matrix_column_vector<Matrix const>(matrix());
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
16
include/boost/numeric/ublas/opencl.hpp
Normal file
16
include/boost/numeric/ublas/opencl.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Copyright (c) 2018 Stefan Seefeld
|
||||
//
|
||||
// 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_numeric_ublas_opencl_hpp_
|
||||
#define boost_numeric_ublas_opencl_hpp_
|
||||
|
||||
#include <boost/numeric/ublas/opencl/library.hpp>
|
||||
#include <boost/numeric/ublas/opencl/vector.hpp>
|
||||
#include <boost/numeric/ublas/opencl/matrix.hpp>
|
||||
#include <boost/numeric/ublas/opencl/operations.hpp>
|
||||
|
||||
#endif
|
||||
508
include/boost/numeric/ublas/opencl/elementwise.hpp
Normal file
508
include/boost/numeric/ublas/opencl/elementwise.hpp
Normal file
@@ -0,0 +1,508 @@
|
||||
// Boost.uBLAS
|
||||
//
|
||||
// Copyright (c) 2018 Fady Essam
|
||||
// Copyright (c) 2018 Stefan Seefeld
|
||||
//
|
||||
// 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_numeric_ublas_opencl_elementwise_hpp_
|
||||
#define boost_numeric_ublas_opencl_elementwise_hpp_
|
||||
|
||||
#include <boost/numeric/ublas/opencl/library.hpp>
|
||||
#include <boost/numeric/ublas/opencl/vector.hpp>
|
||||
#include <boost/numeric/ublas/opencl/matrix.hpp>
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas { namespace opencl {
|
||||
|
||||
namespace compute = boost::compute;
|
||||
namespace lambda = boost::compute::lambda;
|
||||
|
||||
template <typename T, typename L1, typename L2, typename L3, class O>
|
||||
void element_wise(ublas::matrix<T, L1, opencl::storage> const &a,
|
||||
ublas::matrix<T, L2, opencl::storage> const &b,
|
||||
ublas::matrix<T, L3, opencl::storage> &result,
|
||||
O op, compute::command_queue& queue)
|
||||
{
|
||||
assert(a.device() == b.device() &&
|
||||
a.device() == result.device() &&
|
||||
a.device() == queue.get_device());
|
||||
assert(a.size1() == b.size1() && a.size2() == b.size2());
|
||||
|
||||
compute::transform(a.begin(),
|
||||
a.end(),
|
||||
b.begin(),
|
||||
result.begin(),
|
||||
op,
|
||||
queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename L3, typename A, class O>
|
||||
void element_wise(ublas::matrix<T, L1, A> const &a,
|
||||
ublas::matrix<T, L2, A> const &b,
|
||||
ublas::matrix<T, L3, A> &result,
|
||||
O op,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
ublas::matrix<T, L1, opencl::storage> adev(a, queue);
|
||||
ublas::matrix<T, L2, opencl::storage> bdev(b, queue);
|
||||
ublas::matrix<T, L3, opencl::storage> rdev(a.size1(), b.size2(), queue.get_context());
|
||||
element_wise(adev, bdev, rdev, op, queue);
|
||||
rdev.to_host(result, queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename A, typename O>
|
||||
ublas::matrix<T, L1, A> element_wise(ublas::matrix<T, L1, A> const &a,
|
||||
ublas::matrix<T, L2, A> const &b,
|
||||
O op,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
ublas::matrix<T, L1, A> result(a.size1(), b.size2());
|
||||
element_wise(a, b, result, op, queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename O>
|
||||
void element_wise(ublas::vector<T, opencl::storage> const &a,
|
||||
ublas::vector<T, opencl::storage> const &b,
|
||||
ublas::vector<T, opencl::storage> &result,
|
||||
O op,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
assert(a.device() == b.device() &&
|
||||
a.device() == result.device() &&
|
||||
a.device() == queue.get_device());
|
||||
assert(a.size() == b.size());
|
||||
compute::transform(a.begin(),
|
||||
a.end(),
|
||||
b.begin(),
|
||||
result.begin(),
|
||||
op,
|
||||
queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
template <typename T, typename A, typename O>
|
||||
void element_wise(ublas::vector<T, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
ublas::vector<T, A>& result,
|
||||
O op,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
ublas::vector<T, opencl::storage> adev(a, queue);
|
||||
ublas::vector<T, opencl::storage> bdev(b, queue);
|
||||
ublas::vector<T, opencl::storage> rdev(a.size(), queue.get_context());
|
||||
element_wise(adev, bdev, rdev, op, queue);
|
||||
rdev.to_host(result, queue);
|
||||
}
|
||||
|
||||
template <typename T, typename A, typename O>
|
||||
ublas::vector<T, A> element_wise(ublas::vector<T, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
O op,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
ublas::vector<T, A> result(a.size());
|
||||
element_wise(a, b, result, op, queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename L3>
|
||||
void element_add(ublas::matrix<T, L1, opencl::storage> const &a,
|
||||
ublas::matrix<T, L2, opencl::storage> const &b,
|
||||
ublas::matrix<T, L3, opencl::storage> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::plus<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename L3, typename A>
|
||||
void element_add(ublas::matrix<T, L1, A> const &a,
|
||||
ublas::matrix<T, L2, A> const &b,
|
||||
ublas::matrix<T, L3, A> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::plus<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename A>
|
||||
ublas::matrix<T, L1, A> element_add(ublas::matrix<T, L1, A> const &a,
|
||||
ublas::matrix<T, L2, A> const &b,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
return element_wise(a, b, compute::plus<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void element_add(ublas::vector<T, opencl::storage> const &a,
|
||||
ublas::vector<T, opencl::storage> const &b,
|
||||
ublas::vector<T, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::plus<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
void element_add(ublas::vector<T, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
ublas::vector<T, A> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::plus<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
ublas::vector<T, A> element_add(ublas::vector<T, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
return element_wise(a, b, compute::plus<T>(), queue);
|
||||
}
|
||||
|
||||
template<typename T, typename L>
|
||||
void element_add(ublas::matrix<T, L, opencl::storage> const &m, T value,
|
||||
ublas::matrix<T, L, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
assert(m.device() == result.device() && m.device() == queue.get_device());
|
||||
assert(m.size1() == result.size1() && m.size2() == result.size2());
|
||||
compute::transform(m.begin(), m.end(), result.begin(), lambda::_1 + value, queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
template<typename T, typename L, typename A>
|
||||
void element_add(ublas::matrix<T, L, A> const &m, T value,
|
||||
ublas::matrix<T, L, A> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::matrix<T, L, opencl::storage> mdev(m, queue);
|
||||
ublas::matrix<T, L, opencl::storage> rdev(result.size1(), result.size2(), queue.get_context());
|
||||
element_add(mdev, value, rdev, queue);
|
||||
rdev.to_host(result, queue);
|
||||
}
|
||||
|
||||
template<typename T, typename L, typename A>
|
||||
ublas::matrix<T, L, A> element_add(ublas::matrix<T, L, A> const &m, T value,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::matrix<T, L, A> result(m.size1(), m.size2());
|
||||
element_add(m, value, result, queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void element_add(ublas::vector<T, opencl::storage> const &v, T value,
|
||||
ublas::vector<T, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
assert(v.device() == result.device() && v.device() == queue.get_device());
|
||||
assert(v.size() == result.size());
|
||||
compute::transform(v.begin(), v.end(), result.begin(), lambda::_1 + value, queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
template<typename T, typename A>
|
||||
void element_add(ublas::vector<T, A> const &v, T value,
|
||||
ublas::vector<T, A> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::vector<T, opencl::storage> vdev(v, queue);
|
||||
ublas::vector<T, opencl::storage> rdev(v.size(), queue.get_context());
|
||||
element_add(vdev, value, rdev, queue);
|
||||
rdev.to_host(result, queue);
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
ublas::vector<T, A> element_add(ublas::vector<T, A> const &v, T value,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::vector<T, A> result(v.size());
|
||||
element_add(v, value, result, queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename L3>
|
||||
void element_sub(ublas::matrix<T, L1, opencl::storage> const &a,
|
||||
ublas::matrix<T, L2, opencl::storage> const &b,
|
||||
ublas::matrix<T, L3, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
element_wise(a, b, compute::minus<T>(), result, queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename L3, typename A>
|
||||
void element_sub(ublas::matrix<T, L1, A> const &a,
|
||||
ublas::matrix<T, L2, A> const &b,
|
||||
ublas::matrix<T, L3, A> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::minus<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename A>
|
||||
ublas::matrix<T, L1, A> element_sub(ublas::matrix<T, L1, A> const &a,
|
||||
ublas::matrix<T, L2, A> const &b,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
return element_wise(a, b, compute::minus<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void element_sub(ublas::vector<T, opencl::storage> const &a,
|
||||
ublas::vector<T, opencl::storage> const &b,
|
||||
ublas::vector<T, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::minus<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
void element_sub(ublas::vector<T, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
ublas::vector<T, A> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::minus<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
ublas::vector<T, A> element_sub(ublas::vector<T, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
return element_wise(a, b, compute::minus<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L>
|
||||
void element_sub(ublas::matrix<T, L, opencl::storage> const &m, T value,
|
||||
ublas::matrix<T, L, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
assert(m.device() == result.device() && m.device() == queue.get_device());
|
||||
assert(m.size1() == result.size1() && m.size2() == result.size2());
|
||||
compute::transform(m.begin(), m.end(), result.begin(), lambda::_1 - value, queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
template <typename T, typename L, typename A>
|
||||
void element_sub(ublas::matrix<T, L, A> const &m, T value,
|
||||
ublas::matrix<T, L, A> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::matrix<T, L, opencl::storage> mdev(m, queue);
|
||||
ublas::matrix<T, L, opencl::storage> rdev(result.size1(), result.size2(), queue.get_context());
|
||||
element_sub(mdev, value, rdev, queue);
|
||||
rdev.to_host(result, queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L, typename A>
|
||||
ublas::matrix<T, L, A> element_sub(ublas::matrix<T, L, A> const &m, T value,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::matrix<T, L, A> result(m.size1(), m.size2());
|
||||
element_sub(m, value, result, queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void element_sub(ublas::vector<T, opencl::storage> const &v, T value,
|
||||
ublas::vector<T, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
assert(v.device() == result.device() && v.device() == queue.get_device());
|
||||
assert(v.size() == result.size());
|
||||
compute::transform(v.begin(), v.end(), result.begin(), lambda::_1 - value, queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
void element_sub(ublas::vector<T, A> const &v, T value,
|
||||
ublas::vector<T, A> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::vector<T, opencl::storage> vdev(v, queue);
|
||||
ublas::vector<T, opencl::storage> rdev(v.size(), queue.get_context());
|
||||
element_sub(vdev, value, rdev, queue);
|
||||
rdev.to_host(result, queue);
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
ublas::vector<T, A> element_sub(ublas::vector<T, A> const &v, T value,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::vector<T, A> result(v.size());
|
||||
element_sub(v, value, result, queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename L3>
|
||||
void element_prod(ublas::matrix<T, L1, opencl::storage> const &a,
|
||||
ublas::matrix<T, L2, opencl::storage> const &b,
|
||||
ublas::matrix<T, L3, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::multiplies<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename L3, typename A>
|
||||
void element_prod(ublas::matrix<T, L1, A> const &a,
|
||||
ublas::matrix<T, L2, A> const &b,
|
||||
ublas::matrix<T, L3, A> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::multiplies<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename A>
|
||||
ublas::matrix<T, L1, A> element_prod(ublas::matrix<T, L1, A> const &a,
|
||||
ublas::matrix<T, L2, A> const &b,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
return element_wise(a, b, compute::multiplies<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void element_prod(ublas::vector<T, opencl::storage> const &a,
|
||||
ublas::vector<T, opencl::storage> const &b,
|
||||
ublas::vector<T, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::multiplies<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
void element_prod(ublas::vector<T, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
ublas::vector<T, A> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::multiplies<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
ublas::vector<T, A> element_prod(ublas::vector<T, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
return element_wise(a, b, compute::multiplies<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L>
|
||||
void element_scale(ublas::matrix<T, L, opencl::storage> const &m, T value,
|
||||
ublas::matrix<T, L, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
assert(m.device() == result.device() && m.device() == queue.get_device());
|
||||
assert(m.size1() == result.size1() && m.size2() == result.size2());
|
||||
compute::transform(m.begin(), m.end(), result.begin(), lambda::_1 * value, queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
template <typename T, typename L, typename A>
|
||||
void element_scale(ublas::matrix<T, L, A> const &m, T value,
|
||||
ublas::matrix<T, L, A> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::matrix<T, L, opencl::storage> mdev(m, queue);
|
||||
ublas::matrix<T, L, opencl::storage> rdev(result.size1(), result.size2(), queue.get_context());
|
||||
element_scale(mdev, value, rdev, queue);
|
||||
rdev.to_host(result, queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L, typename A>
|
||||
ublas::matrix<T, L, A> element_scale(ublas::matrix<T, L, A> const &m, T value,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::matrix<T, L, A> result(m.size1(), m.size2());
|
||||
element_scale(m, value, result, queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void element_scale(ublas::vector<T, opencl::storage> const &v, T value,
|
||||
ublas::vector<T, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
assert(v.device() == result.device() && v.device() == queue.get_device());
|
||||
assert(v.size() == result.size());
|
||||
compute::transform(v.begin(), v.end(), result.begin(), lambda::_1 * value, queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
void element_scale(ublas::vector<T, A> const &v, T value,
|
||||
ublas::vector<T, A> & result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::vector<T, opencl::storage> vdev(v, queue);
|
||||
ublas::vector<T, opencl::storage> rdev(v.size(), queue.get_context());
|
||||
element_scale(vdev, value, rdev, queue);
|
||||
rdev.to_host(result, queue);
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
ublas::vector<T,A> element_scale(ublas::vector<T, A> const &v, T value,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::vector<T, A> result(v.size());
|
||||
element_scale(v, value, result, queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename L3>
|
||||
void element_div(ublas::matrix<T, L1, opencl::storage> const &a,
|
||||
ublas::matrix<T, L2, opencl::storage> const &b,
|
||||
ublas::matrix<T, L3, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::divides<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename L3, typename A>
|
||||
void element_div(ublas::matrix<T, L1, A> const &a,
|
||||
ublas::matrix<T, L2, A> const &b,
|
||||
ublas::matrix<T, L3, A> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::divides<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename A>
|
||||
ublas::matrix<T, L1, A> element_div(ublas::matrix<T, L1, A> const &a,
|
||||
ublas::matrix<T, L2, A> const &b,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
return element_wise(a, b, compute::divides<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void element_div(ublas::vector<T, opencl::storage> const &a,
|
||||
ublas::vector<T, opencl::storage> const &b,
|
||||
ublas::vector<T, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::divides<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
void element_div(ublas::vector<T, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
ublas::vector<T, A> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
element_wise(a, b, result, compute::divides<T>(), queue);
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
ublas::vector<T, A> element_div(ublas::vector<T, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
return element_wise(a, b, compute::divides<T>(), queue);
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
38
include/boost/numeric/ublas/opencl/library.hpp
Normal file
38
include/boost/numeric/ublas/opencl/library.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// Boost.uBLAS
|
||||
//
|
||||
// Copyright (c) 2018 Fady Essam
|
||||
// Copyright (c) 2018 Stefan Seefeld
|
||||
//
|
||||
// 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_numeric_ublas_opencl_library_hpp_
|
||||
#define boost_numeric_ublas_opencl_library_hpp_
|
||||
|
||||
#include <clBLAS.h>
|
||||
#include <type_traits>
|
||||
#include <complex>
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas { namespace opencl {
|
||||
|
||||
class library
|
||||
{
|
||||
public:
|
||||
library() { clblasSetup();}
|
||||
~library() { clblasTeardown();}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_numeric
|
||||
{
|
||||
static bool const value =
|
||||
std::is_same<T, float>::value |
|
||||
std::is_same<T, double>::value |
|
||||
std::is_same<T, std::complex<float>>::value |
|
||||
std::is_same<T, std::complex<double>>::value;
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
123
include/boost/numeric/ublas/opencl/matrix.hpp
Normal file
123
include/boost/numeric/ublas/opencl/matrix.hpp
Normal file
@@ -0,0 +1,123 @@
|
||||
// Boost.uBLAS
|
||||
//
|
||||
// Copyright (c) 2018 Fady Essam
|
||||
// Copyright (c) 2018 Stefan Seefeld
|
||||
//
|
||||
// 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_numeric_ublas_opencl_matrix_hpp_
|
||||
#define boost_numeric_ublas_opencl_matrix_hpp_
|
||||
|
||||
#include <boost/numeric/ublas/opencl/library.hpp>
|
||||
#include <boost/numeric/ublas/matrix.hpp>
|
||||
#include <boost/numeric/ublas/functional.hpp>
|
||||
#include <boost/compute/core.hpp>
|
||||
#include <boost/compute/algorithm.hpp>
|
||||
#include <boost/compute/buffer.hpp>
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas { namespace opencl {
|
||||
|
||||
class storage;
|
||||
|
||||
namespace compute = boost::compute;
|
||||
|
||||
} // namespace opencl
|
||||
|
||||
template<class T, class L>
|
||||
class matrix<T, L, opencl::storage> : public matrix_container<matrix<T, L, opencl::storage> >
|
||||
{
|
||||
typedef typename boost::compute::buffer_allocator<T>::size_type size_type;
|
||||
typedef L layout_type;
|
||||
typedef matrix<T, L, opencl::storage> self_type;
|
||||
public:
|
||||
matrix()
|
||||
: matrix_container<self_type>(),
|
||||
size1_(0), size2_(0), data_() , device_()
|
||||
{}
|
||||
|
||||
matrix(size_type size1, size_type size2, compute::context c)
|
||||
: matrix_container<self_type>(),
|
||||
size1_(size1), size2_(size2), device_(c.get_device())
|
||||
{
|
||||
compute::buffer_allocator<T> allocator(c);
|
||||
data_ = allocator.allocate(layout_type::storage_size(size1, size2)).get_buffer();
|
||||
}
|
||||
|
||||
matrix(size_type size1, size_type size2, T const &value, compute::command_queue &q)
|
||||
: matrix_container<self_type>(),
|
||||
size1_(size1), size2_(size2), device_(q.get_device())
|
||||
{
|
||||
compute::buffer_allocator<T> allocator(q.get_context());
|
||||
data_ = allocator.allocate(layout_type::storage_size(size1, size2)).get_buffer();
|
||||
compute::fill(this->begin(), this->end(), value, q);
|
||||
q.finish();
|
||||
}
|
||||
|
||||
template <typename A>
|
||||
matrix(matrix<T, L, A> const &m, compute::command_queue &queue)
|
||||
: matrix(m.size1(), m.size2(), queue.get_context())
|
||||
{
|
||||
this->from_host(m, queue);
|
||||
}
|
||||
|
||||
size_type size1() const { return size1_;}
|
||||
size_type size2() const { return size2_;}
|
||||
|
||||
const compute::buffer_iterator<T> begin() const { return compute::make_buffer_iterator<T>(data_);}
|
||||
compute::buffer_iterator<T> begin() { return compute::make_buffer_iterator<T>(data_);}
|
||||
|
||||
compute::buffer_iterator<T> end() { return compute::make_buffer_iterator<T>(data_, layout_type::storage_size(size1_, size2_));}
|
||||
const compute::buffer_iterator<T> end() const { return compute::make_buffer_iterator<T>(data_, layout_type::storage_size(size1_, size2_));}
|
||||
|
||||
const compute::device &device() const { return device_;}
|
||||
compute::device &device() { return device_;}
|
||||
|
||||
void fill(T value, compute::command_queue &queue)
|
||||
{
|
||||
assert(device_ == queue.get_device());
|
||||
compute::fill(this->begin(), this->end(), value, queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
/** Copies a matrix to a device
|
||||
* \param m is a matrix that is not on the device _device and it is copied to it
|
||||
* \param queue is the command queue that will execute the operation
|
||||
*/
|
||||
template<class A>
|
||||
void from_host(ublas::matrix<T, L, A> const &m, compute::command_queue &queue)
|
||||
{
|
||||
assert(device_ == queue.get_device());
|
||||
compute::copy(m.data().begin(),
|
||||
m.data().end(),
|
||||
this->begin(),
|
||||
queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
/** Copies a matrix from a device
|
||||
* \param m is a matrix that will be reized to (size1_,size2) and the values of (*this) will be copied in it
|
||||
* \param queue is the command queue that will execute the operation
|
||||
*/
|
||||
template<class A>
|
||||
void to_host(ublas::matrix<T, L, A> &m, compute::command_queue &queue) const
|
||||
{
|
||||
assert(device_ == queue.get_device());
|
||||
compute::copy(this->begin(),
|
||||
this->end(),
|
||||
m.data().begin(),
|
||||
queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
private:
|
||||
size_type size1_;
|
||||
size_type size2_;
|
||||
compute::buffer data_;
|
||||
compute::device device_;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
182
include/boost/numeric/ublas/opencl/misc.hpp
Normal file
182
include/boost/numeric/ublas/opencl/misc.hpp
Normal file
@@ -0,0 +1,182 @@
|
||||
// Boost.uBLAS
|
||||
//
|
||||
// Copyright (c) 2018 Fady Essam
|
||||
// Copyright (c) 2018 Stefan Seefeld
|
||||
//
|
||||
// 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_numeric_ublas_opencl_misc_hpp_
|
||||
#define boost_numeric_ublas_opencl_misc_hpp_
|
||||
|
||||
#include <boost/numeric/ublas/opencl/library.hpp>
|
||||
#include <boost/numeric/ublas/opencl/vector.hpp>
|
||||
#include <boost/numeric/ublas/opencl/matrix.hpp>
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas { namespace opencl {
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<is_numeric<T>::value, T>::type
|
||||
a_sum(ublas::vector<T, opencl::storage> const &v, compute::command_queue& queue)
|
||||
{
|
||||
compute::vector<T> scratch_buffer(v.size(), queue.get_context());
|
||||
compute::vector<T> result_buffer(1, queue.get_context());
|
||||
cl_event event;
|
||||
if (std::is_same<T, float>::value)
|
||||
clblasSasum(v.size(),
|
||||
result_buffer.begin().get_buffer().get(), //result buffer
|
||||
0, //offset in result buffer
|
||||
v.begin().get_buffer().get(), //input buffer
|
||||
0, //offset in input buffer
|
||||
1, //increment in input buffer
|
||||
scratch_buffer.begin().get_buffer().get(),
|
||||
1, //number of command queues
|
||||
&(queue.get()), //queue
|
||||
0, // number of events waiting list
|
||||
NULL, //event waiting list
|
||||
&event); //event
|
||||
else if (std::is_same<T, double>::value)
|
||||
clblasDasum(v.size(),
|
||||
result_buffer.begin().get_buffer().get(), //result buffer
|
||||
0, //offset in result buffer
|
||||
v.begin().get_buffer().get(), //input buffer
|
||||
0, //offset in input buffer
|
||||
1, //increment in input buffer
|
||||
scratch_buffer.begin().get_buffer().get(),
|
||||
1, //number of command queues
|
||||
&(queue.get()), //queue
|
||||
0, // number of events waiting list
|
||||
NULL, //event waiting list
|
||||
&event); //event
|
||||
else if (std::is_same<T, std::complex<float>>::value)
|
||||
clblasScasum(v.size(),
|
||||
result_buffer.begin().get_buffer().get(), //result buffer
|
||||
0, //offset in result buffer
|
||||
v.begin().get_buffer().get(), //input buffer
|
||||
0, //offset in input buffer
|
||||
1, //increment in input buffer
|
||||
scratch_buffer.begin().get_buffer().get(),
|
||||
1, //number of command queues
|
||||
&(queue.get()), //queue
|
||||
0, // number of events waiting list
|
||||
NULL, //event waiting list
|
||||
&event); //event
|
||||
else if (std::is_same<T, std::complex<double>>::value)
|
||||
clblasDzasum(v.size(),
|
||||
result_buffer.begin().get_buffer().get(), //result buffer
|
||||
0, //offset in result buffer
|
||||
v.begin().get_buffer().get(), //input buffer
|
||||
0, //offset in input buffer
|
||||
1, //increment in input buffer
|
||||
scratch_buffer.begin().get_buffer().get(),
|
||||
1, //number of command queues
|
||||
&(queue.get()), //queue
|
||||
0, // number of events waiting list
|
||||
NULL, //event waiting list
|
||||
&event); //event
|
||||
clWaitForEvents(1, &event);
|
||||
return result_buffer[0];
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
typename std::enable_if<is_numeric<T>::value, T>::type
|
||||
a_sum(ublas::vector<T, A> const &v, compute::command_queue& queue)
|
||||
{
|
||||
ublas::vector<T, opencl::storage> vdev(v, queue);
|
||||
return a_sum(vdev, queue);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_same<T, float>::value |
|
||||
std::is_same<T, double>::value,
|
||||
T>::type
|
||||
norm_1(ublas::vector<T, opencl::storage> const &v, compute::command_queue& queue)
|
||||
{
|
||||
return a_sum(v, queue);
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
typename std::enable_if<std::is_same<T, float>::value |
|
||||
std::is_same<T, double>::value,
|
||||
T>::type
|
||||
norm_1(ublas::vector<T, A> const &v, compute::command_queue& queue)
|
||||
{
|
||||
ublas::vector<T, opencl::storage> vdev(v, queue);
|
||||
return norm_1(vdev, queue);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<is_numeric<T>::value, T>::type
|
||||
norm_2(ublas::vector<T, opencl::storage> const &v, compute::command_queue& queue)
|
||||
{
|
||||
compute::vector<T> scratch_buffer(2*v.size(), queue.get_context());
|
||||
compute::vector<T> result_buffer(1, queue.get_context());
|
||||
cl_event event;
|
||||
if (std::is_same<T, float>::value)
|
||||
clblasSnrm2(v.size(),
|
||||
result_buffer.begin().get_buffer().get(), //result buffer
|
||||
0, //offset in result buffer
|
||||
v.begin().get_buffer().get(), //input buffer
|
||||
0, //offset in input buffer
|
||||
1, //increment in input buffer
|
||||
scratch_buffer.begin().get_buffer().get(),
|
||||
1, //number of command queues
|
||||
&(queue.get()), //queue
|
||||
0, // number of events waiting list
|
||||
NULL, //event waiting list
|
||||
&event); //event
|
||||
else if (std::is_same<T, double>::value)
|
||||
clblasDnrm2(v.size(),
|
||||
result_buffer.begin().get_buffer().get(), //result buffer
|
||||
0, //offset in result buffer
|
||||
v.begin().get_buffer().get(), //input buffer
|
||||
0, //offset in input buffer
|
||||
1, //increment in input buffer
|
||||
scratch_buffer.begin().get_buffer().get(),
|
||||
1, //number of command queues
|
||||
&(queue.get()), //queue
|
||||
0, // number of events waiting list
|
||||
NULL, //event waiting list
|
||||
&event); //event
|
||||
else if (std::is_same<T, std::complex<float>>::value)
|
||||
clblasScnrm2(v.size(),
|
||||
result_buffer.begin().get_buffer().get(), //result buffer
|
||||
0, //offset in result buffer
|
||||
v.begin().get_buffer().get(), //input buffer
|
||||
0, //offset in input buffer
|
||||
1, //increment in input buffer
|
||||
scratch_buffer.begin().get_buffer().get(),
|
||||
1, //number of command queues
|
||||
&(queue.get()), //queue
|
||||
0, // number of events waiting list
|
||||
NULL, //event waiting list
|
||||
&event); //event
|
||||
else if (std::is_same<T, std::complex<double>>::value)
|
||||
clblasDznrm2(v.size(),
|
||||
result_buffer.begin().get_buffer().get(), //result buffer
|
||||
0, //offset in result buffer
|
||||
v.begin().get_buffer().get(), //input buffer
|
||||
0, //offset in input buffer
|
||||
1, //increment in input buffer
|
||||
scratch_buffer.begin().get_buffer().get(),
|
||||
1, //number of command queues
|
||||
&(queue.get()), //queue
|
||||
0, // number of events waiting list
|
||||
NULL, //event waiting list
|
||||
&event); //event
|
||||
clWaitForEvents(1, &event);
|
||||
return result_buffer[0];
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
typename std::enable_if<is_numeric<T>::value, T>::type
|
||||
norm_2(ublas::vector<T, A> const &v, compute::command_queue& queue)
|
||||
{
|
||||
ublas::vector<T, opencl::storage> vdev(v, queue);
|
||||
return norm_2(vdev, queue);
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
18
include/boost/numeric/ublas/opencl/operations.hpp
Normal file
18
include/boost/numeric/ublas/opencl/operations.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// Boost.uBLAS
|
||||
//
|
||||
// Copyright (c) 2018 Fady Essam
|
||||
// Copyright (c) 2018 Stefan Seefeld
|
||||
//
|
||||
// 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_numeric_ublas_opencl_operations_hpp_
|
||||
#define boost_numeric_ublas_opencl_operations_hpp_
|
||||
|
||||
#include <boost/numeric/ublas/opencl/transpose.hpp>
|
||||
#include <boost/numeric/ublas/opencl/prod.hpp>
|
||||
#include <boost/numeric/ublas/opencl/elementwise.hpp>
|
||||
#include <boost/numeric/ublas/opencl/misc.hpp>
|
||||
|
||||
#endif
|
||||
364
include/boost/numeric/ublas/opencl/prod.hpp
Normal file
364
include/boost/numeric/ublas/opencl/prod.hpp
Normal file
@@ -0,0 +1,364 @@
|
||||
// Boost.uBLAS
|
||||
//
|
||||
// Copyright (c) 2018 Fady Essam
|
||||
// Copyright (c) 2018 Stefan Seefeld
|
||||
//
|
||||
// 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_numeric_ublas_opencl_prod_hpp_
|
||||
#define boost_numeric_ublas_opencl_prod_hpp_
|
||||
|
||||
#include <boost/numeric/ublas/opencl/library.hpp>
|
||||
#include <boost/numeric/ublas/opencl/vector.hpp>
|
||||
#include <boost/numeric/ublas/opencl/matrix.hpp>
|
||||
#include <boost/numeric/ublas/opencl/transpose.hpp>
|
||||
#include <boost/compute/buffer.hpp>
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas { namespace opencl {
|
||||
|
||||
#define ONE_DOUBLE_COMPLEX {{1.0, 00.0}}
|
||||
#define ONE_FLOAT_COMPLEX {{1.0f, 00.0f}}
|
||||
|
||||
template <typename T, typename L1, typename L2>
|
||||
typename std::enable_if<is_numeric<T>::value>::type
|
||||
prod(ublas::matrix<T, L1, opencl::storage> const &a,
|
||||
ublas::matrix<T, L2, opencl::storage> const &b,
|
||||
ublas::matrix<T, L1, opencl::storage> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
assert(a.device() == b.device() &&
|
||||
a.device() == result.device() &&
|
||||
a.device() == queue.get_device());
|
||||
assert(a.size2() == b.size1());
|
||||
|
||||
result.fill(0, queue);
|
||||
|
||||
//to hold matrix b with layout 1 if the b has different layout
|
||||
std::unique_ptr<ublas::matrix<T, L1, opencl::storage>> bl1;
|
||||
|
||||
cl_event event = NULL;
|
||||
|
||||
cl_mem buffer_a = a.begin().get_buffer().get();
|
||||
cl_mem buffer_b = b.begin().get_buffer().get();
|
||||
cl_mem buffer_result = result.begin().get_buffer().get();
|
||||
|
||||
if (!(std::is_same<L1, L2>::value))
|
||||
{
|
||||
bl1.reset(new ublas::matrix<T, L1, opencl::storage>(b.size1(), b.size2(), queue.get_context()));
|
||||
change_layout(b, *bl1, queue);
|
||||
buffer_b = bl1->begin().get_buffer().get();
|
||||
}
|
||||
|
||||
clblasOrder Order = std::is_same<L1, ublas::basic_row_major<> >::value ? clblasRowMajor : clblasColumnMajor;
|
||||
size_t lda = Order == clblasRowMajor ? a.size2() : a.size1();
|
||||
size_t ldb = Order == clblasRowMajor ? b.size2() : a.size2();
|
||||
size_t ldc = Order == clblasRowMajor ? b.size2() : a.size1();
|
||||
|
||||
if (std::is_same<T, float>::value)
|
||||
clblasSgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
a.size1(), b.size2(), a.size2(),
|
||||
1, buffer_a, 0, lda,
|
||||
buffer_b, 0, ldb, 1,
|
||||
buffer_result, 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
else if (std::is_same<T, double>::value)
|
||||
clblasDgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
a.size1(), b.size2(), a.size2(),
|
||||
1, buffer_a, 0, lda,
|
||||
buffer_b, 0, ldb, 1,
|
||||
buffer_result, 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
else if (std::is_same<T, std::complex<float>>::value)
|
||||
clblasCgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
a.size1(), b.size2(), a.size2(),
|
||||
ONE_FLOAT_COMPLEX, buffer_a, 0, lda,
|
||||
buffer_b, 0, ldb, ONE_FLOAT_COMPLEX,
|
||||
buffer_result, 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
else if (std::is_same<T, std::complex<double>>::value)
|
||||
clblasZgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
a.size1(), b.size2(), a.size2(),
|
||||
ONE_DOUBLE_COMPLEX, buffer_a, 0, lda,
|
||||
buffer_b, 0, ldb, ONE_DOUBLE_COMPLEX,
|
||||
buffer_result, 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
clWaitForEvents(1, &event);
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename A>
|
||||
typename std::enable_if<is_numeric<T>::value>::type
|
||||
prod(ublas::matrix<T, L1, A> const &a,
|
||||
ublas::matrix<T, L2, A> const &b,
|
||||
ublas::matrix<T, L1, A> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
ublas::matrix<T, L1, opencl::storage> adev(a, queue);
|
||||
ublas::matrix<T, L2, opencl::storage> bdev(b, queue);
|
||||
ublas::matrix<T, L1, opencl::storage> rdev(a.size1(), b.size2(), queue.get_context());
|
||||
prod(adev, bdev, rdev, queue);
|
||||
rdev.to_host(result,queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L1, typename L2, typename A>
|
||||
typename std::enable_if<is_numeric<T>::value, ublas::matrix<T, L1, A>>::type
|
||||
prod(ublas::matrix<T, L1, A> const &a,
|
||||
ublas::matrix<T, L2, A> const &b,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
ublas::matrix<T, L1, A> result(a.size1(), b.size2());
|
||||
prod(a, b, result, queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename L>
|
||||
typename std::enable_if<is_numeric<T>::value>::type
|
||||
prod(ublas::matrix<T, L, opencl::storage> const &a,
|
||||
ublas::vector<T, opencl::storage> const &b,
|
||||
ublas::vector<T, opencl::storage> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
assert(a.device() == b.device() &&
|
||||
a.device() == result.device() &&
|
||||
a.device() == queue.get_device());
|
||||
assert(a.size2() == b.size());
|
||||
result.fill(0, queue);
|
||||
|
||||
cl_event event = NULL;
|
||||
clblasOrder Order = std::is_same<L, ublas::basic_row_major<> >::value ? clblasRowMajor : clblasColumnMajor;
|
||||
int lda = Order == clblasRowMajor ? a.size2() : a.size1();
|
||||
int ldb = Order == clblasRowMajor ? 1 : a.size2();
|
||||
int ldc = Order == clblasRowMajor ? 1 : a.size1();
|
||||
|
||||
if (std::is_same<T, float>::value)
|
||||
clblasSgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
a.size1(), 1, a.size2(),
|
||||
1, a.begin().get_buffer().get(), 0, lda,
|
||||
b.begin().get_buffer().get(), 0, ldb, 1,
|
||||
result.begin().get_buffer().get(), 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
else if (std::is_same<T, double>::value)
|
||||
clblasDgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
a.size1(), 1, a.size2(),
|
||||
1, a.begin().get_buffer().get(), 0, lda,
|
||||
b.begin().get_buffer().get(), 0, ldb, 1,
|
||||
result.begin().get_buffer().get(), 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
else if (std::is_same<T, std::complex<float>>::value)
|
||||
clblasCgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
a.size1(), 1, a.size2(),
|
||||
ONE_FLOAT_COMPLEX, a.begin().get_buffer().get(), 0, lda,
|
||||
b.begin().get_buffer().get(), 0, ldb, ONE_FLOAT_COMPLEX,
|
||||
result.begin().get_buffer().get(), 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
else if (std::is_same<T, std::complex<double>>::value)
|
||||
clblasZgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
a.size1(), 1, a.size2(),
|
||||
ONE_DOUBLE_COMPLEX, a.begin().get_buffer().get(), 0, lda,
|
||||
b.begin().get_buffer().get(), 0, ldb, ONE_DOUBLE_COMPLEX,
|
||||
result.begin().get_buffer().get(), 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
clWaitForEvents(1, &event);
|
||||
}
|
||||
|
||||
template <typename T, typename L, typename A>
|
||||
typename std::enable_if<is_numeric<T>::value>::type
|
||||
prod(ublas::matrix<T, L, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
ublas::vector<T, A> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
ublas::matrix<T, L, opencl::storage> adev(a, queue);
|
||||
ublas::vector<T, opencl::storage> bdev(b, queue);
|
||||
ublas::vector<T, opencl::storage> rdev(a.size1(), queue.get_context());
|
||||
prod(adev, bdev, rdev, queue);
|
||||
rdev.to_host(result, queue);
|
||||
}
|
||||
|
||||
template <typename T, typename L, typename A>
|
||||
typename std::enable_if<is_numeric<T>::value, ublas::vector<T, A>>::type
|
||||
prod(ublas::matrix<T, L, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
ublas::vector<T, A> result(a.size1());
|
||||
prod(a, b, result, queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename L>
|
||||
typename std::enable_if<is_numeric<T>::value>::type
|
||||
prod(ublas::vector<T, opencl::storage> const &a,
|
||||
ublas::matrix<T, L, opencl::storage> const &b,
|
||||
ublas::vector<T, opencl::storage> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
assert(a.device() == b.device() &&
|
||||
a.device() == result.device() &&
|
||||
a.device() == queue.get_device());
|
||||
assert(a.size() == b.size1());
|
||||
result.fill(0, queue);
|
||||
cl_event event = NULL;
|
||||
clblasOrder Order = std::is_same<L, ublas::basic_row_major<> >::value ? clblasRowMajor : clblasColumnMajor;
|
||||
size_t lda = Order == clblasRowMajor ? a.size() : 1;
|
||||
size_t ldb = Order == clblasRowMajor ? b.size2() : a.size();
|
||||
size_t ldc = Order == clblasRowMajor ? b.size2() : 1;
|
||||
|
||||
if (std::is_same<T, float>::value)
|
||||
clblasSgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
1, b.size2(), a.size(),
|
||||
1, a.begin().get_buffer().get(), 0, lda,
|
||||
b.begin().get_buffer().get(), 0, ldb, 1,
|
||||
result.begin().get_buffer().get(), 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
else if (std::is_same<T, double>::value)
|
||||
clblasDgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
1, b.size2(), a.size(),
|
||||
1, a.begin().get_buffer().get(), 0, lda,
|
||||
b.begin().get_buffer().get(), 0, ldb, 1,
|
||||
result.begin().get_buffer().get(), 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
else if (std::is_same<T, std::complex<float>>::value)
|
||||
clblasCgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
1, b.size2(), a.size(),
|
||||
ONE_FLOAT_COMPLEX, a.begin().get_buffer().get(), 0, lda,
|
||||
b.begin().get_buffer().get(), 0, ldb, ONE_FLOAT_COMPLEX,
|
||||
result.begin().get_buffer().get(), 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
else if (std::is_same<T, std::complex<double>>::value)
|
||||
clblasZgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
1, b.size2(), a.size(),
|
||||
ONE_DOUBLE_COMPLEX, a.begin().get_buffer().get(), 0, lda,
|
||||
b.begin().get_buffer().get(), 0, ldb, ONE_DOUBLE_COMPLEX,
|
||||
result.begin().get_buffer().get(), 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
clWaitForEvents(1, &event);
|
||||
}
|
||||
|
||||
template <class T, class L, class A>
|
||||
typename std::enable_if<is_numeric<T>::value>::type
|
||||
prod(ublas::vector<T, A> const &a,
|
||||
ublas::matrix<T, L, A> const &b,
|
||||
ublas::vector<T, A> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
ublas::vector<T, opencl::storage> adev(a, queue);
|
||||
ublas::matrix<T, L, opencl::storage> bdev(b, queue);
|
||||
ublas::vector<T, opencl::storage> rdev(b.size2(), queue.get_context());
|
||||
prod(adev, bdev, rdev, queue);
|
||||
rdev.to_host(result, queue);
|
||||
}
|
||||
|
||||
template <class T, class L, class A>
|
||||
typename std::enable_if<is_numeric<T>::value, ublas::vector<T, A>>::type
|
||||
prod(ublas::vector<T, A> const &a,
|
||||
ublas::matrix<T, L, A> const &b,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
ublas::vector<T, A> result(b.size2());
|
||||
prod(a, b, result, queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_fundamental<T>::value, T>::type
|
||||
inner_prod(ublas::vector<T, opencl::storage> const &a,
|
||||
ublas::vector<T, opencl::storage> const &b,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
assert(a.device() == b.device() && a.device() == queue.get_device());
|
||||
assert(a.size() == b.size());
|
||||
return compute::inner_product(a.begin(), a.end(), b.begin(), T(0), queue);
|
||||
}
|
||||
|
||||
template<class T, class A>
|
||||
typename std::enable_if<std::is_fundamental<T>::value, T>::type
|
||||
inner_prod(ublas::vector<T, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::vector<T, opencl::storage> adev(a, queue);
|
||||
ublas::vector<T, opencl::storage> bdev(b, queue);
|
||||
return inner_prod(adev, bdev, queue);
|
||||
}
|
||||
|
||||
template <class T, class L>
|
||||
typename std::enable_if<is_numeric<T>::value>::type
|
||||
outer_prod(ublas::vector<T, opencl::storage> const &a,
|
||||
ublas::vector<T, opencl::storage> const &b,
|
||||
ublas::matrix<T, L, opencl::storage> &result,
|
||||
compute::command_queue & queue)
|
||||
{
|
||||
assert(a.device() == b.device() &&
|
||||
a.device() == result.device() &&
|
||||
a.device() == queue.get_device());
|
||||
result.fill(0, queue);
|
||||
cl_event event = NULL;
|
||||
clblasOrder Order = std::is_same<L, ublas::basic_row_major<> >::value ? clblasRowMajor : clblasColumnMajor;
|
||||
size_t lda = Order == clblasRowMajor ? 1 : a.size();
|
||||
size_t ldb = Order == clblasRowMajor ? b.size() : 1;
|
||||
size_t ldc = Order == clblasRowMajor ? b.size() : a.size();
|
||||
|
||||
if (std::is_same<T, float>::value)
|
||||
clblasSgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
a.size(), b.size(), 1,
|
||||
1, a.begin().get_buffer().get(), 0, lda,
|
||||
b.begin().get_buffer().get(), 0, ldb, 1,
|
||||
result.begin().get_buffer().get(), 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
else if (std::is_same<T, double>::value)
|
||||
clblasDgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
a.size(), b.size(), 1,
|
||||
1, a.begin().get_buffer().get(), 0, lda,
|
||||
b.begin().get_buffer().get(), 0, ldb, 1,
|
||||
result.begin().get_buffer().get(), 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
else if (std::is_same<T, std::complex<float>>::value)
|
||||
clblasCgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
a.size(), b.size(), 1,
|
||||
ONE_FLOAT_COMPLEX, a.begin().get_buffer().get(), 0, lda,
|
||||
b.begin().get_buffer().get(), 0, ldb, ONE_FLOAT_COMPLEX,
|
||||
result.begin().get_buffer().get(), 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
else if (std::is_same<T, std::complex<double>>::value)
|
||||
clblasZgemm(Order, clblasNoTrans, clblasNoTrans,
|
||||
a.size(), b.size(), 1,
|
||||
ONE_DOUBLE_COMPLEX, a.begin().get_buffer().get(), 0, lda,
|
||||
b.begin().get_buffer().get(), 0, ldb, ONE_DOUBLE_COMPLEX,
|
||||
result.begin().get_buffer().get(), 0, ldc,
|
||||
1, &(queue.get()), 0, NULL, &event);
|
||||
clWaitForEvents(1, &event);
|
||||
}
|
||||
|
||||
template <class T, class L, class A>
|
||||
typename std::enable_if<is_numeric<T>::value>::type
|
||||
outer_prod(ublas::vector<T, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
ublas::matrix<T, L, A> &result,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
ublas::vector<T, opencl::storage> adev(a, queue);
|
||||
ublas::vector<T, opencl::storage> bdev(b, queue);
|
||||
ublas::matrix<T, L, opencl::storage> rdev(a.size(), b.size(), queue.get_context());
|
||||
outer_prod(adev, bdev, rdev, queue);
|
||||
rdev.to_host(result, queue);
|
||||
}
|
||||
|
||||
template <class T,class L = ublas::basic_row_major<>, class A>
|
||||
typename std::enable_if<is_numeric<T>::value, ublas::matrix<T, L, A>>::type
|
||||
outer_prod(ublas::vector<T, A> const &a,
|
||||
ublas::vector<T, A> const &b,
|
||||
compute::command_queue &queue)
|
||||
{
|
||||
ublas::matrix<T, L, A> result(a.size(), b.size());
|
||||
outer_prod(a, b, result, queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
#undef ONE_DOUBLE_COMPLEX
|
||||
#undef ONE_FLOAT_COMPLEX
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
142
include/boost/numeric/ublas/opencl/transpose.hpp
Normal file
142
include/boost/numeric/ublas/opencl/transpose.hpp
Normal file
@@ -0,0 +1,142 @@
|
||||
// Boost.uBLAS
|
||||
//
|
||||
// Copyright (c) 2018 Fady Essam
|
||||
// Copyright (c) 2018 Stefan Seefeld
|
||||
//
|
||||
// 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_numeric_ublas_opencl_transpose_hpp_
|
||||
#define boost_numeric_ublas_opencl_transpose_hpp_
|
||||
|
||||
#include <boost/numeric/ublas/opencl/library.hpp>
|
||||
#include <boost/numeric/ublas/opencl/vector.hpp>
|
||||
#include <boost/numeric/ublas/opencl/matrix.hpp>
|
||||
|
||||
// Kernel for transposition of various data types
|
||||
#define OPENCL_TRANSPOSITION_KERNEL(DATA_TYPE) \
|
||||
"__kernel void transpose(__global " #DATA_TYPE "* in, __global " #DATA_TYPE "* result, unsigned int width, unsigned int height) \n" \
|
||||
"{ \n" \
|
||||
" unsigned int column_index = get_global_id(0); \n" \
|
||||
" unsigned int row_index = get_global_id(1); \n" \
|
||||
" if (column_index < width && row_index < height) \n" \
|
||||
" { \n" \
|
||||
" unsigned int index_in = column_index + width * row_index; \n" \
|
||||
" unsigned int index_result = row_index + height * column_index; \n" \
|
||||
" result[index_result] = in[index_in]; \n" \
|
||||
" } \n" \
|
||||
"} \n"
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas { namespace opencl {
|
||||
|
||||
template<class T, class L1, class L2>
|
||||
typename std::enable_if<is_numeric<T>::value>::type
|
||||
change_layout(ublas::matrix<T, L1, opencl::storage> const &m,
|
||||
ublas::matrix<T, L2, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
assert(m.size1() == result.size1() && m.size2() == result.size2());
|
||||
assert(m.device() == result.device() && m.device() == queue.get_device());
|
||||
assert(!(std::is_same<L1, L2>::value));
|
||||
char const *kernel;
|
||||
if (std::is_same<T, float>::value)
|
||||
kernel = OPENCL_TRANSPOSITION_KERNEL(float);
|
||||
else if (std::is_same<T, double>::value)
|
||||
kernel = OPENCL_TRANSPOSITION_KERNEL(double);
|
||||
else if (std::is_same<T, std::complex<float>>::value)
|
||||
kernel = OPENCL_TRANSPOSITION_KERNEL(float2);
|
||||
else if (std::is_same<T, std::complex<double>>::value)
|
||||
kernel = OPENCL_TRANSPOSITION_KERNEL(double2);
|
||||
size_t len = strlen(kernel);
|
||||
cl_int err;
|
||||
cl_context c_context = queue.get_context().get();
|
||||
cl_program program = clCreateProgramWithSource(c_context, 1, &kernel, &len, &err);
|
||||
clBuildProgram(program, 1, &queue.get_device().get(), NULL, NULL, NULL);
|
||||
cl_kernel c_kernel = clCreateKernel(program, "transpose", &err);
|
||||
size_t width = std::is_same < L1, ublas::basic_row_major<>>::value ? m.size2() : m.size1();
|
||||
size_t height = std::is_same < L1, ublas::basic_row_major<>>::value ? m.size1() : m.size2();
|
||||
size_t global_size[2] = { width , height };
|
||||
clSetKernelArg(c_kernel, 0, sizeof(T*), &m.begin().get_buffer().get());
|
||||
clSetKernelArg(c_kernel, 1, sizeof(T*), &result.begin().get_buffer().get());
|
||||
clSetKernelArg(c_kernel, 2, sizeof(unsigned int), &width);
|
||||
clSetKernelArg(c_kernel, 3, sizeof(unsigned int), &height);
|
||||
cl_command_queue c_queue = queue.get();
|
||||
cl_event event = NULL;
|
||||
clEnqueueNDRangeKernel(c_queue, c_kernel, 2, NULL, global_size, NULL, 0, NULL, &event);
|
||||
clWaitForEvents(1, &event);
|
||||
}
|
||||
|
||||
template<class T, class L1, class L2, class A>
|
||||
typename std::enable_if<is_numeric<T>::value>::type
|
||||
change_layout(ublas::matrix<T, L1, A> const &m,
|
||||
ublas::matrix<T, L2, A> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::matrix<T, L1, opencl::storage> mdev(m, queue);
|
||||
ublas::matrix<T, L2, opencl::storage> rdev(result.size1(), result.size2(), queue.get_context());
|
||||
change_layout(mdev, rdev, queue);
|
||||
rdev.to_host(result, queue);
|
||||
}
|
||||
|
||||
template<class T, class L>
|
||||
typename std::enable_if<is_numeric<T>::value>::type
|
||||
trans(ublas::matrix<T, L, opencl::storage> const &m,
|
||||
ublas::matrix<T, L, opencl::storage> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
assert(m.size1() == result.size2() && m.size2() == result.size1());
|
||||
assert(m.device() == result.device() && m.device() == queue.get_device());
|
||||
char const *kernel;
|
||||
if (std::is_same<T, float>::value)
|
||||
kernel = OPENCL_TRANSPOSITION_KERNEL(float);
|
||||
else if (std::is_same<T, double>::value)
|
||||
kernel = OPENCL_TRANSPOSITION_KERNEL(double);
|
||||
else if (std::is_same<T, std::complex<float>>::value)
|
||||
kernel = OPENCL_TRANSPOSITION_KERNEL(float2);
|
||||
else if (std::is_same<T, std::complex<double>>::value)
|
||||
kernel = OPENCL_TRANSPOSITION_KERNEL(double2);
|
||||
size_t len = strlen(kernel);
|
||||
cl_int err;
|
||||
cl_context c_context = queue.get_context().get();
|
||||
cl_program program = clCreateProgramWithSource(c_context, 1, &kernel, &len, &err);
|
||||
clBuildProgram(program, 1, &queue.get_device().get(), NULL, NULL, NULL);
|
||||
cl_kernel c_kernel = clCreateKernel(program, "transpose", &err);
|
||||
size_t width = std::is_same <L, ublas::basic_row_major<>>::value ? m.size2() : m.size1();
|
||||
size_t height = std::is_same <L, ublas::basic_row_major<>>::value ? m.size1() : m.size2();
|
||||
size_t global_size[2] = { width , height };
|
||||
clSetKernelArg(c_kernel, 0, sizeof(T*), &m.begin().get_buffer().get());
|
||||
clSetKernelArg(c_kernel, 1, sizeof(T*), &result.begin().get_buffer().get());
|
||||
clSetKernelArg(c_kernel, 2, sizeof(unsigned int), &width);
|
||||
clSetKernelArg(c_kernel, 3, sizeof(unsigned int), &height);
|
||||
cl_command_queue c_queue = queue.get();
|
||||
cl_event event = NULL;
|
||||
clEnqueueNDRangeKernel(c_queue, c_kernel, 2, NULL, global_size, NULL, 0, NULL, &event);
|
||||
clWaitForEvents(1, &event);
|
||||
}
|
||||
|
||||
template<class T, class L, class A>
|
||||
typename std::enable_if<is_numeric<T>::value>::type
|
||||
trans(ublas::matrix<T, L, A> const &m,
|
||||
ublas::matrix<T, L, A> &result,
|
||||
compute::command_queue& queue)
|
||||
{
|
||||
ublas::matrix<T, L, opencl::storage> mdev(m, queue);
|
||||
ublas::matrix<T, L, opencl::storage> rdev(result.size1(), result.size2(), queue.get_context());
|
||||
trans(mdev, rdev, queue);
|
||||
rdev.to_host(result, queue);
|
||||
}
|
||||
|
||||
template<class T, class L, class A>
|
||||
typename std::enable_if<is_numeric<T>::value, ublas::matrix<T, L, A>>::type
|
||||
trans(ublas::matrix<T, L, A>& m, compute::command_queue& queue)
|
||||
{
|
||||
ublas::matrix<T, L, A> result(m.size2(), m.size1());
|
||||
trans(m, result, queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
90
include/boost/numeric/ublas/opencl/vector.hpp
Normal file
90
include/boost/numeric/ublas/opencl/vector.hpp
Normal file
@@ -0,0 +1,90 @@
|
||||
// Boost.uBLAS
|
||||
//
|
||||
// Copyright (c) 2018 Fady Essam
|
||||
// Copyright (c) 2018 Stefan Seefeld
|
||||
//
|
||||
// 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_numeric_ublas_opencl_vector_hpp_
|
||||
#define boost_numeric_ublas_opencl_vector_hpp_
|
||||
|
||||
#include <boost/numeric/ublas/opencl/library.hpp>
|
||||
#include <boost/numeric/ublas/functional.hpp>
|
||||
#include <boost/compute/core.hpp>
|
||||
#include <boost/compute/algorithm.hpp>
|
||||
#include <boost/compute/buffer.hpp>
|
||||
#include <boost/compute/container/vector.hpp>
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas { namespace opencl {
|
||||
|
||||
class storage;
|
||||
|
||||
namespace compute = boost::compute;
|
||||
|
||||
} // namespace opencl
|
||||
|
||||
template <class T>
|
||||
class vector<T, opencl::storage> : public boost::compute::vector<T>
|
||||
{
|
||||
typedef std::size_t size_type;
|
||||
public:
|
||||
vector() : compute::vector<T>() {}
|
||||
vector(size_type size, compute::context context)
|
||||
: compute::vector<T>(size, context)
|
||||
{ device_ = context.get_device();}
|
||||
vector(size_type size, T value, compute::command_queue queue)
|
||||
: compute::vector<T>(size, value, queue.get_context())
|
||||
{
|
||||
queue.finish();
|
||||
device_ = queue.get_device();
|
||||
}
|
||||
|
||||
template <typename A>
|
||||
vector(vector<T, A> const &v, compute::command_queue &queue)
|
||||
: vector(v.size(), queue.get_context())
|
||||
{
|
||||
this->from_host(v, queue);
|
||||
}
|
||||
|
||||
|
||||
const compute::device device() const { return device_;}
|
||||
compute::device device() { return device_;}
|
||||
|
||||
template<class A>
|
||||
void from_host(ublas::vector<T, A> const &v, compute::command_queue & queue)
|
||||
{
|
||||
assert(this->device() == queue.get_device());
|
||||
compute::copy(v.begin(),
|
||||
v.end(),
|
||||
this->begin(),
|
||||
queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
template<class A>
|
||||
void to_host(ublas::vector<T, A>& v, compute::command_queue& queue) const
|
||||
{
|
||||
assert(this->device() == queue.get_device());
|
||||
compute::copy(this->begin(),
|
||||
this->end(),
|
||||
v.begin(),
|
||||
queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
void fill(T value, compute::command_queue & queue)
|
||||
{
|
||||
assert(this->device() == queue.get_device());
|
||||
compute::fill(this->begin(), this->end(), value, queue);
|
||||
queue.finish();
|
||||
}
|
||||
|
||||
private:
|
||||
compute::device device_;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
830
include/boost/numeric/ublas/operation.hpp
Normal file
830
include/boost/numeric/ublas/operation.hpp
Normal file
@@ -0,0 +1,830 @@
|
||||
//
|
||||
// Copyright (c) 2000-2002
|
||||
// Joerg Walter, Mathias Koch
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
#ifndef _BOOST_UBLAS_OPERATION_
|
||||
#define _BOOST_UBLAS_OPERATION_
|
||||
|
||||
#include <boost/numeric/ublas/matrix_proxy.hpp>
|
||||
|
||||
/** \file operation.hpp
|
||||
* \brief This file contains some specialized products.
|
||||
*/
|
||||
|
||||
// axpy-based products
|
||||
// Alexei Novakov had a lot of ideas to improve these. Thanks.
|
||||
// Hendrik Kueck proposed some new kernel. Thanks again.
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
template<class V, class T1, class L1, class IA1, class TA1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
|
||||
const vector_expression<E2> &e2,
|
||||
V &v, row_major_tag) {
|
||||
typedef typename V::size_type size_type;
|
||||
typedef typename V::value_type value_type;
|
||||
|
||||
for (size_type i = 0; i < e1.filled1 () -1; ++ i) {
|
||||
size_type begin = e1.index1_data () [i];
|
||||
size_type end = e1.index1_data () [i + 1];
|
||||
value_type t (v (i));
|
||||
for (size_type j = begin; j < end; ++ j)
|
||||
t += e1.value_data () [j] * e2 () (e1.index2_data () [j]);
|
||||
v (i) = t;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class V, class T1, class L1, class IA1, class TA1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
|
||||
const vector_expression<E2> &e2,
|
||||
V &v, column_major_tag) {
|
||||
typedef typename V::size_type size_type;
|
||||
|
||||
for (size_type j = 0; j < e1.filled1 () -1; ++ j) {
|
||||
size_type begin = e1.index1_data () [j];
|
||||
size_type end = e1.index1_data () [j + 1];
|
||||
for (size_type i = begin; i < end; ++ i)
|
||||
v (e1.index2_data () [i]) += e1.value_data () [i] * e2 () (j);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// Dispatcher
|
||||
template<class V, class T1, class L1, class IA1, class TA1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
|
||||
const vector_expression<E2> &e2,
|
||||
V &v, bool init = true) {
|
||||
typedef typename V::value_type value_type;
|
||||
typedef typename L1::orientation_category orientation_category;
|
||||
|
||||
if (init)
|
||||
v.assign (zero_vector<value_type> (e1.size1 ()));
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
vector<value_type> cv (v);
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
|
||||
#endif
|
||||
axpy_prod (e1, e2, v, orientation_category ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
template<class V, class T1, class L1, class IA1, class TA1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V
|
||||
axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
|
||||
const vector_expression<E2> &e2) {
|
||||
typedef V vector_type;
|
||||
|
||||
vector_type v (e1.size1 ());
|
||||
return axpy_prod (e1, e2, v, true);
|
||||
}
|
||||
|
||||
template<class V, class T1, class L1, class IA1, class TA1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const coordinate_matrix<T1, L1, 0, IA1, TA1> &e1,
|
||||
const vector_expression<E2> &e2,
|
||||
V &v, bool init = true) {
|
||||
typedef typename V::size_type size_type;
|
||||
typedef typename V::value_type value_type;
|
||||
typedef L1 layout_type;
|
||||
|
||||
size_type size1 = e1.size1();
|
||||
size_type size2 = e1.size2();
|
||||
|
||||
if (init) {
|
||||
noalias(v) = zero_vector<value_type>(size1);
|
||||
}
|
||||
|
||||
for (size_type i = 0; i < e1.nnz(); ++i) {
|
||||
size_type row_index = layout_type::index_M( e1.index1_data () [i], e1.index2_data () [i] );
|
||||
size_type col_index = layout_type::index_m( e1.index1_data () [i], e1.index2_data () [i] );
|
||||
v( row_index ) += e1.value_data () [i] * e2 () (col_index);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class V, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const vector_expression<E2> &e2,
|
||||
V &v, packed_random_access_iterator_tag, row_major_tag) {
|
||||
typedef const E1 expression1_type;
|
||||
typedef typename V::size_type size_type;
|
||||
|
||||
typename expression1_type::const_iterator1 it1 (e1 ().begin1 ());
|
||||
typename expression1_type::const_iterator1 it1_end (e1 ().end1 ());
|
||||
while (it1 != it1_end) {
|
||||
size_type index1 (it1.index1 ());
|
||||
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
||||
typename expression1_type::const_iterator2 it2 (it1.begin ());
|
||||
typename expression1_type::const_iterator2 it2_end (it1.end ());
|
||||
#else
|
||||
typename expression1_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
|
||||
typename expression1_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
|
||||
#endif
|
||||
while (it2 != it2_end) {
|
||||
v (index1) += *it2 * e2 () (it2.index2 ());
|
||||
++ it2;
|
||||
}
|
||||
++ it1;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class V, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const vector_expression<E2> &e2,
|
||||
V &v, packed_random_access_iterator_tag, column_major_tag) {
|
||||
typedef const E1 expression1_type;
|
||||
typedef typename V::size_type size_type;
|
||||
|
||||
typename expression1_type::const_iterator2 it2 (e1 ().begin2 ());
|
||||
typename expression1_type::const_iterator2 it2_end (e1 ().end2 ());
|
||||
while (it2 != it2_end) {
|
||||
size_type index2 (it2.index2 ());
|
||||
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
||||
typename expression1_type::const_iterator1 it1 (it2.begin ());
|
||||
typename expression1_type::const_iterator1 it1_end (it2.end ());
|
||||
#else
|
||||
typename expression1_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
|
||||
typename expression1_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
|
||||
#endif
|
||||
while (it1 != it1_end) {
|
||||
v (it1.index1 ()) += *it1 * e2 () (index2);
|
||||
++ it1;
|
||||
}
|
||||
++ it2;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class V, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const vector_expression<E2> &e2,
|
||||
V &v, sparse_bidirectional_iterator_tag) {
|
||||
typedef const E2 expression2_type;
|
||||
|
||||
typename expression2_type::const_iterator it (e2 ().begin ());
|
||||
typename expression2_type::const_iterator it_end (e2 ().end ());
|
||||
while (it != it_end) {
|
||||
v.plus_assign (column (e1 (), it.index ()) * *it);
|
||||
++ it;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// Dispatcher
|
||||
template<class V, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const vector_expression<E2> &e2,
|
||||
V &v, packed_random_access_iterator_tag) {
|
||||
typedef typename E1::orientation_category orientation_category;
|
||||
return axpy_prod (e1, e2, v, packed_random_access_iterator_tag (), orientation_category ());
|
||||
}
|
||||
|
||||
|
||||
/** \brief computes <tt>v += A x</tt> or <tt>v = A x</tt> in an
|
||||
optimized fashion.
|
||||
|
||||
\param e1 the matrix expression \c A
|
||||
\param e2 the vector expression \c x
|
||||
\param v the result vector \c v
|
||||
\param init a boolean parameter
|
||||
|
||||
<tt>axpy_prod(A, x, v, init)</tt> implements the well known
|
||||
axpy-product. Setting \a init to \c true is equivalent to call
|
||||
<tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
|
||||
defaults to \c true, but this may change in the future.
|
||||
|
||||
Up to now there are some specialisation for compressed
|
||||
matrices that give a large speed up compared to prod.
|
||||
|
||||
\ingroup blas2
|
||||
|
||||
\internal
|
||||
|
||||
template parameters:
|
||||
\param V type of the result vector \c v
|
||||
\param E1 type of a matrix expression \c A
|
||||
\param E2 type of a vector expression \c x
|
||||
*/
|
||||
template<class V, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const vector_expression<E2> &e2,
|
||||
V &v, bool init = true) {
|
||||
typedef typename V::value_type value_type;
|
||||
typedef typename E2::const_iterator::iterator_category iterator_category;
|
||||
|
||||
if (init)
|
||||
v.assign (zero_vector<value_type> (e1 ().size1 ()));
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
vector<value_type> cv (v);
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
|
||||
#endif
|
||||
axpy_prod (e1, e2, v, iterator_category ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
template<class V, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const vector_expression<E2> &e2) {
|
||||
typedef V vector_type;
|
||||
|
||||
vector_type v (e1 ().size1 ());
|
||||
return axpy_prod (e1, e2, v, true);
|
||||
}
|
||||
|
||||
template<class V, class E1, class T2, class IA2, class TA2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const vector_expression<E1> &e1,
|
||||
const compressed_matrix<T2, column_major, 0, IA2, TA2> &e2,
|
||||
V &v, column_major_tag) {
|
||||
typedef typename V::size_type size_type;
|
||||
typedef typename V::value_type value_type;
|
||||
|
||||
for (size_type j = 0; j < e2.filled1 () -1; ++ j) {
|
||||
size_type begin = e2.index1_data () [j];
|
||||
size_type end = e2.index1_data () [j + 1];
|
||||
value_type t (v (j));
|
||||
for (size_type i = begin; i < end; ++ i)
|
||||
t += e2.value_data () [i] * e1 () (e2.index2_data () [i]);
|
||||
v (j) = t;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class V, class E1, class T2, class IA2, class TA2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const vector_expression<E1> &e1,
|
||||
const compressed_matrix<T2, row_major, 0, IA2, TA2> &e2,
|
||||
V &v, row_major_tag) {
|
||||
typedef typename V::size_type size_type;
|
||||
|
||||
for (size_type i = 0; i < e2.filled1 () -1; ++ i) {
|
||||
size_type begin = e2.index1_data () [i];
|
||||
size_type end = e2.index1_data () [i + 1];
|
||||
for (size_type j = begin; j < end; ++ j)
|
||||
v (e2.index2_data () [j]) += e2.value_data () [j] * e1 () (i);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// Dispatcher
|
||||
template<class V, class E1, class T2, class L2, class IA2, class TA2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const vector_expression<E1> &e1,
|
||||
const compressed_matrix<T2, L2, 0, IA2, TA2> &e2,
|
||||
V &v, bool init = true) {
|
||||
typedef typename V::value_type value_type;
|
||||
typedef typename L2::orientation_category orientation_category;
|
||||
|
||||
if (init)
|
||||
v.assign (zero_vector<value_type> (e2.size2 ()));
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
vector<value_type> cv (v);
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
|
||||
#endif
|
||||
axpy_prod (e1, e2, v, orientation_category ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
template<class V, class E1, class T2, class L2, class IA2, class TA2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V
|
||||
axpy_prod (const vector_expression<E1> &e1,
|
||||
const compressed_matrix<T2, L2, 0, IA2, TA2> &e2) {
|
||||
typedef V vector_type;
|
||||
|
||||
vector_type v (e2.size2 ());
|
||||
return axpy_prod (e1, e2, v, true);
|
||||
}
|
||||
|
||||
template<class V, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const vector_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
V &v, packed_random_access_iterator_tag, column_major_tag) {
|
||||
typedef const E2 expression2_type;
|
||||
typedef typename V::size_type size_type;
|
||||
|
||||
typename expression2_type::const_iterator2 it2 (e2 ().begin2 ());
|
||||
typename expression2_type::const_iterator2 it2_end (e2 ().end2 ());
|
||||
while (it2 != it2_end) {
|
||||
size_type index2 (it2.index2 ());
|
||||
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
||||
typename expression2_type::const_iterator1 it1 (it2.begin ());
|
||||
typename expression2_type::const_iterator1 it1_end (it2.end ());
|
||||
#else
|
||||
typename expression2_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
|
||||
typename expression2_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
|
||||
#endif
|
||||
while (it1 != it1_end) {
|
||||
v (index2) += *it1 * e1 () (it1.index1 ());
|
||||
++ it1;
|
||||
}
|
||||
++ it2;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class V, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const vector_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
V &v, packed_random_access_iterator_tag, row_major_tag) {
|
||||
typedef const E2 expression2_type;
|
||||
typedef typename V::size_type size_type;
|
||||
|
||||
typename expression2_type::const_iterator1 it1 (e2 ().begin1 ());
|
||||
typename expression2_type::const_iterator1 it1_end (e2 ().end1 ());
|
||||
while (it1 != it1_end) {
|
||||
size_type index1 (it1.index1 ());
|
||||
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
||||
typename expression2_type::const_iterator2 it2 (it1.begin ());
|
||||
typename expression2_type::const_iterator2 it2_end (it1.end ());
|
||||
#else
|
||||
typename expression2_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
|
||||
typename expression2_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
|
||||
#endif
|
||||
while (it2 != it2_end) {
|
||||
v (it2.index2 ()) += *it2 * e1 () (index1);
|
||||
++ it2;
|
||||
}
|
||||
++ it1;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class V, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const vector_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
V &v, sparse_bidirectional_iterator_tag) {
|
||||
typedef const E1 expression1_type;
|
||||
|
||||
typename expression1_type::const_iterator it (e1 ().begin ());
|
||||
typename expression1_type::const_iterator it_end (e1 ().end ());
|
||||
while (it != it_end) {
|
||||
v.plus_assign (*it * row (e2 (), it.index ()));
|
||||
++ it;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// Dispatcher
|
||||
template<class V, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const vector_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
V &v, packed_random_access_iterator_tag) {
|
||||
typedef typename E2::orientation_category orientation_category;
|
||||
return axpy_prod (e1, e2, v, packed_random_access_iterator_tag (), orientation_category ());
|
||||
}
|
||||
|
||||
|
||||
/** \brief computes <tt>v += A<sup>T</sup> x</tt> or <tt>v = A<sup>T</sup> x</tt> in an
|
||||
optimized fashion.
|
||||
|
||||
\param e1 the vector expression \c x
|
||||
\param e2 the matrix expression \c A
|
||||
\param v the result vector \c v
|
||||
\param init a boolean parameter
|
||||
|
||||
<tt>axpy_prod(x, A, v, init)</tt> implements the well known
|
||||
axpy-product. Setting \a init to \c true is equivalent to call
|
||||
<tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
|
||||
defaults to \c true, but this may change in the future.
|
||||
|
||||
Up to now there are some specialisation for compressed
|
||||
matrices that give a large speed up compared to prod.
|
||||
|
||||
\ingroup blas2
|
||||
|
||||
\internal
|
||||
|
||||
template parameters:
|
||||
\param V type of the result vector \c v
|
||||
\param E1 type of a vector expression \c x
|
||||
\param E2 type of a matrix expression \c A
|
||||
*/
|
||||
template<class V, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V &
|
||||
axpy_prod (const vector_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
V &v, bool init = true) {
|
||||
typedef typename V::value_type value_type;
|
||||
typedef typename E1::const_iterator::iterator_category iterator_category;
|
||||
|
||||
if (init)
|
||||
v.assign (zero_vector<value_type> (e2 ().size2 ()));
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
vector<value_type> cv (v);
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
|
||||
#endif
|
||||
axpy_prod (e1, e2, v, iterator_category ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
template<class V, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V
|
||||
axpy_prod (const vector_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2) {
|
||||
typedef V vector_type;
|
||||
|
||||
vector_type v (e2 ().size2 ());
|
||||
return axpy_prod (e1, e2, v, true);
|
||||
}
|
||||
|
||||
template<class M, class E1, class E2, class TRI>
|
||||
BOOST_UBLAS_INLINE
|
||||
M &
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
M &m, TRI,
|
||||
dense_proxy_tag, row_major_tag) {
|
||||
|
||||
typedef typename M::size_type size_type;
|
||||
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
typedef typename M::value_type value_type;
|
||||
matrix<value_type, row_major> cm (m);
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
|
||||
#endif
|
||||
size_type size1 (e1 ().size1 ());
|
||||
size_type size2 (e1 ().size2 ());
|
||||
for (size_type i = 0; i < size1; ++ i)
|
||||
for (size_type j = 0; j < size2; ++ j)
|
||||
row (m, i).plus_assign (e1 () (i, j) * row (e2 (), j));
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
||||
#endif
|
||||
return m;
|
||||
}
|
||||
template<class M, class E1, class E2, class TRI>
|
||||
BOOST_UBLAS_INLINE
|
||||
M &
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
M &m, TRI,
|
||||
sparse_proxy_tag, row_major_tag) {
|
||||
|
||||
typedef TRI triangular_restriction;
|
||||
typedef const E1 expression1_type;
|
||||
typedef const E2 expression2_type;
|
||||
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
typedef typename M::value_type value_type;
|
||||
matrix<value_type, row_major> cm (m);
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
|
||||
#endif
|
||||
typename expression1_type::const_iterator1 it1 (e1 ().begin1 ());
|
||||
typename expression1_type::const_iterator1 it1_end (e1 ().end1 ());
|
||||
while (it1 != it1_end) {
|
||||
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
||||
typename expression1_type::const_iterator2 it2 (it1.begin ());
|
||||
typename expression1_type::const_iterator2 it2_end (it1.end ());
|
||||
#else
|
||||
typename expression1_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
|
||||
typename expression1_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
|
||||
#endif
|
||||
while (it2 != it2_end) {
|
||||
// row (m, it1.index1 ()).plus_assign (*it2 * row (e2 (), it2.index2 ()));
|
||||
matrix_row<expression2_type> mr (e2 (), it2.index2 ());
|
||||
typename matrix_row<expression2_type>::const_iterator itr (mr.begin ());
|
||||
typename matrix_row<expression2_type>::const_iterator itr_end (mr.end ());
|
||||
while (itr != itr_end) {
|
||||
if (triangular_restriction::other (it1.index1 (), itr.index ()))
|
||||
m (it1.index1 (), itr.index ()) += *it2 * *itr;
|
||||
++ itr;
|
||||
}
|
||||
++ it2;
|
||||
}
|
||||
++ it1;
|
||||
}
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
||||
#endif
|
||||
return m;
|
||||
}
|
||||
|
||||
template<class M, class E1, class E2, class TRI>
|
||||
BOOST_UBLAS_INLINE
|
||||
M &
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
M &m, TRI,
|
||||
dense_proxy_tag, column_major_tag) {
|
||||
typedef typename M::size_type size_type;
|
||||
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
typedef typename M::value_type value_type;
|
||||
matrix<value_type, column_major> cm (m);
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
|
||||
#endif
|
||||
size_type size1 (e2 ().size1 ());
|
||||
size_type size2 (e2 ().size2 ());
|
||||
for (size_type j = 0; j < size2; ++ j)
|
||||
for (size_type i = 0; i < size1; ++ i)
|
||||
column (m, j).plus_assign (e2 () (i, j) * column (e1 (), i));
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
||||
#endif
|
||||
return m;
|
||||
}
|
||||
template<class M, class E1, class E2, class TRI>
|
||||
BOOST_UBLAS_INLINE
|
||||
M &
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
M &m, TRI,
|
||||
sparse_proxy_tag, column_major_tag) {
|
||||
typedef TRI triangular_restriction;
|
||||
typedef const E1 expression1_type;
|
||||
typedef const E2 expression2_type;
|
||||
|
||||
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
typedef typename M::value_type value_type;
|
||||
matrix<value_type, column_major> cm (m);
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
|
||||
#endif
|
||||
typename expression2_type::const_iterator2 it2 (e2 ().begin2 ());
|
||||
typename expression2_type::const_iterator2 it2_end (e2 ().end2 ());
|
||||
while (it2 != it2_end) {
|
||||
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
||||
typename expression2_type::const_iterator1 it1 (it2.begin ());
|
||||
typename expression2_type::const_iterator1 it1_end (it2.end ());
|
||||
#else
|
||||
typename expression2_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
|
||||
typename expression2_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
|
||||
#endif
|
||||
while (it1 != it1_end) {
|
||||
// column (m, it2.index2 ()).plus_assign (*it1 * column (e1 (), it1.index1 ()));
|
||||
matrix_column<expression1_type> mc (e1 (), it1.index1 ());
|
||||
typename matrix_column<expression1_type>::const_iterator itc (mc.begin ());
|
||||
typename matrix_column<expression1_type>::const_iterator itc_end (mc.end ());
|
||||
while (itc != itc_end) {
|
||||
if(triangular_restriction::other (itc.index (), it2.index2 ()))
|
||||
m (itc.index (), it2.index2 ()) += *it1 * *itc;
|
||||
++ itc;
|
||||
}
|
||||
++ it1;
|
||||
}
|
||||
++ it2;
|
||||
}
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
||||
#endif
|
||||
return m;
|
||||
}
|
||||
|
||||
// Dispatcher
|
||||
template<class M, class E1, class E2, class TRI>
|
||||
BOOST_UBLAS_INLINE
|
||||
M &
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
M &m, TRI, bool init = true) {
|
||||
typedef typename M::value_type value_type;
|
||||
typedef typename M::storage_category storage_category;
|
||||
typedef typename M::orientation_category orientation_category;
|
||||
typedef TRI triangular_restriction;
|
||||
|
||||
if (init)
|
||||
m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
|
||||
return axpy_prod (e1, e2, m, triangular_restriction (), storage_category (), orientation_category ());
|
||||
}
|
||||
template<class M, class E1, class E2, class TRI>
|
||||
BOOST_UBLAS_INLINE
|
||||
M
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
TRI) {
|
||||
typedef M matrix_type;
|
||||
typedef TRI triangular_restriction;
|
||||
|
||||
matrix_type m (e1 ().size1 (), e2 ().size2 ());
|
||||
return axpy_prod (e1, e2, m, triangular_restriction (), true);
|
||||
}
|
||||
|
||||
/** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
|
||||
optimized fashion.
|
||||
|
||||
\param e1 the matrix expression \c A
|
||||
\param e2 the matrix expression \c X
|
||||
\param m the result matrix \c M
|
||||
\param init a boolean parameter
|
||||
|
||||
<tt>axpy_prod(A, X, M, init)</tt> implements the well known
|
||||
axpy-product. Setting \a init to \c true is equivalent to call
|
||||
<tt>M.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
|
||||
defaults to \c true, but this may change in the future.
|
||||
|
||||
Up to now there are no specialisations.
|
||||
|
||||
\ingroup blas3
|
||||
|
||||
\internal
|
||||
|
||||
template parameters:
|
||||
\param M type of the result matrix \c M
|
||||
\param E1 type of a matrix expression \c A
|
||||
\param E2 type of a matrix expression \c X
|
||||
*/
|
||||
template<class M, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
M &
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
M &m, bool init = true) {
|
||||
typedef typename M::value_type value_type;
|
||||
typedef typename M::storage_category storage_category;
|
||||
typedef typename M::orientation_category orientation_category;
|
||||
|
||||
if (init)
|
||||
m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
|
||||
return axpy_prod (e1, e2, m, full (), storage_category (), orientation_category ());
|
||||
}
|
||||
template<class M, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
M
|
||||
axpy_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2) {
|
||||
typedef M matrix_type;
|
||||
|
||||
matrix_type m (e1 ().size1 (), e2 ().size2 ());
|
||||
return axpy_prod (e1, e2, m, full (), true);
|
||||
}
|
||||
|
||||
|
||||
template<class M, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
M &
|
||||
opb_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
M &m,
|
||||
dense_proxy_tag, row_major_tag) {
|
||||
typedef typename M::size_type size_type;
|
||||
typedef typename M::value_type value_type;
|
||||
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
matrix<value_type, row_major> cm (m);
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
|
||||
#endif
|
||||
size_type size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
|
||||
for (size_type k = 0; k < size; ++ k) {
|
||||
vector<value_type> ce1 (column (e1 (), k));
|
||||
vector<value_type> re2 (row (e2 (), k));
|
||||
m.plus_assign (outer_prod (ce1, re2));
|
||||
}
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
||||
#endif
|
||||
return m;
|
||||
}
|
||||
|
||||
template<class M, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
M &
|
||||
opb_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
M &m,
|
||||
dense_proxy_tag, column_major_tag) {
|
||||
typedef typename M::size_type size_type;
|
||||
typedef typename M::value_type value_type;
|
||||
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
matrix<value_type, column_major> cm (m);
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
|
||||
#endif
|
||||
size_type size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
|
||||
for (size_type k = 0; k < size; ++ k) {
|
||||
vector<value_type> ce1 (column (e1 (), k));
|
||||
vector<value_type> re2 (row (e2 (), k));
|
||||
m.plus_assign (outer_prod (ce1, re2));
|
||||
}
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
||||
#endif
|
||||
return m;
|
||||
}
|
||||
|
||||
// Dispatcher
|
||||
|
||||
/** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
|
||||
optimized fashion.
|
||||
|
||||
\param e1 the matrix expression \c A
|
||||
\param e2 the matrix expression \c X
|
||||
\param m the result matrix \c M
|
||||
\param init a boolean parameter
|
||||
|
||||
<tt>opb_prod(A, X, M, init)</tt> implements the well known
|
||||
axpy-product. Setting \a init to \c true is equivalent to call
|
||||
<tt>M.clear()</tt> before <tt>opb_prod</tt>. Currently \a init
|
||||
defaults to \c true, but this may change in the future.
|
||||
|
||||
This function may give a speedup if \c A has less columns than
|
||||
rows, because the product is computed as a sum of outer
|
||||
products.
|
||||
|
||||
\ingroup blas3
|
||||
|
||||
\internal
|
||||
|
||||
template parameters:
|
||||
\param M type of the result matrix \c M
|
||||
\param E1 type of a matrix expression \c A
|
||||
\param E2 type of a matrix expression \c X
|
||||
*/
|
||||
template<class M, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
M &
|
||||
opb_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
M &m, bool init = true) {
|
||||
typedef typename M::value_type value_type;
|
||||
typedef typename M::storage_category storage_category;
|
||||
typedef typename M::orientation_category orientation_category;
|
||||
|
||||
if (init)
|
||||
m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
|
||||
return opb_prod (e1, e2, m, storage_category (), orientation_category ());
|
||||
}
|
||||
template<class M, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
M
|
||||
opb_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2) {
|
||||
typedef M matrix_type;
|
||||
|
||||
matrix_type m (e1 ().size1 (), e2 ().size2 ());
|
||||
return opb_prod (e1, e2, m, true);
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
318
include/boost/numeric/ublas/operation/begin.hpp
Normal file
318
include/boost/numeric/ublas/operation/begin.hpp
Normal file
@@ -0,0 +1,318 @@
|
||||
/**
|
||||
* -*- c++ -*-
|
||||
*
|
||||
* \file begin.hpp
|
||||
*
|
||||
* \brief The \c begin operation.
|
||||
*
|
||||
* Copyright (c) 2009, Marco Guazzone
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* \author Marco Guazzone, marco.guazzone@gmail.com
|
||||
*/
|
||||
|
||||
#ifndef BOOST_NUMERIC_UBLAS_OPERATION_BEGIN_HPP
|
||||
#define BOOST_NUMERIC_UBLAS_OPERATION_BEGIN_HPP
|
||||
|
||||
|
||||
#include <boost/numeric/ublas/expression_types.hpp>
|
||||
#include <boost/numeric/ublas/fwd.hpp>
|
||||
#include <boost/numeric/ublas/traits/const_iterator_type.hpp>
|
||||
#include <boost/numeric/ublas/traits/iterator_type.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* \brief Auxiliary class for implementing the \c begin operation.
|
||||
* \tparam CategoryT The expression category type (e.g., vector_tag).
|
||||
* \tparam TagT The dimension type tag (e.g., tag::major).
|
||||
* \tparam OrientationT The orientation category type (e.g., row_major_tag).
|
||||
*/
|
||||
template <typename CategoryT, typename TagT=void, typename OrientationT=void>
|
||||
struct begin_impl;
|
||||
|
||||
|
||||
/// \brief Specialization of \c begin_impl for iterating vector expressions.
|
||||
template <>
|
||||
struct begin_impl<vector_tag,void,void>
|
||||
{
|
||||
/**
|
||||
* \brief Return an iterator to the first element of the given vector
|
||||
* expression.
|
||||
* \tparam ExprT A model of VectorExpression type.
|
||||
* \param e A vector expression.
|
||||
* \return An iterator over the given vector expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::iterator apply(ExprT& e)
|
||||
{
|
||||
return e.begin();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return a const iterator to the first element of the given vector
|
||||
* expression.
|
||||
* \tparam ExprT A model of VectorExpression type.
|
||||
* \param e A vector expression.
|
||||
* \return A const iterator to the first element of the given vector
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::const_iterator apply(ExprT const& e)
|
||||
{
|
||||
return e.begin();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c begin_impl for iterating matrix expressions with
|
||||
/// a row-major orientation over the major dimension.
|
||||
template <>
|
||||
struct begin_impl<matrix_tag,tag::major,row_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Return an iterator to the first element of the given row-major
|
||||
* matrix expression over the major dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return An iterator over the major dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::iterator1 apply(ExprT& e)
|
||||
{
|
||||
return e.begin1();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return a const iterator to the first element of the given
|
||||
* row-major matrix expression over the major dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return A const iterator over the major dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::const_iterator1 apply(ExprT const& e)
|
||||
{
|
||||
return e.begin1();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c begin_impl for iterating matrix expressions with
|
||||
/// a column-major orientation over the major dimension.
|
||||
template <>
|
||||
struct begin_impl<matrix_tag,tag::major,column_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Return an iterator to the first element of the given column-major
|
||||
* matrix expression over the major dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return An iterator over the major dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::iterator2 apply(ExprT& e)
|
||||
{
|
||||
return e.begin2();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return a const iterator to the first element of the given
|
||||
* column-major matrix expression over the major dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return A const iterator over the major dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::const_iterator2 apply(ExprT const& e)
|
||||
{
|
||||
return e.begin2();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c begin_impl for iterating matrix expressions with
|
||||
/// a row-major orientation over the minor dimension.
|
||||
template <>
|
||||
struct begin_impl<matrix_tag,tag::minor,row_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Return an iterator to the first element of the given row-major
|
||||
* matrix expression over the minor dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return An iterator over the minor dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::iterator2 apply(ExprT& e)
|
||||
{
|
||||
return e.begin2();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return a const iterator to the first element of the given
|
||||
* row-major matrix expression over the minor dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return A const iterator over the minor dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::const_iterator2 apply(ExprT const& e)
|
||||
{
|
||||
return e.begin2();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// \brief Specialization of \c begin_impl for iterating matrix expressions with
|
||||
/// a column-major orientation over the minor dimension.
|
||||
template <>
|
||||
struct begin_impl<matrix_tag,tag::minor,column_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Return an iterator to the first element of the given column-major
|
||||
* matrix expression over the minor dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return An iterator over the minor dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::iterator1 apply(ExprT& e)
|
||||
{
|
||||
return e.begin1();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return a const iterator to the first element of the given
|
||||
* column-major matrix expression over the minor dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return A const iterator over the minor dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::const_iterator1 apply(ExprT const& e)
|
||||
{
|
||||
return e.begin1();
|
||||
}
|
||||
};
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
|
||||
/**
|
||||
* \brief An iterator to the first element of the given vector expression.
|
||||
* \tparam ExprT A model of VectorExpression type.
|
||||
* \param e A vector expression.
|
||||
* \return An iterator to the first element of the given vector expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename ExprT::iterator begin(vector_expression<ExprT>& e)
|
||||
{
|
||||
return detail::begin_impl<typename ExprT::type_category>::apply(e());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief A const iterator to the first element of the given vector expression.
|
||||
* \tparam ExprT A model of VectorExpression type.
|
||||
* \param e A vector expression.
|
||||
* \return A const iterator to the first element of the given vector expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename ExprT::const_iterator begin(vector_expression<ExprT> const& e)
|
||||
{
|
||||
return detail::begin_impl<typename ExprT::type_category>::apply(e());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief An iterator to the first element of the given matrix expression
|
||||
* according to its orientation.
|
||||
* \tparam DimTagT A dimension tag type (e.g., tag::major).
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return An iterator to the first element of the given matrix expression
|
||||
* according to its orientation.
|
||||
*/
|
||||
template <typename TagT, typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename iterator_type<ExprT,TagT>::type begin(matrix_expression<ExprT>& e)
|
||||
{
|
||||
return detail::begin_impl<typename ExprT::type_category, TagT, typename ExprT::orientation_category>::apply(e());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief A const iterator to the first element of the given matrix expression
|
||||
* according to its orientation.
|
||||
* \tparam TagT A dimension tag type (e.g., tag::major).
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return A const iterator to the first element of the given matrix expression
|
||||
* according to its orientation.
|
||||
*/
|
||||
template <typename TagT, typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename const_iterator_type<ExprT,TagT>::type begin(matrix_expression<ExprT> const& e)
|
||||
{
|
||||
return detail::begin_impl<typename ExprT::type_category, TagT, typename ExprT::orientation_category>::apply(e());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief An iterator to the first element over the dual dimension of the given
|
||||
* iterator.
|
||||
* \tparam IteratorT A model of Iterator type.
|
||||
* \param it An iterator.
|
||||
* \return An iterator to the first element over the dual dimension of the given
|
||||
* iterator.
|
||||
*/
|
||||
template <typename IteratorT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename IteratorT::dual_iterator_type begin(IteratorT& it)
|
||||
{
|
||||
return it.begin();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief A const iterator to the first element over the dual dimension of the
|
||||
* given iterator.
|
||||
* \tparam IteratorT A model of Iterator type.
|
||||
* \param it An iterator.
|
||||
* \return A const iterator to the first element over the dual dimension of the
|
||||
* given iterator.
|
||||
*/
|
||||
template <typename IteratorT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename IteratorT::dual_iterator_type begin(IteratorT const& it)
|
||||
{
|
||||
return it.begin();
|
||||
}
|
||||
|
||||
}}} // Namespace boost::numeric::ublas
|
||||
|
||||
|
||||
#endif // BOOST_NUMERIC_UBLAS_OPERATION_BEGIN_HPP
|
||||
41
include/boost/numeric/ublas/operation/c_array.hpp
Normal file
41
include/boost/numeric/ublas/operation/c_array.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* -*- c++ -*-
|
||||
*
|
||||
* \file c_array.hpp
|
||||
*
|
||||
* \brief provides specializations of matrix and vector operations for c arrays and c matrices.
|
||||
*
|
||||
* Copyright (c) 2009, Gunter Winkler
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* \author Gunter Winkler (guwi17 at gmx dot de)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_NUMERIC_UBLAS_OPERATION_C_ARRAY_HPP
|
||||
#define BOOST_NUMERIC_UBLAS_OPERATION_C_ARRAY_HPP
|
||||
|
||||
#include <boost/numeric/ublas/traits/c_array.hpp>
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
|
||||
} // namespace boost::numeric::ublas::detail
|
||||
|
||||
|
||||
template <typename T>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename ExprT::const_iterator begin(vector_expression<ExprT> const& e)
|
||||
{
|
||||
return detail::begin_impl<typename ExprT::type_category>::apply(e());
|
||||
}
|
||||
|
||||
|
||||
}}} // Namespace boost::numeric::ublas
|
||||
|
||||
#endif
|
||||
318
include/boost/numeric/ublas/operation/end.hpp
Normal file
318
include/boost/numeric/ublas/operation/end.hpp
Normal file
@@ -0,0 +1,318 @@
|
||||
/**
|
||||
* -*- c++ -*-
|
||||
*
|
||||
* \file end.hpp
|
||||
*
|
||||
* \brief The \c end operation.
|
||||
*
|
||||
* Copyright (c) 2009, Marco Guazzone
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* \author Marco Guazzone, marco.guazzone@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BOOST_NUMERIC_UBLAS_OPERATION_END_HPP
|
||||
#define BOOST_NUMERIC_UBLAS_OPERATION_END_HPP
|
||||
|
||||
|
||||
#include <boost/numeric/ublas/expression_types.hpp>
|
||||
#include <boost/numeric/ublas/fwd.hpp>
|
||||
#include <boost/numeric/ublas/traits/const_iterator_type.hpp>
|
||||
#include <boost/numeric/ublas/traits/iterator_type.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* \brief Auxiliary class for implementing the \c end operation.
|
||||
* \tparam CategoryT The expression category type (e.g., vector_tag).
|
||||
* \tparam TagT The dimension type tag (e.g., tag::major).
|
||||
* \tparam OrientationT The orientation category type (e.g., row_major_tag).
|
||||
*/
|
||||
template <typename CategoryT, typename TagT=void, typename OrientationT=void>
|
||||
struct end_impl;
|
||||
|
||||
|
||||
/// \brief Specialization of \c end_impl for iterating vector expressions.
|
||||
template <>
|
||||
struct end_impl<vector_tag,void,void>
|
||||
{
|
||||
/**
|
||||
* \brief Return an iterator to the last element of the given vector
|
||||
* expression.
|
||||
* \tparam ExprT A model of VectorExpression type.
|
||||
* \param e A vector expression.
|
||||
* \return An iterator over the given vector expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::iterator apply(ExprT& e)
|
||||
{
|
||||
return e.end();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return a const iterator to the last element of the given vector
|
||||
* expression.
|
||||
* \tparam ExprT A model of VectorExpression type.
|
||||
* \param e A vector expression.
|
||||
* \return A const iterator to the first element of the given vector
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::const_iterator apply(ExprT const& e)
|
||||
{
|
||||
return e.end();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c end_impl for iterating matrix expressions with a
|
||||
/// row-major orientation over the major dimension.
|
||||
template <>
|
||||
struct end_impl<matrix_tag,tag::major,row_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Return an iterator to the last element of the given row-major
|
||||
* matrix expression over the major dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return An iterator over the major dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::iterator1 apply(ExprT& e)
|
||||
{
|
||||
return e.end1();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return a const iterator to the last element of the given row-major
|
||||
* matrix expression over the major dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return A const iterator over the major dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::const_iterator1 apply(ExprT const& e)
|
||||
{
|
||||
return e.end1();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c end_impl for iterating matrix expressions with a
|
||||
/// column-major orientation over the major dimension.
|
||||
template <>
|
||||
struct end_impl<matrix_tag,tag::major,column_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Return an iterator to the last element of the given column-major
|
||||
* matrix expression over the major dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return An iterator over the major dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::iterator2 apply(ExprT& e)
|
||||
{
|
||||
return e.end2();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return a const iterator to the last element of the given
|
||||
* column-major matrix expression over the major dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return A const iterator over the major dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::const_iterator2 apply(ExprT const& e)
|
||||
{
|
||||
return e.end2();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c end_impl for iterating matrix expressions with a
|
||||
/// row-major orientation over the minor dimension.
|
||||
template <>
|
||||
struct end_impl<matrix_tag,tag::minor,row_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Return an iterator to the last element of the given row-major
|
||||
* matrix expression over the minor dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return An iterator over the minor dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::iterator2 apply(ExprT& e)
|
||||
{
|
||||
return e.end2();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return a const iterator to the last element of the given
|
||||
* row-minor matrix expression over the major dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return A const iterator over the minor dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::const_iterator2 apply(ExprT const& e)
|
||||
{
|
||||
return e.end2();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c end_impl for iterating matrix expressions with a
|
||||
/// column-major orientation over the minor dimension.
|
||||
template <>
|
||||
struct end_impl<matrix_tag,tag::minor,column_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Return an iterator to the last element of the given column-major
|
||||
* matrix expression over the minor dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return An iterator over the minor dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::iterator1 apply(ExprT& e)
|
||||
{
|
||||
return e.end1();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return a const iterator to the last element of the given
|
||||
* column-minor matrix expression over the major dimension.
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return A const iterator over the minor dimension of the given matrix
|
||||
* expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
static typename ExprT::const_iterator1 apply(ExprT const& e)
|
||||
{
|
||||
return e.end1();
|
||||
}
|
||||
};
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
|
||||
/**
|
||||
* \brief An iterator to the last element of the given vector expression.
|
||||
* \tparam ExprT A model of VectorExpression type.
|
||||
* \param e A vector expression.
|
||||
* \return An iterator to the last element of the given vector expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename ExprT::iterator end(vector_expression<ExprT>& e)
|
||||
{
|
||||
return detail::end_impl<typename ExprT::type_category>::apply(e());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief A const iterator to the last element of the given vector expression.
|
||||
* \tparam ExprT A model of VectorExpression type.
|
||||
* \param e A vector expression.
|
||||
* \return A const iterator to the last element of the given vector expression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename ExprT::const_iterator end(vector_expression<ExprT> const& e)
|
||||
{
|
||||
return detail::end_impl<typename ExprT::type_category>::apply(e());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief An iterator to the last element of the given matrix expression
|
||||
* according to its orientation.
|
||||
* \tparam DimTagT A dimension tag type (e.g., tag::major).
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return An iterator to the last element of the given matrix expression
|
||||
* according to its orientation.
|
||||
*/
|
||||
template <typename TagT, typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename iterator_type<ExprT,TagT>::type end(matrix_expression<ExprT>& e)
|
||||
{
|
||||
return detail::end_impl<typename ExprT::type_category, TagT, typename ExprT::orientation_category>::apply(e());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief A const iterator to the last element of the given matrix expression
|
||||
* according to its orientation.
|
||||
* \tparam TagT A dimension tag type (e.g., tag::major).
|
||||
* \tparam ExprT A model of MatrixExpression type.
|
||||
* \param e A matrix expression.
|
||||
* \return A const iterator to the last element of the given matrix expression
|
||||
* according to its orientation.
|
||||
*/
|
||||
template <typename TagT, typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename const_iterator_type<ExprT,TagT>::type end(matrix_expression<ExprT> const& e)
|
||||
{
|
||||
return detail::end_impl<typename ExprT::type_category, TagT, typename ExprT::orientation_category>::apply(e());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief An iterator to the last element over the dual dimension of the given
|
||||
* iterator.
|
||||
* \tparam IteratorT A model of Iterator type.
|
||||
* \param it An iterator.
|
||||
* \return An iterator to the last element over the dual dimension of the given
|
||||
* iterator.
|
||||
*/
|
||||
template <typename IteratorT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename IteratorT::dual_iterator_type end(IteratorT& it)
|
||||
{
|
||||
return it.end();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief A const iterator to the last element over the dual dimension of the
|
||||
* given iterator.
|
||||
* \tparam IteratorT A model of Iterator type.
|
||||
* \param it An iterator.
|
||||
* \return A const iterator to the last element over the dual dimension of the
|
||||
* given iterator.
|
||||
*/
|
||||
template <typename IteratorT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename IteratorT::dual_iterator_type end(IteratorT const& it)
|
||||
{
|
||||
return it.end();
|
||||
}
|
||||
|
||||
}}} // Namespace boost::numeric::ublas
|
||||
|
||||
|
||||
#endif // BOOST_NUMERIC_UBLAS_OPERATION_END_HPP
|
||||
45
include/boost/numeric/ublas/operation/num_columns.hpp
Normal file
45
include/boost/numeric/ublas/operation/num_columns.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* -*- c++ -*-
|
||||
*
|
||||
* \file num_columns.hpp
|
||||
*
|
||||
* \brief The \c num_columns operation.
|
||||
*
|
||||
* Copyright (c) 2009, Marco Guazzone
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* \author Marco Guazzone, marco.guazzone@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BOOST_NUMERIC_UBLAS_OPERATION_NUM_COLUMNS_HPP
|
||||
#define BOOST_NUMERIC_UBLAS_OPERATION_NUM_COLUMNS_HPP
|
||||
|
||||
|
||||
#include <boost/numeric/ublas/detail/config.hpp>
|
||||
#include <boost/numeric/ublas/expression_types.hpp>
|
||||
#include <boost/numeric/ublas/traits.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
/**
|
||||
* \brief Return the number of columns.
|
||||
* \tparam MatrixExprT A type which models the matrix expression concept.
|
||||
* \param m A matrix expression.
|
||||
* \return The number of columns.
|
||||
*/
|
||||
template <typename MatrixExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename matrix_traits<MatrixExprT>::size_type num_columns(matrix_expression<MatrixExprT> const& me)
|
||||
{
|
||||
return me().size2();
|
||||
}
|
||||
|
||||
}}} // Namespace boost::numeric::ublas
|
||||
|
||||
|
||||
#endif // BOOST_NUMERIC_UBLAS_OPERATION_NUM_COLUMNS_HPP
|
||||
44
include/boost/numeric/ublas/operation/num_rows.hpp
Normal file
44
include/boost/numeric/ublas/operation/num_rows.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* -*- c++ -*-
|
||||
*
|
||||
* \file num_rows.hpp
|
||||
*
|
||||
* \brief The \c num_rows operation.
|
||||
*
|
||||
* Copyright (c) 2009-2012, Marco Guazzone
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* \author Marco Guazzone, marco.guazzone@gmail.com
|
||||
*/
|
||||
|
||||
#ifndef BOOST_NUMERIC_UBLAS_OPERATION_NUM_ROWS_HPP
|
||||
#define BOOST_NUMERIC_UBLAS_OPERATION_NUM_ROWS_HPP
|
||||
|
||||
|
||||
#include <boost/numeric/ublas/detail/config.hpp>
|
||||
#include <boost/numeric/ublas/expression_types.hpp>
|
||||
#include <boost/numeric/ublas/traits.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
/**
|
||||
* \brief Return the number of rows.
|
||||
* \tparam MatrixExprT A type which models the matrix expression concept.
|
||||
* \param m A matrix expression.
|
||||
* \return The number of rows.
|
||||
*/
|
||||
template <typename MatrixExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename matrix_traits<MatrixExprT>::size_type num_rows(matrix_expression<MatrixExprT> const& me)
|
||||
{
|
||||
return me().size1();
|
||||
}
|
||||
|
||||
}}} // Namespace boost::numeric::ublas
|
||||
|
||||
|
||||
#endif // BOOST_NUMERIC_UBLAS_OPERATION_NUM_ROWS_HPP
|
||||
350
include/boost/numeric/ublas/operation/size.hpp
Normal file
350
include/boost/numeric/ublas/operation/size.hpp
Normal file
@@ -0,0 +1,350 @@
|
||||
/**
|
||||
* \file size.hpp
|
||||
*
|
||||
* \brief The family of \c size operations.
|
||||
*
|
||||
* Copyright (c) 2009-2010, Marco Guazzone
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* \author Marco Guazzone, marco.guazzone@gmail.com
|
||||
*/
|
||||
|
||||
#ifndef BOOST_NUMERIC_UBLAS_OPERATION_SIZE_HPP
|
||||
#define BOOST_NUMERIC_UBLAS_OPERATION_SIZE_HPP
|
||||
|
||||
|
||||
#include <boost/mpl/has_xxx.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/numeric/ublas/detail/config.hpp>
|
||||
#include <boost/numeric/ublas/expression_types.hpp>
|
||||
#include <boost/numeric/ublas/fwd.hpp>
|
||||
#include <boost/numeric/ublas/tags.hpp>
|
||||
#include <boost/numeric/ublas/traits.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
namespace detail { namespace /*<unnamed>*/ {
|
||||
|
||||
/// Define a \c has_size_type trait class.
|
||||
BOOST_MPL_HAS_XXX_TRAIT_DEF(size_type)
|
||||
|
||||
|
||||
/**
|
||||
* \brief Wrapper type-traits used in \c boost::lazy_enabled_if for getting the
|
||||
* size type (see below).
|
||||
* \tparam VectorT A vector type.
|
||||
*/
|
||||
template <typename VectorT>
|
||||
struct vector_size_type
|
||||
{
|
||||
/// The size type.
|
||||
typedef typename vector_traits<VectorT>::size_type type;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Wrapper type-traits used in \c boost::lazy_enabled_if for getting the
|
||||
* size type (see below).
|
||||
* \tparam MatrixT A matrix type.
|
||||
*/
|
||||
template <typename MatrixT>
|
||||
struct matrix_size_type
|
||||
{
|
||||
/// The size type.
|
||||
typedef typename matrix_traits<MatrixT>::size_type type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Auxiliary class for computing the size of the given dimension for
|
||||
* a container of the given category.
|
||||
* \tparam Dim The dimension number (starting from 1).
|
||||
* \tparam CategoryT The category type (e.g., vector_tag).
|
||||
*/
|
||||
template <std::size_t Dim, typename CategoryT>
|
||||
struct size_by_dim_impl;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Auxiliary class for computing the size of the given dimension for
|
||||
* a container of the given category and with the given orientation.
|
||||
* \tparam Dim The dimension number (starting from 1).
|
||||
* \tparam CategoryT The category type (e.g., vector_tag).
|
||||
* \tparam OrientationT The orientation category type (e.g., row_major_tag).
|
||||
*/
|
||||
template <typename TagT, typename CategoryT, typename OrientationT>
|
||||
struct size_by_tag_impl;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Specialization of \c size_by_dim_impl for computing the size of a
|
||||
* vector.
|
||||
*/
|
||||
template <>
|
||||
struct size_by_dim_impl<1, vector_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Compute the size of the given vector.
|
||||
* \tparam ExprT A vector expression type.
|
||||
* \pre ExprT must be a model of VectorExpression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
static typename vector_traits<ExprT>::size_type apply(vector_expression<ExprT> const& ve)
|
||||
{
|
||||
return ve().size();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Specialization of \c size_by_dim_impl for computing the number of
|
||||
* rows of a matrix
|
||||
*/
|
||||
template <>
|
||||
struct size_by_dim_impl<1, matrix_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Compute the number of rows of the given matrix.
|
||||
* \tparam ExprT A matrix expression type.
|
||||
* \pre ExprT must be a model of MatrixExpression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
static typename matrix_traits<ExprT>::size_type apply(matrix_expression<ExprT> const& me)
|
||||
{
|
||||
return me().size1();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Specialization of \c size_by_dim_impl for computing the number of
|
||||
* columns of a matrix
|
||||
*/
|
||||
template <>
|
||||
struct size_by_dim_impl<2, matrix_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Compute the number of columns of the given matrix.
|
||||
* \tparam ExprT A matrix expression type.
|
||||
* \pre ExprT must be a model of MatrixExpression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
static typename matrix_traits<ExprT>::size_type apply(matrix_expression<ExprT> const& me)
|
||||
{
|
||||
return me().size2();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Specialization of \c size_by_tag_impl for computing the size of the
|
||||
* major dimension of a row-major oriented matrix.
|
||||
*/
|
||||
template <>
|
||||
struct size_by_tag_impl<tag::major, matrix_tag, row_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Compute the number of rows of the given matrix.
|
||||
* \tparam ExprT A matrix expression type.
|
||||
* \pre ExprT must be a model of MatrixExpression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
static typename matrix_traits<ExprT>::size_type apply(matrix_expression<ExprT> const& me)
|
||||
{
|
||||
return me().size1();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Specialization of \c size_by_tag_impl for computing the size of the
|
||||
* minor dimension of a row-major oriented matrix.
|
||||
*/
|
||||
template <>
|
||||
struct size_by_tag_impl<tag::minor, matrix_tag, row_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Compute the number of columns of the given matrix.
|
||||
* \tparam ExprT A matrix expression type.
|
||||
* \pre ExprT must be a model of MatrixExpression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
static typename matrix_traits<ExprT>::size_type apply(matrix_expression<ExprT> const& me)
|
||||
{
|
||||
return me().size2();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Specialization of \c size_by_tag_impl for computing the size of the
|
||||
* leading dimension of a row-major oriented matrix.
|
||||
*/
|
||||
template <>
|
||||
struct size_by_tag_impl<tag::leading, matrix_tag, row_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Compute the number of columns of the given matrix.
|
||||
* \tparam ExprT A matrix expression type.
|
||||
* \pre ExprT must be a model of MatrixExpression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
static typename matrix_traits<ExprT>::size_type apply(matrix_expression<ExprT> const& me)
|
||||
{
|
||||
return me().size2();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c size_by_tag_impl for computing the size of the
|
||||
/// major dimension of a column-major oriented matrix.
|
||||
template <>
|
||||
struct size_by_tag_impl<tag::major, matrix_tag, column_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Compute the number of columns of the given matrix.
|
||||
* \tparam ExprT A matrix expression type.
|
||||
* \pre ExprT must be a model of MatrixExpression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
static typename matrix_traits<ExprT>::size_type apply(matrix_expression<ExprT> const& me)
|
||||
{
|
||||
return me().size2();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c size_by_tag_impl for computing the size of the
|
||||
/// minor dimension of a column-major oriented matrix.
|
||||
template <>
|
||||
struct size_by_tag_impl<tag::minor, matrix_tag, column_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Compute the number of rows of the given matrix.
|
||||
* \tparam ExprT A matrix expression type.
|
||||
* \pre ExprT must be a model of MatrixExpression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
static typename matrix_traits<ExprT>::size_type apply(matrix_expression<ExprT> const& me)
|
||||
{
|
||||
return me().size1();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c size_by_tag_impl for computing the size of the
|
||||
/// leading dimension of a column-major oriented matrix.
|
||||
template <>
|
||||
struct size_by_tag_impl<tag::leading, matrix_tag, column_major_tag>
|
||||
{
|
||||
/**
|
||||
* \brief Compute the number of rows of the given matrix.
|
||||
* \tparam ExprT A matrix expression type.
|
||||
* \pre ExprT must be a model of MatrixExpression.
|
||||
*/
|
||||
template <typename ExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
static typename matrix_traits<ExprT>::size_type apply(matrix_expression<ExprT> const& me)
|
||||
{
|
||||
return me().size1();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c size_by_tag_impl for computing the size of the
|
||||
/// given dimension of a unknown oriented expression.
|
||||
template <typename TagT, typename CategoryT>
|
||||
struct size_by_tag_impl<TagT, CategoryT, unknown_orientation_tag>: size_by_tag_impl<TagT, CategoryT, row_major_tag>
|
||||
{
|
||||
// Empty
|
||||
};
|
||||
|
||||
}} // Namespace detail::<unnamed>
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return the number of columns.
|
||||
* \tparam VectorExprT A type which models the vector expression concept.
|
||||
* \param ve A vector expression.
|
||||
* \return The length of the input vector expression.
|
||||
*/
|
||||
template <typename VectorExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename ::boost::lazy_enable_if_c<
|
||||
detail::has_size_type<VectorExprT>::value,
|
||||
detail::vector_size_type<VectorExprT>
|
||||
>::type size(vector_expression<VectorExprT> const& ve)
|
||||
{
|
||||
return ve().size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return the size of the given dimension for the given vector
|
||||
* expression.
|
||||
* \tparam Dim The dimension number (starting from 1).
|
||||
* \tparam VectorExprT A vector expression type.
|
||||
* \param ve A vector expression.
|
||||
* \return The length of the input vector expression.
|
||||
*/
|
||||
template <std::size_t Dim, typename VectorExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename vector_traits<VectorExprT>::size_type size(vector_expression<VectorExprT> const& ve)
|
||||
{
|
||||
return detail::size_by_dim_impl<Dim, vector_tag>::apply(ve);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return the size of the given dimension for the given matrix
|
||||
* expression.
|
||||
* \tparam Dim The dimension number (starting from 1).
|
||||
* \tparam MatrixExprT A matrix expression type.
|
||||
* \param e A matrix expression.
|
||||
* \return The size of the input matrix expression associated to the dimension
|
||||
* \a Dim.
|
||||
*/
|
||||
template <std::size_t Dim, typename MatrixExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename matrix_traits<MatrixExprT>::size_type size(matrix_expression<MatrixExprT> const& me)
|
||||
{
|
||||
return detail::size_by_dim_impl<Dim, matrix_tag>::apply(me);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return the size of the given dimension tag for the given matrix
|
||||
* expression.
|
||||
* \tparam TagT The dimension tag type (e.g., tag::major).
|
||||
* \tparam MatrixExprT A matrix expression type.
|
||||
* \param e A matrix expression.
|
||||
* \return The size of the input matrix expression associated to the dimension
|
||||
* tag \a TagT.
|
||||
*/
|
||||
template <typename TagT, typename MatrixExprT>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename ::boost::lazy_enable_if_c<
|
||||
detail::has_size_type<MatrixExprT>::value,
|
||||
detail::matrix_size_type<MatrixExprT>
|
||||
>::type size(matrix_expression<MatrixExprT> const& me)
|
||||
{
|
||||
return detail::size_by_tag_impl<TagT, matrix_tag, typename matrix_traits<MatrixExprT>::orientation_category>::apply(me);
|
||||
}
|
||||
|
||||
}}} // Namespace boost::numeric::ublas
|
||||
|
||||
|
||||
#endif // BOOST_NUMERIC_UBLAS_OPERATION_SIZE_HPP
|
||||
266
include/boost/numeric/ublas/operation_blocked.hpp
Normal file
266
include/boost/numeric/ublas/operation_blocked.hpp
Normal file
@@ -0,0 +1,266 @@
|
||||
//
|
||||
// Copyright (c) 2000-2002
|
||||
// Joerg Walter, Mathias Koch
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
#ifndef _BOOST_UBLAS_OPERATION_BLOCKED_
|
||||
#define _BOOST_UBLAS_OPERATION_BLOCKED_
|
||||
|
||||
#include <boost/numeric/ublas/traits.hpp>
|
||||
#include <boost/numeric/ublas/detail/vector_assign.hpp> // indexing_vector_assign
|
||||
#include <boost/numeric/ublas/detail/matrix_assign.hpp> // indexing_matrix_assign
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
template<class V, typename V::size_type BS, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V
|
||||
block_prod (const matrix_expression<E1> &e1,
|
||||
const vector_expression<E2> &e2) {
|
||||
typedef V vector_type;
|
||||
typedef const E1 expression1_type;
|
||||
typedef const E2 expression2_type;
|
||||
typedef typename V::size_type size_type;
|
||||
typedef typename V::value_type value_type;
|
||||
const size_type block_size = BS;
|
||||
|
||||
V v (e1 ().size1 ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
vector<value_type> cv (v.size ());
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_vector_assign<scalar_assign> (cv, prod (e1, e2));
|
||||
#endif
|
||||
size_type i_size = e1 ().size1 ();
|
||||
size_type j_size = BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size ());
|
||||
for (size_type i_begin = 0; i_begin < i_size; i_begin += block_size) {
|
||||
size_type i_end = i_begin + (std::min) (i_size - i_begin, block_size);
|
||||
// FIX: never ignore Martin Weiser's advice ;-(
|
||||
#ifdef BOOST_UBLAS_NO_CACHE
|
||||
vector_range<vector_type> v_range (v, range (i_begin, i_end));
|
||||
#else
|
||||
// vector<value_type, bounded_array<value_type, block_size> > v_range (i_end - i_begin);
|
||||
vector<value_type> v_range (i_end - i_begin);
|
||||
#endif
|
||||
v_range.assign (zero_vector<value_type> (i_end - i_begin));
|
||||
for (size_type j_begin = 0; j_begin < j_size; j_begin += block_size) {
|
||||
size_type j_end = j_begin + (std::min) (j_size - j_begin, block_size);
|
||||
#ifdef BOOST_UBLAS_NO_CACHE
|
||||
const matrix_range<expression1_type> e1_range (e1 (), range (i_begin, i_end), range (j_begin, j_end));
|
||||
const vector_range<expression2_type> e2_range (e2 (), range (j_begin, j_end));
|
||||
v_range.plus_assign (prod (e1_range, e2_range));
|
||||
#else
|
||||
// const matrix<value_type, row_major, bounded_array<value_type, block_size * block_size> > e1_range (project (e1 (), range (i_begin, i_end), range (j_begin, j_end)));
|
||||
// const vector<value_type, bounded_array<value_type, block_size> > e2_range (project (e2 (), range (j_begin, j_end)));
|
||||
const matrix<value_type, row_major> e1_range (project (e1 (), range (i_begin, i_end), range (j_begin, j_end)));
|
||||
const vector<value_type> e2_range (project (e2 (), range (j_begin, j_end)));
|
||||
v_range.plus_assign (prod (e1_range, e2_range));
|
||||
#endif
|
||||
}
|
||||
#ifndef BOOST_UBLAS_NO_CACHE
|
||||
project (v, range (i_begin, i_end)).assign (v_range);
|
||||
#endif
|
||||
}
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class V, typename V::size_type BS, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
V
|
||||
block_prod (const vector_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2) {
|
||||
typedef V vector_type;
|
||||
typedef const E1 expression1_type;
|
||||
typedef const E2 expression2_type;
|
||||
typedef typename V::size_type size_type;
|
||||
typedef typename V::value_type value_type;
|
||||
const size_type block_size = BS;
|
||||
|
||||
V v (e2 ().size2 ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
vector<value_type> cv (v.size ());
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_vector_assign<scalar_assign> (cv, prod (e1, e2));
|
||||
#endif
|
||||
size_type i_size = BOOST_UBLAS_SAME (e1 ().size (), e2 ().size1 ());
|
||||
size_type j_size = e2 ().size2 ();
|
||||
for (size_type j_begin = 0; j_begin < j_size; j_begin += block_size) {
|
||||
size_type j_end = j_begin + (std::min) (j_size - j_begin, block_size);
|
||||
// FIX: never ignore Martin Weiser's advice ;-(
|
||||
#ifdef BOOST_UBLAS_NO_CACHE
|
||||
vector_range<vector_type> v_range (v, range (j_begin, j_end));
|
||||
#else
|
||||
// vector<value_type, bounded_array<value_type, block_size> > v_range (j_end - j_begin);
|
||||
vector<value_type> v_range (j_end - j_begin);
|
||||
#endif
|
||||
v_range.assign (zero_vector<value_type> (j_end - j_begin));
|
||||
for (size_type i_begin = 0; i_begin < i_size; i_begin += block_size) {
|
||||
size_type i_end = i_begin + (std::min) (i_size - i_begin, block_size);
|
||||
#ifdef BOOST_UBLAS_NO_CACHE
|
||||
const vector_range<expression1_type> e1_range (e1 (), range (i_begin, i_end));
|
||||
const matrix_range<expression2_type> e2_range (e2 (), range (i_begin, i_end), range (j_begin, j_end));
|
||||
#else
|
||||
// const vector<value_type, bounded_array<value_type, block_size> > e1_range (project (e1 (), range (i_begin, i_end)));
|
||||
// const matrix<value_type, column_major, bounded_array<value_type, block_size * block_size> > e2_range (project (e2 (), range (i_begin, i_end), range (j_begin, j_end)));
|
||||
const vector<value_type> e1_range (project (e1 (), range (i_begin, i_end)));
|
||||
const matrix<value_type, column_major> e2_range (project (e2 (), range (i_begin, i_end), range (j_begin, j_end)));
|
||||
#endif
|
||||
v_range.plus_assign (prod (e1_range, e2_range));
|
||||
}
|
||||
#ifndef BOOST_UBLAS_NO_CACHE
|
||||
project (v, range (j_begin, j_end)).assign (v_range);
|
||||
#endif
|
||||
}
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class M, typename M::size_type BS, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
M
|
||||
block_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
row_major_tag) {
|
||||
typedef M matrix_type;
|
||||
typedef const E1 expression1_type;
|
||||
typedef const E2 expression2_type;
|
||||
typedef typename M::size_type size_type;
|
||||
typedef typename M::value_type value_type;
|
||||
const size_type block_size = BS;
|
||||
|
||||
M m (e1 ().size1 (), e2 ().size2 ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
matrix<value_type, row_major> cm (m.size1 (), m.size2 ());
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_matrix_assign<scalar_assign> (cm, prod (e1, e2), row_major_tag ());
|
||||
disable_type_check<bool>::value = true;
|
||||
#endif
|
||||
size_type i_size = e1 ().size1 ();
|
||||
size_type j_size = e2 ().size2 ();
|
||||
size_type k_size = BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ());
|
||||
for (size_type i_begin = 0; i_begin < i_size; i_begin += block_size) {
|
||||
size_type i_end = i_begin + (std::min) (i_size - i_begin, block_size);
|
||||
for (size_type j_begin = 0; j_begin < j_size; j_begin += block_size) {
|
||||
size_type j_end = j_begin + (std::min) (j_size - j_begin, block_size);
|
||||
// FIX: never ignore Martin Weiser's advice ;-(
|
||||
#ifdef BOOST_UBLAS_NO_CACHE
|
||||
matrix_range<matrix_type> m_range (m, range (i_begin, i_end), range (j_begin, j_end));
|
||||
#else
|
||||
// matrix<value_type, row_major, bounded_array<value_type, block_size * block_size> > m_range (i_end - i_begin, j_end - j_begin);
|
||||
matrix<value_type, row_major> m_range (i_end - i_begin, j_end - j_begin);
|
||||
#endif
|
||||
m_range.assign (zero_matrix<value_type> (i_end - i_begin, j_end - j_begin));
|
||||
for (size_type k_begin = 0; k_begin < k_size; k_begin += block_size) {
|
||||
size_type k_end = k_begin + (std::min) (k_size - k_begin, block_size);
|
||||
#ifdef BOOST_UBLAS_NO_CACHE
|
||||
const matrix_range<expression1_type> e1_range (e1 (), range (i_begin, i_end), range (k_begin, k_end));
|
||||
const matrix_range<expression2_type> e2_range (e2 (), range (k_begin, k_end), range (j_begin, j_end));
|
||||
#else
|
||||
// const matrix<value_type, row_major, bounded_array<value_type, block_size * block_size> > e1_range (project (e1 (), range (i_begin, i_end), range (k_begin, k_end)));
|
||||
// const matrix<value_type, column_major, bounded_array<value_type, block_size * block_size> > e2_range (project (e2 (), range (k_begin, k_end), range (j_begin, j_end)));
|
||||
const matrix<value_type, row_major> e1_range (project (e1 (), range (i_begin, i_end), range (k_begin, k_end)));
|
||||
const matrix<value_type, column_major> e2_range (project (e2 (), range (k_begin, k_end), range (j_begin, j_end)));
|
||||
#endif
|
||||
m_range.plus_assign (prod (e1_range, e2_range));
|
||||
}
|
||||
#ifndef BOOST_UBLAS_NO_CACHE
|
||||
project (m, range (i_begin, i_end), range (j_begin, j_end)).assign (m_range);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
disable_type_check<bool>::value = false;
|
||||
BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
||||
#endif
|
||||
return m;
|
||||
}
|
||||
|
||||
template<class M, typename M::size_type BS, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
M
|
||||
block_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
column_major_tag) {
|
||||
typedef M matrix_type;
|
||||
typedef const E1 expression1_type;
|
||||
typedef const E2 expression2_type;
|
||||
typedef typename M::size_type size_type;
|
||||
typedef typename M::value_type value_type;
|
||||
const size_type block_size = BS;
|
||||
|
||||
M m (e1 ().size1 (), e2 ().size2 ());
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
matrix<value_type, column_major> cm (m.size1 (), m.size2 ());
|
||||
typedef typename type_traits<value_type>::real_type real_type;
|
||||
real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
|
||||
indexing_matrix_assign<scalar_assign> (cm, prod (e1, e2), column_major_tag ());
|
||||
disable_type_check<bool>::value = true;
|
||||
#endif
|
||||
size_type i_size = e1 ().size1 ();
|
||||
size_type j_size = e2 ().size2 ();
|
||||
size_type k_size = BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ());
|
||||
for (size_type j_begin = 0; j_begin < j_size; j_begin += block_size) {
|
||||
size_type j_end = j_begin + (std::min) (j_size - j_begin, block_size);
|
||||
for (size_type i_begin = 0; i_begin < i_size; i_begin += block_size) {
|
||||
size_type i_end = i_begin + (std::min) (i_size - i_begin, block_size);
|
||||
// FIX: never ignore Martin Weiser's advice ;-(
|
||||
#ifdef BOOST_UBLAS_NO_CACHE
|
||||
matrix_range<matrix_type> m_range (m, range (i_begin, i_end), range (j_begin, j_end));
|
||||
#else
|
||||
// matrix<value_type, column_major, bounded_array<value_type, block_size * block_size> > m_range (i_end - i_begin, j_end - j_begin);
|
||||
matrix<value_type, column_major> m_range (i_end - i_begin, j_end - j_begin);
|
||||
#endif
|
||||
m_range.assign (zero_matrix<value_type> (i_end - i_begin, j_end - j_begin));
|
||||
for (size_type k_begin = 0; k_begin < k_size; k_begin += block_size) {
|
||||
size_type k_end = k_begin + (std::min) (k_size - k_begin, block_size);
|
||||
#ifdef BOOST_UBLAS_NO_CACHE
|
||||
const matrix_range<expression1_type> e1_range (e1 (), range (i_begin, i_end), range (k_begin, k_end));
|
||||
const matrix_range<expression2_type> e2_range (e2 (), range (k_begin, k_end), range (j_begin, j_end));
|
||||
#else
|
||||
// const matrix<value_type, row_major, bounded_array<value_type, block_size * block_size> > e1_range (project (e1 (), range (i_begin, i_end), range (k_begin, k_end)));
|
||||
// const matrix<value_type, column_major, bounded_array<value_type, block_size * block_size> > e2_range (project (e2 (), range (k_begin, k_end), range (j_begin, j_end)));
|
||||
const matrix<value_type, row_major> e1_range (project (e1 (), range (i_begin, i_end), range (k_begin, k_end)));
|
||||
const matrix<value_type, column_major> e2_range (project (e2 (), range (k_begin, k_end), range (j_begin, j_end)));
|
||||
#endif
|
||||
m_range.plus_assign (prod (e1_range, e2_range));
|
||||
}
|
||||
#ifndef BOOST_UBLAS_NO_CACHE
|
||||
project (m, range (i_begin, i_end), range (j_begin, j_end)).assign (m_range);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
disable_type_check<bool>::value = false;
|
||||
BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
|
||||
#endif
|
||||
return m;
|
||||
}
|
||||
|
||||
// Dispatcher
|
||||
template<class M, typename M::size_type BS, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
M
|
||||
block_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2) {
|
||||
typedef typename M::orientation_category orientation_category;
|
||||
return block_prod<M, BS> (e1, e2, orientation_category ());
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
198
include/boost/numeric/ublas/operation_sparse.hpp
Normal file
198
include/boost/numeric/ublas/operation_sparse.hpp
Normal file
@@ -0,0 +1,198 @@
|
||||
//
|
||||
// Copyright (c) 2000-2002
|
||||
// Joerg Walter, Mathias Koch
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
#ifndef _BOOST_UBLAS_OPERATION_SPARSE_
|
||||
#define _BOOST_UBLAS_OPERATION_SPARSE_
|
||||
|
||||
#include <boost/numeric/ublas/traits.hpp>
|
||||
|
||||
// These scaled additions were borrowed from MTL unashamedly.
|
||||
// But Alexei Novakov had a lot of ideas to improve these. Thanks.
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
template<class M, class E1, class E2, class TRI>
|
||||
BOOST_UBLAS_INLINE
|
||||
M &
|
||||
sparse_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
M &m, TRI,
|
||||
row_major_tag) {
|
||||
typedef M matrix_type;
|
||||
typedef TRI triangular_restriction;
|
||||
typedef const E1 expression1_type;
|
||||
typedef const E2 expression2_type;
|
||||
typedef typename M::size_type size_type;
|
||||
typedef typename M::value_type value_type;
|
||||
|
||||
// ISSUE why is there a dense vector here?
|
||||
vector<value_type> temporary (e2 ().size2 ());
|
||||
temporary.clear ();
|
||||
typename expression1_type::const_iterator1 it1 (e1 ().begin1 ());
|
||||
typename expression1_type::const_iterator1 it1_end (e1 ().end1 ());
|
||||
while (it1 != it1_end) {
|
||||
size_type jb (temporary.size ());
|
||||
size_type je (0);
|
||||
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
||||
typename expression1_type::const_iterator2 it2 (it1.begin ());
|
||||
typename expression1_type::const_iterator2 it2_end (it1.end ());
|
||||
#else
|
||||
typename expression1_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
|
||||
typename expression1_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
|
||||
#endif
|
||||
while (it2 != it2_end) {
|
||||
// temporary.plus_assign (*it2 * row (e2 (), it2.index2 ()));
|
||||
matrix_row<expression2_type> mr (e2 (), it2.index2 ());
|
||||
typename matrix_row<expression2_type>::const_iterator itr (mr.begin ());
|
||||
typename matrix_row<expression2_type>::const_iterator itr_end (mr.end ());
|
||||
while (itr != itr_end) {
|
||||
size_type j (itr.index ());
|
||||
temporary (j) += *it2 * *itr;
|
||||
jb = (std::min) (jb, j);
|
||||
je = (std::max) (je, j);
|
||||
++ itr;
|
||||
}
|
||||
++ it2;
|
||||
}
|
||||
for (size_type j = jb; j < je + 1; ++ j) {
|
||||
if (temporary (j) != value_type/*zero*/()) {
|
||||
// FIXME we'll need to extend the container interface!
|
||||
// m.push_back (it1.index1 (), j, temporary (j));
|
||||
// FIXME What to do with adaptors?
|
||||
// m.insert (it1.index1 (), j, temporary (j));
|
||||
if (triangular_restriction::other (it1.index1 (), j))
|
||||
m (it1.index1 (), j) = temporary (j);
|
||||
temporary (j) = value_type/*zero*/();
|
||||
}
|
||||
}
|
||||
++ it1;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
template<class M, class E1, class E2, class TRI>
|
||||
BOOST_UBLAS_INLINE
|
||||
M &
|
||||
sparse_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
M &m, TRI,
|
||||
column_major_tag) {
|
||||
typedef M matrix_type;
|
||||
typedef TRI triangular_restriction;
|
||||
typedef const E1 expression1_type;
|
||||
typedef const E2 expression2_type;
|
||||
typedef typename M::size_type size_type;
|
||||
typedef typename M::value_type value_type;
|
||||
|
||||
// ISSUE why is there a dense vector here?
|
||||
vector<value_type> temporary (e1 ().size1 ());
|
||||
temporary.clear ();
|
||||
typename expression2_type::const_iterator2 it2 (e2 ().begin2 ());
|
||||
typename expression2_type::const_iterator2 it2_end (e2 ().end2 ());
|
||||
while (it2 != it2_end) {
|
||||
size_type ib (temporary.size ());
|
||||
size_type ie (0);
|
||||
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
|
||||
typename expression2_type::const_iterator1 it1 (it2.begin ());
|
||||
typename expression2_type::const_iterator1 it1_end (it2.end ());
|
||||
#else
|
||||
typename expression2_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
|
||||
typename expression2_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
|
||||
#endif
|
||||
while (it1 != it1_end) {
|
||||
// column (m, it2.index2 ()).plus_assign (*it1 * column (e1 (), it1.index1 ()));
|
||||
matrix_column<expression1_type> mc (e1 (), it1.index1 ());
|
||||
typename matrix_column<expression1_type>::const_iterator itc (mc.begin ());
|
||||
typename matrix_column<expression1_type>::const_iterator itc_end (mc.end ());
|
||||
while (itc != itc_end) {
|
||||
size_type i (itc.index ());
|
||||
temporary (i) += *it1 * *itc;
|
||||
ib = (std::min) (ib, i);
|
||||
ie = (std::max) (ie, i);
|
||||
++ itc;
|
||||
}
|
||||
++ it1;
|
||||
}
|
||||
for (size_type i = ib; i < ie + 1; ++ i) {
|
||||
if (temporary (i) != value_type/*zero*/()) {
|
||||
// FIXME we'll need to extend the container interface!
|
||||
// m.push_back (i, it2.index2 (), temporary (i));
|
||||
// FIXME What to do with adaptors?
|
||||
// m.insert (i, it2.index2 (), temporary (i));
|
||||
if (triangular_restriction::other (i, it2.index2 ()))
|
||||
m (i, it2.index2 ()) = temporary (i);
|
||||
temporary (i) = value_type/*zero*/();
|
||||
}
|
||||
}
|
||||
++ it2;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
// Dispatcher
|
||||
template<class M, class E1, class E2, class TRI>
|
||||
BOOST_UBLAS_INLINE
|
||||
M &
|
||||
sparse_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
M &m, TRI, bool init = true) {
|
||||
typedef typename M::value_type value_type;
|
||||
typedef TRI triangular_restriction;
|
||||
typedef typename M::orientation_category orientation_category;
|
||||
|
||||
if (init)
|
||||
m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
|
||||
return sparse_prod (e1, e2, m, triangular_restriction (), orientation_category ());
|
||||
}
|
||||
template<class M, class E1, class E2, class TRI>
|
||||
BOOST_UBLAS_INLINE
|
||||
M
|
||||
sparse_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
TRI) {
|
||||
typedef M matrix_type;
|
||||
typedef TRI triangular_restriction;
|
||||
|
||||
matrix_type m (e1 ().size1 (), e2 ().size2 ());
|
||||
// FIXME needed for c_matrix?!
|
||||
// return sparse_prod (e1, e2, m, triangular_restriction (), false);
|
||||
return sparse_prod (e1, e2, m, triangular_restriction (), true);
|
||||
}
|
||||
template<class M, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
M &
|
||||
sparse_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2,
|
||||
M &m, bool init = true) {
|
||||
typedef typename M::value_type value_type;
|
||||
typedef typename M::orientation_category orientation_category;
|
||||
|
||||
if (init)
|
||||
m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
|
||||
return sparse_prod (e1, e2, m, full (), orientation_category ());
|
||||
}
|
||||
template<class M, class E1, class E2>
|
||||
BOOST_UBLAS_INLINE
|
||||
M
|
||||
sparse_prod (const matrix_expression<E1> &e1,
|
||||
const matrix_expression<E2> &e2) {
|
||||
typedef M matrix_type;
|
||||
|
||||
matrix_type m (e1 ().size1 (), e2 ().size2 ());
|
||||
// FIXME needed for c_matrix?!
|
||||
// return sparse_prod (e1, e2, m, full (), false);
|
||||
return sparse_prod (e1, e2, m, full (), true);
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
26
include/boost/numeric/ublas/operations.hpp
Normal file
26
include/boost/numeric/ublas/operations.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* -*- c++ -*-
|
||||
*
|
||||
* \file operations.hpp
|
||||
*
|
||||
* \brief This header includes several headers from the operation directory.
|
||||
*
|
||||
* Copyright (c) 2009, Gunter Winkler
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* \author Gunter Winkler (guwi17 at gmx dot de)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_NUMERIC_UBLAS_OPERATIONS_HPP
|
||||
#define BOOST_NUMERIC_UBLAS_OPERATIONS_HPP
|
||||
|
||||
#include <boost/numeric/ublas/operation/begin.hpp>
|
||||
#include <boost/numeric/ublas/operation/end.hpp>
|
||||
#include <boost/numeric/ublas/operation/num_columns.hpp>
|
||||
#include <boost/numeric/ublas/operation/num_rows.hpp>
|
||||
#include <boost/numeric/ublas/operation/size.hpp>
|
||||
|
||||
#endif
|
||||
2131
include/boost/numeric/ublas/storage.hpp
Normal file
2131
include/boost/numeric/ublas/storage.hpp
Normal file
File diff suppressed because it is too large
Load Diff
578
include/boost/numeric/ublas/storage_sparse.hpp
Normal file
578
include/boost/numeric/ublas/storage_sparse.hpp
Normal file
@@ -0,0 +1,578 @@
|
||||
//
|
||||
// Copyright (c) 2000-2002
|
||||
// Joerg Walter, Mathias Koch
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
#ifndef _BOOST_UBLAS_STORAGE_SPARSE_
|
||||
#define _BOOST_UBLAS_STORAGE_SPARSE_
|
||||
|
||||
#include <map>
|
||||
#include <boost/serialization/collection_size_type.hpp>
|
||||
#include <boost/serialization/nvp.hpp>
|
||||
#include <boost/serialization/array.hpp>
|
||||
#include <boost/serialization/map.hpp>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
|
||||
#include <boost/numeric/ublas/storage.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class I, class T, class C>
|
||||
BOOST_UBLAS_INLINE
|
||||
I lower_bound (const I &begin, const I &end, const T &t, C compare) {
|
||||
// t <= *begin <=> ! (*begin < t)
|
||||
if (begin == end || ! compare (*begin, t))
|
||||
return begin;
|
||||
if (compare (*(end - 1), t))
|
||||
return end;
|
||||
return std::lower_bound (begin, end, t, compare);
|
||||
}
|
||||
template<class I, class T, class C>
|
||||
BOOST_UBLAS_INLINE
|
||||
I upper_bound (const I &begin, const I &end, const T &t, C compare) {
|
||||
if (begin == end || compare (t, *begin))
|
||||
return begin;
|
||||
// (*end - 1) <= t <=> ! (t < *end)
|
||||
if (! compare (t, *(end - 1)))
|
||||
return end;
|
||||
return std::upper_bound (begin, end, t, compare);
|
||||
}
|
||||
|
||||
template<class P>
|
||||
struct less_pair {
|
||||
BOOST_UBLAS_INLINE
|
||||
bool operator () (const P &p1, const P &p2) {
|
||||
return p1.first < p2.first;
|
||||
}
|
||||
};
|
||||
template<class T>
|
||||
struct less_triple {
|
||||
BOOST_UBLAS_INLINE
|
||||
bool operator () (const T &t1, const T &t2) {
|
||||
return t1.first.first < t2.first.first ||
|
||||
(t1.first.first == t2.first.first && t1.first.second < t2.first.second);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifdef BOOST_UBLAS_STRICT_MAP_ARRAY
|
||||
template<class A>
|
||||
class sparse_storage_element:
|
||||
public container_reference<A> {
|
||||
public:
|
||||
typedef A array_type;
|
||||
typedef typename A::key_type index_type;
|
||||
typedef typename A::mapped_type data_value_type;
|
||||
// typedef const data_value_type &data_const_reference;
|
||||
typedef typename type_traits<data_value_type>::const_reference data_const_reference;
|
||||
typedef data_value_type &data_reference;
|
||||
typedef typename A::value_type value_type;
|
||||
typedef value_type *pointer;
|
||||
|
||||
// Construction and destruction
|
||||
BOOST_UBLAS_INLINE
|
||||
sparse_storage_element (array_type &a, pointer it):
|
||||
container_reference<array_type> (a), it_ (it), i_ (it->first), d_ (it->second), dirty_ (false) {}
|
||||
BOOST_UBLAS_INLINE
|
||||
sparse_storage_element (array_type &a, index_type i):
|
||||
container_reference<array_type> (a), it_ (), i_ (i), d_ (), dirty_ (false) {
|
||||
pointer it = (*this) ().find (i_);
|
||||
if (it == (*this) ().end ())
|
||||
it = (*this) ().insert ((*this) ().end (), value_type (i_, d_));
|
||||
d_ = it->second;
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
~sparse_storage_element () {
|
||||
if (dirty_) {
|
||||
if (! it_)
|
||||
it_ = (*this) ().find (i_);
|
||||
BOOST_UBLAS_CHECK (it_ != (*this) ().end (), internal_logic ());
|
||||
it_->second = d_;
|
||||
}
|
||||
}
|
||||
|
||||
// Element access - only if data_const_reference is defined
|
||||
BOOST_UBLAS_INLINE
|
||||
typename data_value_type::data_const_reference
|
||||
operator [] (index_type i) const {
|
||||
return d_ [i];
|
||||
}
|
||||
|
||||
// Assignment
|
||||
BOOST_UBLAS_INLINE
|
||||
sparse_storage_element &operator = (const sparse_storage_element &p) {
|
||||
// Overide the implict copy assignment
|
||||
d_ = p.d_;
|
||||
dirty_ = true;
|
||||
return *this;
|
||||
}
|
||||
template<class D>
|
||||
BOOST_UBLAS_INLINE
|
||||
sparse_storage_element &operator = (const D &d) {
|
||||
d_ = d;
|
||||
dirty_ = true;
|
||||
return *this;
|
||||
}
|
||||
template<class D>
|
||||
BOOST_UBLAS_INLINE
|
||||
sparse_storage_element &operator += (const D &d) {
|
||||
d_ += d;
|
||||
dirty_ = true;
|
||||
return *this;
|
||||
}
|
||||
template<class D>
|
||||
BOOST_UBLAS_INLINE
|
||||
sparse_storage_element &operator -= (const D &d) {
|
||||
d_ -= d;
|
||||
dirty_ = true;
|
||||
return *this;
|
||||
}
|
||||
template<class D>
|
||||
BOOST_UBLAS_INLINE
|
||||
sparse_storage_element &operator *= (const D &d) {
|
||||
d_ *= d;
|
||||
dirty_ = true;
|
||||
return *this;
|
||||
}
|
||||
template<class D>
|
||||
BOOST_UBLAS_INLINE
|
||||
sparse_storage_element &operator /= (const D &d) {
|
||||
d_ /= d;
|
||||
dirty_ = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Comparison
|
||||
template<class D>
|
||||
BOOST_UBLAS_INLINE
|
||||
bool operator == (const D &d) const {
|
||||
return d_ == d;
|
||||
}
|
||||
template<class D>
|
||||
BOOST_UBLAS_INLINE
|
||||
bool operator != (const D &d) const {
|
||||
return d_ != d;
|
||||
}
|
||||
|
||||
// Conversion
|
||||
BOOST_UBLAS_INLINE
|
||||
operator data_const_reference () const {
|
||||
return d_;
|
||||
}
|
||||
|
||||
// Swapping
|
||||
BOOST_UBLAS_INLINE
|
||||
void swap (sparse_storage_element p) {
|
||||
if (this != &p) {
|
||||
dirty_ = true;
|
||||
p.dirty_ = true;
|
||||
std::swap (d_, p.d_);
|
||||
}
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
friend void swap (sparse_storage_element p1, sparse_storage_element p2) {
|
||||
p1.swap (p2);
|
||||
}
|
||||
|
||||
private:
|
||||
pointer it_;
|
||||
index_type i_;
|
||||
data_value_type d_;
|
||||
bool dirty_;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
// Default map type is simply forwarded to std::map
|
||||
template<class I, class T, class ALLOC>
|
||||
class map_std : public std::map<I, T, std::less<I>, ALLOC> {
|
||||
public:
|
||||
// Serialization
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar, const unsigned int /* file_version */){
|
||||
ar & serialization::make_nvp("base", boost::serialization::base_object< std::map<I, T, std::less<I>, ALLOC> >(*this));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Map array
|
||||
// Implementation requires pair<I, T> allocator definition (without const)
|
||||
template<class I, class T, class ALLOC>
|
||||
class map_array {
|
||||
public:
|
||||
typedef ALLOC allocator_type;
|
||||
typedef typename boost::allocator_size_type<ALLOC>::type size_type;
|
||||
typedef typename boost::allocator_difference_type<ALLOC>::type difference_type;
|
||||
typedef std::pair<I,T> value_type;
|
||||
typedef I key_type;
|
||||
typedef T mapped_type;
|
||||
typedef const value_type &const_reference;
|
||||
typedef value_type &reference;
|
||||
typedef const value_type *const_pointer;
|
||||
typedef value_type *pointer;
|
||||
// Iterators simply are pointers.
|
||||
typedef const_pointer const_iterator;
|
||||
typedef pointer iterator;
|
||||
|
||||
typedef const T &data_const_reference;
|
||||
#ifndef BOOST_UBLAS_STRICT_MAP_ARRAY
|
||||
typedef T &data_reference;
|
||||
#else
|
||||
typedef sparse_storage_element<map_array> data_reference;
|
||||
#endif
|
||||
|
||||
// Construction and destruction
|
||||
BOOST_UBLAS_INLINE
|
||||
map_array (const ALLOC &a = ALLOC()):
|
||||
alloc_(a), capacity_ (0), size_ (0) {
|
||||
data_ = 0;
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
map_array (const map_array &c):
|
||||
alloc_ (c.alloc_), capacity_ (c.size_), size_ (c.size_) {
|
||||
if (capacity_) {
|
||||
data_ = alloc_.allocate (capacity_);
|
||||
std::uninitialized_copy (data_, data_ + capacity_, c.data_);
|
||||
// capacity != size_ requires uninitialized_fill (size_ to capacity_)
|
||||
}
|
||||
else
|
||||
data_ = 0;
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
~map_array () {
|
||||
if (capacity_) {
|
||||
std::for_each (data_, data_ + capacity_, static_destroy);
|
||||
alloc_.deallocate (data_, capacity_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Resizing - implicitly exposses uninitialized (but default constructed) mapped_type
|
||||
BOOST_UBLAS_INLINE
|
||||
void resize (size_type size) {
|
||||
BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ());
|
||||
if (size > capacity_) {
|
||||
const size_type capacity = size << 1;
|
||||
BOOST_UBLAS_CHECK (capacity, internal_logic ());
|
||||
pointer data = alloc_.allocate (capacity);
|
||||
std::uninitialized_copy (data_, data_ + (std::min) (size, size_), data);
|
||||
std::uninitialized_fill (data + (std::min) (size, size_), data + capacity, value_type ());
|
||||
|
||||
if (capacity_) {
|
||||
std::for_each (data_, data_ + capacity_, static_destroy);
|
||||
alloc_.deallocate (data_, capacity_);
|
||||
}
|
||||
capacity_ = capacity;
|
||||
data_ = data;
|
||||
}
|
||||
size_ = size;
|
||||
BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ());
|
||||
}
|
||||
public:
|
||||
|
||||
// Reserving
|
||||
BOOST_UBLAS_INLINE
|
||||
void reserve (size_type capacity) {
|
||||
BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ());
|
||||
// Reduce capacity_ if size_ allows
|
||||
BOOST_UBLAS_CHECK (capacity >= size_, bad_size ());
|
||||
pointer data;
|
||||
if (capacity) {
|
||||
data = alloc_.allocate (capacity);
|
||||
std::uninitialized_copy (data_, data_ + size_, data);
|
||||
std::uninitialized_fill (data + size_, data + capacity, value_type ());
|
||||
}
|
||||
else
|
||||
data = 0;
|
||||
|
||||
if (capacity_) {
|
||||
std::for_each (data_, data_ + capacity_, static_destroy);
|
||||
alloc_.deallocate (data_, capacity_);
|
||||
}
|
||||
capacity_ = capacity;
|
||||
data_ = data;
|
||||
BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ());
|
||||
}
|
||||
|
||||
// Random Access Container
|
||||
BOOST_UBLAS_INLINE
|
||||
size_type size () const {
|
||||
return size_;
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
size_type capacity () const {
|
||||
return capacity_;
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
size_type max_size () const {
|
||||
return 0; //TODO
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
bool empty () const {
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
// Element access
|
||||
BOOST_UBLAS_INLINE
|
||||
data_reference operator [] (key_type i) {
|
||||
#ifndef BOOST_UBLAS_STRICT_MAP_ARRAY
|
||||
pointer it = find (i);
|
||||
if (it == end ())
|
||||
it = insert (end (), value_type (i, mapped_type (0)));
|
||||
BOOST_UBLAS_CHECK (it != end (), internal_logic ());
|
||||
return it->second;
|
||||
#else
|
||||
return data_reference (*this, i);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Assignment
|
||||
BOOST_UBLAS_INLINE
|
||||
map_array &operator = (const map_array &a) {
|
||||
if (this != &a) {
|
||||
resize (a.size_);
|
||||
std::copy (a.data_, a.data_ + a.size_, data_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
map_array &assign_temporary (map_array &a) {
|
||||
swap (a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Swapping
|
||||
BOOST_UBLAS_INLINE
|
||||
void swap (map_array &a) {
|
||||
if (this != &a) {
|
||||
std::swap (capacity_, a.capacity_);
|
||||
std::swap (data_, a.data_);
|
||||
std::swap (size_, a.size_);
|
||||
}
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
friend void swap (map_array &a1, map_array &a2) {
|
||||
a1.swap (a2);
|
||||
}
|
||||
|
||||
// Element insertion and deletion
|
||||
|
||||
// From Back Insertion Sequence concept
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
iterator push_back (iterator it, const value_type &p) {
|
||||
if (size () == 0 || (it = end () - 1)->first < p.first) {
|
||||
resize (size () + 1);
|
||||
*(it = end () - 1) = p;
|
||||
return it;
|
||||
}
|
||||
external_logic ().raise ();
|
||||
return it;
|
||||
}
|
||||
// Form Unique Associative Container concept
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
std::pair<iterator,bool> insert (const value_type &p) {
|
||||
iterator it = detail::lower_bound (begin (), end (), p, detail::less_pair<value_type> ());
|
||||
if (it != end () && it->first == p.first)
|
||||
return std::make_pair (it, false);
|
||||
difference_type n = it - begin ();
|
||||
resize (size () + 1);
|
||||
it = begin () + n; // allow for invalidation
|
||||
std::copy_backward (it, end () - 1, end ());
|
||||
*it = p;
|
||||
return std::make_pair (it, true);
|
||||
}
|
||||
// Form Sorted Associative Container concept
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
iterator insert (iterator /*hint*/, const value_type &p) {
|
||||
return insert (p).first;
|
||||
}
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void erase (iterator it) {
|
||||
BOOST_UBLAS_CHECK (begin () <= it && it < end (), bad_index ());
|
||||
std::copy (it + 1, end (), it);
|
||||
resize (size () - 1);
|
||||
}
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void erase (iterator it1, iterator it2) {
|
||||
if (it1 == it2) return /* nothing to erase */;
|
||||
BOOST_UBLAS_CHECK (begin () <= it1 && it1 < it2 && it2 <= end (), bad_index ());
|
||||
std::copy (it2, end (), it1);
|
||||
resize (size () - (it2 - it1));
|
||||
}
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
void clear () {
|
||||
resize (0);
|
||||
}
|
||||
|
||||
// Element lookup
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
const_iterator find (key_type i) const {
|
||||
const_iterator it (detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair<value_type> ()));
|
||||
if (it == end () || it->first != i)
|
||||
it = end ();
|
||||
return it;
|
||||
}
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
iterator find (key_type i) {
|
||||
iterator it (detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair<value_type> ()));
|
||||
if (it == end () || it->first != i)
|
||||
it = end ();
|
||||
return it;
|
||||
}
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
const_iterator lower_bound (key_type i) const {
|
||||
return detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair<value_type> ());
|
||||
}
|
||||
// BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
|
||||
iterator lower_bound (key_type i) {
|
||||
return detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair<value_type> ());
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator begin () const {
|
||||
return data_;
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator cbegin () const {
|
||||
return begin ();
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator end () const {
|
||||
return data_ + size_;
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator cend () const {
|
||||
return end ();
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
iterator begin () {
|
||||
return data_;
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
iterator end () {
|
||||
return data_ + size_;
|
||||
}
|
||||
|
||||
// Reverse iterators
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator rbegin () const {
|
||||
return const_reverse_iterator (end ());
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator crbegin () const {
|
||||
return rbegin ();
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator rend () const {
|
||||
return const_reverse_iterator (begin ());
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator crend () const {
|
||||
return rend ();
|
||||
}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
reverse_iterator rbegin () {
|
||||
return reverse_iterator (end ());
|
||||
}
|
||||
BOOST_UBLAS_INLINE
|
||||
reverse_iterator rend () {
|
||||
return reverse_iterator (begin ());
|
||||
}
|
||||
|
||||
// Allocator
|
||||
allocator_type get_allocator () {
|
||||
return alloc_;
|
||||
}
|
||||
|
||||
// Serialization
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar, const unsigned int /* file_version */){
|
||||
serialization::collection_size_type s (size_);
|
||||
ar & serialization::make_nvp("size",s);
|
||||
if (Archive::is_loading::value) {
|
||||
resize(s);
|
||||
}
|
||||
ar & serialization::make_array(data_, s);
|
||||
}
|
||||
|
||||
private:
|
||||
// Provide destroy as a non member function
|
||||
BOOST_UBLAS_INLINE
|
||||
static void static_destroy (reference p) {
|
||||
(&p) -> ~value_type ();
|
||||
}
|
||||
ALLOC alloc_;
|
||||
size_type capacity_;
|
||||
pointer data_;
|
||||
size_type size_;
|
||||
};
|
||||
|
||||
|
||||
namespace detail {
|
||||
template<class A, class T>
|
||||
struct map_traits {
|
||||
typedef typename A::mapped_type &reference;
|
||||
};
|
||||
template<class I, class T, class ALLOC>
|
||||
struct map_traits<map_array<I, T, ALLOC>, T > {
|
||||
typedef typename map_array<I, T, ALLOC>::data_reference reference;
|
||||
};
|
||||
|
||||
// reserve helpers for map_array and generic maps
|
||||
// ISSUE should be in map_traits but want to use on all compilers
|
||||
|
||||
template<class M>
|
||||
BOOST_UBLAS_INLINE
|
||||
void map_reserve (M &/* m */, typename M::size_type /* capacity */) {
|
||||
}
|
||||
template<class I, class T, class ALLOC>
|
||||
BOOST_UBLAS_INLINE
|
||||
void map_reserve (map_array<I, T, ALLOC> &m, typename map_array<I, T, ALLOC>::size_type capacity) {
|
||||
m.reserve (capacity);
|
||||
}
|
||||
|
||||
template<class M>
|
||||
struct map_capacity_traits {
|
||||
typedef typename M::size_type type ;
|
||||
type operator() ( M const& m ) const {
|
||||
return m.size ();
|
||||
}
|
||||
} ;
|
||||
|
||||
template<class I, class T, class ALLOC>
|
||||
struct map_capacity_traits< map_array<I, T, ALLOC> > {
|
||||
typedef typename map_array<I, T, ALLOC>::size_type type ;
|
||||
type operator() ( map_array<I, T, ALLOC> const& m ) const {
|
||||
return m.capacity ();
|
||||
}
|
||||
} ;
|
||||
|
||||
template<class M>
|
||||
BOOST_UBLAS_INLINE
|
||||
typename map_capacity_traits<M>::type map_capacity (M const& m) {
|
||||
return map_capacity_traits<M>() ( m );
|
||||
}
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
2309
include/boost/numeric/ublas/symmetric.hpp
Normal file
2309
include/boost/numeric/ublas/symmetric.hpp
Normal file
File diff suppressed because it is too large
Load Diff
37
include/boost/numeric/ublas/tags.hpp
Normal file
37
include/boost/numeric/ublas/tags.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* -*- c++ -*-
|
||||
*
|
||||
* \file tags.hpp
|
||||
*
|
||||
* \brief Tags.
|
||||
*
|
||||
* Copyright (c) 2009, Marco Guazzone
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* \author Marco Guazzone, marco.guazzone@gmail.com
|
||||
*/
|
||||
|
||||
#ifndef BOOST_NUMERIC_UBLAS_TAG_HPP
|
||||
#define BOOST_NUMERIC_UBLAS_TAG_HPP
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas { namespace tag {
|
||||
|
||||
/// \brief Tag for the major dimension.
|
||||
struct major {};
|
||||
|
||||
|
||||
/// \brief Tag for the minor dimension.
|
||||
struct minor {};
|
||||
|
||||
|
||||
/// \brief Tag for the leading dimension.
|
||||
struct leading {};
|
||||
|
||||
}}}} // Namespace boost::numeric::ublas::tag
|
||||
|
||||
|
||||
#endif // BOOST_NUMERIC_UBLAS_TAG_HPP
|
||||
26
include/boost/numeric/ublas/tensor.hpp
Normal file
26
include/boost/numeric/ublas/tensor.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2018-2019
|
||||
// Cem Bassoy
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer and Google in producing this work
|
||||
// which started as a Google Summer of Code project.
|
||||
//
|
||||
|
||||
/// \file tensor.hpp Definition for the class vector and its derivative
|
||||
|
||||
#ifndef BOOST_NUMERIC_UBLAS_TENSOR_HPP
|
||||
#define BOOST_NUMERIC_UBLAS_TENSOR_HPP
|
||||
|
||||
#include "tensor/functions.hpp"
|
||||
#include "tensor/operators_arithmetic.hpp"
|
||||
#include "tensor/operators_comparison.hpp"
|
||||
#include "tensor/extents.hpp"
|
||||
#include "tensor/strides.hpp"
|
||||
#include "tensor/ostream.hpp"
|
||||
#include "tensor/tensor.hpp"
|
||||
|
||||
#endif // BOOST_NUMERIC_UBLAS_TENSOR_HPP
|
||||
345
include/boost/numeric/ublas/tensor/algorithms.hpp
Normal file
345
include/boost/numeric/ublas/tensor/algorithms.hpp
Normal file
@@ -0,0 +1,345 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen, Germany
|
||||
//
|
||||
|
||||
|
||||
#ifndef _BOOST_UBLAS_TENSOR_ALGORITHMS_HPP
|
||||
#define _BOOST_UBLAS_TENSOR_ALGORITHMS_HPP
|
||||
|
||||
|
||||
#include <stdexcept>
|
||||
#include <complex>
|
||||
#include <functional>
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
|
||||
|
||||
|
||||
/** @brief Copies a tensor to another tensor with different layouts
|
||||
*
|
||||
* Implements C[i1,i2,...,ip] = A[i1,i2,...,ip]
|
||||
*
|
||||
* @param[in] p rank of input and output tensor
|
||||
* @param[in] n pointer to the extents of input or output tensor of length p
|
||||
* @param[in] pi pointer to a one-based permutation tuple of length p
|
||||
* @param[out] c pointer to the output tensor
|
||||
* @param[in] wc pointer to the strides of output tensor c
|
||||
* @param[in] a pointer to the input tensor
|
||||
* @param[in] wa pointer to the strides of input tensor a
|
||||
*/
|
||||
template <class PointerOut, class PointerIn, class SizeType>
|
||||
void copy(const SizeType p, SizeType const*const n,
|
||||
PointerOut c, SizeType const*const wc,
|
||||
PointerIn a, SizeType const*const wa)
|
||||
{
|
||||
static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn>::value,
|
||||
"Static error in boost::numeric::ublas::copy: Argument types for pointers are not pointer types.");
|
||||
if( p == 0 )
|
||||
return;
|
||||
|
||||
if(c == nullptr || a == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers.");
|
||||
|
||||
if(wc == nullptr || wa == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers.");
|
||||
|
||||
if(n == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::copy: Pointers shall not be null pointers.");
|
||||
|
||||
|
||||
std::function<void(SizeType r, PointerOut c, PointerIn a)> lambda;
|
||||
|
||||
lambda = [&lambda, n, wc, wa](SizeType r, PointerOut c, PointerIn a)
|
||||
{
|
||||
if(r > 0)
|
||||
for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d)
|
||||
lambda(r-1, c, a );
|
||||
else
|
||||
for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d)
|
||||
*c = *a;
|
||||
};
|
||||
|
||||
lambda( p-1, c, a );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Copies a tensor to another tensor with different layouts applying a unary operation
|
||||
*
|
||||
* Implements C[i1,i2,...,ip] = op ( A[i1,i2,...,ip] )
|
||||
*
|
||||
* @param[in] p rank of input and output tensor
|
||||
* @param[in] n pointer to the extents of input or output tensor of length p
|
||||
* @param[in] pi pointer to a one-based permutation tuple of length p
|
||||
* @param[out] c pointer to the output tensor
|
||||
* @param[in] wc pointer to the strides of output tensor c
|
||||
* @param[in] a pointer to the input tensor
|
||||
* @param[in] wa pointer to the strides of input tensor a
|
||||
* @param[in] op unary operation
|
||||
*/
|
||||
template <class PointerOut, class PointerIn, class SizeType, class UnaryOp>
|
||||
void transform(const SizeType p,
|
||||
SizeType const*const n,
|
||||
PointerOut c, SizeType const*const wc,
|
||||
PointerIn a, SizeType const*const wa,
|
||||
UnaryOp op)
|
||||
{
|
||||
static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn>::value,
|
||||
"Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types.");
|
||||
if( p == 0 )
|
||||
return;
|
||||
|
||||
if(c == nullptr || a == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
|
||||
|
||||
if(wc == nullptr || wa == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
|
||||
|
||||
if(n == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
|
||||
|
||||
|
||||
std::function<void(SizeType r, PointerOut c, PointerIn a)> lambda;
|
||||
|
||||
lambda = [&lambda, n, wc, wa, op](SizeType r, PointerOut c, PointerIn a)
|
||||
{
|
||||
if(r > 0)
|
||||
for(auto d = 0u; d < n[r]; c += wc[r], a += wa[r], ++d)
|
||||
lambda(r-1, c, a);
|
||||
else
|
||||
for(auto d = 0u; d < n[0]; c += wc[0], a += wa[0], ++d)
|
||||
*c = op(*a);
|
||||
};
|
||||
|
||||
lambda( p-1, c, a );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** @brief Performs a reduce operation with all elements of the tensor and an initial value
|
||||
*
|
||||
* Implements k = sum_{i1,..,ip} A[i1,i2,...,ip]
|
||||
*
|
||||
* @param[in] r zero-based recursion level starting with r=p-1
|
||||
* @param[in] n pointer to the extents of input or output tensor
|
||||
* @param[in] a pointer to the first input tensor
|
||||
* @param[in] w pointer to the strides of input tensor a
|
||||
* @param[in] k accumulated value
|
||||
*/
|
||||
template <class PointerIn, class ValueType, class SizeType>
|
||||
ValueType accumulate(SizeType const p, SizeType const*const n,
|
||||
PointerIn a, SizeType const*const w,
|
||||
ValueType k)
|
||||
{
|
||||
static_assert(std::is_pointer<PointerIn>::value,
|
||||
"Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types.");
|
||||
|
||||
if( p == 0 )
|
||||
return k;
|
||||
|
||||
if(a == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
|
||||
|
||||
if(w == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
|
||||
|
||||
if(n == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
|
||||
|
||||
|
||||
std::function<ValueType(SizeType r, PointerIn a, ValueType k)> lambda;
|
||||
|
||||
lambda = [&lambda, n, w](SizeType r, PointerIn a, ValueType k)
|
||||
{
|
||||
if(r > 0u)
|
||||
for(auto d = 0u; d < n[r]; a += w[r], ++d)
|
||||
k = lambda(r-1, a, k);
|
||||
else
|
||||
for(auto d = 0u; d < n[0]; a += w[0], ++d)
|
||||
k += *a;
|
||||
return k;
|
||||
};
|
||||
|
||||
return lambda( p-1, a, k );
|
||||
}
|
||||
|
||||
/** @brief Performs a reduce operation with all elements of the tensor and an initial value
|
||||
*
|
||||
* Implements k = op ( k , A[i1,i2,...,ip] ), for all ir
|
||||
*
|
||||
* @param[in] r zero-based recursion level starting with r=p-1
|
||||
* @param[in] n pointer to the extents of input or output tensor
|
||||
* @param[in] a pointer to the first input tensor
|
||||
* @param[in] w pointer to the strides of input tensor a
|
||||
* @param[in] k accumulated value
|
||||
* @param[in] op binary operation
|
||||
*/
|
||||
|
||||
template <class PointerIn, class ValueType, class SizeType, class BinaryOp>
|
||||
ValueType accumulate(SizeType const p, SizeType const*const n,
|
||||
PointerIn a, SizeType const*const w,
|
||||
ValueType k, BinaryOp op)
|
||||
{
|
||||
static_assert(std::is_pointer<PointerIn>::value,
|
||||
"Static error in boost::numeric::ublas::transform: Argument types for pointers are not pointer types.");
|
||||
|
||||
|
||||
if( p == 0 )
|
||||
return k;
|
||||
|
||||
if(a == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
|
||||
|
||||
if(w == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
|
||||
|
||||
if(n == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::transform: Pointers shall not be null pointers.");
|
||||
|
||||
|
||||
std::function<ValueType(SizeType r, PointerIn a, ValueType k)> lambda;
|
||||
|
||||
lambda = [&lambda, n, w, op](SizeType r, PointerIn a, ValueType k)
|
||||
{
|
||||
if(r > 0u)
|
||||
for(auto d = 0u; d < n[r]; a += w[r], ++d)
|
||||
k = lambda(r-1, a, k);
|
||||
else
|
||||
for(auto d = 0u; d < n[0]; a += w[0], ++d)
|
||||
k = op ( k, *a );
|
||||
return k;
|
||||
};
|
||||
|
||||
return lambda( p-1, a, k );
|
||||
}
|
||||
|
||||
/** @brief Transposes a tensor
|
||||
*
|
||||
* Implements C[tau[i1],tau[i2],...,tau[ip]] = A[i1,i2,...,ip]
|
||||
*
|
||||
* @note is used in function trans
|
||||
*
|
||||
* @param[in] p rank of input and output tensor
|
||||
* @param[in] na pointer to the extents of the input tensor a of length p
|
||||
* @param[in] pi pointer to a one-based permutation tuple of length p
|
||||
* @param[out] c pointer to the output tensor
|
||||
* @param[in] wc pointer to the strides of output tensor c
|
||||
* @param[in] a pointer to the input tensor
|
||||
* @param[in] wa pointer to the strides of input tensor a
|
||||
*/
|
||||
|
||||
template <class PointerOut, class PointerIn, class SizeType>
|
||||
void trans( SizeType const p, SizeType const*const na, SizeType const*const pi,
|
||||
PointerOut c, SizeType const*const wc,
|
||||
PointerIn a, SizeType const*const wa)
|
||||
{
|
||||
|
||||
static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn>::value,
|
||||
"Static error in boost::numeric::ublas::trans: Argument types for pointers are not pointer types.");
|
||||
|
||||
if( p < 2)
|
||||
return;
|
||||
|
||||
if(c == nullptr || a == nullptr)
|
||||
throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
|
||||
|
||||
if(na == nullptr)
|
||||
throw std::runtime_error("Error in boost::numeric::ublas::trans: Pointers shall not be null.");
|
||||
|
||||
if(wc == nullptr || wa == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
|
||||
|
||||
if(na == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
|
||||
|
||||
if(pi == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
|
||||
|
||||
|
||||
std::function<void(SizeType r, PointerOut c, PointerIn a)> lambda;
|
||||
|
||||
lambda = [&lambda, na, wc, wa, pi](SizeType r, PointerOut c, PointerIn a)
|
||||
{
|
||||
if(r > 0)
|
||||
for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d)
|
||||
lambda(r-1, c, a);
|
||||
else
|
||||
for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d)
|
||||
*c = *a;
|
||||
};
|
||||
|
||||
lambda( p-1, c, a );
|
||||
}
|
||||
|
||||
|
||||
/** @brief Transposes a tensor
|
||||
*
|
||||
* Implements C[tau[i1],tau[i2],...,tau[ip]] = A[i1,i2,...,ip]
|
||||
*
|
||||
* @note is used in function trans
|
||||
*
|
||||
* @param[in] p rank of input and output tensor
|
||||
* @param[in] na pointer to the extents of the input tensor a of length p
|
||||
* @param[in] pi pointer to a one-based permutation tuple of length p
|
||||
* @param[out] c pointer to the output tensor
|
||||
* @param[in] wc pointer to the strides of output tensor c
|
||||
* @param[in] a pointer to the input tensor
|
||||
* @param[in] wa pointer to the strides of input tensor a
|
||||
*/
|
||||
|
||||
template <class ValueType, class SizeType>
|
||||
void trans( SizeType const p,
|
||||
SizeType const*const na,
|
||||
SizeType const*const pi,
|
||||
std::complex<ValueType>* c, SizeType const*const wc,
|
||||
std::complex<ValueType>* a, SizeType const*const wa)
|
||||
{
|
||||
if( p < 2)
|
||||
return;
|
||||
|
||||
if(c == nullptr || a == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
|
||||
|
||||
if(wc == nullptr || wa == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
|
||||
|
||||
if(na == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
|
||||
|
||||
if(pi == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::trans: Pointers shall not be null pointers.");
|
||||
|
||||
|
||||
std::function<void(SizeType r, std::complex<ValueType>* c, std::complex<ValueType>* a)> lambda;
|
||||
|
||||
lambda = [&lambda, na, wc, wa, pi](SizeType r, std::complex<ValueType>* c, std::complex<ValueType>* a)
|
||||
{
|
||||
if(r > 0)
|
||||
for(auto d = 0u; d < na[r]; c += wc[pi[r]-1], a += wa[r], ++d)
|
||||
lambda(r-1, c, a);
|
||||
else
|
||||
for(auto d = 0u; d < na[0]; c += wc[pi[0]-1], a += wa[0], ++d)
|
||||
*c = std::conj(*a);
|
||||
};
|
||||
|
||||
lambda( p-1, c, a );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
181
include/boost/numeric/ublas/tensor/expression.hpp
Normal file
181
include/boost/numeric/ublas/tensor/expression.hpp
Normal file
@@ -0,0 +1,181 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen, Germany
|
||||
//
|
||||
|
||||
#ifndef BOOST_UBLAS_TENSOR_EXPRESSIONS_HPP
|
||||
#define BOOST_UBLAS_TENSOR_EXPRESSIONS_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/numeric/ublas/expression_types.hpp>
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
|
||||
|
||||
template<class element_type, class storage_format, class storage_type>
|
||||
class tensor;
|
||||
|
||||
template<class size_type>
|
||||
class basic_extents;
|
||||
|
||||
|
||||
//TODO: put in fwd.hpp
|
||||
struct tensor_tag {};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
namespace detail {
|
||||
|
||||
/** @\brief base class for tensor expressions
|
||||
*
|
||||
* \note implements crtp - no use of virtual function calls
|
||||
*
|
||||
* \tparam T type of the tensor
|
||||
* \tparam E type of the derived expression (crtp)
|
||||
*
|
||||
**/
|
||||
template<class T, class E>
|
||||
struct tensor_expression
|
||||
: public ublas_expression<E>
|
||||
{
|
||||
// static const unsigned complexity = 0;
|
||||
using expression_type = E;
|
||||
using type_category = tensor_tag;
|
||||
using tensor_type = T;
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
auto const& operator()() const { return *static_cast<const expression_type*> (this); }
|
||||
|
||||
protected :
|
||||
explicit tensor_expression() = default;
|
||||
tensor_expression(const tensor_expression&) = delete;
|
||||
tensor_expression& operator=(const tensor_expression&) = delete;
|
||||
};
|
||||
|
||||
|
||||
template<class T, class EL, class ER, class OP>
|
||||
struct binary_tensor_expression
|
||||
: public tensor_expression <T, binary_tensor_expression<T,EL,ER,OP>>
|
||||
{
|
||||
using self_type = binary_tensor_expression<T,EL,ER,OP>;
|
||||
using tensor_type = T;
|
||||
using binary_operation = OP;
|
||||
using expression_type_left = EL;
|
||||
using expression_type_right = ER;
|
||||
using derived_type = tensor_expression <tensor_type,self_type>;
|
||||
|
||||
using size_type = typename tensor_type::size_type;
|
||||
|
||||
explicit binary_tensor_expression(expression_type_left const& l, expression_type_right const& r, binary_operation o)
|
||||
: el(l) , er(r) , op(o) {}
|
||||
binary_tensor_expression() = delete;
|
||||
binary_tensor_expression(const binary_tensor_expression& l) = delete;
|
||||
binary_tensor_expression(binary_tensor_expression&& l)
|
||||
: el(l.el), er(l.er), op(l.op) {}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
decltype(auto) operator()(size_type i) const { return op(el(i), er(i)); }
|
||||
|
||||
expression_type_left const& el;
|
||||
expression_type_right const& er;
|
||||
binary_operation op;
|
||||
};
|
||||
|
||||
/// @brief helper function to simply instantiation of lambda proxy class
|
||||
template<class T, class EL, class ER, class OP>
|
||||
auto make_binary_tensor_expression( tensor_expression<T,EL> const& el, tensor_expression<T,ER> const& er, OP op)
|
||||
{
|
||||
return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ;
|
||||
}
|
||||
|
||||
template<class T, class EL, class ER, class OP>
|
||||
auto make_binary_tensor_expression( matrix_expression<EL> const& el, tensor_expression<T,ER> const& er, OP op)
|
||||
{
|
||||
return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ;
|
||||
}
|
||||
|
||||
template<class T, class EL, class ER, class OP>
|
||||
auto make_binary_tensor_expression( tensor_expression<T,EL> const& el, matrix_expression<ER> const& er, OP op)
|
||||
{
|
||||
return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ;
|
||||
}
|
||||
|
||||
template<class T, class EL, class ER, class OP>
|
||||
auto make_binary_tensor_expression( vector_expression<EL> const& el, tensor_expression<T,ER> const& er, OP op)
|
||||
{
|
||||
return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ;
|
||||
}
|
||||
|
||||
template<class T, class EL, class ER, class OP>
|
||||
auto make_binary_tensor_expression( tensor_expression<T,EL> const& el, vector_expression<ER> const& er, OP op)
|
||||
{
|
||||
return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T, class E, class OP>
|
||||
struct unary_tensor_expression
|
||||
: public tensor_expression <T, unary_tensor_expression<T,E,OP>>
|
||||
{
|
||||
|
||||
using self_type = unary_tensor_expression<T,E,OP>;
|
||||
using tensor_type = T;
|
||||
using expression_type = E;
|
||||
|
||||
using derived_type = tensor_expression <T, unary_tensor_expression<T,E,OP>>;
|
||||
|
||||
using size_type = typename tensor_type::size_type;
|
||||
|
||||
explicit unary_tensor_expression(E const& ee, OP o) : e(ee) , op(o) {}
|
||||
unary_tensor_expression() = delete;
|
||||
unary_tensor_expression(const unary_tensor_expression& l) = delete;
|
||||
unary_tensor_expression(unary_tensor_expression&& l)
|
||||
: e(l.e), op(op.l) {}
|
||||
|
||||
BOOST_UBLAS_INLINE
|
||||
decltype(auto) operator()(size_type i) const { return op(e(i)); }
|
||||
|
||||
E const& e;
|
||||
OP op;
|
||||
};
|
||||
|
||||
// \brief helper function to simply instantiation of lambda proxy class
|
||||
template<class T, class E, class OP>
|
||||
auto make_unary_tensor_expression( tensor_expression<T,E> const& e, OP op)
|
||||
{
|
||||
return unary_tensor_expression<T,E,OP>( e() , op);
|
||||
}
|
||||
|
||||
template<class T, class E, class OP>
|
||||
auto make_unary_tensor_expression( matrix_expression<E> const& e, OP op)
|
||||
{
|
||||
return unary_tensor_expression<T,E,OP>( e() , op);
|
||||
}
|
||||
|
||||
template<class T, class E, class OP>
|
||||
auto make_unary_tensor_expression( vector_expression<E> const& e, OP op)
|
||||
{
|
||||
return unary_tensor_expression<T,E,OP>( e() , op);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
288
include/boost/numeric/ublas/tensor/expression_evaluation.hpp
Normal file
288
include/boost/numeric/ublas/tensor/expression_evaluation.hpp
Normal file
@@ -0,0 +1,288 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen, Germany
|
||||
//
|
||||
|
||||
#ifndef _BOOST_UBLAS_TENSOR_EXPRESSIONS_EVALUATION_HPP_
|
||||
#define _BOOST_UBLAS_TENSOR_EXPRESSIONS_EVALUATION_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
namespace boost::numeric::ublas {
|
||||
|
||||
template<class element_type, class storage_format, class storage_type>
|
||||
class tensor;
|
||||
|
||||
template<class size_type>
|
||||
class basic_extents;
|
||||
|
||||
}
|
||||
|
||||
namespace boost::numeric::ublas::detail {
|
||||
|
||||
template<class T, class D>
|
||||
struct tensor_expression;
|
||||
|
||||
template<class T, class EL, class ER, class OP>
|
||||
struct binary_tensor_expression;
|
||||
|
||||
template<class T, class E, class OP>
|
||||
struct unary_tensor_expression;
|
||||
|
||||
}
|
||||
|
||||
namespace boost::numeric::ublas::detail {
|
||||
|
||||
template<class T, class E>
|
||||
struct has_tensor_types
|
||||
{ static constexpr bool value = false; };
|
||||
|
||||
template<class T>
|
||||
struct has_tensor_types<T,T>
|
||||
{ static constexpr bool value = true; };
|
||||
|
||||
template<class T, class D>
|
||||
struct has_tensor_types<T, tensor_expression<T,D>>
|
||||
{ static constexpr bool value = std::is_same<T,D>::value || has_tensor_types<T,D>::value; };
|
||||
|
||||
|
||||
template<class T, class EL, class ER, class OP>
|
||||
struct has_tensor_types<T, binary_tensor_expression<T,EL,ER,OP>>
|
||||
{ static constexpr bool value = std::is_same<T,EL>::value || std::is_same<T,ER>::value || has_tensor_types<T,EL>::value || has_tensor_types<T,ER>::value; };
|
||||
|
||||
template<class T, class E, class OP>
|
||||
struct has_tensor_types<T, unary_tensor_expression<T,E,OP>>
|
||||
{ static constexpr bool value = std::is_same<T,E>::value || has_tensor_types<T,E>::value; };
|
||||
|
||||
} // namespace boost::numeric::ublas::detail
|
||||
|
||||
|
||||
namespace boost::numeric::ublas::detail {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Retrieves extents of the tensor
|
||||
*
|
||||
*/
|
||||
template<class T, class F, class A>
|
||||
auto retrieve_extents(tensor<T,F,A> const& t)
|
||||
{
|
||||
return t.extents();
|
||||
}
|
||||
|
||||
/** @brief Retrieves extents of the tensor expression
|
||||
*
|
||||
* @note tensor expression must be a binary tree with at least one tensor type
|
||||
*
|
||||
* @returns extents of the child expression if it is a tensor or extents of one child of its child.
|
||||
*/
|
||||
template<class T, class D>
|
||||
auto retrieve_extents(tensor_expression<T,D> const& expr)
|
||||
{
|
||||
static_assert(detail::has_tensor_types<T,tensor_expression<T,D>>::value,
|
||||
"Error in boost::numeric::ublas::detail::retrieve_extents: Expression to evaluate should contain tensors.");
|
||||
|
||||
auto const& cast_expr = static_cast<D const&>(expr);
|
||||
|
||||
if constexpr ( std::is_same<T,D>::value )
|
||||
return cast_expr.extents();
|
||||
else
|
||||
return retrieve_extents(cast_expr);
|
||||
}
|
||||
|
||||
/** @brief Retrieves extents of the binary tensor expression
|
||||
*
|
||||
* @note tensor expression must be a binary tree with at least one tensor type
|
||||
*
|
||||
* @returns extents of the (left and if necessary then right) child expression if it is a tensor or extents of a child of its (left and if necessary then right) child.
|
||||
*/
|
||||
template<class T, class EL, class ER, class OP>
|
||||
auto retrieve_extents(binary_tensor_expression<T,EL,ER,OP> const& expr)
|
||||
{
|
||||
static_assert(detail::has_tensor_types<T,binary_tensor_expression<T,EL,ER,OP>>::value,
|
||||
"Error in boost::numeric::ublas::detail::retrieve_extents: Expression to evaluate should contain tensors.");
|
||||
|
||||
if constexpr ( std::is_same<T,EL>::value )
|
||||
return expr.el.extents();
|
||||
|
||||
if constexpr ( std::is_same<T,ER>::value )
|
||||
return expr.er.extents();
|
||||
|
||||
else if constexpr ( detail::has_tensor_types<T,EL>::value )
|
||||
return retrieve_extents(expr.el);
|
||||
|
||||
else if constexpr ( detail::has_tensor_types<T,ER>::value )
|
||||
return retrieve_extents(expr.er);
|
||||
}
|
||||
|
||||
/** @brief Retrieves extents of the binary tensor expression
|
||||
*
|
||||
* @note tensor expression must be a binary tree with at least one tensor type
|
||||
*
|
||||
* @returns extents of the child expression if it is a tensor or extents of a child of its child.
|
||||
*/
|
||||
template<class T, class E, class OP>
|
||||
auto retrieve_extents(unary_tensor_expression<T,E,OP> const& expr)
|
||||
{
|
||||
|
||||
static_assert(detail::has_tensor_types<T,unary_tensor_expression<T,E,OP>>::value,
|
||||
"Error in boost::numeric::ublas::detail::retrieve_extents: Expression to evaluate should contain tensors.");
|
||||
|
||||
if constexpr ( std::is_same<T,E>::value )
|
||||
return expr.e.extents();
|
||||
|
||||
else if constexpr ( detail::has_tensor_types<T,E>::value )
|
||||
return retrieve_extents(expr.e);
|
||||
}
|
||||
|
||||
} // namespace boost::numeric::ublas::detail
|
||||
|
||||
|
||||
///////////////
|
||||
|
||||
namespace boost::numeric::ublas::detail {
|
||||
|
||||
template<class T, class F, class A, class S>
|
||||
auto all_extents_equal(tensor<T,F,A> const& t, basic_extents<S> const& extents)
|
||||
{
|
||||
return extents == t.extents();
|
||||
}
|
||||
|
||||
template<class T, class D, class S>
|
||||
auto all_extents_equal(tensor_expression<T,D> const& expr, basic_extents<S> const& extents)
|
||||
{
|
||||
static_assert(detail::has_tensor_types<T,tensor_expression<T,D>>::value,
|
||||
"Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors.");
|
||||
auto const& cast_expr = static_cast<D const&>(expr);
|
||||
|
||||
|
||||
if constexpr ( std::is_same<T,D>::value )
|
||||
if( extents != cast_expr.extents() )
|
||||
return false;
|
||||
|
||||
if constexpr ( detail::has_tensor_types<T,D>::value )
|
||||
if ( !all_extents_equal(cast_expr, extents))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
template<class T, class EL, class ER, class OP, class S>
|
||||
auto all_extents_equal(binary_tensor_expression<T,EL,ER,OP> const& expr, basic_extents<S> const& extents)
|
||||
{
|
||||
static_assert(detail::has_tensor_types<T,binary_tensor_expression<T,EL,ER,OP>>::value,
|
||||
"Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors.");
|
||||
|
||||
if constexpr ( std::is_same<T,EL>::value )
|
||||
if(extents != expr.el.extents())
|
||||
return false;
|
||||
|
||||
if constexpr ( std::is_same<T,ER>::value )
|
||||
if(extents != expr.er.extents())
|
||||
return false;
|
||||
|
||||
if constexpr ( detail::has_tensor_types<T,EL>::value )
|
||||
if(!all_extents_equal(expr.el, extents))
|
||||
return false;
|
||||
|
||||
if constexpr ( detail::has_tensor_types<T,ER>::value )
|
||||
if(!all_extents_equal(expr.er, extents))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class E, class OP, class S>
|
||||
auto all_extents_equal(unary_tensor_expression<T,E,OP> const& expr, basic_extents<S> const& extents)
|
||||
{
|
||||
|
||||
static_assert(detail::has_tensor_types<T,unary_tensor_expression<T,E,OP>>::value,
|
||||
"Error in boost::numeric::ublas::detail::all_extents_equal: Expression to evaluate should contain tensors.");
|
||||
|
||||
if constexpr ( std::is_same<T,E>::value )
|
||||
if(extents != expr.e.extents())
|
||||
return false;
|
||||
|
||||
if constexpr ( detail::has_tensor_types<T,E>::value )
|
||||
if(!all_extents_equal(expr.e, extents))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace boost::numeric::ublas::detail
|
||||
|
||||
|
||||
namespace boost::numeric::ublas::detail {
|
||||
|
||||
|
||||
/** @brief Evaluates expression for a tensor
|
||||
*
|
||||
* Assigns the results of the expression to the tensor.
|
||||
*
|
||||
* \note Checks if shape of the tensor matches those of all tensors within the expression.
|
||||
*/
|
||||
template<class tensor_type, class derived_type>
|
||||
void eval(tensor_type& lhs, tensor_expression<tensor_type, derived_type> const& expr)
|
||||
{
|
||||
if constexpr (detail::has_tensor_types<tensor_type, tensor_expression<tensor_type,derived_type> >::value )
|
||||
if(!detail::all_extents_equal(expr, lhs.extents() ))
|
||||
throw std::runtime_error("Error in boost::numeric::ublas::tensor: expression contains tensors with different shapes.");
|
||||
|
||||
#pragma omp parallel for
|
||||
for(auto i = 0u; i < lhs.size(); ++i)
|
||||
lhs(i) = expr()(i);
|
||||
}
|
||||
|
||||
/** @brief Evaluates expression for a tensor
|
||||
*
|
||||
* Applies a unary function to the results of the expressions before the assignment.
|
||||
* Usually applied needed for unary operators such as A += C;
|
||||
*
|
||||
* \note Checks if shape of the tensor matches those of all tensors within the expression.
|
||||
*/
|
||||
template<class tensor_type, class derived_type, class unary_fn>
|
||||
void eval(tensor_type& lhs, tensor_expression<tensor_type, derived_type> const& expr, unary_fn const fn)
|
||||
{
|
||||
|
||||
if constexpr (detail::has_tensor_types< tensor_type, tensor_expression<tensor_type,derived_type> >::value )
|
||||
if(!detail::all_extents_equal( expr, lhs.extents() ))
|
||||
throw std::runtime_error("Error in boost::numeric::ublas::tensor: expression contains tensors with different shapes.");
|
||||
|
||||
#pragma omp parallel for
|
||||
for(auto i = 0u; i < lhs.size(); ++i)
|
||||
fn(lhs(i), expr()(i));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Evaluates expression for a tensor
|
||||
*
|
||||
* Applies a unary function to the results of the expressions before the assignment.
|
||||
* Usually applied needed for unary operators such as A += C;
|
||||
*
|
||||
* \note Checks if shape of the tensor matches those of all tensors within the expression.
|
||||
*/
|
||||
template<class tensor_type, class unary_fn>
|
||||
void eval(tensor_type& lhs, unary_fn const fn)
|
||||
{
|
||||
#pragma omp parallel for
|
||||
for(auto i = 0u; i < lhs.size(); ++i)
|
||||
fn(lhs(i));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
335
include/boost/numeric/ublas/tensor/extents.hpp
Normal file
335
include/boost/numeric/ublas/tensor/extents.hpp
Normal file
@@ -0,0 +1,335 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen, Germany
|
||||
//
|
||||
|
||||
|
||||
#ifndef BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_HPP
|
||||
#define BOOST_NUMERIC_UBLAS_TENSOR_EXTENTS_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
|
||||
|
||||
/** @brief Template class for storing tensor extents with runtime variable size.
|
||||
*
|
||||
* Proxy template class of std::vector<int_type>.
|
||||
*
|
||||
*/
|
||||
template<class int_type>
|
||||
class basic_extents
|
||||
{
|
||||
static_assert( std::numeric_limits<typename std::vector<int_type>::value_type>::is_integer, "Static error in basic_layout: type must be of type integer.");
|
||||
static_assert(!std::numeric_limits<typename std::vector<int_type>::value_type>::is_signed, "Static error in basic_layout: type must be of type unsigned integer.");
|
||||
|
||||
public:
|
||||
using base_type = std::vector<int_type>;
|
||||
using value_type = typename base_type::value_type;
|
||||
using const_reference = typename base_type::const_reference;
|
||||
using reference = typename base_type::reference;
|
||||
using size_type = typename base_type::size_type;
|
||||
using const_pointer = typename base_type::const_pointer;
|
||||
using const_iterator = typename base_type::const_iterator;
|
||||
|
||||
|
||||
/** @brief Default constructs basic_extents
|
||||
*
|
||||
* @code auto ex = basic_extents<unsigned>{};
|
||||
*/
|
||||
constexpr explicit basic_extents()
|
||||
: _base{}
|
||||
{
|
||||
}
|
||||
|
||||
/** @brief Copy constructs basic_extents from a one-dimensional container
|
||||
*
|
||||
* @code auto ex = basic_extents<unsigned>( std::vector<unsigned>(3u,3u) );
|
||||
*
|
||||
* @note checks if size > 1 and all elements > 0
|
||||
*
|
||||
* @param b one-dimensional std::vector<int_type> container
|
||||
*/
|
||||
explicit basic_extents(base_type const& b)
|
||||
: _base(b)
|
||||
{
|
||||
if (!this->valid()){
|
||||
throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements.");
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Move constructs basic_extents from a one-dimensional container
|
||||
*
|
||||
* @code auto ex = basic_extents<unsigned>( std::vector<unsigned>(3u,3u) );
|
||||
*
|
||||
* @note checks if size > 1 and all elements > 0
|
||||
*
|
||||
* @param b one-dimensional container of type std::vector<int_type>
|
||||
*/
|
||||
explicit basic_extents(base_type && b)
|
||||
: _base(std::move(b))
|
||||
{
|
||||
if (!this->valid()){
|
||||
throw std::length_error("Error in basic_extents::basic_extents() : shape tuple is not a valid permutation: has zero elements.");
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Constructs basic_extents from an initializer list
|
||||
*
|
||||
* @code auto ex = basic_extents<unsigned>{3,2,4};
|
||||
*
|
||||
* @note checks if size > 1 and all elements > 0
|
||||
*
|
||||
* @param l one-dimensional list of type std::initializer<int_type>
|
||||
*/
|
||||
basic_extents(std::initializer_list<value_type> l)
|
||||
: basic_extents( base_type(std::move(l)) )
|
||||
{
|
||||
}
|
||||
|
||||
/** @brief Constructs basic_extents from a range specified by two iterators
|
||||
*
|
||||
* @code auto ex = basic_extents<unsigned>(a.begin(), a.end());
|
||||
*
|
||||
* @note checks if size > 1 and all elements > 0
|
||||
*
|
||||
* @param first iterator pointing to the first element
|
||||
* @param last iterator pointing to the next position after the last element
|
||||
*/
|
||||
basic_extents(const_iterator first, const_iterator last)
|
||||
: basic_extents ( base_type( first,last ) )
|
||||
{
|
||||
}
|
||||
|
||||
/** @brief Copy constructs basic_extents */
|
||||
basic_extents(basic_extents const& l )
|
||||
: _base(l._base)
|
||||
{
|
||||
}
|
||||
|
||||
/** @brief Move constructs basic_extents */
|
||||
basic_extents(basic_extents && l ) noexcept
|
||||
: _base(std::move(l._base))
|
||||
{
|
||||
}
|
||||
|
||||
~basic_extents() = default;
|
||||
|
||||
basic_extents& operator=(basic_extents other) noexcept
|
||||
{
|
||||
swap (*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend void swap(basic_extents& lhs, basic_extents& rhs) {
|
||||
std::swap(lhs._base , rhs._base );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Returns true if this has a scalar shape
|
||||
*
|
||||
* @returns true if (1,1,[1,...,1])
|
||||
*/
|
||||
bool is_scalar() const
|
||||
{
|
||||
return
|
||||
_base.size() != 0 &&
|
||||
std::all_of(_base.begin(), _base.end(),
|
||||
[](const_reference a){ return a == 1;});
|
||||
}
|
||||
|
||||
/** @brief Returns true if this has a vector shape
|
||||
*
|
||||
* @returns true if (1,n,[1,...,1]) or (n,1,[1,...,1]) with n > 1
|
||||
*/
|
||||
bool is_vector() const
|
||||
{
|
||||
if(_base.size() == 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(_base.size() == 1){
|
||||
return _base.at(0) > 1;
|
||||
}
|
||||
|
||||
auto greater_one = [](const_reference a){ return a > 1;};
|
||||
auto equal_one = [](const_reference a){ return a == 1;};
|
||||
|
||||
return
|
||||
std::any_of(_base.begin(), _base.begin()+2, greater_one) &&
|
||||
std::any_of(_base.begin(), _base.begin()+2, equal_one ) &&
|
||||
std::all_of(_base.begin()+2, _base.end(), equal_one);
|
||||
}
|
||||
|
||||
/** @brief Returns true if this has a matrix shape
|
||||
*
|
||||
* @returns true if (m,n,[1,...,1]) with m > 1 and n > 1
|
||||
*/
|
||||
bool is_matrix() const
|
||||
{
|
||||
if(_base.size() < 2){
|
||||
return false;
|
||||
}
|
||||
|
||||
auto greater_one = [](const_reference a){ return a > 1;};
|
||||
auto equal_one = [](const_reference a){ return a == 1;};
|
||||
|
||||
return
|
||||
std::all_of(_base.begin(), _base.begin()+2, greater_one) &&
|
||||
std::all_of(_base.begin()+2, _base.end(), equal_one );
|
||||
}
|
||||
|
||||
/** @brief Returns true if this is has a tensor shape
|
||||
*
|
||||
* @returns true if !empty() && !is_scalar() && !is_vector() && !is_matrix()
|
||||
*/
|
||||
bool is_tensor() const
|
||||
{
|
||||
if(_base.size() < 3){
|
||||
return false;
|
||||
}
|
||||
|
||||
auto greater_one = [](const_reference a){ return a > 1;};
|
||||
|
||||
return std::any_of(_base.begin()+2, _base.end(), greater_one);
|
||||
}
|
||||
|
||||
const_pointer data() const
|
||||
{
|
||||
return this->_base.data();
|
||||
}
|
||||
|
||||
const_reference operator[] (size_type p) const
|
||||
{
|
||||
return this->_base[p];
|
||||
}
|
||||
|
||||
const_reference at (size_type p) const
|
||||
{
|
||||
return this->_base.at(p);
|
||||
}
|
||||
|
||||
reference operator[] (size_type p)
|
||||
{
|
||||
return this->_base[p];
|
||||
}
|
||||
|
||||
reference at (size_type p)
|
||||
{
|
||||
return this->_base.at(p);
|
||||
}
|
||||
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return this->_base.empty();
|
||||
}
|
||||
|
||||
size_type size() const
|
||||
{
|
||||
return this->_base.size();
|
||||
}
|
||||
|
||||
/** @brief Returns true if size > 1 and all elements > 0 */
|
||||
bool valid() const
|
||||
{
|
||||
return
|
||||
this->size() > 1 &&
|
||||
std::none_of(_base.begin(), _base.end(),
|
||||
[](const_reference a){ return a == value_type(0); });
|
||||
}
|
||||
|
||||
/** @brief Returns the number of elements a tensor holds with this */
|
||||
size_type product() const
|
||||
{
|
||||
if(_base.empty()){
|
||||
return 0;
|
||||
}
|
||||
|
||||
return std::accumulate(_base.begin(), _base.end(), 1ul, std::multiplies<>());
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** @brief Eliminates singleton dimensions when size > 2
|
||||
*
|
||||
* squeeze { 1,1} -> { 1,1}
|
||||
* squeeze { 2,1} -> { 2,1}
|
||||
* squeeze { 1,2} -> { 1,2}
|
||||
*
|
||||
* squeeze {1,2,3} -> { 2,3}
|
||||
* squeeze {2,1,3} -> { 2,3}
|
||||
* squeeze {1,3,1} -> { 3,1}
|
||||
*
|
||||
*/
|
||||
basic_extents squeeze() const
|
||||
{
|
||||
if(this->size() <= 2){
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto new_extent = basic_extents{};
|
||||
auto insert_iter = std::back_insert_iterator<typename basic_extents::base_type>(new_extent._base);
|
||||
std::remove_copy(this->_base.begin(), this->_base.end(), insert_iter ,value_type{1});
|
||||
return new_extent;
|
||||
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
this->_base.clear();
|
||||
}
|
||||
|
||||
bool operator == (basic_extents const& b) const
|
||||
{
|
||||
return _base == b._base;
|
||||
}
|
||||
|
||||
bool operator != (basic_extents const& b) const
|
||||
{
|
||||
return !( _base == b._base );
|
||||
}
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return _base.begin();
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return _base.end();
|
||||
}
|
||||
|
||||
base_type const& base() const { return _base; }
|
||||
|
||||
private:
|
||||
|
||||
base_type _base;
|
||||
|
||||
};
|
||||
|
||||
using shape = basic_extents<std::size_t>;
|
||||
|
||||
} // namespace ublas
|
||||
} // namespace numeric
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
558
include/boost/numeric/ublas/tensor/functions.hpp
Normal file
558
include/boost/numeric/ublas/tensor/functions.hpp
Normal file
@@ -0,0 +1,558 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen, Germany
|
||||
//
|
||||
|
||||
|
||||
#ifndef BOOST_UBLAS_TENSOR_FUNCTIONS_HPP
|
||||
#define BOOST_UBLAS_TENSOR_FUNCTIONS_HPP
|
||||
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
|
||||
#include "multiplication.hpp"
|
||||
#include "algorithms.hpp"
|
||||
#include "expression.hpp"
|
||||
#include "expression_evaluation.hpp"
|
||||
#include "storage_traits.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
|
||||
template<class Value, class Format, class Allocator>
|
||||
class tensor;
|
||||
|
||||
template<class Value, class Format, class Allocator>
|
||||
class matrix;
|
||||
|
||||
template<class Value, class Allocator>
|
||||
class vector;
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Computes the m-mode tensor-times-vector product
|
||||
*
|
||||
* Implements C[i1,...,im-1,im+1,...,ip] = A[i1,i2,...,ip] * b[im]
|
||||
*
|
||||
* @note calls ublas::ttv
|
||||
*
|
||||
* @param[in] m contraction dimension with 1 <= m <= p
|
||||
* @param[in] a tensor object A with order p
|
||||
* @param[in] b vector object B
|
||||
*
|
||||
* @returns tensor object C with order p-1, the same storage format and allocator type as A
|
||||
*/
|
||||
template<class V, class F, class A1, class A2>
|
||||
auto prod(tensor<V,F,A1> const& a, vector<V,A2> const& b, const std::size_t m)
|
||||
{
|
||||
|
||||
using tensor_type = tensor<V,F,A1>;
|
||||
using extents_type = typename tensor_type::extents_type;
|
||||
using ebase_type = typename extents_type::base_type;
|
||||
using value_type = typename tensor_type::value_type;
|
||||
using size_type = typename extents_type::value_type;
|
||||
|
||||
auto const p = std::size_t(a.rank());
|
||||
|
||||
if( m == 0)
|
||||
throw std::length_error("error in boost::numeric::ublas::prod(ttv): contraction mode must be greater than zero.");
|
||||
|
||||
if( p < m )
|
||||
throw std::length_error("error in boost::numeric::ublas::prod(ttv): rank of tensor must be greater than or equal to the modus.");
|
||||
|
||||
if( p == 0)
|
||||
throw std::length_error("error in boost::numeric::ublas::prod(ttv): rank of tensor must be greater than zero.");
|
||||
|
||||
if( a.empty() )
|
||||
throw std::length_error("error in boost::numeric::ublas::prod(ttv): first argument tensor should not be empty.");
|
||||
|
||||
if( b.size() == 0)
|
||||
throw std::length_error("error in boost::numeric::ublas::prod(ttv): second argument vector should not be empty.");
|
||||
|
||||
|
||||
auto nc = ebase_type(std::max(p-1, size_type(2)) , size_type(1));
|
||||
auto nb = ebase_type{b.size(),1};
|
||||
|
||||
|
||||
for(auto i = 0u, j = 0u; i < p; ++i)
|
||||
if(i != m-1)
|
||||
nc[j++] = a.extents().at(i);
|
||||
|
||||
auto c = tensor_type(extents_type(nc),value_type{});
|
||||
|
||||
auto bb = &(b(0));
|
||||
|
||||
ttv(m, p,
|
||||
c.data(), c.extents().data(), c.strides().data(),
|
||||
a.data(), a.extents().data(), a.strides().data(),
|
||||
bb, nb.data(), nb.data());
|
||||
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Computes the m-mode tensor-times-matrix product
|
||||
*
|
||||
* Implements C[i1,...,im-1,j,im+1,...,ip] = A[i1,i2,...,ip] * B[j,im]
|
||||
*
|
||||
* @note calls ublas::ttm
|
||||
*
|
||||
* @param[in] a tensor object A with order p
|
||||
* @param[in] b vector object B
|
||||
* @param[in] m contraction dimension with 1 <= m <= p
|
||||
*
|
||||
* @returns tensor object C with order p, the same storage format and allocator type as A
|
||||
*/
|
||||
template<class V, class F, class A1, class A2>
|
||||
auto prod(tensor<V,F,A1> const& a, matrix<V,F,A2> const& b, const std::size_t m)
|
||||
{
|
||||
|
||||
using tensor_type = tensor<V,F,A1>;
|
||||
using extents_type = typename tensor_type::extents_type;
|
||||
using strides_type = typename tensor_type::strides_type;
|
||||
using value_type = typename tensor_type::value_type;
|
||||
|
||||
|
||||
auto const p = a.rank();
|
||||
|
||||
if( m == 0)
|
||||
throw std::length_error("error in boost::numeric::ublas::prod(ttm): contraction mode must be greater than zero.");
|
||||
|
||||
if( p < m || m > a.extents().size())
|
||||
throw std::length_error("error in boost::numeric::ublas::prod(ttm): rank of the tensor must be greater equal the modus.");
|
||||
|
||||
if( p == 0)
|
||||
throw std::length_error("error in boost::numeric::ublas::prod(ttm): rank of the tensor must be greater than zero.");
|
||||
|
||||
if( a.empty() )
|
||||
throw std::length_error("error in boost::numeric::ublas::prod(ttm): first argument tensor should not be empty.");
|
||||
|
||||
if( b.size1()*b.size2() == 0)
|
||||
throw std::length_error("error in boost::numeric::ublas::prod(ttm): second argument matrix should not be empty.");
|
||||
|
||||
|
||||
auto nc = a.extents().base();
|
||||
auto nb = extents_type {b.size1(),b.size2()};
|
||||
auto wb = strides_type (nb);
|
||||
|
||||
nc[m-1] = nb[0];
|
||||
|
||||
auto c = tensor_type(extents_type(nc),value_type{});
|
||||
|
||||
auto bb = &(b(0,0));
|
||||
|
||||
ttm(m, p,
|
||||
c.data(), c.extents().data(), c.strides().data(),
|
||||
a.data(), a.extents().data(), a.strides().data(),
|
||||
bb, nb.data(), wb.data());
|
||||
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Computes the q-mode tensor-times-tensor product
|
||||
*
|
||||
* Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] )
|
||||
*
|
||||
* @note calls ublas::ttt
|
||||
*
|
||||
* na[phia[x]] = nb[phib[x]] for 1 <= x <= q
|
||||
*
|
||||
* @param[in] phia one-based permutation tuple of length q for the first input tensor a
|
||||
* @param[in] phib one-based permutation tuple of length q for the second input tensor b
|
||||
* @param[in] a left-hand side tensor with order r+q
|
||||
* @param[in] b right-hand side tensor with order s+q
|
||||
* @result tensor with order r+s
|
||||
*/
|
||||
template<class V, class F, class A1, class A2>
|
||||
auto prod(tensor<V,F,A1> const& a, tensor<V,F,A2> const& b,
|
||||
std::vector<std::size_t> const& phia, std::vector<std::size_t> const& phib)
|
||||
{
|
||||
|
||||
using tensor_type = tensor<V,F,A1>;
|
||||
using extents_type = typename tensor_type::extents_type;
|
||||
using value_type = typename tensor_type::value_type;
|
||||
using size_type = typename extents_type::value_type;
|
||||
|
||||
auto const pa = a.rank();
|
||||
auto const pb = b.rank();
|
||||
|
||||
auto const q = size_type(phia.size());
|
||||
|
||||
if(pa == 0ul)
|
||||
throw std::runtime_error("error in ublas::prod: order of left-hand side tensor must be greater than 0.");
|
||||
if(pb == 0ul)
|
||||
throw std::runtime_error("error in ublas::prod: order of right-hand side tensor must be greater than 0.");
|
||||
if(pa < q)
|
||||
throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the left-hand side tensor.");
|
||||
if(pb < q)
|
||||
throw std::runtime_error("error in ublas::prod: number of contraction dimensions cannot be greater than the order of the right-hand side tensor.");
|
||||
|
||||
if(q != phib.size())
|
||||
throw std::runtime_error("error in ublas::prod: permutation tuples must have the same length.");
|
||||
|
||||
if(pa < phia.size())
|
||||
throw std::runtime_error("error in ublas::prod: permutation tuple for the left-hand side tensor cannot be greater than the corresponding order.");
|
||||
if(pb < phib.size())
|
||||
throw std::runtime_error("error in ublas::prod: permutation tuple for the right-hand side tensor cannot be greater than the corresponding order.");
|
||||
|
||||
|
||||
auto const& na = a.extents();
|
||||
auto const& nb = b.extents();
|
||||
|
||||
for(auto i = 0ul; i < q; ++i)
|
||||
if( na.at(phia.at(i)-1) != nb.at(phib.at(i)-1))
|
||||
throw std::runtime_error("error in ublas::prod: permutations of the extents are not correct.");
|
||||
|
||||
auto const r = pa - q;
|
||||
auto const s = pb - q;
|
||||
|
||||
|
||||
std::vector<std::size_t> phia1(pa), phib1(pb);
|
||||
std::iota(phia1.begin(), phia1.end(), 1ul);
|
||||
std::iota(phib1.begin(), phib1.end(), 1ul);
|
||||
|
||||
std::vector<std::size_t> nc( std::max ( r+s , size_type(2) ), size_type(1) );
|
||||
|
||||
for(auto i = 0ul; i < phia.size(); ++i)
|
||||
* std::remove(phia1.begin(), phia1.end(), phia.at(i)) = phia.at(i);
|
||||
|
||||
//phia1.erase( std::remove(phia1.begin(), phia1.end(), phia.at(i)), phia1.end() ) ;
|
||||
|
||||
assert(phia1.size() == pa);
|
||||
|
||||
for(auto i = 0ul; i < r; ++i)
|
||||
nc[ i ] = na[ phia1[ i ] - 1 ];
|
||||
|
||||
for(auto i = 0ul; i < phib.size(); ++i)
|
||||
* std::remove(phib1.begin(), phib1.end(), phib.at(i)) = phib.at(i) ;
|
||||
//phib1.erase( std::remove(phib1.begin(), phib1.end(), phia.at(i)), phib1.end() ) ;
|
||||
|
||||
assert(phib1.size() == pb);
|
||||
|
||||
for(auto i = 0ul; i < s; ++i)
|
||||
nc[ r + i ] = nb[ phib1[ i ] - 1 ];
|
||||
|
||||
// std::copy( phib.begin(), phib.end(), phib1.end() );
|
||||
|
||||
assert( phia1.size() == pa );
|
||||
assert( phib1.size() == pb );
|
||||
|
||||
auto c = tensor_type(extents_type(nc), value_type{});
|
||||
|
||||
ttt(pa, pb, q,
|
||||
phia1.data(), phib1.data(),
|
||||
c.data(), c.extents().data(), c.strides().data(),
|
||||
a.data(), a.extents().data(), a.strides().data(),
|
||||
b.data(), b.extents().data(), b.strides().data());
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
//template<class V, class F, class A1, class A2, std::size_t N, std::size_t M>
|
||||
//auto operator*( tensor_index<V,F,A1,N> const& lhs, tensor_index<V,F,A2,M> const& rhs)
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Computes the q-mode tensor-times-tensor product
|
||||
*
|
||||
* Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] )
|
||||
*
|
||||
* @note calls ublas::ttt
|
||||
*
|
||||
* na[phi[x]] = nb[phi[x]] for 1 <= x <= q
|
||||
*
|
||||
* @param[in] phi one-based permutation tuple of length q for bot input tensors
|
||||
* @param[in] a left-hand side tensor with order r+q
|
||||
* @param[in] b right-hand side tensor with order s+q
|
||||
* @result tensor with order r+s
|
||||
*/
|
||||
template<class V, class F, class A1, class A2>
|
||||
auto prod(tensor<V,F,A1> const& a, tensor<V,F,A2> const& b,
|
||||
std::vector<std::size_t> const& phi)
|
||||
{
|
||||
return prod(a, b, phi, phi);
|
||||
}
|
||||
|
||||
|
||||
/** @brief Computes the inner product of two tensors
|
||||
*
|
||||
* Implements c = sum(A[i1,i2,...,ip] * B[i1,i2,...,jp])
|
||||
*
|
||||
* @note calls inner function
|
||||
*
|
||||
* @param[in] a tensor object A
|
||||
* @param[in] b tensor object B
|
||||
*
|
||||
* @returns a value type.
|
||||
*/
|
||||
template<class V, class F, class A1, class A2>
|
||||
auto inner_prod(tensor<V,F,A1> const& a, tensor<V,F,A2> const& b)
|
||||
{
|
||||
using value_type = typename tensor<V,F,A1>::value_type;
|
||||
|
||||
if( a.rank() != b.rank() )
|
||||
throw std::length_error("error in boost::numeric::ublas::inner_prod: Rank of both tensors must be the same.");
|
||||
|
||||
if( a.empty() || b.empty())
|
||||
throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensors should not be empty.");
|
||||
|
||||
if( a.extents() != b.extents())
|
||||
throw std::length_error("error in boost::numeric::ublas::inner_prod: Tensor extents should be the same.");
|
||||
|
||||
return inner(a.rank(), a.extents().data(),
|
||||
a.data(), a.strides().data(),
|
||||
b.data(), b.strides().data(), value_type{0});
|
||||
}
|
||||
|
||||
/** @brief Computes the outer product of two tensors
|
||||
*
|
||||
* Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq]
|
||||
*
|
||||
* @note calls outer function
|
||||
*
|
||||
* @param[in] a tensor object A
|
||||
* @param[in] b tensor object B
|
||||
*
|
||||
* @returns tensor object C with the same storage format F and allocator type A1
|
||||
*/
|
||||
template<class V, class F, class A1, class A2>
|
||||
auto outer_prod(tensor<V,F,A1> const& a, tensor<V,F,A2> const& b)
|
||||
{
|
||||
using tensor_type = tensor<V,F,A1>;
|
||||
using extents_type = typename tensor_type::extents_type;
|
||||
|
||||
if( a.empty() || b.empty() )
|
||||
throw std::runtime_error("error in boost::numeric::ublas::outer_prod: tensors should not be empty.");
|
||||
|
||||
auto nc = typename extents_type::base_type(a.rank() + b.rank());
|
||||
for(auto i = 0u; i < a.rank(); ++i)
|
||||
nc.at(i) = a.extents().at(i);
|
||||
|
||||
for(auto i = 0u; i < b.rank(); ++i)
|
||||
nc.at(a.rank()+i) = b.extents().at(i);
|
||||
|
||||
auto c = tensor_type(extents_type(nc));
|
||||
|
||||
outer(c.data(), c.rank(), c.extents().data(), c.strides().data(),
|
||||
a.data(), a.rank(), a.extents().data(), a.strides().data(),
|
||||
b.data(), b.rank(), b.extents().data(), b.strides().data());
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Transposes a tensor according to a permutation tuple
|
||||
*
|
||||
* Implements C[tau[i1],tau[i2]...,tau[ip]] = A[i1,i2,...,ip]
|
||||
*
|
||||
* @note calls trans function
|
||||
*
|
||||
* @param[in] a tensor object of rank p
|
||||
* @param[in] tau one-based permutation tuple of length p
|
||||
* @returns a transposed tensor object with the same storage format F and allocator type A
|
||||
*/
|
||||
template<class V, class F, class A>
|
||||
auto trans(tensor<V,F,A> const& a, std::vector<std::size_t> const& tau)
|
||||
{
|
||||
using tensor_type = tensor<V,F,A>;
|
||||
using extents_type = typename tensor_type::extents_type;
|
||||
// using strides_type = typename tensor_type::strides_type;
|
||||
|
||||
if( a.empty() )
|
||||
return tensor<V,F,A>{};
|
||||
|
||||
auto const p = a.rank();
|
||||
auto const& na = a.extents();
|
||||
|
||||
auto nc = typename extents_type::base_type (p);
|
||||
for(auto i = 0u; i < p; ++i)
|
||||
nc.at(tau.at(i)-1) = na.at(i);
|
||||
|
||||
// auto wc = strides_type(extents_type(nc));
|
||||
|
||||
auto c = tensor_type(extents_type(nc));
|
||||
|
||||
|
||||
trans( a.rank(), a.extents().data(), tau.data(),
|
||||
c.data(), c.strides().data(),
|
||||
a.data(), a.strides().data());
|
||||
|
||||
// auto wc_pi = typename strides_type::base_type (p);
|
||||
// for(auto i = 0u; i < p; ++i)
|
||||
// wc_pi.at(tau.at(i)-1) = c.strides().at(i);
|
||||
|
||||
|
||||
//copy(a.rank(),
|
||||
// a.extents().data(),
|
||||
// c.data(), wc_pi.data(),
|
||||
// a.data(), a.strides().data() );
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/** @brief Computes the frobenius norm of a tensor expression
|
||||
*
|
||||
* @note evaluates the tensor expression and calls the accumulate function
|
||||
*
|
||||
*
|
||||
* Implements the two-norm with
|
||||
* k = sqrt( sum_(i1,...,ip) A(i1,...,ip)^2 )
|
||||
*
|
||||
* @param[in] a tensor object of rank p
|
||||
* @returns the frobenius norm of the tensor
|
||||
*/
|
||||
//template<class V, class F, class A>
|
||||
//auto norm(tensor<V,F,A> const& a)
|
||||
template<class T, class D>
|
||||
auto norm(detail::tensor_expression<T,D> const& expr)
|
||||
{
|
||||
|
||||
using tensor_type = typename detail::tensor_expression<T,D>::tensor_type;
|
||||
using value_type = typename tensor_type::value_type;
|
||||
|
||||
auto a = tensor_type( expr );
|
||||
|
||||
if( a.empty() )
|
||||
throw std::runtime_error("error in boost::numeric::ublas::norm: tensors should not be empty.");
|
||||
|
||||
return std::sqrt( accumulate( a.order(), a.extents().data(), a.data(), a.strides().data(), value_type{},
|
||||
[](auto const& l, auto const& r){ return l + r*r; } ) ) ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Extract the real component of tensor elements within a tensor expression
|
||||
*
|
||||
* @param[in] lhs tensor expression
|
||||
* @returns unary tensor expression
|
||||
*/
|
||||
template<class T, class D>
|
||||
auto real(detail::tensor_expression<T,D> const& expr) {
|
||||
return detail::make_unary_tensor_expression<T> (expr(), [] (auto const& l) { return std::real( l ); } );
|
||||
}
|
||||
|
||||
/** @brief Extract the real component of tensor elements within a tensor expression
|
||||
*
|
||||
* @param[in] lhs tensor expression
|
||||
* @returns unary tensor expression
|
||||
*/
|
||||
template<class V, class F, class A, class D>
|
||||
auto real(detail::tensor_expression<tensor<std::complex<V>,F,A>,D> const& expr)
|
||||
{
|
||||
using tensor_complex_type = tensor<std::complex<V>,F,A>;
|
||||
using tensor_type = tensor<V,F,typename storage_traits<A>::template rebind<V>>;
|
||||
|
||||
if( detail::retrieve_extents( expr ).empty() )
|
||||
throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty.");
|
||||
|
||||
auto a = tensor_complex_type( expr );
|
||||
auto c = tensor_type( a.extents() );
|
||||
|
||||
std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::real(l) ; } );
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Extract the imaginary component of tensor elements within a tensor expression
|
||||
*
|
||||
* @param[in] lhs tensor expression
|
||||
* @returns unary tensor expression
|
||||
*/
|
||||
template<class T, class D>
|
||||
auto imag(detail::tensor_expression<T,D> const& lhs) {
|
||||
return detail::make_unary_tensor_expression<T> (lhs(), [] (auto const& l) { return std::imag( l ); } );
|
||||
}
|
||||
|
||||
|
||||
/** @brief Extract the imag component of tensor elements within a tensor expression
|
||||
*
|
||||
* @param[in] lhs tensor expression
|
||||
* @returns unary tensor expression
|
||||
*/
|
||||
template<class V, class A, class F, class D>
|
||||
auto imag(detail::tensor_expression<tensor<std::complex<V>,F,A>,D> const& expr)
|
||||
{
|
||||
using tensor_complex_type = tensor<std::complex<V>,F,A>;
|
||||
using tensor_type = tensor<V,F,typename storage_traits<A>::template rebind<V>>;
|
||||
|
||||
if( detail::retrieve_extents( expr ).empty() )
|
||||
throw std::runtime_error("error in boost::numeric::ublas::real: tensors should not be empty.");
|
||||
|
||||
auto a = tensor_complex_type( expr );
|
||||
auto c = tensor_type( a.extents() );
|
||||
|
||||
std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::imag(l) ; } );
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/** @brief Computes the complex conjugate component of tensor elements within a tensor expression
|
||||
*
|
||||
* @param[in] expr tensor expression
|
||||
* @returns complex tensor
|
||||
*/
|
||||
template<class T, class D>
|
||||
auto conj(detail::tensor_expression<T,D> const& expr)
|
||||
{
|
||||
using tensor_type = T;
|
||||
using value_type = typename tensor_type::value_type;
|
||||
using layout_type = typename tensor_type::layout_type;
|
||||
using array_type = typename tensor_type::array_type;
|
||||
|
||||
using new_value_type = std::complex<value_type>;
|
||||
using new_array_type = typename storage_traits<array_type>::template rebind<new_value_type>;
|
||||
|
||||
using tensor_complex_type = tensor<new_value_type,layout_type, new_array_type>;
|
||||
|
||||
if( detail::retrieve_extents( expr ).empty() )
|
||||
throw std::runtime_error("error in boost::numeric::ublas::conj: tensors should not be empty.");
|
||||
|
||||
auto a = tensor_type( expr );
|
||||
auto c = tensor_complex_type( a.extents() );
|
||||
|
||||
std::transform( a.begin(), a.end(), c.begin(), [](auto const& l){ return std::conj(l) ; } );
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Computes the complex conjugate component of tensor elements within a tensor expression
|
||||
*
|
||||
* @param[in] lhs tensor expression
|
||||
* @returns unary tensor expression
|
||||
*/
|
||||
template<class V, class A, class F, class D>
|
||||
auto conj(detail::tensor_expression<tensor<std::complex<V>,F,A>,D> const& expr)
|
||||
{
|
||||
return detail::make_unary_tensor_expression<tensor<std::complex<V>,F,A>> (expr(), [] (auto const& l) { return std::conj( l ); } );
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
89
include/boost/numeric/ublas/tensor/index.hpp
Normal file
89
include/boost/numeric/ublas/tensor/index.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen, Germany
|
||||
//
|
||||
|
||||
#ifndef BOOST_UBLAS_TENSOR_INDEX_HPP
|
||||
#define BOOST_UBLAS_TENSOR_INDEX_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
namespace index {
|
||||
|
||||
/** @brief Proxy template class for the einstein summation notation
|
||||
*
|
||||
* @note index::index_type<K> for 0<=K<=16 is used in tensor::operator()
|
||||
*
|
||||
* @tparam I wrapped integer
|
||||
*/
|
||||
template<std::size_t I>
|
||||
struct index_type
|
||||
{
|
||||
static constexpr std::size_t value = I;
|
||||
|
||||
constexpr bool operator == (std::size_t other) const { return value == other; }
|
||||
constexpr bool operator != (std::size_t other) const { return value != other; }
|
||||
|
||||
template <std::size_t K>
|
||||
constexpr bool operator == (index_type<K> /*other*/) const { return I==K; }
|
||||
template <std::size_t K>
|
||||
constexpr bool operator != (index_type<K> /*other*/) const { return I!=K; }
|
||||
|
||||
constexpr bool operator == (index_type /*other*/) const { return true; }
|
||||
constexpr bool operator != (index_type /*other*/) const { return false; }
|
||||
|
||||
constexpr std::size_t operator()() const { return I; }
|
||||
};
|
||||
|
||||
/** @brief Proxy classes for the einstein summation notation
|
||||
*
|
||||
* @note index::_a ... index::_z is used in tensor::operator()
|
||||
*/
|
||||
|
||||
static constexpr index_type< 0> _;
|
||||
static constexpr index_type< 1> _a;
|
||||
static constexpr index_type< 2> _b;
|
||||
static constexpr index_type< 3> _c;
|
||||
static constexpr index_type< 4> _d;
|
||||
static constexpr index_type< 5> _e;
|
||||
static constexpr index_type< 6> _f;
|
||||
static constexpr index_type< 7> _g;
|
||||
static constexpr index_type< 8> _h;
|
||||
static constexpr index_type< 9> _i;
|
||||
static constexpr index_type<10> _j;
|
||||
static constexpr index_type<11> _k;
|
||||
static constexpr index_type<12> _l;
|
||||
static constexpr index_type<13> _m;
|
||||
static constexpr index_type<14> _n;
|
||||
static constexpr index_type<15> _o;
|
||||
static constexpr index_type<16> _p;
|
||||
static constexpr index_type<17> _q;
|
||||
static constexpr index_type<18> _r;
|
||||
static constexpr index_type<19> _s;
|
||||
static constexpr index_type<20> _t;
|
||||
static constexpr index_type<21> _u;
|
||||
static constexpr index_type<22> _v;
|
||||
static constexpr index_type<23> _w;
|
||||
static constexpr index_type<24> _x;
|
||||
static constexpr index_type<25> _y;
|
||||
static constexpr index_type<26> _z;
|
||||
|
||||
} // namespace indices
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _BOOST_UBLAS_TENSOR_INDEX_HPP_
|
||||
110
include/boost/numeric/ublas/tensor/multi_index.hpp
Normal file
110
include/boost/numeric/ublas/tensor/multi_index.hpp
Normal file
@@ -0,0 +1,110 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen, Germany
|
||||
//
|
||||
|
||||
#ifndef BOOST_UBLAS_TENSOR_MULTI_INDEX_HPP
|
||||
#define BOOST_UBLAS_TENSOR_MULTI_INDEX_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "multi_index_utility.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
namespace index {
|
||||
|
||||
template<std::size_t I>
|
||||
struct index_type;
|
||||
|
||||
} // namespace indices
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
|
||||
/** @brief Proxy class for the einstein summation notation
|
||||
*
|
||||
* Denotes an array of index_type types ::_a for 0<=K<=16 is used in tensor::operator()
|
||||
*/
|
||||
template<std::size_t N>
|
||||
class multi_index
|
||||
{
|
||||
public:
|
||||
multi_index() = delete;
|
||||
|
||||
template<std::size_t I, class ... indexes>
|
||||
constexpr multi_index(index::index_type<I> const& i, indexes ... is )
|
||||
: _base{i(), is()... }
|
||||
{
|
||||
static_assert( sizeof...(is)+1 == N,
|
||||
"Static assert in boost::numeric::ublas::multi_index: number of constructor arguments is not equal to the template parameter." );
|
||||
|
||||
static_assert( valid_multi_index<std::tuple<index::index_type<I>, indexes ...> >::value,
|
||||
"Static assert in boost::numeric::ublas::multi_index: indexes occur twice in multi-index." );
|
||||
}
|
||||
|
||||
multi_index(multi_index const& other)
|
||||
: _base(other._base)
|
||||
{
|
||||
}
|
||||
|
||||
multi_index& operator=(multi_index const& other)
|
||||
{
|
||||
this->_base = other._base;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~multi_index() = default;
|
||||
|
||||
auto const& base() const { return _base; }
|
||||
constexpr auto size() const { return _base.size(); }
|
||||
constexpr auto at(std::size_t i) const { return _base.at(i); }
|
||||
constexpr auto operator[](std::size_t i) const { return _base.at(i); }
|
||||
|
||||
private:
|
||||
std::array<std::size_t, N> _base;
|
||||
};
|
||||
|
||||
template<std::size_t K, std::size_t N>
|
||||
constexpr auto get(multi_index<N> const& m) { return std::get<K>(m.base()); }
|
||||
|
||||
template<std::size_t M, std::size_t N>
|
||||
auto array_to_vector(multi_index<M> const& lhs, multi_index<N> const& rhs)
|
||||
{
|
||||
using vtype = std::vector<std::size_t>;
|
||||
|
||||
auto pair_of_vector = std::make_pair( vtype {}, vtype{} );
|
||||
|
||||
for(auto i = 0u; i < N; ++i)
|
||||
for(auto j = 0u; j < M; ++j)
|
||||
if ( lhs.at(i) == rhs.at(j) && lhs.at(i) != boost::numeric::ublas::index::_())
|
||||
pair_of_vector.first .push_back( i+1 ),
|
||||
pair_of_vector.second.push_back( j+1 );
|
||||
|
||||
return pair_of_vector;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace ublas
|
||||
} // namespace numeric
|
||||
} // namespace boost
|
||||
|
||||
#endif // MULTI_INDEX_HPP
|
||||
364
include/boost/numeric/ublas/tensor/multi_index_utility.hpp
Normal file
364
include/boost/numeric/ublas/tensor/multi_index_utility.hpp
Normal file
@@ -0,0 +1,364 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen, Germany
|
||||
//
|
||||
|
||||
#ifndef BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP
|
||||
#define BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP
|
||||
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
namespace detail {
|
||||
|
||||
|
||||
template<class ... index_types>
|
||||
struct has_index_impl;
|
||||
|
||||
template<class itype_left, class itype_right>
|
||||
struct has_index_impl<itype_left, itype_right>
|
||||
{
|
||||
static constexpr bool value = itype_left::value == itype_right::value;
|
||||
};
|
||||
|
||||
template<class itype_left>
|
||||
struct has_index_impl <itype_left, std::tuple<> >
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template<class itype_left, class itype_right>
|
||||
struct has_index_impl <itype_left, std::tuple<itype_right> >
|
||||
{
|
||||
static constexpr bool value = has_index_impl<itype_left,itype_right>::value;
|
||||
};
|
||||
|
||||
template<class itype_left, class itype_right, class ... index_types>
|
||||
struct has_index_impl <itype_left, std::tuple<itype_right, index_types...> >
|
||||
{
|
||||
using next_type = has_index_impl<itype_left, std::tuple<index_types...>>;
|
||||
static constexpr bool value = has_index_impl<itype_left,itype_right>::value || next_type::value;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
|
||||
|
||||
/** @brief has_index is true if index occurs once or more in a multi-index
|
||||
*
|
||||
* @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
|
||||
*
|
||||
* @code auto has_index_value = has_index<index_type<1>, std::tuple<index_type<2>,index_type<1>> >::value; @endcode
|
||||
*
|
||||
* @tparam index_type type of index
|
||||
* @tparam tuple_type type of std::tuple representing a multi-index
|
||||
*/
|
||||
template<class index_type, class tuple_type>
|
||||
struct has_index
|
||||
{
|
||||
static constexpr bool value = detail::has_index_impl<std::decay_t<index_type>,std::decay_t<tuple_type>>::value;
|
||||
};
|
||||
|
||||
} // namespace ublas
|
||||
} // namespace numeric
|
||||
} // namespace boost
|
||||
|
||||
////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
namespace detail {
|
||||
|
||||
|
||||
template<class ... index_types>
|
||||
struct valid_multi_index_impl;
|
||||
|
||||
template<>
|
||||
struct valid_multi_index_impl<std::tuple<>>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template<class itype>
|
||||
struct valid_multi_index_impl<std::tuple<itype>>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
|
||||
template<class itype, class ... index_types>
|
||||
struct valid_multi_index_impl<std::tuple<itype,index_types...>>
|
||||
{
|
||||
using ttype = std::tuple<index_types...>;
|
||||
using has_index_type = has_index<itype, ttype>;
|
||||
|
||||
static constexpr bool is_index_zero = itype::value==0ul;
|
||||
static constexpr bool has_index_value = has_index_type::value && !is_index_zero;
|
||||
static constexpr bool value = !has_index_value && valid_multi_index_impl<ttype>::value;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/** @brief valid_multi_index is true if indexes occur only once in a multi-index
|
||||
*
|
||||
* @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
|
||||
*
|
||||
* @code auto valid = valid_multi_index< std::tuple<index_type<2>,index_type<1>> >::value;
|
||||
* @endcode
|
||||
*
|
||||
* @tparam tuple_type type of std::tuple representing a multi-index
|
||||
*/
|
||||
template<class tupe_type>
|
||||
struct valid_multi_index
|
||||
{
|
||||
static constexpr bool value = detail::valid_multi_index_impl<std::decay_t<tupe_type>>::value;
|
||||
};
|
||||
|
||||
} // namespace ublas
|
||||
} // namespace numeric
|
||||
} // namespace boost
|
||||
|
||||
////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
namespace detail {
|
||||
|
||||
template<class ... index_types >
|
||||
struct number_equal_indexes_impl;
|
||||
|
||||
template<class ... itypes_right >
|
||||
struct number_equal_indexes_impl < std::tuple<>, std::tuple<itypes_right...>>
|
||||
{
|
||||
static constexpr unsigned value = 0;
|
||||
};
|
||||
|
||||
template<class itype, class ... itypes_left, class ... itypes_right>
|
||||
struct number_equal_indexes_impl < std::tuple<itype,itypes_left...>, std::tuple<itypes_right...>>
|
||||
{
|
||||
using tuple_right = std::tuple<itypes_right...>;
|
||||
using has_index_type = has_index<itype, tuple_right>;
|
||||
|
||||
static constexpr bool is_index_zero = itype::value==0ul;
|
||||
static constexpr bool has_index_value = has_index_type::value && !is_index_zero;
|
||||
|
||||
using next_type = number_equal_indexes_impl< std::tuple<itypes_left...>, tuple_right >;
|
||||
static constexpr unsigned v = has_index_value ? 1 : 0;
|
||||
static constexpr unsigned value = v + next_type::value;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
|
||||
/** @brief number_equal_indexes contains the number of equal indexes of two multi-indexes
|
||||
*
|
||||
* @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
|
||||
*
|
||||
*
|
||||
* @code auto num = number_equal_indexes<
|
||||
* std::tuple<index_type<2>,index_type<1>>,
|
||||
* std::tuple<index_type<1>,index_type<3>> >::value;
|
||||
* @endcode
|
||||
*
|
||||
* @tparam tuple_type_left type of left std::tuple representing a multi-index
|
||||
* @tparam tuple_type_right type of right std::tuple representing a multi-index
|
||||
*/
|
||||
template<class tuple_left, class tuple_right>
|
||||
struct number_equal_indexes
|
||||
{
|
||||
static constexpr unsigned value =
|
||||
detail::number_equal_indexes_impl< std::decay_t<tuple_left>, std::decay_t<tuple_right>>::value;
|
||||
};
|
||||
|
||||
} // namespace ublas
|
||||
} // namespace numeric
|
||||
} // namespace boost
|
||||
|
||||
|
||||
////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
namespace detail {
|
||||
|
||||
|
||||
template<std::size_t r, std::size_t m, class itype, class ttype>
|
||||
struct index_position_impl
|
||||
{
|
||||
static constexpr auto is_same = std::is_same< std::decay_t<itype>, std::decay_t<std::tuple_element_t<r,ttype>> >::value;
|
||||
static constexpr auto value = is_same ? r : index_position_impl<r+1,m,itype,ttype>::value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<std::size_t m, class itype, class ttype>
|
||||
struct index_position_impl < m, m, itype, ttype>
|
||||
{
|
||||
static constexpr auto value = std::tuple_size<ttype>::value;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
|
||||
/** @brief index_position contains the zero-based index position of an index type within a multi-index
|
||||
*
|
||||
* @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
|
||||
*
|
||||
* @code auto num = index_position<
|
||||
* index_type<1>,
|
||||
* std::tuple<index_type<2>,index_type<1>> >::value;
|
||||
* @endcode
|
||||
*
|
||||
* @returns value returns 0 and N-1 if index_type is found, N otherwise where N is tuple_size_v<tuple_type>.
|
||||
*
|
||||
* @tparam index_type type of index
|
||||
* @tparam tuple_type type of std::tuple that is searched for index
|
||||
*/
|
||||
template<class index_type, class tuple_type>
|
||||
struct index_position
|
||||
{
|
||||
static constexpr auto value = detail::index_position_impl<0ul,std::tuple_size<tuple_type>::value,std::decay_t<index_type>,std::decay_t<tuple_type>>::value;
|
||||
};
|
||||
|
||||
} // namespace ublas
|
||||
} // namespace numeric
|
||||
} // namespace boost
|
||||
|
||||
////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
namespace detail {
|
||||
|
||||
template<std::size_t r, std::size_t m>
|
||||
struct index_position_pairs_impl
|
||||
{
|
||||
template<class array_type, class tuple_left, class tuple_right>
|
||||
static constexpr void run(array_type& out, tuple_left const& lhs, tuple_right const& rhs, std::size_t p)
|
||||
{
|
||||
using index_type = std::tuple_element_t<r-1,tuple_left>;
|
||||
using has_index_type = has_index<index_type, tuple_right>;
|
||||
using get_index_type = index_position<index_type,tuple_right>;
|
||||
using next_type = index_position_pairs_impl<r+1,m>;
|
||||
if constexpr ( has_index_type::value && index_type::value != 0)
|
||||
out[p++] = std::make_pair(r-1,get_index_type::value);
|
||||
next_type::run( out, lhs, rhs, p );
|
||||
}
|
||||
};
|
||||
|
||||
template<std::size_t m>
|
||||
struct index_position_pairs_impl<m,m>
|
||||
{
|
||||
template<class array_type, class tuple_left, class tuple_right>
|
||||
static constexpr void run(array_type& out, tuple_left const& , tuple_right const& , std::size_t p)
|
||||
{
|
||||
using index_type = std::tuple_element_t<m-1,tuple_left>;
|
||||
using has_index_type = has_index<index_type, tuple_right>;
|
||||
using get_index_type = index_position<index_type, tuple_right>;
|
||||
if constexpr ( has_index_type::value && index_type::value != 0 )
|
||||
out[p] = std::make_pair(m-1,get_index_type::value);
|
||||
}
|
||||
};
|
||||
|
||||
template<std::size_t r>
|
||||
struct index_position_pairs_impl<r,0>
|
||||
{
|
||||
template<class array_type, class tuple_left, class tuple_right>
|
||||
static constexpr void run(array_type&, tuple_left const& , tuple_right const& , std::size_t)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
/** @brief index_position_pairs returns zero-based index positions of matching indexes of two multi-indexes
|
||||
*
|
||||
* @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
|
||||
*
|
||||
* @code auto pairs = index_position_pairs(std::make_tuple(_a,_b), std::make_tuple(_b,_c));
|
||||
* @endcode
|
||||
*
|
||||
* @returns a std::array instance containing index position pairs of type std::pair<std::size_t, std::size_t>.
|
||||
*
|
||||
* @param lhs left std::tuple instance representing a multi-index
|
||||
* @param rhs right std::tuple instance representing a multi-index
|
||||
*/
|
||||
template<class tuple_left, class tuple_right>
|
||||
auto index_position_pairs(tuple_left const& lhs, tuple_right const& rhs)
|
||||
{
|
||||
using pair_type = std::pair<std::size_t,std::size_t>;
|
||||
constexpr auto m = std::tuple_size<tuple_left >::value;
|
||||
constexpr auto p = number_equal_indexes<tuple_left, tuple_right>::value;
|
||||
auto array = std::array<pair_type,p>{};
|
||||
detail::index_position_pairs_impl<1,m>::run(array, lhs, rhs,0);
|
||||
return array;
|
||||
}
|
||||
|
||||
} // namespace ublas
|
||||
} // namespace numeric
|
||||
} // namespace boost
|
||||
|
||||
////////////////////////////
|
||||
////////////////////////////
|
||||
////////////////////////////
|
||||
////////////////////////////
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
namespace detail {
|
||||
|
||||
template<class array_type, std::size_t ... R>
|
||||
constexpr auto array_to_vector_impl( array_type const& array, std::index_sequence<R...> )
|
||||
{
|
||||
return std::make_pair(
|
||||
std::vector<std::size_t>{std::get<0>( std::get<R>(array) )+1 ...} ,
|
||||
std::vector<std::size_t>{std::get<1>( std::get<R>(array) )+1 ...} );
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
/** @brief array_to_vector converts a std::array of zero-based index position pairs into two std::vector of one-based index positions
|
||||
*
|
||||
* @code auto two_vectors = array_to_vector(std::make_array ( std::make_pair(1,2), std::make_pair(3,4) ) ) ;
|
||||
* @endcode
|
||||
*
|
||||
* @returns two std::vector of one-based index positions
|
||||
*
|
||||
* @param array std::array of zero-based index position pairs
|
||||
*/
|
||||
template<class pair_type, std::size_t N>
|
||||
constexpr auto array_to_vector( std::array<pair_type,N> const& array)
|
||||
{
|
||||
constexpr auto sequence = std::make_index_sequence<N>{};
|
||||
return detail::array_to_vector_impl( array, sequence );
|
||||
}
|
||||
|
||||
|
||||
} // namespace ublas
|
||||
} // namespace numeric
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // _BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP_
|
||||
945
include/boost/numeric/ublas/tensor/multiplication.hpp
Normal file
945
include/boost/numeric/ublas/tensor/multiplication.hpp
Normal file
@@ -0,0 +1,945 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen, Germany
|
||||
//
|
||||
|
||||
|
||||
#ifndef BOOST_UBLAS_TENSOR_MULTIPLICATION
|
||||
#define BOOST_UBLAS_TENSOR_MULTIPLICATION
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
namespace detail {
|
||||
namespace recursive {
|
||||
|
||||
|
||||
/** @brief Computes the tensor-times-tensor product for q contraction modes
|
||||
*
|
||||
* Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] )
|
||||
*
|
||||
* nc[x] = na[phia[x] ] for 1 <= x <= r
|
||||
* nc[r+x] = nb[phib[x] ] for 1 <= x <= s
|
||||
* na[phia[r+x]] = nb[phib[s+x]] for 1 <= x <= q
|
||||
*
|
||||
* @note is used in function ttt
|
||||
*
|
||||
* @param k zero-based recursion level starting with 0
|
||||
* @param r number of non-contraction indices of A
|
||||
* @param s number of non-contraction indices of B
|
||||
* @param q number of contraction indices with q > 0
|
||||
* @param phia pointer to the permutation tuple of length q+r for A
|
||||
* @param phib pointer to the permutation tuple of length q+s for B
|
||||
* @param c pointer to the output tensor C with rank(A)=r+s
|
||||
* @param nc pointer to the extents of tensor C
|
||||
* @param wc pointer to the strides of tensor C
|
||||
* @param a pointer to the first input tensor with rank(A)=r+q
|
||||
* @param na pointer to the extents of the first input tensor A
|
||||
* @param wa pointer to the strides of the first input tensor A
|
||||
* @param b pointer to the second input tensor B with rank(B)=s+q
|
||||
* @param nb pointer to the extents of the second input tensor B
|
||||
* @param wb pointer to the strides of the second input tensor B
|
||||
*/
|
||||
|
||||
template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
|
||||
void ttt(SizeType const k,
|
||||
SizeType const r, SizeType const s, SizeType const q,
|
||||
SizeType const*const phia, SizeType const*const phib,
|
||||
PointerOut c, SizeType const*const nc, SizeType const*const wc,
|
||||
PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
PointerIn2 b, SizeType const*const nb, SizeType const*const wb)
|
||||
{
|
||||
if(k < r)
|
||||
{
|
||||
assert(nc[k] == na[phia[k]-1]);
|
||||
for(size_t ic = 0u; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic)
|
||||
ttt(k+1, r, s, q, phia,phib, c, nc, wc, a, na, wa, b, nb, wb);
|
||||
}
|
||||
else if(k < r+s)
|
||||
{
|
||||
assert(nc[k] == nb[phib[k-r]-1]);
|
||||
for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic)
|
||||
ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb);
|
||||
}
|
||||
else if(k < r+s+q-1)
|
||||
{
|
||||
assert(na[phia[k-s]-1] == nb[phib[k-r]-1]);
|
||||
for(size_t ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia)
|
||||
ttt(k+1, r, s, q, phia, phib, c, nc, wc, a, na, wa, b, nb, wb);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(na[phia[k-s]-1] == nb[phib[k-r]-1]);
|
||||
for(size_t ia = 0u; ia < na[phia[k-s]-1]; a += wa[phia[k-s]-1], b += wb[phib[k-r]-1], ++ia)
|
||||
*c += *a * *b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Computes the tensor-times-tensor product for q contraction modes
|
||||
*
|
||||
* Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] )
|
||||
*
|
||||
* @note no permutation tuple is used
|
||||
*
|
||||
* nc[x] = na[x ] for 1 <= x <= r
|
||||
* nc[r+x] = nb[x ] for 1 <= x <= s
|
||||
* na[r+x] = nb[s+x] for 1 <= x <= q
|
||||
*
|
||||
* @note is used in function ttt
|
||||
*
|
||||
* @param k zero-based recursion level starting with 0
|
||||
* @param r number of non-contraction indices of A
|
||||
* @param s number of non-contraction indices of B
|
||||
* @param q number of contraction indices with q > 0
|
||||
* @param c pointer to the output tensor C with rank(A)=r+s
|
||||
* @param nc pointer to the extents of tensor C
|
||||
* @param wc pointer to the strides of tensor C
|
||||
* @param a pointer to the first input tensor with rank(A)=r+q
|
||||
* @param na pointer to the extents of the first input tensor A
|
||||
* @param wa pointer to the strides of the first input tensor A
|
||||
* @param b pointer to the second input tensor B with rank(B)=s+q
|
||||
* @param nb pointer to the extents of the second input tensor B
|
||||
* @param wb pointer to the strides of the second input tensor B
|
||||
*/
|
||||
|
||||
template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
|
||||
void ttt(SizeType const k,
|
||||
SizeType const r, SizeType const s, SizeType const q,
|
||||
PointerOut c, SizeType const*const nc, SizeType const*const wc,
|
||||
PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
PointerIn2 b, SizeType const*const nb, SizeType const*const wb)
|
||||
{
|
||||
if(k < r)
|
||||
{
|
||||
assert(nc[k] == na[k]);
|
||||
for(size_t ic = 0u; ic < nc[k]; a += wa[k], c += wc[k], ++ic)
|
||||
ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb);
|
||||
}
|
||||
else if(k < r+s)
|
||||
{
|
||||
assert(nc[k] == nb[k-r]);
|
||||
for(size_t ic = 0u; ic < nc[k]; b += wb[k-r], c += wc[k], ++ic)
|
||||
ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb);
|
||||
}
|
||||
else if(k < r+s+q-1)
|
||||
{
|
||||
assert(na[k-s] == nb[k-r]);
|
||||
for(size_t ia = 0u; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia)
|
||||
ttt(k+1, r, s, q, c, nc, wc, a, na, wa, b, nb, wb);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(na[k-s] == nb[k-r]);
|
||||
for(size_t ia = 0u; ia < na[k-s]; a += wa[k-s], b += wb[k-r], ++ia)
|
||||
*c += *a * *b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @brief Computes the tensor-times-matrix product for the contraction mode m > 0
|
||||
*
|
||||
* Implements C[i1,i2,...,im-1,j,im+1,...,ip] = sum(A[i1,i2,...,im,...,ip] * B[j,im])
|
||||
*
|
||||
* @note is used in function ttm
|
||||
*
|
||||
* @param m zero-based contraction mode with 0<m<p
|
||||
* @param r zero-based recursion level starting with p-1
|
||||
* @param c pointer to the output tensor
|
||||
* @param nc pointer to the extents of tensor c
|
||||
* @param wc pointer to the strides of tensor c
|
||||
* @param a pointer to the first input tensor
|
||||
* @param na pointer to the extents of input tensor a
|
||||
* @param wa pointer to the strides of input tensor a
|
||||
* @param b pointer to the second input tensor
|
||||
* @param nb pointer to the extents of input tensor b
|
||||
* @param wb pointer to the strides of input tensor b
|
||||
*/
|
||||
|
||||
template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
|
||||
void ttm(SizeType const m, SizeType const r,
|
||||
PointerOut c, SizeType const*const nc, SizeType const*const wc,
|
||||
PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
PointerIn2 b, SizeType const*const nb, SizeType const*const wb)
|
||||
{
|
||||
|
||||
if(r == m) {
|
||||
ttm(m, r-1, c, nc, wc, a, na, wa, b, nb, wb);
|
||||
}
|
||||
else if(r == 0){
|
||||
for(auto i0 = 0ul; i0 < nc[0]; c += wc[0], a += wa[0], ++i0) {
|
||||
auto cm = c;
|
||||
auto b0 = b;
|
||||
for(auto i0 = 0ul; i0 < nc[m]; cm += wc[m], b0 += wb[0], ++i0){
|
||||
auto am = a;
|
||||
auto b1 = b0;
|
||||
for(auto i1 = 0ul; i1 < nb[1]; am += wa[m], b1 += wb[1], ++i1)
|
||||
*cm += *am * *b1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else{
|
||||
for(auto i = 0ul; i < na[r]; c += wc[r], a += wa[r], ++i)
|
||||
ttm(m, r-1, c, nc, wc, a, na, wa, b, nb, wb);
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Computes the tensor-times-matrix product for the contraction mode m = 0
|
||||
*
|
||||
* Implements C[j,i2,...,ip] = sum(A[i1,i2,...,ip] * B[j,i1])
|
||||
*
|
||||
* @note is used in function ttm
|
||||
*
|
||||
* @param m zero-based contraction mode with 0<m<p
|
||||
* @param r zero-based recursion level starting with p-1
|
||||
* @param c pointer to the output tensor
|
||||
* @param nc pointer to the extents of tensor c
|
||||
* @param wc pointer to the strides of tensor c
|
||||
* @param a pointer to the first input tensor
|
||||
* @param na pointer to the extents of input tensor a
|
||||
* @param wa pointer to the strides of input tensor a
|
||||
* @param b pointer to the second input tensor
|
||||
* @param nb pointer to the extents of input tensor b
|
||||
* @param wb pointer to the strides of input tensor b
|
||||
*/
|
||||
template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
|
||||
void ttm0( SizeType const r,
|
||||
PointerOut c, SizeType const*const nc, SizeType const*const wc,
|
||||
PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
PointerIn2 b, SizeType const*const nb, SizeType const*const wb)
|
||||
{
|
||||
|
||||
if(r > 1){
|
||||
for(auto i = 0ul; i < na[r]; c += wc[r], a += wa[r], ++i)
|
||||
ttm0(r-1, c, nc, wc, a, na, wa, b, nb, wb);
|
||||
}
|
||||
else{
|
||||
for(auto i1 = 0ul; i1 < nc[1]; c += wc[1], a += wa[1], ++i1) {
|
||||
auto cm = c;
|
||||
auto b0 = b;
|
||||
// r == m == 0
|
||||
for(auto i0 = 0ul; i0 < nc[0]; cm += wc[0], b0 += wb[0], ++i0){
|
||||
|
||||
auto am = a;
|
||||
auto b1 = b0;
|
||||
for(auto i1 = 0u; i1 < nb[1]; am += wa[0], b1 += wb[1], ++i1){
|
||||
|
||||
*cm += *am * *b1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/** @brief Computes the tensor-times-vector product for the contraction mode m > 0
|
||||
*
|
||||
* Implements C[i1,i2,...,im-1,im+1,...,ip] = sum(A[i1,i2,...,im,...,ip] * b[im])
|
||||
*
|
||||
* @note is used in function ttv
|
||||
*
|
||||
* @param m zero-based contraction mode with 0<m<p
|
||||
* @param r zero-based recursion level starting with p-1 for tensor A
|
||||
* @param q zero-based recursion level starting with p-1 for tensor C
|
||||
* @param c pointer to the output tensor
|
||||
* @param nc pointer to the extents of tensor c
|
||||
* @param wc pointer to the strides of tensor c
|
||||
* @param a pointer to the first input tensor
|
||||
* @param na pointer to the extents of input tensor a
|
||||
* @param wa pointer to the strides of input tensor a
|
||||
* @param b pointer to the second input tensor
|
||||
*/
|
||||
|
||||
template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
|
||||
void ttv( SizeType const m, SizeType const r, SizeType const q,
|
||||
PointerOut c, SizeType const*const nc, SizeType const*const wc,
|
||||
PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
PointerIn2 b)
|
||||
{
|
||||
|
||||
if(r == m) {
|
||||
ttv(m, r-1, q, c, nc, wc, a, na, wa, b);
|
||||
}
|
||||
else if(r == 0){
|
||||
for(auto i0 = 0u; i0 < na[0]; c += wc[0], a += wa[0], ++i0) {
|
||||
auto c1 = c; auto a1 = a; auto b1 = b;
|
||||
for(auto im = 0u; im < na[m]; a1 += wa[m], ++b1, ++im)
|
||||
*c1 += *a1 * *b1;
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(auto i = 0u; i < na[r]; c += wc[q], a += wa[r], ++i)
|
||||
ttv(m, r-1, q-1, c, nc, wc, a, na, wa, b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @brief Computes the tensor-times-vector product for the contraction mode m = 0
|
||||
*
|
||||
* Implements C[i2,...,ip] = sum(A[i1,...,ip] * b[i1])
|
||||
*
|
||||
* @note is used in function ttv
|
||||
*
|
||||
* @param m zero-based contraction mode with m=0
|
||||
* @param r zero-based recursion level starting with p-1
|
||||
* @param c pointer to the output tensor
|
||||
* @param nc pointer to the extents of tensor c
|
||||
* @param wc pointer to the strides of tensor c
|
||||
* @param a pointer to the first input tensor
|
||||
* @param na pointer to the extents of input tensor a
|
||||
* @param wa pointer to the strides of input tensor a
|
||||
* @param b pointer to the second input tensor
|
||||
*/
|
||||
template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
|
||||
void ttv0(SizeType const r,
|
||||
PointerOut c, SizeType const*const nc, SizeType const*const wc,
|
||||
PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
PointerIn2 b)
|
||||
{
|
||||
|
||||
if(r > 1){
|
||||
for(auto i = 0u; i < na[r]; c += wc[r-1], a += wa[r], ++i)
|
||||
ttv0(r-1, c, nc, wc, a, na, wa, b);
|
||||
}
|
||||
else{
|
||||
for(auto i1 = 0u; i1 < na[1]; c += wc[0], a += wa[1], ++i1)
|
||||
{
|
||||
auto c1 = c; auto a1 = a; auto b1 = b;
|
||||
for(auto i0 = 0u; i0 < na[0]; a1 += wa[0], ++b1, ++i0)
|
||||
*c1 += *a1 * *b1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @brief Computes the matrix-times-vector product
|
||||
*
|
||||
* Implements C[i1] = sum(A[i1,i2] * b[i2]) or C[i2] = sum(A[i1,i2] * b[i1])
|
||||
*
|
||||
* @note is used in function ttv
|
||||
*
|
||||
* @param[in] m zero-based contraction mode with m=0 or m=1
|
||||
* @param[out] c pointer to the output tensor C
|
||||
* @param[in] nc pointer to the extents of tensor C
|
||||
* @param[in] wc pointer to the strides of tensor C
|
||||
* @param[in] a pointer to the first input tensor A
|
||||
* @param[in] na pointer to the extents of input tensor A
|
||||
* @param[in] wa pointer to the strides of input tensor A
|
||||
* @param[in] b pointer to the second input tensor B
|
||||
*/
|
||||
template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
|
||||
void mtv(SizeType const m,
|
||||
PointerOut c, SizeType const*const , SizeType const*const wc,
|
||||
PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
PointerIn2 b)
|
||||
{
|
||||
// decides whether matrix multiplied with vector or vector multiplied with matrix
|
||||
const auto o = (m == 0) ? 1 : 0;
|
||||
|
||||
for(auto io = 0u; io < na[o]; c += wc[o], a += wa[o], ++io) {
|
||||
auto c1 = c; auto a1 = a; auto b1 = b;
|
||||
for(auto im = 0u; im < na[m]; a1 += wa[m], ++b1, ++im)
|
||||
*c1 += *a1 * *b1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @brief Computes the matrix-times-matrix product
|
||||
*
|
||||
* Implements C[i1,i3] = sum(A[i1,i2] * B[i2,i3])
|
||||
*
|
||||
* @note is used in function ttm
|
||||
*
|
||||
* @param[out] c pointer to the output tensor C
|
||||
* @param[in] nc pointer to the extents of tensor C
|
||||
* @param[in] wc pointer to the strides of tensor C
|
||||
* @param[in] a pointer to the first input tensor A
|
||||
* @param[in] na pointer to the extents of input tensor A
|
||||
* @param[in] wa pointer to the strides of input tensor A
|
||||
* @param[in] b pointer to the second input tensor B
|
||||
* @param[in] nb pointer to the extents of input tensor B
|
||||
* @param[in] wb pointer to the strides of input tensor B
|
||||
*/
|
||||
template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
|
||||
void mtm(PointerOut c, SizeType const*const nc, SizeType const*const wc,
|
||||
PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
PointerIn2 b, SizeType const*const nb, SizeType const*const wb)
|
||||
{
|
||||
|
||||
// C(i,j) = A(i,k) * B(k,j)
|
||||
|
||||
assert(nc[0] == na[0]);
|
||||
assert(nc[1] == nb[1]);
|
||||
assert(na[1] == nb[0]);
|
||||
|
||||
auto cj = c; auto bj = b;
|
||||
for(auto j = 0u; j < nc[1]; cj += wc[1], bj += wb[1], ++j) {
|
||||
|
||||
auto bk = bj; auto ak = a;
|
||||
for(auto k = 0u; k < na[1]; ak += wa[1], bk += wb[0], ++k) {
|
||||
|
||||
auto ci = cj; auto ai = ak;
|
||||
for(auto i = 0u; i < na[0]; ai += wa[0], ci += wc[0], ++i){
|
||||
*ci += *ai * *bk;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Computes the inner product of two tensors
|
||||
*
|
||||
* Implements c = sum(A[i1,i2,...,ip] * B[i1,i2,...,ip])
|
||||
*
|
||||
* @note is used in function inner
|
||||
*
|
||||
* @param r zero-based recursion level starting with p-1
|
||||
* @param n pointer to the extents of input or output tensor
|
||||
* @param a pointer to the first input tensor
|
||||
* @param wa pointer to the strides of input tensor a
|
||||
* @param b pointer to the second input tensor
|
||||
* @param wb pointer to the strides of tensor b
|
||||
* @param v previously computed value (start with v = 0).
|
||||
* @return inner product of two tensors.
|
||||
*/
|
||||
template <class PointerIn1, class PointerIn2, class value_t, class SizeType>
|
||||
value_t inner(SizeType const r, SizeType const*const n,
|
||||
PointerIn1 a, SizeType const*const wa,
|
||||
PointerIn2 b, SizeType const*const wb,
|
||||
value_t v)
|
||||
{
|
||||
if(r == 0)
|
||||
for(auto i0 = 0u; i0 < n[0]; a += wa[0], b += wb[0], ++i0)
|
||||
v += *a * *b;
|
||||
else
|
||||
for(auto ir = 0u; ir < n[r]; a += wa[r], b += wb[r], ++ir)
|
||||
v = inner(r-1, n, a, wa, b, wb, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
|
||||
void outer_2x2(SizeType const pa,
|
||||
PointerOut c, SizeType const*const , SizeType const*const wc,
|
||||
PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
PointerIn2 b, SizeType const*const nb, SizeType const*const wb)
|
||||
{
|
||||
// assert(rc == 3);
|
||||
// assert(ra == 1);
|
||||
// assert(rb == 1);
|
||||
|
||||
for(auto ib1 = 0u; ib1 < nb[1]; b += wb[1], c += wc[pa+1], ++ib1) {
|
||||
auto c2 = c;
|
||||
auto b0 = b;
|
||||
for(auto ib0 = 0u; ib0 < nb[0]; b0 += wb[0], c2 += wc[pa], ++ib0) {
|
||||
const auto b = *b0;
|
||||
auto c1 = c2;
|
||||
auto a1 = a;
|
||||
for(auto ia1 = 0u; ia1 < na[1]; a1 += wa[1], c1 += wc[1], ++ia1) {
|
||||
auto a0 = a1;
|
||||
auto c0 = c1;
|
||||
for(SizeType ia0 = 0u; ia0 < na[0]; a0 += wa[0], c0 += wc[0], ++ia0)
|
||||
*c0 = *a0 * b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Computes the outer product of two tensors
|
||||
*
|
||||
* Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq]
|
||||
*
|
||||
* @note called by outer
|
||||
*
|
||||
*
|
||||
* @param[in] pa number of dimensions (rank) of the first input tensor A with pa > 0
|
||||
*
|
||||
* @param[in] rc recursion level for C that starts with pc-1
|
||||
* @param[out] c pointer to the output tensor
|
||||
* @param[in] nc pointer to the extents of output tensor c
|
||||
* @param[in] wc pointer to the strides of output tensor c
|
||||
*
|
||||
* @param[in] ra recursion level for A that starts with pa-1
|
||||
* @param[in] a pointer to the first input tensor
|
||||
* @param[in] na pointer to the extents of the first input tensor a
|
||||
* @param[in] wa pointer to the strides of the first input tensor a
|
||||
*
|
||||
* @param[in] rb recursion level for B that starts with pb-1
|
||||
* @param[in] b pointer to the second input tensor
|
||||
* @param[in] nb pointer to the extents of the second input tensor b
|
||||
* @param[in] wb pointer to the strides of the second input tensor b
|
||||
*/
|
||||
template<class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
|
||||
void outer(SizeType const pa,
|
||||
SizeType const rc, PointerOut c, SizeType const*const nc, SizeType const*const wc,
|
||||
SizeType const ra, PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
SizeType const rb, PointerIn2 b, SizeType const*const nb, SizeType const*const wb)
|
||||
{
|
||||
if(rb > 1)
|
||||
for(auto ib = 0u; ib < nb[rb]; b += wb[rb], c += wc[rc], ++ib)
|
||||
outer(pa, rc-1, c, nc, wc, ra, a, na, wa, rb-1, b, nb, wb);
|
||||
else if(ra > 1)
|
||||
for(auto ia = 0u; ia < na[ra]; a += wa[ra], c += wc[ra], ++ia)
|
||||
outer(pa, rc-1, c, nc, wc, ra-1, a, na, wa, rb, b, nb, wb);
|
||||
else
|
||||
outer_2x2(pa, c, nc, wc, a, na, wa, b, nb, wb); //assert(ra==1 && rb==1 && rc==3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Computes the outer product with permutation tuples
|
||||
*
|
||||
* Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir] * B[j1,...,js] )
|
||||
*
|
||||
* nc[x] = na[phia[x]] for 1 <= x <= r
|
||||
* nc[r+x] = nb[phib[x]] for 1 <= x <= s
|
||||
*
|
||||
* @note maybe called by ttt function
|
||||
*
|
||||
* @param k zero-based recursion level starting with 0
|
||||
* @param r number of non-contraction indices of A
|
||||
* @param s number of non-contraction indices of B
|
||||
* @param phia pointer to the permutation tuple of length r for A
|
||||
* @param phib pointer to the permutation tuple of length s for B
|
||||
* @param c pointer to the output tensor C with rank(A)=r+s
|
||||
* @param nc pointer to the extents of tensor C
|
||||
* @param wc pointer to the strides of tensor C
|
||||
* @param a pointer to the first input tensor with rank(A)=r
|
||||
* @param na pointer to the extents of the first input tensor A
|
||||
* @param wa pointer to the strides of the first input tensor A
|
||||
* @param b pointer to the second input tensor B with rank(B)=s
|
||||
* @param nb pointer to the extents of the second input tensor B
|
||||
* @param wb pointer to the strides of the second input tensor B
|
||||
*/
|
||||
|
||||
template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
|
||||
void outer(SizeType const k,
|
||||
SizeType const r, SizeType const s,
|
||||
SizeType const*const phia, SizeType const*const phib,
|
||||
PointerOut c, SizeType const*const nc, SizeType const*const wc,
|
||||
PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
PointerIn2 b, SizeType const*const nb, SizeType const*const wb)
|
||||
{
|
||||
if(k < r)
|
||||
{
|
||||
assert(nc[k] == na[phia[k]-1]);
|
||||
for(size_t ic = 0u; ic < nc[k]; a += wa[phia[k]-1], c += wc[k], ++ic)
|
||||
outer(k+1, r, s, phia,phib, c, nc, wc, a, na, wa, b, nb, wb);
|
||||
}
|
||||
else if(k < r+s-1)
|
||||
{
|
||||
assert(nc[k] == nb[phib[k-r]-1]);
|
||||
for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic)
|
||||
outer(k+1, r, s, phia, phib, c, nc, wc, a, na, wa, b, nb, wb);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(nc[k] == nb[phib[k-r]-1]);
|
||||
for(size_t ic = 0u; ic < nc[k]; b += wb[phib[k-r]-1], c += wc[k], ++ic)
|
||||
*c = *a * *b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace recursive
|
||||
} // namespace detail
|
||||
} // namespace ublas
|
||||
} // namespace numeric
|
||||
} // namespace boost
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
|
||||
/** @brief Computes the tensor-times-vector product
|
||||
*
|
||||
* Implements
|
||||
* C[i1,i2,...,im-1,im+1,...,ip] = sum(A[i1,i2,...,im,...,ip] * b[im]) for m>1 and
|
||||
* C[i2,...,ip] = sum(A[i1,...,ip] * b[i1]) for m=1
|
||||
*
|
||||
* @note calls detail::ttv, detail::ttv0 or detail::mtv
|
||||
*
|
||||
* @param[in] m contraction mode with 0 < m <= p
|
||||
* @param[in] p number of dimensions (rank) of the first input tensor with p > 0
|
||||
* @param[out] c pointer to the output tensor with rank p-1
|
||||
* @param[in] nc pointer to the extents of tensor c
|
||||
* @param[in] wc pointer to the strides of tensor c
|
||||
* @param[in] a pointer to the first input tensor
|
||||
* @param[in] na pointer to the extents of input tensor a
|
||||
* @param[in] wa pointer to the strides of input tensor a
|
||||
* @param[in] b pointer to the second input tensor
|
||||
* @param[in] nb pointer to the extents of input tensor b
|
||||
* @param[in] wb pointer to the strides of input tensor b
|
||||
*/
|
||||
template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
|
||||
void ttv(SizeType const m, SizeType const p,
|
||||
PointerOut c, SizeType const*const nc, SizeType const*const wc,
|
||||
const PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
const PointerIn2 b, SizeType const*const nb, SizeType const*const wb)
|
||||
{
|
||||
static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn1>::value & std::is_pointer<PointerIn2>::value,
|
||||
"Static error in boost::numeric::ublas::ttv: Argument types for pointers are not pointer types.");
|
||||
|
||||
if( m == 0)
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttv: Contraction mode must be greater than zero.");
|
||||
|
||||
if( p < m )
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttv: Rank must be greater equal the modus.");
|
||||
|
||||
if( p == 0)
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttv: Rank must be greater than zero.");
|
||||
|
||||
if(c == nullptr || a == nullptr || b == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttv: Pointers shall not be null pointers.");
|
||||
|
||||
for(auto i = 0u; i < m-1; ++i)
|
||||
if(na[i] != nc[i])
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttv: Extents (except of dimension mode) of A and C must be equal.");
|
||||
|
||||
for(auto i = m; i < p; ++i)
|
||||
if(na[i] != nc[i-1])
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttv: Extents (except of dimension mode) of A and C must be equal.");
|
||||
|
||||
const auto max = std::max(nb[0], nb[1]);
|
||||
if( na[m-1] != max)
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttv: Extent of dimension mode of A and b must be equal.");
|
||||
|
||||
|
||||
if((m != 1) && (p > 2))
|
||||
detail::recursive::ttv(m-1, p-1, p-2, c, nc, wc, a, na, wa, b);
|
||||
else if ((m == 1) && (p > 2))
|
||||
detail::recursive::ttv0(p-1, c, nc, wc, a, na, wa, b);
|
||||
else if( p == 2 )
|
||||
detail::recursive::mtv(m-1, c, nc, wc, a, na, wa, b);
|
||||
else /*if( p == 1 )*/{
|
||||
auto v = std::remove_pointer_t<std::remove_cv_t<PointerOut>>{};
|
||||
*c = detail::recursive::inner(SizeType(0), na, a, wa, b, wb, v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Computes the tensor-times-matrix product
|
||||
*
|
||||
* Implements
|
||||
* C[i1,i2,...,im-1,j,im+1,...,ip] = sum(A[i1,i2,...,im,...,ip] * B[j,im]) for m>1 and
|
||||
* C[j,i2,...,ip] = sum(A[i1,i2,...,ip] * B[j,i1]) for m=1
|
||||
*
|
||||
* @note calls detail::ttm or detail::ttm0
|
||||
*
|
||||
* @param[in] m contraction mode with 0 < m <= p
|
||||
* @param[in] p number of dimensions (rank) of the first input tensor with p > 0
|
||||
* @param[out] c pointer to the output tensor with rank p-1
|
||||
* @param[in] nc pointer to the extents of tensor c
|
||||
* @param[in] wc pointer to the strides of tensor c
|
||||
* @param[in] a pointer to the first input tensor
|
||||
* @param[in] na pointer to the extents of input tensor a
|
||||
* @param[in] wa pointer to the strides of input tensor a
|
||||
* @param[in] b pointer to the second input tensor
|
||||
* @param[in] nb pointer to the extents of input tensor b
|
||||
* @param[in] wb pointer to the strides of input tensor b
|
||||
*/
|
||||
|
||||
template <class PointerIn1, class PointerIn2, class PointerOut, class SizeType>
|
||||
void ttm(SizeType const m, SizeType const p,
|
||||
PointerOut c, SizeType const*const nc, SizeType const*const wc,
|
||||
const PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
const PointerIn2 b, SizeType const*const nb, SizeType const*const wb)
|
||||
{
|
||||
|
||||
static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn1>::value & std::is_pointer<PointerIn2>::value,
|
||||
"Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types.");
|
||||
|
||||
if( m == 0 )
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttm: Contraction mode must be greater than zero.");
|
||||
|
||||
if( p < m )
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttm: Rank must be greater equal than the specified mode.");
|
||||
|
||||
if( p == 0)
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttm:Rank must be greater than zero.");
|
||||
|
||||
if(c == nullptr || a == nullptr || b == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers.");
|
||||
|
||||
for(auto i = 0u; i < m-1; ++i)
|
||||
if(na[i] != nc[i])
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttm: Extents (except of dimension mode) of A and C must be equal.");
|
||||
|
||||
for(auto i = m; i < p; ++i)
|
||||
if(na[i] != nc[i])
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttm: Extents (except of dimension mode) of A and C must be equal.");
|
||||
|
||||
if(na[m-1] != nb[1])
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttm: 2nd Extent of B and M-th Extent of A must be the equal.");
|
||||
|
||||
if(nc[m-1] != nb[0])
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttm: 1nd Extent of B and M-th Extent of C must be the equal.");
|
||||
|
||||
if ( m != 1 )
|
||||
detail::recursive::ttm (m-1, p-1, c, nc, wc, a, na, wa, b, nb, wb);
|
||||
else /*if (m == 1 && p > 2)*/
|
||||
detail::recursive::ttm0( p-1, c, nc, wc, a, na, wa, b, nb, wb);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** @brief Computes the tensor-times-tensor product
|
||||
*
|
||||
* Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] )
|
||||
*
|
||||
* @note calls detail::recursive::ttt or ttm or ttv or inner or outer
|
||||
*
|
||||
* nc[x] = na[phia[x] ] for 1 <= x <= r
|
||||
* nc[r+x] = nb[phib[x] ] for 1 <= x <= s
|
||||
* na[phia[r+x]] = nb[phib[s+x]] for 1 <= x <= q
|
||||
*
|
||||
* @param[in] pa number of dimensions (rank) of the first input tensor a with pa > 0
|
||||
* @param[in] pb number of dimensions (rank) of the second input tensor b with pb > 0
|
||||
* @param[in] q number of contraction dimensions with pa >= q and pb >= q and q >= 0
|
||||
* @param[in] phia pointer to a permutation tuple for the first input tensor a
|
||||
* @param[in] phib pointer to a permutation tuple for the second input tensor b
|
||||
* @param[out] c pointer to the output tensor with rank p-1
|
||||
* @param[in] nc pointer to the extents of tensor c
|
||||
* @param[in] wc pointer to the strides of tensor c
|
||||
* @param[in] a pointer to the first input tensor
|
||||
* @param[in] na pointer to the extents of input tensor a
|
||||
* @param[in] wa pointer to the strides of input tensor a
|
||||
* @param[in] b pointer to the second input tensor
|
||||
* @param[in] nb pointer to the extents of input tensor b
|
||||
* @param[in] wb pointer to the strides of input tensor b
|
||||
*/
|
||||
|
||||
template <class PointerIn1, class PointerIn2, class PointerOut, class SizeType>
|
||||
void ttt(SizeType const pa, SizeType const pb, SizeType const q,
|
||||
SizeType const*const phia, SizeType const*const phib,
|
||||
PointerOut c, SizeType const*const nc, SizeType const*const wc,
|
||||
PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
PointerIn2 b, SizeType const*const nb, SizeType const*const wb)
|
||||
{
|
||||
static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn1>::value & std::is_pointer<PointerIn2>::value,
|
||||
"Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types.");
|
||||
|
||||
if( pa == 0 || pb == 0)
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttt: tensor order must be greater zero.");
|
||||
|
||||
if( q > pa && q > pb)
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttt: number of contraction must be smaller than or equal to the tensor order.");
|
||||
|
||||
|
||||
SizeType const r = pa - q;
|
||||
SizeType const s = pb - q;
|
||||
|
||||
if(c == nullptr || a == nullptr || b == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers.");
|
||||
|
||||
for(auto i = 0ul; i < r; ++i)
|
||||
if( na[phia[i]-1] != nc[i] )
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and res tensor not correct.");
|
||||
|
||||
for(auto i = 0ul; i < s; ++i)
|
||||
if( nb[phib[i]-1] != nc[r+i] )
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of rhs and res not correct.");
|
||||
|
||||
for(auto i = 0ul; i < q; ++i)
|
||||
if( nb[phib[s+i]-1] != na[phia[r+i]-1] )
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and rhs not correct.");
|
||||
|
||||
|
||||
if(q == 0ul)
|
||||
detail::recursive::outer(SizeType{0},r,s, phia,phib, c,nc,wc, a,na,wa, b,nb,wb);
|
||||
else
|
||||
detail::recursive::ttt(SizeType{0},r,s,q, phia,phib, c,nc,wc, a,na,wa, b,nb,wb);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Computes the tensor-times-tensor product
|
||||
*
|
||||
* Implements C[i1,...,ir,j1,...,js] = sum( A[i1,...,ir+q] * B[j1,...,js+q] )
|
||||
*
|
||||
* @note calls detail::recursive::ttt or ttm or ttv or inner or outer
|
||||
*
|
||||
* nc[x] = na[x ] for 1 <= x <= r
|
||||
* nc[r+x] = nb[x ] for 1 <= x <= s
|
||||
* na[r+x] = nb[s+x] for 1 <= x <= q
|
||||
*
|
||||
* @param[in] pa number of dimensions (rank) of the first input tensor a with pa > 0
|
||||
* @param[in] pb number of dimensions (rank) of the second input tensor b with pb > 0
|
||||
* @param[in] q number of contraction dimensions with pa >= q and pb >= q and q >= 0
|
||||
* @param[out] c pointer to the output tensor with rank p-1
|
||||
* @param[in] nc pointer to the extents of tensor c
|
||||
* @param[in] wc pointer to the strides of tensor c
|
||||
* @param[in] a pointer to the first input tensor
|
||||
* @param[in] na pointer to the extents of input tensor a
|
||||
* @param[in] wa pointer to the strides of input tensor a
|
||||
* @param[in] b pointer to the second input tensor
|
||||
* @param[in] nb pointer to the extents of input tensor b
|
||||
* @param[in] wb pointer to the strides of input tensor b
|
||||
*/
|
||||
|
||||
template <class PointerIn1, class PointerIn2, class PointerOut, class SizeType>
|
||||
void ttt(SizeType const pa, SizeType const pb, SizeType const q,
|
||||
PointerOut c, SizeType const*const nc, SizeType const*const wc,
|
||||
PointerIn1 a, SizeType const*const na, SizeType const*const wa,
|
||||
PointerIn2 b, SizeType const*const nb, SizeType const*const wb)
|
||||
{
|
||||
static_assert( std::is_pointer<PointerOut>::value & std::is_pointer<PointerIn1>::value & std::is_pointer<PointerIn2>::value,
|
||||
"Static error in boost::numeric::ublas::ttm: Argument types for pointers are not pointer types.");
|
||||
|
||||
if( pa == 0 || pb == 0)
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttt: tensor order must be greater zero.");
|
||||
|
||||
if( q > pa && q > pb)
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttt: number of contraction must be smaller than or equal to the tensor order.");
|
||||
|
||||
|
||||
SizeType const r = pa - q;
|
||||
SizeType const s = pb - q;
|
||||
SizeType const pc = r+s;
|
||||
|
||||
if(c == nullptr || a == nullptr || b == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttm: Pointers shall not be null pointers.");
|
||||
|
||||
for(auto i = 0ul; i < r; ++i)
|
||||
if( na[i] != nc[i] )
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and res tensor not correct.");
|
||||
|
||||
for(auto i = 0ul; i < s; ++i)
|
||||
if( nb[i] != nc[r+i] )
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of rhs and res not correct.");
|
||||
|
||||
for(auto i = 0ul; i < q; ++i)
|
||||
if( nb[s+i] != na[r+i] )
|
||||
throw std::length_error("Error in boost::numeric::ublas::ttt: dimensions of lhs and rhs not correct.");
|
||||
|
||||
using value_type = std::decay_t<decltype(*c)>;
|
||||
|
||||
|
||||
|
||||
if(q == 0ul)
|
||||
detail::recursive::outer(pa, pc-1, c,nc,wc, pa-1, a,na,wa, pb-1, b,nb,wb);
|
||||
else if(r == 0ul && s == 0ul)
|
||||
*c = detail::recursive::inner(q-1, na, a,wa, b,wb, value_type(0) );
|
||||
else
|
||||
detail::recursive::ttt(SizeType{0},r,s,q, c,nc,wc, a,na,wa, b,nb,wb);
|
||||
}
|
||||
|
||||
|
||||
/** @brief Computes the inner product of two tensors
|
||||
*
|
||||
* Implements c = sum(A[i1,i2,...,ip] * B[i1,i2,...,ip])
|
||||
*
|
||||
* @note calls detail::inner
|
||||
*
|
||||
* @param[in] p number of dimensions (rank) of the first input tensor with p > 0
|
||||
* @param[in] n pointer to the extents of input or output tensor
|
||||
* @param[in] a pointer to the first input tensor
|
||||
* @param[in] wa pointer to the strides of input tensor a
|
||||
* @param[in] b pointer to the second input tensor
|
||||
* @param[in] wb pointer to the strides of input tensor b
|
||||
* @param[in] v inital value
|
||||
*
|
||||
* @return inner product of two tensors.
|
||||
*/
|
||||
template <class PointerIn1, class PointerIn2, class value_t, class SizeType>
|
||||
auto inner(const SizeType p, SizeType const*const n,
|
||||
const PointerIn1 a, SizeType const*const wa,
|
||||
const PointerIn2 b, SizeType const*const wb,
|
||||
value_t v)
|
||||
{
|
||||
static_assert( std::is_pointer<PointerIn1>::value && std::is_pointer<PointerIn2>::value,
|
||||
"Static error in boost::numeric::ublas::inner: Argument types for pointers must be pointer types.");
|
||||
if(p<2)
|
||||
throw std::length_error("Error in boost::numeric::ublas::inner: Rank must be greater than zero.");
|
||||
if(a == nullptr || b == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::inner: Pointers shall not be null pointers.");
|
||||
|
||||
return detail::recursive::inner(p-1, n, a, wa, b, wb, v);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** @brief Computes the outer product of two tensors
|
||||
*
|
||||
* Implements C[i1,...,ip,j1,...,jq] = A[i1,i2,...,ip] * B[j1,j2,...,jq]
|
||||
*
|
||||
* @note calls detail::outer
|
||||
*
|
||||
* @param[out] c pointer to the output tensor
|
||||
* @param[in] pc number of dimensions (rank) of the output tensor c with pc > 0
|
||||
* @param[in] nc pointer to the extents of output tensor c
|
||||
* @param[in] wc pointer to the strides of output tensor c
|
||||
* @param[in] a pointer to the first input tensor
|
||||
* @param[in] pa number of dimensions (rank) of the first input tensor a with pa > 0
|
||||
* @param[in] na pointer to the extents of the first input tensor a
|
||||
* @param[in] wa pointer to the strides of the first input tensor a
|
||||
* @param[in] b pointer to the second input tensor
|
||||
* @param[in] pb number of dimensions (rank) of the second input tensor b with pb > 0
|
||||
* @param[in] nb pointer to the extents of the second input tensor b
|
||||
* @param[in] wb pointer to the strides of the second input tensor b
|
||||
*/
|
||||
template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
|
||||
void outer(PointerOut c, SizeType const pc, SizeType const*const nc, SizeType const*const wc,
|
||||
const PointerIn1 a, SizeType const pa, SizeType const*const na, SizeType const*const wa,
|
||||
const PointerIn2 b, SizeType const pb, SizeType const*const nb, SizeType const*const wb)
|
||||
{
|
||||
static_assert( std::is_pointer<PointerIn1>::value & std::is_pointer<PointerIn2>::value & std::is_pointer<PointerOut>::value,
|
||||
"Static error in boost::numeric::ublas::outer: argument types for pointers must be pointer types.");
|
||||
if(pa < 2u || pb < 2u)
|
||||
throw std::length_error("Error in boost::numeric::ublas::outer: number of extents of lhs and rhs tensor must be equal or greater than two.");
|
||||
if((pa + pb) != pc)
|
||||
throw std::length_error("Error in boost::numeric::ublas::outer: number of extents of lhs plus rhs tensor must be equal to the number of extents of C.");
|
||||
if(a == nullptr || b == nullptr || c == nullptr)
|
||||
throw std::length_error("Error in boost::numeric::ublas::outer: pointers shall not be null pointers.");
|
||||
|
||||
detail::recursive::outer(pa, pc-1, c, nc, wc, pa-1, a, na, wa, pb-1, b, nb, wb);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
244
include/boost/numeric/ublas/tensor/operators_arithmetic.hpp
Normal file
244
include/boost/numeric/ublas/tensor/operators_arithmetic.hpp
Normal file
@@ -0,0 +1,244 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen, Germany
|
||||
//
|
||||
|
||||
#ifndef BOOST_UBLAS_TENSOR_OPERATORS_ARITHMETIC_HPP
|
||||
#define BOOST_UBLAS_TENSOR_OPERATORS_ARITHMETIC_HPP
|
||||
|
||||
#include "expression.hpp"
|
||||
#include "expression_evaluation.hpp"
|
||||
#include "multi_index_utility.hpp"
|
||||
#include "functions.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
||||
namespace boost{
|
||||
namespace numeric{
|
||||
namespace ublas {
|
||||
|
||||
|
||||
template<class element_type, class storage_format, class storage_type>
|
||||
class tensor;
|
||||
|
||||
template<class E>
|
||||
class matrix_expression;
|
||||
|
||||
|
||||
template<class E>
|
||||
class vector_expression;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define FIRST_ORDER_OPERATOR_RIGHT(OP, EXPR_TYPE_L, EXPR_TYPE_R) \
|
||||
template<class T, class L, class R> \
|
||||
auto operator OP ( boost::numeric::ublas:: EXPR_TYPE_L <T,L> const& lhs, boost::numeric::ublas:: EXPR_TYPE_R <R> const& rhs) { \
|
||||
return boost::numeric::ublas::detail::make_binary_tensor_expression<T> (lhs(), rhs(), \
|
||||
[](auto const& l, auto const& r){ return l OP r; }); \
|
||||
} \
|
||||
|
||||
FIRST_ORDER_OPERATOR_RIGHT (*, detail:: tensor_expression , vector_expression)
|
||||
FIRST_ORDER_OPERATOR_RIGHT (+, detail:: tensor_expression , vector_expression)
|
||||
FIRST_ORDER_OPERATOR_RIGHT (-, detail:: tensor_expression , vector_expression)
|
||||
FIRST_ORDER_OPERATOR_RIGHT (/, detail:: tensor_expression , vector_expression)
|
||||
|
||||
FIRST_ORDER_OPERATOR_RIGHT (*, detail:: tensor_expression , matrix_expression)
|
||||
FIRST_ORDER_OPERATOR_RIGHT (+, detail:: tensor_expression , matrix_expression)
|
||||
FIRST_ORDER_OPERATOR_RIGHT (-, detail:: tensor_expression , matrix_expression)
|
||||
FIRST_ORDER_OPERATOR_RIGHT (/, detail:: tensor_expression , matrix_expression)
|
||||
|
||||
|
||||
#define FIRST_ORDER_OPERATOR_LEFT(OP, EXPR_TYPE_L, EXPR_TYPE_R) \
|
||||
template<class T, class L, class R> \
|
||||
auto operator OP ( boost::numeric::ublas:: EXPR_TYPE_L <L> const& lhs, boost::numeric::ublas:: EXPR_TYPE_R <T,R> const& rhs) { \
|
||||
return boost::numeric::ublas::detail::make_binary_tensor_expression<T> (lhs(), rhs(), \
|
||||
[](auto const& l, auto const& r){ return l OP r; }); \
|
||||
} \
|
||||
|
||||
FIRST_ORDER_OPERATOR_LEFT (*, vector_expression, detail:: tensor_expression)
|
||||
FIRST_ORDER_OPERATOR_LEFT (+, vector_expression, detail:: tensor_expression)
|
||||
FIRST_ORDER_OPERATOR_LEFT (-, vector_expression, detail:: tensor_expression)
|
||||
FIRST_ORDER_OPERATOR_LEFT (/, vector_expression, detail:: tensor_expression)
|
||||
|
||||
FIRST_ORDER_OPERATOR_LEFT (*, matrix_expression, detail:: tensor_expression)
|
||||
FIRST_ORDER_OPERATOR_LEFT (+, matrix_expression, detail:: tensor_expression)
|
||||
FIRST_ORDER_OPERATOR_LEFT (-, matrix_expression, detail:: tensor_expression)
|
||||
FIRST_ORDER_OPERATOR_LEFT (/, matrix_expression, detail:: tensor_expression)
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T, class L, class R>
|
||||
auto operator+( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::make_binary_tensor_expression<T> (lhs(), rhs(), [](auto const& l, auto const& r){ return l + r; });
|
||||
}
|
||||
template<class T, class L, class R>
|
||||
auto operator-( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::make_binary_tensor_expression<T> (lhs(), rhs(), [](auto const& l, auto const& r){ return l - r; });
|
||||
// return boost::numeric::ublas::detail::make_lambda<T>([&lhs,&rhs](std::size_t i){ return lhs(i) - rhs(i);});
|
||||
}
|
||||
template<class T, class L, class R>
|
||||
auto operator*( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::make_binary_tensor_expression<T> (lhs(), rhs(), [](auto const& l, auto const& r){ return l * r; });
|
||||
}
|
||||
template<class T, class L, class R>
|
||||
auto operator/( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::make_binary_tensor_expression<T> (lhs(), rhs(), [](auto const& l, auto const& r){ return l / r; });
|
||||
}
|
||||
|
||||
|
||||
// Overloaded Arithmetic Operators with Scalars
|
||||
template<class T, class R>
|
||||
auto operator+(typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (rhs(), [lhs](auto const& r){ return lhs + r; });
|
||||
//return boost::numeric::ublas::detail::make_lambda<T>( [&lhs,&rhs](std::size_t i) {return lhs + rhs(i); } );
|
||||
}
|
||||
template<class T, class R>
|
||||
auto operator-(typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (rhs(), [lhs](auto const& r){ return lhs - r; });
|
||||
}
|
||||
template<class T, class R>
|
||||
auto operator*(typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (rhs(), [lhs](auto const& r){ return lhs * r; });
|
||||
}
|
||||
template<class T, class R>
|
||||
auto operator/(typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (rhs(), [lhs](auto const& r){ return lhs / r; });
|
||||
}
|
||||
|
||||
|
||||
template<class T, class L>
|
||||
auto operator+(boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, typename T::const_reference rhs) {
|
||||
return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (lhs(), [rhs] (auto const& l) { return l + rhs; } );
|
||||
}
|
||||
template<class T, class L>
|
||||
auto operator-(boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, typename T::const_reference rhs) {
|
||||
return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (lhs(), [rhs] (auto const& l) { return l - rhs; } );
|
||||
}
|
||||
template<class T, class L>
|
||||
auto operator*(boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, typename T::const_reference rhs) {
|
||||
return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (lhs(), [rhs] (auto const& l) { return l * rhs; } );
|
||||
}
|
||||
template<class T, class L>
|
||||
auto operator/(boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs, typename T::const_reference rhs) {
|
||||
return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (lhs(), [rhs] (auto const& l) { return l / rhs; } );
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T, class D>
|
||||
auto& operator += (T& lhs, const boost::numeric::ublas::detail::tensor_expression<T,D> &expr) {
|
||||
boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l+=r; } );
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<class T, class D>
|
||||
auto& operator -= (T& lhs, const boost::numeric::ublas::detail::tensor_expression<T,D> &expr) {
|
||||
boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l-=r; } );
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<class T, class D>
|
||||
auto& operator *= (T& lhs, const boost::numeric::ublas::detail::tensor_expression<T,D> &expr) {
|
||||
boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l*=r; } );
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<class T, class D>
|
||||
auto& operator /= (T& lhs, const boost::numeric::ublas::detail::tensor_expression<T,D> &expr) {
|
||||
boost::numeric::ublas::detail::eval(lhs, expr(), [](auto& l, auto const& r) { l/=r; } );
|
||||
return lhs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class E, class F, class A>
|
||||
auto& operator += (boost::numeric::ublas::tensor<E,F,A>& lhs, typename boost::numeric::ublas::tensor<E,F,A>::const_reference r) {
|
||||
boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l+=r; } );
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<class E, class F, class A>
|
||||
auto& operator -= (boost::numeric::ublas::tensor<E,F,A>& lhs, typename boost::numeric::ublas::tensor<E,F,A>::const_reference r) {
|
||||
boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l-=r; } );
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<class E, class F, class A>
|
||||
auto& operator *= (boost::numeric::ublas::tensor<E,F,A>& lhs, typename boost::numeric::ublas::tensor<E,F,A>::const_reference r) {
|
||||
boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l*=r; } );
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<class E, class F, class A>
|
||||
auto& operator /= (boost::numeric::ublas::tensor<E,F,A>& lhs, typename boost::numeric::ublas::tensor<E,F,A>::const_reference r) {
|
||||
boost::numeric::ublas::detail::eval(lhs, [r](auto& l) { l/=r; } );
|
||||
return lhs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T, class D>
|
||||
auto const& operator +(const boost::numeric::ublas::detail::tensor_expression<T,D>& lhs) {
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<class T, class D>
|
||||
auto operator -(boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs) {
|
||||
return boost::numeric::ublas::detail::make_unary_tensor_expression<T> (lhs(), [] (auto const& l) { return -l; } );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Performs a tensor contraction, not an elementwise multiplication
|
||||
*
|
||||
*/
|
||||
|
||||
template<class tensor_type_left, class tuple_type_left, class tensor_type_right, class tuple_type_right>
|
||||
auto operator*(
|
||||
std::pair< tensor_type_left const&, tuple_type_left > lhs,
|
||||
std::pair< tensor_type_right const&, tuple_type_right > rhs)
|
||||
{
|
||||
|
||||
using namespace boost::numeric::ublas;
|
||||
|
||||
auto const& tensor_left = lhs.first;
|
||||
auto const& tensor_right = rhs.first;
|
||||
|
||||
auto multi_index_left = lhs.second;
|
||||
auto multi_index_right = rhs.second;
|
||||
|
||||
static constexpr auto num_equal_ind = number_equal_indexes<tuple_type_left, tuple_type_right>::value;
|
||||
|
||||
if constexpr ( num_equal_ind == 0 ){
|
||||
return tensor_left * tensor_right;
|
||||
}
|
||||
else if constexpr ( num_equal_ind==std::tuple_size<tuple_type_left>::value && std::is_same<tuple_type_left, tuple_type_right>::value ){
|
||||
|
||||
return boost::numeric::ublas::inner_prod( tensor_left, tensor_right );
|
||||
}
|
||||
else {
|
||||
auto array_index_pairs = index_position_pairs(multi_index_left,multi_index_right);
|
||||
auto index_pairs = array_to_vector( array_index_pairs );
|
||||
return boost::numeric::ublas::prod( tensor_left, tensor_right, index_pairs.first, index_pairs.second );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
175
include/boost/numeric/ublas/tensor/operators_comparison.hpp
Normal file
175
include/boost/numeric/ublas/tensor/operators_comparison.hpp
Normal file
@@ -0,0 +1,175 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen, Germany
|
||||
//
|
||||
|
||||
#ifndef BOOST_UBLAS_TENSOR_OPERATORS_COMPARISON_HPP
|
||||
#define BOOST_UBLAS_TENSOR_OPERATORS_COMPARISON_HPP
|
||||
|
||||
#include <boost/numeric/ublas/tensor/expression.hpp>
|
||||
#include <boost/numeric/ublas/tensor/expression_evaluation.hpp>
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
|
||||
namespace boost::numeric::ublas {
|
||||
template<class element_type, class storage_format, class storage_type>
|
||||
class tensor;
|
||||
}
|
||||
|
||||
namespace boost::numeric::ublas::detail {
|
||||
|
||||
template<class T, class F, class A, class BinaryPred>
|
||||
bool compare(tensor<T,F,A> const& lhs, tensor<T,F,A> const& rhs, BinaryPred pred)
|
||||
{
|
||||
|
||||
if(lhs.extents() != rhs.extents()){
|
||||
if constexpr(!std::is_same<BinaryPred,std::equal_to<>>::value && !std::is_same<BinaryPred,std::not_equal_to<>>::value)
|
||||
throw std::runtime_error("Error in boost::numeric::ublas::detail::compare: cannot compare tensors with different shapes.");
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if constexpr(std::is_same<BinaryPred,std::greater<>>::value || std::is_same<BinaryPred,std::less<>>::value)
|
||||
if(lhs.empty())
|
||||
return false;
|
||||
|
||||
for(auto i = 0u; i < lhs.size(); ++i)
|
||||
if(!pred(lhs(i), rhs(i)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T, class F, class A, class UnaryPred>
|
||||
bool compare(tensor<T,F,A> const& rhs, UnaryPred pred)
|
||||
{
|
||||
for(auto i = 0u; i < rhs.size(); ++i)
|
||||
if(!pred(rhs(i)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class L, class R, class BinaryPred>
|
||||
bool compare(tensor_expression<T,L> const& lhs, tensor_expression<T,R> const& rhs, BinaryPred pred)
|
||||
{
|
||||
constexpr bool lhs_is_tensor = std::is_same<T,L>::value;
|
||||
constexpr bool rhs_is_tensor = std::is_same<T,R>::value;
|
||||
|
||||
if constexpr (lhs_is_tensor && rhs_is_tensor)
|
||||
return compare(static_cast<T const&>( lhs ), static_cast<T const&>( rhs ), pred);
|
||||
else if constexpr (lhs_is_tensor && !rhs_is_tensor)
|
||||
return compare(static_cast<T const&>( lhs ), T( rhs ), pred);
|
||||
else if constexpr (!lhs_is_tensor && rhs_is_tensor)
|
||||
return compare(T( lhs ), static_cast<T const&>( rhs ), pred);
|
||||
else
|
||||
return compare(T( lhs ), T( rhs ), pred);
|
||||
|
||||
}
|
||||
|
||||
template<class T, class D, class UnaryPred>
|
||||
bool compare(tensor_expression<T,D> const& expr, UnaryPred pred)
|
||||
{
|
||||
if constexpr (std::is_same<T,D>::value)
|
||||
return compare(static_cast<T const&>( expr ), pred);
|
||||
else
|
||||
return compare(T( expr ), pred);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<class T, class L, class R>
|
||||
bool operator==( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs,
|
||||
boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::compare( lhs, rhs, std::equal_to<>{} );
|
||||
}
|
||||
template<class T, class L, class R>
|
||||
auto operator!=(boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs,
|
||||
boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::compare( lhs, rhs, std::not_equal_to<>{} );
|
||||
}
|
||||
template<class T, class L, class R>
|
||||
auto operator< ( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs,
|
||||
boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::compare( lhs, rhs, std::less<>{} );
|
||||
}
|
||||
template<class T, class L, class R>
|
||||
auto operator<=( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs,
|
||||
boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::compare( lhs, rhs, std::less_equal<>{} );
|
||||
}
|
||||
template<class T, class L, class R>
|
||||
auto operator> ( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs,
|
||||
boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::compare( lhs, rhs, std::greater<>{} );
|
||||
}
|
||||
template<class T, class L, class R>
|
||||
auto operator>=( boost::numeric::ublas::detail::tensor_expression<T,L> const& lhs,
|
||||
boost::numeric::ublas::detail::tensor_expression<T,R> const& rhs) {
|
||||
return boost::numeric::ublas::detail::compare( lhs, rhs, std::greater_equal<>{} );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T, class D>
|
||||
bool operator==( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,D> const& rhs) {
|
||||
return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs == r; } );
|
||||
}
|
||||
template<class T, class D>
|
||||
auto operator!=( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,D> const& rhs) {
|
||||
return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs != r; } );
|
||||
}
|
||||
template<class T, class D>
|
||||
auto operator< ( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,D> const& rhs) {
|
||||
return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs < r; } );
|
||||
}
|
||||
template<class T, class D>
|
||||
auto operator<=( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,D> const& rhs) {
|
||||
return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs <= r; } );
|
||||
}
|
||||
template<class T, class D>
|
||||
auto operator> ( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,D> const& rhs) {
|
||||
return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs > r; } );
|
||||
}
|
||||
template<class T, class D>
|
||||
auto operator>=( typename T::const_reference lhs, boost::numeric::ublas::detail::tensor_expression<T,D> const& rhs) {
|
||||
return boost::numeric::ublas::detail::compare( rhs, [lhs](auto const& r){ return lhs >= r; } );
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T, class D>
|
||||
bool operator==( boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs, typename T::const_reference rhs) {
|
||||
return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l == rhs; } );
|
||||
}
|
||||
template<class T, class D>
|
||||
auto operator!=( boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs, typename T::const_reference rhs) {
|
||||
return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l != rhs; } );
|
||||
}
|
||||
template<class T, class D>
|
||||
auto operator< ( boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs, typename T::const_reference rhs) {
|
||||
return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l < rhs; } );
|
||||
}
|
||||
template<class T, class D>
|
||||
auto operator<=( boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs, typename T::const_reference rhs) {
|
||||
return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l <= rhs; } );
|
||||
}
|
||||
template<class T, class D>
|
||||
auto operator> ( boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs, typename T::const_reference rhs) {
|
||||
return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l > rhs; } );
|
||||
}
|
||||
template<class T, class D>
|
||||
auto operator>=( boost::numeric::ublas::detail::tensor_expression<T,D> const& lhs, typename T::const_reference rhs) {
|
||||
return boost::numeric::ublas::detail::compare( lhs, [rhs](auto const& l){ return l >= rhs; } );
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
122
include/boost/numeric/ublas/tensor/ostream.hpp
Normal file
122
include/boost/numeric/ublas/tensor/ostream.hpp
Normal file
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen, Germany
|
||||
//
|
||||
|
||||
#ifndef BOOST_UBLAS_TENSOR_OSTREAM_HPP
|
||||
#define BOOST_UBLAS_TENSOR_OSTREAM_HPP
|
||||
|
||||
#include <ostream>
|
||||
#include <complex>
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
namespace detail {
|
||||
|
||||
template <class value_type>
|
||||
void print(std::ostream& out, value_type const& p)
|
||||
{
|
||||
out << p << " ";
|
||||
}
|
||||
|
||||
template <class value_type>
|
||||
void print(std::ostream& out, const std::complex<value_type>& p)
|
||||
{
|
||||
out << std::real(p) << "+" << std::imag(p) << "i ";
|
||||
}
|
||||
|
||||
|
||||
template <class size_type, class value_type>
|
||||
void print(std::ostream& out, size_type r, const value_type* p, const size_type* w, const size_type* n)
|
||||
{
|
||||
|
||||
if(r < 2)
|
||||
{
|
||||
out << "[ ... " << std::endl;
|
||||
|
||||
for(auto row = 0u; row < n[0]; p += w[0], ++row) // iterate over one column
|
||||
{
|
||||
auto p1 = p;
|
||||
for(auto col = 0u; col < n[1]; p1 += w[1], ++col) // iterate over first row
|
||||
{
|
||||
print(out,*p1);
|
||||
}
|
||||
if(row < n[0]-1)
|
||||
out << "; " << std::endl;
|
||||
}
|
||||
out << "]";
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "cat("<< r+1 <<",..." << std::endl;
|
||||
for(auto d = 0u; d < n[r]-1; p += w[r], ++d){
|
||||
print(out, r-1, p, w, n);
|
||||
out << ",..." << std::endl;
|
||||
}
|
||||
print(out, r-1, p, w, n);
|
||||
}
|
||||
if(r>1)
|
||||
out << ")";
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
|
||||
template<class T, class F, class A>
|
||||
class tensor;
|
||||
|
||||
template<class T, class F, class A>
|
||||
class matrix;
|
||||
|
||||
template<class T, class A>
|
||||
class vector;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class V, class F, class A>
|
||||
std::ostream& operator << (std::ostream& out, boost::numeric::ublas::tensor<V,F,A> const& t)
|
||||
{
|
||||
|
||||
if(t.extents().is_scalar()){
|
||||
out << '[';
|
||||
boost::numeric::ublas::detail::print(out,t[0]);
|
||||
out << ']';
|
||||
}
|
||||
else if(t.extents().is_vector()) {
|
||||
const auto& cat = t.extents().at(0) > t.extents().at(1) ? ';' : ',';
|
||||
out << '[';
|
||||
for(auto i = 0u; i < t.size()-1; ++i){
|
||||
boost::numeric::ublas::detail::print(out,t[i]);
|
||||
out << cat << ' ';
|
||||
}
|
||||
boost::numeric::ublas::detail::print(out,t[t.size()-1]);
|
||||
out << ']';
|
||||
}
|
||||
else{
|
||||
boost::numeric::ublas::detail::print(out, t.rank()-1, t.data(), t.strides().data(), t.extents().data());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
84
include/boost/numeric/ublas/tensor/storage_traits.hpp
Normal file
84
include/boost/numeric/ublas/tensor/storage_traits.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen Germany
|
||||
//
|
||||
|
||||
|
||||
#ifndef _BOOST_STORAGE_TRAITS_HPP_
|
||||
#define _BOOST_STORAGE_TRAITS_HPP_
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
|
||||
|
||||
template <class A>
|
||||
struct storage_traits;
|
||||
|
||||
|
||||
template <class V, class A>
|
||||
struct storage_traits<std::vector<V,A>>
|
||||
{
|
||||
using array_type = std::vector<V,A>;
|
||||
|
||||
using size_type = typename array_type::size_type;
|
||||
using difference_type = typename array_type::difference_type;
|
||||
using value_type = typename array_type::value_type;
|
||||
|
||||
using reference = typename array_type::reference;
|
||||
using const_reference = typename array_type::const_reference;
|
||||
|
||||
using pointer = typename array_type::pointer;
|
||||
using const_pointer = typename array_type::const_pointer;
|
||||
|
||||
using iterator = typename array_type::iterator;
|
||||
using const_iterator = typename array_type::const_iterator;
|
||||
|
||||
using reverse_iterator = typename array_type::reverse_iterator;
|
||||
using const_reverse_iterator = typename array_type::const_reverse_iterator;
|
||||
|
||||
template<class U>
|
||||
using rebind = std::vector<U, typename std::allocator_traits<A>::template rebind_alloc<U>>;
|
||||
};
|
||||
|
||||
|
||||
template <class V, std::size_t N>
|
||||
struct storage_traits<std::array<V,N>>
|
||||
{
|
||||
using array_type = std::array<V,N>;
|
||||
|
||||
using size_type = typename array_type::size_type;
|
||||
using difference_type = typename array_type::difference_type;
|
||||
using value_type = typename array_type::value_type;
|
||||
|
||||
using reference = typename array_type::reference;
|
||||
using const_reference = typename array_type::const_reference;
|
||||
|
||||
using pointer = typename array_type::pointer;
|
||||
using const_pointer = typename array_type::const_pointer;
|
||||
|
||||
using iterator = typename array_type::iterator;
|
||||
using const_iterator = typename array_type::const_iterator;
|
||||
|
||||
using reverse_iterator = typename array_type::reverse_iterator;
|
||||
using const_reverse_iterator = typename array_type::const_reverse_iterator;
|
||||
|
||||
template<class U>
|
||||
using rebind = std::array<U,N>;
|
||||
};
|
||||
|
||||
} // ublas
|
||||
} // numeric
|
||||
} // boost
|
||||
|
||||
|
||||
#endif // _BOOST_STORAGE_TRAITS_HPP_
|
||||
251
include/boost/numeric/ublas/tensor/strides.hpp
Normal file
251
include/boost/numeric/ublas/tensor/strides.hpp
Normal file
@@ -0,0 +1,251 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer IOSB, Ettlingen, Germany
|
||||
//
|
||||
/// \file strides.hpp Definition for the basic_strides template class
|
||||
|
||||
|
||||
#ifndef BOOST_UBLAS_TENSOR_STRIDES_HPP
|
||||
#define BOOST_UBLAS_TENSOR_STRIDES_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <initializer_list>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
#include <boost/numeric/ublas/functional.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace numeric {
|
||||
namespace ublas {
|
||||
|
||||
using first_order = column_major;
|
||||
using last_order = row_major;
|
||||
|
||||
template<class T>
|
||||
class basic_extents;
|
||||
|
||||
|
||||
/** @brief Template class for storing tensor strides for iteration with runtime variable size.
|
||||
*
|
||||
* Proxy template class of std::vector<int_type>.
|
||||
*
|
||||
*/
|
||||
template<class __int_type, class __layout>
|
||||
class basic_strides
|
||||
{
|
||||
public:
|
||||
|
||||
using base_type = std::vector<__int_type>;
|
||||
|
||||
static_assert( std::numeric_limits<typename base_type::value_type>::is_integer,
|
||||
"Static error in boost::numeric::ublas::basic_strides: type must be of type integer.");
|
||||
static_assert(!std::numeric_limits<typename base_type::value_type>::is_signed,
|
||||
"Static error in boost::numeric::ublas::basic_strides: type must be of type unsigned integer.");
|
||||
static_assert(std::is_same<__layout,first_order>::value || std::is_same<__layout,last_order>::value,
|
||||
"Static error in boost::numeric::ublas::basic_strides: layout type must either first or last order");
|
||||
|
||||
|
||||
using layout_type = __layout;
|
||||
using value_type = typename base_type::value_type;
|
||||
using reference = typename base_type::reference;
|
||||
using const_reference = typename base_type::const_reference;
|
||||
using size_type = typename base_type::size_type;
|
||||
using const_pointer = typename base_type::const_pointer;
|
||||
using const_iterator = typename base_type::const_iterator;
|
||||
|
||||
|
||||
/** @brief Default constructs basic_strides
|
||||
*
|
||||
* @code auto ex = basic_strides<unsigned>{};
|
||||
*/
|
||||
constexpr explicit basic_strides()
|
||||
: _base{}
|
||||
{
|
||||
}
|
||||
|
||||
/** @brief Constructs basic_strides from basic_extents for the first- and last-order storage formats
|
||||
*
|
||||
* @code auto strides = basic_strides<unsigned>( basic_extents<std::size_t>{2,3,4} );
|
||||
*
|
||||
*/
|
||||
template <class T>
|
||||
basic_strides(basic_extents<T> const& s)
|
||||
: _base(s.size(),1)
|
||||
{
|
||||
if(s.empty())
|
||||
return;
|
||||
|
||||
if(!s.valid())
|
||||
throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : shape is not valid.");
|
||||
|
||||
if(s.is_vector() || s.is_scalar())
|
||||
return;
|
||||
|
||||
if(this->size() < 2)
|
||||
throw std::runtime_error("Error in boost::numeric::ublas::basic_strides() : size of strides must be greater or equal 2.");
|
||||
|
||||
|
||||
if constexpr (std::is_same<layout_type,first_order>::value){
|
||||
size_type k = 1ul, kend = this->size();
|
||||
for(; k < kend; ++k)
|
||||
_base[k] = _base[k-1] * s[k-1];
|
||||
}
|
||||
else {
|
||||
size_type k = this->size()-2, kend = 0ul;
|
||||
for(; k > kend; --k)
|
||||
_base[k] = _base[k+1] * s[k+1];
|
||||
_base[0] = _base[1] * s[1];
|
||||
}
|
||||
}
|
||||
|
||||
basic_strides(basic_strides const& l)
|
||||
: _base(l._base)
|
||||
{}
|
||||
|
||||
basic_strides(basic_strides && l )
|
||||
: _base(std::move(l._base))
|
||||
{}
|
||||
|
||||
basic_strides(base_type const& l )
|
||||
: _base(l)
|
||||
{}
|
||||
|
||||
basic_strides(base_type && l )
|
||||
: _base(std::move(l))
|
||||
{}
|
||||
|
||||
~basic_strides() = default;
|
||||
|
||||
|
||||
basic_strides& operator=(basic_strides other)
|
||||
{
|
||||
swap (*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend void swap(basic_strides& lhs, basic_strides& rhs) {
|
||||
std::swap(lhs._base , rhs._base);
|
||||
}
|
||||
|
||||
const_reference operator[] (size_type p) const{
|
||||
return _base[p];
|
||||
}
|
||||
|
||||
const_pointer data() const{
|
||||
return _base.data();
|
||||
}
|
||||
|
||||
const_reference at (size_type p) const{
|
||||
return _base.at(p);
|
||||
}
|
||||
|
||||
|
||||
bool empty() const{
|
||||
return _base.empty();
|
||||
}
|
||||
|
||||
size_type size() const{
|
||||
return _base.size();
|
||||
}
|
||||
|
||||
template<class other_layout>
|
||||
bool operator == (basic_strides<value_type, other_layout> const& b) const{
|
||||
return b.base() == this->base();
|
||||
}
|
||||
|
||||
template<class other_layout>
|
||||
bool operator != (basic_strides<value_type, other_layout> const& b) const{
|
||||
return b.base() != this->base();
|
||||
}
|
||||
|
||||
bool operator == (basic_strides const& b) const{
|
||||
return b._base == _base;
|
||||
}
|
||||
|
||||
bool operator != (basic_strides const& b) const{
|
||||
return b._base != _base;
|
||||
}
|
||||
|
||||
const_iterator begin() const{
|
||||
return _base.begin();
|
||||
}
|
||||
|
||||
const_iterator end() const{
|
||||
return _base.end();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
this->_base.clear();
|
||||
}
|
||||
|
||||
base_type const& base() const{
|
||||
return this->_base;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
base_type _base;
|
||||
};
|
||||
|
||||
template<class layout_type>
|
||||
using strides = basic_strides<std::size_t, layout_type>;
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
/** @brief Returns relative memory index with respect to a multi-index
|
||||
*
|
||||
* @code auto j = access(std::vector{3,4,5}, strides{shape{4,2,3},first_order}); @endcode
|
||||
*
|
||||
* @param[in] i multi-index of length p
|
||||
* @param[in] w stride vector of length p
|
||||
* @returns relative memory location depending on \c i and \c w
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
template<class size_type, class layout_type>
|
||||
auto access(std::vector<size_type> const& i, basic_strides<size_type,layout_type> const& w)
|
||||
{
|
||||
const auto p = i.size();
|
||||
size_type sum = 0u;
|
||||
for(auto r = 0u; r < p; ++r)
|
||||
sum += i[r]*w[r];
|
||||
return sum;
|
||||
}
|
||||
|
||||
/** @brief Returns relative memory index with respect to a multi-index
|
||||
*
|
||||
* @code auto j = access(0, strides{shape{4,2,3},first_order}, 2,3,4); @endcode
|
||||
*
|
||||
* @param[in] i first element of the partial multi-index
|
||||
* @param[in] is the following elements of the partial multi-index
|
||||
* @param[in] sum the current relative memory index
|
||||
* @returns relative memory location depending on \c i and \c w
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
template<std::size_t r, class layout_type, class ... size_types>
|
||||
auto access(std::size_t sum, basic_strides<std::size_t, layout_type> const& w, std::size_t i, size_types ... is)
|
||||
{
|
||||
sum+=i*w[r];
|
||||
if constexpr (sizeof...(is) == 0)
|
||||
return sum;
|
||||
else
|
||||
return detail::access<r+1>(sum,w,std::forward<size_types>(is)...);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
734
include/boost/numeric/ublas/tensor/tensor.hpp
Normal file
734
include/boost/numeric/ublas/tensor/tensor.hpp
Normal file
@@ -0,0 +1,734 @@
|
||||
// Copyright (c) 2018-2019
|
||||
// Cem Bassoy
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// Fraunhofer and Google in producing this work
|
||||
// which started as a Google Summer of Code project.
|
||||
//
|
||||
|
||||
|
||||
/// \file tensor.hpp Definition for the tensor template class
|
||||
|
||||
#ifndef BOOST_UBLAS_TENSOR_IMPL_HPP
|
||||
#define BOOST_UBLAS_TENSOR_IMPL_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
#include "algorithms.hpp"
|
||||
#include "expression.hpp"
|
||||
#include "expression_evaluation.hpp"
|
||||
#include "extents.hpp"
|
||||
#include "strides.hpp"
|
||||
#include "index.hpp"
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
template<class T, class F, class A>
|
||||
class tensor;
|
||||
|
||||
template<class T, class F, class A>
|
||||
class matrix;
|
||||
|
||||
template<class T, class A>
|
||||
class vector;
|
||||
|
||||
///** \brief Base class for Tensor container models
|
||||
// *
|
||||
// * it does not model the Tensor concept but all derived types should.
|
||||
// * The class defines a common base type and some common interface for all
|
||||
// * statically derived Tensor classes
|
||||
// * We implement the casts to the statically derived type.
|
||||
// */
|
||||
//template<class C>
|
||||
//class tensor_container:
|
||||
// public detail::tensor_expression<C>
|
||||
//{
|
||||
//public:
|
||||
// static const unsigned complexity = 0;
|
||||
// typedef C container_type;
|
||||
// typedef tensor_tag type_category;
|
||||
|
||||
// BOOST_UBLAS_INLINE
|
||||
// const container_type &operator () () const {
|
||||
// return *static_cast<const container_type *> (this);
|
||||
// }
|
||||
// BOOST_UBLAS_INLINE
|
||||
// container_type &operator () () {
|
||||
// return *static_cast<container_type *> (this);
|
||||
// }
|
||||
//};
|
||||
|
||||
|
||||
|
||||
/** @brief A dense tensor of values of type \c T.
|
||||
*
|
||||
* For a \f$n\f$-dimensional tensor \f$v\f$ and \f$0\leq i < n\f$ every element \f$v_i\f$ is mapped
|
||||
* to the \f$i\f$-th element of the container. A storage type \c A can be specified which defaults to \c unbounded_array.
|
||||
* Elements are constructed by \c A, which need not initialise their value.
|
||||
*
|
||||
* @tparam T type of the objects stored in the tensor (like int, double, complex,...)
|
||||
* @tparam A The type of the storage array of the tensor. Default is \c unbounded_array<T>. \c <bounded_array<T> and \c std::vector<T> can also be used
|
||||
*/
|
||||
template<class T, class F = first_order, class A = std::vector<T,std::allocator<T>> >
|
||||
class tensor:
|
||||
public detail::tensor_expression<tensor<T, F, A>,tensor<T, F, A>>
|
||||
{
|
||||
|
||||
static_assert( std::is_same<F,first_order>::value ||
|
||||
std::is_same<F,last_order >::value, "boost::numeric::tensor template class only supports first- or last-order storage formats.");
|
||||
|
||||
using self_type = tensor<T, F, A>;
|
||||
public:
|
||||
|
||||
|
||||
|
||||
template<class derived_type>
|
||||
using tensor_expression_type = detail::tensor_expression<self_type,derived_type>;
|
||||
|
||||
template<class derived_type>
|
||||
using matrix_expression_type = matrix_expression<derived_type>;
|
||||
|
||||
template<class derived_type>
|
||||
using vector_expression_type = vector_expression<derived_type>;
|
||||
|
||||
using super_type = tensor_expression_type<self_type>;
|
||||
|
||||
// static_assert(std::is_same_v<tensor_expression_type<self_type>, detail::tensor_expression<tensor<T,F,A>,tensor<T,F,A>>>, "tensor_expression_type<self_type>");
|
||||
|
||||
using array_type = A;
|
||||
using layout_type = F;
|
||||
|
||||
|
||||
using size_type = typename array_type::size_type;
|
||||
using difference_type = typename array_type::difference_type;
|
||||
using value_type = typename array_type::value_type;
|
||||
|
||||
using reference = typename array_type::reference;
|
||||
using const_reference = typename array_type::const_reference;
|
||||
|
||||
using pointer = typename array_type::pointer;
|
||||
using const_pointer = typename array_type::const_pointer;
|
||||
|
||||
using iterator = typename array_type::iterator;
|
||||
using const_iterator = typename array_type::const_iterator;
|
||||
|
||||
using reverse_iterator = typename array_type::reverse_iterator;
|
||||
using const_reverse_iterator = typename array_type::const_reverse_iterator;
|
||||
|
||||
using tensor_temporary_type = self_type;
|
||||
using storage_category = dense_tag;
|
||||
|
||||
using strides_type = basic_strides<std::size_t,layout_type>;
|
||||
using extents_type = shape;
|
||||
|
||||
using matrix_type = matrix<value_type,layout_type,array_type>;
|
||||
using vector_type = vector<value_type,array_type>;
|
||||
|
||||
|
||||
/** @brief Constructs a tensor.
|
||||
*
|
||||
* @note the tensor is empty.
|
||||
* @note the tensor needs to reshaped for further use.
|
||||
*
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
constexpr tensor ()
|
||||
: tensor_expression_type<self_type>() // container_type
|
||||
, extents_()
|
||||
, strides_()
|
||||
, data_()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/** @brief Constructs a tensor with an initializer list
|
||||
*
|
||||
* By default, its elements are initialized to 0.
|
||||
*
|
||||
* @code tensor<float> A{4,2,3}; @endcode
|
||||
*
|
||||
* @param l initializer list for setting the dimension extents of the tensor
|
||||
*/
|
||||
explicit BOOST_UBLAS_INLINE
|
||||
tensor (std::initializer_list<size_type> l)
|
||||
: tensor_expression_type<self_type>()
|
||||
, extents_ (std::move(l))
|
||||
, strides_ (extents_)
|
||||
, data_ (extents_.product())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/** @brief Constructs a tensor with a \c shape
|
||||
*
|
||||
* By default, its elements are initialized to 0.
|
||||
*
|
||||
* @code tensor<float> A{extents{4,2,3}}; @endcode
|
||||
*
|
||||
* @param s initial tensor dimension extents
|
||||
*/
|
||||
explicit BOOST_UBLAS_INLINE
|
||||
tensor (extents_type const& s)
|
||||
: tensor_expression_type<self_type>() //tensor_container<self_type>()
|
||||
, extents_ (s)
|
||||
, strides_ (extents_)
|
||||
, data_ (extents_.product())
|
||||
{}
|
||||
|
||||
|
||||
/** @brief Constructs a tensor with a \c shape and initiates it with one-dimensional data
|
||||
*
|
||||
* @code tensor<float> A{extents{4,2,3}, array }; @endcode
|
||||
*
|
||||
*
|
||||
* @param s initial tensor dimension extents
|
||||
* @param a container of \c array_type that is copied according to the storage layout
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
tensor (extents_type const& s, const array_type &a)
|
||||
: tensor_expression_type<self_type>() //tensor_container<self_type>()
|
||||
, extents_ (s)
|
||||
, strides_ (extents_)
|
||||
, data_ (a)
|
||||
{
|
||||
if(this->extents_.product() != this->data_.size())
|
||||
throw std::runtime_error("Error in boost::numeric::ublas::tensor: size of provided data and specified extents do not match.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @brief Constructs a tensor using a shape tuple and initiates it with a value.
|
||||
*
|
||||
* @code tensor<float> A{extents{4,2,3}, 1 }; @endcode
|
||||
*
|
||||
* @param e initial tensor dimension extents
|
||||
* @param i initial value of all elements of type \c value_type
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
tensor (extents_type const& e, const value_type &i)
|
||||
: tensor_expression_type<self_type>() //tensor_container<self_type> ()
|
||||
, extents_ (e)
|
||||
, strides_ (extents_)
|
||||
, data_ (extents_.product(), i)
|
||||
{}
|
||||
|
||||
|
||||
|
||||
/** @brief Constructs a tensor from another tensor
|
||||
*
|
||||
* @param v tensor to be copied.
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
tensor (const tensor &v)
|
||||
: tensor_expression_type<self_type>()
|
||||
, extents_ (v.extents_)
|
||||
, strides_ (v.strides_)
|
||||
, data_ (v.data_ )
|
||||
{}
|
||||
|
||||
|
||||
|
||||
/** @brief Constructs a tensor from another tensor
|
||||
*
|
||||
* @param v tensor to be moved.
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
tensor (tensor &&v)
|
||||
: tensor_expression_type<self_type>() //tensor_container<self_type> ()
|
||||
, extents_ (std::move(v.extents_))
|
||||
, strides_ (std::move(v.strides_))
|
||||
, data_ (std::move(v.data_ ))
|
||||
{}
|
||||
|
||||
|
||||
/** @brief Constructs a tensor with a matrix
|
||||
*
|
||||
* \note Initially the tensor will be two-dimensional.
|
||||
*
|
||||
* @param v matrix to be copied.
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
tensor (const matrix_type &v)
|
||||
: tensor_expression_type<self_type>()
|
||||
, extents_ ()
|
||||
, strides_ ()
|
||||
, data_ (v.data())
|
||||
{
|
||||
if(!data_.empty()){
|
||||
extents_ = extents_type{v.size1(),v.size2()};
|
||||
strides_ = strides_type(extents_);
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Constructs a tensor with a matrix
|
||||
*
|
||||
* \note Initially the tensor will be two-dimensional.
|
||||
*
|
||||
* @param v matrix to be moved.
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
tensor (matrix_type &&v)
|
||||
: tensor_expression_type<self_type>()
|
||||
, extents_ {}
|
||||
, strides_ {}
|
||||
, data_ {}
|
||||
{
|
||||
if(v.size1()*v.size2() != 0){
|
||||
extents_ = extents_type{v.size1(),v.size2()};
|
||||
strides_ = strides_type(extents_);
|
||||
data_ = std::move(v.data());
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Constructs a tensor using a \c vector
|
||||
*
|
||||
* @note It is assumed that vector is column vector
|
||||
* @note Initially the tensor will be one-dimensional.
|
||||
*
|
||||
* @param v vector to be copied.
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
tensor (const vector_type &v)
|
||||
: tensor_expression_type<self_type>()
|
||||
, extents_ ()
|
||||
, strides_ ()
|
||||
, data_ (v.data())
|
||||
{
|
||||
if(!data_.empty()){
|
||||
extents_ = extents_type{data_.size(),1};
|
||||
strides_ = strides_type(extents_);
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Constructs a tensor using a \c vector
|
||||
*
|
||||
* @param v vector to be moved.
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
tensor (vector_type &&v)
|
||||
: tensor_expression_type<self_type>()
|
||||
, extents_ {}
|
||||
, strides_ {}
|
||||
, data_ {}
|
||||
{
|
||||
if(v.size() != 0){
|
||||
extents_ = extents_type{v.size(),1};
|
||||
strides_ = strides_type(extents_);
|
||||
data_ = std::move(v.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @brief Constructs a tensor with another tensor with a different layout
|
||||
*
|
||||
* @param other tensor with a different layout to be copied.
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
template<class other_layout>
|
||||
tensor (const tensor<value_type, other_layout> &other)
|
||||
: tensor_expression_type<self_type> ()
|
||||
, extents_ (other.extents())
|
||||
, strides_ (other.extents())
|
||||
, data_ (other.extents().product())
|
||||
{
|
||||
copy(this->rank(), this->extents().data(),
|
||||
this->data(), this->strides().data(),
|
||||
other.data(), other.strides().data());
|
||||
}
|
||||
|
||||
/** @brief Constructs a tensor with an tensor expression
|
||||
*
|
||||
* @code tensor<float> A = B + 3 * C; @endcode
|
||||
*
|
||||
* @note type must be specified of tensor must be specified.
|
||||
* @note dimension extents are extracted from tensors within the expression.
|
||||
*
|
||||
* @param expr tensor expression
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
template<class derived_type>
|
||||
tensor (const tensor_expression_type<derived_type> &expr)
|
||||
: tensor_expression_type<self_type> ()
|
||||
, extents_ ( detail::retrieve_extents(expr) )
|
||||
, strides_ ( extents_ )
|
||||
, data_ ( extents_.product() )
|
||||
{
|
||||
static_assert( detail::has_tensor_types<self_type, tensor_expression_type<derived_type>>::value,
|
||||
"Error in boost::numeric::ublas::tensor: expression does not contain a tensor. cannot retrieve shape.");
|
||||
detail::eval( *this, expr );
|
||||
}
|
||||
|
||||
/** @brief Constructs a tensor with a matrix expression
|
||||
*
|
||||
* @code tensor<float> A = B + 3 * C; @endcode
|
||||
*
|
||||
* @note matrix expression is evaluated and pushed into a temporary matrix before assignment.
|
||||
* @note extents are automatically extracted from the temporary matrix
|
||||
*
|
||||
* @param expr matrix expression
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
template<class derived_type>
|
||||
tensor (const matrix_expression_type<derived_type> &expr)
|
||||
: tensor( matrix_type ( expr ) )
|
||||
{
|
||||
}
|
||||
|
||||
/** @brief Constructs a tensor with a vector expression
|
||||
*
|
||||
* @code tensor<float> A = b + 3 * b; @endcode
|
||||
*
|
||||
* @note matrix expression is evaluated and pushed into a temporary matrix before assignment.
|
||||
* @note extents are automatically extracted from the temporary matrix
|
||||
*
|
||||
* @param expr vector expression
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
template<class derived_type>
|
||||
tensor (const vector_expression_type<derived_type> &expr)
|
||||
: tensor( vector_type ( expr ) )
|
||||
{
|
||||
}
|
||||
|
||||
/** @brief Evaluates the tensor_expression and assigns the results to the tensor
|
||||
*
|
||||
* @code A = B + C * 2; @endcode
|
||||
*
|
||||
* @note rank and dimension extents of the tensors in the expressions must conform with this tensor.
|
||||
*
|
||||
* @param expr expression that is evaluated.
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
template<class derived_type>
|
||||
tensor &operator = (const tensor_expression_type<derived_type> &expr)
|
||||
{
|
||||
detail::eval(*this, expr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
tensor& operator=(tensor other)
|
||||
{
|
||||
swap (*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
tensor& operator=(const_reference v)
|
||||
{
|
||||
std::fill(this->begin(), this->end(), v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Returns true if the tensor is empty (\c size==0) */
|
||||
BOOST_UBLAS_INLINE
|
||||
bool empty () const {
|
||||
return this->data_.empty();
|
||||
}
|
||||
|
||||
|
||||
/** @brief Returns the size of the tensor */
|
||||
BOOST_UBLAS_INLINE
|
||||
size_type size () const {
|
||||
return this->data_.size ();
|
||||
}
|
||||
|
||||
/** @brief Returns the size of the tensor */
|
||||
BOOST_UBLAS_INLINE
|
||||
size_type size (size_type r) const {
|
||||
return this->extents_.at(r);
|
||||
}
|
||||
|
||||
/** @brief Returns the number of dimensions/modes of the tensor */
|
||||
BOOST_UBLAS_INLINE
|
||||
size_type rank () const {
|
||||
return this->extents_.size();
|
||||
}
|
||||
|
||||
/** @brief Returns the number of dimensions/modes of the tensor */
|
||||
BOOST_UBLAS_INLINE
|
||||
size_type order () const {
|
||||
return this->extents_.size();
|
||||
}
|
||||
|
||||
/** @brief Returns the strides of the tensor */
|
||||
BOOST_UBLAS_INLINE
|
||||
strides_type const& strides () const {
|
||||
return this->strides_;
|
||||
}
|
||||
|
||||
/** @brief Returns the extents of the tensor */
|
||||
BOOST_UBLAS_INLINE
|
||||
extents_type const& extents () const {
|
||||
return this->extents_;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Returns a \c const reference to the container. */
|
||||
BOOST_UBLAS_INLINE
|
||||
const_pointer data () const {
|
||||
return this->data_.data();
|
||||
}
|
||||
|
||||
/** @brief Returns a \c const reference to the container. */
|
||||
BOOST_UBLAS_INLINE
|
||||
pointer data () {
|
||||
return this->data_.data();
|
||||
}
|
||||
|
||||
/** @brief Element access using a single index.
|
||||
*
|
||||
* @code auto a = A[i]; @endcode
|
||||
*
|
||||
* @param i zero-based index where 0 <= i < this->size()
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reference operator [] (size_type i) const {
|
||||
return this->data_[i];
|
||||
}
|
||||
|
||||
/** @brief Element access using a single index.
|
||||
*
|
||||
*
|
||||
* @code A[i] = a; @endcode
|
||||
*
|
||||
* @param i zero-based index where 0 <= i < this->size()
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
reference operator [] (size_type i)
|
||||
{
|
||||
return this->data_[i];
|
||||
}
|
||||
|
||||
|
||||
/** @brief Element access using a multi-index or single-index.
|
||||
*
|
||||
*
|
||||
* @code auto a = A.at(i,j,k); @endcode or
|
||||
* @code auto a = A.at(i); @endcode
|
||||
*
|
||||
* @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0)
|
||||
* @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank()
|
||||
*/
|
||||
template<class ... size_types>
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reference at (size_type i, size_types ... is) const {
|
||||
if constexpr (sizeof...(is) == 0)
|
||||
return this->data_[i];
|
||||
else
|
||||
return this->data_[detail::access<0ul>(size_type(0),this->strides_,i,std::forward<size_types>(is)...)];
|
||||
}
|
||||
|
||||
/** @brief Element access using a multi-index or single-index.
|
||||
*
|
||||
*
|
||||
* @code A.at(i,j,k) = a; @endcode or
|
||||
* @code A.at(i) = a; @endcode
|
||||
*
|
||||
* @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0)
|
||||
* @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank()
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
template<class ... size_types>
|
||||
reference at (size_type i, size_types ... is) {
|
||||
if constexpr (sizeof...(is) == 0)
|
||||
return this->data_[i];
|
||||
else
|
||||
return this->data_[detail::access<0ul>(size_type(0),this->strides_,i,std::forward<size_types>(is)...)];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Element access using a single index.
|
||||
*
|
||||
*
|
||||
* @code A(i) = a; @endcode
|
||||
*
|
||||
* @param i zero-based index where 0 <= i < this->size()
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reference operator()(size_type i) const {
|
||||
return this->data_[i];
|
||||
}
|
||||
|
||||
|
||||
/** @brief Element access using a single index.
|
||||
*
|
||||
* @code A(i) = a; @endcode
|
||||
*
|
||||
* @param i zero-based index where 0 <= i < this->size()
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
reference operator()(size_type i){
|
||||
return this->data_[i];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Generates a tensor index for tensor contraction
|
||||
*
|
||||
*
|
||||
* @code auto Ai = A(_i,_j,k); @endcode
|
||||
*
|
||||
* @param i placeholder
|
||||
* @param is zero-based indices where 0 <= is[r] < this->size(r) where 0 < r < this->rank()
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
template<std::size_t I, class ... index_types>
|
||||
decltype(auto) operator() (index::index_type<I> p, index_types ... ps) const
|
||||
{
|
||||
constexpr auto N = sizeof...(ps)+1;
|
||||
if( N != this->rank() )
|
||||
throw std::runtime_error("Error in boost::numeric::ublas::operator(): size of provided index_types does not match with the rank.");
|
||||
|
||||
return std::make_pair( std::cref(*this), std::make_tuple( p, std::forward<index_types>(ps)... ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Reshapes the tensor
|
||||
*
|
||||
*
|
||||
* (1) @code A.reshape(extents{m,n,o}); @endcode or
|
||||
* (2) @code A.reshape(extents{m,n,o},4); @endcode
|
||||
*
|
||||
* If the size of this smaller than the specified extents than
|
||||
* default constructed (1) or specified (2) value is appended.
|
||||
*
|
||||
* @note rank of the tensor might also change.
|
||||
*
|
||||
* @param e extents with which the tensor is reshaped.
|
||||
* @param v value which is appended if the tensor is enlarged.
|
||||
*/
|
||||
BOOST_UBLAS_INLINE
|
||||
void reshape (extents_type const& e, value_type v = value_type{})
|
||||
{
|
||||
this->extents_ = e;
|
||||
this->strides_ = strides_type(this->extents_);
|
||||
|
||||
if(e.product() != this->size())
|
||||
this->data_.resize (this->extents_.product(), v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
friend void swap(tensor& lhs, tensor& rhs) {
|
||||
std::swap(lhs.data_ , rhs.data_ );
|
||||
std::swap(lhs.extents_, rhs.extents_);
|
||||
std::swap(lhs.strides_, rhs.strides_);
|
||||
}
|
||||
|
||||
|
||||
/// \brief return an iterator on the first element of the tensor
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator begin () const {
|
||||
return data_.begin ();
|
||||
}
|
||||
|
||||
/// \brief return an iterator on the first element of the tensor
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator cbegin () const {
|
||||
return data_.cbegin ();
|
||||
}
|
||||
|
||||
/// \brief return an iterator after the last element of the tensor
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator end () const {
|
||||
return data_.end();
|
||||
}
|
||||
|
||||
/// \brief return an iterator after the last element of the tensor
|
||||
BOOST_UBLAS_INLINE
|
||||
const_iterator cend () const {
|
||||
return data_.cend ();
|
||||
}
|
||||
|
||||
/// \brief Return an iterator on the first element of the tensor
|
||||
BOOST_UBLAS_INLINE
|
||||
iterator begin () {
|
||||
return data_.begin();
|
||||
}
|
||||
|
||||
/// \brief Return an iterator at the end of the tensor
|
||||
BOOST_UBLAS_INLINE
|
||||
iterator end () {
|
||||
return data_.end();
|
||||
}
|
||||
|
||||
/// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor)
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator rbegin () const {
|
||||
return data_.rbegin();
|
||||
}
|
||||
|
||||
/// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor)
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator crbegin () const {
|
||||
return data_.crbegin();
|
||||
}
|
||||
|
||||
/// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor)
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator rend () const {
|
||||
return data_.rend();
|
||||
}
|
||||
|
||||
/// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor)
|
||||
BOOST_UBLAS_INLINE
|
||||
const_reverse_iterator crend () const {
|
||||
return data_.crend();
|
||||
}
|
||||
|
||||
/// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor)
|
||||
BOOST_UBLAS_INLINE
|
||||
reverse_iterator rbegin () {
|
||||
return data_.rbegin();
|
||||
}
|
||||
|
||||
/// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor)
|
||||
BOOST_UBLAS_INLINE
|
||||
reverse_iterator rend () {
|
||||
return data_.rend();
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
// -------------
|
||||
// Serialization
|
||||
// -------------
|
||||
|
||||
/// Serialize a tensor into and archive as defined in Boost
|
||||
/// \param ar Archive object. Can be a flat file, an XML file or any other stream
|
||||
/// \param file_version Optional file version (not yet used)
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar, const unsigned int /* file_version */){
|
||||
ar & serialization::make_nvp("data",data_);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
extents_type extents_;
|
||||
strides_type strides_;
|
||||
array_type data_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
753
include/boost/numeric/ublas/traits.hpp
Normal file
753
include/boost/numeric/ublas/traits.hpp
Normal file
@@ -0,0 +1,753 @@
|
||||
//
|
||||
// Copyright (c) 2000-2002
|
||||
// Joerg Walter, Mathias Koch
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// The authors gratefully acknowledge the support of
|
||||
// GeNeSys mbH & Co. KG in producing this work.
|
||||
//
|
||||
|
||||
#ifndef _BOOST_UBLAS_TRAITS_
|
||||
#define _BOOST_UBLAS_TRAITS_
|
||||
|
||||
#include <iterator>
|
||||
#include <complex>
|
||||
#include <boost/config/no_tr1/cmath.hpp>
|
||||
|
||||
#include <boost/numeric/ublas/detail/config.hpp>
|
||||
#include <boost/numeric/ublas/detail/iterator.hpp>
|
||||
#include <boost/numeric/ublas/detail/returntype_deduction.hpp>
|
||||
#ifdef BOOST_UBLAS_USE_INTERVAL
|
||||
#include <boost/numeric/interval.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <complex>
|
||||
#include <boost/typeof/typeof.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/is_float.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/type_traits/is_unsigned.hpp>
|
||||
#include <boost/mpl/and.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/typeof/typeof.hpp>
|
||||
|
||||
|
||||
// anonymous namespace to avoid ADL issues
|
||||
namespace {
|
||||
template<class T>
|
||||
typename boost::mpl::if_c<boost::is_integral<T>::value,
|
||||
double,
|
||||
T>::type
|
||||
boost_numeric_ublas_sqrt (const T& t) {
|
||||
using namespace std;
|
||||
// we'll find either std::sqrt or else another version via ADL:
|
||||
return sqrt (t);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename boost::disable_if<
|
||||
boost::is_unsigned<T>, T >::type
|
||||
boost_numeric_ublas_abs (const T &t ) {
|
||||
using namespace std;
|
||||
// force a type conversion back to T for char and short types
|
||||
return static_cast<T>(abs( t ));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename boost::enable_if<
|
||||
boost::is_unsigned<T>, T >::type
|
||||
boost_numeric_ublas_abs (const T &t ) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
|
||||
template<typename R, typename I>
|
||||
typename boost::enable_if<
|
||||
mpl::and_<
|
||||
boost::is_float<R>,
|
||||
boost::is_integral<I>
|
||||
>,
|
||||
std::complex<R> >::type inline operator+ (I in1, std::complex<R> const& in2 ) {
|
||||
return R (in1) + in2;
|
||||
}
|
||||
|
||||
template<typename R, typename I>
|
||||
typename boost::enable_if<
|
||||
mpl::and_<
|
||||
boost::is_float<R>,
|
||||
boost::is_integral<I>
|
||||
>,
|
||||
std::complex<R> >::type inline operator+ (std::complex<R> const& in1, I in2) {
|
||||
return in1 + R (in2);
|
||||
}
|
||||
|
||||
template<typename R, typename I>
|
||||
typename boost::enable_if<
|
||||
mpl::and_<
|
||||
boost::is_float<R>,
|
||||
boost::is_integral<I>
|
||||
>,
|
||||
std::complex<R> >::type inline operator- (I in1, std::complex<R> const& in2) {
|
||||
return R (in1) - in2;
|
||||
}
|
||||
|
||||
template<typename R, typename I>
|
||||
typename boost::enable_if<
|
||||
mpl::and_<
|
||||
boost::is_float<R>,
|
||||
boost::is_integral<I>
|
||||
>,
|
||||
std::complex<R> >::type inline operator- (std::complex<R> const& in1, I in2) {
|
||||
return in1 - R (in2);
|
||||
}
|
||||
|
||||
template<typename R, typename I>
|
||||
typename boost::enable_if<
|
||||
mpl::and_<
|
||||
boost::is_float<R>,
|
||||
boost::is_integral<I>
|
||||
>,
|
||||
std::complex<R> >::type inline operator* (I in1, std::complex<R> const& in2) {
|
||||
return R (in1) * in2;
|
||||
}
|
||||
|
||||
template<typename R, typename I>
|
||||
typename boost::enable_if<
|
||||
mpl::and_<
|
||||
boost::is_float<R>,
|
||||
boost::is_integral<I>
|
||||
>,
|
||||
std::complex<R> >::type inline operator* (std::complex<R> const& in1, I in2) {
|
||||
return in1 * R(in2);
|
||||
}
|
||||
|
||||
template<typename R, typename I>
|
||||
typename boost::enable_if<
|
||||
mpl::and_<
|
||||
boost::is_float<R>,
|
||||
boost::is_integral<I>
|
||||
>,
|
||||
std::complex<R> >::type inline operator/ (I in1, std::complex<R> const& in2) {
|
||||
return R(in1) / in2;
|
||||
}
|
||||
|
||||
template<typename R, typename I>
|
||||
typename boost::enable_if<
|
||||
mpl::and_<
|
||||
boost::is_float<R>,
|
||||
boost::is_integral<I>
|
||||
>,
|
||||
std::complex<R> >::type inline operator/ (std::complex<R> const& in1, I in2) {
|
||||
return in1 / R (in2);
|
||||
}
|
||||
|
||||
// uBLAS assumes a common return type for all binary arithmetic operators
|
||||
template<class X, class Y>
|
||||
struct promote_traits {
|
||||
typedef BOOST_TYPEOF_TPL(X() + Y()) promote_type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Type traits - generic numeric properties and functions
|
||||
template<class T>
|
||||
struct type_traits;
|
||||
|
||||
// Define properties for a generic scalar type
|
||||
template<class T>
|
||||
struct scalar_traits {
|
||||
typedef scalar_traits<T> self_type;
|
||||
typedef T value_type;
|
||||
typedef const T &const_reference;
|
||||
typedef T &reference;
|
||||
|
||||
typedef T real_type;
|
||||
typedef real_type precision_type; // we do not know what type has more precision then the real_type
|
||||
|
||||
static const unsigned plus_complexity = 1;
|
||||
static const unsigned multiplies_complexity = 1;
|
||||
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
real_type real (const_reference t) {
|
||||
return t;
|
||||
}
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
real_type imag (const_reference /*t*/) {
|
||||
return 0;
|
||||
}
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
value_type conj (const_reference t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
real_type type_abs (const_reference t) {
|
||||
return boost_numeric_ublas_abs (t);
|
||||
}
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
value_type type_sqrt (const_reference t) {
|
||||
// force a type conversion back to value_type for intgral types
|
||||
return value_type (boost_numeric_ublas_sqrt (t));
|
||||
}
|
||||
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
real_type norm_1 (const_reference t) {
|
||||
return self_type::type_abs (t);
|
||||
}
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
real_type norm_2 (const_reference t) {
|
||||
return self_type::type_abs (t);
|
||||
}
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
real_type norm_inf (const_reference t) {
|
||||
return self_type::type_abs (t);
|
||||
}
|
||||
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
bool equals (const_reference t1, const_reference t2) {
|
||||
return self_type::norm_inf (t1 - t2) < BOOST_UBLAS_TYPE_CHECK_EPSILON *
|
||||
(std::max) ((std::max) (self_type::norm_inf (t1),
|
||||
self_type::norm_inf (t2)),
|
||||
BOOST_UBLAS_TYPE_CHECK_MIN);
|
||||
}
|
||||
};
|
||||
|
||||
// Define default type traits, assume T is a scalar type
|
||||
template<class T>
|
||||
struct type_traits : scalar_traits <T> {
|
||||
typedef type_traits<T> self_type;
|
||||
typedef T value_type;
|
||||
typedef const T &const_reference;
|
||||
typedef T &reference;
|
||||
|
||||
typedef T real_type;
|
||||
typedef real_type precision_type;
|
||||
static const unsigned multiplies_complexity = 1;
|
||||
|
||||
};
|
||||
|
||||
// Define real type traits
|
||||
template<>
|
||||
struct type_traits<float> : scalar_traits<float> {
|
||||
typedef type_traits<float> self_type;
|
||||
typedef float value_type;
|
||||
typedef const value_type &const_reference;
|
||||
typedef value_type &reference;
|
||||
typedef value_type real_type;
|
||||
typedef double precision_type;
|
||||
};
|
||||
template<>
|
||||
struct type_traits<double> : scalar_traits<double> {
|
||||
typedef type_traits<double> self_type;
|
||||
typedef double value_type;
|
||||
typedef const value_type &const_reference;
|
||||
typedef value_type &reference;
|
||||
typedef value_type real_type;
|
||||
typedef long double precision_type;
|
||||
};
|
||||
template<>
|
||||
struct type_traits<long double> : scalar_traits<long double> {
|
||||
typedef type_traits<long double> self_type;
|
||||
typedef long double value_type;
|
||||
typedef const value_type &const_reference;
|
||||
typedef value_type &reference;
|
||||
typedef value_type real_type;
|
||||
typedef value_type precision_type;
|
||||
};
|
||||
|
||||
// Define properties for a generic complex type
|
||||
template<class T>
|
||||
struct complex_traits {
|
||||
typedef complex_traits<T> self_type;
|
||||
typedef T value_type;
|
||||
typedef const T &const_reference;
|
||||
typedef T &reference;
|
||||
|
||||
typedef typename T::value_type real_type;
|
||||
typedef real_type precision_type; // we do not know what type has more precision then the real_type
|
||||
|
||||
static const unsigned plus_complexity = 2;
|
||||
static const unsigned multiplies_complexity = 6;
|
||||
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
real_type real (const_reference t) {
|
||||
return std::real (t);
|
||||
}
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
real_type imag (const_reference t) {
|
||||
return std::imag (t);
|
||||
}
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
value_type conj (const_reference t) {
|
||||
return std::conj (t);
|
||||
}
|
||||
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
real_type type_abs (const_reference t) {
|
||||
return abs (t);
|
||||
}
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
value_type type_sqrt (const_reference t) {
|
||||
return sqrt (t);
|
||||
}
|
||||
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
real_type norm_1 (const_reference t) {
|
||||
return self_type::type_abs (t);
|
||||
// original computation has been replaced because a complex number should behave like a scalar type
|
||||
// return type_traits<real_type>::type_abs (self_type::real (t)) +
|
||||
// type_traits<real_type>::type_abs (self_type::imag (t));
|
||||
}
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
real_type norm_2 (const_reference t) {
|
||||
return self_type::type_abs (t);
|
||||
}
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
real_type norm_inf (const_reference t) {
|
||||
return self_type::type_abs (t);
|
||||
// original computation has been replaced because a complex number should behave like a scalar type
|
||||
// return (std::max) (type_traits<real_type>::type_abs (self_type::real (t)),
|
||||
// type_traits<real_type>::type_abs (self_type::imag (t)));
|
||||
}
|
||||
|
||||
static
|
||||
BOOST_UBLAS_INLINE
|
||||
bool equals (const_reference t1, const_reference t2) {
|
||||
return self_type::norm_inf (t1 - t2) < BOOST_UBLAS_TYPE_CHECK_EPSILON *
|
||||
(std::max) ((std::max) (self_type::norm_inf (t1),
|
||||
self_type::norm_inf (t2)),
|
||||
BOOST_UBLAS_TYPE_CHECK_MIN);
|
||||
}
|
||||
};
|
||||
|
||||
// Define complex type traits
|
||||
template<>
|
||||
struct type_traits<std::complex<float> > : complex_traits<std::complex<float> >{
|
||||
typedef type_traits<std::complex<float> > self_type;
|
||||
typedef std::complex<float> value_type;
|
||||
typedef const value_type &const_reference;
|
||||
typedef value_type &reference;
|
||||
typedef float real_type;
|
||||
typedef std::complex<double> precision_type;
|
||||
|
||||
};
|
||||
template<>
|
||||
struct type_traits<std::complex<double> > : complex_traits<std::complex<double> >{
|
||||
typedef type_traits<std::complex<double> > self_type;
|
||||
typedef std::complex<double> value_type;
|
||||
typedef const value_type &const_reference;
|
||||
typedef value_type &reference;
|
||||
typedef double real_type;
|
||||
typedef std::complex<long double> precision_type;
|
||||
};
|
||||
template<>
|
||||
struct type_traits<std::complex<long double> > : complex_traits<std::complex<long double> > {
|
||||
typedef type_traits<std::complex<long double> > self_type;
|
||||
typedef std::complex<long double> value_type;
|
||||
typedef const value_type &const_reference;
|
||||
typedef value_type &reference;
|
||||
typedef long double real_type;
|
||||
typedef value_type precision_type;
|
||||
};
|
||||
|
||||
#ifdef BOOST_UBLAS_USE_INTERVAL
|
||||
// Define scalar interval type traits
|
||||
template<>
|
||||
struct type_traits<boost::numeric::interval<float> > : scalar_traits<boost::numeric::interval<float> > {
|
||||
typedef type_traits<boost::numeric::interval<float> > self_type;
|
||||
typedef boost::numeric::interval<float> value_type;
|
||||
typedef const value_type &const_reference;
|
||||
typedef value_type &reference;
|
||||
typedef value_type real_type;
|
||||
typedef boost::numeric::interval<double> precision_type;
|
||||
|
||||
};
|
||||
template<>
|
||||
struct type_traits<boost::numeric::interval<double> > : scalar_traits<boost::numeric::interval<double> > {
|
||||
typedef type_traits<boost::numeric::interval<double> > self_type;
|
||||
typedef boost::numeric::interval<double> value_type;
|
||||
typedef const value_type &const_reference;
|
||||
typedef value_type &reference;
|
||||
typedef value_type real_type;
|
||||
typedef boost::numeric::interval<long double> precision_type;
|
||||
};
|
||||
template<>
|
||||
struct type_traits<boost::numeric::interval<long double> > : scalar_traits<boost::numeric::interval<long double> > {
|
||||
typedef type_traits<boost::numeric::interval<long double> > self_type;
|
||||
typedef boost::numeric::interval<long double> value_type;
|
||||
typedef const value_type &const_reference;
|
||||
typedef value_type &reference;
|
||||
typedef value_type real_type;
|
||||
typedef value_type precision_type;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
// Storage tags -- hierarchical definition of storage characteristics
|
||||
|
||||
struct unknown_storage_tag {};
|
||||
struct sparse_proxy_tag: public unknown_storage_tag {};
|
||||
struct sparse_tag: public sparse_proxy_tag {};
|
||||
struct packed_proxy_tag: public sparse_proxy_tag {};
|
||||
struct packed_tag: public packed_proxy_tag {};
|
||||
struct dense_proxy_tag: public packed_proxy_tag {};
|
||||
struct dense_tag: public dense_proxy_tag {};
|
||||
|
||||
template<class S1, class S2>
|
||||
struct storage_restrict_traits {
|
||||
typedef S1 storage_category;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct storage_restrict_traits<sparse_tag, dense_proxy_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct storage_restrict_traits<sparse_tag, packed_proxy_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct storage_restrict_traits<sparse_tag, sparse_proxy_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct storage_restrict_traits<packed_tag, dense_proxy_tag> {
|
||||
typedef packed_proxy_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct storage_restrict_traits<packed_tag, packed_proxy_tag> {
|
||||
typedef packed_proxy_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct storage_restrict_traits<packed_tag, sparse_proxy_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct storage_restrict_traits<packed_proxy_tag, sparse_proxy_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct storage_restrict_traits<dense_tag, dense_proxy_tag> {
|
||||
typedef dense_proxy_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct storage_restrict_traits<dense_tag, packed_proxy_tag> {
|
||||
typedef packed_proxy_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct storage_restrict_traits<dense_tag, sparse_proxy_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct storage_restrict_traits<dense_proxy_tag, packed_proxy_tag> {
|
||||
typedef packed_proxy_tag storage_category;
|
||||
};
|
||||
template<>
|
||||
struct storage_restrict_traits<dense_proxy_tag, sparse_proxy_tag> {
|
||||
typedef sparse_proxy_tag storage_category;
|
||||
};
|
||||
|
||||
|
||||
// Iterator tags -- hierarchical definition of storage characteristics
|
||||
|
||||
struct sparse_bidirectional_iterator_tag : public std::bidirectional_iterator_tag {};
|
||||
struct packed_random_access_iterator_tag : public std::random_access_iterator_tag {};
|
||||
struct dense_random_access_iterator_tag : public packed_random_access_iterator_tag {};
|
||||
|
||||
// Thanks to Kresimir Fresl for convincing Comeau with iterator_base_traits ;-)
|
||||
template<class IC>
|
||||
struct iterator_base_traits {};
|
||||
|
||||
template<>
|
||||
struct iterator_base_traits<std::forward_iterator_tag> {
|
||||
template<class I, class T>
|
||||
struct iterator_base {
|
||||
typedef forward_iterator_base<std::forward_iterator_tag, I, T> type;
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct iterator_base_traits<std::bidirectional_iterator_tag> {
|
||||
template<class I, class T>
|
||||
struct iterator_base {
|
||||
typedef bidirectional_iterator_base<std::bidirectional_iterator_tag, I, T> type;
|
||||
};
|
||||
};
|
||||
template<>
|
||||
struct iterator_base_traits<sparse_bidirectional_iterator_tag> {
|
||||
template<class I, class T>
|
||||
struct iterator_base {
|
||||
typedef bidirectional_iterator_base<sparse_bidirectional_iterator_tag, I, T> type;
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct iterator_base_traits<std::random_access_iterator_tag> {
|
||||
template<class I, class T>
|
||||
struct iterator_base {
|
||||
typedef random_access_iterator_base<std::random_access_iterator_tag, I, T> type;
|
||||
};
|
||||
};
|
||||
template<>
|
||||
struct iterator_base_traits<packed_random_access_iterator_tag> {
|
||||
template<class I, class T>
|
||||
struct iterator_base {
|
||||
typedef random_access_iterator_base<packed_random_access_iterator_tag, I, T> type;
|
||||
};
|
||||
};
|
||||
template<>
|
||||
struct iterator_base_traits<dense_random_access_iterator_tag> {
|
||||
template<class I, class T>
|
||||
struct iterator_base {
|
||||
typedef random_access_iterator_base<dense_random_access_iterator_tag, I, T> type;
|
||||
};
|
||||
};
|
||||
|
||||
template<class I1, class I2>
|
||||
struct iterator_restrict_traits {
|
||||
typedef I1 iterator_category;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct iterator_restrict_traits<packed_random_access_iterator_tag, sparse_bidirectional_iterator_tag> {
|
||||
typedef sparse_bidirectional_iterator_tag iterator_category;
|
||||
};
|
||||
template<>
|
||||
struct iterator_restrict_traits<sparse_bidirectional_iterator_tag, packed_random_access_iterator_tag> {
|
||||
typedef sparse_bidirectional_iterator_tag iterator_category;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct iterator_restrict_traits<dense_random_access_iterator_tag, sparse_bidirectional_iterator_tag> {
|
||||
typedef sparse_bidirectional_iterator_tag iterator_category;
|
||||
};
|
||||
template<>
|
||||
struct iterator_restrict_traits<sparse_bidirectional_iterator_tag, dense_random_access_iterator_tag> {
|
||||
typedef sparse_bidirectional_iterator_tag iterator_category;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct iterator_restrict_traits<dense_random_access_iterator_tag, packed_random_access_iterator_tag> {
|
||||
typedef packed_random_access_iterator_tag iterator_category;
|
||||
};
|
||||
template<>
|
||||
struct iterator_restrict_traits<packed_random_access_iterator_tag, dense_random_access_iterator_tag> {
|
||||
typedef packed_random_access_iterator_tag iterator_category;
|
||||
};
|
||||
|
||||
template<class I>
|
||||
BOOST_UBLAS_INLINE
|
||||
void increment (I &it, const I &it_end, typename I::difference_type compare, packed_random_access_iterator_tag) {
|
||||
it += (std::min) (compare, it_end - it);
|
||||
}
|
||||
template<class I>
|
||||
BOOST_UBLAS_INLINE
|
||||
void increment (I &it, const I &/* it_end */, typename I::difference_type /* compare */, sparse_bidirectional_iterator_tag) {
|
||||
++ it;
|
||||
}
|
||||
template<class I>
|
||||
BOOST_UBLAS_INLINE
|
||||
void increment (I &it, const I &it_end, typename I::difference_type compare) {
|
||||
increment (it, it_end, compare, typename I::iterator_category ());
|
||||
}
|
||||
|
||||
template<class I>
|
||||
BOOST_UBLAS_INLINE
|
||||
void increment (I &it, const I &it_end) {
|
||||
#if BOOST_UBLAS_TYPE_CHECK
|
||||
I cit (it);
|
||||
while (cit != it_end) {
|
||||
BOOST_UBLAS_CHECK (*cit == typename I::value_type/*zero*/(), internal_logic ());
|
||||
++ cit;
|
||||
}
|
||||
#endif
|
||||
it = it_end;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
// specialisation which define whether a type has a trivial constructor
|
||||
// or not. This is used by array types.
|
||||
template<typename T>
|
||||
struct has_trivial_constructor : public boost::has_trivial_constructor<T> {};
|
||||
|
||||
template<typename T>
|
||||
struct has_trivial_destructor : public boost::has_trivial_destructor<T> {};
|
||||
|
||||
template<typename FLT>
|
||||
struct has_trivial_constructor<std::complex<FLT> > : public has_trivial_constructor<FLT> {};
|
||||
|
||||
template<typename FLT>
|
||||
struct has_trivial_destructor<std::complex<FLT> > : public has_trivial_destructor<FLT> {};
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** \brief Traits class to extract type information from a constant matrix or vector CONTAINER.
|
||||
*
|
||||
*/
|
||||
template < class E >
|
||||
struct container_view_traits {
|
||||
/// type of indices
|
||||
typedef typename E::size_type size_type;
|
||||
/// type of differences of indices
|
||||
typedef typename E::difference_type difference_type;
|
||||
|
||||
/// storage category: \c unknown_storage_tag, \c dense_tag, \c packed_tag, ...
|
||||
typedef typename E::storage_category storage_category;
|
||||
|
||||
/// type of elements
|
||||
typedef typename E::value_type value_type;
|
||||
/// const reference to an element
|
||||
typedef typename E::const_reference const_reference;
|
||||
|
||||
/// type used in expressions to mark a reference to this class (usually a const container_reference<const E> or the class itself)
|
||||
typedef typename E::const_closure_type const_closure_type;
|
||||
};
|
||||
|
||||
/** \brief Traits class to extract additional type information from a mutable matrix or vector CONTAINER.
|
||||
*
|
||||
*/
|
||||
template < class E >
|
||||
struct mutable_container_traits {
|
||||
/// reference to an element
|
||||
typedef typename E::reference reference;
|
||||
|
||||
/// type used in expressions to mark a reference to this class (usually a container_reference<E> or the class itself)
|
||||
typedef typename E::closure_type closure_type;
|
||||
};
|
||||
|
||||
/** \brief Traits class to extract type information from a matrix or vector CONTAINER.
|
||||
*
|
||||
*/
|
||||
template < class E >
|
||||
struct container_traits
|
||||
: container_view_traits<E>, mutable_container_traits<E> {
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** \brief Traits class to extract type information from a constant MATRIX.
|
||||
*
|
||||
*/
|
||||
template < class MATRIX >
|
||||
struct matrix_view_traits : container_view_traits <MATRIX> {
|
||||
|
||||
/// orientation of the matrix, either \c row_major_tag, \c column_major_tag or \c unknown_orientation_tag
|
||||
typedef typename MATRIX::orientation_category orientation_category;
|
||||
|
||||
/// row iterator for the matrix
|
||||
typedef typename MATRIX::const_iterator1 const_iterator1;
|
||||
|
||||
/// column iterator for the matrix
|
||||
typedef typename MATRIX::const_iterator2 const_iterator2;
|
||||
};
|
||||
|
||||
/** \brief Traits class to extract additional type information from a mutable MATRIX.
|
||||
*
|
||||
*/
|
||||
template < class MATRIX >
|
||||
struct mutable_matrix_traits
|
||||
: mutable_container_traits <MATRIX> {
|
||||
|
||||
/// row iterator for the matrix
|
||||
typedef typename MATRIX::iterator1 iterator1;
|
||||
|
||||
/// column iterator for the matrix
|
||||
typedef typename MATRIX::iterator2 iterator2;
|
||||
};
|
||||
|
||||
|
||||
/** \brief Traits class to extract type information from a MATRIX.
|
||||
*
|
||||
*/
|
||||
template < class MATRIX >
|
||||
struct matrix_traits
|
||||
: matrix_view_traits <MATRIX>, mutable_matrix_traits <MATRIX> {
|
||||
};
|
||||
|
||||
/** \brief Traits class to extract type information from a VECTOR.
|
||||
*
|
||||
*/
|
||||
template < class VECTOR >
|
||||
struct vector_view_traits : container_view_traits <VECTOR> {
|
||||
|
||||
/// iterator for the VECTOR
|
||||
typedef typename VECTOR::const_iterator const_iterator;
|
||||
|
||||
/// iterator pointing to the first element
|
||||
static
|
||||
const_iterator begin(const VECTOR & v) {
|
||||
return v.begin();
|
||||
}
|
||||
/// iterator pointing behind the last element
|
||||
static
|
||||
const_iterator end(const VECTOR & v) {
|
||||
return v.end();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** \brief Traits class to extract type information from a VECTOR.
|
||||
*
|
||||
*/
|
||||
template < class VECTOR >
|
||||
struct mutable_vector_traits : mutable_container_traits <VECTOR> {
|
||||
/// iterator for the VECTOR
|
||||
typedef typename VECTOR::iterator iterator;
|
||||
|
||||
/// iterator pointing to the first element
|
||||
static
|
||||
iterator begin(VECTOR & v) {
|
||||
return v.begin();
|
||||
}
|
||||
|
||||
/// iterator pointing behind the last element
|
||||
static
|
||||
iterator end(VECTOR & v) {
|
||||
return v.end();
|
||||
}
|
||||
};
|
||||
|
||||
/** \brief Traits class to extract type information from a VECTOR.
|
||||
*
|
||||
*/
|
||||
template < class VECTOR >
|
||||
struct vector_traits
|
||||
: vector_view_traits <VECTOR>, mutable_vector_traits <VECTOR> {
|
||||
};
|
||||
|
||||
|
||||
// Note: specializations for T[N] and T[M][N] have been moved to traits/c_array.hpp
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
110
include/boost/numeric/ublas/traits/c_array.hpp
Normal file
110
include/boost/numeric/ublas/traits/c_array.hpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* -*- c++ -*-
|
||||
*
|
||||
* \file c_array.hpp
|
||||
*
|
||||
* \brief provides specializations of matrix and vector traits for c arrays and c matrices.
|
||||
*
|
||||
* Copyright (c) 2009, Gunter Winkler
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* \author Gunter Winkler (guwi17 at gmx dot de)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_NUMERIC_UBLAS_TRAITS_C_ARRAY_HPP
|
||||
#define BOOST_NUMERIC_UBLAS_TRAITS_C_ARRAY_HPP
|
||||
|
||||
|
||||
#include <boost/numeric/ublas/traits.hpp>
|
||||
#include <boost/numeric/ublas/traits/const_iterator_type.hpp>
|
||||
#include <boost/numeric/ublas/traits/iterator_type.hpp>
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template < class T, int M, int N >
|
||||
struct matrix_view_traits < T[M][N] > {
|
||||
typedef T matrix_type[M][N];
|
||||
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
typedef row_major_tag orientation_category;
|
||||
typedef dense_tag storage_category;
|
||||
|
||||
typedef T value_type;
|
||||
typedef const T &const_reference;
|
||||
typedef const T *const_pointer;
|
||||
|
||||
typedef const matrix_reference<const matrix_type> const_closure_type;
|
||||
|
||||
typedef T row_type[N];
|
||||
|
||||
typedef const row_type *const_iterator1;
|
||||
typedef const_pointer const_iterator2;
|
||||
|
||||
};
|
||||
|
||||
template < class T, int M, int N >
|
||||
struct mutable_matrix_traits < T[M][N] > {
|
||||
typedef T matrix_type[M][N];
|
||||
|
||||
typedef T *reference;
|
||||
|
||||
typedef matrix_reference<matrix_type> closure_type;
|
||||
|
||||
};
|
||||
|
||||
template < class T, int N >
|
||||
struct vector_view_traits < T[N] > {
|
||||
typedef T vector_type[N];
|
||||
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
typedef dense_tag storage_category;
|
||||
|
||||
typedef T value_type;
|
||||
typedef const T &const_reference;
|
||||
typedef const T *const_pointer;
|
||||
|
||||
typedef const vector_reference<const vector_type> const_closure_type;
|
||||
|
||||
typedef const_pointer const_iterator;
|
||||
|
||||
/// iterator pointing to the first element
|
||||
static
|
||||
const_iterator begin(const vector_type & v) {
|
||||
return & (v[0]);
|
||||
}
|
||||
/// iterator pointing behind the last element
|
||||
static
|
||||
const_iterator end(const vector_type & v) {
|
||||
return & (v[N]);
|
||||
}
|
||||
};
|
||||
|
||||
template < class T, int N >
|
||||
struct mutable_vector_traits < T[N] > {
|
||||
|
||||
typedef T &reference;
|
||||
typedef T *pointer;
|
||||
typedef vector_reference< T[N] > closure_type;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}}} // Namespace boost::numeric::ublas
|
||||
|
||||
#endif
|
||||
127
include/boost/numeric/ublas/traits/const_iterator_type.hpp
Normal file
127
include/boost/numeric/ublas/traits/const_iterator_type.hpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* -*- c++ -*-
|
||||
*
|
||||
* \file const_iterator_type.hpp
|
||||
*
|
||||
* \brief Const iterator to a given container type.
|
||||
*
|
||||
* Copyright (c) 2009, Marco Guazzone
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* \author Marco Guazzone, marco.guazzone@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BOOST_NUMERIC_UBLAS_TRAITS_CONST_ITERATOR_TYPE_HPP
|
||||
#define BOOST_NUMERIC_UBLAS_TRAITS_CONST_ITERATOR_TYPE_HPP
|
||||
|
||||
|
||||
#include <boost/numeric/ublas/fwd.hpp>
|
||||
#include <boost/numeric/ublas/tags.hpp>
|
||||
#include <boost/numeric/ublas/traits.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* \brief Auxiliary class for retrieving the const iterator to the given
|
||||
* matrix expression according its orientation and to the given dimension tag.
|
||||
* \tparam MatrixT A model of MatrixExpression.
|
||||
* \tparam TagT A dimension tag type (e.g., tag::major).
|
||||
* \tparam OrientationT An orientation category type (e.g., row_major_tag).
|
||||
*/
|
||||
template <typename MatrixT, typename TagT, typename OrientationT>
|
||||
struct const_iterator_type_impl;
|
||||
|
||||
|
||||
/// \brief Specialization of \c const_iterator_type_impl for row-major oriented
|
||||
/// matrices and over the major dimension.
|
||||
template <typename MatrixT>
|
||||
struct const_iterator_type_impl<MatrixT,tag::major,row_major_tag>
|
||||
{
|
||||
typedef typename matrix_view_traits<MatrixT>::const_iterator1 type;
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c const_iterator_type_impl for column-major
|
||||
/// oriented matrices and over the major dimension.
|
||||
template <typename MatrixT>
|
||||
struct const_iterator_type_impl<MatrixT,tag::major,column_major_tag>
|
||||
{
|
||||
typedef typename matrix_view_traits<MatrixT>::const_iterator2 type;
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c const_iterator_type_impl for row-major oriented
|
||||
/// matrices and over the minor dimension.
|
||||
template <typename MatrixT>
|
||||
struct const_iterator_type_impl<MatrixT,tag::minor,row_major_tag>
|
||||
{
|
||||
typedef typename matrix_view_traits<MatrixT>::const_iterator2 type;
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c const_iterator_type_impl for column-major
|
||||
/// oriented matrices and over the minor dimension.
|
||||
template <typename MatrixT>
|
||||
struct const_iterator_type_impl<MatrixT,tag::minor,column_major_tag>
|
||||
{
|
||||
typedef typename matrix_view_traits<MatrixT>::const_iterator1 type;
|
||||
};
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
|
||||
/**
|
||||
* \brief A const iterator for the given container type over the given
|
||||
* dimension.
|
||||
* \tparam ContainerT A container expression type.
|
||||
* \tparam TagT A dimension tag type (e.g., tag::major).
|
||||
*/
|
||||
template <typename ContainerT, typename TagT=void>
|
||||
struct const_iterator_type;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Specialization of \c const_iterator_type for vector expressions.
|
||||
* \tparam VectorT A model of VectorExpression type.
|
||||
*/
|
||||
template <typename VectorT>
|
||||
struct const_iterator_type<VectorT, void>
|
||||
{
|
||||
typedef typename vector_view_traits<VectorT>::const_iterator type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Specialization of \c const_iterator_type for matrix expressions and
|
||||
* over the major dimension.
|
||||
* \tparam MatrixT A model of MatrixExpression type.
|
||||
*/
|
||||
template <typename MatrixT>
|
||||
struct const_iterator_type<MatrixT,tag::major>
|
||||
{
|
||||
typedef typename detail::const_iterator_type_impl<MatrixT,tag::minor,typename matrix_view_traits<MatrixT>::orientation_category>::type type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Specialization of \c const_iterator_type for matrix expressions and
|
||||
* over the minor dimension.
|
||||
* \tparam MatrixT A model of MatrixExpression type.
|
||||
*/
|
||||
template <typename MatrixT>
|
||||
struct const_iterator_type<MatrixT,tag::minor>
|
||||
{
|
||||
typedef typename detail::const_iterator_type_impl<MatrixT,tag::minor,typename matrix_view_traits<MatrixT>::orientation_category>::type type;
|
||||
};
|
||||
|
||||
}}} // Namespace boost::numeric::ublas
|
||||
|
||||
|
||||
#endif // BOOST_NUMERIC_UBLAS_TRAITS_CONST_ITERATOR_TYPE_HPP
|
||||
126
include/boost/numeric/ublas/traits/iterator_type.hpp
Normal file
126
include/boost/numeric/ublas/traits/iterator_type.hpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* -*- c++ -*-
|
||||
*
|
||||
* \file iterator_type.hpp
|
||||
*
|
||||
* \brief Iterator to a given container type.
|
||||
*
|
||||
* Copyright (c) 2009, Marco Guazzone
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* \author Marco Guazzone, marco.guazzone@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BOOST_NUMERIC_UBLAS_TRAITS_ITERATOR_TYPE_HPP
|
||||
#define BOOST_NUMERIC_UBLAS_TRAITS_ITERATOR_TYPE_HPP
|
||||
|
||||
|
||||
#include <boost/numeric/ublas/fwd.hpp>
|
||||
#include <boost/numeric/ublas/traits.hpp>
|
||||
#include <boost/numeric/ublas/tags.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* \brief Auxiliary class for retrieving the iterator to the given
|
||||
* matrix expression according its orientation and to the given dimension tag.
|
||||
* \tparam MatrixT A model of MatrixExpression.
|
||||
* \tparam TagT A dimension tag type (e.g., tag::major).
|
||||
* \tparam OrientationT An orientation category type (e.g., row_major_tag).
|
||||
*/
|
||||
template <typename MatrixT, typename TagT, typename OrientationT>
|
||||
struct iterator_type_impl;
|
||||
|
||||
|
||||
/// \brief Specialization of \c iterator_type_impl for row-major oriented
|
||||
/// matrices and over the major dimension.
|
||||
template <typename MatrixT>
|
||||
struct iterator_type_impl<MatrixT,tag::major,row_major_tag>
|
||||
{
|
||||
typedef typename matrix_traits<MatrixT>::iterator1 type;
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c iterator_type_impl for column-major oriented
|
||||
/// matrices and over the major dimension.
|
||||
template <typename MatrixT>
|
||||
struct iterator_type_impl<MatrixT,tag::major,column_major_tag>
|
||||
{
|
||||
typedef typename matrix_traits<MatrixT>::iterator2 type;
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c iterator_type_impl for row-major oriented
|
||||
/// matrices and over the minor dimension.
|
||||
template <typename MatrixT>
|
||||
struct iterator_type_impl<MatrixT,tag::minor,row_major_tag>
|
||||
{
|
||||
typedef typename matrix_traits<MatrixT>::iterator2 type;
|
||||
};
|
||||
|
||||
|
||||
/// \brief Specialization of \c iterator_type_impl for column-major oriented
|
||||
/// matrices and over the minor dimension.
|
||||
template <typename MatrixT>
|
||||
struct iterator_type_impl<MatrixT,tag::minor,column_major_tag>
|
||||
{
|
||||
typedef typename matrix_traits<MatrixT>::iterator1 type;
|
||||
};
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
|
||||
/**
|
||||
* \brief A iterator for the given container type over the given dimension.
|
||||
* \tparam ContainerT A container expression type.
|
||||
* \tparam TagT A dimension tag type (e.g., tag::major).
|
||||
*/
|
||||
template <typename ContainerT, typename TagT=void>
|
||||
struct iterator_type;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Specialization of \c iterator_type for vector expressions.
|
||||
* \tparam VectorT A model of VectorExpression type.
|
||||
*/
|
||||
template <typename VectorT>
|
||||
struct iterator_type<VectorT, void>
|
||||
{
|
||||
typedef typename vector_traits<VectorT>::iterator type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Specialization of \c iterator_type for matrix expressions and
|
||||
* over the major dimension.
|
||||
* \tparam MatrixT A model of MatrixExpression type.
|
||||
*/
|
||||
template <typename MatrixT>
|
||||
struct iterator_type<MatrixT,tag::major>
|
||||
{
|
||||
typedef typename detail::iterator_type_impl<MatrixT,tag::major,typename matrix_traits<MatrixT>::orientation_category>::type type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Specialization of \c iterator_type for matrix expressions and
|
||||
* over the minor dimension.
|
||||
* \tparam MatrixT A model of MatrixExpression type.
|
||||
*/
|
||||
template <typename MatrixT>
|
||||
struct iterator_type<MatrixT,tag::minor>
|
||||
{
|
||||
typedef typename detail::iterator_type_impl<MatrixT,tag::minor,typename matrix_traits<MatrixT>::orientation_category>::type type;
|
||||
};
|
||||
|
||||
}}} // Namespace boost::numeric::ublas
|
||||
|
||||
|
||||
#endif // BOOST_NUMERIC_UBLAS_TRAITS_ITERATOR_TYPE_HPP
|
||||
2775
include/boost/numeric/ublas/triangular.hpp
Normal file
2775
include/boost/numeric/ublas/triangular.hpp
Normal file
File diff suppressed because it is too large
Load Diff
2947
include/boost/numeric/ublas/vector.hpp
Normal file
2947
include/boost/numeric/ublas/vector.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1762
include/boost/numeric/ublas/vector_expression.hpp
Normal file
1762
include/boost/numeric/ublas/vector_expression.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1347
include/boost/numeric/ublas/vector_of_vector.hpp
Normal file
1347
include/boost/numeric/ublas/vector_of_vector.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1697
include/boost/numeric/ublas/vector_proxy.hpp
Normal file
1697
include/boost/numeric/ublas/vector_proxy.hpp
Normal file
File diff suppressed because it is too large
Load Diff
2246
include/boost/numeric/ublas/vector_sparse.hpp
Normal file
2246
include/boost/numeric/ublas/vector_sparse.hpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user