diff --git a/public/gal/algebra.hpp b/public/gal/algebra.hpp index c6e71f7..7af7255 100644 --- a/public/gal/algebra.hpp +++ b/public/gal/algebra.hpp @@ -22,9 +22,6 @@ using width_t = uint32_t; // order of "0" here, by convention, refers to an infinite order. struct ind { - // NOTE: the tag of ~0 - 1 is RESERVED by the library for the dual unit. This ensures that the - // dual unit (which has a high chance of extinguishing the monomial it's a factor of) comes - // first in the factor ordering. width_t id = ~0u; int degree = 0; uint8_t order = 0; @@ -34,12 +31,12 @@ struct ind // If all indeterminates are identified (ID != ~0ull), the ordering becomes a total order. [[nodiscard]] constexpr bool operator==(ind lhs, ind rhs) noexcept { - return lhs.id == rhs.id && lhs.degree == rhs.degree && lhs.id != ~0u && rhs.id != ~0u; + return lhs.id == rhs.id && lhs.degree == rhs.degree; } [[nodiscard]] constexpr bool operator!=(ind lhs, ind rhs) noexcept { - return lhs.id != rhs.id || lhs.degree != rhs.degree || lhs.id == ~0u || rhs.id == ~0u; + return lhs.id != rhs.id || lhs.degree != rhs.degree; } [[nodiscard]] constexpr bool operator<(ind lhs, ind rhs) noexcept @@ -428,6 +425,12 @@ struct const_term_it } }; +template +struct dense_mv +{ + std::array>, MonMax>>, TermMax> data; +}; + // Multivector representation, intended to be a compile-time representation // A := Algebra // I := Indeterminate capacity @@ -502,7 +505,7 @@ struct mv } template - [[nodiscard]] constexpr auto shrink() const noexcept + [[nodiscard]] constexpr auto resize() const noexcept { if constexpr (I == I2 && M == M2 && T == T2) { @@ -528,6 +531,59 @@ struct mv } } + // Reshape the multivector to be fully dense in the arrays to simplify compilation of the final reduction + template + [[nodiscard]] constexpr auto regularize() const noexcept + { + dense_mv out; + + for (width_t i = 0; i != size.term; ++i) + { + auto const& term = terms[i]; + auto& out_term = out.data[i]; + out_term.first = term; + + for (width_t j = term.mon_offset; j != term.mon_offset + term.count; ++j) + { + auto const& mon = mons[j]; + auto& out_mon = out_term.second[j - term.mon_offset]; + out_mon.first = mon; + + for (width_t k = mon.ind_offset; k != mon.ind_offset + mon.count; ++k) + { + out_mon.second[k - mon.ind_offset] = inds[k]; + } + } + } + + return out; + } + + [[nodiscard]] constexpr mv_size extent() const noexcept + { + // Determine the maximum number of indeterminates across all monomials and the maximum number of monomials + // across all terms + + width_t mon_count = 0; + width_t ind_count = 0; + for (auto term_it = cbegin(); term_it != cend(); ++term_it) + { + if (term_it->count > mon_count) + { + mon_count = term_it->count; + } + + for (auto mon_it = term_it.cbegin(); mon_it != term_it.cend(); ++mon_it) + { + if (mon_it->count > ind_count) + { + ind_count = mon_it->count; + } + } + } + return {ind_count, mon_count, size.term}; + } + [[nodiscard]] constexpr const_term_it cbegin() const noexcept { return {inds.data(), mons.data(), terms.data()}; diff --git a/public/gal/engine.hpp b/public/gal/engine.hpp index f8fda61..d159fb8 100644 --- a/public/gal/engine.hpp +++ b/public/gal/engine.hpp @@ -78,7 +78,7 @@ namespace detail // Data := flattened array of inputs template - [[nodiscard]] static auto compute_entity(Data const& data, std::index_sequence) noexcept + [[nodiscard]] constexpr static auto compute_entity_typed(Data const& data, std::index_sequence) noexcept { using entity_t = entity; // NOTE: this should be flattened to arrays of constant size ideally @@ -114,6 +114,45 @@ namespace detail tree); } + template + [[nodiscard]] constexpr static auto compute_entity(Data const& data, std::index_sequence) noexcept + { + using entity_t = entity; + // NOTE: this should be flattened to arrays of constant size ideally + return std::apply( + [&data](auto&&... t) { + return entity_t{std::apply( + [&](auto&&... m) { + if constexpr (sizeof...(m) == 0) + { + return F{0}; + } + else + { + return ((m.first.q.num == 0 + ? 0 + : (static_cast(m.first.q) + * std::apply( + [&](auto&&... i) { + if constexpr (sizeof...(i) == 0) + { + return F{1}; + } + else + { + return ((i.id == ~0u ? 1 : ::gal::pow(*data[i.id], i.degree)) + * ...); + } + }, + m.second))) + + ...); + } + }, + t.second)...}; + }, + dmv.data); + } + // The indeterminate value is either a pointer to an entity's value or an evaluated expression template struct ind_value @@ -123,7 +162,7 @@ namespace detail T const* pointer; T value; }; - + bool is_value; [[nodiscard]] constexpr T operator*() const noexcept @@ -156,18 +195,37 @@ namespace detail } template - [[nodiscard]] static auto finalize_entity(D const& data) + [[nodiscard]] static auto finalize_entity_typed(D const& data) { constexpr static auto reified = reify(); if constexpr (detail::uses_null_basis) { constexpr static auto null_conversion = detail::to_null_basis(reified); - return compute_entity( - data, std::make_index_sequence()); + return compute_entity_typed(data, std::make_index_sequence()); + } + else + { + return compute_entity_typed(data, std::make_index_sequence()); + } + } + + template + [[nodiscard]] static auto finalize_entity(D const& data) + { + constexpr auto reified = reify(); + if constexpr (detail::uses_null_basis) + { + constexpr auto null_conversion = detail::to_null_basis(reified); + constexpr auto extent = null_conversion.extent(); + constexpr static auto regularized + = null_conversion.template regularize(); + return compute_entity(data, std::make_index_sequence()); } else { - return compute_entity(data, std::make_index_sequence()); + constexpr auto extent = reified.extent(); + constexpr static auto regularized = reified.template regularize(); + return compute_entity(data, std::make_index_sequence()); } } } // namespace detail @@ -205,7 +263,7 @@ template // an evaluated property if constexpr (detail::is_tuple_v) { - if constexpr (std::tuple_size_v > 0) + if constexpr (std::tuple_size_v> 0) { using value_t = typename std::tuple_element_t<0, ie_result_t>::value_t; using algebra_t = typename std::tuple_element_t<0, ie_result_t>::algebra_t; @@ -216,7 +274,7 @@ template return std::apply( [&](auto&&... args) { return std::make_tuple( - detail::finalize_entity>(data)...); + detail::finalize_entity_typed>(data)...); }, ie_result_t{}); } @@ -228,7 +286,7 @@ template std::array, (Data::ind_count() + ...)> data{}; detail::fill(data.data(), input...); - return detail::finalize_entity(data); + return detail::finalize_entity_typed(data); } } } // namespace gal diff --git a/public/gal/expression.hpp b/public/gal/expression.hpp index 3b9037b..a69b828 100644 --- a/public/gal/expression.hpp +++ b/public/gal/expression.hpp @@ -247,7 +247,7 @@ template if constexpr (detail::uses_null_basis) { constexpr auto out = detail::to_natural_basis(exp_t::lhs); - return out.template shrink(); + return out.template resize(); } else { @@ -282,7 +282,7 @@ template else if constexpr (exp_t::op == expr_op::extract) { constexpr auto out = detail::extract(reify(), exp_t::elements); - return out.template shrink(); + return out.template resize(); } else if constexpr (exp_t::op == expr_op::select) { @@ -296,18 +296,18 @@ template if constexpr (exp_t::op == expr_op::sum) { constexpr auto out = detail::sum(lhs, rhs); - return out.template shrink(); + return out.template resize(); } else if constexpr (exp_t::op == expr_op::difference) { constexpr auto n_rhs = detail::negate(rhs); constexpr auto out = detail::sum(lhs, n_rhs); - return out.template shrink(); + return out.template resize(); } else if constexpr (exp_t::op == expr_op::geometric) { constexpr auto out = detail::product(typename decltype(lhs)::algebra_t::geometric{}, lhs, rhs); - return out.template shrink(); + return out.template resize(); } else if constexpr (exp_t::op == expr_op::sandwich) { @@ -316,13 +316,13 @@ template constexpr auto temp = detail::product(typename decltype(lhs)::algebra_t::geometric{}, lhs, rhs_reverse); constexpr auto temp2 = detail::product(typename decltype(lhs)::algebra_t::geometric{}, rhs, - temp.template shrink()); - return temp2.template shrink(); + temp.template resize()); + return temp2.template resize(); } else if constexpr (exp_t::op == expr_op::exterior) { constexpr auto out = detail::product(typename decltype(lhs)::algebra_t::exterior{}, lhs, rhs); - return out.template shrink(); + return out.template resize(); } else if constexpr (exp_t::op == expr_op::regressive) { @@ -330,17 +330,17 @@ template constexpr auto lhs_dual = detail::poincare_dual(lhs); constexpr auto rhs_dual = detail::poincare_dual(rhs); constexpr auto out = detail::product(typename decltype(lhs)::algebra_t::exterior{}, lhs_dual, rhs_dual); - return detail::poincare_dual(out.template shrink()); + return detail::poincare_dual(out.template resize()); } else if constexpr (exp_t::op == expr_op::contract) { constexpr auto out = detail::product(typename decltype(lhs)::algebra_t::contract{}, lhs, rhs); - return out.template shrink(); + return out.template resize(); } else if constexpr (exp_t::op == expr_op::symmetric_inner) { constexpr auto out = detail::product(typename decltype(lhs)::algebra_t::symmetric_inner{}, lhs, rhs); - return out.template shrink(); + return out.template resize(); } } } diff --git a/public/gal/numeric.hpp b/public/gal/numeric.hpp index 5628bf6..347df6f 100644 --- a/public/gal/numeric.hpp +++ b/public/gal/numeric.hpp @@ -8,20 +8,19 @@ namespace gal { // right-to-left binary exponentiation -template -[[nodiscard]] constexpr T pow(T s, std::integral_constant) noexcept +template +[[nodiscard]] constexpr T pow(T s, int e) noexcept { - if constexpr (exponent < 0) + if (e < 0) { - return T{1} / pow(s, std::integral_constant{}); + return T{1} / pow(s, -e); } - else if constexpr (exponent == 1) + else if (e == 1) { return s; } - else + else { - int e = exponent; T temp1{1}; T temp2{s}; while (e > 1) @@ -98,7 +97,7 @@ template // overflows struct rat { - int num = 1; + int num = 0; int den = 1; [[nodiscard]] constexpr bool is_zero() const noexcept diff --git a/public/gal/pga.hpp b/public/gal/pga.hpp index ff900c6..c502964 100644 --- a/public/gal/pga.hpp +++ b/public/gal/pga.hpp @@ -152,6 +152,7 @@ namespace pga template constexpr point(entity in) noexcept + : data{} { auto input = in.template select<0b111, 0b1011, 0b1101, 0b1110>(); auto w_inv = T{1} / input[3]; @@ -231,6 +232,7 @@ namespace pga template constexpr vector(entity in) noexcept + : data{} { auto input = in.template select<0b111, 0b1011, 0b1101>(); z = -input[0]; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e5b97f1..cf8cf3e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -16,7 +16,7 @@ add_executable(gal_test test_cga.cpp test_ega.cpp test_pga.cpp) - #test_ik.cpp) + # test_ik.cpp) target_link_libraries(gal_test PRIVATE gal doctest) target_compile_definitions(gal_test PRIVATE diff --git a/test/test_ega.cpp b/test/test_ega.cpp index 5881317..9bcb631 100644 --- a/test/test_ega.cpp +++ b/test/test_ega.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -118,6 +119,10 @@ TEST_CASE("rotors") r1, r2, v1); + auto r = gal::evaluate, rotor, vector>{}.debug([](auto r1, auto r2, auto v1) { + auto r = r1 * r2; + return v1 % r; + }); CHECK_EQ(rotated.x, doctest::Approx(0.0)); CHECK_EQ(rotated.y, doctest::Approx(1.0)); CHECK_EQ(rotated.z, doctest::Approx(0.0));