Skip to content
This repository has been archived by the owner on Feb 24, 2024. It is now read-only.

Commit

Permalink
feat: naive layer
Browse files Browse the repository at this point in the history
  • Loading branch information
neko-para committed Aug 22, 2023
1 parent f8f873c commit 375f17a
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 14 deletions.
2 changes: 1 addition & 1 deletion packages/client/src/views/VisualView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function render() {
edges.push(vertIndex.indexOf(to))
}
}
Module.layoutGraph(vertIndex.length, edges)
Module.layoutGraph(vertIndex.length, edges, vertIndex)
}
</script>

Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/wasm.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
declare const Module: {
layoutGraph: (vertCount: number, edges: number[]) => void
layoutGraph: (vertCount: number, edges: number[], names: string[]) => void
}
2 changes: 1 addition & 1 deletion render/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ project(MaaJsonViewer)

set(CMAKE_CXX_STANDARD 20)

add_executable(render main.cpp)
add_executable(render main.cpp graph.cpp deringing.cpp layering.cpp)

target_link_libraries(render embind)
121 changes: 121 additions & 0 deletions render/deringing.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#include "graph.h"

#include <algorithm>
#include <map>
#include <stdio.h>

void tarjan(int cur, int &idx, const std::vector<std::set<int>> &edges,
std::vector<int> &idxs, std::vector<int> &lows,
std::vector<int> &stack, std::vector<int> &instack,
std::vector<std::vector<int>> &result) {
idxs[cur] = idx;
lows[cur] = idx;
idx += 1;
stack.push_back(cur);
instack[cur] = 1;

for (auto to : edges[cur]) {
if (idxs[to] == -1) {
tarjan(to, idx, edges, idxs, lows, stack, instack, result);
lows[cur] = std::min(lows[cur], lows[to]);
} else if (instack[to]) {
lows[cur] = std::min(lows[cur], idxs[to]);
}
}

if (lows[cur] == idxs[cur]) {
int vert;
result.push_back({});
std::vector<int> &res = result.back();
do {
vert = stack.back();
stack.pop_back();
instack[vert] = 0;
res.push_back(vert);
} while (vert != cur);
}
}

std::vector<std::vector<int>> getSCC(const GraphEdges &edges) {
int n = edges.size();
int idx = 0;
std::vector<int> idxs(n, -1);
std::vector<int> lows(n);
std::vector<int> instack(n);
std::vector<int> stack(n);
std::vector<std::vector<int>> result;
for (int i = 0; i < n; i++) {
if (idxs[i] == -1) {
tarjan(i, idx, edges, idxs, lows, stack, instack, result);
}
}
return result;
}

void findLoop(int cur, const GraphEdges &edges, const GraphEdges &erased,
std::vector<int> &path, std::vector<int> &vis,
std::map<std::pair<int, int>, int> &result) {
path.push_back(cur);
vis[cur] = 1;

for (auto to : edges[cur]) {
if (erased[cur].contains(to)) {
continue;
}
if (vis[to]) {
for (int i = 1; i < path.size(); i++) {
result[std::make_pair(path[i - 1], path[i])] += 1;
}
result[std::make_pair(cur, to)] += 1;
} else {
findLoop(to, edges, erased, path, vis, result);
}
}

path.pop_back();
vis[cur] = 0;
}

GraphEdges getFAC(const GraphEdges &edges) {
int n = edges.size();
GraphEdges result(n);

// std::vector<int> inbound(n, 0);
// std::vector<int> outbound(n);

// for (int i = 0; i < n; i++) {
// outbound[i] = edges[i].size();
// for (auto to : edges[i]) {
// inbound[to]++;
// }
// }

auto sccs = getSCC(edges);
for (const auto &scc : sccs) {
if (scc.size() == 1) {
continue;
} else {
auto newg = filterGraph(edges, scc);
std::map<std::pair<int, int>, int> edgeRef;
std::vector<int> path;
std::vector<int> vis(n);
int maxCount = 5;
while (maxCount--) {
edgeRef.clear();
findLoop(scc[0], newg, result, path, vis, edgeRef);
std::vector<std::pair<int, std::pair<int, int>>> es;
for (const auto &[e, v] : edgeRef) {
es.emplace_back(v, e);
}
if (es.size() == 0) {
break;
}
std::sort(es.begin(), es.end());
auto [from, to] = es.back().second;
result[from].insert(to);
}
}
}

return result;
}
61 changes: 61 additions & 0 deletions render/graph.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include "graph.h"

#include <stdio.h>

GraphEdges filterGraph(const GraphEdges &edges, const std::vector<int> &verts) {
int n = edges.size();
GraphEdges result(n);
std::vector<int> vertBucket(n, 0);
for (auto v : verts) {
vertBucket[v] = 1;
}
for (int from = 0; from < n; from++) {
if (!vertBucket[from]) {
continue;
}
auto &es = result[from];
for (auto to : edges[from]) {
if (vertBucket[to]) {
es.insert(to);
}
}
}
return result;
}

GraphEdges buildIndirectGraph(const GraphEdges &edges) {
int n = edges.size();
GraphEdges result(n);
for (int from = 0; from < n; from++) {
for (auto to : edges[from]) {
result[from].insert(to);
result[to].insert(from);
}
}
return result;
}

void travel(int cur, const GraphEdges &edges, std::vector<int> &vis,
std::vector<int> &verts) {
vis[cur] = 1;
verts.push_back(cur);
for (auto to : edges[cur]) {
if (!vis[to]) {
travel(to, edges, vis, verts);
}
}
}

std::vector<std::vector<int>> splitGraph(const GraphEdges &edges) {
int n = edges.size();
std::vector<std::vector<int>> result;
std::vector<int> vis(n, 0);
for (int i = 0; i < n; i++) {
if (!vis[i]) {
std::vector<int> verts;
travel(i, edges, vis, verts);
result.emplace_back(verts);
}
}
return result;
}
15 changes: 15 additions & 0 deletions render/graph.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once
// http://leungwensen.github.io/blog/2017/a-technique-for-drawing-directed-graphs.html

#include <set>
#include <vector>

using GraphEdges = std::vector<std::set<int>>;

GraphEdges getFAC(const GraphEdges &edges);

std::vector<std::vector<int>> getNaiveLayer(const GraphEdges &edges);

GraphEdges filterGraph(const GraphEdges &edges, const std::vector<int> &verts);
GraphEdges buildIndirectGraph(const GraphEdges &edges);
std::vector<std::vector<int>> splitGraph(const GraphEdges &edges);
37 changes: 37 additions & 0 deletions render/layering.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "graph.h"

std::vector<std::vector<int>> getNaiveLayer(const GraphEdges &edges) {
int n = edges.size();
std::vector<int> inbound(n, 0);
for (int i = 0; i < n; i++) {
for (auto to : edges[i]) {
inbound[to] += 1;
}
}

std::vector<int> next;
std::vector<std::vector<int>> result;
for (int i = 0; i < n; i++) {
if (inbound[i] == 0) {
next.push_back(i);
}
}
do {
result.push_back(next);
const auto &order = result.back();
next.clear();

int ptr = 0;
while (ptr < order.size()) {
int from = order[ptr++];
for (auto to : edges[from]) {
int &v = inbound[to];
v -= 1;
if (v == 0) {
next.push_back(to);
}
}
}
} while (next.size() > 0);
return result;
}
67 changes: 56 additions & 11 deletions render/main.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
#include "graph.h"
#include <emscripten.h>
#include <emscripten/bind.h>
#include <set>
#include <stdio.h>

struct Edge {
int from, to;
};

int main() {}
#include <vector>

template <typename T>
std::vector<T> convertToVector(const emscripten::val &arr) {
Expand All @@ -17,21 +14,69 @@ std::vector<T> convertToVector(const emscripten::val &arr) {
return vec;
}

void layoutGraph(int n, const emscripten::val &v_edges) {
void dumpGraph(const GraphEdges &edges) {
int n = edges.size();
printf("dump graph begin\n");
for (int i = 0; i < n; i++) {
for (auto j : edges[i]) {
printf("%d -> %d\n", i, j);
}
}
printf("dump graph end\n");
}

void layoutGraph(int n, const emscripten::val &v_edges,
const emscripten::val &v_names) {
auto edgeVerts = convertToVector<int>(v_edges);
std::vector<Edge> edges;
auto names = convertToVector<std::string>(v_names);
std::vector<std::set<int>> edges(n);

for (int idx = 0; idx + 1 < edgeVerts.size(); idx += 2) {
int from = edgeVerts[idx];
int to = edgeVerts[idx + 1];
if (from < 0 || from >= n || to < 0 || to >= n) {
continue;
}
edges.emplace_back(Edge{from, to});
if (from == to) {
continue;
}
edges[from].insert(to);
}

for (auto [f, t] : edges) {
printf("%d -> %d\n", f, t);
auto fac = getFAC(edges);
for (int from = 0; from < n; from++) {
for (auto to : fac[from]) {
printf("revert %d -> %d\n", from, to);
edges[from].erase(to);
edges[to].insert(from);
}
}

auto vertsGroups = splitGraph(buildIndirectGraph(edges));

for (const auto &toMain : vertsGroups) {
int m = toMain.size();
std::vector<int> toSub(n, -1);
for (int i = 0; i < m; i++) {
toSub[toMain[i]] = i;
}
GraphEdges subGraph(m);
for (auto from : toMain) {
for (auto to : edges[from]) {
subGraph[toSub[from]].insert(toSub[to]);
}
}

auto initLayers = getNaiveLayer(subGraph);

int level = 0;
for (const auto &layer : initLayers) {
printf("%d:", level++);
for (auto v : layer) {
printf(" %s", names[toMain[v]].c_str());
}
puts("");
}
}
}

Expand Down

0 comments on commit 375f17a

Please sign in to comment.