Eigen  5.0.1
 
Loading...
Searching...
No Matches
NullaryFunctors.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2008-2016 Gael Guennebaud <gael.guennebaud@inria.fr>
5//
6// This Source Code Form is subject to the terms of the Mozilla
7// Public License v. 2.0. If a copy of the MPL was not distributed
8// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9// SPDX-License-Identifier: MPL-2.0
10
11#ifndef EIGEN_NULLARY_FUNCTORS_H
12#define EIGEN_NULLARY_FUNCTORS_H
13
14// IWYU pragma: private
15#include "../InternalHeaderCheck.h"
16
17namespace Eigen {
18
19namespace internal {
20
21template <typename Scalar>
22struct scalar_constant_op {
23 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE scalar_constant_op(const Scalar& other) : m_other(other) {}
24 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()() const { return m_other; }
25 template <typename PacketType>
26 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetOp() const {
27 return internal::pset1<PacketType>(m_other);
28 }
29 const Scalar m_other;
30};
31template <typename Scalar>
32struct functor_traits<scalar_constant_op<Scalar>> {
33 enum {
34 Cost = 0 /* as the constant value should be loaded in register only once for the whole expression */,
35 PacketAccess = packet_traits<Scalar>::Vectorizable,
36 IsRepeatable = true
37 };
38};
39
40template <typename Scalar>
41struct scalar_zero_op {
42 EIGEN_DEVICE_FUNC scalar_zero_op() = default;
43 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()() const { return Scalar(0); }
44 template <typename PacketType>
45 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetOp() const {
46 return internal::pzero<PacketType>(PacketType());
47 }
48};
49template <typename Scalar>
50struct functor_traits<scalar_zero_op<Scalar>> : functor_traits<scalar_constant_op<Scalar>> {};
51
52template <typename Scalar>
53struct scalar_identity_op {
54 template <typename IndexType>
55 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(IndexType row, IndexType col) const {
56 return row == col ? Scalar(1) : Scalar(0);
57 }
58};
59template <typename Scalar>
60struct functor_traits<scalar_identity_op<Scalar>> {
61 enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = false, IsRepeatable = true };
62};
63
64template <typename Scalar, bool IsInteger>
65struct linspaced_op_impl;
66
67template <typename Scalar>
68struct linspaced_op_impl<Scalar, /*IsInteger*/ false> {
69 using RealScalar = typename NumTraits<Scalar>::Real;
70
71 EIGEN_DEVICE_FUNC constexpr linspaced_op_impl(const Scalar& low, const Scalar& high, Index num_steps)
72 : m_low(low),
73 m_high(high),
74 m_size1(num_steps == 1 ? 1 : num_steps - 1),
75 m_step(num_steps == 1 ? Scalar() : Scalar((high - low) / RealScalar(num_steps - 1))),
76 m_flip(numext::abs(high) < numext::abs(low)) {}
77
78 template <typename IndexType>
79 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(IndexType i) const {
80 if (m_flip)
81 return (i == 0) ? m_low : Scalar(m_high - RealScalar(m_size1 - i) * m_step);
82 else
83 return (i == m_size1) ? m_high : Scalar(m_low + RealScalar(i) * m_step);
84 }
85
86 template <typename Packet, typename IndexType>
87 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(IndexType i) const {
88 // Principle:
89 // [low, ..., low] + ( [step, ..., step] * ( [i, ..., i] + [0, ..., size] ) )
90 Packet low = pset1<Packet>(m_low);
91 Packet high = pset1<Packet>(m_high);
92 Packet step = pset1<Packet>(m_step);
93 if (m_flip) {
94 Packet pi = plset<Packet>(Scalar(i - m_size1));
95 Packet res = pmadd(step, pi, high);
96 Packet mask = pcmp_lt(pzero(res), plset<Packet>(Scalar(i)));
97 return pselect<Packet>(mask, res, low);
98 } else {
99 Packet pi = plset<Packet>(Scalar(i));
100 Packet res = pmadd(step, pi, low);
101 Packet mask = pcmp_lt(pi, pset1<Packet>(Scalar(m_size1)));
102 return pselect<Packet>(mask, res, high);
103 }
104 }
105
106 const Scalar m_low;
107 const Scalar m_high;
108 const Index m_size1;
109 const Scalar m_step;
110 const bool m_flip;
111};
112
113template <typename Scalar>
114struct linspaced_op_impl<Scalar, /*IsInteger*/ true> {
115 EIGEN_DEVICE_FUNC constexpr linspaced_op_impl(const Scalar& low, const Scalar& high, Index num_steps)
116 : m_low(low),
117 m_multiplier((high - low) / convert_index<Scalar>(num_steps <= 1 ? 1 : num_steps - 1)),
118 m_divisor(convert_index<Scalar>((high >= low ? num_steps : -num_steps) + (high - low)) /
119 ((numext::abs(high - low) + 1) == 0 ? 1 : (numext::abs(high - low) + 1))),
120 m_use_divisor(num_steps > 1 && (numext::abs(high - low) + 1) < num_steps) {}
121
122 template <typename IndexType>
123 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(IndexType i) const {
124 if (m_use_divisor)
125 return m_low + convert_index<Scalar>(i) / m_divisor;
126 else
127 return m_low + convert_index<Scalar>(i) * m_multiplier;
128 }
129
130 const Scalar m_low;
131 const Scalar m_multiplier;
132 const Scalar m_divisor;
133 const bool m_use_divisor;
134};
135
136// ----- Linspace functor ----------------------------------------------------------------
137
138// Forward declaration (we default to random access which does not really give
139// us a speed gain when using packet access but it allows to use the functor in
140// nested expressions).
141template <typename Scalar>
142struct linspaced_op;
143template <typename Scalar>
144struct functor_traits<linspaced_op<Scalar>> {
145 enum {
146 Cost = 1,
147 PacketAccess = (!NumTraits<Scalar>::IsInteger) && packet_traits<Scalar>::HasSetLinear,
148 /*&& ((!NumTraits<Scalar>::IsInteger) || packet_traits<Scalar>::HasDiv),*/ // <- vectorization for integer is
149 // currently disabled
150 IsRepeatable = true
151 };
152};
153template <typename Scalar>
154struct linspaced_op {
155 EIGEN_DEVICE_FUNC constexpr linspaced_op(const Scalar& low, const Scalar& high, Index num_steps)
156 : impl((num_steps == 1 ? high : low), high, num_steps) {}
157
158 template <typename IndexType>
159 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(IndexType i) const {
160 return impl(i);
161 }
162
163 template <typename Packet, typename IndexType>
164 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(IndexType i) const {
165 return impl.template packetOp<Packet>(i);
166 }
167
168 // This proxy object handles the actual required temporaries and the different
169 // implementations (integer vs. floating point).
170 const linspaced_op_impl<Scalar, NumTraits<Scalar>::IsInteger> impl;
171};
172
173template <typename Scalar>
174struct equalspaced_op {
175 EIGEN_DEVICE_FUNC constexpr equalspaced_op(const Scalar& start, const Scalar& step) : m_start(start), m_step(step) {}
176 template <typename IndexType>
177 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(IndexType i) const {
178 return m_start + m_step * static_cast<Scalar>(i);
179 }
180 template <typename Packet, typename IndexType>
181 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(IndexType i) const {
182 const Packet cst_start = pset1<Packet>(m_start);
183 const Packet cst_step = pset1<Packet>(m_step);
184 const Packet cst_lin0 = plset<Packet>(Scalar(0));
185 const Packet cst_offset = pmadd(cst_lin0, cst_step, cst_start);
186
187 Packet i_packet = pset1<Packet>(static_cast<Scalar>(i));
188 return pmadd(i_packet, cst_step, cst_offset);
189 }
190 const Scalar m_start;
191 const Scalar m_step;
192};
193
194template <typename Scalar>
195struct functor_traits<equalspaced_op<Scalar>> {
196 enum {
197 Cost = NumTraits<Scalar>::AddCost + NumTraits<Scalar>::MulCost,
198 PacketAccess =
199 packet_traits<Scalar>::HasSetLinear && packet_traits<Scalar>::HasMul && packet_traits<Scalar>::HasAdd,
200 IsRepeatable = true
201 };
202};
203
204// Linear access is automatically determined from the operator() prototypes available for the given functor.
205// If it exposes an operator()(i,j), then we assume the i and j coefficients are required independently
206// and linear access is not possible. In all other cases, linear access is enabled.
207// Users should not have to deal with this structure.
208template <typename Functor>
209using functor_has_linear_access = bool_constant<!has_binary_operator<Functor>::value>;
210
211} // end namespace internal
212
213} // end namespace Eigen
214
215#endif // EIGEN_NULLARY_FUNCTORS_H