From 84b0e3a3e41bc4999a80aafd561f12cb061be3c6 Mon Sep 17 00:00:00 2001 From: Tania Krisanty Date: Mon, 24 Jan 2022 18:11:01 +0100 Subject: [PATCH] permutation iterator, not thoroughly checked yet --- example/permutationIterator/CMakeLists.txt | 4 + .../src/permutationIterator-main.cpp | 177 +++++++++++ .../mem/iterator/PermutationIterator.hpp | 274 ++++++++++++++++++ 3 files changed, 455 insertions(+) create mode 100644 example/permutationIterator/CMakeLists.txt create mode 100644 example/permutationIterator/src/permutationIterator-main.cpp create mode 100644 include/vikunja/mem/iterator/PermutationIterator.hpp diff --git a/example/permutationIterator/CMakeLists.txt b/example/permutationIterator/CMakeLists.txt new file mode 100644 index 0000000..802413a --- /dev/null +++ b/example/permutationIterator/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.18) +set(_TARGET_NAME "example_permutation_iterator") +alpaka_add_executable(${_TARGET_NAME} src/permutationIterator-main.cpp) +target_link_libraries(${_TARGET_NAME} PUBLIC vikunja::internalvikunja) diff --git a/example/permutationIterator/src/permutationIterator-main.cpp b/example/permutationIterator/src/permutationIterator-main.cpp new file mode 100644 index 0000000..b99b1c6 --- /dev/null +++ b/example/permutationIterator/src/permutationIterator-main.cpp @@ -0,0 +1,177 @@ +/* Copyright 2021 Hauke Mewes, Simeon Ehrig, Victor + * + * This file is part of vikunja. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include + +#include +#include + +int main() +{ + // Define the accelerator here. Must be one of the enabled accelerators. + //using TAcc = alpaka::AccGpuCudaRt, std::uint64_t>; + using TAcc = alpaka::AccCpuSerial, std::uint64_t>; + + // Type of the data that will be reduced + using TRed = uint64_t; + + // Alpaka index type + using Idx = alpaka::Idx; + // Alpaka dimension type + using Dim = alpaka::Dim; + // number of elements to reduce + const Idx n = static_cast(3); + + /* + // define device, platform, and queue types. + using DevAcc = alpaka::Dev; + using PltfAcc = alpaka::Pltf; + // using QueueAcc = alpaka::test::queue::DefaultQueue>; + using PltfHost = alpaka::PltfCpu; + using DevHost = alpaka::Dev; + using QueueAcc = alpaka::Queue; + + // Get the host device. + DevHost devHost(alpaka::getDevByIdx(0u)); + // Select a device to execute on. + DevAcc devAcc(alpaka::getDevByIdx(0u)); + // Get a queue on the accelerator device. + QueueAcc queueAcc(devAcc); + + typedef std::vector element_range_type; + typedef std::vector index_type; + + // Use Lambda function for reduction + // auto sum = [] ALPAKA_FN_HOST_ACC(vikunja::mem::iterator::PermutationIterator i, vikunja::mem::iterator::PermutationIterator j) { return i + j; }; + // auto doubleNum = [] ALPAKA_FN_HOST_ACC(TRed const i) { return 2 * i; }; + std::cout << "Testing accelerator: " << alpaka::getAccName() << " with size: " << n << "\n" + << "Testing permutation iterator with value: 10\n"; + //*/ + + std::vector values{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + std::vector indices{ 5, 7, 10 }; + + // Create the permutation iterator + typedef vikunja::mem::iterator::PermutationIterator permutation_type; + + permutation_type permutationIter(values.begin(), indices.begin(), n); + + std::cout << "Permutation result:\n"; + + auto it = permutationIter.begin(); + + // for (int i = 0; i < n; ++i) + // { + // std::cout << indices[i] << "\t: " << it[i] << "\n"; + // } + + std::cout << "*++permutationIter: "; + std::cout << *++permutationIter; + std::cout << "\n*permutationIter: "; + std::cout << *permutationIter; + std::cout << "\n\n"; + + std::cout << "*permutationIter++: "; + std::cout << *permutationIter++; + std::cout << "\n*permutationIter: "; + std::cout << *permutationIter; + std::cout << "\n\n"; + + permutationIter += 6; + std::cout << "permutationIter += 6;\n" + << "*permutationIter: "; + std::cout << *permutationIter; + std::cout << "\n\n"; + + permutationIter -= 2; + std::cout << "permutationIter -= 2;\n" + << "*permutationIter: "; + std::cout << *permutationIter; + std::cout << "\n\n"; + + std::cout << "--permutationIter: "; + std::cout << *--permutationIter; + std::cout << "\n*permutationIter: "; + std::cout << *permutationIter; + std::cout << "\n\n"; + + std::cout << "permutationIter--: "; + std::cout << *permutationIter--; + std::cout << "\n*permutationIter: "; + std::cout << *permutationIter; + std::cout << "\n\n"; + + std::cout << "*(permutationIter + 2): "; + std::cout << *(permutationIter + 2); + std::cout << "\n\n"; + + std::cout << "*(permutationIter - 3): "; + std::cout << *(permutationIter - 3); + std::cout << "\n\n"; + + std::cout << "*permutationIter[0]: "; + std::cout << permutationIter[0]; + std::cout << "\n"; + + std::cout << "*permutationIter[3]: "; + std::cout << permutationIter[3]; + std::cout << "\n"; + + // REDUCE CALL: + // Takes the arguments: accelerator device, host device, accelerator queue, size of data, pointer-like to memory, + // reduce lambda. + // Idx reduceResult = vikunja::reduce::deviceReduce, + // vikunja::mem::iterator::MemAccessPolicy, + // TFunc, + // TInputIterator, + // DevAcc, + // DevHost, + // QueueAcc, + // Idx, + // TOperator = vikunja::operators::BinaryOp< + // TAcc, + // TFunc, + // typename std::iterator_traits, + // typename std::iterator_traits>, + // typename TRed = typename TOperator::TRed>( + // // Idx reduceResult = vikunja::reduce::deviceReduce( + // devAcc, + // devHost, + // queueAcc, + // n, + // permutationIterBegin, + // sum); + + // // check reduce result + // auto expectedResult = n * 10; + // std::cout << "Expected reduce result: " << expectedResult << ", real result: " << reduceResult << "\n"; + + // TRANSFORM_REDUCE CALL: + // Takes the arguments: accelerator device, host device, accelerator queue, size of data, pointer-like to memory, + // transform lambda, reduce lambda. + // Idx transformReduceResult = vikunja::reduce::deviceTransformReduce( + // devAcc, + // devHost, + // queueAcc, + // n, + // permutationIterBegin, + // doubleNum, + // sum); + + // // check transform result + // auto expectedTransformReduce = expectedResult * 2; + // std::cout << "Expected transform_reduce result: " << expectedTransformReduce + // << ", real result: " << transformReduceResult << "\n"; + + return 0; +} diff --git a/include/vikunja/mem/iterator/PermutationIterator.hpp b/include/vikunja/mem/iterator/PermutationIterator.hpp new file mode 100644 index 0000000..37924c3 --- /dev/null +++ b/include/vikunja/mem/iterator/PermutationIterator.hpp @@ -0,0 +1,274 @@ +#pragma once + +#include + +#include + +// check for spaceship support +#if defined __has_include +# if __has_include() +# include +# endif +# if __has_include() +# include +# if defined(__cpp_lib_three_way_comparison) && defined(__cpp_impl_three_way_comparison) +# define USESPACESHIP +# endif +# endif +#endif + +#if __has_cpp_attribute(nodiscard) +# define NODISCARD [[nodiscard]] +#else +# define NODISCARD +#endif + +namespace vikunja +{ + namespace mem + { + namespace iterator + { + template + class PermutationIterator + { + public: + using difference_type = int64_t; + using value_type = typename std::iterator_traits::value_type; + using pointer = typename std::iterator_traits::pointer; + using reference = typename std::iterator_traits::reference; + using iterator_category = std::random_access_iterator_tag; + + //----------------------------------------------------------------------------- + //! Constructor. + //! + //! \param data Data. + ALPAKA_FN_HOST_ACC ALPAKA_FN_INLINE + PermutationIterator(const ElementIterator& _elIter, const IndexIterator& _idxIter, const IdxType& _idx = static_cast(0)) + : elIter(_elIter) + , idxIter(_idxIter) + , idx(_idx) + { + } + + /** + * @brief Dereference operator to receive the stored value + */ + NODISCARD ALPAKA_FN_INLINE reference operator*() const + { + return *(elIter + *idxIter); + } + + /** + * @brief Index operator to get stored value at some given offset from this iterator + */ + NODISCARD ALPAKA_FN_INLINE reference operator[](int _idx) + { + static_assert(std::is_convertible::iterator_category>::value, + "The function only accepts random access iterators or raw pointers to an array.\n"); + std::advance(idxIter, _idx - idx); + idx = _idx; + return elIter[*(idxIter)]; + } + + /** + * @brief Index operator to get stored value at some given offset from this iterator + */ + NODISCARD ALPAKA_FN_INLINE PermutationIterator begin() + { + return PermutationIterator(elIter, idxIter, 0); + } + + /** + * @brief Index operator to get stored value at some given offset from this iterator + */ + NODISCARD ALPAKA_FN_INLINE PermutationIterator end() + { + return PermutationIterator(elIter, idxIter, 3); + } + +#pragma region arithmeticoperators + /** + * @brief Prefix increment operator + */ + NODISCARD ALPAKA_FN_INLINE PermutationIterator& operator++() + { + ++idx; + return *this; + } + + /** + * @brief Postfix increment operator + * @note Use prefix increment operator instead if possible to avoid copies + */ + NODISCARD ALPAKA_FN_INLINE PermutationIterator operator++(int) + { + PermutationIterator cpy = *this; + ++idx; + return cpy; + } + + /** + * @brief Prefix decrement operator + */ + NODISCARD ALPAKA_FN_INLINE PermutationIterator& operator--() + { + // static_assert(std::is_convertible::iterator_category>::value, + // "The function only accepts random access iterators or raw pointers to an array.\n"); + --idx; + return *this; + } + + /** + * @brief Postfix decrement operator + * @note Use prefix decrement operator instead if possible to avoid copies + */ + NODISCARD ALPAKA_FN_INLINE PermutationIterator operator--(int) + { + // static_assert(std::is_convertible::iterator_category>::value, + // "The function only accepts random access iterators or raw pointers to an array.\n"); + PermutationIterator cpy = *this; + --idx; + return cpy; + } + + /** + * @brief Add an index to this iterator + */ + NODISCARD ALPAKA_FN_INLINE PermutationIterator operator+(const IdxType _idx) const + { + return PermutationIterator(elIter, idxIter, idx + _idx); + } + + /** + * @brief Add a second constant iterator of the same value to this one + */ + NODISCARD ALPAKA_FN_INLINE PermutationIterator operator+(const PermutationIterator& other) const + { + return PermutationIterator(elIter.insert(std::end(elIter), std::begin(other.elIter), std::end(other.elIter)), idxIter.insert(std::end(idxIter), std::begin(other.idxIter), std::end(other.idxIter))); + } + + /** + * @brief Subtract an index from this iterator + */ + NODISCARD ALPAKA_FN_INLINE PermutationIterator operator-(const IdxType _idx) const + { + return PermutationIterator(elIter, idxIter); + } + + /** + * @brief Subtract a second constant iterator of the same value from this one + */ + NODISCARD ALPAKA_FN_INLINE PermutationIterator operator-(const PermutationIterator& other) const + { + return PermutationIterator(elIter, idxIter); + } + + /** + * @brief Add an index to this iterator + */ + NODISCARD ALPAKA_FN_INLINE PermutationIterator& operator+=(const IdxType _idx) + { + idx += _idx; + return *this; + } + + /** + * @brief Subtract an index from this iterator + */ + NODISCARD ALPAKA_FN_INLINE PermutationIterator& operator-=(const IdxType _idx) + { + idx -= _idx; + return *this; + } + +#pragma endregion arithmeticoperators + +#pragma region comparisonoperators + +// if spaceship operator is available is being used we can use spaceship operator magic +#ifdef USESPACESHIP + + /** + * @brief Spaceship operator for comparisons + */ + NODISCARD ALPAKA_FN_INLINE auto operator<=>(const PermutationIterator& other) const noexcept = default; + +// if cpp20 *isn't* defined we get to write 70 lines of boilerplate +#else + + /** + * @brief Equality comparison, returns true if the iterators are the same + */ + NODISCARD ALPAKA_FN_INLINE bool operator==(const PermutationIterator& other) const noexcept + { + return elIter == other.elIter && idxIter == other.idxIter; + } + + /** + * @brief Inequality comparison, negated equality operator + */ + NODISCARD ALPAKA_FN_INLINE bool operator!=(const PermutationIterator& other) const noexcept + { + return !operator==(other); + } + + /** + * @brief Less than comparison, value is checked first, then index + */ + NODISCARD ALPAKA_FN_INLINE bool operator<(const PermutationIterator& other) const noexcept + { + if (elIter < other.elIter) + return true; + if (elIter > other.elIter) + return false; + return idxIter < other.idxIter; + } + + /** + * @brief Greater than comparison, value is checked first, then index + */ + NODISCARD ALPAKA_FN_INLINE bool operator>(const PermutationIterator& other) const noexcept + { + if (elIter > other.elIter) + return true; + if (elIter < other.elIter) + return false; + return idxIter > other.idxIter; + } + + /** + * @brief Less than or equal comparison, value is checked first, then index + */ + NODISCARD ALPAKA_FN_INLINE bool operator<=(const PermutationIterator& other) const noexcept + { + if (elIter < other.elIter) + return true; + if (elIter > other.elIter) + return false; + return idxIter <= other.idxIter; + } + + /** + * @brief Greater than or equal comparison, value is checked first, then index + */ + NODISCARD ALPAKA_FN_INLINE bool operator>=(const PermutationIterator& other) const noexcept + { + if (elIter > other.elIter) + return true; + if (elIter < other.elIter) + return false; + return idxIter >= other.idxIter; + } +#endif + +#pragma endregion comparisonoperators + + private: + ElementIterator elIter; + IndexIterator idxIter; + IdxType idx; + }; + } // namespace iterator + } // namespace mem +} // namespace vikunja