16 #ifndef OPENKALMAN_TRIANGULARADAPTER_HPP 17 #define OPENKALMAN_TRIANGULARADAPTER_HPP 24 template<square_shaped<applicability::permitted> NestedObject, triangle_type tri>
25 requires (index_count_v<NestedObject> <= 2)
27 template<
typename NestedObject, triangle_type tri>
32 #ifndef __cpp_concepts 33 static_assert(square_shaped<NestedObject, applicability::permitted>);
34 static_assert(index_count_v<NestedObject> <= 2);
41 static constexpr
auto dim = dynamic_dimension<NestedObject, 0> ? index_dimension_of_v<NestedObject, 1> :
42 index_dimension_of_v<NestedObject, 0>;
44 template<
typename Arg>
45 static bool constexpr dimensions_match = dimension_size_of_index_is<Arg, 0, dim, applicability::permitted> and
46 dimension_size_of_index_is<Arg, 1, dim, applicability::permitted>;
50 using Scalar = scalar_type_of_t<NestedObject>;
57 template<
bool Enable =
true, std::enable_if_t<Enable and
58 stdex::default_initializable<NestedObject> and (not has_dynamic_dimensions<NestedObject>),
int> = 0>
66 template<triangular_adapter Arg> requires (not std::is_base_of_v<
TriangularAdapter, std::decay_t<Arg>>) and
67 triangular_matrix<Arg, tri> and (not diagonal_matrix<NestedObject>) and
68 dimensions_match<nested_object_of_t<Arg>> and
69 # if OPENKALMAN_CPP_FEATURE_CONCEPTS 70 requires(Arg&& arg) { NestedObject {
nested_object(std::forward<Arg>(arg))}; }
72 std::constructible_from<NestedObject, decltype(nested_object(std::declval<Arg&&>()))>
75 template<
typename Arg, std::enable_if_t<triangular_adapter<Arg> and (not std::is_base_of_v<
TriangularAdapter, std::decay_t<Arg>>) and
76 (triangular_matrix<Arg, tri>) and (not diagonal_matrix<NestedObject>) and
77 dimensions_match<typename nested_object_of<Arg>::type> and
78 std::is_constructible<NestedObject, decltype(nested_object(std::declval<Arg&&>()))>::
value,
int> = 0>
85 template<square_shaped<applicability::permitted> Arg> requires (not triangular_matrix<Arg, tri>) and
86 (not diagonal_matrix<NestedObject>) and dimensions_match<Arg> and std::constructible_from<NestedObject, Arg&&>
88 template<
typename Arg, std::enable_if_t<square_shaped<Arg, applicability::permitted> and
89 (not triangular_matrix<Arg, tri>) and (not diagonal_matrix<NestedObject>) and
90 dimensions_match<Arg> and stdex::constructible_from<NestedObject, Arg&&>,
int> = 0>
93 [](Arg&& arg) -> decltype(
auto) {
94 if constexpr (has_dynamic_dimensions<Arg>)
if (not
is_square_shaped(arg))
throw std::invalid_argument {
95 "Argument to TriangularAdapter must be a square matrix, but the argument has dimensions " +
96 std::to_string(get_index_dimension_of<0>(arg)) +
"×" + std::to_string(get_index_dimension_of<1>(arg)) +
97 " in " + __func__ +
" at line " + std::to_string(__LINE__) +
" of " + __FILE__};
98 return std::forward<Arg>(arg);
99 }(std::forward<Arg>(arg))
104 #ifdef __cpp_concepts 105 template<triangular_matrix<tri> Arg> requires (not triangular_adapter<Arg>) and
106 (not has_nested_object<Arg> or (diagonal_matrix<NestedObject> and diagonal_matrix<Arg>)) and
107 dimensions_match<Arg> and std::constructible_from<NestedObject, Arg&&>
109 template<
typename Arg, std::enable_if_t<triangular_matrix<Arg, tri> and (not triangular_adapter<Arg>) and
110 (not has_nested_
object<Arg> or (diagonal_matrix<NestedObject> and diagonal_matrix<Arg>)) and
111 dimensions_match<Arg> and std::is_constructible<NestedObject, Arg&&>::value,
int> = 0>
117 #ifdef __cpp_concepts 118 template<diagonal_matrix Arg> requires (not std::is_base_of_v<
TriangularAdapter, std::decay_t<Arg>>) and
119 diagonal_matrix<NestedObject> and dimensions_match<Arg> and (not std::constructible_from<NestedObject, Arg&&>) and
120 requires(Arg&& arg) { NestedObject {
diagonal_of(std::forward<Arg>(arg))}; }
122 template<
typename Arg, std::enable_if_t<(not std::is_base_of_v<TriangularAdapter, std::decay_t<Arg>>) and
123 diagonal_matrix<NestedObject> and dimensions_match<Arg> and (not stdex::constructible_from<NestedObject, Arg&&>) and
124 std::is_constructible<NestedObject, decltype(diagonal_of(std::declval<Arg&&>()))>::value,
int> = 0>
130 #ifdef __cpp_concepts 131 template<square_shaped<applicability::permitted> Arg> requires (not triangular_matrix<Arg>) and diagonal_matrix<NestedObject> and
132 dimensions_match<Arg> and requires(Arg&& arg) { NestedObject {
diagonal_of(std::forward<Arg>(arg))}; }
134 template<
typename Arg, std::enable_if_t<square_shaped<Arg, applicability::permitted> and
135 (not triangular_matrix<Arg>) and diagonal_matrix<NestedObject> and
136 dimensions_match<Arg> and std::is_constructible<NestedObject, decltype(diagonal_of(std::declval<Arg&&>()))>::value,
int> = 0>
139 [](Arg&& arg) -> decltype(
auto) {
140 if constexpr (has_dynamic_dimensions<Arg>)
if (not
is_square_shaped(arg))
throw std::invalid_argument {
141 "Argument to TriangularAdapter must be a square matrix, but the argument has dimensions " +
142 std::to_string(get_index_dimension_of<0>(arg)) +
"×" + std::to_string(get_index_dimension_of<1>(arg)) +
143 " in " + __func__ +
" at line " + std::to_string(__LINE__) +
" of " + __FILE__};
145 }(std::forward<Arg>(arg))
155 #ifdef __cpp_concepts 156 template<std::convertible_to<const Scalar>...Args> requires (
sizeof...(Args) > 0) and
158 requires(Args...args) { NestedObject {make_dense_object_from<NestedObject>(
static_cast<const Scalar
>(args)...)}; }
160 template<
typename...Args, std::enable_if_t<std::conjunction_v<std::is_convertible<Args, const Scalar>...> and
164 :
Base {make_dense_object_from<NestedObject>(
static_cast<const Scalar
>(args)...)} {}
171 #if defined(__cpp_concepts) and OPENKALMAN_CPP_FEATURE_CONCEPTS 172 template<std::convertible_to<const Scalar>...Args> requires (
sizeof...(Args) > 0) and
174 requires(Args ... args) { NestedObject {
176 std::tuple<Dimensions<
sizeof...(Args)>, Dimensions<1>>{},
static_cast<const Scalar
>(args)...))}; }
178 template<
typename ... Args, std::enable_if_t<std::conjunction_v<std::is_convertible<Args, const Scalar>...> and
182 std::tuple<Dimensions<
sizeof...(Args)>, Dimensions<1>>{},
static_cast<const Scalar
>(args)...))} {}
186 #ifdef __cpp_concepts 187 template<triangular_matrix<tri> Arg> requires
189 vector_space_descriptors_may_match_with<NestedObject, Arg> and
194 template<
typename Arg, std::enable_if_t<triangular_matrix<Arg, tri> and
195 (not std::is_base_of_v<TriangularAdapter, std::decay_t<Arg>>) and vector_space_descriptors_may_match_with<NestedObject, Arg> and
196 (not constant_diagonal_matrix<NestedObject> or constant_diagonal_matrix<Arg>) and
197 (not (diagonal_matrix<NestedObject> or tri == triangle_type::diagonal) or diagonal_matrix<Arg>),
int> = 0>
201 if constexpr (not constant_diagonal_matrix<NestedObject>)
202 internal::set_triangle<tri>(this->
nested_object(), std::forward<Arg>(arg));
207 #ifdef __cpp_concepts 208 template<vector_space_descriptors_may_match_with<NestedObject> Arg, triangle_type t>
210 template<
typename Arg, triangle_type t, std::enable_if_t<vector_space_descriptors_may_match_with<Arg, NestedObject>,
int> = 0>
219 #ifdef __cpp_concepts 220 template<vector_space_descriptors_may_match_with<NestedObject> Arg, triangle_type t>
222 template<
typename Arg, triangle_type t, std::enable_if_t<vector_space_descriptors_may_match_with<Arg, NestedObject>,
int> = 0>
231 #ifdef __cpp_concepts 232 template<std::convertible_to<Scalar> S>
234 template<
typename S, std::enable_if_t<stdex::convertible_to<S, Scalar>,
int> = 0>
236 auto& operator*=(
const S s)
243 #ifdef __cpp_concepts 244 template<std::convertible_to<Scalar> S>
246 template<
typename S, std::enable_if_t<stdex::convertible_to<S, Scalar>,
int> = 0>
248 auto& operator/=(
const S s)
255 #ifdef __cpp_concepts 256 template<vector_space_descriptors_may_match_with<NestedObject> Arg>
258 template<
typename Arg, std::enable_if_t<vector_space_descriptors_may_match_with<Arg, NestedObject>,
int> = 0>
267 #ifdef __cpp_concepts 268 template<
typename Arg> requires std::same_as<std::decay_t<Arg>,
TriangularAdapter>
269 friend decltype(
auto) operator-(Arg&& arg)
271 return make_triangular_matrix<triangle_type_of_v<Arg>>(-
nested_object(std::forward<Arg>(arg)));
274 decltype(
auto) operator-()
const&
279 decltype(
auto) operator-()
const&&
281 return make_triangular_matrix<tri>(-
nested_object(std::move(*
this)));
286 #ifdef __cpp_concepts 287 template<
typename Arg, std::convertible_to<const scalar_type_of_t<Arg>> S> requires std::same_as<std::decay_t<Arg>,
TriangularAdapter>
289 template<
typename Arg,
typename S, std::enable_if_t<
290 std::is_same_v<std::decay_t<Arg>,
TriangularAdapter> and stdex::convertible_to<S, const scalar_type_of_t<Arg>>>>
292 friend decltype(
auto) operator*(Arg&& arg, S s)
294 return make_triangular_matrix<triangle_type_of_v<Arg>>(
nested_object(std::forward<Arg>(arg)) * s);
298 #ifdef __cpp_concepts 299 template<
typename Arg, std::convertible_to<const scalar_type_of_t<Arg>> S> requires std::same_as<std::decay_t<Arg>,
TriangularAdapter>
301 template<
typename Arg,
typename S, std::enable_if_t<
302 std::is_same_v<std::decay_t<Arg>,
TriangularAdapter> and stdex::convertible_to<S, const scalar_type_of_t<Arg>>>>
304 friend decltype(
auto) operator*(S s, Arg&& arg)
306 return make_triangular_matrix<triangle_type_of_v<Arg>>(s *
nested_object(std::forward<Arg>(arg)));
310 #ifdef __cpp_concepts 311 template<
typename Arg, std::convertible_to<const scalar_type_of_t<Arg>> S> requires std::same_as<std::decay_t<Arg>,
TriangularAdapter>
313 template<
typename Arg,
typename S, std::enable_if_t<
314 std::is_same_v<std::decay_t<Arg>,
TriangularAdapter> and stdex::convertible_to<S, const scalar_type_of_t<Arg>>>>
316 friend decltype(
auto) operator/(Arg&& arg, S s)
318 return make_triangular_matrix<triangle_type_of_v<Arg>>(
nested_object(std::forward<Arg>(arg)) / s);
328 #ifdef __cpp_concepts 329 template<triangular_matrix M>
331 template<
typename M, std::enable_if_t<triangular_matrix<M>,
int> = 0>
335 triangle_type_of_v<M>>;
338 #ifdef __cpp_concepts 339 template<hermitian_matrix<applicability::permitted> M> requires (not triangular_matrix<M>)
341 template<
typename M, std::enable_if_t<hermitian_matrix<M, applicability::permitted> and
342 (not triangular_matrix<M>),
int> = 0>
345 std::conditional_t<hermitian_adapter<M>, nested_object_of_t<M>, M>,
349 #ifdef __cpp_concepts 350 template<indexible M> requires (not triangular_matrix<M>) and
351 (not hermitian_matrix<M, applicability::permitted>)
353 template<
typename M, std::enable_if_t<indexible<M> and (not triangular_matrix<M>) and
354 (not hermitian_matrix<M, applicability::permitted>),
int> = 0>
365 template<
typename NestedObject, triangle_type tri>
368 using scalar_type = scalar_type_of_t<NestedObject>;
371 template<
typename Arg>
372 static constexpr
auto count_indices(
const Arg& arg) {
return std::integral_constant<std::size_t, 2>{}; }
375 template<
typename Arg,
typename N>
378 return internal::most_fixed_pattern(
384 template<
typename Arg>
391 template<
typename Arg>
392 static constexpr
auto get_constant_diagonal(
const Arg& arg)
401 template<applicability b>
402 static constexpr
bool one_dimensional = OpenKalman::one_dimensional<NestedObject, b>;
405 template<applicability b>
406 static constexpr
bool is_square = OpenKalman::square_shaped<NestedObject, b>;
409 static constexpr
triangle_type triangle_type_value = tri * triangle_type_of_v<NestedObject>;
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 data_layout layout = OpenKalman::one_dimensional<NestedObject> ? layout_of_v<NestedObject> :
data_layout::none;
typename nested_object_of< T >::type nested_object_of_t
Helper type for nested_object_of.
Definition: nested_object_of.hpp:58
constexpr bool one_dimensional
Specifies that a type is one-dimensional in every index.
Definition: one_dimensional.hpp:56
triangle_type
The type of a triangular matrix.
Definition: enumerations.hpp:26
A lower-left triangular matrix.
constexpr auto count_indices(const T &)
Get the number of indices necessary to address all the components of an indexible object...
Definition: count_indices.hpp:51
A triangular_adapter, where components above or below the diagonal (or both) are zero.
Definition: forward-class-declarations.hpp:147
TriangularAdapter()
Default constructor.
Definition: TriangularAdapter.hpp:59
decltype(auto) constexpr get_pattern_collection(T &&t)
Get the coordinates::pattern_collection associated with indexible object T.
Definition: get_pattern_collection.hpp:59
constexpr auto is_square_shaped(const T &t)
Determine whether an object is square_shaped.
Definition: is_square_shaped.hpp:69
constexpr bool value
T is a fixed or dynamic value that is reducible to a number.
Definition: value.hpp:45
decltype(auto) constexpr to_diagonal(Arg &&arg)
Convert an indexible object into a diagonal matrix.
Definition: to_diagonal.hpp:33
A diagonal matrix (both a lower-left and an upper-right triangular matrix).
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
Definition: AdapterBase.hpp:37
The root namespace for OpenKalman.
Definition: basics.hpp:34
Definition: object_traits.hpp:38
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:36
An upper-right triangular matrix.
constexpr bool has_dynamic_dimensions
Specifies that T has at least one index with dynamic dimensions.
Definition: has_dynamic_dimensions.hpp:30
constexpr NestedObject & nested_object() &
Get the nested object.
Definition: AdapterBase.hpp:76
constexpr auto constant_value(T &&t)
The constant value associated with a constant_object or constant_diagonal_object. ...
Definition: constant_value.hpp:37
TriangularAdapter(Arg &&arg)
Construct from a triangular adapter if NestedObject is non-diagonal.
Definition: TriangularAdapter.hpp:80
constexpr bool fixed
T is a value that is determinable at compile time.
Definition: fixed.hpp:66
Definition for triangle_type_of.
auto & operator=(Arg &&arg)
Assign from another triangular_matrix.
Definition: TriangularAdapter.hpp:199
decltype(auto) constexpr nested_object(Arg &&arg)
Retrieve a nested object of Arg, if it exists.
Definition: nested_object.hpp:35
TriangularAdapter(Arg &&arg)
Construct from a non-triangular or square matrix if NestedObject is non-diagonal. ...
Definition: TriangularAdapter.hpp:92
TriangularAdapter(Args...args)
Construct from a list of scalar coefficients, in row-major order.
Definition: TriangularAdapter.hpp:163