16 #ifndef OPENKALMAN_TRIANGULARADAPTER_HPP 17 #define OPENKALMAN_TRIANGULARADAPTER_HPP 22 template<square_shaped<Applicability::permitted> NestedObject, TriangleType triangle_type>
23 requires (index_count_v<NestedObject> <= 2)
25 template<
typename NestedObject, TriangleType triangle_type>
30 #ifndef __cpp_concepts 31 static_assert(square_shaped<NestedObject, Applicability::permitted>);
32 static_assert(index_count_v<NestedObject> <= 2);
39 static constexpr
auto dim = dynamic_dimension<NestedObject, 0> ? index_dimension_of_v<NestedObject, 1> :
40 index_dimension_of_v<NestedObject, 0>;
42 template<
typename Arg>
43 static bool constexpr dimensions_match = dimension_size_of_index_is<Arg, 0, dim, Applicability::permitted> and
44 dimension_size_of_index_is<Arg, 1, dim, Applicability::permitted>;
48 using Scalar = scalar_type_of_t<NestedObject>;
55 template<
typename T = NestedObject, std::enable_if_t<
56 std::is_default_constructible_v<T> and (not has_dynamic_dimensions<NestedObject>),
int> = 0>
64 template<triangular_adapter Arg> requires (not std::is_base_of_v<
TriangularAdapter, std::decay_t<Arg>>) and
65 triangular_matrix<Arg, triangle_type> and (not diagonal_matrix<NestedObject>) and
66 dimensions_match<nested_object_of_t<Arg>> and
67 # if OPENKALMAN_CPP_FEATURE_CONCEPTS 68 requires(Arg&& arg) { NestedObject {
nested_object(std::forward<Arg>(arg))}; }
70 std::constructible_from<NestedObject, decltype(nested_object(std::declval<Arg&&>()))>
73 template<
typename Arg, std::enable_if_t<triangular_adapter<Arg> and (not std::is_base_of_v<
TriangularAdapter, std::decay_t<Arg>>) and
74 (triangular_matrix<Arg, triangle_type>) and (not diagonal_matrix<NestedObject>) and
75 dimensions_match<typename nested_object_of<Arg>::type> and
76 std::is_constructible<NestedObject, decltype(nested_object(std::declval<Arg&&>()))>::
value,
int> = 0>
83 template<square_shaped<Applicability::permitted> Arg> requires (not triangular_matrix<Arg, triangle_type>) and
84 (not diagonal_matrix<NestedObject>) and dimensions_match<Arg> and std::constructible_from<NestedObject, Arg&&>
86 template<
typename Arg, std::enable_if_t<square_shaped<Arg, Applicability::permitted> and
87 (not triangular_matrix<Arg, triangle_type>) and (not diagonal_matrix<NestedObject>) and
88 dimensions_match<Arg> and std::is_constructible_v<NestedObject, Arg&&>,
int> = 0>
91 [](Arg&& arg) -> decltype(
auto) {
92 if constexpr (has_dynamic_dimensions<Arg>)
if (not
is_square_shaped(arg))
throw std::invalid_argument {
93 "Argument to TriangularAdapter must be a square matrix, but the argument has dimensions " +
94 std::to_string(get_index_dimension_of<0>(arg)) +
"×" + std::to_string(get_index_dimension_of<1>(arg)) +
95 " in " + __func__ +
" at line " + std::to_string(__LINE__) +
" of " + __FILE__};
96 return std::forward<Arg>(arg);
97 }(std::forward<Arg>(arg))
102 #ifdef __cpp_concepts 103 template<triangular_matrix<triangle_type> Arg> requires (not triangular_adapter<Arg>) and
104 (not has_nested_object<Arg> or (diagonal_matrix<NestedObject> and diagonal_matrix<Arg>)) and
105 dimensions_match<Arg> and std::constructible_from<NestedObject, Arg&&>
107 template<
typename Arg, std::enable_if_t<triangular_matrix<Arg, triangle_type> and (not triangular_adapter<Arg>) and
108 (not has_nested_
object<Arg> or (diagonal_matrix<NestedObject> and diagonal_matrix<Arg>)) and
109 dimensions_match<Arg> and std::is_constructible<NestedObject, Arg&&>::value,
int> = 0>
115 #ifdef __cpp_concepts 116 template<diagonal_matrix Arg> requires (not std::is_base_of_v<
TriangularAdapter, std::decay_t<Arg>>) and
117 diagonal_matrix<NestedObject> and dimensions_match<Arg> and (not std::constructible_from<NestedObject, Arg&&>) and
118 requires(Arg&& arg) { NestedObject {
diagonal_of(std::forward<Arg>(arg))}; }
120 template<
typename Arg, std::enable_if_t<(not std::is_base_of_v<TriangularAdapter, std::decay_t<Arg>>) and
121 diagonal_matrix<NestedObject> and dimensions_match<Arg> and (not std::is_constructible_v<NestedObject, Arg&&>) and
122 std::is_constructible<NestedObject, decltype(diagonal_of(std::declval<Arg&&>()))>::value,
int> = 0>
128 #ifdef __cpp_concepts 129 template<square_shaped<Applicability::permitted> Arg> requires (not triangular_matrix<Arg>) and diagonal_matrix<NestedObject> and
130 dimensions_match<Arg> and requires(Arg&& arg) { NestedObject {
diagonal_of(std::forward<Arg>(arg))}; }
132 template<
typename Arg, std::enable_if_t<square_shaped<Arg, Applicability::permitted> and
133 (not triangular_matrix<Arg>) and diagonal_matrix<NestedObject> and
134 dimensions_match<Arg> and std::is_constructible<NestedObject, decltype(diagonal_of(std::declval<Arg&&>()))>::value,
int> = 0>
137 [](Arg&& arg) -> decltype(
auto) {
138 if constexpr (has_dynamic_dimensions<Arg>)
if (not
is_square_shaped(arg))
throw std::invalid_argument {
139 "Argument to TriangularAdapter must be a square matrix, but the argument has dimensions " +
140 std::to_string(get_index_dimension_of<0>(arg)) +
"×" + std::to_string(get_index_dimension_of<1>(arg)) +
141 " in " + __func__ +
" at line " + std::to_string(__LINE__) +
" of " + __FILE__};
143 }(std::forward<Arg>(arg))
153 #ifdef __cpp_concepts 154 template<std::convertible_to<const Scalar>...Args> requires (
sizeof...(Args) > 0) and
156 requires(Args...args) { NestedObject {make_dense_object_from<NestedObject>(
static_cast<const Scalar
>(args)...)}; }
158 template<
typename...Args, std::enable_if_t<std::conjunction_v<std::is_convertible<Args, const Scalar>...> and
159 (
sizeof...(Args) > 0) and (triangle_type !=
TriangleType::diagonal) and (not diagonal_matrix<NestedObject>),
int> = 0>
162 :
Base {make_dense_object_from<NestedObject>(
static_cast<const Scalar
>(args)...)} {}
169 #if defined(__cpp_concepts) and OPENKALMAN_CPP_FEATURE_CONCEPTS 170 template<std::convertible_to<const Scalar>...Args> requires (
sizeof...(Args) > 0) and
172 requires(Args ... args) { NestedObject {
174 std::tuple<Dimensions<
sizeof...(Args)>, Dimensions<1>>{},
static_cast<const Scalar
>(args)...))}; }
176 template<
typename ... Args, std::enable_if_t<std::conjunction_v<std::is_convertible<Args, const Scalar>...> and
177 (
sizeof...(Args) > 0) and (triangle_type ==
TriangleType::diagonal or diagonal_matrix<NestedObject>),
int> = 0>
180 std::tuple<Dimensions<
sizeof...(Args)>, Dimensions<1>>{},
static_cast<const Scalar
>(args)...))} {}
184 #ifdef __cpp_concepts 185 template<triangular_matrix<triangle_type> Arg> requires
187 vector_space_descriptors_may_match_with<NestedObject, Arg> and
192 template<
typename Arg, std::enable_if_t<triangular_matrix<Arg, triangle_type> and
193 (not std::is_base_of_v<TriangularAdapter, std::decay_t<Arg>>) and vector_space_descriptors_may_match_with<NestedObject, Arg> and
194 (not constant_diagonal_matrix<NestedObject> or constant_diagonal_matrix<Arg>) and
195 (not (diagonal_matrix<NestedObject> or triangle_type == TriangleType::diagonal) or diagonal_matrix<Arg>),
int> = 0>
199 if constexpr (not constant_diagonal_matrix<NestedObject>)
200 internal::set_triangle<triangle_type>(this->
nested_object(), std::forward<Arg>(arg));
205 #ifdef __cpp_concepts 206 template<vector_space_descriptors_may_match_with<NestedObject> Arg, TriangleType t>
208 template<
typename Arg, TriangleType t, std::enable_if_t<vector_space_descriptors_may_match_with<Arg, NestedObject>,
int> = 0>
217 #ifdef __cpp_concepts 218 template<vector_space_descriptors_may_match_with<NestedObject> Arg, TriangleType t>
220 template<
typename Arg, TriangleType t, std::enable_if_t<vector_space_descriptors_may_match_with<Arg, NestedObject>,
int> = 0>
229 #ifdef __cpp_concepts 230 template<std::convertible_to<Scalar> S>
232 template<
typename S, std::enable_if_t<std::is_convertible_v<S, Scalar>,
int> = 0>
234 auto& operator*=(
const S s)
241 #ifdef __cpp_concepts 242 template<std::convertible_to<Scalar> S>
244 template<
typename S, std::enable_if_t<std::is_convertible_v<S, Scalar>,
int> = 0>
246 auto& operator/=(
const S s)
253 #ifdef __cpp_concepts 254 template<vector_space_descriptors_may_match_with<NestedObject> Arg>
256 template<
typename Arg, std::enable_if_t<vector_space_descriptors_may_match_with<Arg, NestedObject>,
int> = 0>
265 #ifdef __cpp_concepts 266 template<
typename Arg> requires std::same_as<std::decay_t<Arg>,
TriangularAdapter>
267 friend decltype(
auto) operator-(Arg&& arg)
269 return make_triangular_matrix<triangle_type_of_v<Arg>>(-
nested_object(std::forward<Arg>(arg)));
272 decltype(
auto) operator-()
const&
274 return make_triangular_matrix<triangle_type>(-
nested_object(*
this));
277 decltype(
auto) operator-()
const&&
279 return make_triangular_matrix<triangle_type>(-
nested_object(std::move(*
this)));
284 #ifdef __cpp_concepts 285 template<
typename Arg, std::convertible_to<const scalar_type_of_t<Arg>> S> requires std::same_as<std::decay_t<Arg>,
TriangularAdapter>
287 template<
typename Arg,
typename S, std::enable_if_t<
288 std::is_same_v<std::decay_t<Arg>,
TriangularAdapter> and std::is_convertible_v<S, const scalar_type_of_t<Arg>>>>
290 friend decltype(
auto) operator*(Arg&& arg, S s)
292 return make_triangular_matrix<triangle_type_of_v<Arg>>(
nested_object(std::forward<Arg>(arg)) * s);
296 #ifdef __cpp_concepts 297 template<
typename Arg, std::convertible_to<const scalar_type_of_t<Arg>> S> requires std::same_as<std::decay_t<Arg>,
TriangularAdapter>
299 template<
typename Arg,
typename S, std::enable_if_t<
300 std::is_same_v<std::decay_t<Arg>,
TriangularAdapter> and std::is_convertible_v<S, const scalar_type_of_t<Arg>>>>
302 friend decltype(
auto) operator*(S s, Arg&& arg)
304 return make_triangular_matrix<triangle_type_of_v<Arg>>(s *
nested_object(std::forward<Arg>(arg)));
308 #ifdef __cpp_concepts 309 template<
typename Arg, std::convertible_to<const scalar_type_of_t<Arg>> S> requires std::same_as<std::decay_t<Arg>,
TriangularAdapter>
311 template<
typename Arg,
typename S, std::enable_if_t<
312 std::is_same_v<std::decay_t<Arg>,
TriangularAdapter> and std::is_convertible_v<S, const scalar_type_of_t<Arg>>>>
314 friend decltype(
auto) operator/(Arg&& arg, S s)
316 return make_triangular_matrix<triangle_type_of_v<Arg>>(
nested_object(std::forward<Arg>(arg)) / s);
326 #ifdef __cpp_concepts 327 template<triangular_matrix M>
329 template<
typename M, std::enable_if_t<triangular_matrix<M>,
int> = 0>
333 triangle_type_of_v<M>>;
336 #ifdef __cpp_concepts 337 template<hermitian_matrix<Applicability::permitted> M> requires (not triangular_matrix<M>)
339 template<
typename M, std::enable_if_t<hermitian_matrix<M, Applicability::permitted> and
340 (not triangular_matrix<M>),
int> = 0>
343 std::conditional_t<hermitian_adapter<M>, nested_object_of_t<M>, M>,
347 #ifdef __cpp_concepts 348 template<indexible M> requires (not triangular_matrix<M>) and
349 (not hermitian_matrix<M, Applicability::permitted>)
351 template<
typename M, std::enable_if_t<indexible<M> and (not triangular_matrix<M>) and
352 (not hermitian_matrix<M, Applicability::permitted>),
int> = 0>
363 template<
typename NestedObject, TriangleType triangle_type>
369 template<
typename Arg>
370 static constexpr
auto count_indices(
const Arg& arg) {
return std::integral_constant<std::size_t, 2>{}; }
373 template<
typename Arg,
typename N>
376 return internal::best_vector_space_descriptor(
377 OpenKalman::get_vector_space_descriptor<0>(
nested_object(arg)),
378 OpenKalman::get_vector_space_descriptor<1>(
nested_object(arg)));
382 template<
typename Arg>
389 template<
typename Arg>
390 static constexpr
auto get_constant_diagonal(
const Arg& arg)
399 template<Applicability b>
400 static constexpr
bool one_dimensional = OpenKalman::one_dimensional<NestedObject, b>;
403 template<Applicability b>
404 static constexpr
bool is_square = OpenKalman::square_shaped<NestedObject, b>;
407 template<TriangleType t>
409 triangular_matrix<NestedObject, t>;
412 static constexpr
bool is_triangular_adapter =
true;
415 static constexpr
bool is_writable =
false;
418 #ifdef __cpp_lib_concepts 419 template<
typename Arg> requires OpenKalman::one_dimensional<nested_object_of_t<Arg&>> and raw_data_defined_for<nested_object_of_t<Arg&>>
421 template<typename Arg, std::enable_if_t<one_dimensional<typename nested_object_of<Arg&>::type> and
422 raw_data_defined_for<typename nested_object_of<Arg&>::type>,
int> = 0>
424 static constexpr
auto *
const 428 static constexpr
Layout layout = OpenKalman::one_dimensional<NestedObject> ? layout_of_v<NestedObject> :
Layout::none;
437 #endif //OPENKALMAN_TRIANGULARADAPTER_HPP constexpr auto count_indices(const T &t)
Get the number of indices available to address the components of an indexible object.
Definition: count_indices.hpp:33
typename nested_object_of< T >::type nested_object_of_t
Helper type for nested_object_of.
Definition: nested_object_of.hpp:66
TriangularAdapter(Arg &&arg)
Construct from a non-triangular or square matrix if NestedObject is non-diagonal. ...
Definition: TriangularAdapter.hpp:90
constexpr NestedObject & nested_object() &
Get the nested object.
Definition: AdapterBase.hpp:97
constexpr bool one_dimensional
Specifies that a type is one-dimensional in every index.
Definition: one_dimensional.hpp:83
Definition: indexible_object_traits.hpp:36
TriangularAdapter()
Default constructor.
Definition: TriangularAdapter.hpp:57
auto & operator=(Arg &&arg)
Assign from another triangular_matrix.
Definition: TriangularAdapter.hpp:197
TriangularAdapter(Arg &&arg)
Construct from a triangular adapter if NestedObject is non-diagonal.
Definition: TriangularAdapter.hpp:78
No storage layout (e.g., if the elements are calculated rather than stored).
typename scalar_type_of< T >::type scalar_type_of_t
helper template for scalar_type_of.
Definition: scalar_type_of.hpp:54
TriangularAdapter(Args...args)
Construct from a list of scalar coefficients, in row-major order.
Definition: TriangularAdapter.hpp:161
A triangular_adapter, where components above or below the diagonal (or both) are zero.
Definition: forward-class-declarations.hpp:257
Lower, upper, or diagonal matrix.
constexpr auto is_square_shaped(const T &t)
Determine whether an object is square_shaped at runtime.
Definition: is_square_shaped.hpp:63
Definition: tuple_reverse.hpp:103
constexpr bool value
T is numerical value or is reducible to a numerical value.
Definition: value.hpp:31
decltype(auto) constexpr to_diagonal(Arg &&arg)
Convert an indexible object into a diagonal matrix.
Definition: to_diagonal.hpp:32
decltype(auto) constexpr to_dense_object(Arg &&arg)
Convert the argument to a dense, writable matrix of a particular scalar type.
Definition: to_dense_object.hpp:37
An upper-right triangular matrix.
Definition: AdapterBase.hpp:36
The constant associated with T, assuming T is a constant_matrix.
Definition: constant_coefficient.hpp:36
The root namespace for OpenKalman.
Definition: basics.hpp:34
The constant associated with T, assuming T is a constant_diagonal_matrix.
Definition: constant_diagonal_coefficient.hpp:32
constexpr A && contract_in_place(A &&a, B &&b)
In-place matrix multiplication of A * B, storing the result in A.
Definition: contract_in_place.hpp:38
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
Layout
The layout format of a multidimensional array.
Definition: global-definitions.hpp:47
constexpr bool has_dynamic_dimensions
Specifies that T has at least one index with dynamic dimensions.
Definition: has_dynamic_dimensions.hpp:29
A diagonal matrix (both a lower-left and an upper-right triangular matrix).
constexpr bool fixed
T is a values::value that is determinable at compile time.
Definition: fixed.hpp:60
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 auto get_vector_space_descriptor(const T &t, const N &n)
Get the coordinates::pattern object for index N of indexible object T.
Definition: get_vector_space_descriptor.hpp:56