diff options
| author | Gloria Mundi <gloria@gloria-mundi.eu> | 2024-02-27 23:01:41 +0100 |
|---|---|---|
| committer | Gloria Mundi <gloria@gloria-mundi.eu> | 2024-02-27 23:01:41 +0100 |
| commit | 496e4f909f4c6f4100ad3cef0a663b3f69b3b89f (patch) | |
| tree | 2bb5ad440c683abb215fb46ffd3818da6dc0df46 | |
| parent | 69cccd197a4aa331647a02046e708396f6a13937 (diff) | |
add binary lifting test
| -rw-r--r-- | .gitignore | 4 | ||||
| -rw-r--r-- | Makefile | 22 | ||||
| -rw-r--r-- | graph/test/binary_lifting.cpp | 93 |
3 files changed, 118 insertions, 1 deletions
@@ -220,3 +220,7 @@ TSWLatexianTemp* *-tags.tex *~ + +# files produced by the testing system +*.test +*.ok @@ -1,5 +1,25 @@ -all: +TESTS = graph/test/binary_lifting.test + +pdf: latexmk -pdf tcr + +all: pdf test + +test: $(TESTS:.test=.ok) + clean: latexmk -c tcr rm -f *.thm + rm -f $(TESTS) $(TESTS:.test=.ok) + +%.ok: %.test + timeout -v 1 ./$< + @touch $@ +%.test: %.cpp + g++ -std=gnu++20 -Wall -Wextra -Wpedantic -Werror \ + -fsanitize=address,undefined -g -o $@ $< + +graph/test/binary_lifting.test: graph/test/binary_lifting.cpp \ + graph/binary_lifting.cpp + +.PHONY: all pdf test clean diff --git a/graph/test/binary_lifting.cpp b/graph/test/binary_lifting.cpp new file mode 100644 index 0000000..e1cf7d2 --- /dev/null +++ b/graph/test/binary_lifting.cpp @@ -0,0 +1,93 @@ +#include <bits/stdc++.h> +using namespace std; + +#include "../binary_lifting.cpp" + +mt19937 rd(0); + +void test(const vector<vector<int>> &old_adj, int root) { + int n = old_adj.size(); + vector<int> perm(n); + iota(perm.begin(), perm.end(), 0); + ranges::shuffle(perm, rd); + vector<vector<int>> adj(n); + for (int i = 0; i < n; i++) { + auto &a = adj[perm[i]] = old_adj[i]; + for (int &v: a) v = perm[v]; + ranges::shuffle(a, rd); + } + root = perm[root]; + + vector<int> parent(n); + function<void(int,int)> dfs = [&](int u, int p) { + parent[u] = p; + for (int v: adj[u]) if (v != p) dfs(v, u); + }; + dfs(root, -1); + + function<bool(int, int)> is_ancestor = [&](int u, int v) { + while (v != -1 && u != v) v = parent[v]; + return u == v; + }; + function<int(int)> depth = [&](int v) { + int r = 0; + while ((v = parent[v]) != -1) r++; + return r; + }; + + Lift lift(adj, root); + for (int i = 0; i < n; i++) assert(lift.depth(i) == depth(i)); + uniform_int_distribution<int> distrib(0, n-1); + for (int i = 0; i < 1000; i++) { + int v = distrib(rd); + int d = distrib(rd); + int u = lift.lift(v, d); + assert(is_ancestor(u, v)); + if (d <= depth(v)) assert(depth(u) == d); + else assert(u == v); + } + for (int i = 0; i < 1000; i++) { + int u = distrib(rd); + int v = distrib(rd); + int lca = lift.lca(u, v); + assert(is_ancestor(lca, u)); + assert(is_ancestor(lca, v)); + for (int p = parent[lca]; int c: adj[lca]) { + if (c == p) continue; + assert(!is_ancestor(c, u) || !is_ancestor(c, v)); + } + } +} + +int main() { + { + // Single vertex + vector<vector<int>> adj(1); + test(adj, 0); + } + { + // Path + vector<vector<int>> adj(100); + for (int i = 1; i < 100; i++) { + adj[i-1].push_back(i); + adj[i].push_back(i-1); + } + test(adj, 0); + test(adj, 99); + test(adj, 40); + } + { + // Random + vector<vector<int>> adj(1000); + for (int i = 1; i < 1000; i++) { + uniform_int_distribution<int> distrib(0, i-1); + int p = distrib(rd); + adj[p].push_back(i); + adj[i].push_back(p); + } + test(adj, 0); + test(adj, 300); + test(adj, 600); + test(adj, 900); + } +} |
