15#include "./InternalHeaderCheck.h"
22template <
typename RealScalar>
23struct stable_norm_accumulator {
24 using type = RealScalar;
28struct stable_norm_accumulator<half> {
33struct stable_norm_accumulator<bfloat16> {
37template <
typename RealScalar,
typename Accumulator>
38struct stable_normalization_normal_min {
39 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE Accumulator run() {
40 return static_cast<Accumulator
>((numext::numeric_limits<RealScalar>::min)());
45template <
typename Accumulator>
46struct stable_normalization_normal_min<half, Accumulator> {
47 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE Accumulator run() {
return Accumulator(1) / Accumulator(16384); }
50template <
typename Accumulator>
51struct stable_normalization_normal_min<bfloat16, Accumulator> {
52 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE Accumulator run() {
53 return static_cast<Accumulator
>((numext::numeric_limits<float>::min)());
57template <
typename RealScalar,
typename Accumulator>
58EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
bool stable_normalization_inv_scale(
const Accumulator& value,
59 Accumulator& invScale) {
60 safe_scaling_factors<Accumulator> factors;
61 const Accumulator normalMin = stable_normalization_normal_min<RealScalar, Accumulator>::run();
62 if (!safe_scaling<Accumulator>::try_compute_ceiling_factors_with_normal_reciprocal(value, normalMin, factors))
64 invScale = factors.invScale;
68template <
typename Accumulator>
69EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
bool stable_normalization_combined_factor(
const Accumulator& invScale,
70 const Accumulator& sqrtNorm,
71 Accumulator& factor) {
73 if (sqrtNorm < Accumulator(1) && invScale > Accumulator(NumTraits<Accumulator>::highest()) * sqrtNorm)
return false;
74 Accumulator localSqrtNorm = sqrtNorm;
75 EIGEN_OPTIMIZATION_BARRIER(localSqrtNorm)
76 factor = invScale / localSqrtNorm;
77 return factor >= stable_normalization_normal_min<Accumulator, Accumulator>::run();
80template <
typename VectorType,
typename Accumulator,
82 (int(inner_stride_at_compile_time<VectorType>::value) != 1)>
83struct stable_normalization_dispatch {
84 using Scalar =
typename traits<VectorType>::Scalar;
85 using RealScalar =
typename NumTraits<Scalar>::Real;
87 using HasWritableRealView = bool_constant<!NumTraits<Scalar>::IsComplex || complex_array_access<Scalar>::value>;
89 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE Accumulator max_abs(
const VectorType& vec) {
90 return vec.realView().template cast<Accumulator>().cwiseAbs().template maxCoeff<PropagateNaN>();
93 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE Accumulator scaled_squared_norm(
const VectorType& vec,
94 const Accumulator& factor) {
95 return (vec.realView().template cast<Accumulator>() * factor).squaredNorm();
98 template <
typename ResultType>
99 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE
void assign_scaled(ResultType& result,
const VectorType& vec,
100 const Accumulator& factor) {
101 assign_scaled_impl(result, vec, factor, HasWritableRealView());
104 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE
void scale_in_place(VectorType& vec,
const Accumulator& factor) {
105 assign_scaled_impl(vec, vec, factor, HasWritableRealView());
109 template <
typename ResultType>
110 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE
void assign_scaled_impl(ResultType& result,
const VectorType& vec,
111 const Accumulator& factor, std::true_type) {
112 result.realView() = (vec.realView().
template cast<Accumulator>() * factor).template cast<RealScalar>();
115 template <
typename ResultType>
116 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE
void assign_scaled_impl(ResultType& result,
const VectorType& vec,
117 const Accumulator& factor, std::false_type) {
118 result = vec *
static_cast<RealScalar
>(factor);
123template <
typename VectorType,
typename Accumulator>
124struct stable_normalization_dispatch<VectorType, Accumulator, true> {
125 using Scalar =
typename traits<VectorType>::Scalar;
126 using RealScalar =
typename NumTraits<Scalar>::Real;
128 using PlainVector = Matrix<Scalar, Dynamic, 1>;
129 using ConstContiguousMap = Map<const PlainVector, evaluator<VectorType>::Alignment>;
130 using ContiguousMap = Map<PlainVector, evaluator<VectorType>::Alignment>;
132 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE
bool is_contiguous(
const VectorType& vec) {
133 return vec.innerStride() == 1 && (vec.outerSize() == 1 || vec.outerStride() == vec.innerSize());
136 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE Accumulator max_abs(
const VectorType& vec) {
137 if (is_contiguous(vec)) {
138 const ConstContiguousMap contiguous(vec.data(), vec.size());
139 return stable_normalization_dispatch<ConstContiguousMap, Accumulator, false>::max_abs(contiguous);
141 return stable_normalization_dispatch<VectorType, Accumulator, false>::max_abs(vec);
144 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE Accumulator scaled_squared_norm(
const VectorType& vec,
145 const Accumulator& factor) {
146 if (is_contiguous(vec)) {
147 const ConstContiguousMap contiguous(vec.data(), vec.size());
148 return stable_normalization_dispatch<ConstContiguousMap, Accumulator, false>::scaled_squared_norm(contiguous,
151 return stable_normalization_dispatch<VectorType, Accumulator, false>::scaled_squared_norm(vec, factor);
154 template <
typename ResultType>
155 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE
void assign_scaled(ResultType& result,
const VectorType& vec,
156 const Accumulator& factor) {
157 if (is_contiguous(vec)) {
158 const ConstContiguousMap contiguous(vec.data(), vec.size());
159 Map<PlainVector> output(result.data(), result.size());
160 stable_normalization_dispatch<ConstContiguousMap, Accumulator, false>::assign_scaled(output, contiguous, factor);
163 stable_normalization_dispatch<VectorType, Accumulator, false>::assign_scaled(result, vec, factor);
166 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE
void scale_in_place(VectorType& vec,
const Accumulator& factor) {
167 if (is_contiguous(vec)) {
168 ContiguousMap contiguous(vec.data(), vec.size());
169 stable_normalization_dispatch<ContiguousMap, Accumulator, false>::scale_in_place(contiguous, factor);
172 stable_normalization_dispatch<VectorType, Accumulator, false>::scale_in_place(vec, factor);
177template <
typename VectorType,
typename Accumulator>
178EIGEN_DEVICE_FUNC EIGEN_DONT_INLINE
void stable_normalization_scale_in_place(VectorType& vec,
179 const Accumulator& factor) {
180 stable_normalization_dispatch<VectorType, Accumulator>::scale_in_place(vec, factor);
183template <
typename VectorType,
typename Divisor>
184EIGEN_DEVICE_FUNC EIGEN_DONT_INLINE
void stable_normalization_divide_in_place(VectorType& vec,
const Divisor& divisor) {
188template <
typename VectorType,
typename Accumulator>
189EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
void stable_normalization_with_division(VectorType& vec,
194 const Accumulator sqrtMax = numext::sqrt(
maxCoeff);
195 const RealScalar scale1 =
static_cast<RealScalar
>(sqrtMax);
196 const RealScalar scale2 =
static_cast<RealScalar
>(
maxCoeff / sqrtMax);
197 stable_normalization_divide_in_place(vec, scale1);
198 stable_normalization_divide_in_place(vec, scale2);
200 if (z > Accumulator(0)) {
201 stable_normalization_scale_in_place(vec, Accumulator(1) / numext::sqrt(z));
205template <
typename VectorType,
typename Accumulator,
206 bool = use_subnormal_preserving_scaling<Accumulator, typename traits<VectorType>::Scalar>::value>
207struct stable_normalization_subnormal_recovery {
208 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE
void run(VectorType&) {}
211template <
typename VectorType,
typename Accumulator>
212struct stable_normalization_subnormal_recovery<VectorType, Accumulator, true> {
213 using RealScalar =
typename NumTraits<typename traits<VectorType>::Scalar>::Real;
215 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE
void run(VectorType& vec) {
216 using Binary = binary_floating_point_traits<RealScalar>;
217 using Bits =
typename Binary::Bits;
218 decltype(
auto) components = vec.realView();
220 for (Index col = 0; col < components.cols(); ++col) {
221 for (Index row = 0; row < components.rows(); ++row) {
222 const Bits bits = Binary::magnitude(components.coeff(row, col));
223 if (bits > maxBits) maxBits = bits;
226 if (maxBits == 0 || maxBits >= Binary::kExponentUnit)
return;
228 const Accumulator maxAbs = numext::bit_cast<RealScalar>(maxBits);
229 const auto factors = safe_scaling<Accumulator>::compute_ceiling_factors(maxAbs);
230 safe_scaling<Accumulator>::scale_in_place(vec, maxAbs, factors);
231 const Accumulator squaredNorm = components.template cast<Accumulator>().squaredNorm();
232 if (squaredNorm > Accumulator(0)) {
233 stable_normalization_divide_in_place(vec, numext::sqrt(squaredNorm));
244template <
typename Xpr>
245struct squared_norm_runtime_unit_stride {
246 using Scalar =
typename traits<Xpr>::Scalar;
247 static constexpr bool value =
248 bool(traits<Xpr>::Flags &
DirectAccessBit) && bool(packet_traits<Scalar>::Vectorizable) &&
249 !bool(internal::is_same<Scalar, bool>::value) && (int(inner_stride_at_compile_time<Xpr>::value) != 1);
252template <typename Derived, typename Scalar = typename traits<Derived>::Scalar,
typename Enable =
void>
253struct squared_norm_impl {
254 using Real =
typename NumTraits<Scalar>::Real;
255 static EIGEN_DEVICE_FUNC
constexpr EIGEN_STRONG_INLINE Real run(
const Derived& a) {
256 return a.realView().cwiseAbs2().sum();
260template <
typename Derived>
261struct squared_norm_impl<Derived, bool, void> {
262 static EIGEN_DEVICE_FUNC
constexpr EIGEN_STRONG_INLINE
bool run(
const Derived& a) {
return a.any(); }
268template <
typename Derived,
typename Scalar>
269struct squared_norm_impl<Derived, Scalar, std::enable_if_t<squared_norm_runtime_unit_stride<Derived>::value>> {
270 using Real =
typename NumTraits<Scalar>::Real;
271 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Real run(
const Derived& a) {
272 if (a.innerStride() == 1 && (a.outerSize() == 1 || a.outerStride() == a.innerSize())) {
275 return contiguous.realView().cwiseAbs2().sum();
277 return a.realView().cwiseAbs2().sum();
294template <
typename Derived>
295template <
typename OtherDerived>
296EIGEN_DEVICE_FUNC
constexpr EIGEN_STRONG_INLINE
298 typename internal::traits<OtherDerived>::Scalar>::ReturnType
300 return internal::inner_product_dispatch<Derived, OtherDerived, true>::run(derived(), other.derived());
311template <
typename Derived>
314 return internal::squared_norm_impl<Derived>::run(derived());
323template <
typename Derived>
338template <
typename Derived>
341 using Nested_ =
typename internal::nested_eval<Derived, 2>::type;
342 Nested_ n(derived());
343 RealScalar z = n.squaredNorm();
345 if (z > RealScalar(0))
346 return n / numext::sqrt(z);
359template <
typename Derived>
363 if (z > RealScalar(0)) derived() /= numext::sqrt(z);
378template <
typename Derived>
379EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
const typename MatrixBase<Derived>::PlainObject
381 using Nested_ =
typename internal::nested_eval<Derived, 3>::type;
382 using NestedClean = internal::remove_all_t<Nested_>;
383 using Accumulator =
typename internal::stable_norm_accumulator<RealScalar>::type;
384 using Dispatch = internal::stable_normalization_dispatch<NestedClean, Accumulator>;
385 Nested_ vec(derived());
386 if (EIGEN_PREDICT_FALSE(vec.size() == 0))
return vec;
390 const Accumulator w = Dispatch::max_abs(vec);
391 const Accumulator highest =
static_cast<Accumulator
>(NumTraits<RealScalar>::highest());
392 if (EIGEN_PREDICT_FALSE(!(w > Accumulator(0)))) {
394 internal::stable_normalization_subnormal_recovery<PlainObject, Accumulator>::run(
normalized);
397 if (EIGEN_PREDICT_FALSE(!(w <= highest)))
return vec;
399 Accumulator invScale;
400 if (EIGEN_PREDICT_TRUE((internal::stable_normalization_inv_scale<RealScalar>(w, invScale)))) {
401 const Accumulator z = Dispatch::scaled_squared_norm(vec, invScale);
402 if (z > Accumulator(0)) {
403 const Accumulator sqrt_z = numext::sqrt(z);
406 if (EIGEN_PREDICT_TRUE(internal::stable_normalization_combined_factor(invScale, sqrt_z, factor))) {
407 Dispatch::assign_scaled(
normalized, vec, factor);
410 Dispatch::assign_scaled(
normalized, vec, invScale);
411 internal::stable_normalization_divide_in_place(
normalized,
static_cast<RealScalar
>(sqrt_z));
417 internal::stable_normalization_subnormal_recovery<PlainObject, Accumulator>::run(
normalized);
422 internal::stable_normalization_with_division(
normalized, w);
437template <
typename Derived>
439 using Accumulator =
typename internal::stable_norm_accumulator<RealScalar>::type;
440 using Dispatch = internal::stable_normalization_dispatch<Derived, Accumulator>;
441 if (EIGEN_PREDICT_FALSE(size() == 0))
return;
443 const Accumulator w = Dispatch::max_abs(derived());
444 const Accumulator highest =
static_cast<Accumulator
>(NumTraits<RealScalar>::highest());
445 if (EIGEN_PREDICT_FALSE(!(w > Accumulator(0)))) {
446 internal::stable_normalization_subnormal_recovery<Derived, Accumulator>::run(derived());
449 if (EIGEN_PREDICT_FALSE(!(w <= highest)))
return;
451 Accumulator invScale;
452 if (EIGEN_PREDICT_TRUE((internal::stable_normalization_inv_scale<RealScalar>(w, invScale)))) {
453 const Accumulator z = Dispatch::scaled_squared_norm(derived(), invScale);
454 if (z > Accumulator(0)) {
455 const Accumulator sqrt_z = numext::sqrt(z);
457 if (EIGEN_PREDICT_TRUE(internal::stable_normalization_combined_factor(invScale, sqrt_z, factor))) {
458 Dispatch::scale_in_place(derived(), factor);
460 internal::stable_normalization_scale_in_place(derived(), invScale);
461 internal::stable_normalization_divide_in_place(derived(),
static_cast<RealScalar
>(sqrt_z));
464 internal::stable_normalization_subnormal_recovery<Derived, Accumulator>::run(derived());
469 internal::stable_normalization_with_division(derived(), w);
476template <
typename Derived,
int p>
477struct lpNorm_selector {
481 return pow(m.
cwiseAbs().array().pow(p).sum(), RealScalar(1) / p);
485template <
typename Derived>
486struct lpNorm_selector<Derived, 1> {
487 EIGEN_DEVICE_FUNC
static inline typename NumTraits<typename traits<Derived>::Scalar>::Real run(
488 const MatrixBase<Derived>& m) {
489 return m.cwiseAbs().sum();
493template <
typename Derived>
494struct lpNorm_selector<Derived, 2> {
495 EIGEN_DEVICE_FUNC
static inline typename NumTraits<typename traits<Derived>::Scalar>::Real run(
496 const MatrixBase<Derived>& m) {
501template <
typename Derived>
502struct lpNorm_selector<Derived, Infinity> {
503 using RealScalar =
typename NumTraits<typename traits<Derived>::Scalar>::Real;
504 EIGEN_DEVICE_FUNC
static inline RealScalar run(
const MatrixBase<Derived>& m) {
505 if (Derived::SizeAtCompileTime == 0 || (Derived::SizeAtCompileTime == Dynamic && m.size() == 0))
506 return RealScalar(0);
507 return m.cwiseAbs().maxCoeff();
527template <
typename Derived>
529#ifndef EIGEN_PARSED_BY_DOXYGEN
532EIGEN_DEVICE_FUNC MatrixBase<Derived>::RealScalar
535 return internal::lpNorm_selector<Derived, p>::run(*
this);
546template <
typename Derived>
547template <
typename OtherDerived>
549 typename internal::nested_eval<Derived, 2>::type nested(derived());
550 typename internal::nested_eval<OtherDerived, 2>::type otherNested(other.derived());
551 return numext::abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm();
565template <
typename Derived>
567 typename internal::nested_eval<Derived, 1>::type self(derived());
568 for (Index i = 0; i < cols(); ++i) {
569 if (!internal::isApprox(self.col(i).squaredNorm(),
static_cast<RealScalar
>(1), prec))
return false;
570 for (Index j = 0; j < i; ++j)
571 if (!internal::isMuchSmallerThan(self.col(i).dot(self.col(j)),
static_cast<Scalar>(1), prec))
return false;
constexpr const GlobalUnaryPowReturnType< Derived, ScalarExponent > pow(const Eigen::ArrayBase< Derived > &x, const ScalarExponent &exponent)
internal::traits< Derived >::Scalar maxCoeff() const
Definition Redux.h:799
typename internal::traits< Derived >::Scalar Scalar
Definition DenseBase.h:63
constexpr CastXpr< NewType >::Type cast() const
Definition DenseBase.h:66
A matrix or vector expression mapping an existing array of data.
Definition Map.h:97
Base class for all dense matrices, vectors, and expressions.
Definition MatrixBase.h:53
void stableNormalize()
Definition Dot.h:438
constexpr ScalarBinaryOpTraits< typenameinternal::traits< Derived >::Scalar, typenameinternal::traits< OtherDerived >::Scalar >::ReturnType dot(const MatrixBase< OtherDerived > &other) const
Definition Dot.h:299
const PlainObject stableNormalized() const
Definition Dot.h:380
const PlainObject normalized() const
Definition Dot.h:339
RealScalar lpNorm() const
Definition Dot.h:534
bool isUnitary(const RealScalar &prec=NumTraits< Scalar >::dummy_precision()) const
Definition Dot.h:566
const CwiseUnaryOp< internal::scalar_abs_op< Scalar >, const Derived > cwiseAbs() const
constexpr RealScalar squaredNorm() const
Definition Dot.h:313
void normalize()
Definition Dot.h:360
RealScalar norm() const
Definition Dot.h:325
bool isOrthogonal(const MatrixBase< OtherDerived > &other, const RealScalar &prec=NumTraits< Scalar >::dummy_precision()) const
Definition Dot.h:548
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:188
constexpr unsigned int DirectAccessBit
Definition Constants.h:160
Holds information about the various numeric (i.e. scalar) types allowed by Eigen.
Definition NumTraits.h:233
Determines whether the given binary operation of two numeric types is allowed and what the scalar ret...
Definition XprHelper.h:1062