22#include "absl/container/flat_hash_set.h"
27inline bool Connects(std::function<
bool(
int,
int)>
graph,
int i,
int j) {
28 return i == j ||
graph(i, j);
51void Search(std::function<
bool(
int,
int)>
graph,
52 std::function<
bool(
const std::vector<int>&)>
callback,
53 int* input_candidates,
int first_candidate_index,
54 int num_input_candidates, std::vector<int>* current_clique,
66 int disconnected_node = 0;
74 int num_disconnected_candidates = num_input_candidates;
79 int pre_increment = 0;
82 for (
int i = 0;
i < num_input_candidates && num_disconnected_candidates != 0;
84 int pivot_candidate = input_candidates[
i];
94 int disconnected_node_candidate = 0;
99 for (
int j = first_candidate_index;
100 j < num_input_candidates && count < num_disconnected_candidates; ++j) {
101 if (!Connects(
graph, pivot_candidate, input_candidates[j])) {
103 disconnected_node_candidate = j;
109 if (count < num_disconnected_candidates) {
110 pivot = pivot_candidate;
111 num_disconnected_candidates = count;
113 if (i < first_candidate_index) {
114 disconnected_node = disconnected_node_candidate;
116 disconnected_node =
i;
124 std::vector<int> new_candidates;
125 new_candidates.reserve(num_input_candidates);
126 for (
int remaining_candidates = num_disconnected_candidates + pre_increment;
127 remaining_candidates >= 1; remaining_candidates--) {
131 const int selected = input_candidates[disconnected_node];
132 std::swap(input_candidates[disconnected_node],
133 input_candidates[first_candidate_index]);
136 new_candidates.clear();
137 for (
int i = 0;
i < first_candidate_index; ++
i) {
138 if (Connects(
graph, selected, input_candidates[i])) {
139 new_candidates.push_back(input_candidates[i]);
142 const int new_first_candidate_index = new_candidates.size();
143 for (
int i = first_candidate_index + 1;
i < num_input_candidates; ++
i) {
144 if (Connects(
graph, selected, input_candidates[i])) {
145 new_candidates.push_back(input_candidates[i]);
148 const int new_candidate_size = new_candidates.size();
151 current_clique->push_back(selected);
155 if (new_candidate_size == 0) {
158 if (new_first_candidate_index < new_candidate_size) {
160 new_first_candidate_index, new_candidate_size, current_clique,
169 current_clique->pop_back();
174 first_candidate_index++;
177 if (remaining_candidates > 1) {
178 disconnected_node = first_candidate_index;
179 while (disconnected_node < num_input_candidates &&
180 Connects(
graph, pivot, input_candidates[disconnected_node])) {
187class FindAndEliminate {
189 FindAndEliminate(std::function<
bool(
int,
int)>
graph,
int node_count,
190 std::function<
bool(
const std::vector<int>&)>
callback)
192 node_count_(node_count),
195 bool GraphCallback(
int node1,
int node2) {
197 std::make_pair(std::min(node1, node2), std::max(node1, node2))) !=
201 return Connects(graph_, node1, node2);
204 bool SolutionCallback(
const std::vector<int>&
solution) {
207 for (
int i = 0;
i <
size - 1; ++
i) {
208 for (
int j = i + 1; j <
size; ++j) {
219 std::function<bool(
int,
int)> graph_;
221 std::function<bool(
const std::vector<int>&)> callback_;
222 absl::flat_hash_set<std::pair<int, int>> visited_;
229 std::function<
bool(
const std::vector<int>&)>
callback) {
230 std::unique_ptr<int[]> initial_candidates(
new int[node_count]);
231 std::vector<int> actual;
233 for (
int c = 0; c < node_count; ++c) {
234 initial_candidates[c] = c;
239 node_count, &actual, &stop);
243 std::function<
bool(
const std::vector<int>&)>
callback) {
244 FindAndEliminate cache(std::move(
graph), node_count, std::move(
callback));
245 std::unique_ptr<int[]> initial_candidates(
new int[node_count]);
246 std::vector<int> actual;
248 std::function<bool(
int,
int)> cached_graph = [&cache](
int i,
int j) {
249 return cache.GraphCallback(i, j);
251 std::function<bool(
const std::vector<int>&)> cached_callback =
252 [&cache](
const std::vector<int>& res) {
253 return cache.SolutionCallback(res);
256 for (
int c = 0; c < node_count; ++c) {
257 initial_candidates[c] = c;
261 Search(std::move(cached_graph), std::move(cached_callback),
262 initial_candidates.get(), 0, node_count, &actual, &stop);
---------------— Search class --------------—
In SWIG mode, we don't want anything besides these top-level includes.
void FindCliques(std::function< bool(int, int)> graph, int node_count, std::function< bool(const std::vector< int > &)> callback)
void CoverArcsByCliques(std::function< bool(int, int)> graph, int node_count, std::function< bool(const std::vector< int > &)> callback)