Experience return on writing a linear algebra plugin; and other exploration #823
FrancoisCarouge
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
TL;DR
Linear Algebra Plugin
I author a highly experimental linear algebra library. I used my library vector type as the backend representation for quantity. A vehicle I used for this exploration has been mp-units' Using a Linear Algebra Library guide and related references on quantity representation and compatibility plugins. I share my learnings and opinions in this comment.
My library is not Eigen, Blaze, or GLM and so I wrote the plugin including the CPO, specialization support:
magnitudefunction.operator*.representation_canonical_typeCPO specialization.representation_underlying_typeCPO specialization.The effort was not trivial, though I would qualify it as acceptable for a library writer, eventually resolved with the help from the mp-units examples, compiler errors, AI, and documentation references on the topic.
The exercise helped find a couple of gaps in my library required for mp-units:
common_typetype composition.After this first step, I was able to write the code of the form:
quantity velocity{isq::velocity(my_vector{30, 40, 0} * km / h)}; assert(std::format("{}", velocity) == "[[30], [40], [0]] km/h");Along with the other mp-units' quantity operations backed by this vector, including vector axis, components flavors. So far so good.
At this point, I believe component-wise access, in a generic manner, is only possible if the quantity is established with axis, components support:
I feel there is an asymetry, friction, gap, or arbitrary design: Why missing integral index access in the
(2)when it is provided in(1)? I feel it should be provided in (2) since the user decision to not provide strong axis, components was already established, permitted in the velocity declaration. Or the symmetric, alternative design of not providing strong axis, components for a vector type should be prevented. Either would reduce ergonomics frictions and/or improve safety.The plugin and more are stagged in this pull request.
Beyond
My library happens to also be capable of maintaining strong types at the element level. Not only homogeneously typed vectors, but also heterogeneous vectors. I've been exploring the confusing space between a vector as a quantity and a vector of quantities. Therefore I attempted to extend the plugin from vectors of doubles to vectors of quantities, with, without strong axis, components.
Some learning from this attempts, given mp-units was not designed for this abuse.
The quantity's tuple API permits conversions:
quantity velocity{flight_velocity(vector3d{30, 40, 0} * km / h)}; // A heterogeneous 3-component quantity-typed column vector (itself backed by // an Eigen vector of doubles). using velocities = column_vector<double, quantity<forward_velocity[km / h]>, quantity<lateral_velocity[km / h]>, quantity<vertical_velocity[km / h]>>; // Convert the vector quantity to a heterogeneous typed column vector of // quantities. velocities state{velocity}; // Note the difference in presentation of the state compared to the quantity: assert(std::format("{}", state) == "[[30 km/h], [40 km/h], [0 km/h]]"); assert(std::format("{}", velocity) == "[[30], [40], [0]] km/h"); // The vector quantity has a magnitude, but not the heterogeneous typed // vector of quantities, which doesn't have a meaning of a mathematical // vector nor homogeneous units. quantity speed{magnitude(velocity)}; // 🗸 // quantity speed{magnitude(state)}; // 𐄂 assert(std::format("{}", speed) == "50 km/h");And if the element conversion supports quantity specification conversion
(e.g. forward_velocity to isq::velocity) then conversion to a strongly typed
homogeneous vector is possible:
Similarly to the previous section, I am unable to generically convert a quantity to a typed vector, unless the quantity has named axis, components. I feel the API should have better allowance to enter and exit mp-units' quantity type. Perhaps best illustrated by the following unsupported/failing example (custom formatting to highlight the components entering and existing the mp-units quantity type).
quantity velocity{ isq::velocity( vector3d{30, 40, 0} * km / h)}; // Enter mp-units by component. auto [ x, y, z] = velocity; // Exit mp-units by component. (A) // ^^^^^^^^^^^^^^^^ // Not supported.I feel there is an asymetry. Either the input the should be component based (B), or the output by component should be permitted (A).
Another torturous use case was to use a strongly typed (not built-in types), heterogeneous vector as the backend to the quantity. An exploration of the composability of the types used in mp-units. This was a long shot, though this could be nice.
The multiplication of a vector and a quantity (Ref?)
operator*(V v, Q q)created difficulties and conflicts. My library supports the operation generically as part of its strongly typed support. A collision appeared when mp-units added support for vector as a quantity. There exists twooperator*(V v, Q q). One in mp-units namespace/types; and one in my owns. The implications are unclear to me nor is the compiler selection. Perhaps the nuances of the quantity and reference type escape me for now.What should the product of a vector and a quantity return? A vector whose elements have been multiplied with the quantity? Or a quantity with a vector backend? Respectively for the quantity reference, specification, etc... We've already established that vector as a quantity and vector of quantities have distinct different mathemtical, and C++ object properties. What of their interoperability?
Anyway, I hope this curious exercise was interesting.
All reactions