Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Division of vector quantities? #409

Open
mpusz opened this issue Dec 17, 2022 · 6 comments
Open

Division of vector quantities? #409

mpusz opened this issue Dec 17, 2022 · 6 comments
Labels
design Design-related discussion
Milestone

Comments

@mpusz
Copy link
Owner

mpusz commented Dec 17, 2022

Acceleration is a change of velocity over time (a = V / t). Acceleration and velocity are defined as vector quantities, whereas time is scalar.

If I want to calculate t = V / a, it is impossible if representation types of a and V are linear algebra vectors as it is impossible to divide two vectors. Additionally, the characteristics of a derived quantity of velocity divided by acceleration is vector as well so it will not allow assigning to a scalar time.

This is a simple and common case but also so complicated now after #405. How to handle that?

@mpusz mpusz mentioned this issue Dec 17, 2022
18 tasks
@JohelEGP
Copy link
Collaborator

If it's not mathematically defined in the first place, there's nothing we can do.

ISO 80000-6 actually has many quantities that are a coefficient of two vector quantities:

inline constexpr auto permittivity            = defn<"𝜀", "𝘿 = 𝜀𝙀", electric_flux_density("𝘿"), electric_field_strength("𝙀")>();
inline constexpr auto electric_susceptibility = defn<"𝜒", "𝙋 = 𝜀₀𝜒𝙀", electric_polarization("𝙋"), electric_constant("𝜀₀"), electric_field_strength("𝙀")>();
inline constexpr auto permeability          = defn<"𝜇", "𝘽 = 𝜇𝙃", magnetic_flux_density("𝘽"), magnetic_field_strength("𝙃")>();
inline constexpr auto magnetic_susceptibility = defn<"𝜅", "𝙈 = 𝜅𝙃", magnetization("𝙈"), magnetic_field_strength("𝙃")>();
inline constexpr auto conductivity = defn<"𝜎", "𝙅 = 𝜎𝙀", electric_current_density("𝙅"), electric_field_strength("𝙀")>();

@mpusz
Copy link
Owner Author

mpusz commented Dec 17, 2022

Well, I think that an LA vector is not the only way to model a vector quantity, and maybe not even a good choice at all. I can imagine a type like vector<Rep, Direction> where direction can be any coordinate system specified by the user. For such a type, a division may be defined, assuming that the Direction is the same for both objects.

Maybe we should provide such a type in the library?

@JohelEGP
Copy link
Collaborator

Although I haven't gotten far using it, at some point I made something like that:

template<class Id, units::Dimension D> struct linear_dimension : units::kind<linear_dimension<Id, D>, D> { };
template<class Id, units::Dimension D> struct coordinate
  : units::point_kind<coordinate<Id, D>, linear_dimension<Id, D>> { };

// Cartesian coordinate systems

struct x;
struct y;
struct z;

export template<class D, class U, class R> using x_dimension = units::quantity_kind<linear_dimension<x, D>, U, R>;
export template<class D, class U, class R> using y_dimension = units::quantity_kind<linear_dimension<y, D>, U, R>;
export template<class D, class U, class R> using z_dimension = units::quantity_kind<linear_dimension<z, D>, U, R>;

export template<class D, class U, class R> using x_coordinate = units::quantity_point_kind<coordinate<x, D>, U, R>;
export template<class D, class U, class R> using y_coordinate = units::quantity_point_kind<coordinate<y, D>, U, R>;
export template<class D, class U, class R> using z_coordinate = units::quantity_point_kind<coordinate<z, D>, U, R>;

