mpusz / mp-units

The quantities and units library for C++
https://mpusz.github.io/mp-units/
MIT License
1.09k stars 87 forks source link

Provide proper support for complex quantities #618

Open mpusz opened 1 month ago

mpusz commented 1 month ago

For example the following should be supported (as much as possible):

template<template<auto, typename> typename Q>
concept complex_operations =
  requires(Q<isq::voltage_phasor[si::kilo<si::volt>], std::complex<double>> voltage_phasor,
           Q<isq::electric_current_phasor[si::ampere], std::complex<double>> electric_current_phasor,
           Q<isq::phase_angle[si::radian], double> phase_angle,
           Q<isq::complex_power[si::kilo<si::volt> * si::ampere], std::complex<double>> complex_power,
           Q<isq::apparent_power[si::kilo<si::volt> * si::ampere], double> apparent_power,
           Q<isq::active_power[si::watt], double> active_power,
           Q<isq::reactive_power[iec::volt_ampere_reactive_power], double> reactive_power,
           Q<isq::power_factor[one], double> power_factor) {
    // valid operations
    { voltage_phasor* conj(electric_current_phasor) } -> std::convertible_to<decltype(complex_power)>;
    { complex(active_power, reactive_power) } -> std::convertible_to<decltype(complex_power)>;
    { mod(complex_power) } -> std::convertible_to<decltype(apparent_power)>;
    { re(complex_power) } -> std::convertible_to<decltype(active_power)>;
    { im(complex_power) } -> std::convertible_to<decltype(reactive_power)>;
    { arg(complex_power) } -> std::convertible_to<decltype(phase_angle)>;
    { active_power / apparent_power } -> std::convertible_to<decltype(power_factor)>;
    { reactive_power.in(si::volt * si::ampere) };  // has to work according to ISO 80000
    // invalid operations
    requires !requires { active_power + reactive_power; };
    requires !requires { complex(apparent_power, reactive_power); } -> std::convertible_to<decltype(complex_power)>;  // ?
    requires !requires { complex(reactive_power, active_power); } -> std::convertible_to<decltype(complex_power)>;
    requires !requires { complex_power = apparent_power; };
    requires !requires { complex_power = active_power; };
    requires !requires { complex_power = reactive_power; };
    requires !requires { active_power = complex_power; };
    requires !requires { active_power = reactive_power; };
    requires !requires { active_power = apparent_power; };  // ?
    requires !requires { reactive_power = complex_power; };
    requires !requires { reactive_power = active_power; };
    requires !requires { reactive_power = apparent_power; };
    requires !requires { complex_power.in(iec::volt_ampere_reactive_power); };
    requires !requires { active_power.in(iec::volt_ampere_reactive_power); };
    requires !requires { apparent_power.in(iec::volt_ampere_reactive_power); };
    requires !requires { complex_power.in(si::watt); };
    requires !requires { apparent_power.in(si::watt); };
    // probably impossible to enforce
    requires !requires { active_power.in(si::watt * si::ampere); };
  };

static_assert(complex_operations<quantity>);
AlexVermette-Eaton commented 1 month ago

This bug might be problematic in Clang (not present in MSVC). https://github.com/llvm/llvm-project/issues/55370