This commit is contained in:
2026-03-23 20:54:41 +08:00
commit e13b3650e9
4596 changed files with 1015768 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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
*/

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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
*/

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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_

View 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

View 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_

View 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

View 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

View 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

View 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

View 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_

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff