mirror of
https://github.com/VectorCamp/vectorscan.git
synced 2025-06-28 16:41:01 +03:00
Optimize max clique analysis
Use vectors of state ids to avoid the overhead of subgraph copies
This commit is contained in:
parent
1507b3fd36
commit
e8bfe5478b
@ -145,7 +145,6 @@ struct CliqueVertexProps {
|
|||||||
u32 stateId = ~0U;
|
u32 stateId = ~0U;
|
||||||
u32 parentId = ~0U;
|
u32 parentId = ~0U;
|
||||||
bool leftChild = false; /* tells us if it is the left child of its parent */
|
bool leftChild = false; /* tells us if it is the left child of its parent */
|
||||||
bool rightChildVisited = false; /* tells us if its right child is visited */
|
|
||||||
|
|
||||||
vector<u32> clique1; /* clique for the left branch */
|
vector<u32> clique1; /* clique for the left branch */
|
||||||
vector<u32> indepSet1; /* independent set for the left branch */
|
vector<u32> indepSet1; /* independent set for the left branch */
|
||||||
@ -188,56 +187,6 @@ unique_ptr<CliqueGraph> makeCG(const vector<vector<u32>> &exclusiveSet) {
|
|||||||
return cg;
|
return cg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
CliqueGraph createSubgraph(const CliqueGraph &cg,
|
|
||||||
const vector<CliqueVertex> &vertices) {
|
|
||||||
CliqueGraph g;
|
|
||||||
map<u32, CliqueVertex> vertexMap;
|
|
||||||
for (auto u : vertices) {
|
|
||||||
u32 id = cg[u].stateId;
|
|
||||||
CliqueVertex v = add_vertex(CliqueVertexProps(id), g);
|
|
||||||
vertexMap[id] = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
set<u32> found;
|
|
||||||
for (auto u : vertices) {
|
|
||||||
u32 srcId = cg[u].stateId;
|
|
||||||
CliqueVertex src = vertexMap[srcId];
|
|
||||||
found.insert(srcId);
|
|
||||||
for (auto n : adjacent_vertices_range(u, cg)) {
|
|
||||||
u32 dstId = cg[n].stateId;
|
|
||||||
if (found.find(dstId) == found.end() &&
|
|
||||||
vertexMap.find(dstId) != vertexMap.end()) {
|
|
||||||
CliqueVertex dst = vertexMap[dstId];
|
|
||||||
add_edge(src, dst, g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return g;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void getNeighborInfo(const CliqueGraph &g, vector<CliqueVertex> &neighbor,
|
|
||||||
vector<CliqueVertex> &nonneighbor,
|
|
||||||
const CliqueVertex &cv) {
|
|
||||||
u32 id = g[cv].stateId;
|
|
||||||
ue2::unordered_set<u32> neighborId;
|
|
||||||
|
|
||||||
// find neighbors for cv
|
|
||||||
for (auto v : adjacent_vertices_range(cv, g)) {
|
|
||||||
neighbor.push_back(v);
|
|
||||||
neighborId.insert(g[v].stateId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// find non-neighbors for cv
|
|
||||||
for (auto v : vertices_range(g)) {
|
|
||||||
if (g[v].stateId != id &&
|
|
||||||
neighborId.find(g[v].stateId) == neighborId.end()) {
|
|
||||||
nonneighbor.push_back(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
void updateCliqueInfo(CliqueGraph &cg, const CliqueVertex &n,
|
void updateCliqueInfo(CliqueGraph &cg, const CliqueVertex &n,
|
||||||
vector<u32> &clique, vector<u32> &indepSet) {
|
vector<u32> &clique, vector<u32> &indepSet) {
|
||||||
@ -257,59 +206,82 @@ void updateCliqueInfo(CliqueGraph &cg, const CliqueVertex &n,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void getNeighborInfo(const CliqueGraph &g, vector<u32> &neighbor,
|
||||||
|
vector<u32> &nonneighbor, const CliqueVertex &cv,
|
||||||
|
const set<u32> &group) {
|
||||||
|
u32 id = g[cv].stateId;
|
||||||
|
ue2::unordered_set<u32> neighborId;
|
||||||
|
|
||||||
|
// find neighbors for cv
|
||||||
|
for (const auto &v : adjacent_vertices_range(cv, g)) {
|
||||||
|
if (g[v].stateId != id && contains(group, g[v].stateId)) {
|
||||||
|
neighbor.push_back(g[v].stateId);
|
||||||
|
neighborId.insert(g[v].stateId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
neighborId.insert(id);
|
||||||
|
// find non-neighbors for cv
|
||||||
|
for (const auto &v : vertices_range(g)) {
|
||||||
|
if (!contains(neighborId, g[v].stateId) &&
|
||||||
|
contains(group, g[v].stateId)) {
|
||||||
|
nonneighbor.push_back(g[v].stateId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void findCliqueGroup(CliqueGraph &cg, vector<u32> &clique,
|
void findCliqueGroup(CliqueGraph &cg, vector<u32> &clique,
|
||||||
vector<u32> &indepSet) {
|
vector<u32> &indepSet) {
|
||||||
stack<CliqueGraph> gStack;
|
stack<vector<u32>> gStack;
|
||||||
gStack.push(cg);
|
|
||||||
|
|
||||||
// create mapping between vertex and id
|
// create mapping between vertex and id
|
||||||
map<u32, CliqueVertex> vertexMap;
|
map<u32, CliqueVertex> vertexMap;
|
||||||
for (auto v : vertices_range(cg)) {
|
vector<u32> init;
|
||||||
|
for (auto &v : vertices_range(cg)) {
|
||||||
vertexMap[cg[v].stateId] = v;
|
vertexMap[cg[v].stateId] = v;
|
||||||
|
init.push_back(cg[v].stateId);
|
||||||
}
|
}
|
||||||
|
gStack.push(init);
|
||||||
|
|
||||||
// get the vertex to start from
|
// get the vertex to start from
|
||||||
ue2::unordered_set<u32> foundVertexId;
|
set<u32> foundVertexId;
|
||||||
|
ue2::unordered_set<u32> visitedId;
|
||||||
CliqueGraph::vertex_iterator vi, ve;
|
CliqueGraph::vertex_iterator vi, ve;
|
||||||
tie(vi, ve) = vertices(cg);
|
tie(vi, ve) = vertices(cg);
|
||||||
CliqueVertex start = *vi;
|
CliqueVertex start = *vi;
|
||||||
u32 startId = cg[start].stateId;
|
u32 startId = cg[start].stateId;
|
||||||
|
DEBUG_PRINTF("startId:%u\n", startId);
|
||||||
bool leftChild = false;
|
bool leftChild = false;
|
||||||
u32 prevId = startId;
|
u32 prevId = startId;
|
||||||
while (!gStack.empty()) {
|
while (!gStack.empty()) {
|
||||||
CliqueGraph g = gStack.top();
|
const auto &g = gStack.top();
|
||||||
gStack.pop();
|
|
||||||
|
|
||||||
// choose a vertex from the graph
|
// choose a vertex from the graph
|
||||||
tie(vi, ve) = vertices(g);
|
assert(!g.empty());
|
||||||
CliqueVertex cv = *vi;
|
u32 id = g[0];
|
||||||
u32 id = g[cv].stateId;
|
CliqueVertex &n = vertexMap.at(id);
|
||||||
|
|
||||||
// corresponding vertex in the original graph
|
vector<u32> neighbor;
|
||||||
CliqueVertex n = vertexMap.at(id);
|
vector<u32> nonneighbor;
|
||||||
|
set<u32> subgraphId(g.begin(), g.end());
|
||||||
vector<CliqueVertex> neighbor;
|
getNeighborInfo(cg, neighbor, nonneighbor, n, subgraphId);
|
||||||
vector<CliqueVertex> nonneighbor;
|
if (contains(foundVertexId, id)) {
|
||||||
getNeighborInfo(g, neighbor, nonneighbor, cv);
|
|
||||||
|
|
||||||
if (foundVertexId.find(id) != foundVertexId.end()) {
|
|
||||||
prevId = id;
|
prevId = id;
|
||||||
// get graph consisting of non-neighbors for right branch
|
// get non-neighbors for right branch
|
||||||
if (!cg[n].rightChildVisited) {
|
if (visitedId.insert(id).second) {
|
||||||
gStack.push(g);
|
DEBUG_PRINTF("right branch\n");
|
||||||
if (!nonneighbor.empty()) {
|
if (!nonneighbor.empty()) {
|
||||||
const CliqueGraph &nSub = createSubgraph(g, nonneighbor);
|
gStack.push(nonneighbor);
|
||||||
gStack.push(nSub);
|
|
||||||
leftChild = false;
|
leftChild = false;
|
||||||
}
|
}
|
||||||
cg[n].rightChildVisited = true;
|
} else {
|
||||||
} else if (id != startId) {
|
if (id != startId) {
|
||||||
// both the left and right branches are visited,
|
// both the left and right branches are visited,
|
||||||
// update its parent's clique and independent sets
|
// update its parent's clique and independent sets
|
||||||
u32 parentId = cg[n].parentId;
|
u32 parentId = cg[n].parentId;
|
||||||
CliqueVertex parent = vertexMap.at(parentId);
|
CliqueVertex &parent = vertexMap.at(parentId);
|
||||||
if (cg[n].leftChild) {
|
if (cg[n].leftChild) {
|
||||||
updateCliqueInfo(cg, n, cg[parent].clique1,
|
updateCliqueInfo(cg, n, cg[parent].clique1,
|
||||||
cg[parent].indepSet1);
|
cg[parent].indepSet1);
|
||||||
@ -318,15 +290,19 @@ void findCliqueGroup(CliqueGraph &cg, vector<u32> &clique,
|
|||||||
cg[parent].indepSet2);
|
cg[parent].indepSet2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
gStack.pop();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
foundVertexId.insert(id);
|
foundVertexId.insert(id);
|
||||||
g[n].leftChild = leftChild;
|
cg[n].leftChild = leftChild;
|
||||||
g[n].parentId = prevId;
|
cg[n].parentId = prevId;
|
||||||
gStack.push(g);
|
cg[n].clique1.clear();
|
||||||
// get graph consisting of neighbors for left branch
|
cg[n].clique2.clear();
|
||||||
|
cg[n].indepSet1.clear();
|
||||||
|
cg[n].indepSet2.clear();
|
||||||
|
// get neighbors for left branch
|
||||||
if (!neighbor.empty()) {
|
if (!neighbor.empty()) {
|
||||||
const CliqueGraph &sub = createSubgraph(g, neighbor);
|
gStack.push(neighbor);
|
||||||
gStack.push(sub);
|
|
||||||
leftChild = true;
|
leftChild = true;
|
||||||
}
|
}
|
||||||
prevId = id;
|
prevId = id;
|
||||||
@ -351,12 +327,12 @@ vector<u32> removeClique(CliqueGraph &cg) {
|
|||||||
while (!graph_empty(cg)) {
|
while (!graph_empty(cg)) {
|
||||||
const vector<u32> &c = cliquesVec.back();
|
const vector<u32> &c = cliquesVec.back();
|
||||||
vector<CliqueVertex> dead;
|
vector<CliqueVertex> dead;
|
||||||
for (auto v : vertices_range(cg)) {
|
for (const auto &v : vertices_range(cg)) {
|
||||||
if (find(c.begin(), c.end(), cg[v].stateId) != c.end()) {
|
if (find(c.begin(), c.end(), cg[v].stateId) != c.end()) {
|
||||||
dead.push_back(v);
|
dead.push_back(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto v : dead) {
|
for (const auto &v : dead) {
|
||||||
clear_vertex(v, cg);
|
clear_vertex(v, cg);
|
||||||
remove_vertex(v, cg);
|
remove_vertex(v, cg);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user