Skip to content

Commit

Permalink
powerset intersection
Browse files Browse the repository at this point in the history
  • Loading branch information
felixguendling committed Apr 10, 2024
1 parent 67414c9 commit b83c0af
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
46 changes: 46 additions & 0 deletions include/utl/power_set_intersection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once

#include <functional>
#include <type_traits>

namespace utl {

template <bool Swap, typename It, typename Lt, typename Fn>
void for_each_equal(It const a, It b, It const b_end, Lt&& lt, Fn&& fn) {
while (b != b_end) {
if (lt(*a, *b) || lt(*b, *a)) {
return;
}
Swap ? fn(*b, *a) : fn(*a, *b);
++b;
}
}

template <typename It, typename Fn,
typename Lt = std::less<decltype(*std::declval<It>())>>
void power_set_intersection(It const a_begin, It const a_end, It const b_begin,
It const b_end, Fn&& fn, Lt&& lt = Lt{}) {
auto a = a_begin;
auto b = b_begin;
while (a != a_end && b != b_end) {
if (lt(*a, *b)) {
++a;
} else if (lt(*b, *a)) {
++b;
} else {
for_each_equal<false>(a, b, b_end, lt, fn);
++a;
for_each_equal<true>(b, a, a_end, lt, fn);
++b;
}
}
}

template <typename A, typename B, typename Fn,
typename Lt = std::less<decltype(*begin(std::declval<A>()))>>
void power_set_intersection(A const& a, B const& b, Fn&& fn, Lt&& lt = Lt{}) {
power_set_intersection(begin(a), end(a), begin(b), end(b),
std::forward<Fn>(fn), std::forward<Lt>(lt));
}

} // namespace utl
38 changes: 38 additions & 0 deletions test/power_set_intersection_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include "gtest/gtest.h"

#include <vector>

#include "utl/power_set_intersection.h"

namespace {

struct k {
friend std::ostream& operator<<(std::ostream& out, k const& x) {
return out << "(" << x.a_ << ", " << x.b_ << ")";
}
friend bool operator==(k const& a, k const& b) {
return a.a_ == b.a_ && a.b_ == b.b_;
}
friend bool operator<(k const& a, k const& b) { return a.a_ < b.a_; }
int a_, b_;
};

} // namespace

TEST(power_set_intersection, basic) {
auto intersection = std::vector<std::pair<k, k>>{};
utl::power_set_intersection(
std::vector<k>{{1, 100}, {1, 200}, {2, 300}, {3, 400}, {3, 500}},
std::vector<k>{{1, 600}, {2, 700}, {2, 800}, {3, 900}, {3, 1000}},
[&](auto&& x, auto&& y) { intersection.emplace_back(x, y); });

auto const expected =
std::vector<std::pair<k, k>>{{{1, 100}, {1, 600}}, {{1, 200}, {1, 600}},

{{2, 300}, {2, 700}}, {{2, 300}, {2, 800}},

{{3, 400}, {3, 900}}, {{3, 400}, {3, 1000}},
{{3, 500}, {3, 900}}, {{3, 500}, {3, 1000}}};

EXPECT_EQ(expected, intersection);
}

0 comments on commit b83c0af

Please sign in to comment.