Eigen  5.0.1
 
Loading...
Searching...
No Matches
Householder.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@gmail.com>
5// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
6//
7// This Source Code Form is subject to the terms of the Mozilla
8// Public License v. 2.0. If a copy of the MPL was not distributed
9// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10// SPDX-License-Identifier: MPL-2.0
11
12#ifndef EIGEN_HOUSEHOLDER_H
13#define EIGEN_HOUSEHOLDER_H
14
15// IWYU pragma: private
16#include "./InternalHeaderCheck.h"
17
18namespace Eigen {
19
20namespace internal {
21template <int N>
22struct decrement_size : std::integral_constant<int, N - 1> {};
23template <>
24struct decrement_size<0> : std::integral_constant<int, 0> {};
25template <>
26struct decrement_size<Dynamic> : std::integral_constant<int, Dynamic> {};
27
28template <typename RealScalar>
29struct householder_norm_accumulator : stable_norm_accumulator<RealScalar> {};
30
31template <>
32struct householder_norm_accumulator<float> {
33 // Stable norm reductions can avoid underflow by scaling in float. Householder construction must also preserve each
34 // subnormal component while forming scale-free tau and essential-vector ratios, so widen only these intermediates.
35 using type = double;
36};
37
38template <typename Scalar, typename Accumulator, bool IsComplex = NumTraits<Scalar>::IsComplex>
39struct householder_rescale;
40
41template <typename Scalar, typename Accumulator>
42struct householder_rescale<Scalar, Accumulator, false> {
43 EIGEN_DEVICE_FUNC static Scalar run(const Scalar& value, const Accumulator& scale) {
44 return Scalar(Accumulator(value) / scale);
45 }
46
47 // This overload only keeps the shared C++14 call site well-formed; real inputs return before reaching it.
48 EIGEN_DEVICE_FUNC static Scalar zero_tail_tau(const Accumulator& scaledReal, const Accumulator&,
49 const Scalar& scaledBeta) {
50 return Scalar(1) - Scalar(scaledReal) / scaledBeta;
51 }
52
53 template <typename EssentialPart, typename TailView>
54 EIGEN_DEVICE_FUNC static void run(EssentialPart& essential, const TailView& tail, const Accumulator& scale,
55 const Scalar& denominator) {
56 essential = ((tail.template cast<Accumulator>().array() / scale) / Accumulator(denominator))
57 .matrix()
58 .template cast<Scalar>();
59 }
60};
61
62template <typename Scalar, typename Accumulator>
63struct householder_rescale<Scalar, Accumulator, true> {
64 using RealScalar = typename NumTraits<Scalar>::Real;
65
66 EIGEN_DEVICE_FUNC static Scalar run(const Scalar& value, const Accumulator& scale) {
67 return Scalar(RealScalar(Accumulator(numext::real(value)) / scale),
68 RealScalar(Accumulator(numext::imag(value)) / scale));
69 }
70
71 EIGEN_DEVICE_FUNC static Scalar zero_tail_tau(const Accumulator& scaledReal, const Accumulator& scaledImag,
72 const RealScalar& scaledBeta) {
73 return Scalar(RealScalar(1) - RealScalar(scaledReal) / scaledBeta, RealScalar(scaledImag) / scaledBeta);
74 }
75
76 template <typename EssentialPart, typename TailView>
77 EIGEN_DEVICE_FUNC static void run(EssentialPart& essential, const TailView& tail, const Accumulator& scale,
78 const Scalar& denominator) {
79 run(essential, tail, scale, denominator, complex_array_access<Scalar>());
80 }
81
82 private:
83 template <typename EssentialPart, typename TailView>
84 EIGEN_DEVICE_FUNC static void run(EssentialPart& essential, const TailView& tail, const Accumulator& scale,
85 const Scalar& denominator, std::true_type) {
86 essential.realView().array() =
87 (tail.realView().array().template cast<Accumulator>() / scale).template cast<RealScalar>();
88 essential.array() /= denominator;
89 }
90
91 template <typename EssentialPart, typename TailView>
92 EIGEN_DEVICE_FUNC static void run(EssentialPart& essential, const TailView& tail, const Accumulator& scale,
93 const Scalar& denominator, std::false_type) {
94 for (Index i = 0; i < tail.size(); ++i) essential.coeffRef(i) = run(tail.coeff(i), scale) / denominator;
95 }
96};
97} // namespace internal
98
115template <typename Derived>
116EIGEN_DEVICE_FUNC void MatrixBase<Derived>::makeHouseholderInPlace(Scalar& tau, RealScalar& beta) {
118 size() - 1);
119 makeHouseholder(essentialPart, tau, beta);
120}
121
137template <typename Derived>
138template <typename EssentialPart>
139EIGEN_DEVICE_FUNC void MatrixBase<Derived>::makeHouseholder(EssentialPart& essential, Scalar& tau,
140 RealScalar& beta) const {
141 using numext::conj;
142
143 EIGEN_STATIC_ASSERT_VECTOR_ONLY(EssentialPart)
145
146 const RealScalar tailSqNorm = size() == 1 ? RealScalar(0) : tail.unwind().squaredNorm();
147 Scalar c0 = coeff(0);
148 const RealScalar tol = (std::numeric_limits<RealScalar>::min)();
149 RealScalar unscaledNormThreshold = tol;
150 // Whether the direct construction's abs2(c0) + tailSqNorm would exceed the range. Integer scalars keep the direct
151 // path they have always taken; the scaled path divides by a component maximum, which does not apply to them.
152 bool unscaledSqNormOverflows = false;
153 EIGEN_IF_CONSTEXPR (!NumTraits<RealScalar>::IsInteger) {
154 const RealScalar precision = RealScalar(NumTraits<RealScalar>::epsilon());
155 // With flush-to-zero arithmetic, every tail component square below tol can be lost. Account for every component
156 // so the discarded contribution is at most epsilon relative to a squared norm above this threshold. The narrow
157 // normal range of half makes this scaled path common for moderately small inputs; preserving the bound there is
158 // intentional.
159 const RealScalar componentCount = RealScalar(size() - 1) * RealScalar(NumTraits<Scalar>::IsComplex ? 2 : 1);
160 unscaledNormThreshold = (tol / precision) * componentCount;
161
162 // Both terms overflow well before the reflector stops being representable, so classify the input before the
163 // squares are formed: abs2(c0) is at most twice the square of the larger component of c0, and the tail's own
164 // reduction has already overflowed if tailSqNorm exceeds the bound. Testing the sum with isinf() instead would
165 // not survive -ffinite-math-only, which folds that test away, whereas a comparison against a finite bound is
166 // still evaluated.
167 const RealScalar sqNormBound = NumTraits<RealScalar>::highest() / RealScalar(2);
168 const RealScalar componentBound = numext::sqrt<RealScalar>(sqNormBound / RealScalar(2));
169 const RealScalar c0Max = numext::maxi(numext::abs(numext::real(c0)), numext::abs(numext::imag(c0)));
170 unscaledSqNormOverflows = !(c0Max <= componentBound) || !(tailSqNorm <= sqNormBound);
171 }
172
173 // The scaled path forms the reflector from ratios of the largest component and never squares an unscaled
174 // coefficient, so it is also the path for inputs the direct construction cannot square.
175 if ((tailSqNorm <= unscaledNormThreshold || unscaledSqNormOverflows) && !(numext::isnan)(c0)) {
176 using Accumulator = typename internal::householder_norm_accumulator<RealScalar>::type;
177 const auto tailView = tail.unwind();
178 const auto tailComponents = tailView.realView();
179 // Component maxima cannot underflow when a representable tail is nonzero.
180 const Accumulator tailMax =
181 tailView.size() == 0 ? Accumulator(0) : Accumulator(tailComponents.cwiseAbs().maxCoeff());
182 if (numext::is_exactly_zero(tailMax) && numext::is_exactly_zero(numext::imag(c0))) {
183 tau = RealScalar(0);
184 beta = numext::real(c0);
185 essential.setZero();
186 return;
187 }
188 const Accumulator c0RealAbs = numext::abs(Accumulator(numext::real(c0)));
189 const Accumulator c0ImagAbs = numext::abs(Accumulator(numext::imag(c0)));
190 const Accumulator c0Max = numext::maxi(c0RealAbs, c0ImagAbs);
191 const Accumulator scale = numext::maxi(c0Max, tailMax);
192 const RealScalar realScale = RealScalar(scale);
193 // A target that flushes this scale cannot form meaningful ratios from the entirely subnormal vector.
194 if (scale < Accumulator(tol) && numext::is_exactly_zero(realScale + realScale)) {
195 tau = RealScalar(0);
196 beta = numext::real(c0);
197 essential.setZero();
198 return;
199 }
200 if (numext::is_exactly_zero(tailMax)) {
201 const Accumulator scaledReal = Accumulator(numext::real(c0)) / scale;
202 const Accumulator scaledImag = Accumulator(numext::imag(c0)) / scale;
203 RealScalar scaledBeta = RealScalar(numext::hypot(scaledReal, scaledImag));
204 if (numext::real(c0) >= RealScalar(0)) scaledBeta = -scaledBeta;
205 beta = RealScalar(scale * Accumulator(scaledBeta));
206 essential.setZero();
207 tau = internal::householder_rescale<Scalar, Accumulator>::zero_tail_tau(scaledReal, scaledImag, scaledBeta);
208 return;
209 }
210 // Form the reflector from scale-free ratios to preserve subnormal inputs and avoid overflowing c0 - beta.
211 Accumulator scaledTailSqNorm;
212 EIGEN_IF_CONSTEXPR (std::is_same<RealScalar, float>::value) {
213 // Double has enough exponent range to square every finite float scale without underflow or overflow.
214 scaledTailSqNorm = tailComponents.template cast<Accumulator>().squaredNorm() / (scale * scale);
215 } else {
216 scaledTailSqNorm = (tailComponents.template cast<Accumulator>().array() / scale).matrix().squaredNorm();
217 }
218 if (numext::is_exactly_zero(RealScalar(tailMax / scale)) && numext::is_exactly_zero(numext::imag(c0))) {
219 tau = RealScalar(0);
220 beta = numext::real(c0);
221 essential.setZero();
222 return;
223 }
224 const Scalar scaledC0 = internal::householder_rescale<Scalar, Accumulator>::run(c0, scale);
225 RealScalar scaledBeta =
226 RealScalar(numext::hypot(Accumulator(numext::abs(scaledC0)), numext::sqrt(scaledTailSqNorm)));
227 if (numext::real(c0) >= RealScalar(0)) scaledBeta = -scaledBeta;
228 beta = RealScalar(scale * Accumulator(scaledBeta));
229 internal::householder_rescale<Scalar, Accumulator>::run(essential, tailView, scale, scaledC0 - scaledBeta);
230 tau = conj(Scalar(RealScalar(1)) - scaledC0 / scaledBeta);
231 return;
232 }
233 beta = numext::sqrt<RealScalar>(numext::abs2(c0) + tailSqNorm);
234 if (numext::real(c0) >= RealScalar(0)) beta = -beta;
235 essential = tail.unwind() / (c0 - beta);
236 tau = conj((beta - c0) / beta);
237}
238
239namespace internal {
240
241template <typename Derived, typename EssentialPart,
242 bool Fused = !Derived::IsRowMajor && EssentialPart::ColsAtCompileTime == 1 &&
243 (EssentialPart::RowsAtCompileTime == 1 || EssentialPart::RowsAtCompileTime == 2)>
244struct householder_apply_left_impl {
245 using Scalar = typename Derived::Scalar;
246 static EIGEN_DEVICE_FUNC void run(MatrixBase<Derived>& mat, const EssentialPart& essential, const Scalar& tau,
247 Scalar* workspace) {
250 mat.rows() - 1, mat.cols());
251 tmp.noalias() = essential.adjoint() * bottom.unwind();
252 tmp = tau * (tmp + mat.row(0));
253 mat.row(0) -= tmp;
254 bottom.unwind().noalias() -= essential * tmp;
255 }
256};
257
258// Two- and three-element reflectors on column-major storage: finishing each column before advancing replaces
259// four strided row passes, which thrash the cache at large outer strides (issue #3160).
260template <typename Derived, typename EssentialPart>
261struct householder_apply_left_impl<Derived, EssentialPart, true> {
262 using Scalar = typename Derived::Scalar;
263 static EIGEN_DEVICE_FUNC void run(MatrixBase<Derived>& mat, const EssentialPart& essential, const Scalar& tau,
264 Scalar*) {
265 // Evaluated once so that the column loop reads plain coefficients; tau may reference a coefficient of mat.
266 const Matrix<Scalar, EssentialPart::RowsAtCompileTime, 1> v = essential;
267 const Scalar tauValue = tau;
268 Block<Derived, EssentialPart::RowsAtCompileTime, Derived::ColsAtCompileTime> bottom(mat.derived(), 1, 0,
269 mat.rows() - 1, mat.cols());
270 for (Index j = 0; j < mat.cols(); ++j) {
271 const Scalar tmp = tauValue * (v.dot(bottom.col(j)) + mat.coeff(0, j));
272 mat.coeffRef(0, j) -= tmp;
273 bottom.col(j) -= v * tmp;
274 }
275 }
276};
277
278template <typename Derived, typename EssentialPart,
279 bool Fused = !Derived::IsRowMajor && bool(traits<Derived>::Flags & DirectAccessBit) &&
280 inner_stride_at_compile_time<Derived>::value == 1 &&
281 packet_traits<typename Derived::Scalar>::Vectorizable && EssentialPart::ColsAtCompileTime == 1 &&
282 (EssentialPart::RowsAtCompileTime == 1 || EssentialPart::RowsAtCompileTime == 2)>
283struct householder_apply_right_impl {
284 using Scalar = typename Derived::Scalar;
285 static EIGEN_DEVICE_FUNC void run(MatrixBase<Derived>& mat, const EssentialPart& essential, const Scalar& tau,
286 Scalar* workspace) {
287 Map<typename plain_col_type<typename Derived::PlainObject>::type> tmp(workspace, mat.rows());
288 Block<Derived, Derived::RowsAtCompileTime, EssentialPart::SizeAtCompileTime> right(mat.derived(), 0, 1, mat.rows(),
289 mat.cols() - 1);
290 tmp.noalias() = right.unwind() * essential;
291 // M H = M - (M v) tau v^*: tau multiplies from the right, as in the one-column branch.
292 tmp = (tmp + mat.col(0)) * tau;
293 mat.col(0) = mat.col(0) - tmp;
294 right.unwind().noalias() -= tmp * essential.adjoint();
295 }
296};
297
298// Two- and three-element reflectors on contiguous columns: one pass down the rows updates all the columns, where the
299// general path makes four passes through a temporary. These are the O(n^3) updates of the Francis QR step.
300template <typename Derived, typename EssentialPart>
301struct householder_apply_right_impl<Derived, EssentialPart, true> {
302 using Scalar = typename Derived::Scalar;
303 using Packet = typename packet_traits<Scalar>::type;
304 static constexpr int K = EssentialPart::RowsAtCompileTime;
305
306 static EIGEN_DEVICE_FUNC void run(MatrixBase<Derived>& mat, const EssentialPart& essential, const Scalar& tau,
307 Scalar*) {
308 constexpr Index PacketSize = unpacket_traits<Packet>::size;
309 eigen_assert(mat.cols() == K + 1);
310 // Copied first: tau and the essential part may alias coefficients of mat.
311 Scalar v[K], vc[K];
312 for (int j = 0; j < K; ++j) {
313 v[j] = essential.coeff(j);
314 vc[j] = numext::conj(v[j]);
315 }
316 const Scalar tauValue = tau;
317 const Index rows = mat.rows();
318 Scalar* col[K + 1];
319 for (int j = 0; j <= K; ++j) col[j] = &mat.derived().coeffRef(0, j);
320
321 const Packet ptau = pset1<Packet>(tauValue);
322 Packet pv[K], pvc[K];
323 for (int j = 0; j < K; ++j) {
324 pv[j] = pset1<Packet>(v[j]);
325 pvc[j] = pset1<Packet>(vc[j]);
326 }
327 const Index vectorEnd = numext::round_down(rows, PacketSize);
328 for (Index i = 0; i < vectorEnd; i += PacketSize) {
329 Packet x[K + 1];
330 for (int j = 0; j <= K; ++j) x[j] = ploadu<Packet>(col[j] + i);
331 Packet t = x[0];
332 for (int j = 0; j < K; ++j) t = pmadd(x[j + 1], pv[j], t);
333 t = pmul(t, ptau);
334 pstoreu(col[0] + i, psub(x[0], t));
335 for (int j = 0; j < K; ++j) pstoreu(col[j + 1] + i, pnmadd(t, pvc[j], x[j + 1]));
336 }
337 for (Index i = vectorEnd; i < rows; ++i) {
338 Scalar t = col[0][i];
339 for (int j = 0; j < K; ++j) t += col[j + 1][i] * v[j];
340 t *= tauValue;
341 col[0][i] -= t;
342 for (int j = 0; j < K; ++j) col[j + 1][i] -= t * vc[j];
343 }
344 }
345};
346
347} // namespace internal
348
364template <typename Derived>
365template <typename EssentialPart>
366EIGEN_DEVICE_FUNC void MatrixBase<Derived>::applyHouseholderOnTheLeft(const EssentialPart& essential, const Scalar& tau,
367 Scalar* workspace) {
368 if (rows() == 1) {
369 // H = 1 - tau multiplies from the left, which a noncommutative scalar distinguishes.
370 *this = (Scalar(1) - tau) * *this;
371 } else if (!numext::is_exactly_zero(tau)) {
372 internal::householder_apply_left_impl<Derived, EssentialPart>::run(*this, essential, tau, workspace);
373 }
374}
375
391template <typename Derived>
392template <typename EssentialPart>
393EIGEN_DEVICE_FUNC void MatrixBase<Derived>::applyHouseholderOnTheRight(const EssentialPart& essential,
394 const Scalar& tau, Scalar* workspace) {
395 if (cols() == 1) {
396 *this *= Scalar(1) - tau;
397 } else if (!numext::is_exactly_zero(tau)) {
398 internal::householder_apply_right_impl<Derived, EssentialPart>::run(*this, essential, tau, workspace);
399 }
400}
401
402} // end namespace Eigen
403
404#endif // EIGEN_HOUSEHOLDER_H
Expression of a fixed-size or dynamic-size block.
Definition Block.h:111
constexpr FixedSegmentReturnType<... >::Type tail(NType n)
Definition DenseBase.h:1221
constexpr RowXpr row(Index i)
Definition DenseBase.h:1094
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 makeHouseholder(EssentialPart &essential, Scalar &tau, RealScalar &beta) const
Definition Householder.h:139
void applyHouseholderOnTheLeft(const EssentialPart &essential, const Scalar &tau, Scalar *workspace)
Definition Householder.h:366
void applyHouseholderOnTheRight(const EssentialPart &essential, const Scalar &tau, Scalar *workspace)
Definition Householder.h:393
void makeHouseholderInPlace(Scalar &tau, RealScalar &beta)
Definition Householder.h:116
Expression of a fixed-size or dynamic-size sub-vector.
Definition VectorBlock.h:59
constexpr unsigned int DirectAccessBit
Definition Constants.h:160