$darkmode
Eigen  5.0.1-dev
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 
10 #ifndef EIGEN_NULLARY_FUNCTORS_H
11 #define EIGEN_NULLARY_FUNCTORS_H
12 
13 // IWYU pragma: private
14 #include "../InternalHeaderCheck.h"
15 
16 namespace Eigen {
17 
18 namespace internal {
19 
20 template <typename Scalar>
21 struct scalar_constant_op {
22  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE scalar_constant_op(const Scalar& other) : m_other(other) {}
23  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()() const { return m_other; }
24  template <typename PacketType>
25  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const PacketType packetOp() const {
26  return internal::pset1<PacketType>(m_other);
27  }
28  const Scalar m_other;
29 };
30 template <typename Scalar>
31 struct functor_traits<scalar_constant_op<Scalar>> {
32  enum {
33  Cost = 0 /* as the constant value should be loaded in register only once for the whole expression */,
34  PacketAccess = packet_traits<Scalar>::Vectorizable,
35  IsRepeatable = true
36  };
37 };
38 
39 template <typename Scalar>
40 struct scalar_zero_op {
41  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE scalar_zero_op() = default;
42  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()() const { return Scalar(0); }
43  template <typename PacketType>
44  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const PacketType packetOp() const {
45  return internal::pzero<PacketType>(PacketType());
46  }
47 };
48 template <typename Scalar>
49 struct functor_traits<scalar_zero_op<Scalar>> : functor_traits<scalar_constant_op<Scalar>> {};
50 
51 template <typename Scalar>
52 struct scalar_identity_op {
53  template <typename IndexType>
54  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(IndexType row, IndexType col) const {
55  return row == col ? Scalar(1) : Scalar(0);
56  }
57 };
58 template <typename Scalar>
59 struct functor_traits<scalar_identity_op<Scalar>> {
60  enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = false, IsRepeatable = true };
61 };
62 
63 template <typename Scalar, bool IsInteger>
64 struct linspaced_op_impl;
65 
66 template <typename Scalar>
67 struct linspaced_op_impl<Scalar, /*IsInteger*/ false> {
68  typedef typename NumTraits<Scalar>::Real RealScalar;
69 
70  EIGEN_DEVICE_FUNC linspaced_op_impl(const Scalar& low, const Scalar& high, Index num_steps)
71  : m_low(low),
72  m_high(high),
73  m_size1(num_steps == 1 ? 1 : num_steps - 1),
74  m_step(num_steps == 1 ? Scalar() : Scalar((high - low) / RealScalar(num_steps - 1))),
75  m_flip(numext::abs(high) < numext::abs(low)) {}
76 
77  template <typename IndexType>
78  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(IndexType i) const {
79  if (m_flip)
80  return (i == 0) ? m_low : Scalar(m_high - RealScalar(m_size1 - i) * m_step);
81  else
82  return (i == m_size1) ? m_high : Scalar(m_low + RealScalar(i) * m_step);
83  }
84 
85  template <typename Packet, typename IndexType>
86  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(IndexType i) const {
87  // Principle:
88  // [low, ..., low] + ( [step, ..., step] * ( [i, ..., i] + [0, ..., size] ) )
89  Packet low = pset1<Packet>(m_low);
90  Packet high = pset1<Packet>(m_high);
91  Packet step = pset1<Packet>(m_step);
92  if (m_flip) {
93  Packet pi = plset<Packet>(Scalar(i - m_size1));
94  Packet res = pmadd(step, pi, high);
95  Packet mask = pcmp_lt(pzero(res), plset<Packet>(Scalar(i)));
96  return pselect<Packet>(mask, res, low);
97  } else {
98  Packet pi = plset<Packet>(Scalar(i));
99  Packet res = pmadd(step, pi, low);
100  Packet mask = pcmp_lt(pi, pset1<Packet>(Scalar(m_size1)));
101  return pselect<Packet>(mask, res, high);
102  }
103  }
104 
105  const Scalar m_low;
106  const Scalar m_high;
107  const Index m_size1;
108  const Scalar m_step;
109  const bool m_flip;
110 };
111 
112 template <typename Scalar>
113 struct linspaced_op_impl<Scalar, /*IsInteger*/ true> {
114  EIGEN_DEVICE_FUNC linspaced_op_impl(const Scalar& low, const Scalar& high, Index num_steps)
115  : m_low(low),
116  m_multiplier((high - low) / convert_index<Scalar>(num_steps <= 1 ? 1 : num_steps - 1)),
117  m_divisor(convert_index<Scalar>((high >= low ? num_steps : -num_steps) + (high - low)) /
118  ((numext::abs(high - low) + 1) == 0 ? 1 : (numext::abs(high - low) + 1))),
119  m_use_divisor(num_steps > 1 && (numext::abs(high - low) + 1) < num_steps) {}
120 
121  template <typename IndexType>
122  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(IndexType i) const {
123  if (m_use_divisor)
124  return m_low + convert_index<Scalar>(i) / m_divisor;
125  else
126  return m_low + convert_index<Scalar>(i) * m_multiplier;
127  }
128 
129  const Scalar m_low;
130  const Scalar m_multiplier;
131  const Scalar m_divisor;
132  const bool m_use_divisor;
133 };
134 
135 // ----- Linspace functor ----------------------------------------------------------------
136 
137 // Forward declaration (we default to random access which does not really give
138 // us a speed gain when using packet access but it allows to use the functor in
139 // nested expressions).
140 template <typename Scalar>
141 struct linspaced_op;
142 template <typename Scalar>
143 struct functor_traits<linspaced_op<Scalar>> {
144  enum {
145  Cost = 1,
146  PacketAccess = (!NumTraits<Scalar>::IsInteger) && packet_traits<Scalar>::HasSetLinear,
147  /*&& ((!NumTraits<Scalar>::IsInteger) || packet_traits<Scalar>::HasDiv),*/ // <- vectorization for integer is
148  // currently disabled
149  IsRepeatable = true
150  };
151 };
152 template <typename Scalar>
153 struct linspaced_op {
154  EIGEN_DEVICE_FUNC linspaced_op(const Scalar& low, const Scalar& high, Index num_steps)
155  : impl((num_steps == 1 ? high : low), high, num_steps) {}
156 
157  template <typename IndexType>
158  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(IndexType i) const {
159  return impl(i);
160  }
161 
162  template <typename Packet, typename IndexType>
163  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(IndexType i) const {
164  return impl.template packetOp<Packet>(i);
165  }
166 
167  // This proxy object handles the actual required temporaries and the different
168  // implementations (integer vs. floating point).
169  const linspaced_op_impl<Scalar, NumTraits<Scalar>::IsInteger> impl;
170 };
171 
172 template <typename Scalar>
173 struct equalspaced_op {
174  typedef typename NumTraits<Scalar>::Real RealScalar;
175 
176  EIGEN_DEVICE_FUNC equalspaced_op(const Scalar& start, const Scalar& step) : m_start(start), m_step(step) {}
177  template <typename IndexType>
178  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(IndexType i) const {
179  return m_start + m_step * static_cast<Scalar>(i);
180  }
181  template <typename Packet, typename IndexType>
182  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(IndexType i) const {
183  const Packet cst_start = pset1<Packet>(m_start);
184  const Packet cst_step = pset1<Packet>(m_step);
185  const Packet cst_lin0 = plset<Packet>(Scalar(0));
186  const Packet cst_offset = pmadd(cst_lin0, cst_step, cst_start);
187 
188  Packet i_packet = pset1<Packet>(static_cast<Scalar>(i));
189  return pmadd(i_packet, cst_step, cst_offset);
190  }
191  const Scalar m_start;
192  const Scalar m_step;
193 };
194 
195 template <typename Scalar>
196 struct functor_traits<equalspaced_op<Scalar>> {
197  enum {
198  Cost = NumTraits<Scalar>::AddCost + NumTraits<Scalar>::MulCost,
199  PacketAccess =
200  packet_traits<Scalar>::HasSetLinear && packet_traits<Scalar>::HasMul && packet_traits<Scalar>::HasAdd,
201  IsRepeatable = true
202  };
203 };
204 
205 // Linear access is automatically determined from the operator() prototypes available for the given functor.
206 // If it exposes an operator()(i,j), then we assume the i and j coefficients are required independently
207 // and linear access is not possible. In all other cases, linear access is enabled.
208 // Users should not have to deal with this structure.
209 template <typename Functor>
210 struct functor_has_linear_access {
211  enum { ret = !has_binary_operator<Functor>::value };
212 };
213 
214 // For unreliable compilers, let's specialize the has_*ary_operator
215 // helpers so that at least built-in nullary functors work fine.
216 #if !(EIGEN_COMP_MSVC || EIGEN_COMP_GNUC || (EIGEN_COMP_ICC >= 1600))
217 template <typename Scalar, typename IndexType>
218 struct has_nullary_operator<scalar_constant_op<Scalar>, IndexType> {
219  enum { value = 1 };
220 };
221 template <typename Scalar, typename IndexType>
222 struct has_unary_operator<scalar_constant_op<Scalar>, IndexType> {
223  enum { value = 0 };
224 };
225 template <typename Scalar, typename IndexType>
226 struct has_binary_operator<scalar_constant_op<Scalar>, IndexType> {
227  enum { value = 0 };
228 };
229 
230 template <typename Scalar, typename IndexType>
231 struct has_nullary_operator<scalar_identity_op<Scalar>, IndexType> {
232  enum { value = 0 };
233 };
234 template <typename Scalar, typename IndexType>
235 struct has_unary_operator<scalar_identity_op<Scalar>, IndexType> {
236  enum { value = 0 };
237 };
238 template <typename Scalar, typename IndexType>
239 struct has_binary_operator<scalar_identity_op<Scalar>, IndexType> {
240  enum { value = 1 };
241 };
242 
243 template <typename Scalar, typename IndexType>
244 struct has_nullary_operator<linspaced_op<Scalar>, IndexType> {
245  enum { value = 0 };
246 };
247 template <typename Scalar, typename IndexType>
248 struct has_unary_operator<linspaced_op<Scalar>, IndexType> {
249  enum { value = 1 };
250 };
251 template <typename Scalar, typename IndexType>
252 struct has_binary_operator<linspaced_op<Scalar>, IndexType> {
253  enum { value = 0 };
254 };
255 
256 template <typename Scalar, typename IndexType>
257 struct has_nullary_operator<scalar_random_op<Scalar>, IndexType> {
258  enum { value = 1 };
259 };
260 template <typename Scalar, typename IndexType>
261 struct has_unary_operator<scalar_random_op<Scalar>, IndexType> {
262  enum { value = 0 };
263 };
264 template <typename Scalar, typename IndexType>
265 struct has_binary_operator<scalar_random_op<Scalar>, IndexType> {
266  enum { value = 0 };
267 };
268 #endif
269 
270 } // end namespace internal
271 
272 } // end namespace Eigen
273 
274 #endif // EIGEN_NULLARY_FUNCTORS_H
Namespace containing all symbols from the Eigen library.
Definition: B01_Experimental.dox:1
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)