7#ifndef DUNE_FUFEM_FORMS_TENSORS_HH
8#define DUNE_FUFEM_FORMS_TENSORS_HH
21namespace Dune::Fufem::Forms::Impl::Tensor {
38 template<
class T, std::
size_t k>
43 static decltype(
auto) resolveIndices(
auto&& t)
48 static decltype(
auto) resolveIndices(
auto&& t,
const auto& i0,
const auto&... i)
50 return resolveIndices(t[i0], i...);
53 template<
class I, I... i>
56 return resolveIndices(t, i...);
72 decltype(
auto)
operator()(
const auto&... i)
const
74 return resolveIndices(t_, i...);
78 template<
class T, std::
size_t k>
85 template<
class T, std::
size_t k>
93 using value_type =
typename T::value_type;
104 template<
class I0,
class... I>
106 decltype(
auto)
operator()(
const I0& i0,
const I&... i)
const
111 template<
class I0,
class I1,
class... I>
113 decltype(
auto)
operator()(
const I0& i0,
const I1& i1,
const I&... i)
const
119 template<
class T, std::
size_t k>
126 template<
class T, std::
size_t k>
133 using value_type =
typename RawT::value_type;
144 template<
class I0,
class... I>
146 decltype(
auto)
operator()(
const I0& i0,
const I&... i)
const
151 template<
class I0,
class I1,
class... I>
153 decltype(
auto)
operator()(
const I0& i0,
const I1& i1,
const I&... i)
const
159 template<
class T, std::
size_t k>
165 template<
class Value>
170 using value_type = Value;
177 RankZeroTensor(Value value)
182 friend void sparseForEach(
const RankZeroTensor& tensor, F&& f)
187 template<
class Outer>
188 friend auto compose(
const Outer& outer,
const RankZeroTensor& inner)
190 return Dune::Fufem::Forms::Impl::Tensor::RankZeroTensor(outer(inner()));
208 template<
class Value>
214 template<std::
size_t r,
class Value,
class ForEach>
232 friend void sparseForEach(
const SparseTensor& tensor, F&& f)
237 template<
class Outer>
238 friend auto compose(
const Outer& outer,
const SparseTensor& inner)
241 return Dune::Fufem::Forms::Impl::Tensor::SparseTensor(
243 [outer, innerForEach=inner.forEach_](
auto&& f) {
244 innerForEach([&](const auto& y_i, auto... i) {
263 template<std::
size_t r,
class Value,
class ForEach>
264 struct IsTensor<SparseTensor<r, Value, ForEach>> :
public std::true_type
267 template<std::
size_t r,
class Value,
class ForEach>
273 template<
class Product,
class T0,
class T1>
274 class SparseProductTensor
285 SparseProductTensor(Product product, T0 t0, T1 t1)
292 friend void sparseForEach(
const SparseProductTensor& tensor, F&& f)
295 if constexpr(T0::rank() == 0)
296 sparseForEach(tensor.t1_, [&](
const auto& x1_j,
auto... j) {
297 f(tensor.product_(tensor.t0_(), x1_j), j...);
299 else if constexpr(T1::rank() == 0)
300 sparseForEach(tensor.t0_, [&](
const auto& x0_i,
auto... i) {
301 f(tensor.product_(x0_i, tensor.t1_()), i...);
303 else if constexpr((T0::rank() == 2) and (T1::rank() == 2))
304 sparseForEach(tensor.t0_, [&](
const auto& x0_i,
auto i0,
auto i1) {
305 sparseForEach(tensor.t1_, [&](const auto& x1_j, auto j0, auto j1) {
306 f(tensor.product_(x0_i, x1_j), i0, j0, i1, j1);
311 template<
class Outer>
312 friend auto compose(
const Outer& outer,
const SparseProductTensor& inner)
315 return Dune::Fufem::Forms::Impl::Tensor::SparseProductTensor(
316 [outer, innerProduct=inner.product()](
const auto&... args) { return outer(innerProduct(args...)); },
324 return t0_.nnz() * t1_.nnz();
333 template<std::
size_t k>
338 else if constexpr(k==1)
348 template<
class Product,
class T0,
class T1>
349 struct IsTensor<SparseProductTensor<Product, T0, T1>> :
public std::true_type
352 template<
class Product,
class T0,
class T1>
353 struct IsLazyTensor<SparseProductTensor<Product, T0, T1>> :
public std::true_type
358 template<
class Product,
class X,
class Y>
359 requires (IsTensor<X>::value and IsTensor<Y>::value)
360 auto interleavedOuterProduct(Product product,
const X& x,
const Y& y)
363 if constexpr((X::rank() == 0) and (Y::rank() == 0))
364 return RankZeroTensor(
product(x(), y()));
366 return SparseProductTensor(product, x, y);
371 template<
class K, std::
size_t rank,
class Value,
class ForEach,
class Y>
374 and IsTensor<Y>::value
375 and (rank == Y::rank())
377 void axpy(
const K&
alpha,
const SparseTensor<rank, Value, ForEach>& x, Y& y)
379 sparseForEach(x, [&](
const auto& xi,
auto...i) {
384 template<
class K,
class Product,
class T0,
class T1,
class Y>
387 and IsTensor<Y>::value
388 and (SparseProductTensor<Product, T0, T1>::rank() == Y::rank())
390 void axpy(
const K&
alpha,
const SparseProductTensor<Product, T0, T1>& x, Y& y)
395 if constexpr(T0::rank() == 0)
396 sparseForEach(x.factor(_1), [&](
const auto& x1_j,
auto... j) {
397 y(j...) += x.product()(
alpha*x.factor(_0)(), x1_j);
399 else if constexpr(T1::rank() == 0)
400 sparseForEach(x.factor(_0), [&](
const auto& x0_i,
auto... i) {
401 y(i...) += x.product()(x0_i,
alpha*x.factor(_1)());
403 else if constexpr((T0::rank() == 2) and (T1::rank() == 2))
404 sparseForEach(x.factor(_0), [&](
const auto& x0_i,
auto i0,
auto i1) {
405 auto x0_i_alpha = x0_i*alpha;
406 sparseForEach(x.factor(_1), [&](const auto& x1_j, auto j0, auto j1) {
407 y(i0, j0, i1, j1) += x.product()(x0_i_alpha, x1_j);
411 static_assert((T0::rank() == 2) and (T1::rank() == 2));
void axpy(const Ta &a, const type &y)
auto operator()(T &&t) -> decltype(this->apply(t, std::index_sequence_for< Args... >{})) const
constexpr void forEach(Range &&range, F &&f)
constexpr T & resolveRef(T &gf) noexcept
virtual void operator()()=0
auto product(const Op &op, const L &l, const R &r)
Generic exterior product of two multilinear operators.
Definition userfunctions.hh:409
auto compose(const OuterOp &outerOp, const InnerOp &innerOp)
Generic composition of a multilinear operators with a pointwise outer operator.
Definition userfunctions.hh:483