7#ifndef DUNE_FUFEM_FORMS_TENSORS_HH
8#define DUNE_FUFEM_FORMS_TENSORS_HH
22namespace Dune::Fufem::Forms::Impl::Tensor {
39 template<
class T, std::
size_t k>
44 static decltype(
auto) resolveIndices(
auto&& t)
49 static decltype(
auto) resolveIndices(
auto&& t,
const auto& i0,
const auto&... i)
51 return resolveIndices(t[i0], i...);
54 template<
class I, I... i>
57 return resolveIndices(t, i...);
73 decltype(
auto)
operator()(
const auto&... i)
const
75 return resolveIndices(t_, i...);
79 template<
class T, std::
size_t k>
86 template<
class T, std::
size_t k>
94 using value_type =
typename T::value_type;
105 template<
class I0,
class... I>
107 decltype(
auto)
operator()(
const I0& i0,
const I&... i)
const
112 template<
class I0,
class I1,
class... I>
114 decltype(
auto)
operator()(
const I0& i0,
const I1& i1,
const I&... i)
const
120 template<
class T, std::
size_t k>
127 template<
class T, std::
size_t k>
134 using value_type =
typename RawT::value_type;
145 template<
class I0,
class... I>
147 decltype(
auto)
operator()(
const I0& i0,
const I&... i)
const
152 template<
class I0,
class I1,
class... I>
154 decltype(
auto)
operator()(
const I0& i0,
const I1& i1,
const I&... i)
const
160 template<
class T, std::
size_t k>
166 template<
class Value>
171 using value_type = Value;
178 RankZeroTensor(Value value)
183 friend void sparseForEach(
const RankZeroTensor& tensor, F&& f)
188 template<
class Outer>
189 friend auto compose(
const Outer& outer,
const RankZeroTensor& inner)
191 return Dune::Fufem::Forms::Impl::Tensor::RankZeroTensor(outer(inner()));
209 template<
class Value>
215 template<std::
size_t r,
class Value,
class ForEach>
233 friend void sparseForEach(
const SparseTensor& tensor, F&& f)
238 template<
class Outer>
239 friend auto compose(
const Outer& outer,
const SparseTensor& inner)
242 return Dune::Fufem::Forms::Impl::Tensor::SparseTensor(
244 [outer, innerForEach=inner.forEach_](
auto&& f) {
245 innerForEach([&](const auto& y_i, auto... i) {
264 template<std::
size_t r,
class Value,
class ForEach>
265 struct IsTensor<SparseTensor<r, Value, ForEach>> :
public std::true_type
268 template<std::
size_t r,
class Value,
class ForEach>
274 template<
class Product,
class T0,
class T1>
275 class SparseProductTensor
286 SparseProductTensor(Product product, T0 t0, T1 t1)
293 friend void sparseForEach(
const SparseProductTensor& tensor, F&& f)
296 if constexpr(T0::rank() == 0)
297 sparseForEach(tensor.t1_, [&](
const auto& x1_j,
auto... j) {
298 f(tensor.product_(tensor.t0_(), x1_j), j...);
300 else if constexpr(T1::rank() == 0)
301 sparseForEach(tensor.t0_, [&](
const auto& x0_i,
auto... i) {
302 f(tensor.product_(x0_i, tensor.t1_()), i...);
304 else if constexpr((T0::rank() == 2) and (T1::rank() == 2))
305 sparseForEach(tensor.t0_, [&](
const auto& x0_i,
auto i0,
auto i1) {
306 sparseForEach(tensor.t1_, [&](const auto& x1_j, auto j0, auto j1) {
307 f(tensor.product_(x0_i, x1_j), i0, j0, i1, j1);
312 template<
class Outer>
313 friend auto compose(
const Outer& outer,
const SparseProductTensor& inner)
316 return Dune::Fufem::Forms::Impl::Tensor::SparseProductTensor(
317 [outer, innerProduct=inner.product()](
const auto&... args) { return outer(innerProduct(args...)); },
325 return t0_.nnz() * t1_.nnz();
334 template<std::
size_t k>
339 else if constexpr(k==1)
349 template<
class Product,
class T0,
class T1>
350 struct IsTensor<SparseProductTensor<Product, T0, T1>> :
public std::true_type
353 template<
class Product,
class T0,
class T1>
354 struct IsLazyTensor<SparseProductTensor<Product, T0, T1>> :
public std::true_type
359 template<
class Product,
class X,
class Y>
360 requires (IsTensor<X>::value and IsTensor<Y>::value)
361 auto interleavedOuterProduct(Product product,
const X& x,
const Y& y)
364 if constexpr((X::rank() == 0) and (Y::rank() == 0))
365 return RankZeroTensor(
product(x(), y()));
367 return SparseProductTensor(product, x, y);
372 template<
class K, std::
size_t rank,
class Value,
class ForEach,
class Y>
375 and IsTensor<Y>::value
376 and (rank == Y::rank())
378 void axpy(
const K&
alpha,
const SparseTensor<rank, Value, ForEach>& x, Y& y)
380 sparseForEach(x, [&](
const auto& xi,
auto...i) {
385 template<
class K,
class Product,
class T0,
class T1,
class Y>
388 and IsTensor<Y>::value
389 and (SparseProductTensor<Product, T0, T1>::rank() == Y::rank())
391 void axpy(
const K&
alpha,
const SparseProductTensor<Product, T0, T1>& x, Y& y)
397 if constexpr(T0::rank() == 0)
398 sparseForEach(x.factor(_1), [&](
const auto& x1_j,
auto... j) {
399 y(j...) += x.product()(mult(
alpha,x.factor(_0)()), x1_j);
401 else if constexpr(T1::rank() == 0)
402 sparseForEach(x.factor(_0), [&](
const auto& x0_i,
auto... i) {
403 y(i...) += x.product()(x0_i, mult(
alpha,x.factor(_1)()));
405 else if constexpr((T0::rank() == 2) and (T1::rank() == 2))
406 sparseForEach(x.factor(_0), [&](
const auto& x0_i,
auto i0,
auto i1) {
407 auto x0_i_alpha = mult(x0_i,alpha);
408 sparseForEach(x.factor(_1), [&](const auto& x1_j, auto j0, auto j1) {
409 y(i0, j0, i1, j1) += x.product()(x0_i_alpha, x1_j);
413 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:407
auto compose(const OuterOp &outerOp, const InnerOp &innerOp)
Generic composition of a multilinear operators with a pointwise outer operator.
Definition userfunctions.hh:483
Definition localoperators.hh:341