mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Add permutation functions (#1348)
* Print test names at test time (#1343) * Add permutation functions * Refactor permutation to use etl::less * Add test for next_permutation where begin == end * Update code to avoid multiple bind1st objects in loop * Remove duplicate is_partitioned test case Removed the duplicate is_partitioned test case from the test suite. --------- Co-authored-by: Roland Reichwein <Roland.Reichwein@bmw.de> Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
parent
29ad4b327e
commit
325908b1b9
@ -2005,11 +2005,12 @@ namespace etl
|
||||
|
||||
for (TIterator1 i = begin1; i != end1; ++i)
|
||||
{
|
||||
if (i == etl::find_if(begin1, i, etl::bind1st(predicate, *i)))
|
||||
const typename etl::binder1st<TBinaryPredicate> predicate_is_i = etl::bind1st(predicate, *i);
|
||||
if (i == etl::find_if(begin1, i, predicate_is_i))
|
||||
{
|
||||
size_t n = etl::count_if(begin2, end2, etl::bind1st(predicate, *i));
|
||||
size_t n = etl::count_if(begin2, end2, predicate_is_i);
|
||||
|
||||
if (n == 0 || size_t(etl::count_if(i, end1, etl::bind1st(predicate, *i))) != n)
|
||||
if (n == 0 || size_t(etl::count_if(i, end1, predicate_is_i)) != n)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -2038,15 +2039,18 @@ namespace etl
|
||||
return false;
|
||||
}
|
||||
|
||||
for (TIterator1 i = begin1; i != end1; ++i)
|
||||
if (begin1 != end1)
|
||||
{
|
||||
if (i == etl::find(begin1, i, *i))
|
||||
for (TIterator1 i = begin1; i != end1; ++i)
|
||||
{
|
||||
size_t n = etl::count(begin2, end2, *i);
|
||||
|
||||
if (n == 0 || size_t(etl::count(i, end1, *i)) != n)
|
||||
if (i == etl::find(begin1, i, *i))
|
||||
{
|
||||
return false;
|
||||
size_t n = etl::count(begin2, end2, *i);
|
||||
|
||||
if (n == 0 || size_t(etl::count(i, end1, *i)) != n)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2073,15 +2077,19 @@ namespace etl
|
||||
return false;
|
||||
}
|
||||
|
||||
for (TIterator1 i = begin1; i != end1; ++i)
|
||||
if (begin1 != end1)
|
||||
{
|
||||
if (i == etl::find_if(begin1, i, etl::bind1st(predicate, *i)))
|
||||
for (TIterator1 i = begin1; i != end1; ++i)
|
||||
{
|
||||
size_t n = etl::count_if(begin2, end2, etl::bind1st(predicate, *i));
|
||||
|
||||
if (n == 0 || size_t(etl::count_if(i, end1, etl::bind1st(predicate, *i))) != n)
|
||||
const typename etl::binder1st<TBinaryPredicate> predicate_is_i = etl::bind1st(predicate, *i);
|
||||
if (i == etl::find_if(begin1, i, predicate_is_i))
|
||||
{
|
||||
return false;
|
||||
size_t n = etl::count_if(begin2, end2, predicate_is_i);
|
||||
|
||||
if (n == 0 || size_t(etl::count_if(i, end1, predicate_is_i)) != n)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2089,6 +2097,132 @@ namespace etl
|
||||
return true;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// next_permutation
|
||||
///\ingroup algorithm
|
||||
///<a href="http://en.cppreference.com/w/cpp/algorithm/next_permutation"></a>
|
||||
//***************************************************************************
|
||||
template <typename TIterator, typename TCompare>
|
||||
ETL_CONSTEXPR14
|
||||
bool next_permutation(TIterator first, TIterator last, TCompare compare)
|
||||
{
|
||||
if (first == last)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TIterator i = last;
|
||||
--i;
|
||||
|
||||
if (first == i)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
TIterator i1 = i;
|
||||
--i;
|
||||
|
||||
if (compare(*i, *i1))
|
||||
{
|
||||
TIterator j = last;
|
||||
--j;
|
||||
|
||||
while (!compare(*i, *j))
|
||||
{
|
||||
--j;
|
||||
}
|
||||
|
||||
etl::iter_swap(i, j);
|
||||
etl::reverse(i1, last);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (i == first)
|
||||
{
|
||||
etl::reverse(first, last);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// next_permutation
|
||||
///\ingroup algorithm
|
||||
///<a href="http://en.cppreference.com/w/cpp/algorithm/next_permutation"></a>
|
||||
//***************************************************************************
|
||||
template <typename TIterator>
|
||||
ETL_CONSTEXPR14
|
||||
bool next_permutation(TIterator first, TIterator last)
|
||||
{
|
||||
typedef etl::less<typename etl::iterator_traits<TIterator>::value_type> compare;
|
||||
return etl::next_permutation(first, last, compare());
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// prev_permutation
|
||||
///\ingroup algorithm
|
||||
///<a href="http://en.cppreference.com/w/cpp/algorithm/prev_permutation"></a>
|
||||
//***************************************************************************
|
||||
template <typename TIterator, typename TCompare>
|
||||
ETL_CONSTEXPR14
|
||||
bool prev_permutation(TIterator first, TIterator last, TCompare compare)
|
||||
{
|
||||
if (first == last)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TIterator i = last;
|
||||
--i;
|
||||
|
||||
if (first == i)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
TIterator i1 = i;
|
||||
--i;
|
||||
|
||||
if (compare(*i1, *i))
|
||||
{
|
||||
TIterator j = last;
|
||||
--j;
|
||||
|
||||
while (!compare(*j, *i))
|
||||
{
|
||||
--j;
|
||||
}
|
||||
|
||||
etl::iter_swap(i, j);
|
||||
etl::reverse(i1, last);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (i == first)
|
||||
{
|
||||
etl::reverse(first, last);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// prev_permutation
|
||||
///\ingroup algorithm
|
||||
///<a href="http://en.cppreference.com/w/cpp/algorithm/prev_permutation"></a>
|
||||
//***************************************************************************
|
||||
template <typename TIterator>
|
||||
ETL_CONSTEXPR14
|
||||
bool prev_permutation(TIterator first, TIterator last)
|
||||
{
|
||||
typedef etl::less<typename etl::iterator_traits<TIterator>::value_type> compare;
|
||||
return etl::prev_permutation(first, last, compare());
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// is_partitioned
|
||||
///\ingroup algorithm
|
||||
|
||||
@ -116,6 +116,14 @@ namespace
|
||||
}
|
||||
};
|
||||
|
||||
struct DataEquivalenceByA : public etl::binary_function<Data, Data, bool>
|
||||
{
|
||||
bool operator ()(const Data& lhs, const Data& rhs) const
|
||||
{
|
||||
return lhs.a == rhs.a;
|
||||
}
|
||||
};
|
||||
|
||||
Data dataD[10] = { Data(1, 2), Data(2, 1), Data(3, 4), Data(4, 3), Data(5, 6), Data(6, 5), Data(7, 8), Data(8, 7), Data(9, 10), Data(10, 9) };
|
||||
|
||||
struct Greater : public etl::binary_function<int, int, bool>
|
||||
@ -3449,18 +3457,174 @@ namespace
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(stable_sort_greater)
|
||||
TEST(next_permutation)
|
||||
{
|
||||
std::vector<NDC> initial_data = { NDC(1, 1), NDC(2, 1), NDC(3, 1), NDC(2, 2), NDC(3, 2), NDC(4, 1), NDC(2, 3), NDC(3, 3), NDC(5, 1) };
|
||||
std::array<int, 4U> expected = { 1, 1, 2, 2 };
|
||||
std::array<int, 4U> result = expected;
|
||||
|
||||
std::vector<NDC> data1(initial_data);
|
||||
std::vector<NDC> data2(initial_data);
|
||||
for (size_t i = 0U; i < 8U; ++i)
|
||||
{
|
||||
bool expected_has_next = std::next_permutation(expected.begin(), expected.end());
|
||||
bool result_has_next = etl::next_permutation(result.begin(), result.end());
|
||||
|
||||
std::stable_sort(data1.begin(), data1.end(), std::greater<NDC>());
|
||||
etl::stable_sort(data2.begin(), data2.end(), std::greater<NDC>());
|
||||
CHECK_EQUAL(expected_has_next, result_has_next);
|
||||
CHECK_ARRAY_EQUAL(expected.data(), result.data(), result.size());
|
||||
}
|
||||
|
||||
bool is_same = std::equal(data1.begin(), data1.end(), data2.begin(), NDC::are_identical);
|
||||
CHECK(is_same);
|
||||
// Check one past the end.
|
||||
bool expected_has_next = std::next_permutation(expected.begin(), expected.end());
|
||||
bool result_has_next = etl::next_permutation(result.begin(), result.end());
|
||||
CHECK_EQUAL(expected_has_next, result_has_next);
|
||||
CHECK_ARRAY_EQUAL(expected.data(), result.data(), result.size());
|
||||
|
||||
int single_expected[] = { 1 };
|
||||
int single_result[] = { 1 };
|
||||
|
||||
expected_has_next = std::next_permutation(std::begin(single_expected), std::end(single_expected));
|
||||
result_has_next = etl::next_permutation(std::begin(single_result), std::end(single_result));
|
||||
|
||||
CHECK_EQUAL(expected_has_next, result_has_next);
|
||||
CHECK_ARRAY_EQUAL(single_expected, single_result, 1U);
|
||||
|
||||
// Check for what happens if the beginning and end are the same.
|
||||
expected_has_next = std::next_permutation(std::begin(single_expected), std::begin(single_expected));
|
||||
result_has_next = etl::next_permutation(std::begin(single_result), std::begin(single_result));
|
||||
|
||||
CHECK_EQUAL(expected_has_next, result_has_next);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(next_permutation_compare)
|
||||
{
|
||||
std::array<int, 4U> expected = { 3, 2, 2, 1 };
|
||||
std::array<int, 4U> result = expected;
|
||||
|
||||
for (size_t i = 0U; i < 8U; ++i)
|
||||
{
|
||||
bool expected_has_next = std::next_permutation(expected.begin(), expected.end(), std::greater<int>());
|
||||
bool result_has_next = etl::next_permutation(result.begin(), result.end(), std::greater<int>());
|
||||
|
||||
CHECK_EQUAL(expected_has_next, result_has_next);
|
||||
CHECK_ARRAY_EQUAL(expected.data(), result.data(), result.size());
|
||||
}
|
||||
|
||||
// Check one past the end.
|
||||
bool expected_has_next = std::next_permutation(expected.begin(), expected.end(), std::greater<int>());
|
||||
bool result_has_next = etl::next_permutation(result.begin(), result.end(), std::greater<int>());
|
||||
CHECK_EQUAL(expected_has_next, result_has_next);
|
||||
CHECK_ARRAY_EQUAL(expected.data(), result.data(), result.size());
|
||||
|
||||
int single_expected[] = { 1 };
|
||||
int single_result[] = { 1 };
|
||||
|
||||
// Check for what happens if the beginning and end are the same.
|
||||
expected_has_next = std::next_permutation(std::begin(single_expected), std::begin(single_expected), std::greater<int>());
|
||||
result_has_next = etl::next_permutation(std::begin(single_result), std::begin(single_result), std::greater<int>());
|
||||
|
||||
CHECK_EQUAL(expected_has_next, result_has_next);
|
||||
CHECK_ARRAY_EQUAL(single_expected, single_result, 1U);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(prev_permutation)
|
||||
{
|
||||
std::array<int, 4U> expected = { 2, 2, 1, 1 };
|
||||
std::array<int, 4U> result = expected;
|
||||
|
||||
for (size_t i = 0U; i < 8U; ++i)
|
||||
{
|
||||
bool expected_has_prev = std::prev_permutation(expected.begin(), expected.end());
|
||||
bool result_has_prev = etl::prev_permutation(result.begin(), result.end());
|
||||
|
||||
CHECK_EQUAL(expected_has_prev, result_has_prev);
|
||||
CHECK_ARRAY_EQUAL(expected.data(), result.data(), result.size());
|
||||
}
|
||||
|
||||
// Check one past the end.
|
||||
bool expected_has_prev = std::prev_permutation(expected.begin(), expected.end());
|
||||
bool result_has_prev = etl::prev_permutation(result.begin(), result.end());
|
||||
CHECK_EQUAL(expected_has_prev, result_has_prev);
|
||||
CHECK_ARRAY_EQUAL(expected.data(), result.data(), result.size());
|
||||
|
||||
int single_expected[] = { 1 };
|
||||
int single_result[] = { 1 };
|
||||
|
||||
expected_has_prev = std::prev_permutation(std::begin(single_expected), std::end(single_expected));
|
||||
result_has_prev = etl::prev_permutation(std::begin(single_result), std::end(single_result));
|
||||
|
||||
CHECK_EQUAL(expected_has_prev, result_has_prev);
|
||||
CHECK_ARRAY_EQUAL(single_expected, single_result, 1U);
|
||||
|
||||
// Check for what happens if the beginning and end are the same.
|
||||
expected_has_prev = std::prev_permutation(std::begin(single_expected), std::begin(single_expected));
|
||||
result_has_prev = etl::prev_permutation(std::begin(single_result), std::begin(single_result));
|
||||
|
||||
CHECK_EQUAL(expected_has_prev, result_has_prev);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(prev_permutation_compare)
|
||||
{
|
||||
std::array<int, 4U> expected = { 1, 1, 2, 3 };
|
||||
std::array<int, 4U> result = expected;
|
||||
|
||||
for (size_t i = 0U; i < 8U; ++i)
|
||||
{
|
||||
bool expected_has_prev = std::prev_permutation(expected.begin(), expected.end(), std::greater<int>());
|
||||
bool result_has_prev = etl::prev_permutation(result.begin(), result.end(), std::greater<int>());
|
||||
|
||||
CHECK_EQUAL(expected_has_prev, result_has_prev);
|
||||
CHECK_ARRAY_EQUAL(expected.data(), result.data(), result.size());
|
||||
}
|
||||
|
||||
// Check one past the end.
|
||||
bool expected_has_prev = std::prev_permutation(expected.begin(), expected.end(), std::greater<int>());
|
||||
bool result_has_prev = etl::prev_permutation(result.begin(), result.end(), std::greater<int>());
|
||||
CHECK_EQUAL(expected_has_prev, result_has_prev);
|
||||
CHECK_ARRAY_EQUAL(expected.data(), result.data(), result.size());
|
||||
|
||||
int single_expected[] = { 1 };
|
||||
int single_result[] = { 1 };
|
||||
|
||||
// Check for what happens if the beginning and end are the same.
|
||||
expected_has_prev = std::prev_permutation(std::begin(single_expected), std::begin(single_expected), std::greater<int>());
|
||||
result_has_prev = etl::prev_permutation(std::begin(single_result), std::begin(single_result), std::greater<int>());
|
||||
|
||||
CHECK_EQUAL(expected_has_prev, result_has_prev);
|
||||
CHECK_ARRAY_EQUAL(single_expected, single_result, 1U);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(is_permutation_length_mismatch)
|
||||
{
|
||||
int data1[] = { 1, 2, 3 };
|
||||
int data2[] = { 1, 2, 3, 4 };
|
||||
|
||||
bool is_permutation = etl::is_permutation(std::begin(data1), std::end(data1), std::begin(data2), std::end(data2));
|
||||
CHECK_FALSE(is_permutation);
|
||||
|
||||
is_permutation = etl::is_permutation(std::begin(data1), std::end(data1), std::begin(data2), std::end(data2), etl::equal_to<int>());
|
||||
CHECK_FALSE(is_permutation);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(is_permutation_predicate)
|
||||
{
|
||||
Data data1[] = { Data(1, 10), Data(2, 20), Data(2, 30), Data(3, 40) };
|
||||
Data permutation[] = { Data(2, 200), Data(1, 100), Data(3, 300), Data(2, 400) };
|
||||
Data not_permutation[] = { Data(2, 200), Data(1, 100), Data(4, 300), Data(2, 400) };
|
||||
|
||||
bool is_permutation = etl::is_permutation(std::begin(data1), std::end(data1), std::begin(permutation), DataEquivalenceByA());
|
||||
CHECK_TRUE(is_permutation);
|
||||
|
||||
is_permutation = etl::is_permutation(std::begin(data1), std::end(data1), std::begin(not_permutation), DataEquivalenceByA());
|
||||
CHECK_FALSE(is_permutation);
|
||||
|
||||
is_permutation = etl::is_permutation(std::begin(data1), std::end(data1), std::begin(permutation), std::end(permutation), DataEquivalenceByA());
|
||||
CHECK_TRUE(is_permutation);
|
||||
|
||||
is_permutation = etl::is_permutation(std::begin(data1), std::end(data1), std::begin(not_permutation), std::end(not_permutation), DataEquivalenceByA());
|
||||
CHECK_FALSE(is_permutation);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user