OpenKalman
pattern_adapter.hpp
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2024-2025 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 
11 #ifndef OPENKALMAN_PATTERN_ADAPTER_HPP
12 #define OPENKALMAN_PATTERN_ADAPTER_HPP
13 
14 #include "coordinates/coordinates.hpp"
17 #include "linear-algebra/adapters/internal/AdapterBase.hpp"
23 
24 namespace OpenKalman
25 {
30 #ifdef __cpp_concepts
31  template<indexible Nested, pattern_collection_for<Nested> PatternCollection>
32 #else
33  template<typename Nested, typename PatternCollection>
34 #endif
35  struct pattern_adapter : internal::AdapterBase<pattern_adapter<Nested, PatternCollection>, Nested>
36  {
37  private:
38 
39 #ifndef __cpp_concepts
40  static_assert(pattern_collection_for<PatternCollection, Nested>);
41 #endif
42 
44 
45  public:
46 
50  constexpr pattern_adapter() = default;
51 
52 
56 #ifdef __cpp_concepts
57  template<indexible Arg, coordinates::pattern_collection P> requires
58  std::constructible_from<Nested, Arg&&> and
59  std::constructible_from<PatternCollection, P&&>
60 #else
61  template<typename Arg, typename P, std::enable_if_t<
62  stdex::constructible_from<Nested, Arg&&> and
63  stdex::constructible_from<PatternCollection, P&&>, int> = 0>
64 #endif
65  constexpr
66  pattern_adapter(Arg&& arg, P&& p) : Base {std::forward<Arg>(arg)}, patt_ {std::forward<P>(p)} {}
67 
68 
72 #ifdef __cpp_concepts
73  template<indexible Arg, coordinates::pattern_collection P> requires
74  std::constructible_from<Nested, Arg&&> and
75  std::default_initializable<PatternCollection>
76 #else
77  template<typename Arg, typename P, std::enable_if_t<
78  stdex::constructible_from<Nested, Arg&&> and
79  stdex::default_initializable<PatternCollection>, int> = 0>
80 #endif
81  constexpr
82  pattern_adapter(Arg&& arg) : Base {std::forward<Arg>(arg)} {}
83 
84 
88 #ifdef __cpp_concepts
89  template<typename N, typename P> requires
90  std::constructible_from<Nested, const N&> and
91  std::constructible_from<PatternCollection, P&&>
92 #else
93  template<typename N, typename P, std::enable_if_t<
94  stdex::constructible_from<Nested, const N&> and
95  stdex::constructible_from<PatternCollection, P&&>, int> = 0>
96 #endif
97  constexpr pattern_adapter(const pattern_adapter<N, P>& arg, P&& p)
98  : Base {arg.nested_object()}, patt_ {std::forward<P>(p)} {}
99 
100 
104 #ifdef __cpp_concepts
105  template<typename N, typename P> requires
106  std::constructible_from<Nested, N&&> and
107  std::constructible_from<PatternCollection, P&&>
108 #else
109  template<typename N, typename P, std::enable_if_t<
110  stdex::constructible_from<Nested, N&&> and
111  stdex::constructible_from<PatternCollection, P&&>, int> = 0>
112 #endif
113  constexpr pattern_adapter(pattern_adapter<N, P>&& arg, P&& p)
114  : Base {std::move(arg).nested_object()}, patt_ {std::forward<P>(p)} {}
115 
116 
120 #ifdef __cpp_explicit_this_parameter
121  template<typename Self>
122  constexpr decltype(auto) pattern_collection(this Self&& self) { return std::forward<Self>(self).patt_; }
123 #else
124  constexpr PatternCollection& pattern_collection() & { return patt_; }
125 
127  constexpr const PatternCollection& pattern_collection() const & { return patt_; }
128 
130  constexpr PatternCollection&& pattern_collection() && { return std::move(*this).patt_; }
131 
133  constexpr const PatternCollection&& pattern_collection() const && { return std::move(*this).patt_; }
134 #endif
135 
136 
137  private:
138 
139  PatternCollection patt_;
140 
141  };
142 
143 
147 #ifdef __cpp_concepts
148  template<indexible Arg, pattern_collection_for<Arg> P>
149 #else
150  template<typename Arg, typename P, std::enable_if_t<indexible<Arg> and pattern_collection_for<P, Arg>, int> = 0>
151 #endif
153 
154 
155  namespace interface
156  {
160  template<typename Nested, typename PatternCollection>
161  struct object_traits<pattern_adapter<Nested, PatternCollection>>
162  {
163  private:
164 
166 
167  public:
168 
169  static constexpr auto
170  get_mdspan = [](auto&& t) -> decltype(auto)
171  { return OpenKalman::get_mdspan(std::forward<decltype(t)>(t).nested_object()); };
172 
173 
174  static constexpr auto
175  get_pattern_collection = [](auto&& t) -> decltype(auto)
176  { return std::forward<decltype(t)>(t).pattern_collection(); };
177 
178 
179  static constexpr triangle_type
180  triangle_type_value = triangle_type_of_v<Nested>;
181 
182 
183 #ifdef __cpp_concepts
184  static constexpr auto
185  get_constant = [](get_constant_defined_for auto&& t)
186 #else
187  template<bool Enable = true, std::enable_if_t<Enable and get_constant_defined_for<Nested>, int> = 0>
188  static constexpr auto
189  get_constant = [](auto&& t)
190 #endif
191  { return NestedTraits::get_constant(std::forward<decltype(t)>(t).nested_object()); };
192 
193 
194  static constexpr auto
195  nested_object = [](auto&& t) -> decltype(auto)
196  { return std::forward<decltype(t)>(t).nested_object(); };
197 
198 
199  template<applicability b>
200  static constexpr bool
201  is_square = square_shaped<Nested, b>;
202 
203 
204  static constexpr bool
205  is_triangular_adapter = false;
206 
207 
208  static constexpr bool is_hermitian = hermitian_matrix<Nested>;
209 
210 
211  static constexpr HermitianAdapterType
212  hermitian_adapter_type = hermitian_adapter_type_of_v<Nested>;
213 
214  };
215 
216 
220  template<typename Nested, typename PatternCollection>
221  struct library_interface<pattern_adapter<Nested, PatternCollection>>
222  {
223  private:
224 
226 
227  template<typename T, typename Arg>
228  static constexpr auto
229  make_adapter(T&& t, Arg&& arg)
230  {
231  return std::apply([](auto&& a, auto&&...vs){
232  return attach_pattern(std::forward<decltype(a)>(a), std::forward<decltype(vs)>(vs)...);
233  }, std::tuple_cat(std::forward_as_tuple(std::forward<Arg>(arg)), std::forward<T>(t).my_descriptors));
234  }
235 
236  public:
237 
238  template<typename Derived>
239  using library_base = internal::library_base_t<Derived, Nested>;
240 
241 
242 #ifdef __cpp_concepts
243  static constexpr auto
244  copy_from = []<typename T, typename Other> requires copy_from_defined_for<Nested&, Other&&> (T& t, Other&& other)
245 #else
246  static constexpr auto
247  copy_from = [](auto& t, auto&& other) -> std::enable_if_t<copy_from_defined_for<Nested&, decltype(other)>>
248 #endif
249  { NestedInterface::copy_from(t.nested_object(), std::forward<decltype(other)>(other)); };
250 
251 
252  /*#ifdef __cpp_lib_ranges
253  template<indexible Arg, std::ranges::input_range Indices> requires values::index<std::ranges::range_value_t<Indices>> and
254  interface::get_component_defined_for<Nested, nested_object_of_t<Arg&&>, const Indices&>
255  static constexpr values::scalar decltype(auto)
256  #else
257  template<typename Arg, typename Indices, std::enable_if_t<
258  interface::get_component_defined_for<Nested, typename nested_object_of<Arg&&>::type, const Indices&>, int> = 0>
259  static constexpr decltype(auto)
260  #endif
261  get_component(Arg&& arg, const Indices& indices)
262  {
263  return NestedInterface::get_component(nested_object(std::forward<Arg>(arg)), indices);
264  }
265 
266 
267  #ifdef __cpp_lib_ranges
268  template<indexible Arg, std::ranges::input_range Indices> requires values::index<std::ranges::range_value_t<Indices>> and
269  interface::set_component_defined_for<Nested, nested_object_of_t<Arg&&>, const scalar_type_of_t<Arg>&, const Indices&>
270  #else
271  template<typename Arg, typename Indices, std::enable_if_t<
272  interface::set_component_defined_for<Nested, typename nested_object_of<Arg&&>::type, const typename scalar_type_of<Arg>::type&, const Indices&>, int> = 0>
273  #endif
274  static constexpr void
275  set_component(Arg& arg, const scalar_type_of_t<Arg>& s, const Indices& indices)
276  {
277  NestedInterface::set_component(nested_object(arg), s, indices);
278  }
279 
280 
281  #ifdef __cpp_concepts
282  template<typename Arg> requires interface::to_native_matrix_defined_for<Nested, nested_object_of_t<Arg&&>>
283  #else
284  template<typename Arg, std::enable_if_t<interface::to_native_matrix_defined_for<Nested, nested_object_of_t<Arg&&>>, int> = 0>
285  #endif
286  static decltype(auto)
287  to_native_matrix(Arg&& arg)
288  {
289  return make_adapter(std::forward<Arg>(arg), NestedInterface::to_native_matrix(nested_object(std::forward<Arg>(arg))));
290  }
291 
292 
293  #ifdef __cpp_concepts
294  template<data_layout layout, typename Scalar, typename D> requires
295  interface::make_default_defined_for<Nested, layout, Scalar, D&&>
296  #else
297  template<data_layout layout, typename Scalar, typename D, std::enable_if_t<
298  interface::make_default_defined_for<Nested, layout, Scalar, D&&>, int> = 0>
299  #endif
300  static auto
301  make_default(D&& d)
302  {
303  return NestedInterface::template make_default<layout, Scalar>(std::forward<D>(d));
304  }
305 
306 
307  #ifdef __cpp_concepts
308  template<data_layout layout, typename Arg, typename...Scalars> requires
309  interface::fill_components_defined_for<Nested, layout, nested_object_of_t<Arg&>, Scalars...>
310  #else
311  template<data_layout layout, typename Arg, typename...Scalars, std::enable_if_t<
312  interface::fill_components_defined_for<Nested, layout, typename nested_object_of<Arg&>::type, Scalars...>, int> = 0>
313  #endif
314  static void
315  fill_components(Arg& arg, const Scalars...scalars)
316  {
317  NestedInterface::template fill_components<layout>(nested_object(arg), scalars...);
318  }
319 
320 
321  #ifdef __cpp_concepts
322  template<typename C, typename D> requires interface::make_constant_defined_for<Nested, C&&, D&&>
323  #else
324  template<typename C, typename D, std::enable_if_t<interface::make_constant_defined_for<Nested, C&&, D&&>, int> = 0>
325  #endif
326  static constexpr auto
327  make_constant(C&& c, D&& d)
328  {
329  return NestedInterface::make_constant(std::forward<C>(c), std::forward<D>(d));
330  }
331 
332 
333  #ifdef __cpp_concepts
334  template<typename Scalar, typename D> requires interface::make_identity_matrix_defined_for<Nested, Scalar, D&&>
335  #else
336  template<typename Scalar, typename D, std::enable_if_t<interface::make_identity_matrix_defined_for<Nested, Scalar, D&&>, int> = 0>
337  #endif
338  static constexpr auto
339  make_identity_matrix(D&& d)
340  {
341  return NestedInterface::make_identity_matrix(std::forward<D>(d));
342  }
343 
344 
345  #ifdef __cpp_concepts
346  template<triangle_type t, indexible Arg> requires
347  interface::make_triangular_matrix_defined_for<Nested, t, nested_object_of_t<Arg&&>>
348  static constexpr triangular_matrix<t> auto
349  #else
350  template<triangle_type t, typename Arg, std::enable_if_t<
351  interface::make_triangular_matrix_defined_for<Nested, t, typename nested_object_of<Arg&&>::type>, int> = 0>
352  static constexpr auto
353  #endif
354  make_triangular_matrix(Arg&& arg)
355  {
356  return make_adapter(std::forward<Arg>(arg), (NestedInterface::template make_triangular_matrix<t>(nested_object(std::forward<Arg>(arg)))));
357  }
358 
359 
360  #ifdef __cpp_concepts
361  template<HermitianAdapterType t, indexible Arg> requires
362  interface::make_hermitian_adapter_defined_for<Nested, t, nested_object_of_t<Arg&&>>
363  static constexpr hermitian_matrix auto
364  #else
365  template<HermitianAdapterType t, typename Arg, std::enable_if_t<
366  make_hermitian_adapter_defined_for<Nested, t, typename nested_object_of<Arg&>::type>, int> = 0>
367  static constexpr auto
368  #endif
369  make_hermitian_adapter(Arg&& arg)
370  {
371  return make_adapter(std::forward<Arg>(arg), NestedInterface::template make_hermitian_adapter<t>(nested_object(std::forward<Arg>(arg))));
372  }
373 
374  private:
375 
376  template<typename Arg, typename BeginTup, typename SizeTup, std::size_t...Ix>
377  static decltype(auto)
378  get_slice_impl(Arg&& arg, const BeginTup& begin_tup, const SizeTup& size_tup, std::index_sequence<Ix...>)
379  {
380  return attach_pattern(NestedInterface::get_slice(nested_object(std::forward<Arg>(arg)), begin_tup, size_tup),
381  std::tuple {coordinates::get_slice<scalar_type_of_t<Arg>>(OpenKalman::get_pattern_collection(arg, Ix), std::get<Ix>(begin_tup), std::get<Ix>(size_tup))...});
382  }
383 
384  public:
385 
386  #ifdef __cpp_concepts
387  template<typename Arg, typename...Begin, typename...Size> requires
388  interface::get_slice_defined_for<Nested, nested_object_of_t<Arg&&>, const std::tuple<Begin...>&, const std::tuple<Size...>&>
389  #else
390  template<typename Arg, typename...Begin, typename...Size, std::enable_if_t<
391  interface::get_slice_defined_for<Nested, typename nested_object_of<Arg&&>::type, const std::tuple<Begin...>&, const std::tuple<Size...>&>, int> = 0>
392  #endif
393  static decltype(auto)
394  get_slice(Arg&& arg, const std::tuple<Begin...>& begin_tup, const std::tuple<Size...>& size_tup)
395  {
396  return get_slice_impl(std::forward<Arg>(arg), begin_tup, size_tup, std::index_sequence_for<Begin...>{});
397  };
398 
399 
400  #ifdef __cpp_concepts
401  template<typename Arg, typename Block, typename...Begin> requires
402  interface::set_slice_defined_for<Arg, nested_object_of_t<Arg&>, Block&&, const Begin&...>
403  #else
404  template<typename Arg, typename Block, typename...Begin, std::enable_if_t<
405  interface::set_slice_defined_for<Arg, typename nested_object_of<Arg&>::type, Block&&, const Begin&...>, int> = 0>
406  #endif
407  static void
408  set_slice(Arg& arg, Block&& block, const Begin&...begin)
409  {
410  NestedInterface::set_slice(nested_object(arg), std::forward<Block>(block), begin...);
411  };
412 
413 
414  #ifdef __cpp_concepts
415  template<triangle_type t, typename A, typename B> requires
416  interface::set_triangle_defined_for<Nested, t, nested_object_of_t<A&&>, B&&>
417  #else
418  template<triangle_type t, typename A, typename B, std::enable_if_t<
419  interface::set_triangle_defined_for<Nested, t, typename nested_object_of<A&&>::type, B&&>, int> = 0>
420  #endif
421  static void
422  set_triangle(A&& a, B&& b)
423  {
424  NestedInterface::template set_triangle<t>(nested_object(std::forward<A>(a)), std::forward<B>(b));
425  }
426 
427 
428  #ifdef __cpp_concepts
429  template<typename Arg> requires
430  interface::to_diagonal_defined_for<Nested, nested_object_of_t<Arg&&>>
431  static constexpr diagonal_matrix auto
432  #else
433  template<typename Arg, std::enable_if_t<
434  interface::to_diagonal_defined_for<Nested, typename nested_object_of<Arg&&>::type>, int> = 0>
435  static constexpr auto
436  #endif
437  to_diagonal(Arg&& arg)
438  {
439  return std::apply([](auto&& a, auto&& v, auto&&...vs){
440  return attach_pattern(
441  std::forward<decltype(a)>(a),
442  std::forward<decltype(v)>(v),
443  std::forward<decltype(v)>(v),
444  std::forward<decltype(vs)>(vs)...);
445  }, std::tuple_cat(
446  std::forward_as_tuple(NestedInterface::to_diagonal(nested_object(std::forward<Arg>(arg)))),
447  std::forward<Arg>(arg).my_descriptors),
448  std::tuple{coordinates::Axis{}});
449  }
450 
451  private:
452 
453  template<typename Arg, typename V0, typename V1, typename...Vs>
454  static constexpr decltype(auto)
455  diagonal_of_impl(Arg&& arg, V0&& v0, V1&& v1, const Vs&...vs)
456  {
457  auto d0 = internal::smallest_pattern<scalar_type_of_t<Arg>>(std::forward<V0>(v0), std::forward<V1>(v1));
458  return attach_pattern(std::forward<Arg>(arg), d0, vs...);
459  }
460 
461  public:
462 
463  #ifdef __cpp_concepts
464  template<indexible Arg> requires (diagonal_matrix<Nested> and internal::has_nested_vector<Nested>) or
465  (diagonal_matrix<Nested> and internal::has_nested_vector<Nested, 1> and
466  interface::transpose_defined_for<Nested, decltype(nested_object(nested_object(std::declval<Arg>())))>) or
467  interface::diagonal_of_defined_for<Nested, nested_object_of_t<Arg&&>>
468  static constexpr vector auto
469  #else
470  template<typename Arg, std::enable_if_t<(diagonal_matrix<Nested> and internal::has_nested_vector<Nested>) or
471  (diagonal_matrix<Nested> and internal::has_nested_vector<Nested, 1> and
472  interface::transpose_defined_for<Nested, decltype(nested_object(nested_object(std::declval<Arg>())))>) or
473  interface::diagonal_of_defined_for<Nested, typename nested_object_of<Arg&&>::type>, int> = 0>
474  static constexpr auto
475  #endif
476  diagonal_of(Arg&& arg)
477  {
478  if constexpr (diagonal_matrix<Nested> and internal::has_nested_vector<Nested>)
479  return diagonal_of_impl(nested_object(nested_object(std::forward<Arg>(arg))));
480  else if constexpr (diagonal_matrix<Nested> and internal::has_nested_vector<Nested, 1> and
481  interface::transpose_defined_for<Nested, decltype(nested_object(nested_object(std::declval<Arg>())))>)
482  return diagonal_of_impl(NestedInterface::transpose(nested_object(nested_object(std::forward<Arg>(arg)))));
483  else
484  return diagonal_of_impl(NestedInterface::diagonal_of(nested_object(std::forward<Arg>(arg))),
485  std::tuple_cat(all_vector_space_descriptors(std::forward<Arg>(arg)), std::tuple{coordinates::Axis{}, coordinates::Axis{}}));
486  }
487 
488  private:
489 
490  template<std::size_t Ix, typename Arg, typename Factors_tup>
491  static constexpr auto broadcast_for_index(const Arg& arg, const Factors_tup& factors_tup)
492  {
493  constexpr auto N = collections::size_of_v<Factors_tup>;
494  if constexpr (Ix < N)
495  return get_pattern_collection<Ix>(arg) * std::get<Ix>(factors_tup);
496  else
497  return coordinates::Axis{};
498  }
499 
500 
501  template<typename Arg, std::size_t...Is, typename Factors_tup>
502  static constexpr auto broadcast_impl(Arg&& arg, std::index_sequence<Is...>, const Factors_tup& factors_tup)
503  {
504  constexpr auto N = collections::size_of_v<Factors_tup>;
505  return attach_pattern(std::forward<Arg>(arg), broadcast_for_index<Is>(arg, factors_tup)...);
506  }
507 
508  public:
509 
510  #ifdef __cpp_concepts
511  template<indexible Arg, values::index...Factors> requires
512  interface::broadcast_defined_for<Nested, nested_object_of_t<Arg&&>, const Factors&...>
513  static indexible auto
514  #else
515  template<typename Arg, typename...Factors, std::enable_if_t<
516  interface::broadcast_defined_for<Nested, typename nested_object_of<Arg&&>::type, const Factors&...>, int> = 0>
517  static auto
518  #endif
519  broadcast(Arg&& arg, const Factors&...factors)
520  {
521  auto&& ret = NestedInterface::broadcast(nested_object(std::forward<Arg>(arg)), factors...);
522  using Ret = decltype(ret);
523  auto seq = std::make_index_sequence<std::max(index_count_v<Arg>, sizeof...(factors))>{};
524  return broadcast_impl(std::forward<Ret>(ret), seq, std::forward_as_tuple(factors...));
525  }
526 
527 
528  #ifdef __cpp_concepts
529  template<coordinates::pattern...Vs, typename Operation> requires
530  interface::n_ary_operation_defined_for<NestedInterface, const std::tuple<Vs...>&, Operation&&>
531  static indexible auto
532  #else
533  template<typename...Vs, typename Operation, std::enable_if_t<
534  interface::n_ary_operation_defined_for<NestedInterface, const std::tuple<Vs...>&, Operation&&>, int> = 0>
535  static auto
536  #endif
537  n_ary_operation(const std::tuple<Vs...>& d_tup, Operation&& op)
538  {
539  return NestedInterface::n_ary_operation(d_tup, std::forward<Operation>(op));
540  }
541 
542 
543  #ifdef __cpp_concepts
544  template<coordinates::pattern...Vs, typename Operation, indexible Arg, indexible...Args> requires
545  interface::n_ary_operation_defined_for<Nested, const std::tuple<Vs...>&, Operation&&, nested_object_of_t<Arg&&>, Args...>
546  static indexible auto
547  #else
548  template<typename...Vs, typename Operation, typename Arg, typename...Args, std::enable_if_t<
549  interface::n_ary_operation_defined_for<Nested, const std::tuple<Vs...>&, Operation&&, typename nested_object_of<Arg&&>::type, Args...>, int> = 0>
550  static auto
551  #endif
552  n_ary_operation(const std::tuple<Vs...>& d_tup, Operation&& op, Arg&& arg, Args&&...args)
553  {
554  return NestedInterface::n_ary_operation(d_tup, std::forward<Operation>(op), nested_object(std::forward<Arg>(arg)), std::forward<Args>(args)...);
555  }
556 
557  private:
558 
559  template<std::size_t...indices, typename Arg, typename...Vs, std::size_t...Ix>
560  static constexpr decltype(auto)
561  reduce_impl(Arg&& arg, const std::tuple<Vs...>& tup_vs, std::index_sequence<Ix...> seq)
562  {
563  return attach_pattern(std::forward<Arg>(arg),
564  ([]{ constexpr auto I = Ix; return ((I == indices) or ...); } ?
565  uniform_pattern_component_of_t<vector_space_descriptor_of_t<Vs, Ix>>{} :
566  std::get<Ix>(tup_vs))...);
567  }
568 
569  public:
570 
571  #ifdef __cpp_concepts
572  template<std::size_t...indices, typename BinaryFunction, indexible Arg> requires
573  interface::reduce_defined_for<Nested, BinaryFunction&&, nested_object_of_t<Arg&&>, indices...>
574  #else
575  template<std::size_t...indices, typename BinaryFunction, typename Arg, std::enable_if_t<
576  interface::reduce_defined_for<Nested, BinaryFunction&&, typename nested_object_of<Arg&&>::type, indices...>, int> = 0>
577  #endif
578  static constexpr auto
579  reduce(BinaryFunction&& op, Arg&& arg)
580  {
581  return reduce_impl<indices...>(
582  NestedInterface::template reduce<indices...>(std::forward<BinaryFunction>(op), nested_object(std::forward<Arg>(arg))),
583  std::forward<Arg>(arg).my_descriptors,
584  std::index_sequence_for<Ds...>{});
585  }
586 
587 
588  #ifdef __cpp_concepts
589  template<indexible Arg> requires
590  interface::to_euclidean_defined_for<Nested, Arg&&> or
591  interface::to_euclidean_defined_for<Nested, nested_object_of_t<Arg&&>>
592  static constexpr indexible auto
593  #else
594  template<typename Arg, std::enable_if_t<
595  interface::to_euclidean_defined_for<Nested, Arg&&> or
596  interface::to_euclidean_defined_for<Nested, typename nested_object_of<Arg&&>::type>, int> = 0>
597  static constexpr auto
598  #endif
599  to_euclidean(Arg&& arg)
600  {
601  if constexpr (interface::to_euclidean_defined_for<Nested, Arg&&>)
602  return NestedInterface::to_euclidean(std::forward<Arg>(arg));
603  else
604  return NestedInterface::to_euclidean(nested_object(std::forward<Arg>(arg)));
605  }
606 
607 
608  #ifdef __cpp_concepts
609  template<indexible Arg, coordinates::pattern V> requires
610  interface::from_euclidean_defined_for<Nested, Arg&&, const V&> or
611  interface::from_euclidean_defined_for<Nested, nested_object_of_t<Arg&&>, const V&>
612  static constexpr indexible auto
613  #else
614  template<typename Arg, typename V, std::enable_if_t<
615  interface::from_euclidean_defined_for<Nested, Arg&&, const V&> or
616  interface::from_euclidean_defined_for<Nested, typename nested_object_of<Arg&&>::type, const V&>, int> = 0>
617  static constexpr auto
618  #endif
619  from_euclidean(Arg&& arg, const V& v)
620  {
621  if constexpr (interface::from_euclidean_defined_for<Nested, Arg&&, const V&>)
622  return NestedInterface::from_euclidean(std::forward<Arg>(arg), v);
623  else
624  return NestedInterface::from_euclidean(nested_object(std::forward<Arg>(arg)), v);
625  }
626 
627 
628  #ifdef __cpp_concepts
629  template<indexible Arg> requires
630  interface::wrap_angles_defined_for<Nested, Arg&&> or
631  interface::wrap_angles_defined_for<Nested, nested_object_of_t<Arg&&>>
632  static constexpr indexible auto
633  #else
634  template<typename Arg, std::enable_if_t<
635  interface::wrap_angles_defined_for<Nested, Arg&&> or
636  interface::wrap_angles_defined_for<Nested, typename nested_object_of<Arg&&>::type>, int> = 0>
637  static constexpr auto
638  #endif
639  wrap_angles(Arg&& arg)
640  {
641  if constexpr (interface::wrap_angles_defined_for<Nested, Arg&&>)
642  return NestedInterface::wrap_angles(std::forward<Arg>(arg));
643  else
644  return NestedInterface::wrap_angles(nested_object(std::forward<Arg>(arg)));
645  }
646 
647 
648  #ifdef __cpp_concepts
649  template<indexible Arg> requires
650  interface::conjugate_defined_for<Nested, Arg&&> or
651  interface::conjugate_defined_for<Nested, nested_object_of_t<Arg&&>>
652  static constexpr indexible auto
653  #else
654  template<typename Arg, std::enable_if_t<
655  interface::conjugate_defined_for<Nested, Arg&&> or
656  interface::conjugate_defined_for<Nested, typename nested_object_of<Arg&&>::type>, int> = 0>
657  static constexpr auto
658  #endif
659  conjugate(Arg&& arg)
660  {
661  if constexpr (interface::conjugate_defined_for<Nested, Arg&&>)
662  {
663  return NestedInterface::conjugate(std::forward<Arg>(arg));
664  }
665  else
666  {
667  auto&& conj = NestedInterface::conjugate(nested_object(std::forward<Arg>(arg)));
668  return internal::make_fixed_size_adapter_like<Arg>(std::forward<decltype(conj)>(conj));
669  }
670  }
671 
672 
673  #ifdef __cpp_concepts
674  template<indexible Arg> requires
675  interface::transpose_defined_for<Nested, Arg&&> or
676  interface::transpose_defined_for<Nested, nested_object_of_t<Arg&&>>
677  static constexpr indexible auto
678  #else
679  template<typename Arg, std::enable_if_t<
680  interface::transpose_defined_for<Nested, Arg&&> or
681  interface::transpose_defined_for<Nested, typename nested_object_of<Arg&&>::type>, int> = 0>
682  static constexpr auto
683  #endif
684  transpose(Arg&& arg)
685  {
686  if constexpr (interface::transpose_defined_for<Nested, Arg&&>)
687  {
688  return NestedInterface::transpose(std::forward<Arg>(arg));
689  }
690  else
691  {
692  return internal::make_fixed_size_adapter<vector_space_descriptor_of_t<Arg, 1>, vector_space_descriptor_of_t<Arg, 0>>(
693  NestedInterface::transpose(nested_object(std::forward<Arg>(arg))));
694  }
695  }
696 
697 
698  #ifdef __cpp_concepts
699  template<indexible Arg> requires
700  interface::adjoint_defined_for<Nested, Arg&&> or
701  interface::adjoint_defined_for<Nested, nested_object_of_t<Arg&&>>
702  static constexpr indexible auto
703  #else
704  template<typename Arg, std::enable_if_t<
705  interface::adjoint_defined_for<Nested, Arg&&> or
706  interface::adjoint_defined_for<Nested, typename nested_object_of<Arg&&>::type>, int> = 0>
707  static constexpr auto
708  #endif
709  adjoint(Arg&& arg)
710  {
711  if constexpr (interface::adjoint_defined_for<Nested, Arg&&>)
712  {
713  return NestedInterface::adjoint(std::forward<Arg>(arg));
714  }
715  else
716  {
717  return internal::make_fixed_size_adapter<vector_space_descriptor_of_t<Arg, 1>, vector_space_descriptor_of_t<Arg, 0>>(
718  NestedInterface::adjoint(nested_object(std::forward<Arg>(arg))));
719  }
720  }
721 
722 
723  #ifdef __cpp_concepts
724  template<indexible Arg> requires
725  interface::determinant_defined_for<Nested, Arg&&> or
726  interface::determinant_defined_for<Nested, nested_object_of_t<Arg&&>>
727  static constexpr std::convertible_to<scalar_type_of_t<Arg>> auto
728  #else
729  template<typename Arg, std::enable_if_t<
730  interface::determinant_defined_for<Nested, Arg&&> or
731  interface::determinant_defined_for<Nested, typename nested_object_of<Arg&&>::type>, int> = 0>
732  static constexpr auto
733  #endif
734  determinant(Arg&& arg)
735  {
736  if constexpr (interface::determinant_defined_for<Nested, Arg&&>)
737  {
738  return NestedInterface::determinant(std::forward<Arg>(arg));
739  }
740  else
741  {
742  return NestedInterface::determinant(nested_object(std::forward<Arg>(arg)));
743  }
744  }
745 
746 
747  #ifdef __cpp_concepts
748  template<typename Arg, typename...Args> requires
749  interface::sum_defined_for<Nested, Arg&&, Args&&...> or
750  interface::sum_defined_for<Nested, nested_object_of_t<Arg&&>, Args&&...>
751  #else
752  template<typename Arg, typename...Args, std::enable_if_t<
753  interface::sum_defined_for<Nested, Arg&&, Args&&...> or
754  interface::sum_defined_for<Nested, typename nested_object_of<Arg&&>::type, Args&&...>, int> = 0>
755  #endif
756  static auto
757  sum(Arg&& arg, Args&&...args)
758  {
759  if constexpr (interface::sum_defined_for<Nested, Arg&&, Args&&...>)
760  {
761  return NestedInterface::sum(std::forward<Arg>(arg), std::forward<Args>(args)...);
762  }
763  else
764  {
765  return NestedInterface::sum(nested_object(std::forward<Arg>(arg)), std::forward<Args>(args)...);
766  }
767  }
768 
769 
770  #ifdef __cpp_concepts
771  template<typename A, typename B> requires
772  interface::contract_defined_for<Nested, A&&, B&&> or
773  interface::contract_defined_for<Nested, nested_object_of_t<A&&>, B&&>
774  #else
775  template<typename A, typename B, std::enable_if_t<
776  interface::contract_defined_for<Nested, A&&, B&&> or
777  interface::contract_defined_for<Nested, typename nested_object_of<A&&>::type, B&&>, int> = 0>
778  #endif
779  static auto
780  contract(A&& a, B&& b)
781  {
782  if constexpr (interface::contract_defined_for<Nested, A&&, B&&>)
783  {
784  return NestedInterface::contract(std::forward<A>(a), std::forward<B>(b));
785  }
786  else
787  {
788  return internal::make_fixed_size_adapter<vector_space_descriptor_of_t<A, 0>, vector_space_descriptor_of_t<B, 1>>(
789  NestedInterface::contract(nested_object(std::forward<A>(a)), std::forward<B>(b)));
790  }
791  }
792 
793 
794  #ifdef __cpp_concepts
795  template<bool on_the_right, typename A, typename B> requires
796  interface::contract_in_place_defined_for<Nested, on_the_right, A&&, B&&> or
797  interface::contract_in_place_defined_for<Nested, on_the_right, nested_object_of_t<A&&>, B&&>
798  #else
799  template<bool on_the_right, typename A, typename B, std::enable_if_t<
800  interface::contract_in_place_defined_for<Nested, on_the_right, A&&, B&&> or
801  interface::contract_in_place_defined_for<Nested, on_the_right, typename nested_object_of<A&&>::type, B&&>, int> = 0>
802  #endif
803  static decltype(auto)
804  contract_in_place(A&& a, B&& b)
805  {
806  if constexpr (interface::contract_in_place_defined_for<Nested, on_the_right, A&&, B&&>)
807  {
808  return NestedInterface::template contract_in_place<on_the_right>(std::forward<A>(a), std::forward<B>(b));
809  }
810  else
811  {
812  auto&& ret = NestedInterface::template contract_in_place<on_the_right>(nested_object(std::forward<A>(a)), std::forward<B>(b));
813  using Ret = decltype(ret);
814  if constexpr (std::is_lvalue_reference_v<Ret> and std::is_same_v<Ret, nested_object_of_t<A&&>>)
815  {
816  return std::forward<A>(a);
817  }
818  else if constexpr (on_the_right)
819  {
820  return internal::make_fixed_size_adapter<vector_space_descriptor_of_t<A, 0>, vector_space_descriptor_of_t<B, 1>>(std::forward<Ret>(ret));
821  }
822  else
823  {
824  return internal::make_fixed_size_adapter<vector_space_descriptor_of_t<B, 0>, vector_space_descriptor_of_t<A, 1>>(std::forward<Ret>(ret));
825  }
826  }
827  }
828 
829 
830  #ifdef __cpp_concepts
831  template<triangle_type tri, indexible Arg> requires
832  interface::cholesky_factor_defined_for<Nested, tri, Arg&&> or
833  interface::cholesky_factor_defined_for<Nested, tri, nested_object_of_t<Arg&&>>
834  static constexpr triangular_matrix<tri> auto
835  #else
836  template<triangle_type tri, typename Arg, std::enable_if_t<
837  interface::cholesky_factor_defined_for<Nested, tri, Arg&&> or
838  interface::cholesky_factor_defined_for<Nested, tri, typename nested_object_of<Arg&&>::type>, int> = 0>
839  static constexpr auto
840  #endif
841  cholesky_factor(Arg&& arg)
842  {
843  if constexpr (interface::cholesky_factor_defined_for<Nested, tri, Arg&&>)
844  {
845  return NestedInterface::template cholesky_factor<tri>(std::forward<Arg>(arg));
846  }
847  else
848  {
849  auto tri = NestedInterface::template cholesky_factor<tri>(nested_object(std::forward<Arg>(arg)));
850  return internal::make_fixed_square_adapter_like(std::move(tri));
851  }
852  }
853 
854 
855  #ifdef __cpp_concepts
856  template<HermitianAdapterType significant_triangle, indexible A, indexible U> requires
857  interface::rank_update_self_adjoint_defined_for<Nested, significant_triangle, A&&, U&&, const scalar_type_of_t<A>&> or
858  interface::rank_update_self_adjoint_defined_for<Nested, significant_triangle, nested_object_of_t<A&&>, U&&, const scalar_type_of_t<A>&>
859  static constexpr hermitian_matrix auto
860  #else
861  template<HermitianAdapterType significant_triangle, typename A, typename U, std::enable_if_t<
862  interface::rank_update_self_adjoint_defined_for<Nested, significant_triangle, A&&, U&&, const typename scalar_type_of<A>::type&> or
863  interface::rank_update_self_adjoint_defined_for<Nested, significant_triangle, typename nested_object_of<A&&>::type, U&&, const typename scalar_type_of<A>::type&>, int> = 0>
864  static constexpr auto
865  #endif
866  rank_update_hermitian(A&& a, U&& u, const scalar_type_of_t<A>& alpha)
867  {
868  if constexpr (interface::rank_update_self_adjoint_defined_for<Nested, significant_triangle, A&&, U&&, const scalar_type_of_t<A>&>)
869  {
870  return NestedInterface::template rank_update_hermitian<significant_triangle>(std::forward<A>(a), std::forward<U>(u), alpha);
871  }
872  else
873  {
874  auto tri = NestedInterface::template rank_update_hermitian<significant_triangle>(nested_object(std::forward<A>(a), std::forward<U>(u), alpha));
875  return internal::make_fixed_square_adapter_like(std::move(tri));
876  }
877  }
878 
879 
880  #ifdef __cpp_concepts
881  template<triangle_type tri, indexible A, indexible U> requires
882  interface::rank_update_triangular_defined_for<Nested, tri, A&&, U&&, const scalar_type_of_t<A>&> or
883  interface::rank_update_triangular_defined_for<Nested, tri, nested_object_of_t<A&&>, U&&, const scalar_type_of_t<A>&>
884  static constexpr triangular_matrix<tri> auto
885  #else
886  template<triangle_type tri, typename A, typename U, std::enable_if_t<
887  interface::rank_update_triangular_defined_for<Nested, tri, A&&, U&&, const typename scalar_type_of<A>::type&> or
888  interface::rank_update_triangular_defined_for<Nested, tri, typename nested_object_of<A&&>::type, U&&, const typename scalar_type_of<A>::type&>, int> = 0>
889  static constexpr auto
890  #endif
891  rank_update_triangular(A&& a, U&& u, const scalar_type_of_t<A>& alpha)
892  {
893  if constexpr (interface::rank_update_triangular_defined_for<Nested, tri, A&&, U&&, const scalar_type_of_t<A>&>)
894  {
895  return NestedInterface::template rank_update_triangular<tri>(std::forward<A>(a), std::forward<U>(u), alpha);
896  }
897  else
898  {
899  auto tri = NestedInterface::template rank_update_triangular<tri>(nested_object(std::forward<A>(a), std::forward<U>(u), alpha));
900  return internal::make_fixed_square_adapter_like(std::move(tri));
901  }
902  }
903 
904 
905  #ifdef __cpp_concepts
906  template<bool must_be_unique, bool must_be_exact, typename A, typename B> requires
907  interface::solve_defined_for<Nested, must_be_unique, must_be_exact, A&&, B&&> or
908  interface::solve_defined_for<Nested, must_be_unique, must_be_exact, nested_object_of_t<A&&>, B&&>
909  static compatible_with_vector_space_descriptor_collection<std::tuple<vector_space_descriptor_of_t<A, 1>, vector_space_descriptor_of_t<B, 1>>> auto
910  #else
911  template<bool must_be_unique, bool must_be_exact, typename A, typename B, std::enable_if_t<
912  interface::solve_defined_for<Nested, must_be_unique, must_be_exact, A&&, B&&> or
913  interface::solve_defined_for<Nested, must_be_unique, must_be_exact, typename nested_object_of<A&&>::type, B&&>, int> = 0>
914  static auto
915  #endif
916  solve(A&& a, B&& b)
917  {
918  if constexpr (interface::solve_defined_for<Nested, must_be_unique, must_be_exact, A&&, B&&>)
919  {
920  return NestedInterface::template solve<must_be_unique, must_be_exact>(std::forward<A>(a), std::forward<B>(b));
921  }
922  else
923  {
924  return internal::make_fixed_size_adapter<vector_space_descriptor_of_t<A, 1>, vector_space_descriptor_of_t<B, 1>>(
925  NestedInterface::template solve<must_be_unique, must_be_exact>(nested_object(std::forward<A>(a)), std::forward<B>(b)));
926  }
927  }
928 
929 
930  #ifdef __cpp_concepts
931  template<typename A> requires
932  interface::LQ_decomposition_defined_for<Nested, A&&> or
933  interface::LQ_decomposition_defined_for<Nested, nested_object_of_t<A&&>>
934  #else
935  template<typename A, std::enable_if_t<
936  interface::LQ_decomposition_defined_for<Nested, A&&> or
937  interface::LQ_decomposition_defined_for<Nested, typename nested_object_of<A&&>::type>, int> = 0>
938  #endif
939  static auto
940  LQ_decomposition(A&& a)
941  {
942  if constexpr (interface::LQ_decomposition_defined_for<Nested, A&&>)
943  {
944  return NestedInterface::LQ_decomposition(std::forward<A>(a));
945  }
946  else
947  {
948  auto&& ret = NestedInterface::LQ_decomposition(nested_object(std::forward<A>(a)));
949  using D0 = vector_space_descriptor_of<A, 0>;
950  return internal::make_fixed_square_adapter_like<D0>(std::forward<decltype(ret)>(ret));
951  }
952  }
953 
954 
955  #ifdef __cpp_concepts
956  template<typename A> requires
957  interface::QR_decomposition_defined_for<Nested, A&&> or
958  interface::QR_decomposition_defined_for<Nested, nested_object_of_t<A&&>>
959  #else
960  template<typename A, std::enable_if_t<
961  interface::QR_decomposition_defined_for<Nested, A&&> or
962  interface::QR_decomposition_defined_for<Nested, typename nested_object_of<A&&>::type>, int> = 0>
963  #endif
964  static auto
965  QR_decomposition(A&& a)
966  {
967  if constexpr (interface::QR_decomposition_defined_for<Nested, A&&>)
968  {
969  return NestedInterface::QR_decomposition(std::forward<A>(a));
970  }
971  else
972  {
973  auto&& ret = NestedInterface::QR_decomposition(nested_object(std::forward<A>(a)));
974  using D1 = vector_space_descriptor_of<A, 1>;
975  return internal::make_fixed_square_adapter_like<D1>(std::forward<decltype(ret)>(ret));
976  }
977  }
978  */
979 
980  };
981 
982  }
983 
984 
985 }
986 
987 
988 #endif
constexpr auto attach_pattern(Arg &&arg, P &&p)
Attach a pattern_collection to an indexible object.
Definition: attach_pattern.hpp:36
constexpr auto get_mdspan(T &t)
Get the coordinates::pattern_collection associated with indexible object T.
Definition: get_mdspan.hpp:35
constexpr pattern_adapter(Arg &&arg, P &&p)
Construct from an indexible object and a pattern_collection.
Definition: pattern_adapter.hpp:66
triangle_type
The type of a triangular matrix.
Definition: enumerations.hpp:26
Definition for square_shaped.
decltype(auto) constexpr get_pattern_collection(T &&t)
Get the coordinates::pattern_collection associated with indexible object T.
Definition: get_pattern_collection.hpp:59
HermitianAdapterType
The type of a hermitian adapter, indicating which triangle of the nested matrix is used...
Definition: enumerations.hpp:79
decltype(auto) constexpr copy_from(Dest &&dest, Source &&source)
Copy elements from one object to another.
Definition: copy_from.hpp:59
Definition: AdapterBase.hpp:37
decltype(auto) constexpr apply(F &&f, T &&t)
A generalization of std::apply.
Definition: apply.hpp:49
constexpr const PatternCollection & pattern_collection() const &
Definition: pattern_adapter.hpp:127
Definition for hermitian_adapter_type_of.
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:42
Definition: object_traits.hpp:38
Definition of copy_from function.
constexpr const PatternCollection && pattern_collection() const &&
Definition: pattern_adapter.hpp:133
An adapter that attaches a pattern_collection to an indexible object.
Definition: pattern_adapter.hpp:35
constexpr pattern_adapter(const pattern_adapter< N, P > &arg, P &&p)
Copy construct from another pattern_adapter, attaching a different pattern_collection.
Definition: pattern_adapter.hpp:97
Definition for pattern_collection_for.
constexpr Nested & nested_object() &
Get the nested object.
Definition: AdapterBase.hpp:76
Definition for hermitian_matrix.
Definition for indexible.
Concepts for testing whether object_traits or library_interface definitions exist for a particular ob...
constexpr pattern_adapter()=default
Default constructor.
constexpr pattern_adapter(pattern_adapter< N, P > &&arg, P &&p)
Move construct from another pattern_adapter, attaching a different pattern_collection.
Definition: pattern_adapter.hpp:113
constexpr pattern_adapter(Arg &&arg)
Construct from an indexible object.
Definition: pattern_adapter.hpp:82
constexpr PatternCollection & pattern_collection() &
Get the associated pattern_collection.
Definition: pattern_adapter.hpp:124
constexpr PatternCollection && pattern_collection() &&
Definition: pattern_adapter.hpp:130