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