blob: 1337dec054e7ab520496a1fda01142bd8667f345 [file] [edit]
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2024 The Eigen Authors
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// SPDX-License-Identifier: MPL-2.0
#ifndef EIGEN_LAPACK_UTILS_H
#define EIGEN_LAPACK_UTILS_H
#include <algorithm>
#include <cctype>
#include <cmath>
#include <complex>
#include <limits>
#include "../Eigen/Core"
namespace Eigen {
namespace internal {
// Compute sqrt(x*x + y*y) taking care not to cause unnecessary overflow.
template <typename T>
T xlapy2(const T x, const T y) {
return numext::hypot(x, y);
}
// Compute sqrt(x*x + y*y + z*z) taking care not to cause unnecessary overflow.
template <typename T>
T xlapy3(const T x, const T y, const T z) {
if (x == T(0) && y == T(0) && z == T(0)) {
return T(0);
}
const T xabs = numext::abs(x);
const T yabs = numext::abs(y);
const T zabs = numext::abs(z);
const T w = numext::maxi(numext::maxi(xabs, yabs), zabs);
if (numext::is_exactly_zero(w)) {
return (xabs + yabs + zabs);
}
const T tx = xabs / w;
const T ty = yabs / w;
const T tz = zabs / w;
return w * numext::sqrt(tx * tx + ty * ty + tz * tz);
}
// Determines machine parameters according to LAPACK specification.
template <typename T>
T xlamch(const char c) {
switch (std::tolower(static_cast<unsigned char>(c))) {
case 'e':
return numext::numeric_limits<T>::epsilon() / numext::numeric_limits<T>::radix;
case 's': {
EIGEN_CONSTEXPR T tiny = (numext::numeric_limits<T>::min)();
EIGEN_CONSTEXPR T small = T(1) / (numext::numeric_limits<T>::max)();
EIGEN_CONSTEXPR T small_scaled = small * (T(1) + numext::numeric_limits<T>::epsilon());
return (small >= tiny) ? small_scaled : tiny;
}
case 'b':
return numext::numeric_limits<T>::radix;
case 'p':
return numext::numeric_limits<T>::epsilon();
case 'n':
return numext::numeric_limits<T>::digits;
case 'r':
return 1;
case 'm':
return numext::numeric_limits<T>::min_exponent;
case 'u':
return (numext::numeric_limits<T>::min)();
case 'l':
return numext::numeric_limits<T>::max_exponent;
case 'o':
return (numext::numeric_limits<T>::max)();
default:
return 0;
}
}
// Performs complex division in real arithmetic, avoiding unnecessary intermediate overflow.
// Consistent with LAPACK auxiliary routines SLADIV / DLADIV and CLADIV / ZLADIV
// (algorithm due to Robert L. Smith, D. Knuth, The Art of Computer Programming, Vol. 2, p. 195).
template <typename RealScalar>
EIGEN_STRONG_INLINE std::complex<RealScalar> xladiv(const std::complex<RealScalar>& num,
const std::complex<RealScalar>& den) {
const RealScalar a = numext::real(num);
const RealScalar b = numext::imag(num);
const RealScalar c = numext::real(den);
const RealScalar d = numext::imag(den);
RealScalar p, q;
if (numext::abs(d) < numext::abs(c)) {
const RealScalar e = d / c;
const RealScalar f = c + d * e;
p = (a + b * e) / f;
q = (b - a * e) / f;
} else {
const RealScalar e = c / d;
const RealScalar f = d + c * e;
p = (b + a * e) / f;
q = (-a + b * e) / f;
}
return std::complex<RealScalar>(p, q);
}
template <typename RealScalar>
EIGEN_STRONG_INLINE std::complex<RealScalar> xladiv(const RealScalar a, const RealScalar b, const RealScalar c,
const RealScalar d) {
return xladiv(std::complex<RealScalar>(a, b), std::complex<RealScalar>(c, d));
}
// Conjugate entries of vector x.
template <typename T>
void xlacgv(const int n, T* x, const int incx) {
using StridedVector = Map<Matrix<T, Dynamic, 1>, Unaligned, InnerStride<Dynamic> >;
StridedVector xvec(x, n, InnerStride<Dynamic>(numext::abs(incx)));
xvec = xvec.conjugate();
}
// Scan a matrix for its last non-zero column.
template <typename T>
int ilaxlc(const int m, const int n, const T* a, const int lda) {
if (m == 0 || n == 0) return 0;
using MatrixType = Map<const Matrix<T, Dynamic, Dynamic, ColMajor>, Unaligned, OuterStride<> >;
MatrixType a_matrix(a, m, n, OuterStride<>(lda));
// Quick test for the common case where one corner is non-zero.
if (!numext::is_exactly_zero(a_matrix(0, n - 1)) || !numext::is_exactly_zero(a_matrix(m - 1, n - 1))) {
return n;
}
// Now scan each column from the end, returning with the first non-zero.
int c = n - 1;
while (c >= 0 && (a_matrix.array().col(c) == T(0)).all()) {
--c;
}
return c + 1;
}
// Scan a matrix for its last non-zero row.
template <typename T>
int ilaxlr(const int m, const int n, const T* a, const int lda) {
if (m == 0 || n == 0) return 0;
using MatrixType = Map<const Matrix<T, Dynamic, Dynamic, ColMajor>, Unaligned, OuterStride<> >;
MatrixType a_matrix(a, m, n, OuterStride<>(lda));
// Quick test for the common case where one corner is non-zero.
if (!numext::is_exactly_zero(a_matrix(m - 1, 0)) || !numext::is_exactly_zero(a_matrix(m - 1, n - 1))) {
return m;
}
// Now scan each row from the end, returning with the first non-zero.
int r = m - 1;
while (r >= 0 && (a_matrix.array().row(r) == T(0)).all()) {
--r;
}
return r + 1;
}
} // namespace internal
} // namespace Eigen
#endif // EIGEN_LAPACK_UTILS_H