OpenKalman
FixedSizeAdapter.hpp
Go to the documentation of this file.
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2023-2024 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 
16 #ifndef OPENKALMAN_INTERFACES_FIXEDSIZEADAPTER_HPP
17 #define OPENKALMAN_INTERFACES_FIXEDSIZEADAPTER_HPP
18 
19 
20 namespace OpenKalman::interface
21 {
22  // --------------------------- //
23  // object_traits //
24  // --------------------------- //
25 
26  template<typename NestedObject, typename Descriptors>
27  struct object_traits<internal::FixedSizeAdapter<NestedObject, Descriptors>>
28  {
29  static const bool is_specialized = true;
30 
31  private:
32 
34 
35  public:
36 
37  using scalar_type = scalar_type_of_t<NestedObject>;
38 
39 
40  template<typename Arg>
41  static constexpr auto count_indices(const Arg&)
42  {
43  // Truncate any trailing ℝ¹ dimensions
44  using NewDesc = decltype(OpenKalman::patterns::internal::strip_1D_tail(std::declval<Descriptors>()));
46  }
47 
48 
49  template<typename Arg, typename N>
50  static constexpr auto get_pattern_collection(Arg&& arg, const N& n)
51  {
52  constexpr auto dim = decltype(count_indices(arg))::value;
53  if constexpr (values::fixed<N>)
54  {
55  if constexpr (N::value >= dim)
56  return patterns::Axis{};
59  else
60  return OpenKalman::get_pattern_collection(std::forward<Arg>(arg).nested_object(), n);
61  }
62  else
63  {
64  return OpenKalman::get_pattern_collection(std::forward<Arg>(arg).nested_object(), n);
65  }
66  }
67 
68 
69  template<typename Arg>
70  static decltype(auto) nested_object(Arg&& arg)
71  {
72  return std::forward<Arg>(arg).nested_object();
73  }
74 
75 
76 #ifdef __cpp_concepts
77  template<typename Arg> requires constant_matrix<NestedObject>
78 #else
79  template<typename M = NestedObject, typename Arg, std::enable_if_t<constant_matrix<M>, int> = 0>
80 #endif
81  static constexpr auto get_constant(const Arg& arg)
82  {
83  return constant_value {nested_object(arg)};
84  }
85 
86 
87 #ifdef __cpp_concepts
88  template<typename Arg> requires constant_diagonal_matrix<NestedObject>
89 #else
90  template<typename M = NestedObject, typename Arg, std::enable_if_t<constant_diagonal_matrix<M>, int> = 0>
91 #endif
92  static constexpr auto get_constant_diagonal(const Arg& arg)
93  {
94  return constant_diagonal_value {nested_object(arg)};
95  }
96 
97 
98  // one_dimensional is not necessary
99 
100 
101  // is_square is not necessary
102 
103 
104  static constexpr triangle_type triangle_type_value = triangle_type_of<NestedObject>;
105 
106 
107  static constexpr bool is_triangular_adapter = false;
108 
109 
110  static constexpr bool is_hermitian = hermitian_matrix<NestedObject, applicability::permitted>;
111 
112 
113  static constexpr bool is_writable = writable<NestedObject>;
114 
115 
116 #ifdef __cpp_lib_concepts
117  template<typename Arg> requires raw_data_defined_for<nested_object_of_t<Arg&&>>
118 #else
119  template<typename Arg, std::enable_if_t<raw_data_defined_for<typename nested_object_of<Arg&&>::type>, int> = 0>
120 #endif
121  static constexpr decltype(auto)
122  raw_data(Arg&& arg)
123  {
124  return internal::raw_data(OpenKalman::nested_object(std::forward<Arg>(arg)));
125  }
126 
127 
128  static constexpr data_layout layout = layout_of_v<NestedObject>;
129 
130 
131 #ifdef __cpp_concepts
132  template<typename Arg> requires (layout == data_layout::stride)
133 #else
134  template<data_layout l = layout, typename Arg, std::enable_if_t<l == data_layout::stride, int> = 0>
135 #endif
136  static auto
137  strides(Arg&& arg)
138  {
139  return OpenKalman::internal::strides(nested_object(std::forward<Arg>(arg)));
140  }
141 
142  };
143 
144 
145  // ------------------- //
146  // library_interface //
147  // ------------------- //
148 
149  template<typename Nested, typename Descriptors>
150  struct library_interface<internal::FixedSizeAdapter<Nested, Descriptors>> : library_interface<std::decay_t<Nested>>
151  {
152  private:
153 
154  using NestedObject = std::decay_t<Nested>;
156 
157  public:
158 
159  template<typename Derived>
160  using library_base = internal::library_base_t<Derived, NestedObject>;
161 
162  private:
163 
164  template<typename Object, typename Indices>
165  static constexpr decltype(auto) add_trailing_indices(const Indices& indices)
166  {
167  if constexpr (not index_collection_for<Indices, Object>)
168  {
169  constexpr auto N = index_count_v<Object>; //< We know N is not stdex::dynamic_extent because index_collection_for is not satisfied.
170  std::array<std::size_t, N> ret;
171  std::ranges::fill(std::ranges::copy<stdex::ranges::begin(indices), stdex::ranges::end(indices), stdex::ranges::begin(ret)), stdex::ranges::end(ret), 0);
172  return ret;
173  }
174  else return indices;
175  }
176 
177  public:
178 
179 #ifdef __cpp_lib_ranges
180  template<indexible Arg, std::ranges::input_range Indices> requires values::index<std::ranges::range_value_t<Indices>> and
181  interface::get_component_defined_for<NestedObject, nested_object_of_t<Arg&>, std::initializer_list<std::size_t>>
182  static constexpr values::scalar decltype(auto)
183 #else
184  template<typename Arg, typename Indices, std::enable_if_t<
185  interface::get_component_defined_for<NestedObject, typename nested_object_of<Arg&>::type, std::initializer_list<std::size_t>>, int> = 0>
186  static constexpr decltype(auto)
187 #endif
188  get_component(Arg&& arg, const Indices& indices)
189  {
190  return NestedInterface::get_component(nested_object(std::forward<Arg>(arg)), add_trailing_indices<NestedObject>(indices));
191  }
192 
193 
194 #ifdef __cpp_lib_ranges
195  template<indexible Arg, std::ranges::input_range Indices> requires values::index<std::ranges::range_value_t<Indices>> and
196  interface::set_component_defined_for<NestedObject, nested_object_of_t<Arg&>, const scalar_type_of_t<Arg>&, std::initializer_list<std::size_t>>
197 #else
198  template<typename Arg, typename Indices, std::enable_if_t<
199  interface::set_component_defined_for<NestedObject, typename nested_object_of<Arg&>::type, const typename scalar_type_of<Arg>::type&, std::initializer_list<std::size_t>>, int> = 0>
200 #endif
201  static constexpr void
202  set_component(Arg& arg, const scalar_type_of_t<Arg>& s, const Indices& indices)
203  {
204  NestedInterface::set_component(nested_object(arg), s, add_trailing_indices<NestedObject>(indices));
205  }
206 
207 
208 #ifdef __cpp_concepts
209  template<typename A> requires interface::to_native_matrix_defined_for<NestedObject, nested_object_of_t<A&&>>
210 #else
211  template<typename A, std::enable_if_t<interface::to_native_matrix_defined_for<NestedObject, nested_object_of_t<A&&>>, int> = 0>
212 #endif
213  static decltype(auto)
214  to_native_matrix(A&& a)
215  {
216  return internal::make_fixed_size_adapter<Descriptors>(NestedInterface::to_native_matrix(nested_object(std::forward<A>(a))));
217  }
218 
219 
220 #ifdef __cpp_concepts
221  template<typename To, typename From> requires
222  interface::copy_defined_for<NestedObject, nested_object_of_t<To&>, From&&>
223 #else
224  template<typename To, typename From, std::enable_if_t<
225  interface::copy_defined_for<NestedObject, nested_object_of_t<To&>, From&&>, int> = 0>
226 #endif
227  static void
228  copy(To& a, From&& b)
229  {
230  NestedInterface::copy(nested_object(a), std::forward<From>(b));
231  }
232 
233 
234 #ifdef __cpp_concepts
235  template<data_layout layout, typename Scalar, typename D> requires
236  interface::make_default_defined_for<NestedObject, layout, Scalar, D&&>
237 #else
238  template<data_layout layout, typename Scalar, typename D, std::enable_if_t<
239  interface::make_default_defined_for<NestedObject, layout, Scalar, D&&>, int> = 0>
240 #endif
241  static auto
242  make_default(D&& d)
243  {
244  return NestedInterface::template make_default<layout, Scalar>(std::forward<D>(d));
245  }
246 
247 
248 #ifdef __cpp_concepts
249  template<data_layout layout, typename Arg, typename...Scalars> requires
250  interface::fill_components_defined_for<NestedObject, layout, nested_object_of_t<Arg&>, Scalars...>
251 #else
252  template<data_layout layout, typename Arg, typename...Scalars, std::enable_if_t<
253  interface::fill_components_defined_for<NestedObject, layout, typename nested_object_of<Arg&>::type, Scalars...>, int> = 0>
254 #endif
255  static void
256  fill_components(Arg& arg, const Scalars...scalars)
257  {
258  NestedInterface::template fill_components<layout>(nested_object(arg), scalars...);
259  }
260 
261 
262 #ifdef __cpp_concepts
263  template<typename C, typename D> requires interface::make_constant_defined_for<NestedObject, C&&, D&&>
264 #else
265  template<typename C, typename D, std::enable_if_t<interface::make_constant_defined_for<NestedObject, C&&, D&&>, int> = 0>
266 #endif
267  static constexpr auto
268  make_constant(C&& c, D&& d)
269  {
270  return NestedInterface::make_constant(std::forward<C>(c), std::forward<D>(d));
271  }
272 
273 
274 #ifdef __cpp_concepts
275  template<typename Scalar, typename D> requires interface::make_identity_matrix_defined_for<NestedObject, Scalar, D&&>
276 #else
277  template<typename Scalar, typename D, std::enable_if_t<interface::make_identity_matrix_defined_for<NestedObject, Scalar, D&&>, int> = 0>
278 #endif
279  static constexpr auto
280  make_identity_matrix(D&& d)
281  {
282  return NestedInterface::make_identity_matrix(std::forward<D>(d));
283  }
284 
285 
286 #ifdef __cpp_concepts
287  template<triangle_type t, indexible Arg> requires
288  interface::make_triangular_matrix_defined_for<NestedObject, t, nested_object_of_t<Arg&&>>
289  static constexpr triangular_matrix<t> auto
290 #else
291  template<triangle_type t, typename Arg, std::enable_if_t<
292  interface::make_triangular_matrix_defined_for<NestedObject, t, typename nested_object_of<Arg&&>::type>, int> = 0>
293  static constexpr auto
294 #endif
295  make_triangular_matrix(Arg&& arg)
296  {
297  return internal::make_fixed_size_adapter<Descriptors>(NestedInterface::template make_triangular_matrix<t>(nested_object(std::forward<Arg>(arg))));
298  }
299 
300 
301 #ifdef __cpp_concepts
302  template<HermitianAdapterType t, indexible Arg> requires
303  interface::make_hermitian_adapter_defined_for<NestedObject, t, nested_object_of_t<Arg&&>>
304  static constexpr hermitian_matrix auto
305 #else
306  template<HermitianAdapterType t, typename Arg, std::enable_if_t<
307  make_hermitian_adapter_defined_for<NestedObject, t, typename nested_object_of<Arg&>::type>, int> = 0>
308  static constexpr auto
309 #endif
310  make_hermitian_adapter(Arg&& arg)
311  {
312  return internal::make_fixed_size_adapter<Descriptors>(NestedInterface::template make_hermitian_adapter<t>(nested_object(std::forward<Arg>(arg))));
313  }
314 
315  private:
316 
317  template<typename Arg, typename...Begin, typename...Size, std::size_t...Ix>
318  static decltype(auto)
319  get_slice_impl(Arg&& arg, const std::tuple<Begin...>& begin_tup, const std::tuple<Size...>& size_tup, std::index_sequence<Ix...>)
320  {
321  using NewDesc = std::tuple<std::decay_t<decltype(patterns::get_slice<scalar_type_of_t<Arg>>(
322  std::declval<collections::collection_element_t<Ix, Descriptors>>, std::declval<Begin>(), std::declval<Size>()))>...>;
323  return internal::make_fixed_size_adapter<NewDesc>(NestedInterface::get_slice(nested_object(std::forward<Arg>(arg)), begin_tup, size_tup));
324  }
325 
326  public:
327 
328 #ifdef __cpp_concepts
329  template<typename Arg, typename...Begin, typename...Size> requires
330  interface::get_slice_defined_for<NestedObject, nested_object_of_t<Arg&&>, const std::tuple<Begin...>&, const std::tuple<Size...>&>
331 #else
332  template<typename Arg, typename...Begin, typename...Size, std::enable_if_t<
333  interface::get_slice_defined_for<NestedObject, typename nested_object_of<Arg&&>::type, const std::tuple<Begin...>&, const std::tuple<Size...>&>, int> = 0>
334 #endif
335  static decltype(auto)
336  get_slice(Arg&& arg, const std::tuple<Begin...>& begin_tup, const std::tuple<Size...>& size_tup)
337  {
338  return get_slice_impl(std::forward<Arg>(arg), begin_tup, size_tup, std::make_index_sequence<collections::size_of_v<Descriptors>>{});
339  };
340 
341 
342 #ifdef __cpp_concepts
343  template<typename Arg, typename Block, typename...Begin> requires
344  interface::set_slice_defined_for<Arg, nested_object_of_t<Arg&>, Block&&, const Begin&...>
345 #else
346  template<typename Arg, typename Block, typename...Begin, std::enable_if_t<
347  interface::set_slice_defined_for<Arg, typename nested_object_of<Arg&>::type, Block&&, const Begin&...>, int> = 0>
348 #endif
349  static void
350  set_slice(Arg& arg, Block&& block, const Begin&...begin)
351  {
352  NestedInterface::set_slice(nested_object(arg), std::forward<Block>(block), begin...);
353  };
354 
355 
356 #ifdef __cpp_concepts
357  template<triangle_type t, typename A, typename B> requires
358  interface::set_triangle_defined_for<NestedObject, t, nested_object_of_t<A&&>, B&&>
359 #else
360  template<triangle_type t, typename A, typename B, std::enable_if_t<
361  interface::set_triangle_defined_for<NestedObject, t, typename nested_object_of<A&&>::type, B&&>, int> = 0>
362 #endif
363  static void
364  set_triangle(A&& a, B&& b)
365  {
366  NestedInterface::template set_triangle<t>(nested_object(std::forward<A>(a)), std::forward<B>(b));
367  }
368 
369 
370 #ifdef __cpp_concepts
371  template<typename Arg> requires
372  interface::to_diagonal_defined_for<NestedObject, nested_object_of_t<Arg&&>>
373  static constexpr diagonal_matrix auto
374 #else
375  template<typename Arg, std::enable_if_t<
376  interface::to_diagonal_defined_for<NestedObject, typename nested_object_of<Arg&&>::type>, int> = 0>
377  static constexpr auto
378 #endif
379  to_diagonal(Arg&& arg)
380  {
381  using D = vector_space_descriptor_of_t<Arg, 0>;
382  return internal::make_fixed_square_adapter_like<D>(NestedInterface::to_diagonal(nested_object(std::forward<Arg>(arg))));
383  }
384 
385  private:
386 
387  template<typename Arg, typename V0, typename V1, typename...Vs>
388  static constexpr decltype(auto)
389  diagonal_of_impl(Arg&& arg, const std::tuple<V0, V1, Vs...>&)
390  {
391  using D0 = decltype(internal::smallest_pattern<scalar_type_of_t<Arg>>(std::declval<V0>(), std::declval<V1>()));
392  return OpenKalman::internal::make_fixed_size_adapter<D0, Vs...>(std::forward<Arg>(arg));
393  }
394 
395  public:
396 
397 #ifdef __cpp_concepts
398  template<indexible Arg> requires (diagonal_matrix<NestedObject> and internal::has_nested_vector<NestedObject>) or
399  (diagonal_matrix<NestedObject> and internal::has_nested_vector<NestedObject, 1> and
400  interface::transpose_defined_for<NestedObject, decltype(nested_object(nested_object(std::declval<Arg>())))>) or
401  interface::diagonal_of_defined_for<NestedObject, nested_object_of_t<Arg&&>>
402  static constexpr indexible auto
403 #else
404  template<typename Arg, std::enable_if_t<(diagonal_matrix<NestedObject> and internal::has_nested_vector<NestedObject>) or
405  (diagonal_matrix<NestedObject> and internal::has_nested_vector<NestedObject, 1> and
406  interface::transpose_defined_for<NestedObject, decltype(nested_object(nested_object(std::declval<Arg>())))>) or
407  interface::diagonal_of_defined_for<NestedObject, typename nested_object_of<Arg&&>::type>, int> = 0>
408  static constexpr auto
409 #endif
410  diagonal_of(Arg&& arg)
411  {
412  if constexpr (diagonal_matrix<NestedObject> and internal::has_nested_vector<NestedObject>)
413  return diagonal_of_impl(nested_object(nested_object(std::forward<Arg>(arg))));
414  else if constexpr (diagonal_matrix<NestedObject> and internal::has_nested_vector<NestedObject, 1> and
415  interface::transpose_defined_for<NestedObject, decltype(nested_object(nested_object(std::declval<Arg>())))>)
416  return diagonal_of_impl(NestedInterface::transpose(nested_object(nested_object(std::forward<Arg>(arg)))));
417  else
418  return diagonal_of_impl(NestedInterface::diagonal_of(nested_object(std::forward<Arg>(arg))),
419  std::tuple_cat(all_vector_space_descriptors(std::forward<Arg>(arg)), std::tuple{patterns::Axis{}, patterns::Axis{}}));
420  }
421 
422  private:
423 
424  template<std::size_t Ix, typename Arg, typename Factors_tup>
425  static constexpr auto broadcast_for_index(const Arg& arg, const Factors_tup& factors_tup)
426  {
427  constexpr auto N = collections::size_of_v<Factors_tup>;
428  if constexpr (Ix < N)
429  return get_pattern_collection<Ix>(arg) * std::get<Ix>(factors_tup);
430  else
431  return patterns::Axis{};
432  }
433 
434 
435  template<typename Arg, std::size_t...Is, typename Factors_tup>
436  static constexpr auto broadcast_impl(Arg&& arg, std::index_sequence<Is...>, const Factors_tup& factors_tup)
437  {
438  constexpr auto N = collections::size_of_v<Factors_tup>;
439  return internal::make_fixed_size_adapter<decltype(broadcast_for_index<Is>(arg, factors_tup))...>(std::forward<Arg>(arg));
440  }
441 
442  public:
443 
444 #ifdef __cpp_concepts
445  template<indexible Arg, values::index...Factors> requires
446  interface::broadcast_defined_for<NestedObject, nested_object_of_t<Arg&&>, const Factors&...>
447  static indexible auto
448 #else
449  template<typename Arg, typename...Factors, std::enable_if_t<
450  interface::broadcast_defined_for<NestedObject, typename nested_object_of<Arg&&>::type, const Factors&...>, int> = 0>
451  static auto
452 #endif
453  broadcast(Arg&& arg, const Factors&...factors)
454  {
455  auto&& ret = NestedInterface::broadcast(nested_object(std::forward<Arg>(arg)), factors...);
456  using Ret = decltype(ret);
457  auto seq = std::make_index_sequence<std::max(index_count_v<Arg>, sizeof...(factors))>{};
458  return broadcast_impl(std::forward<Ret>(ret), seq, std::forward_as_tuple(factors...));
459  }
460 
461 
462 #ifdef __cpp_concepts
463  template<patterns::pattern...IDs, typename Operation> requires
464  interface::n_ary_operation_defined_for<NestedInterface, const std::tuple<IDs...>&, Operation&&>
465  static indexible auto
466 #else
467  template<typename...IDs, typename Operation, std::enable_if_t<
468  interface::n_ary_operation_defined_for<NestedInterface, const std::tuple<IDs...>&, Operation&&>, int> = 0>
469  static auto
470 #endif
471  n_ary_operation(const std::tuple<IDs...>& d_tup, Operation&& op)
472  {
473  return NestedInterface::n_ary_operation(d_tup, std::forward<Operation>(op));
474  }
475 
476 
477 #ifdef __cpp_concepts
478  template<patterns::pattern...IDs, typename Operation, indexible Arg, indexible...Args> requires
479  interface::n_ary_operation_defined_for<NestedObject, const std::tuple<IDs...>&, Operation&&, nested_object_of_t<Arg&&>, Args...>
480  static indexible auto
481 #else
482  template<typename...IDs, typename Operation, typename Arg, typename...Args, std::enable_if_t<
483  interface::n_ary_operation_defined_for<NestedObject, const std::tuple<IDs...>&, Operation&&, typename nested_object_of<Arg&&>::type, Args...>, int> = 0>
484  static auto
485 #endif
486  n_ary_operation(const std::tuple<IDs...>& d_tup, Operation&& op, Arg&& arg, Args&&...args)
487  {
488  return internal::make_fixed_size_adapter<IDs...>(
489  NestedInterface::n_ary_operation(d_tup, std::forward<Operation>(op), nested_object(std::forward<Arg>(arg)), std::forward<Args>(args)...));
490  }
491 
492  private:
493 
494  template<std::size_t Ix, std::size_t...indices>
495  static constexpr bool matching_Ix() { return ((Ix == indices) or ...); }
496 
497  template<std::size_t...indices, typename Arg, std::size_t...Ix>
498  static constexpr decltype(auto)
499  reduce_impl(Arg&& arg, std::index_sequence<Ix...> seq)
500  {
501  return internal::make_fixed_size_adapter<std::tuple<
502  std::conditional_t<
503  matching_Ix<Ix, indices...>(),
504  uniform_pattern_component_of_t<vector_space_descriptor_of_t<Arg, Ix>>,
506  (std::forward<Arg>(arg));
507  }
508 
509  public:
510 
511 #ifdef __cpp_concepts
512  template<std::size_t...indices, typename BinaryFunction, indexible Arg> requires
513  interface::reduce_defined_for<NestedObject, BinaryFunction&&, nested_object_of_t<Arg&&>, indices...>
514 #else
515  template<std::size_t...indices, typename BinaryFunction, typename Arg, std::enable_if_t<
516  interface::reduce_defined_for<NestedObject, BinaryFunction&&, typename nested_object_of<Arg&&>::type, indices...>, int> = 0>
517 #endif
518  static constexpr decltype(auto)
519  reduce(BinaryFunction&& op, Arg&& arg)
520  {
521  return reduce_impl<indices...>(
522  NestedInterface::template reduce<indices...>(std::forward<BinaryFunction>(op), nested_object(std::forward<Arg>(arg))),
523  std::make_index_sequence<collections::size_of_v<Descriptors>>{});
524  }
525 
526 
527 #ifdef __cpp_concepts
528  template<indexible Arg> requires interface::to_euclidean_defined_for<NestedObject, nested_object_of_t<Arg&&>>
529  static constexpr indexible auto
530 #else
531  template<typename Arg, std::enable_if_t<
532  interface::to_euclidean_defined_for<NestedObject, typename nested_object_of<Arg&&>::type>, int> = 0>
533  static constexpr auto
534 #endif
535  to_euclidean(Arg&& arg)
536  {
537  constexpr auto dim = collections::size_of_v<Descriptors>;
538  if constexpr (dim == 0)
539  {
540  return std::forward<Arg>(arg);
541  }
542  else
543  {
545  if constexpr (patterns::euclidean_pattern<D0>)
546  {
547  return std::forward<Arg>(arg);
548  }
549  else
550  {
551  using V0 = std::conditional_t<
552  fixed_pattern<D0>,
554  patterns::DynamicDescriptor<scalar_type_of_t<Arg>>>;
555  using Vtail = std::decay_t<decltype(internal::tuple_slice<1, dim>(std::declval<Descriptors>()))>;
556  using Vcat = decltype(std::tuple_cat(std::declval<V0>()), std::declval<Vtail>());
557  return internal::make_fixed_size_adapter<Vcat>(NestedInterface::to_euclidean(nested_object(std::forward<Arg>(arg))));
558  }
559  }
560  }
561 
562 
563 #ifdef __cpp_concepts
564  template<indexible Arg, patterns::pattern D> requires
565  interface::from_euclidean_defined_for<NestedObject, nested_object_of_t<Arg&&>, D&&>
566  static constexpr indexible auto
567 #else
568  template<typename Arg, typename V, std::enable_if_t<
569  interface::from_euclidean_defined_for<NestedObject, typename nested_object_of<Arg&&>::type, V&&>, int> = 0>
570  static constexpr auto
571 #endif
572  from_euclidean(Arg&& arg, D&& d)
573  {
574  if constexpr (patterns::euclidean_pattern<D>)
575  {
576  return std::forward<Arg>(arg);
577  }
578  else
579  {
580  constexpr auto dim = collections::size_of_v<Descriptors>;
581  using Vtail = std::decay_t<decltype(internal::tuple_slice<1, dim>(std::declval<Descriptors>()))>;
582  using Vcat = decltype(std::tuple_cat(std::declval<D>()), std::declval<Vtail>());
583  return internal::make_fixed_size_adapter<Vcat>(NestedInterface::from_euclidean(nested_object(std::forward<Arg>(arg)), std::forward<D>(d)));
584  }
585  }
586 
587 
588 #ifdef __cpp_concepts
589  template<indexible Arg> requires interface::wrap_angles_defined_for<NestedObject, nested_object_of_t<Arg&&>>
590  static constexpr indexible auto
591 #else
592  template<typename Arg, std::enable_if_t<
593  interface::wrap_angles_defined_for<NestedObject, typename nested_object_of<Arg&&>::type>, int> = 0>
594  static constexpr auto
595 #endif
596  wrap_angles(Arg&& arg)
597  {
598  return internal::make_fixed_size_adapter<Descriptors>(NestedInterface::wrap_angles(nested_object(std::forward<Arg>(arg))));
599  }
600 
601 
602 #ifdef __cpp_concepts
603  template<indexible Arg> requires
604  interface::conjugate_defined_for<NestedObject, Arg&&> or
605  interface::conjugate_defined_for<NestedObject, nested_object_of_t<Arg&&>>
606  static constexpr indexible auto
607 #else
608  template<typename Arg, std::enable_if_t<
609  interface::conjugate_defined_for<NestedObject, Arg&&> or
610  interface::conjugate_defined_for<NestedObject, typename nested_object_of<Arg&&>::type>, int> = 0>
611  static constexpr auto
612 #endif
613  conjugate(Arg&& arg)
614  {
615  if constexpr (interface::conjugate_defined_for<NestedObject, Arg&&>)
616  {
617  return NestedInterface::conjugate(std::forward<Arg>(arg));
618  }
619  else
620  {
621  auto&& conj = NestedInterface::conjugate(nested_object(std::forward<Arg>(arg)));
622  return internal::make_fixed_size_adapter_like<Arg>(std::forward<decltype(conj)>(conj));
623  }
624  }
625 
626 
627 #ifdef __cpp_concepts
628  template<indexible Arg> requires
629  interface::transpose_defined_for<NestedObject, Arg&&> or
630  interface::transpose_defined_for<NestedObject, nested_object_of_t<Arg&&>>
631  static constexpr indexible auto
632 #else
633  template<typename Arg, std::enable_if_t<
634  interface::transpose_defined_for<NestedObject, Arg&&> or
635  interface::transpose_defined_for<NestedObject, typename nested_object_of<Arg&&>::type>, int> = 0>
636  static constexpr auto
637 #endif
638  transpose(Arg&& arg)
639  {
640  if constexpr (interface::transpose_defined_for<NestedObject, Arg&&>)
641  {
642  return NestedInterface::transpose(std::forward<Arg>(arg));
643  }
644  else
645  {
646  return internal::make_fixed_size_adapter<vector_space_descriptor_of_t<Arg, 1>, vector_space_descriptor_of_t<Arg, 0>>(
647  NestedInterface::transpose(nested_object(std::forward<Arg>(arg))));
648  }
649  }
650 
651 
652 #ifdef __cpp_concepts
653  template<indexible Arg> requires
654  interface::adjoint_defined_for<NestedObject, Arg&&> or
655  interface::adjoint_defined_for<NestedObject, nested_object_of_t<Arg&&>>
656  static constexpr indexible auto
657 #else
658  template<typename Arg, std::enable_if_t<
659  interface::adjoint_defined_for<NestedObject, Arg&&> or
660  interface::adjoint_defined_for<NestedObject, typename nested_object_of<Arg&&>::type>, int> = 0>
661  static constexpr auto
662 #endif
663  conjugate_transpose(Arg&& arg)
664  {
665  if constexpr (interface::adjoint_defined_for<NestedObject, Arg&&>)
666  {
667  return NestedInterface::conjugate_transpose(std::forward<Arg>(arg));
668  }
669  else
670  {
671  return internal::make_fixed_size_adapter<vector_space_descriptor_of_t<Arg, 1>, vector_space_descriptor_of_t<Arg, 0>>(
672  NestedInterface::conjugate_transpose(nested_object(std::forward<Arg>(arg))));
673  }
674  }
675 
676 
677 #ifdef __cpp_concepts
678  template<indexible Arg> requires
679  interface::determinant_defined_for<NestedObject, Arg&&> or
680  interface::determinant_defined_for<NestedObject, nested_object_of_t<Arg&&>>
681  static constexpr std::convertible_to<scalar_type_of_t<Arg>> auto
682 #else
683  template<typename Arg, std::enable_if_t<
684  interface::determinant_defined_for<NestedObject, Arg&&> or
685  interface::determinant_defined_for<NestedObject, typename nested_object_of<Arg&&>::type>, int> = 0>
686  static constexpr auto
687 #endif
688  determinant(Arg&& arg)
689  {
690  if constexpr (interface::determinant_defined_for<NestedObject, Arg&&>)
691  {
692  return NestedInterface::determinant(std::forward<Arg>(arg));
693  }
694  else
695  {
696  return NestedInterface::determinant(nested_object(std::forward<Arg>(arg)));
697  }
698  }
699 
700 
701 #ifdef __cpp_concepts
702  template<typename Arg, typename...Args> requires
703  interface::sum_defined_for<NestedObject, Arg&&, Args&&...> or
704  interface::sum_defined_for<NestedObject, nested_object_of_t<Arg&&>, Args&&...>
705 #else
706  template<typename Arg, typename...Args, std::enable_if_t<
707  interface::sum_defined_for<NestedObject, Arg&&, Args&&...> or
708  interface::sum_defined_for<NestedObject, typename nested_object_of<Arg&&>::type, Args&&...>, int> = 0>
709 #endif
710  static auto
711  sum(Arg&& arg, Args&&...args)
712  {
713  if constexpr (interface::sum_defined_for<NestedObject, Arg&&, Args&&...>)
714  {
715  return NestedInterface::sum(std::forward<Arg>(arg), std::forward<Args>(args)...);
716  }
717  else
718  {
719  return NestedInterface::sum(nested_object(std::forward<Arg>(arg)), std::forward<Args>(args)...);
720  }
721  }
722 
723 
724 #ifdef __cpp_concepts
725  template<typename A, typename B> requires
726  interface::contract_defined_for<NestedObject, A&&, B&&> or
727  interface::contract_defined_for<NestedObject, nested_object_of_t<A&&>, B&&>
728 #else
729  template<typename A, typename B, std::enable_if_t<
730  interface::contract_defined_for<NestedObject, A&&, B&&> or
731  interface::contract_defined_for<NestedObject, typename nested_object_of<A&&>::type, B&&>, int> = 0>
732 #endif
733  static auto
734  contract(A&& a, B&& b)
735  {
736  if constexpr (interface::contract_defined_for<NestedObject, A&&, B&&>)
737  {
738  return NestedInterface::contract(std::forward<A>(a), std::forward<B>(b));
739  }
740  else
741  {
742  return internal::make_fixed_size_adapter<vector_space_descriptor_of_t<A, 0>, vector_space_descriptor_of_t<B, 1>>(
743  NestedInterface::contract(nested_object(std::forward<A>(a)), std::forward<B>(b)));
744  }
745  }
746 
747 
748 #ifdef __cpp_concepts
749  template<bool on_the_right, typename A, typename B> requires
750  interface::contract_in_place_defined_for<NestedObject, on_the_right, A&&, B&&> or
751  interface::contract_in_place_defined_for<NestedObject, on_the_right, nested_object_of_t<A&&>, B&&>
752 #else
753  template<bool on_the_right, typename A, typename B, std::enable_if_t<
754  interface::contract_in_place_defined_for<NestedObject, on_the_right, A&&, B&&> or
755  interface::contract_in_place_defined_for<NestedObject, on_the_right, typename nested_object_of<A&&>::type, B&&>, int> = 0>
756 #endif
757  static decltype(auto)
758  contract_in_place(A&& a, B&& b)
759  {
760  if constexpr (interface::contract_in_place_defined_for<NestedObject, on_the_right, A&&, B&&>)
761  {
762  return NestedInterface::template contract_in_place<on_the_right>(std::forward<A>(a), std::forward<B>(b));
763  }
764  else
765  {
766  auto&& ret = NestedInterface::template contract_in_place<on_the_right>(nested_object(std::forward<A>(a)), std::forward<B>(b));
767  using Ret = decltype(ret);
768  if constexpr (std::is_lvalue_reference_v<Ret> and std::is_same_v<Ret, nested_object_of_t<A&&>>)
769  {
770  return std::forward<A>(a);
771  }
772  else if constexpr (on_the_right)
773  {
774  return internal::make_fixed_size_adapter<vector_space_descriptor_of_t<A, 0>, vector_space_descriptor_of_t<B, 1>>(std::forward<Ret>(ret));
775  }
776  else
777  {
778  return internal::make_fixed_size_adapter<vector_space_descriptor_of_t<B, 0>, vector_space_descriptor_of_t<A, 1>>(std::forward<Ret>(ret));
779  }
780  }
781  }
782 
783 
784 #ifdef __cpp_concepts
785  template<triangle_type tri, indexible Arg> requires
786  interface::cholesky_factor_defined_for<NestedObject, tri, Arg&&> or
787  interface::cholesky_factor_defined_for<NestedObject, tri, nested_object_of_t<Arg&&>>
788  static constexpr triangular_matrix<tri> auto
789 #else
790  template<triangle_type tri, typename Arg, std::enable_if_t<
791  interface::cholesky_factor_defined_for<NestedObject, tri, Arg&&> or
792  interface::cholesky_factor_defined_for<NestedObject, tri, typename nested_object_of<Arg&&>::type>, int> = 0>
793  static constexpr auto
794 #endif
795  cholesky_factor(Arg&& arg)
796  {
797  if constexpr (interface::cholesky_factor_defined_for<NestedObject, tri, Arg&&>)
798  {
799  return NestedInterface::template cholesky_factor<tri>(std::forward<Arg>(arg));
800  }
801  else
802  {
803  auto tri = NestedInterface::template cholesky_factor<tri>(nested_object(std::forward<Arg>(arg)));
804  return internal::make_fixed_square_adapter_like(std::move(tri));
805  }
806  }
807 
808 
809 #ifdef __cpp_concepts
810  template<HermitianAdapterType significant_triangle, indexible A, indexible U> requires
811  interface::rank_update_self_adjoint_defined_for<NestedObject, significant_triangle, A&&, U&&, const scalar_type_of_t<A>&> or
812  interface::rank_update_self_adjoint_defined_for<NestedObject, significant_triangle, nested_object_of_t<A&&>, U&&, const scalar_type_of_t<A>&>
813  static constexpr hermitian_matrix auto
814 #else
815  template<HermitianAdapterType significant_triangle, typename A, typename U, std::enable_if_t<
816  interface::rank_update_self_adjoint_defined_for<NestedObject, significant_triangle, A&&, U&&, const typename scalar_type_of<A>::type&> or
817  interface::rank_update_self_adjoint_defined_for<NestedObject, significant_triangle, typename nested_object_of<A&&>::type, U&&, const typename scalar_type_of<A>::type&>, int> = 0>
818  static constexpr auto
819 #endif
820  rank_update_hermitian(A&& a, U&& u, const scalar_type_of_t<A>& alpha)
821  {
822  if constexpr (interface::rank_update_self_adjoint_defined_for<NestedObject, significant_triangle, A&&, U&&, const scalar_type_of_t<A>&>)
823  {
824  return NestedInterface::template rank_update_hermitian<significant_triangle>(std::forward<A>(a), std::forward<U>(u), alpha);
825  }
826  else
827  {
828  auto tri = NestedInterface::template rank_update_hermitian<significant_triangle>(nested_object(std::forward<A>(a), std::forward<U>(u), alpha));
829  return internal::make_fixed_square_adapter_like(std::move(tri));
830  }
831  }
832 
833 
834 #ifdef __cpp_concepts
835  template<triangle_type tri, indexible A, indexible U> requires
836  interface::rank_update_triangular_defined_for<NestedObject, tri, A&&, U&&, const scalar_type_of_t<A>&> or
837  interface::rank_update_triangular_defined_for<NestedObject, tri, nested_object_of_t<A&&>, U&&, const scalar_type_of_t<A>&>
838  static constexpr triangular_matrix<tri> auto
839 #else
840  template<triangle_type tri, typename A, typename U, std::enable_if_t<
841  interface::rank_update_triangular_defined_for<NestedObject, tri, A&&, U&&, const typename scalar_type_of<A>::type&> or
842  interface::rank_update_triangular_defined_for<NestedObject, tri, typename nested_object_of<A&&>::type, U&&, const typename scalar_type_of<A>::type&>, int> = 0>
843  static constexpr auto
844 #endif
845  rank_update_triangular(A&& a, U&& u, const scalar_type_of_t<A>& alpha)
846  {
847  if constexpr (interface::rank_update_triangular_defined_for<NestedObject, tri, A&&, U&&, const scalar_type_of_t<A>&>)
848  {
849  return NestedInterface::template rank_update_triangular<tri>(std::forward<A>(a), std::forward<U>(u), alpha);
850  }
851  else
852  {
853  auto tri = NestedInterface::template rank_update_triangular<tri>(nested_object(std::forward<A>(a), std::forward<U>(u), alpha));
854  return internal::make_fixed_square_adapter_like(std::move(tri));
855  }
856  }
857 
858 
859 #ifdef __cpp_concepts
860  template<bool must_be_unique, bool must_be_exact, typename A, typename B> requires
861  interface::solve_defined_for<NestedObject, must_be_unique, must_be_exact, A&&, B&&> or
862  interface::solve_defined_for<NestedObject, must_be_unique, must_be_exact, nested_object_of_t<A&&>, B&&>
863  static compatible_with_vector_space_descriptor_collection<std::tuple<vector_space_descriptor_of_t<A, 1>, vector_space_descriptor_of_t<B, 1>>> auto
864 #else
865  template<bool must_be_unique, bool must_be_exact, typename A, typename B, std::enable_if_t<
866  interface::solve_defined_for<NestedObject, must_be_unique, must_be_exact, A&&, B&&> or
867  interface::solve_defined_for<NestedObject, must_be_unique, must_be_exact, typename nested_object_of<A&&>::type, B&&>, int> = 0>
868  static auto
869 #endif
870  solve(A&& a, B&& b)
871  {
872  if constexpr (interface::solve_defined_for<NestedObject, must_be_unique, must_be_exact, A&&, B&&>)
873  {
874  return NestedInterface::template solve<must_be_unique, must_be_exact>(std::forward<A>(a), std::forward<B>(b));
875  }
876  else
877  {
878  return internal::make_fixed_size_adapter<vector_space_descriptor_of_t<A, 1>, vector_space_descriptor_of_t<B, 1>>(
879  NestedInterface::template solve<must_be_unique, must_be_exact>(nested_object(std::forward<A>(a)), std::forward<B>(b)));
880  }
881  }
882 
883 
884 #ifdef __cpp_concepts
885  template<typename A> requires
886  interface::LQ_decomposition_defined_for<NestedObject, A&&> or
887  interface::LQ_decomposition_defined_for<NestedObject, nested_object_of_t<A&&>>
888 #else
889  template<typename A, std::enable_if_t<
890  interface::LQ_decomposition_defined_for<NestedObject, A&&> or
891  interface::LQ_decomposition_defined_for<NestedObject, typename nested_object_of<A&&>::type>, int> = 0>
892 #endif
893  static auto
894  LQ_decomposition(A&& a)
895  {
896  if constexpr (interface::LQ_decomposition_defined_for<NestedObject, A&&>)
897  {
898  return NestedInterface::LQ_decomposition(std::forward<A>(a));
899  }
900  else
901  {
902  auto&& ret = NestedInterface::LQ_decomposition(nested_object(std::forward<A>(a)));
903  using D0 = vector_space_descriptor_of<A, 0>;
904  return internal::make_fixed_square_adapter_like<D0>(std::forward<decltype(ret)>(ret));
905  }
906  }
907 
908 
909 #ifdef __cpp_concepts
910  template<typename A> requires
911  interface::QR_decomposition_defined_for<NestedObject, A&&> or
912  interface::QR_decomposition_defined_for<NestedObject, nested_object_of_t<A&&>>
913 #else
914  template<typename A, std::enable_if_t<
915  interface::QR_decomposition_defined_for<NestedObject, A&&> or
916  interface::QR_decomposition_defined_for<NestedObject, typename nested_object_of<A&&>::type>, int> = 0>
917 #endif
918  static auto
919  QR_decomposition(A&& a)
920  {
921  if constexpr (interface::QR_decomposition_defined_for<NestedObject, A&&>)
922  {
923  return NestedInterface::QR_decomposition(std::forward<A>(a));
924  }
925  else
926  {
927  auto&& ret = NestedInterface::QR_decomposition(nested_object(std::forward<A>(a)));
928  using D1 = vector_space_descriptor_of<A, 1>;
929  return internal::make_fixed_square_adapter_like<D1>(std::forward<decltype(ret)>(ret));
930  }
931  }
932 
933  };
934 
935 }
936 
937 
938 #endif
constexpr bool fixed_pattern
A patterns::pattern for which the dimension is fixed at compile time.
Definition: fixed_pattern.hpp:32
decltype(auto) constexpr from_euclidean(Arg &&arg, const V &v)
Project the Euclidean vector space associated with index 0 to patterns::pattern v after applying dire...
Definition: from_euclidean.hpp:35
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
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
triangle_type
The type of a triangular matrix.
Definition: enumerations.hpp:26
constexpr bool diagonal_matrix
Specifies that a type is a diagonal matrix or tensor.
Definition: diagonal_matrix.hpp:32
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
constexpr auto count_indices(const T &)
Get the number of indices necessary to address all the components of an indexible object...
Definition: count_indices.hpp:51
constexpr bool pattern
An object describing the characteristics (e.g., dimensions, wrapping structure) of an index...
Definition: pattern.hpp:31
constexpr bool indexible
T is a multidimensional array type.
Definition: indexible.hpp:32
decltype(auto) constexpr get_pattern_collection(T &&t)
Get the patterns::pattern_collection associated with indexible object T.
Definition: get_pattern_collection.hpp:36
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
decltype(auto) constexpr conjugate_transpose(Arg &&arg)
Take the conjugate-transpose of an indexible_object.
Definition: conjugate_transpose.hpp:35
HermitianAdapterType
The type of a hermitian adapter, indicating which triangle of the nested matrix is used...
Definition: enumerations.hpp:79
The size of a sized object (including a collection).
Definition: size_of.hpp:33
constexpr bool value
T is a fixed or dynamic value that is reducible to a number.
Definition: value.hpp:45
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
A structure representing the dimensions associated with of a particular index.
Definition: Dimensions.hpp:42
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
constexpr detail::to_diagonal_adapter to_diagonal
A RangeAdapterObject that converts one pattern_collection to another that is equivalent to duplicatin...
Definition: to_diagonal.hpp:81
constexpr bool hermitian_matrix
Specifies that a type is a hermitian matrix.
Definition: hermitian_matrix.hpp:59
static const bool is_specialized
Identifies types for which object_traits is specialized.
Definition: object_traits.hpp:44
constexpr auto make_identity_matrix(P &&p)
Make an identity_matrix with a given shape pattern.
Definition: make_identity_matrix.hpp:37
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
decltype(auto) constexpr transpose(Arg &&arg)
Swap any two indices of an indexible_object.
Definition: transpose.hpp:49
constexpr A && contract_in_place(A &&a, B &&b)
In-place matrix multiplication of A * B, storing the result in A.
Definition: contract_in_place.hpp:38
decltype(auto) constexpr diagonal_of(Arg &&arg)
Extract a column vector (or column slice for rank>2 tensors) comprising the diagonal elements...
Definition: diagonal_of.hpp:44
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 determinant(Arg &&arg)
Take the determinant of a matrix.
Definition: determinant.hpp:44
Definition: FixedSizeAdapter.hpp:30
decltype(auto) constexpr to_euclidean(Arg &&arg)
Project the vector space associated with index 0 to a Euclidean space for applying directional statis...
Definition: to_euclidean.hpp:38
constexpr auto make_constant(C c, P &&p)
Make an indexible object in which every element is a constant value.
Definition: make_constant.hpp:41
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
decltype(auto) constexpr sum(Ts &&...ts)
Element-by-element sum of one or more objects.
Definition: sum.hpp:112
The triangle_type associated with an indexible object.
Definition: triangle_type_of.hpp:66
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
constexpr detail::diagonal_of_adapter diagonal_of
A RangeAdapterObject that converts one pattern_collection to another corresponding to the diagonal_ma...
Definition: diagonal_of.hpp:153
Definition: trait_backports.hpp:64
typename collection_element< i, T >::type collection_element_t
Helper template for collection_element.
Definition: collection_element.hpp:116
constexpr bool index
T is an index value.
Definition: index.hpp:62
decltype(auto) constexpr to_diagonal(Arg &&arg, P &&p)
Convert a column vector (or any other array with a 1D second index) into a diagonal_matrix.
Definition: to_diagonal.hpp:46
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
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