mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-29 18:07:16 +02:00
refactor: representation concepts refactored + some quantities switched to complex
This commit is contained in:
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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>
|
||||
|
Reference in New Issue
Block a user