OpenKalman
rank_update_hermitian.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_HERMITIAN_HPP
17 #define OPENKALMAN_RANK_UPDATE_HERMITIAN_HPP
18 
19 
20 namespace OpenKalman
21 {
32 #ifdef __cpp_concepts
33  template<hermitian_matrix<Applicability::permitted> A, indexible U> requires
34  dimension_size_of_index_is<U, 0, index_dimension_of_v<A, 0>, Applicability::permitted> and
35  dimension_size_of_index_is<U, 0, index_dimension_of_v<A, 1>, Applicability::permitted> and
36  std::convertible_to<scalar_type_of_t<U>, const scalar_type_of_t<A>>
37  inline hermitian_matrix decltype(auto)
38 #else
39  template<typename A, typename U, std::enable_if_t<indexible<U> and hermitian_matrix<A, Applicability::permitted> and
40  dimension_size_of_index_is<U, 0, index_dimension_of<A, 0>::value, Applicability::permitted> and
41  dimension_size_of_index_is<U, 0, index_dimension_of<A, 1>::value, Applicability::permitted> and
42  std::is_convertible_v<typename scalar_type_of<U>::type, const typename scalar_type_of<A>::type>, int> = 0>
43  inline decltype(auto)
44 #endif
45  rank_update_hermitian(A&& a, U&& u, scalar_type_of_t<A> alpha = 1)
46  {
47  constexpr auto t = hermitian_adapter<A> ? hermitian_adapter_type_of_v<A> : HermitianAdapterType::lower;
48 
49  if constexpr (zero<U> or 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>)
50  {
51  if constexpr ((dynamic_dimension<A, 0> and dynamic_dimension<A, 1>) or dynamic_dimension<U, 0>)
52  if (get_index_dimension_of<0>(a) != get_index_dimension_of<0>(u))
53  throw std::invalid_argument {"In rank_update_hermitian, rows of a (" + std::to_string(get_index_dimension_of<0>(a)) +
54  ") do not match rows of u (" + std::to_string(get_index_dimension_of<0>(u)) + ")"};
55 
56  if constexpr (zero<U>)
57  {
58  return make_hermitian_matrix<t>(std::forward<A>(a));
59  }
60  else // A is known to be a 1-by-1 matrix.
61  {
62  auto e = internal::get_singular_component(a) + alpha * internal::get_singular_component(contract(u, adjoint(u)));
63 
64  if constexpr (writable_by_component<A&&>)
65  {
66  set_component(a, e, 0, 0);
67  return make_hermitian_matrix<t>(std::forward<A>(a));
68  }
69  else
70  {
71  auto ret {make_dense_object_from<A>(std::tuple{}, e)};
72  if constexpr (std::is_assignable_v<A, decltype(std::move(ret))>)
73  {
74  a = std::move(ret);
75  return make_hermitian_matrix<t>(std::forward<A>(a));
76  }
77  else return ret;
78  }
79  }
80  }
81  else if constexpr (zero<A> and diagonal_matrix<U>)
82  {
83  if constexpr (has_dynamic_dimensions<A>) if (get_index_dimension_of<0>(a) != get_index_dimension_of<1>(a))
84  throw std::invalid_argument {
85  "In rank_update_hermitian, rows of a (" + std::to_string(get_index_dimension_of<0>(a)) +
86  ") do not match columns of a (" + std::to_string(get_index_dimension_of<1>(a)) + ")"};
87 
88  return alpha * cholesky_square(std::forward<U>(u));
89  }
90  else if constexpr (diagonal_matrix<A> and diagonal_matrix<U>)
91  {
92  auto d = sum(std::forward<A>(a), alpha * cholesky_square(std::forward<U>(u)));
93  if constexpr (std::is_assignable_v<A, decltype(std::move(d))>) return a = std::move(d);
94  else return d;
95  }
96  else if constexpr (hermitian_adapter<A>)
97  {
98  auto&& aw = internal::make_writable_square_matrix<U>(nested_object(std::forward<A>(a)));
100  auto&& ret = Trait::template rank_update_hermitian<t>(std::forward<decltype(aw)>(aw), std::forward<U>(u), alpha);
101  return make_hermitian_matrix<t>(std::forward<decltype(ret)>(ret));
102  }
103  else // hermitian_matrix but not hermitian_adapter
104  {
105  auto&& aw = internal::make_writable_square_matrix<U>(std::forward<A>(a));
107  auto&& ret = Trait::template rank_update_hermitian<t>(std::forward<decltype(aw)>(aw), std::forward<U>(u), alpha);
108  return make_hermitian_matrix<t>(std::forward<decltype(ret)>(ret));
109  }
110  }
111 
112 
113 } // namespace OpenKalman
114 
115 #endif //OPENKALMAN_RANK_UPDATE_HERMITIAN_HPP
decltype(auto) constexpr contract(A &&a, B &&b)
Matrix multiplication of A * B.
Definition: contract.hpp:54
decltype(auto) rank_update_hermitian(A &&a, U &&u, scalar_type_of_t< A > alpha=1)
Do a rank update on a hermitian matrix.
Definition: rank_update_hermitian.hpp:45
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
decltype(auto) constexpr cholesky_square(A &&a)
Take the Cholesky square of a triangular_matrix.
Definition: cholesky_square.hpp:33
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...
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 nested_object(Arg &&arg)
Retrieve a nested object of Arg, if it exists.
Definition: nested_object.hpp:34
A lower-left triangular matrix.
constexpr bool hermitian_matrix
Specifies that a type is a hermitian matrix (assuming it is square_shaped).
Definition: hermitian_matrix.hpp:50