From 079e6406149701bb1b9987353d72fdba9200c720 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 14 Feb 2023 12:29:45 +0100 Subject: [PATCH] test: linear algebra test refactored to benefit from the latest features --- .../unit_test/runtime/linear_algebra_test.cpp | 239 +++++++++++++++++- 1 file changed, 229 insertions(+), 10 deletions(-) diff --git a/test/unit_test/runtime/linear_algebra_test.cpp b/test/unit_test/runtime/linear_algebra_test.cpp index 4de3f8ff..dfcd2649 100644 --- a/test/unit_test/runtime/linear_algebra_test.cpp +++ b/test/unit_test/runtime/linear_algebra_test.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +74,8 @@ namespace { template [[nodiscard]] auto get_magnitude(const vector& v) { - return std::hypot(v[0], v[1], v[2]); + using namespace std; + return hypot(v[0], v[1], v[2]); } template @@ -85,9 +87,9 @@ template template requires is_vector && is_vector && requires(typename Q1::rep v1, typename Q2::rep v2) { cross_product(v1, v2); } -[[nodiscard]] QuantityOf auto cross_product(const Q1& q1, const Q2& q2) +[[nodiscard]] QuantityOf auto cross_product(const Q1& q1, const Q2& q2) { - return (Q1::reference * Q2::reference)(cross_product(q1.number(), q2.number())); + return cross_product(q1.number(), q2.number()) * (Q1::reference * Q2::reference); } } // namespace @@ -195,12 +197,12 @@ TEST_CASE("vector quantity", "[la]") { SECTION("scalar on LHS") { - const quantity> momentum = mass * v; + const quantity> momentum = mass * v; CHECK(momentum.number() == vector{2, 4, 6}); } SECTION("scalar on RHS") { - const quantity> momentum = v * mass; + const quantity> momentum = v * mass; CHECK(momentum.number() == vector{2, 4, 6}); } } @@ -230,12 +232,12 @@ TEST_CASE("vector quantity", "[la]") { SECTION("scalar on LHS") { - const quantity> momentum = mass * v; + const quantity> momentum = mass * v; CHECK(momentum.number() == vector{0.5, 1., 1.5}); } SECTION("scalar on RHS") { - const quantity> momentum = v * mass; + const quantity> momentum = v * mass; CHECK(momentum.number() == vector{0.5, 1., 1.5}); } } @@ -281,9 +283,226 @@ TEST_CASE("vector quantity", "[la]") SECTION("cross product with a vector quantity") { - const quantity> r{vector{3, 0, 0}}; - const quantity> f{vector{0, 10, 0}}; + const auto r = vector{3, 0, 0} * isq::position_vector[m]; + const auto f = vector{0, 10, 0} * isq::force[N]; - CHECK(cross_product(r, f) == isq::moment_of_force[N * m](vector{0, 0, 30})); + CHECK(cross_product(r, f) == vector{0, 0, 30} * isq::moment_of_force[N * m]); } } + +template + requires mp_units::is_scalar +inline constexpr bool mp_units::is_vector = true; + +TEST_CASE("vector of quantities", "[la]") +{ + SECTION("cast of unit") + { + SECTION("non-truncating") + { + const vector> v = {3 * km, 2 * km, 1 * km}; + + CHECK(vector>(v) == + vector>{3000 * m, 2000 * m, 1000 * m}); + } + + // truncating not possible (no way to apply quantity_cast to sub-components of a vector) + } + + SECTION("to scalar magnitude") + { + const vector> v = {2 * (km / h), 3 * (km / h), 6 * (km / h)}; + const auto speed = get_magnitude(v).number() * isq::speed[v[0].unit]; // TODO can we do better here? + CHECK(speed.number() == 7); + } + + SECTION("multiply by scalar value") + { + const vector> v = {1 * m, 2 * m, 3 * m}; + + SECTION("integral") + { + const vector> result = {2 * m, 4 * m, 6 * m}; + + SECTION("scalar on LHS") { CHECK(2 * v == result); } + SECTION("scalar on RHS") { CHECK(v * 2 == result); } + } + + SECTION("floating-point") + { + const vector> result = {0.5 * m, 1. * m, 1.5 * m}; + + SECTION("scalar on LHS") { CHECK(0.5 * v == result); } + SECTION("scalar on RHS") { CHECK(v * 0.5 == result); } + } + } + + // TODO check if the below is a bug in mp-units or LA + // SECTION("divide by scalar value") + // { + // const vector> v = {isq::position_vector[m](2), isq::position_vector[m](4), + // isq::position_vector[m](6)}; + + // SECTION("integral") + // { + // CHECK(v / 2 == vector>{ + // isq::position_vector[m](1), isq::position_vector[m](2), isq::position_vector[m](3)}); + // } + // SECTION("floating-point") + // { + // CHECK(v / 0.5 == vector>{ + // isq::position_vector[m](4.), isq::position_vector[m](8.), isq::position_vector[m](12.)}); + // } + // } + + SECTION("add") + { + const vector> v = {1 * m, 2 * m, 3 * m}; + + SECTION("same unit") + { + const vector> u = {3 * m, 2 * m, 1 * m}; + + CHECK(v + u == vector>{4 * m, 4 * m, 4 * m}); + } + SECTION("different units") + { + const vector> u = {3 * km, 2 * km, 1 * km}; + + CHECK(v + u == vector>{3001 * m, 2002 * m, 1003 * m}); + } + } + + SECTION("subtract") + { + const vector> v = {1 * m, 2 * m, 3 * m}; + + SECTION("same unit") + { + const vector> u = {3 * m, 2 * m, 1 * m}; + CHECK(v - u == vector>{-2 * m, 0 * m, 2 * m}); + } + SECTION("different units") + { + const vector> u = {3 * km, 2 * km, 1 * km}; + CHECK(v - u == vector>{-2999 * m, -1998 * m, -997 * m}); + } + } + + SECTION("multiply by scalar quantity") + { + const vector> v = {1 * (m / s), 2 * (m / s), 3 * (m / s)}; + + SECTION("integral") + { + const auto mass = 2 * isq::mass[kg]; + const auto result = vector>{2 * (N * s), 4 * (N * s), 6 * (N * s)}; + + SECTION("derived_quantity_spec") + { + SECTION("scalar on LHS") { CHECK(mass * v == result); } + SECTION("scalar on RHS") { CHECK(v * mass == result); } + } + + // no way to apply quantity_cast to sub-components + + SECTION("quantity of momentum") + { + SECTION("scalar on LHS") + { + const vector> momentum = mass * v; + CHECK(momentum == result); + } + SECTION("scalar on RHS") + { + const vector> momentum = v * mass; + CHECK(momentum == result); + } + } + } + + SECTION("floating-point") + { + const auto mass = 0.5 * isq::mass[kg]; + const auto result = vector>{0.5 * (N * s), 1. * (N * s), 1.5 * (N * s)}; + + SECTION("derived_quantity_spec") + { + SECTION("scalar on LHS") { CHECK(mass * v == result); } + SECTION("scalar on RHS") { CHECK(v * mass == result); } + } + + // no way to apply quantity_cast to sub-components + + SECTION("quantity of momentum") + { + SECTION("scalar on LHS") + { + const vector> momentum = mass * v; + CHECK(momentum == result); + } + SECTION("scalar on RHS") + { + const vector> momentum = v * mass; + CHECK(momentum == result); + } + } + } + } + + // TODO check if the below is a bug in mp-units or LA + // SECTION("divide by scalar quantity") + // { + // const vector> pos = { + // isq::position_vector[km](30), isq::position_vector[km](20), isq::position_vector[km](10)}; + + // SECTION("integral") + // { + // const auto dur = 2 * isq::duration[h]; + + // SECTION("derived_quantity_spec") + // { + // CHECK(pos / dur == vector>{ + // isq::velocity[km / h](15), isq::velocity[km / h](10), isq::velocity[km / h](5)}); + // } + + // // no way to apply quantity_cast to sub-components + + // SECTION("quantity of velocity") + // { + // const vector> v = pos / dur; + // CHECK(v == vector>{isq::velocity[km / h](15), isq::velocity[km / h](10), + // isq::velocity[km / h](5)}); + // } + // } + + // SECTION("floating-point") + // { + // const auto dur = 0.5 * isq::duration[h]; + + // SECTION("derived_quantity_spec") + // { + // CHECK(pos / dur == vector>{ + // isq::velocity[km / h](60.), isq::velocity[km / h](40.), isq::velocity[km / h](20)}); + // } + + // // no way to apply quantity_cast to sub-components + + // SECTION("quantity of velocity") + // { + // const vector> v = pos / dur; + // CHECK(v == vector>{ + // isq::velocity[km / h](60.), isq::velocity[km / h](40.), isq::velocity[km / h](20)}); + // } + // } + // } + + // SECTION("cross product with a vector of quantities") + // { + // const vector> r{ + // vector{isq::position_vector[m](3), isq::position_vector[m](0), isq::position_vector[m](0)}}; + // const vector> f{vector{isq::force[N](0), isq::force[N](10), isq::force[N](0)}}; + + // CHECK(cross_product(r, f) == vector>{0, 0, 30})); + // } +}