export template<units::Dimension D, units::UnitOf<D> U, units::Representation R> struct cartesian_size3d {
  using x_type        = x_dimension<D, U, R>;
  using y_type        = y_dimension<D, U, R>;
  using z_type        = z_dimension<D, U, R>;
  using quantity_type = units::quantity<D, U, R>;
  using dimension     = D;
  using unit          = U;
  using rep           = R;

  x_type x;
  y_type y;
  z_type z;

  template<class D2, class U2, class R2>
    requires std::convertible_to<x_type, x_dimension<D2, U2, R2>>
  [[nodiscard]] constexpr explicit(false) operator cartesian_size3d<D2, U2, R2>() const { return {x, y, z}; }

  template<class D2, class U2, class R2> [[nodiscard]] constexpr bool operator==(const cartesian_size3d<D2, U2, R2>& r)
    const requires std::equality_comparable_with<x_type, x_dimension<D2, U2, R2>> {
    return x == r.x and y == r.y and z == r.z;
  }

  // clang-format off
  constexpr cartesian_size3d& operator+=(const x_type& r) requires requires { x += r; } { x += r; return *this; }
  constexpr cartesian_size3d& operator+=(const y_type& r) requires requires { y += r; } { y += r; return *this; }
  constexpr cartesian_size3d& operator+=(const z_type& r) requires requires { z += r; } { z += r; return *this; }

  constexpr cartesian_size3d& operator-=(const x_type& r) requires requires { x -= r; } { x -= r; return *this; }
  constexpr cartesian_size3d& operator-=(const y_type& r) requires requires { y -= r; } { y -= r; return *this; }
  constexpr cartesian_size3d& operator-=(const z_type& r) requires requires { z -= r; } { z -= r; return *this; }

  constexpr cartesian_size3d& operator%=(const auto& r) requires requires { x %= r; } { x %= r; return *this; }
  constexpr cartesian_size3d& operator%=(const auto& r) requires requires { y %= r; } { y %= r; return *this; }
  constexpr cartesian_size3d& operator%=(const auto& r) requires requires { z %= r; } { z %= r; return *this; }
  // clang-format on

  template<class D2, class U2, class R2> constexpr cartesian_size3d&
  operator%=(const cartesian_size3d<D2, U2, R2>& r) requires(requires { x %= r.x, y %= r.y, z %= r.z; }) {
    x %= r.x;
    y %= r.y;
    z %= r.z;
    return *this;
  }

  constexpr cartesian_size3d& operator/=(const auto& r) requires(requires { x /= r, y /= r, z /= r; }) {
    x /= r;
    y /= r;
    z /= r;
    return *this;
  }

  constexpr cartesian_size3d& operator*=(const auto& r) requires(requires { x *= r, y *= r, z *= r; }) {
    x *= r;
    y *= r;
    z *= r;
    return *this;
  }

  template<class D2, class U2, class R2> [[nodiscard]] friend constexpr specialization_of<cartesian_size3d> auto
  operator+(const x_dimension<D2, U2, R2>& l, const cartesian_size3d& r) requires(requires { l + r.x; }) {
    return jegp::cartesian_size3d{l + r.x, r.y, r.z};
  }
};

Even for the single use case of Cartesian coordinate system, it takes effort to specify.

@burnpanck
Copy link
Contributor

Is there any other concept than the linear algebra concept of vectors? If so, there may be a need to clarify the concept of a "vector quantity", as I do not know anything else than linear algebra.

With that, the following is simply not true:

Additionally, the characteristics of a derived quantity of velocity divided by acceleration is vector as well so it will not allow assigning to a scalar time.

Instead, the general division between two vectors is mathematically undefined. However, the expression V / a is well defined for projections of the two vectors onto a chosen axis, which is a scalar. Therefore, the result is in fact a scalar.

However, In the case 𝘿 = 𝜀𝙀, 𝜀 may be a tensor, and things can become much more complicated. Still, an experimentalist may determine 𝜀 using a hand full of measurements of 𝘿 and 𝙀. They should be able to express the relevant computation using mp-units, which may involve both vectors of 𝙀 represented using an LA vector type, as well as scalar projections represented using a scalar representation (and either of them can additionally be complex, if we talk about AC-characteristics).

My gut feeling is thus that, maybe it would be best to simply leave the scalar/vector characteristic to the representation type.

@JohelEGP
Copy link
Collaborator

JohelEGP commented Jan 2, 2023

My gut feeling is thus that, maybe it would be best to simply leave the scalar/vector characteristic to the representation type.

That makes sense. One argument raised by @mpusz is that int can be both a vector and a scalar. But of course, int can also be milliseconds or student ID. In that sense, we should leave it to the user to use a wrapper over int that represents a vector if that's what the user wants.

@mpusz
Copy link
Owner Author

mpusz commented Jan 2, 2023

Is there any other concept than the linear algebra concept of vectors? If so, there may be a need to clarify the concept of a "vector quantity", as I do not know anything else than linear algebra.

As I stated in #409 (comment) I think that we could introduce a physical quantities vector<Rep, Direction> type where a direction would be a policy type that specifies a behavior (i.e. compile-time 2D, 3D, or maybe even runtime specified direction). For example, glide_computer could be rewritten in terms of vectors quantities where we specify that distance, height, sink_rate, etc are position_vectors over the different axis.

@mpusz mpusz added the design Design-related discussion label Jun 24, 2023
@mpusz mpusz added this to the v2.4.0 milestone Jun 22, 2024
@mpusz mpusz modified the milestones: v2.4.0, v2.5.0 Oct 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
design Design-related discussion
Projects
None yet
Development

No branches or pull requests

3 participants