Sequoia
Loading...
Searching...
No Matches
PhysicalValues.hpp
Go to the documentation of this file.
1
2// Copyright Oliver J. Rosten 2024. //
3// Distributed under the GNU GENERAL PUBLIC LICENSE, Version 3.0. //
4// (See accompanying file LICENSE.md or copy at //
5// https://www.gnu.org/licenses/gpl-3.0.en.html) //
7
8#pragma once
9
13
14#include <numbers>
15
16namespace sequoia::physics
17{
18 template<class T>
20
21 template<class T>
22 using reciprocal_validator_t = reciprocal_validator<T>::type;
23
24 template<class T>
25 requires maths::defines_identity_validator_v<T>
27 {
28 using type = T;
29 };
30
31 template<class T>
32 requires maths::defines_half_line_validator_v<T>
33 struct reciprocal_validator<T>
34 {
35 using type = T;
36 };
37
38 template<class T>
39 inline constexpr bool has_reciprocal_validator_v{
40 requires { typename reciprocal_validator_t<T>; }
41 };
42
43 template<free_module M, physical_unit U>
45 {
46 using is_basis = std::true_type;
47 using free_module_type = M;
48 using units_type = U;
49 using isomorphism_type = units_type;
50 };
51
53 {
54 using is_unit = std::true_type; // TO DO: naming makes this peverse!
56 };
57
58 inline constexpr no_unit_t no_unit{};
59}
60
61namespace sequoia::maths
62{
63 template<physics::physical_unit T>
64 requires physics::has_reciprocal_validator_v<typename T::validator_type>
65 struct dual<T>
66 {
67 using is_unit = std::true_type;
68 using validator_type = physics::reciprocal_validator_t<typename T::validator_type>;
69 };
70
78 template<physics::physical_unit T>
79 requires (!physics::has_reciprocal_validator_v<typename T::validator_type>)
80 struct dual<T>
81 {
82 using is_unit = std::true_type;
83 using validator_type = void;
84 };
85
86 template<free_module M, physics::physical_unit U>
88 {
90 };
91
92 template<free_module M, physics::physical_unit U>
93 struct dual_of<physics::unit_defined_right_handed_basis<dual<M>, dual<U>>>
94 {
96 };
97
98 template<>
99 struct dual_of<physics::no_unit_t>
100 {
101 using type = physics::no_unit_t;
102 };
103}
104
105namespace sequoia::physics
106{
107 using namespace maths;
108
109 template<class... Ts>
111
112 template<class... Ts>
113 using reduced_validator_t = reduced_validator<Ts...>::type;
114
115 template<class T>
117 {
118 using type = T;
119 };
120
121 template<class T, class... Us>
122 struct reduced_validator<T, Us...>
123 {
124 using type = reduced_validator_t<T, reduced_validator_t<Us...>>;
125 };
126
127 template<physical_unit... Ts>
129 {
130 using is_unit = std::true_type;
131 using validator_type = reduced_validator_t<typename Ts::validator_type...>;
132 };
133
135 template<class T>
136 struct reduction;
137
138 template<class T>
139 using reduction_t = reduction<T>::type;
140
141 template<class... Ts>
143
144 template<convex_space... Ts>
145 requires (free_module<Ts> || ...)
146 struct composite_space<Ts...>
147 {
148 using direct_product_t = direct_product<Ts...>;
150 using commutative_ring_type = commutative_ring_type_of_t<direct_product_t>;
151 using is_free_module = std::true_type;
152 using arena_type = arena_type_of_t<direct_product<Ts...>>;
153 constexpr static std::size_t dimension{std::ranges::max({dimension_of<Ts>...})};
154 };
155
156 template<convex_space... Ts>
157 requires (!affine_space<Ts> && ...)
158 struct composite_space<Ts...>
159 {
160 using direct_product_t = direct_product<Ts...>;
162 using free_module_type = composite_space<free_module_type_of_t<Ts>...>;
163 using is_convex_space = std::true_type;
164 using arena_type = arena_type_of_t<direct_product<Ts...>>;
165 using distinguished_origin = std::bool_constant<(has_distinguished_origin_v<Ts> && ...)>;
166 using non_negative_orthant = std::bool_constant<(is_non_negative_orthant_v<Ts> && ...)>;
167 };
168
169 template<physical_unit... Us>
171 {
172 using type = impl::simplify_t<direct_product<Us...>>;
173 };
174
175 template<physical_unit... Ts, physical_unit U>
177 {
178 using type = impl::simplify_t<direct_product<Ts...>, direct_product<U>>;
179 };
180
181 template<physical_unit T, physical_unit... Us>
183 {
184 using type = impl::simplify_t<direct_product<T>, direct_product<Us...>>;
185 };
186
187 template<physical_unit... Ts, physical_unit... Us>
189 {
190 using type = impl::simplify_t<direct_product<Ts...>, direct_product<Us...>>;
191 };
192
193 template<convex_space... Ts>
195 {
196 using type = impl::simplify_t<direct_product<Ts...>>;
197 };
198
199 template<convex_space... Ts, convex_space U>
201 {
202 using type = impl::simplify_t<direct_product<Ts...>, direct_product<U>>;
203 };
204
205 template<convex_space T, convex_space... Us>
207 {
208 using type = impl::simplify_t<direct_product<Us...>, direct_product<T>>;
209 };
210
211 template<convex_space... Ts, convex_space... Us>
213 {
214 using type = impl::simplify_t<direct_product<Ts...>, direct_product<Us...>>;
215 };
216
217 template<class T>
218 struct reduced_validator<T, std::identity>
219 {
220 using type = std::identity;
221 };
222
223 template<class T>
224 requires (!std::is_same_v<T, std::identity>)
226 {
227 using type = std::identity;
228 };
229
230 template<>
232 {
234 };
235
236 template<convex_space ValueSpace, validator_for<ValueSpace> Validator>
237 inline constexpr bool has_consistent_validator{
238 !affine_space<ValueSpace> || defines_identity_validator_v<Validator>
239 };
240
241 template<convex_space ValueSpace>
242 inline constexpr bool has_consistent_space{
243 (!is_dual_v<ValueSpace>) || vector_space<ValueSpace> || (!affine_space<ValueSpace>)
244 };
245
246 template<
247 convex_space ValueSpace,
248 physical_unit Unit,
249 basis_for<free_module_type_of_t<ValueSpace>> Basis,
250 class Origin,
251 validator_for<ValueSpace> Validator
252 >
253 requires has_consistent_space<ValueSpace>
254 && has_consistent_validator<ValueSpace, Validator>
255 class physical_value;
256
257 template<physical_unit Unit>
259
260 template<affine_space T>
262
263 template<convex_space T>
264 requires has_distinguished_origin_v<T>
266
267 template<convex_space ValueSpace, physical_unit Unit>
269
270 template<convex_space ValueSpace, physical_unit Unit>
271 requires (!has_distinguished_origin_v<ValueSpace>) && (!affine_space<ValueSpace>)
272 struct to_origin_type<ValueSpace, Unit>
273 {
275 };
276
277 template<convex_space ValueSpace, physical_unit Unit>
278 using to_origin_type_t = to_origin_type<ValueSpace, Unit>::type;
279
280 template<convex_space ValueSpace, physical_unit Unit>
281 requires has_distinguished_origin_v<ValueSpace>
282 struct to_origin_type<ValueSpace, Unit>
283 {
285 };
286
287 template<convex_space ValueSpace, physical_unit Unit>
288 requires (!has_distinguished_origin_v<ValueSpace> && affine_space<ValueSpace>)
289 struct to_origin_type<ValueSpace, Unit>
290 {
291 using type = implicit_affine_origin<ValueSpace>;
292 };
293
294 template<convex_space ValueSpace, physical_unit Unit, basis_for<free_module_type_of_t<ValueSpace>> Basis, class Validator>
295 using to_coordinates_base_type
296 = coordinates_base<
297 ValueSpace,
298 Basis,
299 Validator,
300 physical_value<free_module_type_of_t<ValueSpace>, Unit, Basis, distinguished_origin<free_module_type_of_t<ValueSpace>>, std::identity>>;
301
302 template<class T>
303 inline constexpr bool has_base_space_v{
304 requires { typename T::base_space; }
305 };
306
307 template<convex_space T>
309 {
310 using type = T;
311 };
312
313 template<convex_space T>
314 using to_base_space_t = to_base_space<T>::type;
315
316 template<convex_space T>
317 requires has_base_space_v<T>
319 {
320 using type = T::base_space;
321 };
322
323 template<convex_space T>
325 {
326 using type = dual<T>;
327 };
328
329 template<convex_space T>
330 requires has_base_space_v<T>
331 struct to_base_space<dual<T>>
332 {
333 using type = dual<typename T::base_space>;
334 };
335
336 template<convex_space... Ts>
338 {
339 using sorted_direct_product_t = meta::stable_sort_t<direct_product<to_base_space_t<Ts>...>, meta::type_comparator>;
340 using type = impl::to_composite_space_t<reduction<impl::reduce_t<impl::count_and_combine_t<sorted_direct_product_t>>>>;
341 };
342
343 template<convex_space T, convex_space U>
344 inline constexpr bool have_compatible_base_spaces_v{
345 has_base_space_v<T> && has_base_space_v<U> && (free_module_type_of_t<T>::dimension == free_module_type_of_t<U>::dimension) && requires {
346 typename std::common_type<typename T::base_space, typename U::base_space>::type;
347 }
348 };
349
350 template<convex_space T, convex_space U>
352
353 template<convex_space T, convex_space U>
354 using to_displacement_space_t = to_displacement_space<T, U>::type;
355
356 template<convex_space T>
358 {
359 using type = free_module_type_of_t<T>;
360 };
361
362 template<convex_space T, convex_space U>
363 requires (!std::is_same_v<T, U>) && have_compatible_base_spaces_v<T, U>
365 {
366 using type = free_module_type_of_t<std::common_type_t<typename T::base_space, typename U::base_space>>;
367 };
368
369 template<basis Basis1, basis Basis2>
370 struct consistent_bases : std::false_type {};
371
372 template<basis Basis1, basis Basis2>
373 inline constexpr bool consistent_bases_v{consistent_bases<Basis1, Basis2>::value};
374
375 template<free_module M1, physical_unit U1, free_module M2, physical_unit U2>
377 {
378 template<free_module M, physical_unit U>
380 };
381
382 template<class T, class U>
384
385 template<class T, class U>
386 using physical_value_product_t = physical_value_product<T, U>::type;
387
388 template<physical_unit LHS, physical_unit RHS>
389 constexpr auto operator*(LHS, RHS) noexcept
390 {
391 return impl::to_composite_space_t<reduction_t<direct_product<LHS, RHS>>>{};
392 }
393
394 template<physical_unit LHS>
395 constexpr auto operator*(LHS lhs, no_unit_t) noexcept
396 {
397 return lhs;
398 };
399
400 template<physical_unit RHS>
401 requires (!std::same_as<RHS, no_unit_t>)
402 constexpr auto operator*(no_unit_t, RHS rhs) noexcept
403 {
404 return rhs;
405 };
406
407 template<physical_unit LHS, physical_unit RHS>
408 constexpr auto operator/(LHS, RHS) noexcept
409 {
410 return impl::to_composite_space_t<reduction_t<direct_product<LHS, dual_of_t<RHS>>>>{};
411 }
412
413 template<physical_unit LHS>
414 constexpr auto operator/(LHS lhs, no_unit_t) noexcept
415 {
416 return lhs;
417 };
418
419 template<physical_unit RHS>
420 requires (!std::same_as<RHS, no_unit_t>)
421 constexpr auto operator/(no_unit_t, RHS) noexcept
422 {
423 return dual_of_t<RHS>{};
424 };
425
426 template<
427 convex_space LHSValueSpace, physical_unit LHSUnit, basis_for<free_module_type_of_t<LHSValueSpace>> LHSBasis, class LHSValidator,
428 convex_space RHSValueSpace, physical_unit RHSUnit, basis_for<free_module_type_of_t<RHSValueSpace>> RHSBasis, class RHSValidator
429 >
430 requires consistent_bases_v<LHSBasis, RHSBasis>
431 struct physical_value_product<physical_value<LHSValueSpace, LHSUnit, LHSBasis, distinguished_origin<LHSValueSpace>, LHSValidator>,
432 physical_value<RHSValueSpace, RHSUnit, RHSBasis, distinguished_origin<RHSValueSpace>, RHSValidator>>
433 {
434 using value_space_type = impl::to_composite_space_t<reduction_t<direct_product<LHSValueSpace, RHSValueSpace>>>;
435 using units_type = impl::to_composite_space_t<reduction_t<direct_product<LHSUnit, RHSUnit>>>;
436 using type
438 value_space_type,
439 units_type,
440 typename consistent_bases<LHSBasis, RHSBasis>::template rebind_type<free_module_type_of_t<value_space_type>, units_type>,
442 reduced_validator_t<LHSValidator, RHSValidator>
443 >;
444 };
445
446 template<class From, class To>
447 inline constexpr bool has_quantity_conversion_v{
448 has_coordinate_transformation_v<From, To> && std::constructible_from<coordinate_transformation<From, To>>
449 };
450
451 template<convex_space C, physical_unit FromUnit, physical_unit ToUnit>
453 {
454 using type = C;
455 };
456
457 template<convex_space C, physical_unit FromUnit, physical_unit ToUnit>
458 using conversion_space_t = conversion_space<C, FromUnit, ToUnit>::type;
459
460 template<convex_space ValueSpace, physical_unit Unit>
461 using default_validator_t = std::conditional_t<affine_space<ValueSpace>, std::identity, typename Unit::validator_type>;
462
463 namespace impl
464 {
465
466 template<class Rep, class...>
467 struct is_valid_physical_value_pack : std::false_type {};
468
469 template<class Rep, class... Args, std::size_t... Is>
470 requires (sizeof...(Args) == sizeof...(Is) + 1)
471 && physical_unit<std::tuple_element_t<sizeof...(Is), std::tuple<Args...>>>
472 && (std::convertible_to<std::tuple_element_t<Is, std::tuple<Args...>>, Rep> && ...)
473 struct is_valid_physical_value_pack<Rep, std::tuple<Args...>, std::index_sequence<Is...>> : std::true_type
474 {
475 };
476 }
477
478 template<class Rep, class... Args>
479 requires (sizeof...(Args) > 1)
481 : impl::is_valid_physical_value_pack<Rep, std::tuple<Args...>, std::make_index_sequence<sizeof...(Args) - 1>>
482 {};
483
484 template<class Rep, class... Args>
485 inline constexpr bool is_valid_physical_value_pack_v{is_valid_physical_value_pack<Rep, Args...>::value};
486
487 template<
488 convex_space ValueSpace,
489 physical_unit Unit,
490 basis_for<free_module_type_of_t<ValueSpace>> Basis = unit_defined_right_handed_basis<free_module_type_of_t<ValueSpace>, Unit>,
491 class Origin = to_origin_type_t<ValueSpace, Unit>,
492 validator_for<ValueSpace> Validator = default_validator_t<ValueSpace, Unit>
493 >
494 requires has_consistent_space<ValueSpace>
495 && has_consistent_validator<ValueSpace, Validator>
496 class physical_value final : public to_coordinates_base_type<ValueSpace, Unit, Basis, Validator>
497 {
498 public:
500 using space_type = ValueSpace;
501 using units_type = Unit;
502 using basis_type = Basis;
503 using origin_type = Origin;
504 using displacement_space_type = free_module_type_of_t<ValueSpace>;
505 using intrinsic_validator_type = Unit::validator_type;
506 using validator_type = Validator;
507 using ring_type = commutative_ring_type_of_t<ValueSpace>;
508 using value_type = ring_type;
509 using displacement_type = coordinates_type::displacement_coordinates_type;
510
511 constexpr static std::size_t dimension{displacement_space_type::dimension};
512 constexpr static std::size_t D{dimension};
513
514 constexpr static bool has_identity_validator{coordinates_type::has_identity_validator};
515
516 template<convex_space RHSValueSpace, class RHSBasis>
517 constexpr static bool is_composable_with{
518 consistent_bases_v<basis_type, RHSBasis>
519 && (is_non_negative_orthant_v<space_type> || vector_space<space_type>)
520 && (is_non_negative_orthant_v<RHSValueSpace> || vector_space<RHSValueSpace>)
521 };
522
523 template<convex_space RHSValueSpace, class RHSBasis>
524 constexpr static bool is_multipicable_with{
525 is_composable_with<RHSValueSpace, RHSBasis>
526 && ((D == 1) || (free_module_type_of_t<RHSValueSpace>::dimension == 1))
527 };
528
529 template<convex_space RHSValueSpace, class RHSBasis>
530 constexpr static bool is_divisible_with{
531 weak_field<ring_type>
532 && weak_field<commutative_ring_type_of_t<RHSValueSpace>>
533 && is_composable_with<RHSValueSpace, RHSBasis>
534 && (free_module_type_of_t<RHSValueSpace>::dimension == 1)
535 };
536
537 using coordinates_type::coordinates_type;
538
539 using coordinates_type::operator+=;
540
541 template<convex_space OtherValueSpace, basis_for<free_module_type_of_t<OtherValueSpace>> OtherBasis, class OtherOrigin>
542 requires (!std::same_as<space_type, OtherValueSpace>)
543 && has_distinguished_origin_v<space_type>
544 && (std::derived_from<OtherValueSpace, space_type>)
545 && consistent_bases_v<basis_type, OtherBasis>
546 constexpr physical_value& operator+=(const physical_value<OtherValueSpace, Unit, OtherBasis, OtherOrigin, Validator>& other) & noexcept(has_identity_validator)
547 {
548 return *this = (*this + other);
549 }
550
551 template<convex_space OtherValueSpace, basis_for<free_module_type_of_t<OtherValueSpace>> OtherBasis, class OtherOrigin>
552 requires (!std::same_as<space_type, OtherValueSpace>)
553 && has_distinguished_origin_v<space_type>
554 && (std::derived_from<OtherValueSpace, space_type>)
555 && consistent_bases_v<basis_type, OtherBasis>
557
558 template<convex_space OtherValueSpace, basis_for<free_module_type_of_t<OtherValueSpace>> OtherBasis, class OtherOrigin>
559 requires has_distinguished_origin_v<space_type>
560 && (!std::is_same_v<space_type, OtherValueSpace>)
561 && have_compatible_base_spaces_v<space_type, OtherValueSpace>
562 && consistent_bases_v<basis_type, OtherBasis>
563 [[nodiscard]]
564 friend constexpr auto operator+(const physical_value& lhs, const physical_value<OtherValueSpace, Unit, OtherBasis, OtherOrigin, Validator>& rhs)
565 {
566 using value_space_t = std::common_type_t<typename ValueSpace::base_space, typename OtherValueSpace::base_space>;
567 using basis_t = consistent_bases<basis_type, OtherBasis>::template rebind_type<free_module_type_of_t<value_space_t>, Unit>;
569
570 return [&] <std::size_t... Is>(std::index_sequence<Is...>) {
571 return physical_value_t{std::array{(lhs.values()[Is] + rhs.values()[Is])...}, units_type{}};
572 }(std::make_index_sequence<D>{});
573 }
574
575 template<class OtherValueSpace, basis_for<free_module_type_of_t<OtherValueSpace>> OtherBasis, class OtherOrigin>
576 requires (!std::same_as<OtherValueSpace, displacement_space_type>)
577 && (!std::same_as<space_type, OtherValueSpace> && have_compatible_base_spaces_v<space_type, OtherValueSpace>)
578 && consistent_bases_v<basis_type, OtherBasis>
579 [[nodiscard]]
580 friend constexpr auto operator-(const physical_value& lhs, const physical_value<OtherValueSpace, Unit, OtherBasis, OtherOrigin, Validator>& rhs)
581 noexcept(has_identity_validator)
582 {
583 using disp_space_t = to_displacement_space_t<ValueSpace, OtherValueSpace>;
584 using basis_t = consistent_bases<basis_type, OtherBasis>::template rebind_type<free_module_type_of_t<disp_space_t>, Unit>;
585 using disp_t = to_coordinates_base_type<disp_space_t, Unit, basis_t, Validator>::displacement_coordinates_type;
586 return[&] <std::size_t... Is>(std::index_sequence<Is...>) {
587 return disp_t{std::array{(lhs.values()[Is] - rhs.values()[Is])...}, units_type{}};
588 }(std::make_index_sequence<D>{});
589 }
590
591 template<convex_space RHSValueSpace, physical_unit RHSUnit, basis_for<free_module_type_of_t<RHSValueSpace>> RHSBasis, class RHSOrigin, class RHSValidator>
592 requires is_multipicable_with<RHSValueSpace, RHSBasis>
593 [[nodiscard]]
594 friend constexpr auto operator*(const physical_value& lhs,
596 {
597 using physical_value_t
598 = physical_value_product_t<
601 >;
602
603 using derived_units_type = physical_value_t::units_type;
604 return physical_value_t{lhs.value() * rhs.value(), derived_units_type{}};
605 }
606
607 template<convex_space RHSValueSpace, class RHSUnit, basis_for<free_module_type_of_t<RHSValueSpace>> RHSBasis, class RHSOrigin, class RHSValidator>
608 requires is_divisible_with<RHSValueSpace, RHSBasis>
609 [[nodiscard]]
610 friend constexpr auto operator/(const physical_value& lhs,
612 {
613 using physical_value_t
614 = physical_value_product_t<
617 >;
618 using derived_units_type = physical_value_t::units_type;
619 if constexpr(dimension == 1)
620 {
621 return physical_value_t{lhs.value() / rhs.value(), derived_units_type{}};
622 }
623 else
624 {
625 return[&] <std::size_t... Is>(std::index_sequence<Is...>) {
626 return physical_value_t{std::array{(lhs.values()[Is] / rhs.value())...}, derived_units_type{}};
627 }(std::make_index_sequence<D>{});
628 }
629 }
630
631 [[nodiscard]] friend constexpr auto operator/(value_type value, const physical_value& rhs)
632 requires ((D == 1) && (is_non_negative_orthant_v<space_type> || vector_space<ValueSpace>))
633 {
635 using derived_units_type = physical_value_t::units_type;
636 return physical_value_t{value / rhs.value(), derived_units_type{}};
637 }
638
639 // Reduce *everything* to its base space on both sides of the equation; if these are the same, allow the conversion
640 template<class LoweredValueSpace, class OtherUnit, basis_for<free_module_type_of_t<LoweredValueSpace>> OtherBasis, class OtherOrigin>
641 requires std::same_as<to_base_space_t<space_type>, to_base_space_t<LoweredValueSpace>> && consistent_bases_v<basis_type, OtherBasis>
642 [[nodiscard]]
644 {
645 using value_space_t = to_base_space_t<LoweredValueSpace>;
647 using physical_value_t = physical_value<to_base_space_t<LoweredValueSpace>, Unit, basis_t, to_origin_type_t<value_space_t, Unit>, validator_type>;
648 if constexpr(dimension == 1)
649 {
650 return physical_value_t{this->value(), OtherUnit{}};
651 }
652 else
653 {
654 return [this] <std::size_t... Is>(std::index_sequence<Is...>) {
655 return physical_value_t{std::array{this->values()[Is]...}, OtherUnit{}};
656 }(std::make_index_sequence<D>{});
657 }
658 }
659
660 template<
661 physical_unit OtherUnit,
662 convex_space OtherSpace = conversion_space_t<ValueSpace, Unit, OtherUnit>,
663 basis_for<free_module_type_of_t<OtherSpace>> OtherBasis = unit_defined_right_handed_basis<free_module_type_of_t<OtherSpace>, OtherUnit>,
664 class OtherOrigin = to_origin_type_t<OtherSpace, OtherUnit>,
665 validator_for<OtherSpace> OtherValidator = default_validator_t<OtherSpace, OtherUnit>
666 >
667 requires has_quantity_conversion_v<physical_value, physical_value<OtherSpace, OtherUnit, OtherBasis, OtherOrigin, OtherValidator>>
668 [[nodiscard]]
670 noexcept(has_noexcept_coordinate_transformation_v<physical_value, physical_value<OtherSpace, OtherUnit, OtherBasis, OtherOrigin, OtherValidator>>)
671 {
673 }
674
675 [[nodiscard]]
676 constexpr physical_value convert_to(Unit) const noexcept { return *this; }
677 };
678
679 template<physical_unit Unit, class Rep>
680 struct default_space {};
681
682 template<physical_unit Unit, class Rep>
683 using default_space_t = default_space<Unit, Rep>::type;
684
685 template<physical_unit Unit, class Rep>
686 inline constexpr bool has_default_space_v{
687 requires {
688 typename default_space_t<Unit, Rep>;
689 }
690 };
691
692 template<physical_unit Unit, class Rep>
693 requires has_default_space_v<Unit, Rep>
694 struct default_space<dual<Unit>, Rep>
695 {
697 };
698
699 template<physical_unit... Ts, class Rep>
700 requires (has_default_space_v<Ts, Rep> && ...)
701 struct default_space<composite_unit<Ts...>, Rep>
702 {
703 using type = impl::to_composite_space_t<reduction_t<direct_product<default_space_t<Ts, Rep>...>>>;
704 };
705
706 template<class T, physical_unit U>
707 requires has_default_space_v<U, T>
709
710 namespace sets::classical
711 {
712 template<class Arena>
713 struct masses
714 {
715 using arena_type = Arena;
716 };
717
718 template<class Arena>
720 {
721 using arena_type = Arena;
722 };
723
724 template<class Arena>
726 {
727 using arena_type = Arena;
728 };
729
730 template<class Arena>
731 struct times
732 {
733 using arena_type = Arena;
734 };
735
736 template<class Arena>
738 {
739 using arena_type = Arena;
740 };
741
742 template<std::size_t D, class Arena>
744 {
745 using arena_type = Arena;
746 };
747
748 template<class Arena>
749 struct lengths
750 {
751 using arena_type = Arena;
752 };
753
754 template<class Arena>
755 struct angles
756 {
757 using arena_type = Arena;
758 };
759
760 template<class PhysicalValueSet>
762 {
763 using physical_value_set_type = PhysicalValueSet;
764 };
765 }
766
767 template<class Space>
769 {
770 constexpr static std::size_t dimension{Space::dimension};
772 using commutative_ring_type = Space::representation_type;
773 using is_free_module = std::true_type;
774 using arena_type = Space::arena_type;
775 };
776
777 template<class Space>
778 requires has_base_space_v<Space>
780 {
781 constexpr static std::size_t dimension{Space::dimension};
783 using commutative_ring_type = Space::representation_type;
784 using is_free_module = std::true_type;
786 using arena_type = Space::arena_type;
787 };
788
789 template<class PhysicalValueSet, arithmetic Rep, std::size_t D, class Derived>
791 {
792 constexpr static std::size_t dimension{D};
793 using set_type = PhysicalValueSet;
794 using representation_type = Rep;
796 using is_convex_space = std::true_type;
797 using arena_type = PhysicalValueSet::arena_type;
798 };
799
800 template<class PhysicalValueSet, arithmetic Rep, std::size_t D, class Derived>
802 {
803 constexpr static std::size_t dimension{D};
804 using set_type = PhysicalValueSet;
805 using representation_type = Rep;
807 using is_affine_space = std::true_type;
808 using arena_type = PhysicalValueSet::arena_type;
809 };
810
811 template<class PhysicalValueSet, arithmetic Rep, std::size_t D, class Derived>
813 {
814 constexpr static std::size_t dimension{D};
815 using set_type = PhysicalValueSet;
816 using representation_type = Rep;
817 using field_type = Rep;
818 using is_vector_space = std::true_type;
819 };
820
821 template<std::floating_point Rep, class Arena>
823 : physical_value_convex_space<sets::classical::masses<Arena>, Rep, 1, mass_space<Rep, Arena>>
824 {
825 using arena_type = Arena;
826 using base_space = mass_space;
827 using distinguished_origin = std::true_type;
828 using non_negative_orthant = std::true_type;
829 };
830
831 template<std::floating_point Rep, class Arena>
833 : physical_value_convex_space<sets::classical::temperatures<Arena>, Rep, 1, absolute_temperature_space<Rep, Arena>>
834 {
835 using arena_type = Arena;
837 using distinguished_origin = std::true_type;
838 using non_negative_orthant = std::true_type;
839 };
840
841 template<convex_space C>
842 requires has_distinguished_origin_v<C>
843 struct relaxed_space : C
844 {
847 using distinguished_origin = std::false_type;
848 using non_negative_orthant = std::false_type;
849 };
850
851 template<std::floating_point Rep, class Arena>
853
854 template<std::floating_point Rep, class Arena>
856 : physical_value_vector_space<sets::classical::electrical_currents<Arena>, Rep, 1, electrical_current_space<Rep, Arena>>
857 {
858 using arena_type = Arena;
860 };
861
862 template<std::floating_point Rep, class Arena>
863 struct angular_space : physical_value_vector_space<sets::classical::angles<Arena>, Rep, 1, angular_space<Rep, Arena>>
864 {
865 using arena_type = Arena;
867 };
868
869 template<arithmetic Rep, class Arena>
871 : physical_value_convex_space<sets::classical::lengths<Arena>, Rep, 1, length_space<Rep, Arena>>
872 {
873 using arena_type = Arena;
874 using base_space = length_space;
875 using distinguished_origin = std::true_type;
876 using non_negative_orthant = std::true_type;
877 };
878
879 template<arithmetic Rep, class Arena>
880 struct width_space : length_space<Rep, Arena>
881 {
882 struct free_module_type : associated_displacement_space<width_space<Rep, Arena>> {};
883 };
884
885 template<arithmetic Rep, class Arena>
886 struct height_space : length_space<Rep, Arena>
887 {
888 struct free_module_type : associated_displacement_space<height_space<Rep, Arena>> {};
889 };
890
891 template<arithmetic Rep, class Arena>
893 : physical_value_convex_space<sets::classical::time_intervals<Arena>, Rep, 1, time_interval_space<Rep, Arena>>
894 {
895 using arena_type = Arena;
896 using distinguished_origin = std::true_type;
897 using non_negative_orthant = std::true_type;
898 };
899
900 template<arithmetic Rep, class Arena>
901 struct time_space : physical_value_affine_space<sets::classical::times<Arena>, Rep, 1, time_space<Rep, Arena>>
902 {
903 using arena_type = Arena;
904 };
905
906 template<arithmetic Rep, std::size_t D, class Arena>
907 struct position_space : physical_value_affine_space<sets::classical::positions<D, Arena>, Rep, D, position_space<Rep, D, Arena>>
908 {
909 using arena_type = Arena;
910 };
911
913
914 template<physical_unit U>
915 inline constexpr bool has_symbol_v{
916 requires {
917 { U::symbol } -> std::convertible_to<std::string_view>; }
918 };
919
920 template<class Validator>
921 struct scale_invariant_validator : std::false_type {};
922
923 template<class T>
924 requires defines_identity_validator_v<T>
925 struct scale_invariant_validator<T> : std::true_type {};
926
927 template<class T>
928 requires defines_half_line_validator_v<T>
929 struct scale_invariant_validator<T> : std::true_type {};
930
931 template<class Validator>
932 using scale_invariant_validator_t = scale_invariant_validator<Validator>::type;
933
934 template<class Validator>
935 inline constexpr bool scale_invariant_validator_v{scale_invariant_validator<Validator>::value};
936
937 template<class Validator>
938 struct translation_invariant_validator : std::false_type {};
939
940 template<>
941 struct translation_invariant_validator<std::identity> : std::true_type {};
942
943 template<class Validator>
944 using translation_invariant_validator_t = translation_invariant_validator<Validator>::type;
945
946 template<class Validator>
947 inline constexpr bool translation_invariant_validator_v{translation_invariant_validator<Validator>::value};
948
949 template<class...>
950 struct product;
951
952 template<class... Ts>
953 using product_t = product<Ts...>::type;
954
955 template<class T, class U, class... Vs>
956 struct product<T, U, Vs...>
957 {
958 using tpye = product_t<product_t<T, U>, Vs...>;
959 };
960
961 template<class>
962 struct inverse;
963
964 template<class T>
965 using inverse_t = inverse<T>::type;
966
967 template<auto Num, auto Den>
968 struct inverse<dilatation<ratio<Num, Den>>>
969 {
971 };
972
973 template<std::intmax_t Num, std::intmax_t Den>
974 struct inverse<dilatation<std::ratio<Num, Den>>>
975 {
977 };
978
979 template<auto Displacement>
980 requires arithmetic<std::remove_const_t<decltype(Displacement)>>
982 {
983 using displacement_type = std::remove_const_t<decltype(Displacement)>;
984 constexpr static auto displacement{Displacement};
985 };
986
987 template<auto Displacement>
988 struct inverse<translation<Displacement>>
989 {
990 using type = translation<-Displacement>;
991 };
992
993 template<class T>
995
996 template<class T>
997 using synthesised_validator_t = synthesised_validator<T>::type;
998
999 template<class...>
1001
1002 template<physical_unit U, class Ratio, auto Displacement>
1003 requires scale_invariant_validator_v<typename U::validator_type> && (translation_invariant_validator_v<typename U::validator_type> || !Displacement)
1005 {
1006 using type = U::validator_type;
1007 };
1008
1009 template<physical_unit U, class Ratio, auto Displacement>
1010 requires scale_invariant_validator_v<typename U::validator_type> && (Displacement != 0)
1012 {
1013 using value_type = std::remove_cv_t<decltype(Displacement)>;
1015 };
1016
1017 template<physical_unit U, class Ratio, auto Displacement>
1018 requires (!scale_invariant_validator_v<typename U::validator_type>) && is_interval_validator_v<typename U::validator_type>
1019 struct synthesised_validator<coordinate_transform<U, dilatation<Ratio>, translation<Displacement>>>
1020 {
1021 using underlying_validator_type = U::validator_type;
1022 using value_type = std::remove_cv_t<decltype(underlying_validator_type::lower)>;
1023
1024 [[nodiscard]]
1025 constexpr static value_type transform(value_type val) {
1026 return (val * Ratio::num / Ratio::den) + Displacement;
1027 }
1028
1029 using type = interval_validator<value_type, transform(underlying_validator_type::lower), transform(underlying_validator_type::upper)>;
1030 };
1031
1032 template<physical_unit U, class Ratio, auto Displacement>
1034 {
1035 using is_unit = std::true_type;
1037 using validator_type = synthesised_validator_t<transform_type>;
1038 using with_respect_to_type = U;
1041 };
1042
1043 template<physical_unit U, class Ratio, auto Displacement>
1044 struct inverse<coordinate_transform<U, dilatation<Ratio>, translation<Displacement>>>
1045 {
1046 using inverse_dil_type = inverse_t<dilatation<Ratio>>;
1047 using inverse_ratio_type = inverse_dil_type::ratio_type;
1048 using type = coordinate_transform<U, inverse_dil_type, inverse_t<translation<Displacement * inverse_ratio_type::num / inverse_ratio_type::den>>>;
1049 };
1050
1051 template<
1052 physical_unit LHSUnit, class LHSRatio, auto LHSDisplacement,
1053 physical_unit RHSUnit, class RHSRatio, auto RHSDisplacement
1054 >
1055 struct product<coordinate_transform<LHSUnit, dilatation<LHSRatio>, translation<LHSDisplacement>>,
1056 coordinate_transform<RHSUnit, dilatation<RHSRatio>, translation<RHSDisplacement>>>
1057 {
1059 using translation_type = translation<LHSDisplacement + RHSDisplacement * LHSRatio::num / LHSRatio::den>;
1061 };
1062
1063 template<class T>
1064 struct is_coordinate_transform : std::false_type {};
1065
1066 template<class T>
1067 using is_coordinate_transform_t = is_coordinate_transform<T>::type;
1068
1069 template<class T>
1070 inline constexpr bool is_coordinate_transform_v{is_coordinate_transform<T>::value};
1071
1072 template<physical_unit U, class Ratio, auto Displacement>
1073 struct is_coordinate_transform<coordinate_transform<U, dilatation<Ratio>, translation<Displacement>>> : std::true_type {};
1074
1075 template<physical_unit U>
1076 inline constexpr bool has_coordinate_transform_v{
1077 requires {
1078 typename U::transform_type;
1079 requires is_coordinate_transform_v<typename U::transform_type>;
1080 }
1081 };
1082
1083 template<physical_unit U>
1084 inline constexpr bool derives_from_another_unit_v{
1085 requires {
1086 typename U::with_respect_to_type;
1087 requires physical_unit<typename U::with_respect_to_type>;
1088 }
1089 };
1090
1091 template<physical_unit U>
1093 {
1095 using units_type = U;
1096 };
1097
1098 template<physical_unit U>
1100
1101 template<physical_unit U>
1102 using root_transform_unit_t = root_transform<U>::units_type;
1103
1104 template<physical_unit U>
1105 requires derives_from_another_unit_v<U>
1106 && (!derives_from_another_unit_v<typename U::with_respect_to_type>)
1108 {
1109 using transform_type = U::transform_type;
1110 };
1111
1112 template<physical_unit U>
1113 requires derives_from_another_unit_v<U>
1114 && derives_from_another_unit_v<typename U::with_respect_to_type>
1115 struct root_transform<U> : root_transform<typename U::with_respect_to_type>
1116 {
1117 using wrt_type = typename U::with_respect_to_type;
1118 using nested_transform_type = root_transform_t<wrt_type>;
1119 using transform_type = product_t<typename U::transform_type, nested_transform_type>;
1120 };
1121
1122 template<physical_unit... Us>
1123 requires (scale_invariant_validator_v<typename Us::validator_type> && ...)
1125 {
1126 using units_type = decltype((root_transform_unit_t<Us>{} * ...));
1127 using transform_type = product_t<root_transform_t<Us>...>;
1128 };
1129
1130 template<class T>
1131 struct has_identity_dilatation : std::false_type {};
1132
1133 template<class T>
1134 using has_identity_dilatation_t = has_identity_dilatation<T>::type;
1135
1136 template<class T>
1137 inline constexpr bool has_identity_dilatation_v{has_identity_dilatation<T>::value};
1138
1139 template<physical_unit U, class Ratio, auto Displacement>
1141 : std::bool_constant<Ratio::num == Ratio::den>
1142 {};
1143
1144 template<class T>
1145 struct has_identity_translation : std::false_type {};
1146
1147 template<class T>
1148 using has_identity_translation_t = has_identity_translation<T>::type;
1149
1150 template<class T>
1151 inline constexpr bool has_identity_translation_v{has_identity_translation<T>::value};
1152
1153 template<physical_unit U, class Ratio, auto Displacement>
1155 : std::bool_constant<Displacement == 0>
1156 {};
1157
1158 template<convex_space C, physical_unit FromUnit, physical_unit ToUnit>
1159 requires (!has_distinguished_origin_v<C>)
1160 || (!has_identity_translation_v<root_transform_t<FromUnit>> && !has_identity_translation_v<root_transform_t<ToUnit>>)
1161 struct conversion_space<C, FromUnit, ToUnit>
1162 {
1163 using type = C;
1164 };
1165
1166 template<convex_space C, physical_unit FromUnit, physical_unit ToUnit>
1167 requires has_distinguished_origin_v<C>
1168 && (has_identity_translation_v<root_transform_t<FromUnit>> && !has_identity_translation_v<root_transform_t<ToUnit>>)
1170 {
1171 using type = relaxed_space<C>;
1172 };
1173
1174 template<convex_space C, physical_unit FromUnit, physical_unit ToUnit>
1175 requires has_distinguished_origin_v<C> && has_identity_translation_v<root_transform_t<ToUnit>>
1176 struct conversion_space<relaxed_space<C>, FromUnit, ToUnit>
1177 {
1178 using type = C;
1179 };
1180
1181 template<physical_unit Unit>
1182 struct micro : coordinate_transform<Unit, dilatation<std::mega>, translation<0>>
1183 {
1184 using validator_type = Unit::validator_type;
1186 };
1187
1188 template<physical_unit Unit>
1189 struct milli : coordinate_transform<Unit, dilatation<std::kilo>, translation<0>>
1190 {
1191 using validator_type = Unit::validator_type;
1193 };
1194
1195 template<physical_unit Unit>
1196 struct kilo : coordinate_transform<Unit, dilatation<std::milli>, translation<0>>
1197 {
1198 using validator_type = Unit::validator_type;
1200 };
1201
1202 template<physical_unit Unit>
1203 struct mega : coordinate_transform<Unit, dilatation<std::micro>, translation<0>>
1204 {
1205 using validator_type = Unit::validator_type;
1207 };
1208
1209 // TO DO: these namespace have been made inline to workaround an MSVC bug
1210 // https://developercommunity.visualstudio.com/t/Overload-resolution-failing-with-a-class/10977207
1211 // It may be worth making them inline, regardless, and possibly abandoning
1212 // the inner namespace. I need to think about this.
1213 inline namespace si
1214 {
1215 inline namespace units
1216 {
1218 {
1219 using is_unit = std::true_type;
1220 using validator_type = std::identity;
1221 constexpr static std::string_view symbol{"A"};
1222 };
1223
1225 {
1226 using is_unit = std::true_type;
1227 using validator_type = half_line_validator;
1228 constexpr static std::string_view symbol{"kg"};
1229 };
1230
1231 struct metre_t
1232 {
1233 using is_unit = std::true_type;
1234 using validator_type = half_line_validator;
1235 constexpr static std::string_view symbol{"m"};
1236 };
1237
1239 {
1240 using is_unit = std::true_type;
1241 using validator_type = half_line_validator;
1242 constexpr static std::string_view symbol{"s"};
1243 };
1244
1246 {
1247 using is_unit = std::true_type;
1248 using validator_type = half_line_validator;
1249 constexpr static std::string_view symbol{"K"};
1250 };
1251
1253 {
1254 using is_unit = std::true_type;
1255 using validator_type = std::identity;
1256 constexpr static std::string_view symbol{"C"};
1257 };
1258
1260 {
1261 using is_unit = std::true_type;
1262 using validator_type = std::identity;
1263 constexpr static std::string_view symbol{"rad"};
1264 };
1265
1266 struct celsius_t : coordinate_transform<kelvin_t, dilatation<std::ratio<1, 1>>, translation<-273.15L>>
1267 {
1268 constexpr static std::string_view symbol{"degC"};
1269 };
1270
1271 inline constexpr ampere_t ampere{};
1272 inline constexpr kilogram_t kilogram{};
1273 inline constexpr metre_t metre{};
1274 inline constexpr second_t second{};
1275 inline constexpr kelvin_t kelvin{};
1276 inline constexpr coulomb_t coulomb{};
1277 inline constexpr radian_t radian{};
1278
1279 inline constexpr celsius_t celsius{};
1280
1281 using milligram_t = micro<si::units::kilogram_t>;
1282 using gram_t = milli<si::units::kilogram_t>;
1283 using tonne_t = kilo<si::units::kilogram_t>;
1284 using kilotonne_t = mega<si::units::kilogram_t>;
1285
1286 inline constexpr milligram_t milligram{};
1287 inline constexpr gram_t gram{};
1288 inline constexpr tonne_t tonne{};
1289 inline constexpr kilotonne_t kilotonne{};
1290 }
1291
1292 template<std::floating_point T, class Arena=implicit_common_arena>
1293 using mass = physical_value<mass_space<T, Arena>, units::kilogram_t>;
1294
1295 template<std::floating_point T, class Arena=implicit_common_arena>
1296 using length = physical_value<length_space<T, Arena>, units::metre_t>;
1297
1298 template<std::floating_point T, class Arena=implicit_common_arena>
1299 using time_interval = physical_value<time_interval_space<T, Arena>, units::second_t>;
1300
1301 template<std::floating_point T, class Arena=implicit_common_arena>
1302 using temperature = physical_value<absolute_temperature_space<T, Arena>, units::kelvin_t>;
1303
1304 template<std::floating_point T, class Arena=implicit_common_arena>
1305 using temperature_celsius = physical_value<temperature_space<T, Arena>, units::celsius_t>;
1306
1307 template<std::floating_point T, class Arena=implicit_common_arena>
1308 using electrical_current = physical_value<electrical_current_space<T, Arena>, units::ampere_t>;
1309
1310 template<std::floating_point T, class Arena=implicit_common_arena>
1311 using angle = physical_value<angular_space<T, Arena>, units::radian_t>;
1312
1313 template<std::floating_point T, class Arena=implicit_common_arena>
1314 using width = physical_value<width_space<T, Arena>, units::metre_t>;
1315
1316 template<std::floating_point T, class Arena=implicit_common_arena>
1317 using height = physical_value<height_space<T, Arena>, units::metre_t>;
1318
1319 template<
1320 std::floating_point T,
1321 class Arena=implicit_common_arena,
1322 class Origin=implicit_affine_origin<time_space<T, Arena>>
1323 >
1324 using time
1325 = physical_value<
1326 time_space<T, Arena>,
1327 units::second_t,
1328 unit_defined_right_handed_basis<free_module_type_of_t<time_space<T, Arena>>, units::second_t>,
1329 Origin,
1330 std::identity
1331 >;
1332
1333 template<
1334 std::floating_point T,
1335 std::size_t D,
1336 class Arena = implicit_common_arena,
1337 basis_for<free_module_type_of_t<position_space<T, D, Arena>>> Basis = unit_defined_right_handed_basis<free_module_type_of_t<position_space<T, D, Arena>>, units::metre_t>,
1338 class Origin = implicit_affine_origin<position_space<T, D, Arena>>
1339 >
1340 using position = physical_value<position_space<T, D, Arena>, units::metre_t, Basis, Origin, std::identity>;
1341 }
1342
1343 // TO DO: see commnent above si namespace
1344 inline namespace non_si
1345 {
1346 inline namespace units
1347 {
1348 struct degree_t : coordinate_transform<si::units::radian_t, dilatation<ratio<std::intmax_t{180}, std::numbers::pi_v<long double>>>, translation<0>>
1349 {
1350 using is_unit = std::true_type;
1351 using validator_type = std::identity;
1352 constexpr static std::string_view symbol{"deg"};
1353 };
1354
1355 struct gradian_t : coordinate_transform<si::units::radian_t, dilatation<ratio<std::intmax_t{200}, std::numbers::pi_v<long double>>>, translation<0>>
1356 {
1357 using is_unit = std::true_type;
1358 using validator_type = std::identity;
1359 constexpr static std::string_view symbol{"gon"};
1360 };
1361
1362 inline constexpr degree_t degree{};
1363 inline constexpr gradian_t gradian{};
1364
1365 struct farenheight_t : coordinate_transform<si::units::celsius_t, dilatation<std::ratio<9, 5>>, translation<32.0L>>
1366 {
1367 using is_unit = std::true_type;
1368 constexpr static std::string_view symbol{"degF"};
1369 };
1370
1371 inline constexpr farenheight_t farenheight{};
1372
1373 struct foot_t : coordinate_transform<si::units::metre_t, dilatation<std::ratio<10000, 3048>>, translation<0>>
1374 {
1375 using is_unit = std::true_type;
1376 constexpr static std::string_view symbol{"ft"};
1377 };
1378
1379 inline constexpr foot_t foot{};
1380 }
1381
1382 template<std::floating_point T, class Arena=implicit_common_arena>
1383 using temperature_farenheight = physical_value<temperature_space<T, Arena>, units::farenheight_t>;
1384 }
1385
1386 template<convex_space C, physical_unit FromUnit, physical_unit ToUnit>
1388 {
1390 };
1391
1392 template<physical_unit Unit, class Rep, class Ratio, auto Trans>
1393 requires has_default_space_v<Unit, Rep> && (Trans == 0)
1395
1396 template<physical_unit Unit, class Rep>
1397 requires has_coordinate_transform_v<Unit>
1398 struct default_space<Unit, Rep> : default_space<root_transform_t<Unit>, Rep> {};
1399
1400 template<std::floating_point T>
1401 struct default_space<si::units::metre_t, T>
1402 {
1404 };
1405
1406 template<std::floating_point T>
1407 struct default_space<si::units::second_t, T>
1408 {
1410 };
1411
1412 template<std::floating_point T>
1413 struct default_space<si::units::kilogram_t, T>
1414 {
1416 };
1417
1418 template<std::floating_point T>
1419 struct default_space<si::units::radian_t, T>
1420 {
1422 };
1423
1424 template<std::floating_point T>
1425 struct default_space<si::units::kelvin_t, T>
1426 {
1428 };
1429
1430 template<std::floating_point T>
1431 struct default_space<si::units::ampere_t, T>
1432 {
1434 };
1435
1436 template<vector_space ValueSpace, physical_unit Unit, class Basis, class Origin, validator_for<ValueSpace> Validator>
1437 requires (dimension_of<ValueSpace> == 1)
1438 [[nodiscard]]
1440 {
1441 return {std::abs(q.value()), Unit{}};
1442 }
1443
1444 template<std::floating_point T, class Arena=implicit_common_arena>
1445 [[nodiscard]]
1446 constexpr T sin(physical_value<angular_space<T, Arena>, si::units::radian_t> theta)
1447 {
1448 return std::sin(theta.value());
1449 }
1450
1451 template<std::floating_point T, class Arena=implicit_common_arena>
1452 [[nodiscard]]
1453 constexpr T cos(physical_value<angular_space<T, Arena>, si::units::radian_t> theta)
1454 {
1455 return std::cos(theta.value());
1456 }
1457
1458 template<std::floating_point T, class Arena=implicit_common_arena>
1459 [[nodiscard]]
1460 constexpr T tan(physical_value<angular_space<T, Arena>, si::units::radian_t> theta)
1461 {
1462 return std::tan(theta.value());
1463 }
1464
1465 template<class Arena=implicit_common_arena, std::floating_point T>
1466 [[nodiscard]]
1467 constexpr physical_value<angular_space<T, Arena>, si::units::radian_t> asin(T x)
1468 {
1469 return {std::asin(x), si::units::radian};
1470 }
1471
1472 template<class Arena=implicit_common_arena, std::floating_point T>
1473 [[nodiscard]]
1474 constexpr physical_value<angular_space<T, Arena>, si::units::radian_t> acos(T x)
1475 {
1476 return {std::acos(x), si::units::radian};
1477 }
1478
1479 template<class Arena=implicit_common_arena, std::floating_point T>
1480 [[nodiscard]]
1481 constexpr physical_value<angular_space<T, Arena>, si::units::radian_t> atan(T x)
1482 {
1483 return {std::atan(x), si::units::radian};
1484 }
1485
1486 template<physical_unit Unit, class Rep, class Validator=typename Unit::validator_type>
1487 requires has_default_space_v<Unit, Rep>
1488 using quantity = physical_value<default_space_t<Unit, Rep>, Unit, unit_defined_right_handed_basis<free_module_type_of_t<default_space_t<Unit, Rep>>, Unit>, to_origin_type_t<default_space_t<Unit, Rep>, Unit>, Validator>;
1489
1490 template<
1491 convex_space ValueSpace,
1492 physical_unit Unit,
1493 validator_for<ValueSpace> Validator=typename Unit::validator_type
1494 >
1495 requires has_consistent_validator<ValueSpace, Validator>
1496 using dimensionless_quantity = physical_value<ValueSpace, Unit, unit_defined_right_handed_basis<free_module_type_of_t<ValueSpace>, Unit>, to_origin_type_t<ValueSpace, Unit>, Validator>;
1497
1498 template<std::floating_point Rep, class Arena=implicit_common_arena>
1499 using euclidean_1d_vector_quantity = dimensionless_quantity<euclidean_vector_space<Rep, 1, Arena>, no_unit_t, std::identity>;
1500
1501 template<std::floating_point Rep, class Arena=implicit_common_arena>
1502 using euclidean_half_line_quantity = dimensionless_quantity<euclidean_half_space<Rep, Arena>, no_unit_t>;
1503}
1504
1505namespace sequoia::maths
1506{
1507 using namespace physics;
1508
1509 template<
1510 convex_space ValueSpaceFrom,
1511 physical_unit UnitFrom,
1512 basis_for<free_module_type_of_t<ValueSpaceFrom>> BasisFrom,
1513 class OriginFrom,
1514 validator_for<ValueSpaceFrom> ValidatorFrom,
1515 convex_space ValueSpaceTo,
1516 basis_for<free_module_type_of_t<ValueSpaceTo>> BasisTo,
1517 physical_unit UnitTo,
1518 class OriginTo,
1519 validator_for<ValueSpaceTo> ValidatorTo
1520 >
1521 requires std::same_as<root_transform_unit_t<UnitFrom>, root_transform_unit_t<UnitTo>>
1523 physical_value<ValueSpaceFrom, UnitFrom, BasisFrom, OriginFrom, ValidatorFrom>,
1524 physical_value<ValueSpaceTo, UnitTo, BasisTo, OriginTo, ValidatorTo>
1525 >
1526 {
1527 using value_type = commutative_ring_type_of_t<ValueSpaceFrom>;
1528 using from_units_type = UnitFrom;
1530 using to_units_type = UnitTo;
1532 using transform_type = product_t<root_transform_t<UnitTo>, inverse_t<root_transform_t<UnitFrom>>>;
1533
1534 constexpr static auto to_displacement() noexcept {
1535 if constexpr(free_module<ValueSpaceFrom>)
1536 return value_type{};
1537 else
1538 return transform_type::translation_type::displacement;
1539 };
1540
1541 [[nodiscard]]
1542 constexpr to_type operator()(const from_type& pv)
1543 {
1544 return {
1545 utilities::to_array(
1546 pv.values(),
1547 [](value_type v) -> value_type {
1548 using ratio_type = transform_type::dilatation_type::ratio_type;
1549
1550 return static_cast<value_type>((v * ratio_type::num / ratio_type::den) + to_displacement());
1551 }
1552 ),
1553 to_units_type{}
1554 };
1555 }
1556 };
1557}
1558
1559template<
1563 class Origin,
1564 sequoia::maths::validator_for<ValueSpace> Validator
1565>
1566struct std::formatter<sequoia::physics::physical_value<ValueSpace, Unit, Basis, Origin, Validator>>
1567{
1569 constexpr static auto dimension{sequoia::maths::dimension_of<ValueSpace> };
1570
1571 constexpr auto parse(auto& ctx)
1572 {
1573 return ctx.begin();
1574 }
1575
1576 auto format(const physical_value_type& v, auto& ctx) const
1577 requires (dimension == 1)
1578 {
1579 if constexpr(sequoia::physics::has_symbol_v<Unit>)
1580 return std::format_to(ctx.out(), "{} {}", v.value(), Unit::symbol);
1581 else
1582 return std::format_to(ctx.out(), "{}", v.value());
1583 }
1584
1585 // TO DO: reinstate when formatting is working for spans
1586 /*auto format(const physical_value_type& v, auto& ctx) const
1587 requires (dimension > 1)
1588 {
1589 if constexpr(sequoia::physics::has_symbol_v<Unit>)
1590 return std::format_to(ctx.out(), "{} {}", v.values(), Unit::symbol);
1591 else
1592 return std::format_to(ctx.out(), "{}", v.values());
1593 }*/
1594};
1595
Definition: Spaces.hpp:1321
Definition: PhysicalValues.hpp:497
\brieft A concept for arithmetic types
Definition: Concepts.hpp:81
A concept to determine if a basis is appropriate for a particular free module.
Definition: Spaces.hpp:692
concept for convex spaces
Definition: Spaces.hpp:518
concept for a free module, implicitly understood to be over a commutative ring.
Definition: Spaces.hpp:477
concept to check if a validator is compatible with a convex space.
Definition: Spaces.hpp:749
Definition: PhysicalValuesDetails.hpp:44
Definition: Spaces.hpp:1955
Definition: Spaces.hpp:907
Definition: Spaces.hpp:896
Specialization for units, such as degrees Celsius, for which the corresponding quantity cannot be inv...
Definition: PhysicalValues.hpp:66
Helper to generate the dual of a space, taking into account that the dual of the dual may be related ...
Definition: Spaces.hpp:1109
Primary class template for defining duals.
Definition: Spaces.hpp:1041
A validator for the half line.
Definition: Spaces.hpp:776
Definition: Spaces.hpp:665
A generic interval validator for floating-point types.
Definition: Spaces.hpp:800
Definition: Ratio.hpp:18
Definition: PhysicalValues.hpp:834
Definition: PhysicalValues.hpp:864
Definition: PhysicalValues.hpp:769
Definition: PhysicalValues.hpp:142
Definition: PhysicalValues.hpp:129
Definition: PhysicalValues.hpp:370
Definition: PhysicalValues.hpp:453
Definition: PhysicalValues.hpp:1000
Definition: PhysicalValues.hpp:680
Definition: PhysicalValues.hpp:265
Definition: PhysicalValues.hpp:857
Definition: PhysicalValues.hpp:1131
Definition: PhysicalValues.hpp:1145
Definition: PhysicalValues.hpp:888
Definition: PhysicalValues.hpp:887
Definition: PhysicalValues.hpp:261
Definition: PhysicalValues.hpp:912
Definition: PhysicalValues.hpp:962
Definition: PhysicalValues.hpp:1064
Definition: PhysicalValues.hpp:1197
Definition: PhysicalValues.hpp:872
Definition: PhysicalValues.hpp:824
Definition: PhysicalValues.hpp:1204
Definition: PhysicalValues.hpp:1183
Definition: PhysicalValues.hpp:1190
Definition: PhysicalValues.hpp:53
Definition: PhysicalValues.hpp:1349
Definition: PhysicalValues.hpp:1366
Definition: PhysicalValues.hpp:1374
Definition: PhysicalValues.hpp:1356
Definition: PhysicalValues.hpp:802
Definition: PhysicalValues.hpp:791
Definition: PhysicalValues.hpp:383
Definition: PhysicalValues.hpp:813
Definition: PhysicalValues.hpp:908
Definition: PhysicalValues.hpp:950
Definition: PhysicalValues.hpp:19
Definition: PhysicalValues.hpp:110
Definition: PhysicalValues.hpp:136
Definition: PhysicalValues.hpp:844
Definition: PhysicalValues.hpp:1093
Definition: PhysicalValues.hpp:921
Definition: PhysicalValues.hpp:756
Definition: PhysicalValues.hpp:762
Definition: PhysicalValues.hpp:750
Definition: PhysicalValues.hpp:714
Definition: PhysicalValues.hpp:744
Definition: PhysicalValues.hpp:720
Definition: PhysicalValues.hpp:738
Definition: PhysicalValues.hpp:732
Definition: PhysicalValues.hpp:1218
Definition: PhysicalValues.hpp:1267
Definition: PhysicalValues.hpp:1253
Definition: PhysicalValues.hpp:1246
Definition: PhysicalValues.hpp:1225
Definition: PhysicalValues.hpp:1232
Definition: PhysicalValues.hpp:1260
Definition: PhysicalValues.hpp:1239
Definition: PhysicalValues.hpp:994
Definition: PhysicalValues.hpp:894
Definition: PhysicalValues.hpp:902
Definition: PhysicalValues.hpp:309
Definition: PhysicalValues.hpp:351
Definition: PhysicalValues.hpp:268
Definition: PhysicalValues.hpp:938
Definition: PhysicalValues.hpp:982
Definition: PhysicalValues.hpp:258
Definition: PhysicalValues.hpp:45
Definition: PhysicalValues.hpp:882
Definition: PhysicalValues.hpp:881
Detects value_type.
Definition: Iterator.hpp:111