1 #ifndef MPQC_MATH_TENSOR_BASE_HPP
2 #define MPQC_MATH_TENSOR_BASE_HPP
7 #include <boost/array.hpp>
8 #include <boost/tuple/tuple.hpp>
10 #include <boost/preprocessor/repetition/enum_params.hpp>
11 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
13 #include "mpqc/range.hpp"
14 #include "mpqc/range/tie.hpp"
15 #include "mpqc/utility/string.hpp"
17 #include "mpqc/math/tensor/forward.hpp"
18 #include "mpqc/math/tensor/functional.hpp"
19 #include "mpqc/math/tensor/exception.hpp"
31 template<
typename T,
size_t N,
class Order>
35 static const size_t RANK = N;
36 typedef boost::array<size_t,N> Dims;
37 typedef boost::array<size_t,N> Strides;
48 const size_t *ld = NULL)
51 std::copy(dims, dims+N, this->dims_.begin());
52 strides_ = Order::template strides<N>(ld ? ld : dims);
57 for (
int i = 0; i < N; ++i)
58 size *= this->dims_[i];
62 const Dims& dims()
const {
68 template<
typename U,
class O>
74 this->
operator=<T>(o);
81 #define MPQC_MATH_TENSOR_INDEX_OPERATOR(Z, N, CV) \
82 template< BOOST_PP_ENUM_PARAMS(N, class T) > \
83 typename boost::enable_if \
84 < detail::Tensor::is_integral_tuple \
85 < boost::tuple<BOOST_PP_ENUM_PARAMS(N,T)> >, \
87 operator()(BOOST_PP_ENUM_BINARY_PARAMS(N, const T, &i)) CV { \
88 using detail::Tensor::tie; \
89 return this->operator()(tie(boost::tie(BOOST_PP_ENUM_PARAMS(N,i)))); \
94 #define MPQC_MATH_TENSOR_RANGE_OPERATOR(Z, N, CV) \
95 template< BOOST_PP_ENUM_PARAMS(N, class T) > \
96 typename boost::disable_if \
97 < detail::Tensor::is_integral_tuple \
98 < boost::tuple<BOOST_PP_ENUM_PARAMS(N,T)> >, \
99 TensorBase<CV T, N, Order> >::type \
100 operator()(BOOST_PP_ENUM_BINARY_PARAMS(N, const T, &i)) CV { \
101 using detail::Tensor::tie; \
102 return this->operator()(tie(boost::tie(BOOST_PP_ENUM_PARAMS(N,i)))); \
105 BOOST_PP_REPEAT_FROM_TO(1, 5, MPQC_MATH_TENSOR_INDEX_OPERATOR, )
106 BOOST_PP_REPEAT_FROM_TO(1, 5, MPQC_MATH_TENSOR_INDEX_OPERATOR,
const)
107 BOOST_PP_REPEAT_FROM_TO(1, 5, MPQC_MATH_TENSOR_RANGE_OPERATOR, )
108 BOOST_PP_REPEAT_FROM_TO(1, 5, MPQC_MATH_TENSOR_RANGE_OPERATOR,
const)
115 return this->data_[this->index(idx)];
121 return this->data_[this->index(idx)];
127 return block< TensorBase<T, N, Order> >(*
this, tie);
131 TensorBase<const T, N, Order>
132 operator()(
const detail::Tensor::range_tie<Seq> &tie)
const {
133 return block< TensorBase<const T, N, Order> >(*
this, tie);
138 template<
class Seq,
int K>
139 void check_index(
const detail::Tensor::integral_tie<Seq> &tie,
140 boost::mpl::int_<K>)
const {
141 using boost::fusion::at_c;
142 if ((at_c<K>(tie) < 0) || (at_c<K>(tie) > this->dims_[K])) {
143 throw TensorIndexException(K, at_c<K>(tie), 0, this->dims_[K]);
145 check_index(tie, boost::mpl::int_<K+1>());
149 void check_index(
const detail::Tensor::integral_tie<Seq> &tie,
150 boost::mpl::int_<N>)
const {}
153 ptrdiff_t index(
const detail::Tensor::integral_tie<Seq> &idx)
const {
154 static_assert(boost::fusion::result_of::size<Seq>::value == N,
155 "Invalid TensorBase::operator() arity");
159 ptrdiff_t index = Order::index((
const Seq&)idx, this->strides_);
166 template<
class U,
class This,
class Tie>
167 static U block(This &t, detail::Tensor::range_tie<Tie> tie) {
168 static_assert(boost::tuples::length<Tie>::value == N,
169 "Invalid TensorBase::operator() arity");
170 boost::array<range,N> r = range::tie<Tie>(tie);
171 boost::array<ptrdiff_t,N> begin;
173 for (
int i = 0; i < N; ++i) {
174 begin[i] = *r[i].begin();
175 dims[i] = r[i].size();
177 if ((*r[i].begin() < 0) || (*r[i].end() > t.dims_[i])) {
178 throw TensorRangeException(i, r[i], 0, t.dims_[i]);
182 ptrdiff_t offset = Order::index(begin, t.strides_);
184 return U(t.data_+offset, dims, t.strides_);
189 friend class TensorBase< typename boost::remove_const<T>::type, N, Order>;
190 TensorBase(T *data, const Dims &dims, const Strides &strides)
191 : data_(data), dims_(dims), strides_(strides)