refactor: representation concepts refactored + some quantities switched to complex

This commit is contained in:
Mateusz Pusz
2024-11-05 19:09:16 +01:00
parent 1595fca9a9
commit c7303cc5fb
5 changed files with 112 additions and 35 deletions

View File

@ -63,37 +63,106 @@ MP_UNITS_EXPORT enum class quantity_character : std::int8_t { scalar, complex, v
namespace detail {
template<typename T, typename U>
concept CommonTypeWith =
std::same_as<std::common_type_t<T, U>, std::common_type_t<U, T>> &&
std::constructible_from<std::common_type_t<T, U>, T> && std::constructible_from<std::common_type_t<T, U>, U>;
template<typename T, typename U = T>
concept ScalableNumber =
std::regular_invocable<std::multiplies<>, T, U> && std::regular_invocable<std::divides<>, T, U>;
template<typename T>
concept CastableNumber = CommonTypeWith<T, std::intmax_t> && ScalableNumber<std::common_type_t<T, std::intmax_t>>;
// TODO Fix it according to sudo_cast implementation
template<typename T>
concept Scalable =
CastableNumber<T> || (requires { typename wrapped_type_t<T>; } && CastableNumber<wrapped_type_t<T>> &&
ScalableNumber<T, std::common_type_t<wrapped_type_t<T>, std::intmax_t>>);
template<typename T>
concept WeaklyRegular = std::copyable<T> && std::equality_comparable<T>;
template<typename T>
concept Scalar = is_scalar<T>;
template<typename T>
concept Complex = is_complex<T>;
template<typename T>
concept Vector = is_vector<T>;
template<typename T>
concept Tensor = is_tensor<T>;
template<typename T, quantity_character Ch>
concept IsOfCharacter =
(Ch == quantity_character::scalar && is_scalar<T>) || (Ch == quantity_character::complex && is_complex<T>) ||
(Ch == quantity_character::vector && is_vector<T>) || (Ch == quantity_character::tensor && is_tensor<T>);
;
template<typename T>
using scaling_factor_type_t = conditional<treat_as_floating_point<T>, long double, std::intmax_t>;
template<typename T>
concept ScalarRepresentation = Scalar<T> && WeaklyRegular<T> && requires(T a, T b, scaling_factor_type_t<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<typename T>
concept ComplexRepresentation = Complex<T> && WeaklyRegular<T> && requires(T a, T b, scaling_factor_type_t<T> f) {
// scaling
// TODO The below conversion to `T` is an exception compared to other representation types
// `std::complex<T>` * `U` do not work, but `std::complex<T>` 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<typename T>
concept VectorRepresentation = Vector<T> && WeaklyRegular<T> && requires(T a, T b, scaling_factor_type_t<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<T>() } -> 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<typename T>
concept TensorRepresentation = Tensor<T> && WeaklyRegular<T>; // && 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<typename T>
concept Representation =
(is_scalar<T> || is_complex<T> || is_vector<T> || is_tensor<T>) && detail::WeaklyRegular<T> && detail::Scalable<T>;
concept Representation = detail::ScalarRepresentation<T> || detail::ComplexRepresentation<T> ||
detail::VectorRepresentation<T> || detail::TensorRepresentation<T>;
MP_UNITS_EXPORT template<typename T, quantity_character Ch>
concept RepresentationOf =
Representation<T> &&
((Ch == quantity_character::scalar && is_scalar<T>) || (Ch == quantity_character::complex && is_complex<T>) ||
(Ch == quantity_character::vector && is_vector<T>) || (Ch == quantity_character::tensor && is_tensor<T>));
concept RepresentationOf = detail::IsOfCharacter<T, Ch> && Representation<T>;
} // namespace mp_units

View File

@ -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

View File

@ -37,9 +37,10 @@ import std;
#if MP_UNITS_HOSTED
template<typename T>
constexpr bool mp_units::is_scalar<std::complex<T>> = true;
constexpr bool mp_units::is_complex<std::complex<T>> = true;
#endif
namespace {
using namespace mp_units;
@ -268,7 +269,9 @@ static_assert(Representation<double>);
static_assert(!Representation<bool>);
static_assert(!Representation<std::optional<int>>);
#if MP_UNITS_HOSTED
static_assert(Representation<std::complex<float>>);
static_assert(Representation<std::complex<double>>);
static_assert(Representation<std::complex<long double>>);
static_assert(!Representation<std::string>);
static_assert(!Representation<std::chrono::seconds>);
#endif
@ -279,7 +282,7 @@ static_assert(RepresentationOf<double, quantity_character::scalar>);
static_assert(!RepresentationOf<bool, quantity_character::scalar>);
static_assert(!RepresentationOf<std::optional<int>, quantity_character::scalar>);
#if MP_UNITS_HOSTED
static_assert(RepresentationOf<std::complex<double>, quantity_character::scalar>);
static_assert(RepresentationOf<std::complex<double>, quantity_character::complex>);
static_assert(!RepresentationOf<std::chrono::seconds, quantity_character::scalar>);
static_assert(!RepresentationOf<std::string, quantity_character::scalar>);
#endif

View File

@ -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));

View File

@ -24,6 +24,7 @@
#include <mp-units/bits/hacks.h>
#include <mp-units/ext/fixed_string.h>
#include <mp-units/ext/type_traits.h>
#include <mp-units/systems/isq/electromagnetism.h>
#include <mp-units/systems/isq/mechanics.h>
#include <mp-units/systems/isq/space_and_time.h>
#include <mp-units/systems/si.h>
@ -46,7 +47,7 @@ import std;
#if MP_UNITS_HOSTED
template<typename T>
constexpr bool mp_units::is_scalar<std::complex<T>> = true;
constexpr bool mp_units::is_complex<std::complex<T>> = 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<template<auto, typename> typename Q>