Eigen  5.0.1
 
Loading...
Searching...
No Matches
SparseScatter.h
1// SPDX-FileCopyrightText: The Eigen Authors
2// SPDX-License-Identifier: MPL-2.0
3
4#ifndef EIGEN_SPARSE_SCATTER_H
5#define EIGEN_SPARSE_SCATTER_H
6
7// IWYU pragma: private
8#include "./InternalHeaderCheck.h"
9
10namespace Eigen {
11namespace internal {
12
13constexpr Index kSparseScatterPacketMinSize = 32;
14
15template <typename Scalar, bool Vectorize>
16struct sparse_scatter_sub_impl {
17 template <typename StorageIndex, typename ValuesEvaluator>
18 static EIGEN_STRONG_INLINE Index run(Scalar*, const StorageIndex*, const ValuesEvaluator&, Index) {
19 return 0;
20 }
21};
22
23template <typename Scalar>
24struct sparse_scatter_sub_impl<Scalar, true> {
25 // Keep the packet loop out of the common path for short updates.
26 template <typename StorageIndex, typename ValuesEvaluator>
27 static EIGEN_DONT_INLINE Index run(Scalar* EIGEN_RESTRICT dense, const StorageIndex* indices,
28 const ValuesEvaluator& values, Index size) {
29 // Limit register pressure from the indirect addresses.
30 using Packet = typename find_best_packet<Scalar, 4>::type;
31 constexpr Index PacketSize = unpacket_traits<Packet>::size;
32 const Index end = size - size % PacketSize;
33 for (Index i = 0; i < end; i += PacketSize) {
34 EIGEN_ALIGN_MAX Scalar gathered[PacketSize];
35 for (Index lane = 0; lane < PacketSize; ++lane) gathered[lane] = dense[indices[i + lane]];
36 pstoreu(gathered, psub(ploadu<Packet>(gathered), values.template packet<Unaligned, Packet>(i)));
37 for (Index lane = 0; lane < PacketSize; ++lane) dense[indices[i + lane]] = gathered[lane];
38 }
39 return end;
40 }
41};
42
43// Subtract a packet-sized prefix of values from dense at distinct indices, returning its length.
44// Neither input may alias dense. Callers retain their scalar loop for short updates and the tail.
45// Packing complex destinations costs more than the packet arithmetic saves.
46template <typename Scalar, typename StorageIndex, typename Values>
47EIGEN_STRONG_INLINE Index sparse_scatter_sub_packets(Scalar* EIGEN_RESTRICT dense, const StorageIndex* indices,
48 const MatrixBase<Values>& values) {
49 EIGEN_STATIC_ASSERT_VECTOR_ONLY(Values)
50 EIGEN_STATIC_ASSERT((std::is_same<Scalar, typename Values::Scalar>::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES)
51 constexpr bool Vectorize = (evaluator<Values>::Flags & PacketAccessBit) &&
52 (evaluator<Values>::Flags & LinearAccessBit) && packet_traits<Scalar>::HasSub &&
53 !NumTraits<Scalar>::IsComplex;
54 if (!Vectorize || values.size() < kSparseScatterPacketMinSize) return 0;
55 evaluator<Values> valuesEval(values.derived());
56 return sparse_scatter_sub_impl<Scalar, Vectorize>::run(dense, indices, valuesEval, values.size());
57}
58
59template <bool Conjugate, typename Scalar, typename StorageIndex>
60EIGEN_STRONG_INLINE Index sparse_scatter_sub_packets(Scalar* dense, const StorageIndex* indices, const Scalar* values,
61 Index size, const Scalar& scale) {
62 constexpr bool Vectorize = packet_traits<Scalar>::Vectorizable && packet_traits<Scalar>::HasMul &&
63 packet_traits<Scalar>::HasSub && !NumTraits<Scalar>::IsComplex;
64 if (!Vectorize || size < kSparseScatterPacketMinSize) return 0;
65 const Map<const Matrix<Scalar, Dynamic, 1>> mappedValues(values, size);
66 return sparse_scatter_sub_packets(dense, indices, mappedValues.template conjugateIf<Conjugate>() * scale);
67}
68
69} // namespace internal
70} // namespace Eigen
71
72#endif // EIGEN_SPARSE_SCATTER_H
constexpr unsigned int PacketAccessBit
Definition Constants.h:98
constexpr unsigned int LinearAccessBit
Definition Constants.h:134