From c7303cc5fb32a94bf0e3adb5e7257491e46a7ef3 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 5 Nov 2024 19:09:16 +0100 Subject: [PATCH] refactor: representation concepts refactored + some quantities switched to complex --- .../framework/representation_concepts.h | 107 ++++++++++++++---- .../mp-units/systems/isq/electromagnetism.h | 6 +- test/static/concepts_test.cpp | 7 +- test/static/isq_test.cpp | 6 +- test/static/quantity_test.cpp | 11 +- 5 files changed, 107 insertions(+), 30 deletions(-) diff --git a/src/core/include/mp-units/framework/representation_concepts.h b/src/core/include/mp-units/framework/representation_concepts.h index 3a19398ed..d802163d7 100644 --- a/src/core/include/mp-units/framework/representation_concepts.h +++ b/src/core/include/mp-units/framework/representation_concepts.h @@ -63,37 +63,106 @@ MP_UNITS_EXPORT enum class quantity_character : std::int8_t { scalar, complex, v namespace detail { -template -concept CommonTypeWith = - std::same_as, std::common_type_t> && - std::constructible_from, T> && std::constructible_from, U>; +template +concept WeaklyRegular = std::copyable && std::equality_comparable; -template -concept ScalableNumber = - std::regular_invocable, T, U> && std::regular_invocable, T, U>; +template +concept Scalar = is_scalar; template -concept CastableNumber = CommonTypeWith && ScalableNumber>; +concept Complex = is_complex; -// TODO Fix it according to sudo_cast implementation template -concept Scalable = - CastableNumber || (requires { typename wrapped_type_t; } && CastableNumber> && - ScalableNumber, std::intmax_t>>); +concept Vector = is_vector; template -concept WeaklyRegular = std::copyable && std::equality_comparable; +concept Tensor = is_tensor; + +template +concept IsOfCharacter = + (Ch == quantity_character::scalar && is_scalar) || (Ch == quantity_character::complex && is_complex) || + (Ch == quantity_character::vector && is_vector) || (Ch == quantity_character::tensor && is_tensor); +; + +template +using scaling_factor_type_t = conditional, long double, std::intmax_t>; + +template +concept ScalarRepresentation = Scalar && WeaklyRegular && requires(T a, T b, scaling_factor_type_t f) { + // scaling + { a* f } -> Scalar; + { f* a } -> Scalar; + { a / f } -> Scalar; + + // scalar operations + { a + b } -> Scalar; + { a - b } -> Scalar; + { a* b } -> Scalar; + { a / b } -> Scalar; +}; + +template +concept ComplexRepresentation = Complex && WeaklyRegular && requires(T a, T b, scaling_factor_type_t f) { + // scaling + // TODO The below conversion to `T` is an exception compared to other representation types + // `std::complex` * `U` do not work, but `std::complex` is convertible from `U` + // Maybe expose this as a customization point? + { a* T(f) } -> Complex; + { T(f) * a } -> Complex; + { a / T(f) } -> Complex; + + // complex operations + { a + b } -> Complex; + { a - b } -> Complex; + { a* b } -> Complex; + { a / b } -> Complex; + // TBD + // { re(a) } -> Scalar; + // { im(a) } -> Scalar; + // { mod(a) } -> Scalar; + // { arg(a) } -> Scalar; + // { conj(a) } -> Complex; +}; + +// TODO how to check for a complex(Scalar, Scalar) -> Complex? + +template +concept VectorRepresentation = Vector && WeaklyRegular && requires(T a, T b, scaling_factor_type_t f) { + // scaling + { a* f } -> Vector; + { f* a } -> Vector; + { a / f } -> Vector; + + // vector operations + { a + b } -> Vector; + { a - b } -> Vector; + // TBD + // { norm(a) } -> Scalar; + // { zero_vector() } -> Vector; + // { unit_vector(a) } -> Vector; + // { scalar_product(a, b) } -> Scalar; + // { vector_product(a, b) } -> Vector; + // { tensor_product(a, b) } -> Tensor2; + // divergence(a) + // rotation(a) +}; + +template +concept TensorRepresentation = Tensor && WeaklyRegular; // && requires(T a, T b) { + // TBD + // tensor operations + // { tensor_product(a, b) } -> Tensor4; + // { inner_product(a, b) } -> Tensor2; + // { scalar_product(a, b) } -> Scalar; +//}; } // namespace detail MP_UNITS_EXPORT template -concept Representation = - (is_scalar || is_complex || is_vector || is_tensor) && detail::WeaklyRegular && detail::Scalable; +concept Representation = detail::ScalarRepresentation || detail::ComplexRepresentation || + detail::VectorRepresentation || detail::TensorRepresentation; MP_UNITS_EXPORT template -concept RepresentationOf = - Representation && - ((Ch == quantity_character::scalar && is_scalar) || (Ch == quantity_character::complex && is_complex) || - (Ch == quantity_character::vector && is_vector) || (Ch == quantity_character::tensor && is_tensor)); +concept RepresentationOf = detail::IsOfCharacter && Representation; } // namespace mp_units diff --git a/src/systems/include/mp-units/systems/isq/electromagnetism.h b/src/systems/include/mp-units/systems/isq/electromagnetism.h index 96adc09fa..43988465b 100644 --- a/src/systems/include/mp-units/systems/isq/electromagnetism.h +++ b/src/systems/include/mp-units/systems/isq/electromagnetism.h @@ -122,8 +122,8 @@ inline constexpr auto instantaneous_power = electromagnetism_power; QUANTITY_SPEC(resistance, voltage / electric_current); QUANTITY_SPEC(conductance, inverse(resistance)); QUANTITY_SPEC(phase_difference, phase_angle); -QUANTITY_SPEC(electric_current_phasor, electric_current); -QUANTITY_SPEC(voltage_phasor, voltage); +QUANTITY_SPEC(electric_current_phasor, electric_current, quantity_character::complex); +QUANTITY_SPEC(voltage_phasor, voltage, quantity_character::complex); QUANTITY_SPEC(impedance, voltage_phasor / electric_current_phasor); inline constexpr auto complex_impedance = impedance; QUANTITY_SPEC(resistance_to_alternating_current, impedance); @@ -139,7 +139,7 @@ QUANTITY_SPEC(loss_factor, dimensionless, inverse(quality_factor)); QUANTITY_SPEC(loss_angle, angular_measure); QUANTITY_SPEC(active_power, isq::power, inverse(period) * (instantaneous_power * time)); QUANTITY_SPEC(complex_power, voltage_phasor* electric_current_phasor); // separate kind -QUANTITY_SPEC(apparent_power, complex_power); +QUANTITY_SPEC(apparent_power, complex_power, quantity_character::scalar); QUANTITY_SPEC(power_factor, dimensionless, active_power / apparent_power); QUANTITY_SPEC(reactive_power, isq::mass* pow<2>(isq::length) / pow<3>(isq::time)); // separate kind QUANTITY_SPEC(non_active_power, pow<1, 2>(pow<2>(apparent_power))); // separate kind diff --git a/test/static/concepts_test.cpp b/test/static/concepts_test.cpp index d43978287..c79e8851e 100644 --- a/test/static/concepts_test.cpp +++ b/test/static/concepts_test.cpp @@ -37,9 +37,10 @@ import std; #if MP_UNITS_HOSTED template -constexpr bool mp_units::is_scalar> = true; +constexpr bool mp_units::is_complex> = true; #endif + namespace { using namespace mp_units; @@ -268,7 +269,9 @@ static_assert(Representation); static_assert(!Representation); static_assert(!Representation>); #if MP_UNITS_HOSTED +static_assert(Representation>); static_assert(Representation>); +static_assert(Representation>); static_assert(!Representation); static_assert(!Representation); #endif @@ -279,7 +282,7 @@ static_assert(RepresentationOf); static_assert(!RepresentationOf); static_assert(!RepresentationOf, quantity_character::scalar>); #if MP_UNITS_HOSTED -static_assert(RepresentationOf, quantity_character::scalar>); +static_assert(RepresentationOf, quantity_character::complex>); static_assert(!RepresentationOf); static_assert(!RepresentationOf); #endif diff --git a/test/static/isq_test.cpp b/test/static/isq_test.cpp index 6f0e7b179..7d7fef844 100644 --- a/test/static/isq_test.cpp +++ b/test/static/isq_test.cpp @@ -303,8 +303,8 @@ static_assert(verify(isq::instantaneous_power, scalar, W)); static_assert(verify(isq::resistance, scalar, Ω)); static_assert(verify(isq::conductance, scalar, S)); static_assert(verify(isq::phase_difference, scalar, rad)); -static_assert(verify(isq::electric_current_phasor, scalar, A)); -static_assert(verify(isq::voltage_phasor, scalar, V)); +static_assert(verify(isq::electric_current_phasor, complex, A)); +static_assert(verify(isq::voltage_phasor, complex, V)); static_assert(verify(isq::impedance, scalar, Ω)); static_assert(verify(isq::complex_impedance, scalar, Ω)); static_assert(verify(isq::resistance_to_alternating_current, scalar, Ω)); @@ -321,7 +321,7 @@ static_assert(verify(isq::loss_angle, scalar, rad)); static_assert(verify(isq::active_power, scalar, W)); static_assert(verify(isq::apparent_power, scalar, V* A)); static_assert(verify(isq::power_factor, scalar, one)); -static_assert(verify(isq::complex_power, scalar, V* A)); +static_assert(verify(isq::complex_power, complex, V* A)); static_assert(verify(isq::reactive_power, scalar, V* A)); static_assert(verify(isq::non_active_power, scalar, V* A)); static_assert(verify(isq::active_energy, scalar, J, W* h)); diff --git a/test/static/quantity_test.cpp b/test/static/quantity_test.cpp index e175f25c7..276a70e7c 100644 --- a/test/static/quantity_test.cpp +++ b/test/static/quantity_test.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -46,7 +47,7 @@ import std; #if MP_UNITS_HOSTED template -constexpr bool mp_units::is_scalar> = true; +constexpr bool mp_units::is_complex> = true; #endif template<> @@ -282,8 +283,12 @@ static_assert((1. * rad + 1. * deg).in(deg) != 0 * deg); #if MP_UNITS_HOSTED using namespace std::complex_literals; -static_assert(((2. + 1i) * V).in(mV).numerical_value_in(mV) == 2000. + 1000i); -static_assert(((2. + 1i) * V).in(mV).numerical_value_in(V) == 2. + 1i); +static_assert(((2.f + 1if) * isq::voltage_phasor[V]).in(mV).numerical_value_in(mV) == 2000.f + 1000if); +static_assert(((2.f + 1if) * isq::voltage_phasor[V]).in(mV).numerical_value_in(V) == 2.f + 1if); +static_assert(((2. + 1i) * isq::voltage_phasor[V]).in(mV).numerical_value_in(mV) == 2000. + 1000i); +static_assert(((2. + 1i) * isq::voltage_phasor[V]).in(mV).numerical_value_in(V) == 2. + 1i); +static_assert(((2.L + 1il) * isq::voltage_phasor[V]).in(mV).numerical_value_in(mV) == 2000.L + 1000il); +static_assert(((2.L + 1il) * isq::voltage_phasor[V]).in(mV).numerical_value_in(V) == 2.L + 1il); #endif template typename Q>