16 #ifndef OPENKALMAN_EIGEN_LIBRARY_INTERFACE_HPP 17 #define OPENKALMAN_EIGEN_LIBRARY_INTERFACE_HPP 19 #include <type_traits> 27 template<Eigen3::eigen_general<true> T>
28 struct library_interface<T>
34 template<
typename Derived>
36 std::conditional_t<Eigen3::eigen_array_general<T>, Eigen::ArrayBase<Derived>,
37 std::conditional_t<Eigen3::eigen_matrix_general<T>, Eigen::MatrixBase<Derived>, Eigen::EigenBase<Derived>>>>;
41 template<
typename Arg, std::size_t...I,
typename...Ind>
45 ([](
auto max,
auto ind){
if (ind < 0 or ind >= max)
throw std::out_of_range {
46 (
"Index " + std::to_string(I) +
" is out of bounds: it is " + std::to_string(ind) +
47 " but should be in range [0..." + std::to_string(max - 1) +
"].")};
48 }(get_index_dimension_of<I>(arg), ind),...);
52 template<
typename Arg>
53 static constexpr decltype(
auto)
54 get_coeff(Arg&& arg, Eigen::Index i, Eigen::Index j)
58 using Scalar = scalar_type_of_t<Arg>;
60 if constexpr (Eigen3::eigen_DiagonalMatrix<Arg> or Eigen3::eigen_DiagonalWrapper<Arg>)
63 return static_cast<Scalar
>(get_coeff(
nested_object(std::forward<Arg>(arg)), i, 0));
65 return static_cast<Scalar
>(0);
67 else if constexpr (Eigen3::eigen_TriangularView<Arg>)
69 constexpr
int Mode {std::decay_t<Arg>::Mode};
70 if ((i > j and (Mode &
int{Eigen::Upper}) != 0x0) or (i < j and (Mode &
int{Eigen::Lower}) != 0x0))
71 return static_cast<Scalar
>(0);
73 return static_cast<Scalar
>(get_coeff(
nested_object(std::forward<Arg>(arg)), i, j));
75 else if constexpr (Eigen3::eigen_SelfAdjointView<Arg>)
77 return get_coeff(
nested_object(std::forward<Arg>(arg)), i, j);
81 auto evaluator = Eigen::internal::evaluator<std::decay_t<Arg>>(arg);
82 constexpr
bool use_coeffRef = (Eigen::internal::traits<std::decay_t<Arg>>::Flags & Eigen::LvalueBit) != 0x0 and
83 std::is_lvalue_reference_v<Arg> and not std::is_const_v<std::remove_reference_t<Arg>>;
84 if constexpr (use_coeffRef)
return evaluator.coeffRef(i, j);
85 else return evaluator.coeff(i, j);
90 template<
typename Indices>
91 static constexpr std::tuple<Eigen::Index, Eigen::Index>
92 extract_indices(
const Indices& indices)
94 auto it = stdex::ranges::begin(indices);
95 auto e = stdex::ranges::end(indices);
96 if (it == e)
return {0, 0};
97 auto i =
static_cast<std::size_t
>(*it);
98 if (++it == e)
return {i, 0};
99 auto j =
static_cast<std::size_t
>(*it);
100 if (++it == e)
return {i, j};
101 throw std::logic_error(
"Wrong number of indices on component access");
106 #ifdef __cpp_lib_ranges 107 template<
typename Arg, std::ranges::input_range Indices> requires
108 std::convertible_to<std::ranges::range_value_t<Indices>,
const typename std::decay_t<Arg>::Index> and
109 (collections::size_of_v<Indices> == stdex::dynamic_extent or collections::size_of_v<Indices> <= 2)
110 static constexpr values::scalar decltype(
auto)
112 template<
typename Arg,
typename Indices, std::enable_if_t<
113 (collections::size_of_v<Indices> == stdex::dynamic_extent or collections::size_of_v<Indices> <= 2),
int> = 0>
114 static constexpr decltype(
auto)
116 get_component(Arg&& arg,
const Indices& indices)
118 using Scalar = scalar_type_of_t<Arg>;
119 auto [i, j] = extract_indices(indices);
120 if constexpr (Eigen3::eigen_SelfAdjointView<Arg>)
122 constexpr
int Mode {std::decay_t<Arg>::Mode};
123 bool transp = (i > j and (Mode &
int{Eigen::Upper}) != 0) or (i < j and (Mode &
int{Eigen::Lower}) != 0);
124 if constexpr (values::complex<Scalar>)
126 if (transp)
return static_cast<Scalar
>(
values::conj(get_coeff(std::as_const(arg), j, i)));
127 else return static_cast<Scalar
>(get_coeff(std::as_const(arg), i, j));
131 if (transp)
return get_coeff(std::forward<Arg>(arg), j, i);
132 else return get_coeff(std::forward<Arg>(arg), i, j);
137 return get_coeff(std::forward<Arg>(arg), i, j);
142 #ifdef __cpp_lib_ranges 143 template<
typename Arg, std::ranges::input_range Indices> requires (not std::is_const_v<Arg>) and
144 std::convertible_to<std::ranges::range_value_t<Indices>,
const typename Arg::Index> and
145 (collections::size_of_v<Indices> == stdex::dynamic_extent or collections::size_of_v<Indices> <= 2) and
146 std::assignable_from<decltype(get_coeff(std::declval<Arg&>(), 0, 0)),
const scalar_type_of_t<Arg>&> and
147 ((Eigen::internal::traits<std::decay_t<Arg>>::Flags & Eigen::LvalueBit) != 0) and
148 (not Eigen3::eigen_DiagonalWrapper<Arg>) and (not Eigen3::eigen_TriangularView<Arg>)
150 template<
typename Arg,
typename Indices, std::enable_if_t<(not std::is_const_v<Arg>) and
151 (collections::size_of_v<Indices> == stdex::dynamic_extent or collections::size_of_v<Indices> <= 2) and
152 std::is_assignable<decltype(get_coeff(std::declval<Arg&>(), 0, 0)), const scalar_type_of_t<Arg>&>::value and
153 (Eigen::
internal::traits<std::decay_t<Arg>>::Flags & Eigen::LvalueBit) != 0 and
154 (not Eigen3::eigen_DiagonalWrapper<Arg>) and (not Eigen3::eigen_TriangularView<Arg>),
int> = 0>
157 set_component(Arg& arg, const scalar_type_of_t<Arg>& s, const Indices& indices)
159 using Scalar = scalar_type_of_t<Arg>;
160 auto [i, j] = extract_indices(indices);
161 if constexpr (Eigen3::eigen_SelfAdjo
intView<Arg>)
163 constexpr
int Mode {std::decay_t<Arg>::Mode};
164 bool transp = (i > j and (Mode &
int{Eigen::Upper}) != 0) or (i < j and (Mode &
int{Eigen::Lower}) != 0);
165 if constexpr (values::complex<Scalar>)
168 else get_coeff(arg, i, j) = s;
172 if (transp) get_coeff(arg, j, i) = s;
173 else get_coeff(arg, i, j) = s;
178 get_coeff(arg, i, j) = s;
184 template<
typename Arg>
185 static decltype(
auto)
186 wrap_if_nests_by_reference(Arg&& arg)
188 if constexpr (Eigen3::eigen_general<Arg>)
190 constexpr
auto Flags = Eigen::internal::traits<std::remove_reference_t<Arg>>::Flags;
191 if constexpr (std::is_lvalue_reference_v<Arg> and static_cast<bool>(Flags & Eigen::NestByRefBit))
192 return std::forward<Arg>(arg);
194 return Eigen3::make_eigen_wrapper(std::forward<Arg>(arg));
198 return Eigen3::make_eigen_wrapper(std::forward<Arg>(arg));
204 template<
typename Arg>
205 static decltype(
auto)
206 to_native_matrix(Arg&& arg)
208 if constexpr (Eigen3::eigen_wrapper<Arg>)
210 return std::forward<Arg>(arg);
212 else if constexpr (internal::library_wrapper<Arg>)
216 else if constexpr (Eigen3::eigen_ArrayWrapper<Arg>)
218 return to_native_matrix(
nested_object(std::forward<Arg>(arg)));
220 else if constexpr (Eigen3::eigen_array_general<Arg>)
222 return wrap_if_nests_by_reference(std::forward<Arg>(arg)).matrix();
224 else if constexpr (Eigen3::eigen_matrix_general<Arg>)
226 return wrap_if_nests_by_reference(std::forward<Arg>(arg));
228 else if constexpr (not Eigen3::eigen_general<Arg> and directly_accessible<Arg> and std::is_lvalue_reference_v<Arg>)
230 using Scalar = scalar_type_of_t<Arg>;
231 constexpr
int rows = dynamic_dimension<Arg, 0> ? Eigen::Dynamic : index_dimension_of_v<Arg, 0>;
232 constexpr
int cols = dynamic_dimension<Arg, 1> ? Eigen::Dynamic : index_dimension_of_v<Arg, 1>;
234 if constexpr (layout_of_v<Arg> == data_layout::stride)
236 auto [s0, s1] = internal::strides(arg);
237 using S0 = decltype(s0);
238 using S1 = decltype(s1);
239 constexpr
int es0 = []() ->
int {
240 if constexpr (values::fixed<S0>)
return static_cast<std::ptrdiff_t
>(S0{});
241 else return Eigen::Dynamic;
243 constexpr
int es1 = []() ->
int {
244 if constexpr (values::fixed<S1>)
return static_cast<std::ptrdiff_t
>(S1{});
245 else return Eigen::Dynamic;
247 using IndexType =
typename std::decay_t<Arg>::Index;
248 auto is0 =
static_cast<IndexType
>(
static_cast<std::ptrdiff_t
>(s0));
249 auto is1 =
static_cast<IndexType
>(
static_cast<std::ptrdiff_t
>(s1));
251 if constexpr (values::fixed<S0> and
252 (es0 == 1 or (values::fixed<S1> and es0 < es1)))
254 using M = Eigen::Matrix<Scalar, rows, cols, Eigen::ColMajor>;
255 Eigen::Stride<es1, es0> strides {is1, is0};
256 return Eigen::Map<const M, Eigen::Unaligned, decltype(strides)> {internal::raw_data(arg), rows, cols, strides};
258 else if constexpr (values::fixed<S1> and
259 (es1 == 1 or (values::fixed<S0> and es1 < es0)))
261 using M = Eigen::Matrix<Scalar, rows, cols, Eigen::RowMajor>;
262 Eigen::Stride<es0, es1> strides {is0, is1};
263 return Eigen::Map<const M, Eigen::Unaligned, decltype(strides)> {internal::raw_data(arg), rows, cols, strides};
269 using M = Eigen::Matrix<Scalar, rows, cols, Eigen::RowMajor>;
270 Eigen::Stride<es0, es1> strides {is0, is1};
271 return Eigen::Map<const M, Eigen::Unaligned, decltype(strides)> {internal::raw_data(arg), rows, cols, strides};
275 using M = Eigen::Matrix<Scalar, rows, cols, Eigen::ColMajor>;
276 Eigen::Stride<es1, es0> strides {is1, is0};
277 return Eigen::Map<const M, Eigen::Unaligned, decltype(strides)> {internal::raw_data(arg), rows, cols, strides};
283 constexpr
auto l = layout_of_v<Arg> == data_layout::right ? Eigen::RowMajor : Eigen::ColMajor;
284 using M = Eigen::Matrix<Scalar, rows, cols, l>;
285 return Eigen::Map<const M> {internal::raw_data(arg), rows, cols};
290 return Eigen3::make_eigen_wrapper(std::forward<Arg>(arg));
296 template<
typename Scalar,
int rows,
int cols, auto options>
297 using dense_type = std::conditional_t<Eigen3::eigen_array_general<T, true>,
298 Eigen::Array<Scalar, rows, cols, options>, Eigen::Matrix<Scalar, rows, cols, options>>;
300 template<
typename Scalar, std::
size_t rows, std::
size_t cols, auto options>
301 using writable_type = dense_type<Scalar,
302 (rows == stdex::dynamic_extent ? Eigen::Dynamic :
static_cast<int>(rows)),
303 (cols == stdex::dynamic_extent ? Eigen::Dynamic :
static_cast<int>(cols)), options>;
307 #ifdef __cpp_concepts 308 template<
typename To, Eigen3::eigen_general From> requires (std::assignable_from<To&, From&&>)
310 template<
typename To,
typename From, std::enable_if_t<Eigen3::eigen_general<From> and std::is_assignable_v<To&, From&&>,
int> = 0>
312 static void copy(To& a, From&& b)
314 if constexpr (Eigen3::eigen_DiagonalWrapper<From>)
317 a = std::forward<From>(b);
319 a =
diagonal_of(std::forward<From>(b)).asDiagonal();
323 a = std::forward<From>(b);
329 template<
typename Descriptors>
330 static constexpr decltype(
auto)
331 extract_descriptors(Descriptors&& descriptors)
333 if constexpr (pattern_collection<Descriptors>)
335 constexpr
auto dim = collections::size_of_v<Descriptors>;
336 static_assert(dim <= 2);
338 else if constexpr (dim == 1)
return std::tuple {std::get<0>(std::forward<Descriptors>(descriptors)),
coordinates::Axis{}};
339 else return std::forward<Descriptors>(descriptors);
343 auto it = stdex::ranges::begin(descriptors);
344 auto e = stdex::ranges::end(descriptors);
349 if (++it == e)
return std::tuple {i, j};
350 throw std::logic_error(
"Wrong number of vector space descriptors");
356 #ifdef __cpp_concepts 357 template<data_layout layout, values::number Scalar, coordinates::eucl
idean_pattern_collection Ds>
359 template<data_layout layout,
typename Scalar,
typename Ds, std::enable_if_t<values::number<Scalar> and
360 coordinates::eucl
idean_pattern_collection<Ds>,
int> = 0>
362 static auto make_default(Ds&& ds)
364 using IndexType =
typename Eigen::Index;
366 if constexpr (pattern_collection<Ds> and collections::size_of_v<Ds> > 2)
368 constexpr
auto options = layout == data_layout::right ? Eigen::RowMajor : Eigen::ColMajor;
370 if constexpr (fixed_pattern_collection<Ds>)
373 return Eigen::Sizes<static_cast<std::ptrdiff_t>(coordinates::dimension_of_v<decltype(d)>)...> {};
374 }, std::forward<Ds>(ds));
376 return Eigen::TensorFixedSize<Scalar, decltype(sizes), options, IndexType> {};
381 using Ten = Eigen::Tensor<Scalar, collections::size_of_v<Ds>, options, IndexType>;
383 }, std::forward<Ds>(ds));
388 auto [d0, d1] = extract_descriptors(std::forward<Ds>(ds));
389 constexpr
auto dim0 = coordinates::dimension_of_v<decltype(d0)>;
390 constexpr
auto dim1 = coordinates::dimension_of_v<decltype(d1)>;
392 static_assert(layout != data_layout::right or dim0 == 1 or dim1 != 1,
393 "Eigen does not allow creation of a row-major column vector.");
394 static_assert(layout != data_layout::left or dim0 != 1 or dim1 == 1,
395 "Eigen does not allow creation of a column-major row vector.");
397 constexpr
auto options =
398 layout == data_layout::right or (layout ==
data_layout::none and dim0 == 1 and dim1 != 1) ?
399 Eigen::RowMajor : Eigen::ColMajor;
401 using M = writable_type<Scalar, dim0, dim1, options>;
403 if constexpr (dim0 == stdex::dynamic_extent or dim1 == stdex::dynamic_extent)
413 #ifdef __cpp_concepts 414 template<data_layout layout, writable Arg, std::convertible_to<scalar_type_of_t<Arg>> S, std::convertible_to<scalar_type_of_t<Arg>>...Ss>
415 requires (layout == data_layout::right) or (layout == data_layout::left)
417 template<data_layout layout,
typename Arg,
typename S,
typename...Ss, std::enable_if_t<writable<Arg> and
418 (layout == data_layout::right or layout == data_layout::left) and
419 std::conjunction<std::is_convertible<S, typename scalar_type_of<Arg>::type>,
420 std::is_convertible<Ss, typename scalar_type_of<Arg>::type>...>
::value,
int> = 0>
424 if constexpr (layout == data_layout::left) ((arg.transpose() << s), ... , ss);
425 else ((arg << s), ... , ss);
429 #ifdef __cpp_lib_ranges 430 template<values::dynamic C, coordinates::eucl
idean_pattern_collection Ds> requires
431 (collections::size_of_v<Ds> != stdex::dynamic_extent) and (collections::size_of_v<Ds> <= 2)
432 static constexpr constant_matrix
auto 434 template<
typename C,
typename Ds, std::enable_if_t<values::dynamic<C> and
435 coordinates::eucl
idean_pattern_collection<Ds> and
436 (collections::size_of_v<Ds> != stdex::dynamic_extent) and (collections::size_of_v<Ds> <= 2)),
int> = 0>
437 static constexpr auto
439 make_constant(C&& c, Ds&& ds)
441 auto [d0, d1] = extract_descriptors(std::forward<Ds>(ds));
442 constexpr auto dim0 = coordinates::dimension_of_v<decltype(d0)>;
443 constexpr auto dim1 = coordinates::dimension_of_v<decltype(d1)>;
445 auto value = values::to_value_type(std::forward<C>(c));
446 using Scalar = std::decay_t<decltype(value)>;
447 constexpr auto options = (dim0 == 1 and dim1 != 1) ? Eigen::RowMajor : Eigen::ColMajor;
448 using M = writable_type<Scalar, dim0, dim1, options>;
450 using IndexType =
typename Eigen::Index;
452 if constexpr (fixed_pattern_collection<Ds>)
453 return M::Constant(value);
455 return M::Constant(static_cast<IndexType>(dim0), static_cast<IndexType>(get_dimension(d1)), value);
460 #ifdef __cpp_concepts
461 template<
typename Scalar, coordinates::eucl
idean_pattern_collection Ds> requires
462 (collections::size_of_v<Ds> != stdex::dynamic_extent) and (collections::size_of_v<Ds> <= 2)
465 template<
typename Scalar,
typename...Ds, std::enable_if_t<coordinates::euclidean_pattern_collection<Ds> and
466 (collections::size_of_v<Ds> != stdex::dynamic_extent) and (collections::size_of_v<Ds> <= 2),
int> = 0>
467 static constexpr
auto 469 make_identity_matrix(Ds&& ds)
471 auto [d0, d1] = extract_descriptors(std::forward<Ds>(ds));
472 constexpr
auto dim0 = coordinates::dimension_of_v<decltype(d0)>;
473 constexpr
auto dim1 = coordinates::dimension_of_v<decltype(d1)>;
475 constexpr
auto options = (dim0 == 1 and dim1 != 1) ? Eigen::RowMajor : Eigen::ColMajor;
476 using M = writable_type<Scalar, dim0, dim1, options>;
478 using IndexType =
typename Eigen::Index;
480 if constexpr (fixed_pattern_collection<Ds>)
481 return M::Identity();
487 #ifdef __cpp_concepts 488 template<triangle_type t, Eigen3::eigen_dense_general Arg> requires std::is_lvalue_reference_v<Arg> or
489 (not std::is_lvalue_reference_v<
typename Eigen::internal::ref_selector<std::decay_t<Arg>>::non_const_type>)
491 template<triangle_type t,
typename Arg, std::enable_if_t<Eigen3::eigen_dense_general<Arg> and (std::is_lvalue_reference_v<Arg> or
492 not std::is_lvalue_reference_v<
typename Eigen::
internal::ref_selector<std::remove_reference_t<Arg>>::non_const_type>),
int> = 0>
494 static constexpr
auto 498 return arg.template triangularView<Mode>();
502 #ifdef __cpp_concepts 503 template<HermitianAdapterType t, Eigen3::eigen_dense_general Arg> requires std::is_lvalue_reference_v<Arg>
505 template<HermitianAdapterType t,
typename Arg, std::enable_if_t<Eigen3::eigen_dense_general<Arg> and std::is_lvalue_reference_v<Arg>,
int> = 0>
507 static constexpr
auto 508 make_hermitian_adapter(Arg&& arg)
511 return arg.template selfadjointView<Mode>();
522 #ifdef __cpp_concepts 523 template<
typename Arg,
typename...Begin,
typename...Size> requires (
sizeof...(Begin) <= 2)
525 template<
typename Arg,
typename...Begin,
typename...Size, std::enable_if_t<(
sizeof...(Begin) <= 2),
int> = 0>
528 get_slice(Arg&& arg,
const std::tuple<Begin...>& begin,
const std::tuple<Size...>&
size)
530 auto b0 = [](
const auto& begin){
531 using Begin0 = std::decay_t<decltype(std::get<0>(begin))>;
532 if constexpr (values::fixed<Begin0>)
return std::integral_constant<Eigen::Index, Begin0::value>{};
533 else return static_cast<Eigen::Index
>(std::get<0>(begin));
536 auto b1 = [](
const auto& begin){
537 if constexpr (
sizeof...(Begin) < 2)
return std::integral_constant<Eigen::Index, 0>{};
540 using Begin1 = std::decay_t<decltype(std::get<1>(begin))>;
541 if constexpr (values::fixed<Begin1>)
return std::integral_constant<Eigen::Index, Begin1::value>{};
542 else return static_cast<Eigen::Index
>(std::get<1>(begin));
546 auto s0 = [](
const auto&
size){
547 using Size0 = std::decay_t<decltype(std::get<0>(
size))>;
548 if constexpr (values::fixed<Size0>)
return std::integral_constant<Eigen::Index, Size0::value>{};
549 else return static_cast<Eigen::Index
>(std::get<0>(
size));
552 auto s1 = [](
const auto&
size){
553 if constexpr (
sizeof...(Size) < 2)
return std::integral_constant<Eigen::Index, 1>{};
556 using Size1 = std::decay_t<decltype(std::get<1>(
size))>;
557 if constexpr (values::fixed<Size1>)
return std::integral_constant<Eigen::Index, Size1::value>{};
558 else return static_cast<Eigen::Index
>(std::get<1>(
size));
562 constexpr
int S0 =
static_cast<int>(values::fixed<decltype(s0)> ?
static_cast<Eigen::Index
>(s0) : Eigen::Dynamic);
563 constexpr
int S1 =
static_cast<int>(values::fixed<decltype(s1)> ?
static_cast<Eigen::Index
>(s1) : Eigen::Dynamic);
565 decltype(
auto) m = to_native_matrix(std::forward<Arg>(arg));
566 using M = decltype(m);
568 constexpr
auto Flags = Eigen::internal::traits<std::remove_reference_t<M>>::Flags;
570 if constexpr (directly_accessible<M> and not (std::is_lvalue_reference_v<M> and static_cast<bool>(Flags & Eigen::NestByRefBit)))
573 auto rep {std::forward<M>(m).
template replicate<1,1>()};
574 using B = Eigen::Block<const decltype(rep), S0, S1>;
575 if constexpr ((values::fixed<Size> and ...))
576 return B {std::move(rep), std::move(b0), std::move(b1)};
578 return B {std::move(rep), std::move(b0), std::move(b1), std::move(s0), std::move(s1)};
582 using M_noref = std::remove_reference_t<M>;
583 using XprType = std::conditional_t<std::is_lvalue_reference_v<M>, M_noref,
const M_noref>;
584 using B = Eigen::Block<XprType, S0, S1>;
585 if constexpr ((values::fixed<Size> and ...))
586 return B {std::forward<M>(m), std::move(b0), std::move(b1)};
588 return B {std::forward<M>(m), std::move(b0), std::move(b1), std::move(s0), std::move(s1)};
593 #ifdef __cpp_concepts 594 template<Eigen3::eigen_dense_general Arg, Eigen3::eigen_general Block,
typename...Begin> requires (
sizeof...(Begin) <= 2)
596 template<
typename Arg,
typename Block,
typename...Begin, std::enable_if_t<
597 Eigen3::eigen_dense_general<Arg> and Eigen3::eigen_general<Block> and (
sizeof...(Begin) <= 2),
int> = 0>
600 set_slice(Arg& arg, Block&& block,
const Begin&...begin)
602 auto [b0, b1] = [](Eigen::Index bs0, Eigen::Index bs1,
const auto&...){
return std::tuple {bs0, bs1}; }
603 (
static_cast<std::size_t
>(begin)..., 0_uz, 0_uz);
605 if constexpr (Eigen3::eigen_Block<Block>)
607 if (std::addressof(arg) == std::addressof(block.nestedExpression()) and b0 == block.startRow() and b1 == block.startCol())
611 constexpr
auto Bx0 =
static_cast<int>(index_dimension_of_v<Block, 0>);
612 constexpr
auto Bx1 =
static_cast<int>(index_dimension_of_v<Block, 1>);
613 using Bk = Eigen::Block<std::remove_reference_t<Arg>, Bx0, Bx1>;
615 if constexpr (not has_dynamic_dimensions<Block>)
617 Bk {arg, b0, b1} = std::forward<Block>(block);
621 auto s0 =
static_cast<Eigen::Index
>(get_index_dimension_of<0>(block));
622 auto s1 =
static_cast<Eigen::Index
>(get_index_dimension_of<1>(block));
623 Bk {arg, b0, b1, s0, s1} = std::forward<Block>(block);
628 #ifdef __cpp_concepts 629 template<triangle_type t, Eigen3::eigen_SelfAdjo
intView A, Eigen3::eigen_general B> requires (not hermitian_matrix<A>) and
630 set_triangle_defined_for<T, t, decltype(OpenKalman::nested_object(std::declval<A>())), B&&>
632 template<
triangle_type t,
typename A,
typename B, std::enable_if_t<
633 Eigen3::eigen_general<B> and Eigen3::eigen_SelfAdjointView<A> and (not hermitian_matrix<A>) and
634 set_triangle_defined_for<T, t, decltype(OpenKalman::nested_object(std::declval<A>())), B&&>,
int> = 0>
637 set_triangle(
A&& a, B&& b)
648 #ifdef __cpp_concepts 649 template<triangle_type t,
typename A, Eigen3::eigen_general B> requires
651 std::assignable_from<decltype(OpenKalman::diagonal_of(std::declval<A&&>())), decltype(
OpenKalman::diagonal_of(std::declval<B&&>()))>
653 template<
triangle_type t,
typename A,
typename B, std::enable_if_t<
654 Eigen3::eigen_general<B> and ((diagonal_matrix<A> and internal::has_nested_vector<A>) or t ==
triangle_type::diagonal) and
655 std::is_assignable_v<decltype(OpenKalman::diagonal_of(std::declval<A&&>())), decltype(
OpenKalman::diagonal_of(std::declval<B&&>()))>,
int> = 0>
658 set_triangle(
A&& a, B&& b)
664 #ifdef __cpp_concepts 665 template<triangle_type t,
typename A, Eigen3::eigen_general B> requires
666 (Eigen3::eigen_MatrixWrapper<A> or Eigen3::eigen_ArrayWrapper<A>) and
667 set_triangle_defined_for<T, t, decltype(OpenKalman::nested_object(std::declval<A>())), B&&>
669 template<
triangle_type t,
typename A,
typename B, std::enable_if_t<Eigen3::eigen_general<B> and
670 (Eigen3::eigen_MatrixWrapper<A> or Eigen3::eigen_ArrayWrapper<A>) and
671 set_triangle_defined_for<T, t, decltype(OpenKalman::nested_object(std::declval<A>())), B&&>,
int> = 0>
674 set_triangle(
A&& a, B&& b)
680 #ifdef __cpp_concepts 681 template<triangle_type t, Eigen3::eigen_dense_general A, Eigen3::eigen_general B> requires
682 (not Eigen3::eigen_MatrixWrapper<A>) and (not Eigen3::eigen_ArrayWrapper<A>) and
685 template<
triangle_type t,
typename A,
typename B, std::enable_if_t<
686 Eigen3::eigen_dense_general<A> and Eigen3::eigen_general<B> and
687 (not Eigen3::eigen_MatrixWrapper<A>) and (not Eigen3::eigen_ArrayWrapper<A>) and
691 set_triangle(
A&& a, B&& b)
693 a.template triangularView<t == triangle_type::upper ? Eigen::Upper : Eigen::Lower>() = std::forward<B>(b);
697 #ifdef __cpp_concepts 698 template<Eigen3::eigen_dense_general Arg> requires square_shaped<Arg> or dimension_size_of_index_is<Arg, 0, 1> or
699 std::is_lvalue_reference_v<Arg> or (not std::is_lvalue_reference_v<
typename std::decay_t<Arg>::Nested>)
701 template<
typename Arg, std::enable_if_t<Eigen3::eigen_dense_general<Arg> and
702 (square_shaped<Arg> or dimension_size_of_index_is<Arg, 0, 1> or std::is_lvalue_reference_v<Arg> or
703 not std::is_lvalue_reference_v<
typename std::decay_t<Arg>::Nested>),
int> = 0>
705 static constexpr
auto 708 if constexpr (not vector<Arg>)
if (not
is_vector(arg))
throw std::invalid_argument {
709 "Argument of to_diagonal must have 1 column; instead it has " + std::to_string(get_index_dimension_of<1>(arg))};
711 if constexpr (square_shaped<Arg> or dimension_size_of_index_is<Arg, 0, 1>)
713 return internal::make_fixed_size_adapter(std::forward<Arg>(arg));
715 else if constexpr (Eigen3::eigen_array_general<Arg>)
717 return arg.matrix().asDiagonal();
721 return arg.asDiagonal();
726 #ifdef __cpp_concepts 729 template<
typename Arg, std::enable_if_t<Eigen3::eigen_SelfAdjo
intView<Arg>,
int> = 0>
731 static constexpr
auto 739 #ifdef __cpp_concepts 740 template<Eigen3::eigen_TriangularView Arg> requires (triangle_type_of_v<Arg> ==
triangle_type::lower)
742 template<
typename Arg, std::enable_if_t<Eigen3::eigen_TriangularView<Arg> and (triangle_type_of_v<Arg> == triangle_type::lower),
int> = 0>
744 static constexpr
auto 752 template<
typename Arg>
753 #ifdef __cpp_concepts 754 static constexpr
vector decltype(
auto)
756 static constexpr decltype(
auto)
760 using Scalar = scalar_type_of_t<Arg>;
762 if constexpr (Eigen3::eigen_DiagonalWrapper<Arg>)
764 using Diag = decltype(
nested_object(std::forward<Arg>(arg)));
765 using EigenTraits = Eigen::internal::traits<std::decay_t<Diag>>;
766 constexpr
auto rows = EigenTraits::RowsAtCompileTime;
767 constexpr
auto cols = EigenTraits::ColsAtCompileTime;
769 static_assert(cols != 1,
"For Eigen::DiagonalWrapper<T> interface, T should never be a column vector " 770 "because diagonal_of function handles this case.");
771 if constexpr (cols == 0)
776 else if constexpr (rows == 1 or rows == 0)
781 else if constexpr (rows == Eigen::Dynamic or cols == Eigen::Dynamic)
784 using M = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
786 get_index_dimension_of<0>(diag) * get_index_dimension_of<1>(diag))};
790 using M = Eigen::Matrix<Scalar, rows * cols, 1>;
794 else if constexpr (Eigen3::eigen_SelfAdjointView<Arg> or Eigen3::eigen_TriangularView<Arg>)
798 else if constexpr (Eigen3::eigen_Identity<Arg>)
800 auto f = [](
const auto& a,
const auto& b) {
return std::min(a, b); };
801 auto dim =
values::operation(f, get_index_dimension_of<0>(arg), get_index_dimension_of<1>(arg));
802 return make_constant<Arg, Scalar, 1>(dim);
804 else if constexpr (Eigen3::eigen_dense_general<Arg>)
806 decltype(
auto) m = to_native_matrix(std::forward<Arg>(arg));
807 using M = decltype(m);
808 using M_noref = std::remove_reference_t<M>;
809 using MatrixType = std::conditional_t<std::is_lvalue_reference_v<M>, M_noref,
const M_noref>;
810 return Eigen::Diagonal<MatrixType, 0> {std::forward<M>(m)};
819 template<
typename Arg,
typename Factor0 = std::
integral_constant<std::
size_t, 1>,
typename Factor1 = std::
integral_constant<std::
size_t, 1>>
821 broadcast(Arg&& arg,
const Factor0& factor0 = Factor0{},
const Factor1& factor1 = Factor1{})
823 constexpr
int F0 = []{
824 if constexpr (values::fixed<Factor0>)
return static_cast<std::size_t
>(Factor0{});
825 else return Eigen::Dynamic;
827 constexpr
int F1 = []{
828 if constexpr (values::fixed<Factor1>)
return static_cast<std::size_t
>(Factor1{});
829 else return Eigen::Dynamic;
832 using IndexType =
typename std::decay_t<Arg>::Index;
834 decltype(
auto) m = to_native_matrix(std::forward<Arg>(arg));
835 using M = decltype(m);
836 using R = Eigen::Replicate<std::remove_reference_t<M>, F0, F1>;
837 if constexpr (values::fixed<Factor0> and values::fixed<Factor1>)
838 return R {std::forward<M>(m)};
840 return R {std::forward<M>(m), static_cast<IndexType>(factor0),
static_cast<IndexType
>(factor1)};
846 template<
typename Op,
typename...S>
847 static constexpr
auto dummy_op(Op op, S...s)
849 if constexpr (std::is_invocable_v<Op, S...>)
return op(s...);
850 else if constexpr (std::is_invocable_v<Op, std::size_t, std::size_t>)
return op(std::size_t{0}, std::size_t{0});
851 else return op(std::size_t{0});
855 template<
typename Op,
typename...Args>
858 template<
typename Op,
typename Arg>
859 struct EigenNaryOp<Op, Arg> {
using type = Eigen::CwiseUnaryOp<Op, Arg>; };
861 template<
typename Op,
typename Arg1,
typename Arg2>
862 struct EigenNaryOp<Op, Arg1, Arg2> {
using type = Eigen::CwiseBinaryOp<Op, Arg1, Arg2>; };
864 template<
typename Op,
typename Arg1,
typename Arg2,
typename Arg3>
865 struct EigenNaryOp<Op, Arg1, Arg2, Arg3> {
using type = Eigen::CwiseTernaryOp<Op, Arg1, Arg2, Arg3>; };
869 #ifdef __cpp_concepts 871 (
sizeof...(Ds) <= 2) and (
sizeof...(Args) <= 3) and
872 (
values::number<std::invoke_result_t<Operation, scalar_type_of_t<Args>...>> or
873 (
sizeof...(Args) == 0 and
874 (
values::number<std::invoke_result_t<Operation, std::conditional_t<true, std::size_t, Ds>...>> or
877 template<
typename...Ds,
typename Operation,
typename...Args, std::enable_if_t<
sizeof...(Ds) <= 2 and
sizeof...(Args) <= 3 and
878 (coordinates::pattern<Ds> and ...) and (indexible<Args> and ...) and
879 (
values::number<
typename std::invoke_result<Operation,
typename scalar_type_of<Args>::type...>::type> or
880 (
sizeof...(Args) == 0 and
881 (
values::number<
typename std::invoke_result<Operation, std::conditional_t<true, std::size_t, Ds>...>::type> or
882 values::number<
typename std::invoke_result<Operation, std::size_t>::type>))),
int> = 0>
887 decltype(
auto) op = Eigen3::native_operation(std::forward<Operation>(
operation));
888 using Op = decltype(op);
889 using Scalar = decltype(dummy_op(
operation, std::declval<scalar_type_of_t<Args>>()...));
891 if constexpr (
sizeof...(Args) == 0)
894 return Eigen::CwiseNullaryOp<std::remove_reference_t<Op>, P> {
895 static_cast<typename P::Index
>(
get_dimension(std::get<0>(tup))),
896 static_cast<typename P::Index>(
get_dimension(std::get<1>(tup))),
897 std::forward<Op>(op)};
901 auto seq = std::index_sequence_for<Ds...>{};
902 using CW =
typename EigenNaryOp<std::decay_t<Op>, std::remove_reference_t<Args>...>::type;
903 return CW {std::forward<Args>(args)..., std::forward<Op>(op)};
908 #ifdef __cpp_concepts 909 template<std::size_t...indices,
typename BinaryFunction,
typename Arg> requires ((indices <= 1) and ...)
911 template<std::size_t...indices,
typename BinaryFunction,
typename Arg, std::enable_if_t<((indices <= 1) and ...),
int> = 0>
914 reduce(BinaryFunction&& b, Arg&& arg)
916 if constexpr (Eigen3::eigen_dense_general<Arg>)
918 auto&& op = Eigen3::native_operation(std::forward<BinaryFunction>(b));
919 using Op = decltype(op);
921 if constexpr (((indices == 0) or ...) and ((indices == 1) or ...))
923 return std::forward<Arg>(arg).redux(std::forward<Op>(op));
927 constexpr
auto dir = ((indices == 0) and ...) ? Eigen::Vertical : Eigen::Horizontal;
928 using ROp = Eigen::internal::member_redux<std::decay_t<Op>, scalar_type_of_t<Arg>>;
929 decltype(
auto) m = to_native_matrix(std::forward<Arg>(arg));
930 using M = decltype(m);
931 using M_noref = std::remove_reference_t<M>;
932 using MatrixType = std::conditional_t<std::is_lvalue_reference_v<M>, M_noref,
const M_noref>;
933 return Eigen::PartialReduxExpr<MatrixType, ROp, dir> {std::forward<M>(m), ROp{std::forward<Op>(op)}};
938 return reduce<indices...>(std::forward<BinaryFunction>(b), to_native_matrix(std::forward<Arg>(arg)));
943 template<
typename Arg>
944 static constexpr decltype(
auto)
947 if constexpr (Eigen3::eigen_dense_general<Arg>)
949 using UnaryOp = Eigen::internal::scalar_conjugate_op<scalar_type_of_t<Arg>>;
950 decltype(
auto) m = to_native_matrix(std::forward<Arg>(arg));
951 using M = decltype(m);
952 return Eigen::CwiseUnaryOp<UnaryOp, std::remove_reference_t<M>> {std::forward<M>(m)};
954 else if constexpr (Eigen3::eigen_TriangularView<Arg> or Eigen3::eigen_SelfAdjointView<Arg>)
956 return std::forward<Arg>(arg).
conjugate();
958 else if constexpr (triangular_matrix<Arg>)
964 return conjugate(to_native_matrix(std::forward<Arg>(arg)));
970 template<
typename Arg>
971 static constexpr decltype(
auto)
974 if constexpr (Eigen3::eigen_matrix_general<Arg>)
976 decltype(
auto) m = to_native_matrix(std::forward<Arg>(arg));
977 using M = decltype(m);
978 using M_noref = std::remove_reference_t<M>;
979 using MatrixType = std::conditional_t<std::is_lvalue_reference_v<M>, M_noref,
const M_noref>;
980 return Eigen::Transpose<MatrixType> {std::forward<M>(m)};
982 else if constexpr (Eigen3::eigen_TriangularView<Arg> or Eigen3::eigen_SelfAdjointView<Arg>)
984 return std::forward<Arg>(arg).
transpose();
986 else if constexpr (triangular_matrix<Arg>)
990 return OpenKalman::make_triangular_matrix<t>(
transpose(to_native_matrix(std::forward<Arg>(arg))));
994 return transpose(to_native_matrix(std::forward<Arg>(arg)));
1000 #ifdef __cpp_concepts 1001 template<
typename Arg> requires (not Eigen3::eigen_dense_general<Arg>)
1003 template<
typename Arg, std::enable_if_t<not Eigen3::eigen_dense_general<Arg>,
int> = 0>
1005 static constexpr decltype(
auto)
1008 if constexpr (Eigen3::eigen_TriangularView<Arg> or Eigen3::eigen_SelfAdjointView<Arg>)
1010 return std::forward<Arg>(arg).
adjoint();
1012 else if constexpr (triangular_matrix<Arg>)
1016 return OpenKalman::make_triangular_matrix<t>(
OpenKalman::adjoint(to_native_matrix(std::forward<Arg>(arg))));
1026 template<
typename Arg>
1027 static constexpr
auto 1030 if constexpr (Eigen3::eigen_matrix_general<Arg, true>)
1032 else if constexpr (Eigen3::eigen_array_general<Arg, true>)
1033 return std::forward<Arg>(arg).matrix().determinant();
1035 return to_native_matrix(std::forward<Arg>(arg)).determinant();
1040 #ifdef __cpp_concepts 1041 template<
typename A, Eigen3::eigen_general B>
1043 template<
typename A,
typename B, std::enable_if_t<Eigen3::eigen_general<B>,
int> = 0>
1045 static constexpr
auto 1051 auto f = [](
auto&& x) -> decltype(
auto) {
1052 constexpr
bool herm = hermitian_matrix<A> and hermitian_matrix<B>;
1058 return std::forward<decltype(x)>(x);
1061 auto op = Eigen::internal::scalar_sum_op<scalar_type_of_t<A>, scalar_type_of_t<B>>{};
1063 decltype(
auto) a_wrap = to_native_matrix(f(std::forward<A>(a)));
1064 using AWrap = decltype(a_wrap);
1065 decltype(
auto) b_wrap = to_native_matrix(f(std::forward<B>(b)));
1066 using BWrap = decltype(b_wrap);
1067 using CW = Eigen::CwiseBinaryOp<decltype(op), std::remove_reference_t<AWrap>, std::remove_reference_t<BWrap>>;
1068 CW s {std::forward<AWrap>(a_wrap), std::forward<BWrap>(b_wrap), std::move(op)};
1070 if constexpr (triangle_type_of_v<A, B> !=
triangle_type::any)
return OpenKalman::make_triangular_matrix<triangle_type_of_v<A, B>>(std::move(s));
1071 else if constexpr (hermitian_matrix<A> and hermitian_matrix<B>)
return make_hermitian_matrix<h>(std::move(s));
1077 template<
typename Arg,
typename S,
typename Op>
1078 static constexpr
auto 1079 scalar_op_impl(Arg&& arg, S&& s, Op&& op)
1081 using Scalar = scalar_type_of_t<Arg>;
1082 using ConstOp = Eigen::internal::scalar_constant_op<Scalar>;
1083 decltype(
auto) m {to_native_matrix(std::forward<Arg>(arg))};
1084 using M = decltype(m);
1086 using Index =
typename PlainObjectType::Index;
1087 auto c {Eigen::CwiseNullaryOp<ConstOp, PlainObjectType> {
1088 static_cast<Index
>(get_index_dimension_of<0>(m)),
1089 static_cast<Index
>(get_index_dimension_of<1>(m)),
1091 using CW = Eigen::CwiseBinaryOp<Op, std::remove_reference_t<M>, decltype(c)>;
1092 return CW {std::forward<M>(m), c, std::forward<Op>(op)};
1097 #ifdef __cpp_concepts 1098 template<indexible Arg, values::scalar S>
1099 static constexpr vector_space_descriptors_may_match_with<Arg>
auto 1101 template<
typename Arg,
typename S>
1102 static constexpr
auto 1104 scalar_product(Arg&& arg, S&& s)
1106 using Scalar = scalar_type_of_t<Arg>;
1107 using Op = Eigen::internal::scalar_product_op<Scalar, Scalar>;
1108 return scalar_op_impl(std::forward<Arg>(arg), std::forward<S>(s), Op{});
1112 #ifdef __cpp_concepts 1113 template<indexible Arg, values::scalar S>
1114 static constexpr vector_space_descriptors_may_match_with<Arg>
auto 1116 template<
typename Arg,
typename S>
1117 static constexpr
auto 1119 scalar_quotient(Arg&& arg, S&& s)
1121 using Scalar = scalar_type_of_t<Arg>;
1122 using Op = Eigen::internal::scalar_quotient_op<Scalar, Scalar>;
1123 return scalar_op_impl(std::forward<Arg>(arg), std::forward<S>(s), Op{});
1127 #ifdef __cpp_concepts 1128 template<Eigen3::eigen_general A, Eigen3::eigen_general B>
1130 template<
typename A,
typename B, std::enable_if_t<(Eigen3::eigen_general<A> and Eigen3::eigen_general<B>),
int> = 0>
1132 static constexpr
auto 1135 if constexpr (diagonal_matrix<A> and not Eigen3::eigen_DiagonalWrapper<A> and not Eigen3::eigen_DiagonalMatrix<A>)
1137 return contract(to_native_matrix(
diagonal_of(std::forward<A>(a))).asDiagonal(), std::forward<B>(b));
1139 else if constexpr (diagonal_matrix<B> and not Eigen3::eigen_DiagonalWrapper<B> and not Eigen3::eigen_DiagonalMatrix<B>)
1141 return contract(std::forward<A>(a), to_native_matrix(
diagonal_of(std::forward<B>(b))).asDiagonal());
1143 else if constexpr (diagonal_matrix<A> or diagonal_matrix<B>)
1145 decltype(
auto) a_wrap = to_native_matrix(std::forward<A>(a));
1146 using AWrap = decltype(a_wrap);
1147 decltype(
auto) b_wrap = to_native_matrix(std::forward<B>(b));
1148 using BWrap = decltype(b_wrap);
1149 using Prod = Eigen::Product<std::remove_reference_t<AWrap>, std::remove_reference_t<BWrap>, Eigen::LazyProduct>;
1150 return Prod {std::forward<AWrap>(a_wrap), std::forward<BWrap>(b_wrap)};
1152 else if constexpr (not Eigen3::eigen_matrix_general<B>)
1154 return contract(std::forward<A>(a), to_native_matrix(std::forward<B>(b)));
1156 else if constexpr (Eigen3::eigen_matrix_general<A> or Eigen3::eigen_TriangularView<A> or Eigen3::eigen_SelfAdjointView<A>)
1158 using Prod = Eigen::Product<std::remove_reference_t<A>, std::remove_reference_t<B>, Eigen::DefaultProduct>;
1159 return to_dense_object(Prod {std::forward<A>(a), std::forward<B>(b)});
1163 return contract(to_native_matrix(std::forward<A>(a)), std::forward<B>(b));
1168 #ifdef __cpp_concepts 1169 template<
bool on_the_right, writable A, indexible B> requires Eigen3::eigen_dense_general<A> or
1170 Eigen3::eigen_DiagonalMatrix<A> or Eigen3::eigen_DiagonalWrapper<A>
1172 template<
bool on_the_right,
typename A,
typename B, std::enable_if_t<writable<A> and
1173 (Eigen3::eigen_dense_general<A> or Eigen3::eigen_DiagonalMatrix<A> or (Eigen3::eigen_DiagonalWrapper<A> and diagonal_matrix<A> and
internal::has_nested_vector<A, 0>)),
int> = 0>
1178 if constexpr (Eigen3::eigen_DiagonalMatrix<A> or Eigen3::eigen_DiagonalWrapper<A>)
1180 static_assert(diagonal_matrix<B>);
1183 else if constexpr (Eigen3::eigen_TriangularView<A>)
1190 auto&& ma = [](
A& a) -> decltype(
auto) {
1191 if constexpr (Eigen3::eigen_array_general<A>)
return a.matrix();
1195 if constexpr (on_the_right)
1196 return ma.applyOnTheRight(OpenKalman::to_native_matrix<T>(std::forward<B>(b)));
1198 return ma.applyOnTheLeft(OpenKalman::to_native_matrix<T>(std::forward<B>(b)));
1204 #ifdef __cpp_concepts 1205 template<triangle_type tri, Eigen3::eigen_SelfAdjo
intView A>
1207 template<triangle_type tri,
typename A, std::enable_if_t<Eigen3::eigen_SelfAdjo
intView<A>,
int> = 0>
1209 static constexpr
auto 1212 using NestedMatrix = std::decay_t<nested_object_of_t<A>>;
1213 using Scalar = scalar_type_of_t<A>;
1216 if constexpr (constant_matrix<NestedMatrix>)
1225 throw (std::runtime_error(
"cholesky_factor of constant HermitianAdapter: result is indefinite"));
1230 static_assert(diagonal_matrix<A>);
1236 auto col0 = make_constant<A>(
values::sqrt(s), euc_dim, Dimensions<1>{});
1237 auto othercols = make_zero<A>(euc_dim, euc_dim - Dimensions<1>{});
1244 auto row0 = make_constant<A>(
values::sqrt(s), Dimensions<1>{}, dim);
1245 auto otherrows = make_zero<A>(euc_dim - Dimensions<1>{}, euc_dim);
1254 auto LL_x = a.llt();
1255 if (LL_x.info() == Eigen::Success)
1260 b = std::move(LL_x.matrixLLT());
1265 b.template triangularView<uplo>() = LL_x.matrixLLT().adjoint();
1272 if ((not LDL_x.isPositive() and not LDL_x.isNegative()) or LDL_x.info() != Eigen::Success) [[unlikely]]
1274 if (LDL_x.isPositive() and LDL_x.isNegative())
1283 throw (std::runtime_error(
"cholesky_factor of HermitianAdapter: covariance is indefinite"));
1288 b.template triangularView<Eigen::Lower>() =
1289 LDL_x.matrixL().toDenseMatrix() * LDL_x.vectorD().cwiseSqrt().asDiagonal();
1293 b.template triangularView<Eigen::Upper>() =
1294 LDL_x.vectorD().cwiseSqrt().asDiagonal() * LDL_x.matrixU().toDenseMatrix();
1302 template<HermitianAdapterType significant_triangle,
typename A,
typename U,
typename Alpha>
1303 static decltype(
auto)
1306 if constexpr (Eigen3::eigen_matrix_general<A>)
1308 static_assert(writable<A>);
1310 a.template selfadjointView<s>().
template rankUpdate(std::forward<U>(u), alpha);
1311 return std::forward<A>(a);
1315 return rank_update_hermitian<significant_triangle>(to_native_matrix(std::forward<A>(a)), std::forward<U>(u), alpha);
1320 template<triangle_type triangle,
typename A,
typename U,
typename Alpha>
1321 static decltype(
auto)
1324 if constexpr (Eigen3::eigen_matrix_general<A>)
1326 static_assert(writable<A>);
1328 using Scalar = scalar_type_of_t<A>;
1329 for (std::size_t i = 0; i < get_index_dimension_of<1>(u); i++)
1331 if (Eigen::internal::llt_inplace<Scalar, t>::rankUpdate(a, get_chip<1>(u, i), alpha) >= 0)
1332 throw (std::runtime_error(
"rank_update_triangular: product is not positive definite"));
1334 return std::forward<A>(a);
1338 return rank_update_triangular<triangle>(to_native_matrix(std::forward<A>(a)), std::forward<U>(u), alpha);
1343 #ifdef __cpp_concepts 1344 template<
bool must_be_unique,
bool must_be_exact,
typename A,
typename B> requires Eigen3::eigen_matrix_general<B>
1346 template<
bool must_be_unique,
bool must_be_exact,
typename A,
typename B, std::enable_if_t<Eigen3::eigen_matrix_general<B>,
int> = 0>
1348 static constexpr
auto 1351 using Scalar = scalar_type_of_t<A>;
1353 constexpr std::size_t a_rows = dynamic_dimension<A, 0> ? index_dimension_of_v<B, 0> : index_dimension_of_v<A, 0>;
1354 constexpr std::size_t a_cols = index_dimension_of_v<A, 1>;
1355 constexpr std::size_t b_cols = index_dimension_of_v<B, 1>;
1357 if constexpr (Eigen3::eigen_TriangularView<A>)
1359 auto ret {Eigen::Solve {std::forward<A>(a), std::forward<B>(b)}};
1360 if constexpr (std::is_lvalue_reference_v<A> and std::is_lvalue_reference_v<B>)
return ret;
1363 else if constexpr (Eigen3::eigen_SelfAdjointView<A>)
1365 constexpr
auto uplo = hermitian_adapter_type_of_v<A> ==
triangle_type::upper ? Eigen::Upper : Eigen::Lower;
1366 auto v {std::forward<A>(a).
template selfadjointView<uplo>()};
1370 if (llt.info() == Eigen::Success)
1372 ret = Eigen::Solve {llt, std::forward<B>(b)};
1377 auto ldlt {v.ldlt()};
1378 if ((not ldlt.isPositive() and not ldlt.isNegative()) or ldlt.info() != Eigen::Success)
1380 throw (std::runtime_error(
"Eigen solve (hermitian case): A is indefinite"));
1382 ret = Eigen::Solve {ldlt, std::forward<B>(b)};
1386 else if constexpr (Eigen3::eigen_matrix_general<A>)
1389 if constexpr (must_be_exact or must_be_unique)
1391 auto a_cols_rt = get_index_dimension_of<1>(a);
1392 auto qr {Eigen::ColPivHouseholderQR<Mat> {std::forward<A>(a)}};
1394 if constexpr (must_be_unique)
1396 if (qr.rank() < a_cols_rt)
throw std::runtime_error {
"solve function requests a " 1397 "unique solution, but A is rank-deficient, so result X is not unique"};
1400 auto res {
to_dense_object(Eigen::Solve {std::move(qr), std::forward<B>(b)})};
1402 if constexpr (must_be_exact)
1404 bool a_solution_exists = (a * res).isApprox(b, a_cols_rt * std::numeric_limits<scalar_type_of_t<A>>::epsilon());
1406 if (a_solution_exists)
return res;
1407 else throw std::runtime_error {
"solve function requests an exact solution, " 1408 "but the solution is only an approximation"};
1417 return to_dense_object(Eigen::Solve {Eigen::HouseholderQR<Mat> {std::forward<A>(a)}, std::forward<B>(b)});
1422 return solve<must_be_unique, must_be_exact>(to_native_matrix(std::forward<A>(a)), std::forward<B>(b));
1428 template<
typename A>
1429 static constexpr
auto 1430 QR_decomp_impl(
A&& a)
1432 using Scalar = scalar_type_of_t<A>;
1433 constexpr
auto rows = index_dimension_of_v<A, 0>;
1434 constexpr
auto cols = index_dimension_of_v<A, 1>;
1438 Eigen::HouseholderQR<MatrixType> QR {std::forward<A>(a)};
1440 if constexpr (dynamic_dimension<A, 1>)
1442 auto rt_cols = get_index_dimension_of<1>(a);
1444 ResultType ret {rt_cols, rt_cols};
1446 if constexpr (dynamic_dimension<A, 0>)
1448 auto rt_rows = get_index_dimension_of<0>(a);
1450 if (rt_rows < rt_cols)
1451 ret << QR.matrixQR().topRows(rt_rows),
1454 ret = QR.matrixQR().topRows(rt_cols);
1459 ret << QR.matrixQR().template topRows<rows>(),
1462 ret = QR.matrixQR().topRows(rt_cols);
1471 if constexpr (dynamic_dimension<A, 0>)
1473 auto rt_rows = get_index_dimension_of<0>(a);
1476 ret << QR.matrixQR().topRows(rt_rows),
1479 ret = QR.matrixQR().template topRows<cols>();
1483 if constexpr (rows < cols)
1486 ret = QR.matrixQR().template topRows<cols>();
1495 template<
typename A>
1496 static constexpr
auto 1503 template<
typename A>
1504 static constexpr
auto 1507 return OpenKalman::make_triangular_matrix<triangle_type::upper>(QR_decomp_impl(std::forward<A>(a)));
decltype(auto) constexpr concatenate_vertical(V &&v, Vs &&... vs)
Concatenate one or more typed matrices objects vertically.
Definition: typed-matrix-overloads.hpp:270
constexpr auto attach_pattern(Arg &&arg, P &&p)
Attach a pattern_collection to an indexible object.
Definition: attach_pattern.hpp:36
typename nested_object_of< T >::type nested_object_of_t
Helper type for nested_object_of.
Definition: nested_object_of.hpp:58
constexpr auto n_ary_operation(const std::tuple< Ds... > &d_tup, Operation &&operation, Args &&...args)
Perform a component-wise n-ary operation, using broadcasting to match the size of a pattern matrix...
Definition: n_ary_operation.hpp:325
decltype(auto) constexpr contract(A &&a, B &&b)
Matrix multiplication of A * B.
Definition: contract.hpp:54
Definition: basics.hpp:41
constexpr bool hermitian_adapter
Specifies that a type is a hermitian matrix adapter of a particular type.
Definition: hermitian_adapter.hpp:55
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
Definition: eigen-forward-declarations.hpp:90
triangle_type
The type of a triangular matrix.
Definition: enumerations.hpp:26
A lower-left triangular matrix.
decltype(auto) constexpr conjugate(Arg &&arg)
Take the complex conjugate of an indexible object.
Definition: conjugate.hpp:44
decltype(auto) constexpr get_slice(Arg &&arg, const std::tuple< Offset... > &offsets, const std::tuple< Extent... > &extents)
Extract a slice from a matrix or tensor.
Definition: get_slice.hpp:103
Forward declarations for OpenKalman's Eigen interface.
constexpr bool pattern
An object describing the set of coordinates associated with a tensor index.
Definition: pattern.hpp:31
A triangular_adapter, where components above or below the diagonal (or both) are zero.
Definition: forward-class-declarations.hpp:147
constexpr bool indexible
T is a multidimensional array type.
Definition: indexible.hpp:32
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
constexpr auto is_square_shaped(const T &t)
Determine whether an object is square_shaped.
Definition: is_square_shaped.hpp:69
decltype(auto) constexpr to_value_type(Arg &&arg)
Convert, if necessary, a fixed or dynamic value to its underlying base type.
Definition: to_value_type.hpp:28
constexpr bool number
T is a numerical field type.
Definition: number.hpp:41
HermitianAdapterType
The type of a hermitian adapter, indicating which triangle of the nested matrix is used...
Definition: enumerations.hpp:79
constexpr bool triangular_adapter
Specifies that a type is a triangular adapter of triangle type tri.
Definition: triangular_adapter.hpp:47
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
decltype(auto) constexpr concatenate_horizontal(V &&v, Vs &&... vs)
Concatenate one or more matrix objects vertically.
Definition: typed-matrix-overloads.hpp:308
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
decltype(auto) constexpr reduce(BinaryFunction &&b, Arg &&arg)
Perform a partial reduction based on an associative binary function, across one or more indices...
Definition: reduce.hpp:143
std::conditional_t< sizeof...(dims)==1, Eigen::Matrix< Scalar, detail::eigen_index_convert< dims >..., detail::eigen_index_convert< 1 > >, Eigen::Matrix< Scalar, detail::eigen_index_convert< dims >... > > eigen_matrix_t
An alias for a self-contained, writable, native Eigen matrix.
Definition: eigen-forward-declarations.hpp:491
decltype(auto) constexpr broadcast(Arg &&arg, const Factors &...factors)
Broadcast an object by replicating it by factors specified for each index.
Definition: broadcast.hpp:49
decltype(auto) constexpr apply(F &&f, T &&t)
A generalization of std::apply.
Definition: apply.hpp:49
constexpr auto get_dimension(const Arg &arg)
Get the vector dimension of coordinates::pattern Arg.
Definition: get_dimension.hpp:54
constexpr bool triangular_matrix
Specifies that an argument is an indexible object having a given triangle_type (e.g., upper, lower, or diagonal).
Definition: triangular_matrix.hpp:36
Lower, upper, or diagonal matrix.
An interface to various routines from the linear algebra library associated with indexible object T...
Definition: library_interface.hpp:42
Definition: object_traits.hpp:38
constexpr bool identity_matrix
Specifies that a type is known at compile time to be a rank-2 or lower identity matrix.
Definition: identity_matrix.hpp:50
decltype(auto) constexpr transpose(Arg &&arg)
Swap any two indices of an indexible_object.
Definition: transpose.hpp:163
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
constexpr auto solve(A &&a, B &&b)
Solve the equation AX = B for X, which may or may not be a unique solution.
Definition: solve.hpp:87
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
constexpr auto determinant(Arg &&arg)
Take the determinant of a matrix.
Definition: determinant.hpp:44
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
constexpr auto make_zero(stdex::extents< IndexType, Extents... > extents)
Make an indexible object in which every element is 0.
Definition: make_zero.hpp:35
constexpr bool size
T is either an index representing a size, or unbounded_size_t, which indicates that the size is unbou...
Definition: size.hpp:65
Arg && fill_components(Arg &&arg, S...s)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: fill_components.hpp:67
constexpr auto is_vector(const T &t)
Return true if T is a vector at runtime.
Definition: is_vector.hpp:60
An upper-right triangular matrix.
decltype(auto) constexpr sum(Ts &&...ts)
Element-by-element sum of one or more objects.
Definition: sum.hpp:112
constexpr auto constant_value(T &&t)
The constant value associated with a constant_object or constant_diagonal_object. ...
Definition: constant_value.hpp:37
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
std::decay_t< decltype(make_dense_object< T, layout, S >(std::declval< D >()))> dense_writable_matrix_t
An alias for a dense, writable matrix, patterned on parameter T.
Definition: dense_writable_matrix_t.hpp:38
A structure representing the dimensions associated with of a particular index.
Definition: Dimensions.hpp:42
Definition: trait_backports.hpp:64
decltype(auto) constexpr adjoint(Arg &&arg)
Take the conjugate-transpose of an indexible_object.
Definition: adjoint.hpp:35
decltype(auto) constexpr nested_object(Arg &&arg)
Retrieve a nested object of Arg, if it exists.
Definition: nested_object.hpp:35
constexpr bool vector
T is a vector (e.g., column or row vector).
Definition: vector.hpp:61
A matrix with typed rows and columns.
Definition: forward-class-declarations.hpp:292
decltype(auto) constexpr make_triangular_matrix(Arg &&arg)
Create a triangular_matrix from a general matrix.
Definition: make_triangular_matrix.hpp:35
constexpr auto operation(Operation &&op, Args &&...args)
A potentially constant-evaluated operation involving some number of values.
Definition: operation.hpp:98
decltype(auto) constexpr cholesky_factor(A &&a)
Take the Cholesky factor of a matrix.
Definition: cholesky_factor.hpp:38
constexpr Arg && set_slice(Arg &&arg, Block &&block, const Begin &...begin)
Assign an object to a particular slice of a matrix or tensor.
Definition: set_slice.hpp:56