OpenKalman
rank_update_triangular.hpp
Go to the documentation of this file.
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2022-2023 Christopher Lee Ogden <ogden@gatech.edu>
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
9  */
10 
16 #ifndef OPENKALMAN_RANK_UPDATE_TRIANGULAR_HPP
17 #define OPENKALMAN_RANK_UPDATE_TRIANGULAR_HPP
18 
19 
20 namespace OpenKalman
21 {
35 # ifdef __cpp_concepts
36  template<triangular_matrix<TriangleType::any> A, indexible U> requires
37  dimension_size_of_index_is<U, 0, index_dimension_of_v<A, 0>, Applicability::permitted> and
38  dimension_size_of_index_is<U, 0, index_dimension_of_v<A, 1>, Applicability::permitted> and
39  std::convertible_to<scalar_type_of_t<U>, const scalar_type_of_t<A>>
40  inline triangular_matrix<triangle_type_of_v<A> == TriangleType::upper ? TriangleType::upper : TriangleType::lower> decltype(auto)
41 # else
42  template<typename A, typename U, std::enable_if_t<triangular_matrix<A, TriangleType::any> and indexible<U> and
43  dimension_size_of_index_is<U, 0, index_dimension_of<A, 0>::value, Applicability::permitted> and
44  dimension_size_of_index_is<U, 0, index_dimension_of<A, 1>::value, Applicability::permitted> and
45  std::is_convertible_v<scalar_type_of_t<U>, const scalar_type_of_t<A>>, int> = 0>
46  inline decltype(auto)
47 # endif
49  {
50  constexpr auto t = triangle_type_of_v<A> == TriangleType::upper ? TriangleType::upper : TriangleType::lower;
51 
52  if constexpr (zero<U>)
53  {
54  if constexpr (dynamic_dimension<A, 0> or dynamic_dimension<U, 0>) if (get_index_dimension_of<0>(a) != get_index_dimension_of<0>(u))
55  throw std::invalid_argument {"In rank_update_triangular, rows of a (" + std::to_string(get_index_dimension_of<0>(a)) +
56  ") do not match rows of u (" + std::to_string(get_index_dimension_of<0>(u)) + ")"};
57 
58  return make_triangular_matrix<t>(std::forward<A>(a));
59  }
60  else if constexpr (dimension_size_of_index_is<A, 0, 1> or dimension_size_of_index_is<A, 1, 1> or dimension_size_of_index_is<U, 0, 1>)
61  {
62  if constexpr (dynamic_dimension<A, 0> or dynamic_dimension<U, 0>) if (get_index_dimension_of<0>(a) != get_index_dimension_of<0>(u))
63  throw std::invalid_argument {"In rank_update_triangular, rows of a (" + std::to_string(get_index_dimension_of<0>(a)) +
64  ") do not match rows of u (" + std::to_string(get_index_dimension_of<0>(u)) + ")"};
65 
66  // From here on, A is known to be a 1-by-1 matrix.
67 
68  auto e = [](auto ax, const auto& uterm) {
69  if constexpr (values::complex<scalar_type_of<A>>) return values::sqrt(ax * values::conj(ax) + uterm);
70  else return values::sqrt(ax * ax + uterm);
71  }(internal::get_singular_component(a), alpha * internal::get_singular_component(contract(u, adjoint(u))));
72 
73  if constexpr (writable_by_component<A&&>)
74  {
75  set_component(a, e, 0, 0);
76  return make_triangular_matrix<t>(std::forward<A>(a));
77  }
78  else
79  {
80  auto ret {make_dense_object_from<A>(std::tuple{coordinates::Axis{}, coordinates::Axis{}}, e)};
81  if constexpr (std::is_assignable_v<A, decltype(std::move(ret))>)
82  {
83  a = std::move(ret);
84  return make_triangular_matrix<t>(std::forward<A>(a));
85  }
86  else return ret;
87  }
88  }
89  else if constexpr (zero<A>)
90  {
91  if constexpr (diagonal_matrix<U>)
92  return to_diagonal(sqrt(alpha) * diagonal_of(std::forward<U>(u)));
93  else if constexpr (t == TriangleType::upper)
94  return QR_decomposition(sqrt(alpha) * adjoint(std::forward<U>(u)));
95  else
96  return LQ_decomposition(sqrt(alpha) * std::forward<U>(u));
97  }
98  else if constexpr (diagonal_matrix<A> and diagonal_matrix<U>)
99  {
100  auto d = cholesky_factor(sum(cholesky_square(std::forward<A>(a)), alpha * cholesky_square(std::forward<U>(u))));
101  if constexpr (std::is_assignable_v<A, decltype(std::move(d))>) return a = std::move(d);
102  else return d;
103  }
104  else
105  {
106  auto&& an = [](A&& a) -> decltype(auto) {
107  if constexpr (triangular_adapter<A>) return nested_object(std::forward<A>(a));
108  else return std::forward<A>(a);
109  }(std::forward<A>(a));
110 
111  auto&& aw = internal::make_writable_square_matrix<U>(std::forward<decltype(an)>(an));
113  auto&& ret = Trait::template rank_update_triangular<t>(std::forward<decltype(aw)>(aw), std::forward<U>(u), alpha);
114  return make_triangular_matrix<t>(std::forward<decltype(ret)>(ret));
115  }
116  }
117 
118 
119 } // namespace OpenKalman
120 
121 #endif //OPENKALMAN_RANK_UPDATE_TRIANGULAR_HPP
decltype(auto) constexpr contract(A &&a, B &&b)
Matrix multiplication of A * B.
Definition: contract.hpp:54
Arg && set_component(Arg &&arg, const scalar_type_of_t< Arg > &s, const Indices &indices)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: set_component.hpp:51
typename scalar_type_of< T >::type scalar_type_of_t
helper template for scalar_type_of.
Definition: scalar_type_of.hpp:54
constexpr bool complex
T is a values::value that reduces to std::complex or a custom complex type.
Definition: complex.hpp:46
decltype(auto) constexpr QR_decomposition(A &&a)
Perform a QR decomposition of matrix A=Q[U,0], U is a upper-triangular matrix, and Q is orthogonal...
Definition: QR_decomposition.hpp:33
decltype(auto) constexpr to_diagonal(Arg &&arg)
Convert an indexible object into a diagonal matrix.
Definition: to_diagonal.hpp:32
An upper-right triangular matrix.
decltype(auto) constexpr cholesky_square(A &&a)
Take the Cholesky square of a triangular_matrix.
Definition: cholesky_square.hpp:33
Type scalar type (e.g., std::float, std::double, std::complex<double>) of a tensor.
Definition: scalar_type_of.hpp:32
The root namespace for OpenKalman.
Definition: basics.hpp:34
An interface to various routines from the linear algebra library associated with indexible object T...
Definition: library_interface.hpp:37
The concept, trait, or restraint is permitted, but whether it applies is not necessarily known at com...
constexpr auto conj(const Arg &arg)
A constexpr function for the complex conjugate of a (complex) number.
Definition: conj.hpp:39
constexpr auto sqrt(const Arg &arg)
A constexpr alternative to std::sqrt.
Definition: sqrt.hpp:46
decltype(auto) constexpr diagonal_of(Arg &&arg)
Extract a column vector (or column slice for rank>2 tensors) comprising the diagonal elements...
Definition: diagonal_of.hpp:33
decltype(auto) constexpr adjoint(Arg &&arg)
Take the adjoint of a matrix.
Definition: adjoint.hpp:33
decltype(auto) constexpr sum(Ts &&...ts)
Element-by-element sum of one or more objects.
Definition: sum.hpp:112
decltype(auto) constexpr LQ_decomposition(A &&a)
Perform an LQ decomposition of matrix A=[L,0]Q, L is a lower-triangular matrix, and Q is orthogonal...
Definition: LQ_decomposition.hpp:33
decltype(auto) rank_update_triangular(A &&a, U &&u, scalar_type_of_t< A > alpha=1)
Do a rank update on triangular matrix.
Definition: rank_update_triangular.hpp:48
A structure representing the dimensions associated with of a particular index.
Definition: Dimensions.hpp:42
decltype(auto) constexpr nested_object(Arg &&arg)
Retrieve a nested object of Arg, if it exists.
Definition: nested_object.hpp:34
A lower-left triangular matrix.
decltype(auto) constexpr cholesky_factor(A &&a)
Take the Cholesky factor of a matrix.
Definition: cholesky_factor.hpp:38