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

[ENH] Augment coiteration algorithm to handle hashed level during conjunctive merge #19

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8714270
WIP example of compareVector
adam2392 Mar 23, 2023
652d8b0
Adding the unit test for coiteration that should work
adam2392 Apr 3, 2023
bcbcbe2
Clean diff
adam2392 Apr 3, 2023
462dbb0
Update test/source/coiteration_test.cpp
adam2392 Apr 8, 2023
7cc42f7
Update test/source/coiteration_test.cpp
adam2392 Apr 8, 2023
1969843
Fix unit test based on comments
adam2392 May 25, 2023
a9dc754
Merge branch 'comparevec' of github.com:adam2392/xsparse into comparevec
adam2392 May 25, 2023
0c91a0d
Fix unit test based on comments
adam2392 May 25, 2023
0a35239
Attempt at the right answer
adam2392 May 25, 2023
8d97006
Clean
adam2392 May 25, 2023
c0bc015
I think this enables us to store the ordered indices, but does not ye…
adam2392 May 26, 2023
fc08789
Fix docstring and clean up unit-test
adam2392 May 30, 2023
eb63b3c
Fix ci and doctest errors
adam2392 May 30, 2023
0420df3
Merge branch 'main' into comparevec
adam2392 May 30, 2023
828092a
Add levelproperty to all the levels
adam2392 May 31, 2023
b5ec7ef
Merge branch 'main' into levelprops
adam2392 May 31, 2023
aa56276
Try again
adam2392 May 31, 2023
29f4f7f
Adding unit tests for level property
adam2392 May 31, 2023
3e0afc4
Clean diff
adam2392 May 31, 2023
b63b67c
Only check strict property requirements
adam2392 May 31, 2023
2ac6d71
Fixed unit-tests for dense ordered
adam2392 May 31, 2023
5e72277
Level to lower-case
adam2392 Jun 1, 2023
25c5c2e
Merging level props
adam2392 Jun 1, 2023
ddaf8d2
Merge branch 'levelprops' into comparevec
adam2392 Jun 1, 2023
f77dd0d
Trying again
adam2392 Jun 1, 2023
6a73b73
Fix new design
adam2392 Jun 5, 2023
1a6d711
Merge branch 'levelprops' into comparevec
adam2392 Jun 5, 2023
8690b48
Fix co-iteration and just get initial design template for getting tup…
adam2392 Jun 5, 2023
a379e0b
Trying
adam2392 Jun 5, 2023
89ee47d
Merge branch 'main' into comparevec
adam2392 Jun 6, 2023
f7d0ed1
Merge main
adam2392 Jun 6, 2023
7730adb
Kind of wip
adam2392 Jun 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ This template is the result of learnings from many previous projects and should
- Reproducible dependency management via [CPM.cmake](https://github.com/TheLartians/CPM.cmake)
- Installable target with automatic versioning information and header generation via [PackageProject.cmake](https://github.com/TheLartians/PackageProject.cmake)
- Automatic [documentation](https://thelartians.github.io/ModernCppStarter) and deployment with [Doxygen](https://www.doxygen.nl) and [GitHub Pages](https://pages.github.com)
- Support for [sanitizer tools, and more](#additional-tools)

## Usage

Expand All @@ -42,7 +41,7 @@ This template is the result of learnings from many previous projects and should
Eventually, you can remove any unused files, such as the standalone directory or irrelevant github workflows for your project.
Feel free to replace the License with one suited for your project.

To cleanly separate the library and subproject code, the outer `CMakeList.txt` only defines the library itself while the tests and other subprojects are self-contained in their own directories.
To cleanly separate the library and subproject code, the outer `CMakeList.txt` only defines the library itself while the tests and other subprojects are self-contained in their own directories.
During development it is usually convenient to [build all subprojects at once](#build-everything-at-once).

### Build and run the standalone target
Expand Down
112 changes: 109 additions & 3 deletions include/xsparse/level_capabilities/co_iteration.hpp
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file contains my initial attempt at: adding a constexpr check at compile time to determine if the coiteration is valid (this assumes that the user converts non-ordered, non-locatable formats to a correct format).

What I'm not sure on now is how to best implement the locate logic. That is, we want to somehow given a tuple of levels, determine which of these have locate and instead of advancing the iterator on those levels, we locate into them given a index and pointer.

Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,46 @@
#include <algorithm>
#include <stdexcept>

#include <xsparse/level_capabilities/locate.hpp>

namespace xsparse::level_capabilities
{
/**
* @brief The class template for Coiteration of level formats.
*
* @details Uses a generic function object F to compare elements
* from different sequences at the same position and returns a tuple of the
* minimum index and the corresponding elements from each sequence.
*
* @tparam F - A function object that is used to compare elements from different ranges.
* Its input is a tuple of booleans corresponding to each of the levels. The output is a boolean
* that is the result of the function.
* @tparam IK - The type of the first element of each range.
* @tparam PK - The type of the second element of each range.
* @tparam Levels - A tuple of level formats, where each level is itself a tuple of elements
* to be iterated.
* @tparam Is - A tuple of indices that is used to keep track of the current position in each
* level.
*
* @note Coiteration is only allowed through tuples of levels if the following criterion is met:
* If:
* 1. the levels are all ordered (i.e. has the `is_ordered == True` property)
* 2. if any of the level are do not have the is_ordered property, it must have the locate
* function, else return False. Then do a check that `m_comparisonHelper` defines
* a conjunctive merge (i.e. AND operation).
* Otherwise, coiteration is not allowed.
*
* This check is done automatically in the constructor, via the function `
*/
template <class F, class IK, class PK, class Levels, class Is>
class Coiterate;

template <class F, class IK, class PK, class... Levels, class... Is>
class Coiterate<F, IK, PK, std::tuple<Levels...>, std::tuple<Is...>>
{
private:
std::tuple<Levels&...> const m_levelsTuple;
F const m_comparisonHelper;
std::tuple<Levels&...> const m_levelsTuple; // tuple of levels
F const m_comparisonHelper; // comparison function

public:
explicit inline Coiterate(F f, Levels&... levels)
Expand All @@ -30,6 +59,71 @@ namespace xsparse::level_capabilities
}
}

template <std::size_t I>
consteval bool is_level_ordered() const noexcept
/**
* @brief Check if a single level is ordered or not at index I.
*/
{
return std::decay_t<decltype(std::get<I>(m_levelsTuple))>::LevelProperties::is_ordered;
}

template <std::size_t... I>
consteval auto ordered_level_mask_impl(std::index_sequence<I...>) const noexcept
/**
* @brief Template recursion to construct tuples of true/false indicating ordered/unordered levels.
*/
{
return std::make_tuple(is_level_ordered<I>()...);
}

consteval auto ordered_level_mask() const noexcept
/**
* @brief Compute a tuple of true/false indicating ordered/unordered levels.
*
* @details If all levels are ordered, return a tuple of true. If any of the levels
* are unordered, return a tuple of true/false, where the true/false indicates
* ordered/unordered levels. Also does a compiler-time check that the levels meet the
* coiteration criteria given the function object `f`. This function IS compiler-evaluated.
*
* @return A tuple of true/false indicating ordered/unordered levels.
*/
{
return ordered_level_mask_impl(std::index_sequence_for<Levels...>());
}

// template <typename Tuple, int Index = 0>
// consteval auto filter(Tuple t)
// /**
// * @brief Helper function to recursively filter out the levels that are ordered.
// */
// {
// constexpr auto tup_size = std::tuple_size_v<decltype(t())>;

// if constexpr(Index == tup_size)
// return std::tuple<>{};
// else {
// constexpr auto v = std::get<Index>(t());
// if constexpr(v) {
// constexpr auto level = std::get<Index>(m_levelsTuple);
// return std::tuple_cat(std::tuple(level), filter<Tuple, 1+Index>(t));
// } else {
// return filter<Tuple, 1+Index>(t);
// }
// }
// }

// constexpr auto ordered_levels() const noexcept
// /**
// * @brief Compute a tuple of the ordered levels in Coiterate.
// *
// * @return A tuple of the ordered levels in Coiterate.
// */
// {
// constexpr auto levels = filter([&] {return ordered_level_mask();});
// return levels;
// }

public:
class coiteration_helper
{
Expand All @@ -38,7 +132,13 @@ namespace xsparse::level_capabilities
std::tuple<Is...> const m_i;
PK const m_pkm1;
std::tuple<typename Levels::LevelCapabilities::iteration_helper...> m_iterHelpers;

// pull out first element of tuple and rest via unpacking...
// -> if level is not ordered, static_assert to make sure has locate_v and also
// static_assert over F(false,...) and F(true,, ...)
// -> if level is ordered, static_assert to make sure is_ordered is true and
// stati_ciassert over F(false, ...)
// have a tuple of only ordered levels stored as reference
// -> and then add in locate
public:
explicit inline coiteration_helper(Coiterate const& coiterate,
std::tuple<Is...> i,
Expand All @@ -56,6 +156,7 @@ namespace xsparse::level_capabilities
{
private:
coiteration_helper const& m_coiterHelper;
// TODO: add LevelCapabilities to hashed levels
std::tuple<typename Levels::LevelCapabilities::iteration_helper::iterator...>
iterators;
IK min_ik;
Expand Down Expand Up @@ -123,6 +224,8 @@ namespace xsparse::level_capabilities

template <class iter>
inline auto locate(iter i) const noexcept
// TODO: if consteval: locate over unordered levels (using is_ordered) and
// deref other levels aka what is already here.
{
return (std::get<0>(*i) == min_ik)
? std::optional<std::tuple_element_t<1, decltype(*i)>>(
Expand All @@ -133,6 +236,9 @@ namespace xsparse::level_capabilities
template <class iter>
inline void advance_iter(iter& i) const noexcept
{
// TODO: anything that fails a conjunctive check, we must
// have is_ordered and we iterate into, otherwise we can
// locate into it. -> optimization for conjunctive operations
if (static_cast<IK>(std::get<0>(*i)) == min_ik)
{
++i;
Expand Down
98 changes: 97 additions & 1 deletion include/xsparse/level_capabilities/coordinate_iterate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ namespace xsparse::level_capabilities
};

iteration_helper iter_helper(typename BaseTraits::I i, typename BaseTraits::PKM1 pkm1)
/*Create an instance of iteration_helper that manages the iteration process.*/
{
return iteration_helper{ *static_cast<typename BaseTraits::Level*>(this), i, pkm1 };
}
Expand All @@ -150,7 +151,7 @@ namespace xsparse::level_capabilities
class coordinate_position_iterate
{
using BaseTraits = util::base_traits<T, IK, PK, LowerLevels...>;

public:
class iteration_helper
{
Expand Down Expand Up @@ -269,6 +270,101 @@ namespace xsparse::level_capabilities
return iteration_helper{ *static_cast<typename BaseTraits::Level*>(this), i, pkm1 };
}
};

template <template <class...> class T, class IK, class PK, class... LowerLevels>
class locate_position_iterate
{
using BaseTraits = util::base_traits<T, IK, PK, LowerLevels...>;

public:
class iteration_helper
{
static_assert(std::is_nothrow_invocable_r_v<std::optional<typename BaseTraits::PK>,
decltype(&BaseTraits::Level::locate),
typename BaseTraits::Level&,
typename BaseTraits::PKM1,
typename BaseTraits::IK>);

private:
typename BaseTraits::Level const& m_level;
typename BaseTraits::I const m_i;
typename BaseTraits::PKM1 const m_pkm1;
typename BaseTraits::IK m_ik_begin, m_ik_end;

public:
class iterator;
using value_type =
typename std::pair<typename BaseTraits::IK, typename BaseTraits::PK>;
using difference_type = typename std::make_signed_t<typename BaseTraits::PK>;
using pointer =
typename std::pair<typename BaseTraits::IK, typename BaseTraits::PK>*;
using reference = std::pair<typename BaseTraits::IK, typename BaseTraits::PK>;
using iterator_type = iterator;

class iterator : public xtl::xbidirectional_iterator_base2<iteration_helper>
{

private:
iteration_helper const& m_iterHelper;
typename BaseTraits::IK m_ik;
// using wrapped_iterator_type = typename ContainerTraits::template Map<
// typename BaseTraits::IK,
// typename BaseTraits::PK>::const_iterator;
// wrapped_iterator_type m_iterHelper;

public:
explicit inline iterator(iteration_helper iterationHelper) noexcept
: m_iterHelper(iterationHelper)
, m_ik(ik)
{
}

inline std::tuple<typename BaseTraits::IK, typename BaseTraits::PK> operator*()
const noexcept
{
return { m_iterHelper->first, m_iterHelper->second };
}

inline bool operator==(const iterator& other) const noexcept
{
return m_iterHelper == other.m_iterHelper;
}

inline iterator& operator++() noexcept
{
++m_iterHelper;
return *this;
}

inline iterator& operator--() noexcept
{
--m_iterHelper;
return *this;
}
};

explicit inline iteration_helper(typename BaseTraits::IK const& ik
typename BaseTraits::PK const& pk map) noexcept
: m_map(map)
{
}

inline iterator_type begin() const noexcept
{
return iterator_type{ m_map.begin() };
}

inline iterator_type end() const noexcept
{
return iterator_type{ m_map.end() };
}
};

iteration_helper iter_helper(typename BaseTraits::PKM1 pkm1)
{
return iteration_helper{ this->m_crd[pkm1] };
}
}
}

#endif // XSPARSE_COORDINATE_ITERATE_HPP
Loading