Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hessenberg decomposition of a matrix #3833

Merged
merged 22 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions geometry/r3x3_matrix_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ TEST_F(R3x3MatrixTest, QRDecomposition) {
EXPECT_THAT(
q,
AlmostEquals(R3x3Matrix<double>(
{6.0 / 7.0, 3.0 / 7.0, 2.0 / 7.0},
{-30.0 / Sqrt(3577.0), 34.0 / Sqrt(3577.0), 39.0 / Sqrt(3577.0)},
{1.0 / Sqrt(73.0), -6.0 / Sqrt(73.0), 6.0 / Sqrt(73.0)}), 10));
{6.0 / 7.0, -30.0 / Sqrt(3577.0), 1.0 / Sqrt(73.0)},
{3.0 / 7.0, 34.0 / Sqrt(3577.0), -6.0 / Sqrt(73.0)},
{2.0 / 7.0, 39.0 / Sqrt(3577.0), 6.0 / Sqrt(73.0)}), 569));
EXPECT_THAT(
r,
AlmostEquals(R3x3Matrix<Length>(
Expand Down
46 changes: 37 additions & 9 deletions numerics/fixed_arrays.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ using namespace principia::numerics::_transposed_view;
using namespace principia::quantities::_named_quantities;
using namespace principia::quantities::_si;

// TODO(phl): This should support the same operations as unbounded_arrays.hpp.

template<typename Scalar, int rows, int columns>
class FixedMatrix;

Expand Down Expand Up @@ -221,10 +223,10 @@ template<typename Scalar, int size>
constexpr FixedVector<double, size> Normalize(
FixedVector<Scalar, size> const& vector);

template<typename LScalar, typename RScalar, int lsize, int rsize>
constexpr FixedMatrix<Product<LScalar, RScalar>, lsize, rsize> SymmetricProduct(
FixedVector<LScalar, lsize> const& left,
FixedVector<RScalar, rsize> const& right);
template<typename LScalar, typename RScalar, int size>
constexpr FixedMatrix<Product<LScalar, RScalar>, size, size> SymmetricProduct(
FixedVector<LScalar, size> const& left,
FixedVector<RScalar, size> const& right);

template<typename Scalar, int size>
constexpr FixedMatrix<Square<Scalar>, size, size> SymmetricSquare(
Expand Down Expand Up @@ -284,23 +286,23 @@ constexpr FixedMatrix<Scalar, rows, columns>& operator-=(

template<typename LScalar, typename RScalar, int size>
constexpr FixedVector<Product<LScalar, RScalar>, size> operator*(
LScalar const left,
LScalar const& left,
FixedVector<RScalar, size> const& right);

template<typename LScalar, typename RScalar, int size>
constexpr FixedVector<Product<LScalar, RScalar>, size> operator*(
FixedVector<LScalar, size> const& left,
RScalar const right);
RScalar const& right);

template<typename LScalar, typename RScalar, int rows, int columns>
constexpr FixedMatrix<Product<LScalar, RScalar>, rows, columns>
operator*(LScalar const left,
operator*(LScalar const& left,
FixedMatrix<RScalar, rows, columns> const& right);

template<typename LScalar, typename RScalar, int rows, int columns>
constexpr FixedMatrix<Product<LScalar, RScalar>, rows, columns>
operator*(FixedMatrix<LScalar, rows, columns> const& left,
RScalar const right);
RScalar const& right);

template<typename LScalar, typename RScalar, int size>
constexpr FixedVector<Quotient<LScalar, RScalar>, size> operator/(
Expand All @@ -310,7 +312,27 @@ constexpr FixedVector<Quotient<LScalar, RScalar>, size> operator/(
template<typename LScalar, typename RScalar, int rows, int columns>
constexpr FixedMatrix<Quotient<LScalar, RScalar>, rows, columns>
operator/(FixedMatrix<LScalar, rows, columns> const& left,
RScalar const right);
RScalar const& right);

template<typename Scalar, int size>
constexpr FixedVector<Scalar, size>& operator*=(
FixedVector<Scalar, size>& left,
double right);

template<typename Scalar, int rows, int columns>
constexpr FixedMatrix<Scalar, rows, columns>& operator*=(
FixedMatrix<Scalar, rows, columns>& left,
double right);

template<typename Scalar, int size>
constexpr FixedVector<Scalar, size>& operator/=(
FixedVector<Scalar, size>& left,
double right);

template<typename Scalar, int rows, int columns>
constexpr FixedMatrix<Scalar, rows, columns>& operator/=(
FixedMatrix<Scalar, rows, columns>& left,
double right);

// Hilbert space and algebra.

Expand Down Expand Up @@ -341,6 +363,12 @@ constexpr FixedVector<Product<LScalar, RScalar>, rows> operator*(
FixedMatrix<LScalar, rows, columns> const& left,
FixedVector<RScalar, columns> const& right);

// Use this operator to multiply a row vector with a matrix.
template<typename LScalar, typename RScalar, int rows, int columns>
constexpr FixedVector<Product<LScalar, RScalar>, columns> operator*(
TransposedView<FixedMatrix<LScalar, rows, columns>> const& left,
FixedVector<RScalar, rows> const& right);

// Ouput.

template<typename Scalar, int size>
Expand Down
64 changes: 52 additions & 12 deletions numerics/fixed_arrays_body.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ Scalar FixedVector<Scalar, size_>::Norm() const {
}

template<typename Scalar, int size_>
inline Square<Scalar> FixedVector<Scalar, size_>::Norm²() const {
Square<Scalar> FixedVector<Scalar, size_>::Norm²() const {
return DotProduct<Scalar, Scalar, size_>::Compute(data_, data_);
}

Expand Down Expand Up @@ -397,12 +397,12 @@ constexpr FixedVector<double, size> Normalize(
return vector / vector.Norm();
}

template<typename LScalar, typename RScalar, int lsize, int rsize>
constexpr FixedMatrix<Product<LScalar, RScalar>, lsize, rsize> SymmetricProduct(
FixedVector<LScalar, lsize> const& left,
FixedVector<RScalar, rsize> const& right) {
FixedMatrix<Product<LScalar, RScalar>, lsize, rsize> result(uninitialized);
for (int i = 0; i < lsize; ++i) {
template<typename LScalar, typename RScalar, int size>
constexpr FixedMatrix<Product<LScalar, RScalar>, size, size> SymmetricProduct(
FixedVector<LScalar, size> const& left,
FixedVector<RScalar, size> const& right) {
FixedMatrix<Product<LScalar, RScalar>, size, size> result(uninitialized);
for (int i = 0; i < size; ++i) {
for (int j = 0; j < i; ++j) {
auto const r = 0.5 * (left[i] * right[j] + left[j] * right[i]);
result(i, j) = r;
Expand Down Expand Up @@ -533,7 +533,7 @@ constexpr FixedMatrix<Scalar, rows, columns>& operator-=(

template<typename LScalar, typename RScalar, int size>
constexpr FixedVector<Product<LScalar, RScalar>, size> operator*(
LScalar const left,
LScalar const& left,
FixedVector<RScalar, size> const& right) {
std::array<Product<LScalar, RScalar>, size> result;
for (int i = 0; i < size; ++i) {
Expand All @@ -545,7 +545,7 @@ constexpr FixedVector<Product<LScalar, RScalar>, size> operator*(
template<typename LScalar, typename RScalar, int size>
constexpr FixedVector<Product<LScalar, RScalar>, size> operator*(
FixedVector<LScalar, size> const& left,
RScalar const right) {
RScalar const& right) {
std::array<Product<LScalar, RScalar>, size> result;
for (int i = 0; i < size; ++i) {
result[i] = left[i] * right;
Expand All @@ -555,7 +555,7 @@ constexpr FixedVector<Product<LScalar, RScalar>, size> operator*(

template<typename LScalar, typename RScalar, int rows, int columns>
constexpr FixedMatrix<Product<LScalar, RScalar>, rows, columns> operator*(
LScalar const left,
LScalar const& left,
FixedMatrix<RScalar, rows, columns> const& right) {
FixedMatrix<Product<LScalar, RScalar>, rows, columns> result(
uninitialized);
Expand All @@ -570,7 +570,7 @@ constexpr FixedMatrix<Product<LScalar, RScalar>, rows, columns> operator*(
template<typename LScalar, typename RScalar, int rows, int columns>
constexpr FixedMatrix<Product<LScalar, RScalar>, rows, columns> operator*(
FixedMatrix<LScalar, rows, columns> const& left,
RScalar const right) {
RScalar const& right) {
FixedMatrix<Product<LScalar, RScalar>, rows, columns> result(
uninitialized);
for (int i = 0; i < rows; ++i) {
Expand All @@ -595,7 +595,7 @@ constexpr FixedVector<Quotient<LScalar, RScalar>, size> operator/(
template<typename LScalar, typename RScalar, int rows, int columns>
constexpr FixedMatrix<Quotient<LScalar, RScalar>, rows, columns> operator/(
FixedMatrix<LScalar, rows, columns> const& left,
RScalar const right) {
RScalar const& right) {
FixedMatrix<Quotient<LScalar, RScalar>, rows, columns> result(
uninitialized);
for (int i = 0; i < rows; ++i) {
Expand All @@ -606,6 +606,32 @@ constexpr FixedMatrix<Quotient<LScalar, RScalar>, rows, columns> operator/(
return result;
}

template<typename Scalar, int size>
constexpr FixedVector<Scalar, size>& operator*=(FixedVector<Scalar, size>& left,
double const right) {
return left = left * right;
}

template<typename Scalar, int rows, int columns>
constexpr FixedMatrix<Scalar, rows, columns>& operator*=(
FixedMatrix<Scalar, rows, columns>& left,
double const right) {
return left = left * right;
}

template<typename Scalar, int size>
constexpr FixedVector<Scalar, size>& operator/=(FixedVector<Scalar, size>& left,
double const right) {
return left = left / right;
}

template<typename Scalar, int rows, int columns>
constexpr FixedMatrix<Scalar, rows, columns>& operator/=(
FixedMatrix<Scalar, rows, columns>& left,
double const right) {
return left = left / right;
}

template<typename LScalar, typename RScalar, int size>
constexpr Product<LScalar, RScalar> operator*(
LScalar* const left,
Expand Down Expand Up @@ -664,6 +690,20 @@ constexpr FixedVector<Product<LScalar, RScalar>, rows> operator*(
return FixedVector<Product<LScalar, RScalar>, rows>(std::move(result));
}

template<typename LScalar, typename RScalar, int rows, int columns>
constexpr FixedVector<Product<LScalar, RScalar>, columns> operator*(
TransposedView<FixedMatrix<LScalar, rows, columns>> const& left,
FixedVector<RScalar, rows> const& right) {
std::array<Product<LScalar, RScalar>, columns> result{};
for (int j = 0; j < columns; ++j) {
auto& result_j = result[j];
for (int i = 0; i < rows; ++i) {
result_j += left.transpose(i, j) * right[i];
}
}
return FixedVector<Product<LScalar, RScalar>, columns>(std::move(result));
}

template<typename Scalar, int size>
std::ostream& operator<<(std::ostream& out,
FixedVector<Scalar, size> const& vector) {
Expand Down
2 changes: 2 additions & 0 deletions numerics/fixed_arrays_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ TEST_F(FixedArraysTest, Algebra) {
14, -63, 5, -92})),
m23_ * m34_);
EXPECT_EQ(v3_, m34_ * v4_);
EXPECT_EQ((FixedVector<double, 4>({-486, -229, 333, 198})),
TransposedView{m34_} * v3_); // NOLINT
}

TEST_F(FixedArraysTest, VectorIndexing) {
Expand Down
20 changes: 19 additions & 1 deletion numerics/matrix_computations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ struct ᵗRDRDecompositionGenerator;
template<typename M, typename V>
struct SubstitutionGenerator;

// Declares:
// struct Result {
// (matrix) H;
// (matrix) U;
// }
// TODO(phl): Add support for U.
template<typename M>
struct HessenbergDecompositionGenerator;

// Declares:
// struct Result {
// ⟨matrix⟩ rotation;
Expand Down Expand Up @@ -81,6 +90,13 @@ typename SubstitutionGenerator<LowerTriangularMatrix, Vector>::Result
ForwardSubstitution(LowerTriangularMatrix const& L,
Vector const& b);

// If A is a square matrix, returns U and H so that A = ᵗU H U, where H is an
// upper Hessenberg matrix.
// TODO(phl): Add support for returning U.
template<typename Matrix>
typename HessenbergDecompositionGenerator<Matrix>::Result
HessenbergDecomposition(Matrix const& A);

// Returns the eigensystem of A, which must be symmetric.
// As a safety measure we limit the number of iterations. We prefer to exit
// when the matrix is nearly diagonal, though.
Expand All @@ -95,7 +111,8 @@ template<typename Matrix, typename Vector>
typename RayleighQuotientGenerator<Matrix, Vector>::Result
RayleighQuotient(Matrix const& A, Vector const& x);

// Returns the eigenvector closest to x and its eigenvalue.
// Returns the eigenvector closest to x and its eigenvalue. A must be
// symmetric.
template<typename Matrix, typename Vector>
typename RayleighQuotientIterationGenerator<Matrix, Vector>::Result
RayleighQuotientIteration(Matrix const& A, Vector const& x);
Expand All @@ -111,6 +128,7 @@ using internal::BackSubstitution;
using internal::CholeskyDecomposition;
using internal::ClassicalJacobi;
using internal::ForwardSubstitution;
using internal::HessenbergDecomposition;
using internal::RayleighQuotient;
using internal::RayleighQuotientIteration;
using internal::Solve;
Expand Down
Loading