11#ifndef EIGEN_MATRIX_NORMS_H
12#define EIGEN_MATRIX_NORMS_H
15#include "./InternalHeaderCheck.h"
24template <
unsigned int UpLo,
int ExtraDiagonals,
typename Derived>
25EIGEN_DEVICE_FUNC
typename Derived::RealScalar triangular_band_abs_sum(
const MatrixBase<Derived>& matrix) {
26 static_assert(UpLo ==
Upper || UpLo ==
Lower,
"UpLo must be Upper or Lower");
27 static_assert(ExtraDiagonals == 0 || ExtraDiagonals == 1,
"Expected a triangular or Hessenberg envelope");
28 using RealScalar =
typename Derived::RealScalar;
30 if (matrix.rows() == 0 || matrix.cols() == 0)
return result;
32 constexpr bool Leading = (UpLo ==
Upper) !=
bool(Derived::IsRowMajor);
33 const Index inner = matrix.innerSize();
35 for (Index j = 0; j < matrix.outerSize(); ++j) {
36 const Index start = Leading ? Index(0) : numext::mini(inner, numext::maxi(Index(0), j - ExtraDiagonals));
37 const Index end = Leading ? numext::mini(inner, j + ExtraDiagonals + 1) : inner;
38 result += matrix.derived().innerVector(j).segment(start, end - start).template lpNorm<1>();
45template <
unsigned int UpLo,
typename Derived>
46EIGEN_DEVICE_FUNC
typename Derived::RealScalar triangular_abs_sum(
const MatrixBase<Derived>& matrix) {
47 return triangular_band_abs_sum<UpLo, 0>(matrix);
51template <
unsigned int UpLo,
typename Derived>
52EIGEN_DEVICE_FUNC
typename Derived::RealScalar hessenberg_abs_sum(
const MatrixBase<Derived>& matrix) {
53 return triangular_band_abs_sum<UpLo, 1>(matrix);
70template <
typename Scalar_>
71struct selfadjoint_l1norm_real_lanes {
72 using Scalar = Scalar_;
74 using Packet =
typename packet_traits<Scalar>::type;
75 using RPacket = Packet;
76 static constexpr Index PacketSize = unpacket_traits<Packet>::size;
79 static constexpr Index PerColumnUpTo = 4;
80 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE RPacket lanes(
const Packet& p) {
return p; }
81 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Real abs(
const Scalar& x) {
return numext::abs(x); }
83 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Real component(
const Scalar&) {
return Real(0); }
84 static EIGEN_DEVICE_FUNC
bool inRange(Real, Index) {
return true; }
89 RPacket acc0 = pset1<RPacket>(Real(0));
90 RPacket acc1 = pset1<RPacket>(Real(0));
91 template <
typename SumsEvaluator>
92 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
void step(
const RPacket& u,
const RPacket& v, SumsEvaluator& s, Index i) {
97 s.template writePacket<Unaligned>(i, padd(s.template packet<Unaligned, Packet>(i), padd(a, b)));
99 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Real sum0()
const {
return predux(acc0); }
100 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Real sum1()
const {
return predux(acc1); }
101 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Real peak()
const {
return Real(0); }
106struct selfadjoint_l1norm_complex_lanes {
107 using Scalar = std::complex<T>;
109 using Packet =
typename packet_traits<Scalar>::type;
110 using RPacket =
typename unpacket_traits<Packet>::as_real;
111 static constexpr Index PacketSize = unpacket_traits<Packet>::size;
112 static constexpr Index PerColumnUpTo = 0;
113 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE RPacket lanes(
const Packet& p) {
return p.v; }
116 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Real abs(
const Scalar& z) {
return numext::sqrt(numext::abs2(z)); }
117 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Real component(
const Scalar& z) {
118 return numext::maxi(numext::abs(numext::real(z)), numext::abs(numext::imag(z)));
122 static EIGEN_DEVICE_FUNC
bool inRange(Real peak, Index n) {
123 Real tiny = Real(n) * numext::sqrt((std::numeric_limits<Real>::min)()) / NumTraits<Real>::epsilon();
124 Real huge = numext::sqrt(NumTraits<Real>::highest()) / Real(2);
125 return peak > tiny && peak < huge;
129 RPacket acc = pset1<RPacket>(Real(0));
130 RPacket peak_ = pset1<RPacket>(Real(0));
131 template <
typename SumsEvaluator>
132 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
void step(
const RPacket& u,
const RPacket& v, SumsEvaluator& s, Index i) {
133 peak_ = pmax(peak_, pmax(pabs(u), pabs(v)));
134 RPacket r = psqrt(pselect(peven_mask(u), abs2(u), abs2(v)));
136 s.template writePacket<Unaligned>(i,
137 Packet(padd(lanes(s.template packet<Unaligned, Packet>(i)), padd(r, flip(r)))));
139 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Real sum0()
const {
return numext::real(predux(Packet(acc))); }
140 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Real sum1()
const {
return numext::imag(predux(Packet(acc))); }
141 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Real peak()
const {
return predux_max(peak_); }
145 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE RPacket flip(
const RPacket& r) {
return pcplxflip(Packet(r)).v; }
147 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE RPacket abs2(
const RPacket& v) {
148 RPacket s = pmul(v, v);
149 return padd(s, flip(s));
155template <
typename Lanes>
156struct selfadjoint_l1norm_packet_impl : Lanes {
157 using Lanes::PacketSize;
158 using typename Lanes::Packet;
159 using typename Lanes::Real;
160 using typename Lanes::RPacket;
161 using typename Lanes::Scalar;
163 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Real abs(
const Scalar& x) {
164 m_peak = numext::maxi(m_peak, Lanes::component(x));
165 return Lanes::abs(x);
167 EIGEN_DEVICE_FUNC
bool inRange(Index n)
const {
return Lanes::inRange(m_peak, n); }
169 template <
typename SumsDerived,
typename Derived>
170 EIGEN_DEVICE_FUNC
void accumulate(DenseBase<SumsDerived>& sums,
const DenseBase<Derived>& m, Index j0, Index j1,
171 Index begin, Index end) {
172 accumulateCast(sums, j0, j1, begin, m.col(j0).segment(begin, end - begin).template cast<Scalar>(),
173 m.col(j1).segment(begin, end - begin).template cast<Scalar>());
177 Real m_peak = Real(0);
179 template <
typename SumsDerived,
typename Derived0,
typename Derived1>
180 EIGEN_DEVICE_FUNC
void accumulateCast(DenseBase<SumsDerived>& sums, Index j0, Index j1, Index begin,
181 const DenseBase<Derived0>& x0,
const DenseBase<Derived1>& x1) {
182 using SumsEvaluator = evaluator<SumsDerived>;
183 using Evaluator0 = evaluator<Derived0>;
184 using Evaluator1 = evaluator<Derived1>;
186 constexpr bool Vectorize = (SumsEvaluator::Flags & Needed) == Needed && (Evaluator0::Flags & Needed) == Needed &&
187 (Evaluator1::Flags & Needed) == Needed;
188 SumsEvaluator s(sums.derived());
189 accumulate(s, j0, j1, begin, Evaluator0(x0.derived()), Evaluator1(x1.derived()), x0.size(),
190 bool_constant<Vectorize>());
192 template <
typename Evaluator>
193 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE RPacket load(
const Evaluator& x, Index i) {
194 return Lanes::lanes(x.template packet<Unaligned, Packet>(i));
196 template <
typename SumsEvaluator,
typename Evaluator0,
typename Evaluator1>
197 EIGEN_DEVICE_FUNC
void accumulate(SumsEvaluator& s, Index j0, Index j1, Index begin,
const Evaluator0& x0,
198 const Evaluator1& x1, Index from, Index to) {
201 for (Index i = from; i < to; ++i) {
202 Real a = abs(x0.coeff(i));
203 Real b = abs(x1.coeff(i));
204 s.coeffRef(begin + i) += a + b;
208 s.coeffRef(j0) += sum0;
209 s.coeffRef(j1) += sum1;
211 template <
typename SumsEvaluator,
typename Evaluator0,
typename Evaluator1>
212 EIGEN_DEVICE_FUNC
void accumulate(SumsEvaluator& s, Index j0, Index j1, Index begin,
const Evaluator0& x0,
213 const Evaluator1& x1, Index n, std::false_type) {
214 accumulate(s, j0, j1, begin, x0, x1, Index(0), n);
216 template <
typename SumsEvaluator,
typename Evaluator0,
typename Evaluator1>
217 EIGEN_DEVICE_FUNC
void accumulate(SumsEvaluator& s, Index j0, Index j1, Index begin,
const Evaluator0& x0,
218 const Evaluator1& x1, Index n, std::true_type) {
219 if (n < PacketSize)
return accumulate(s, j0, j1, begin, x0, x1, Index(0), n);
220 typename Lanes::Pass pass;
222 for (; i + PacketSize <= n; i += PacketSize) pass.step(load(x0, i), load(x1, i), s, begin + i);
223 accumulate(s, j0, j1, begin, x0, x1, i, n);
224 s.coeffRef(j0) += pass.sum0();
225 s.coeffRef(j1) += pass.sum1();
226 m_peak = numext::maxi(m_peak, pass.peak());
231template <
typename Scalar_,
typename Enable =
void>
232struct selfadjoint_l1norm_impl {
233 using Scalar = Scalar_;
234 using Real =
typename NumTraits<Scalar>::Real;
235 static constexpr Index PerColumnUpTo = 16;
236 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Real abs(
const Scalar& x)
const {
return numext::abs(x); }
237 EIGEN_DEVICE_FUNC
bool inRange(Index)
const {
return true; }
238 template <
typename SumsDerived,
typename Derived>
239 EIGEN_DEVICE_FUNC
void accumulate(DenseBase<SumsDerived>& sums,
const DenseBase<Derived>& m, Index j0, Index j1,
240 Index begin, Index end)
const {
243 for (Index i = begin; i < end; ++i) {
244 Real a = numext::abs(m.coeff(i, j0));
245 Real b = numext::abs(m.coeff(i, j1));
246 sums.coeffRef(i) += Scalar(a + b);
250 sums.coeffRef(j0) += Scalar(sum0);
251 sums.coeffRef(j1) += Scalar(sum1);
255template <
typename Scalar>
256struct selfadjoint_l1norm_impl<Scalar, std::enable_if_t<!NumTraits<Scalar>::IsComplex>>
257 : selfadjoint_l1norm_packet_impl<selfadjoint_l1norm_real_lanes<typename stable_norm_accumulator<Scalar>::type>> {};
259template <
typename Packet,
typename Enable =
void>
260struct selfadjoint_l1norm_plain_real_view : std::false_type {};
261template <
typename Packet>
262struct selfadjoint_l1norm_plain_real_view<Packet, void_t<typename unpacket_traits<Packet>::as_real>>
263 : bool_constant<sizeof(typename unpacket_traits<Packet>::as_real) ==
264 unpacket_traits<Packet>::size * sizeof(typename unpacket_traits<Packet>::type)> {};
266struct selfadjoint_l1norm_impl<
268 std::enable_if_t<selfadjoint_l1norm_plain_real_view<typename packet_traits<std::complex<T>>::type>::value>>
269 : selfadjoint_l1norm_packet_impl<selfadjoint_l1norm_complex_lanes<T>> {};
271template <
typename MatrixType,
unsigned int UpLo>
272class selfadjoint_l1norm {
273 using Scalar =
typename MatrixType::Scalar;
274 using RealScalar =
typename MatrixType::RealScalar;
277 EIGEN_DEVICE_FUNC
explicit selfadjoint_l1norm(
const MatrixType& matrix) : m_matrix(matrix) {}
279 EIGEN_DEVICE_FUNC RealScalar run()
const {
280#ifdef EIGEN_GPU_COMPILE_PHASE
282 return l1NormPerColumn();
284 if (m_matrix.rows() <= L1NormImpl::PerColumnUpTo)
return l1NormPerColumn();
287 EIGEN_IF_CONSTEXPR (
bool(MatrixType::IsRowMajor)) {
288 return l1NormStreaming<(UpLo == Lower ? Upper : Lower)>(m_matrix.transpose());
290 return l1NormStreaming<UpLo>(m_matrix);
296 using L1NormImpl = internal::selfadjoint_l1norm_impl<Scalar>;
298 using L1NormScalar =
typename L1NormImpl::Scalar;
299 using L1NormAccumulator =
typename L1NormImpl::Real;
305 template <
int Mode,
typename Mat>
306 RealScalar l1NormStreaming(
const Mat& m)
const {
307 const Index n = m.rows();
310 internal::gemv_static_vector_if<L1NormScalar, Mat::RowsAtCompileTime, Mat::MaxRowsAtCompileTime, true> static_sums;
311 ei_declare_aligned_stack_constructed_variable(L1NormScalar, sums_data, n, static_sums.data());
312 Map<Matrix<L1NormScalar, Dynamic, 1>> sums(sums_data, n);
315 L1NormAccumulator norm = L1NormAccumulator(0);
317 for (; k + 1 < n; k += 2) {
318 Index j0 = Mode ==
Lower ? k : n - 1 - k;
319 Index j1 = Mode ==
Lower ? j0 + 1 : j0 - 1;
320 Index rowBegin = Mode ==
Lower ? j1 + 1 : 0;
321 Index rowEnd = Mode ==
Lower ? n : j1;
322 impl.accumulate(sums, m, j0, j1, rowBegin, rowEnd);
324 L1NormAccumulator boundary = impl.abs(m.coeff(j1, j0));
327 L1NormAccumulator col0 = numext::real(sums.coeff(j0)) + impl.abs(m.coeff(j0, j0)) + boundary;
328 L1NormAccumulator col1 = numext::real(sums.coeff(j1)) + impl.abs(m.coeff(j1, j1)) + boundary;
329 norm = numext::maxi(norm, col0);
330 norm = numext::maxi(norm, col1);
333 Index j = Mode ==
Lower ? k : 0;
334 L1NormAccumulator col = numext::real(sums.coeff(j)) + impl.abs(m.coeff(j, j));
335 norm = numext::maxi(norm, col);
337 return impl.inRange(n) ? RealScalar(norm) : l1NormPerColumn();
341 EIGEN_DEVICE_FUNC RealScalar l1NormPerColumn()
const {
342 L1NormAccumulator norm = L1NormAccumulator(0);
343 const Index n = m_matrix.rows();
344 for (Index col = 0; col < n; ++col) {
345 L1NormAccumulator abs_col_sum;
346 EIGEN_IF_CONSTEXPR (UpLo ==
Lower) {
347 abs_col_sum = m_matrix.col(col).tail(n - col).template cast<L1NormScalar>().template lpNorm<1>() +
348 m_matrix.row(col).head(col).template cast<L1NormScalar>().template lpNorm<1>();
350 abs_col_sum = m_matrix.col(col).head(col).template cast<L1NormScalar>().template lpNorm<1>() +
351 m_matrix.row(col).tail(n - col).template cast<L1NormScalar>().template lpNorm<1>();
353 norm = numext::maxi(norm, abs_col_sum);
355 return RealScalar(norm);
358 const MatrixType& m_matrix;
362template <
unsigned int UpLo,
typename Derived>
363EIGEN_DEVICE_FUNC
typename Derived::RealScalar selfadjoint_l1_norm(
const MatrixBase<Derived>& matrix) {
364 static_assert(UpLo ==
Upper || UpLo ==
Lower,
"UpLo must be Upper or Lower");
365 eigen_assert(matrix.rows() == matrix.cols());
366 return selfadjoint_l1norm<Derived, UpLo>(matrix.derived()).run();
@ Lower
Definition Constants.h:212
@ Upper
Definition Constants.h:214
constexpr unsigned int PacketAccessBit
Definition Constants.h:98
constexpr unsigned int LinearAccessBit
Definition Constants.h:134