37# include <gtest/gtest.h>
51# include <unordered_map>
70 using Edge = std::pair<size_t, size_t>;
76 std::vector<typename GT::Node *>
nodes;
77 std::vector<typename GT::Arc *>
arcs;
83 const std::vector<Edge> & edges)
86 built.nodes.reserve(n);
87 built.arcs.reserve(edges.size());
89 for (
size_t i = 0; i < n; ++i)
90 built.nodes.push_back(
built.g.insert_node(
static_cast<int>(i)));
92 for (
const auto & [u, v] : edges)
102 const std::vector<Edge> &
arcs)
105 built.nodes.reserve(n);
108 for (
size_t i = 0; i < n; ++i)
109 built.nodes.push_back(
built.g.insert_node(
static_cast<int>(i)));
111 for (
const auto & [u, v] :
arcs)
121 const std::vector<Edge> & edges)
124 built.nodes.reserve(n);
125 built.arcs.reserve(edges.size());
127 for (
size_t i = 0; i < n; ++i)
128 built.nodes.push_back(
built.g.insert_node(
static_cast<int>(i)));
130 for (
const auto & [u, v] : edges)
140 std::vector<Edge> edges;
141 for (
size_t u = 0; u < n; ++u)
142 for (
size_t v = u + 1; v < n; ++v)
143 edges.emplace_back(u, v);
151 std::vector<Edge> edges;
152 for (
size_t u = 0; u < left; ++u)
153 for (
size_t v = 0; v < right; ++v)
154 edges.emplace_back(u, left + v);
166 size_t component_count(
const size_t n,
const std::vector<Edge> & edges)
168 std::vector<std::vector<int>> adj(n);
169 for (
const auto & [u, v] : edges)
171 adj[u].push_back(
static_cast<int>(v));
172 adj[v].push_back(
static_cast<int>(u));
175 std::vector<int>
vis(n, 0);
178 for (
size_t s = 0; s < n; ++s)
184 std::vector<int> stack = {
static_cast<int>(s)};
187 while (
not stack.empty())
189 const int v = stack.back();
194 vis[
static_cast<size_t>(
w)] = 1;
206 const std::vector<Edge> & edges,
215 std::vector<std::vector<int>> adj(n);
216 for (
const auto & [u, v] : edges)
218 adj[u].push_back(
static_cast<int>(v));
219 adj[v].push_back(
static_cast<int>(u));
222 const size_t m = edges.
size();
226 if (c == 1
and n >= 3
and m > 3 * n - 6)
232 for (
size_t v = 0; v < n; ++v)
237 const size_t d =
neigh.size();
244 const int first =
neigh.front();
245 std::vector<int> tail(
neigh.begin() + 1,
neigh.end());
246 std::sort(tail.begin(), tail.end());
250 std::vector<int> order;
252 order.push_back(first);
253 order.insert(order.end(), tail.begin(), tail.end());
256 while (std::next_permutation(tail.begin(), tail.end()));
263 std::vector<std::pair<int, int>> darts;
264 darts.reserve(2 *
m);
265 std::unordered_map<uint64_t, int>
dart_id;
267 for (
const auto & [u, v] : edges)
269 const int duv =
static_cast<int>(darts.size());
270 darts.emplace_back(
static_cast<int>(u),
static_cast<int>(v));
273 const int dvu =
static_cast<int>(darts.size());
274 darts.emplace_back(
static_cast<int>(v),
static_cast<int>(u));
278 std::vector<int> alpha(darts.size(), -1);
279 for (
size_t i = 0; i < darts.size(); ++i)
281 const auto [u, v] = darts[i];
285 std::vector<size_t> selected(n, 0);
286 std::vector<size_t>
vars;
288 for (
size_t v = 0; v < n; ++v)
295 return order_options[a].size() > order_options[b].size();
300 std::vector<int> sigma(darts.size(), -1);
302 for (
size_t v = 0; v < n; ++v)
308 for (
size_t i = 0; i <
ord.size(); ++i)
310 const int to =
ord[i];
319 for (
const int s : sigma)
323 std::vector<int>
vis(darts.size(), 0);
325 for (
size_t d = 0; d < darts.size(); ++d)
335 x =
static_cast<size_t>(sigma[
static_cast<size_t>(alpha[x])]);
340 for (
size_t v = 0; v < n; ++v)
346 return static_cast<long long>(n)
347 -
static_cast<long long>(
m)
349 ==
static_cast<long long>(c) + 1;
352 std::function<
bool(
size_t)>
dfs = [&](
const size_t pos) ->
bool
354 if (pos ==
vars.size())
357 const size_t v =
vars[pos];
376 for (
size_t i = 0; i < s.size(); ++i)
389 std::optional<std::filesystem::path>
392 namespace fs = std::filesystem;
393 fs::path p = fs::current_path();
395 for (
size_t i = 0; i < 12; ++i)
397 if (fs::exists(p /
"Planarity_Test.H")
and fs::exists(p /
"scripts"))
400 if (p == p.root_path())
412 const std::string &
ext)
414 static size_t seq = 0;
415 namespace fs = std::filesystem;
416 std::ostringstream
out;
417 out << (fs::temp_directory_path() /
"aleph_planarity").
string()
418 <<
"_" <<
stem <<
"_" << ++seq <<
ext;
425 const std::string & content)
427 std::ofstream
out(path);
435 std::ifstream
in(path);
436 std::ostringstream
out;
449 namespace fs = std::filesystem;
451 (fs::temp_directory_path() / (
"aleph_planarity_" + label +
".stdout")).string();
452 const std::string full =
454 return std::system(full.c_str());
466 const std::string & label =
"validator")
468 namespace fs = std::filesystem;
473 const fs::path
script = *
root /
"scripts" /
"planarity_certificate_validator.rb";
477 std::ostringstream
cmd;
480 for (
size_t i = 0; i <
inputs.size(); ++i)
484 cmd <<
" --networkx";
486 cmd <<
" --require-networkx";
490 cmd <<
" --require-gephi";
505 namespace fs = std::filesystem;
510 const fs::path
script = *
root /
"scripts" /
"planarity_certificate_ci_batch.rb";
514 std::ostringstream
cmd;
516 for (
size_t i = 0; i <
inputs.size(); ++i)
529 const std::vector<std::string> &
profiles,
533 namespace fs = std::filesystem;
538 const fs::path
script = *
root /
"scripts" /
"planarity_certificate_ci_visual_diff.rb";
542 std::ostringstream
cmd;
545 for (
size_t i = 0; i <
inputs.size(); ++i)
548 for (
size_t i = 0; i <
profiles.size(); ++i)
565 namespace fs = std::filesystem;
570 const fs::path
script = *
root /
"scripts" /
"planarity_gephi_weekly_comparison.rb";
574 std::ostringstream
cmd;
577 <<
" --resolved-tags " <<
shell_quote(
"v0.9.7,v0.10.1")
596 namespace fs = std::filesystem;
601 const fs::path
script = *
root /
"scripts" /
"planarity_gephi_regression_notify.rb";
605 std::ostringstream
cmd;
609 <<
" --repository " <<
shell_quote(
"lrleon/Aleph-w")
610 <<
" --run-url " <<
shell_quote(
"https://example.invalid/run/123");
621 namespace fs = std::filesystem;
622 return (fs::temp_directory_path() / (
"aleph_planarity_" + label +
".stdout")).string();
631 namespace fs = std::filesystem;
635 if (
not fs::exists(*
root /
"scripts" /
"planarity_certificate_validator.rb"))
637 return std::system(
"ruby --version > /dev/null 2>&1") == 0;
645 return std::system(
"python3 --version > /dev/null 2>&1") == 0;
664 const std::vector<Edge> edges = {
665 {0, 1}, {1, 2}, {1, 3}, {3, 4}, {3, 5}
703 EXPECT_EQ(
r.certificate_type, Planarity_Certificate_Type::K5_Subdivision);
704 EXPECT_EQ(
r.certificate_branch_nodes.size(), 5u);
720 EXPECT_EQ(
r.certificate_type, Planarity_Certificate_Type::K33_Subdivision);
721 EXPECT_EQ(
r.certificate_branch_nodes.size(), 6u);
741 ASSERT_EQ(
r.certificate_type, Planarity_Certificate_Type::K5_Subdivision);
742 ASSERT_EQ(
r.certificate_obstruction_edges.size(), 10u);
746 it(
r.certificate_obstruction_edges); it.has_curr(); it.next_ne())
748 const auto &
w = it.get_curr_ne();
749 EXPECT_NE(
w.representative_input_arc,
nullptr);
770 auto it = std::find(edges.begin(), edges.end(),
Edge{0, 3});
773 edges.emplace_back(0, 6);
774 edges.emplace_back(6, 3);
785 ASSERT_EQ(
r.certificate_type, Planarity_Certificate_Type::K33_Subdivision);
790 pit(
r.certificate_paths);
pit.has_curr();
pit.next_ne())
792 const auto & p =
pit.get_curr_ne();
794 EXPECT_EQ(p.edges.size(), p.nodes.size() - 1);
796 if (p.nodes.size() > 2)
800 eit(p.edges);
eit.has_curr();
eit.next_ne())
802 const auto & e =
eit.get_curr_ne();
803 EXPECT_NE(e.representative_input_arc,
nullptr);
815 edges.erase(edges.begin());
827 edges.erase(edges.begin());
849 {0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0}, {0, 2}
854 opts.embedding_allow_bruteforce_fallback =
false;
866 EXPECT_EQ(
md.dual_edges.size(),
r.simplified_num_edges);
874 {0, 1}, {1, 2}, {1, 3}
879 opts.embedding_allow_bruteforce_fallback =
false;
891 it(
md.dual_edges); it.has_curr(); it.next_ne())
893 const auto & e = it.get_curr_ne();
912 opts.embedding_allow_bruteforce_fallback =
false;
929 {0, 1}, {1, 2}, {2, 3}
943 {0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0}, {0, 2}
948 opts.embedding_allow_bruteforce_fallback =
false;
961 edges.erase(edges.begin());
966 strict_opts.embedding_allow_bruteforce_fallback =
false;
987 edges.erase(edges.begin());
992 opts.embedding_allow_bruteforce_fallback =
false;
993 opts.embedding_max_combinations = 1;
1006 edges.erase(edges.begin());
1011 opts.embedding_prefer_lr_linear =
false;
1012 opts.embedding_max_combinations = 1;
1025 edges.erase(edges.begin());
1039 auto it = std::find(edges.begin(), edges.end(),
Edge{0, 3});
1042 edges.emplace_back(0, 6);
1043 edges.emplace_back(6, 3);
1058 opts.certificate_max_edges = 5;
1071 {0, 1}, {0, 2}, {0, 3}, {0, 4},
1072 {1, 2}, {1, 3}, {1, 4},
1073 {2, 3}, {2, 4}, {3, 4},
1074 {2, 5}, {5, 6}, {6, 7}
1084 EXPECT_EQ(
r.certificate_type, Planarity_Certificate_Type::K5_Subdivision);
1085 EXPECT_EQ(
r.certificate_branch_nodes.size(), 5u);
1093 {0, 3}, {0, 4}, {0, 5},
1094 {1, 3}, {1, 4}, {1, 5},
1095 {2, 3}, {2, 4}, {2, 5},
1096 {0, 8}, {8, 7}, {7, 6}
1106 EXPECT_EQ(
r.certificate_type, Planarity_Certificate_Type::K33_Subdivision);
1107 EXPECT_EQ(
r.certificate_branch_nodes.size(), 6u);
1118 opts.certificate_max_branch_nodes_search = 4;
1125 Planarity_Certificate_Type::Minimal_NonPlanar_Obstruction);
1133 edges.emplace_back(6, 7);
1147 {0, 2}, {1, 2}, {1, 4}, {2, 4}
1181 {0, 3}, {0, 4}, {0, 5},
1182 {1, 3}, {1, 4}, {1, 5},
1183 {2, 3}, {2, 4}, {2, 5}
1195 {0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0}, {0, 2}
1220 std::mt19937_64
rng(0xA11CE123456789ULL);
1221 std::uniform_int_distribution<int>
n_dist(1, 7);
1222 std::bernoulli_distribution
has_edge(0.35);
1227 const size_t n =
static_cast<size_t>(
n_dist(
rng));
1228 std::vector<Edge> edges;
1230 for (
size_t u = 0; u < n; ++u)
1231 for (
size_t v = u + 1; v < n; ++v)
1233 edges.emplace_back(u, v);
1251 std::mt19937_64
rng(0xD00D1234A11CEULL);
1252 std::uniform_int_distribution<int>
n_dist(1, 7);
1253 std::bernoulli_distribution
has_edge(0.36);
1257 strict_opts.embedding_allow_bruteforce_fallback =
false;
1264 const size_t n =
static_cast<size_t>(
n_dist(
rng));
1265 std::vector<Edge> edges;
1267 for (
size_t u = 0; u < n; ++u)
1268 for (
size_t v = u + 1; v < n; ++v)
1270 edges.emplace_back(u, v);
1281 +
" n=" + std::to_string(n)
1282 +
" m=" + std::to_string(edges.size()));
1302 {0, 1}, {1, 2}, {2, 0}
1315 {0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0}, {0, 2}
1320 opts.embedding_allow_bruteforce_fallback =
false;
1330 EXPECT_EQ(d.node_positions.size(),
r.simplified_num_nodes);
1332 bool distinct =
false;
1333 for (
size_t i = 1; i < d.node_positions.size(); ++i)
1334 if (std::abs(d.node_positions[i].x - d.node_positions[0].x) > 1e-9
1335 or std::abs(d.node_positions[i].y - d.node_positions[0].y) > 1e-9)
1347 edges.erase(edges.begin());
1352 opts.embedding_allow_bruteforce_fallback =
false;
1362 EXPECT_NE(d.chosen_outer_face, std::numeric_limits<size_t>::max());
1369 {0, 1}, {1, 2}, {2, 0},
1370 {3, 4}, {4, 5}, {5, 3}
1375 opts.embedding_allow_bruteforce_fallback =
false;
1385 double min_x_a = std::numeric_limits<double>::max();
1386 double max_x_a = -std::numeric_limits<double>::max();
1387 double min_x_b = std::numeric_limits<double>::max();
1388 double max_x_b = -std::numeric_limits<double>::max();
1391 it(d.node_positions); it.has_curr(); it.next_ne())
1393 const auto & p = it.get_curr_ne();
1413 {0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0}, {0, 2}
1418 opts.embedding_allow_bruteforce_fallback =
false;
1446 EXPECT_NE(json.find(
"\"certificate_type\": \"K33_Subdivision\""), std::string::npos);
1447 EXPECT_NE(json.find(
"\"obstruction_edges\""), std::string::npos);
1448 EXPECT_NE(dot.find(
"graph NonPlanarCertificate"), std::string::npos);
1449 EXPECT_NE(dot.find(
"obs x"), std::string::npos);
1466 eopt.dot_highlight_paths =
false;
1476 EXPECT_EQ(json.find(
'\n'), std::string::npos);
1477 EXPECT_NE(json.find(
"q\\\"\\\\\\n"), std::string::npos);
1478 EXPECT_NE(dot.find(
"q\\\"\\\\\\n"), std::string::npos);
1479 EXPECT_EQ(dot.find(
"label=\"p"), std::string::npos);
1480 EXPECT_NE(dot.find(
"obs x"), std::string::npos);
1502 EXPECT_NE(
gexf.find(
"defaultedgetype=\"undirected\""), std::string::npos);
1519 eopt.gexf_include_paths =
false;
1542 EXPECT_EQ(
vr.num_obstruction_edges,
r.certificate_obstruction_edges.size());
1560 r.certificate_paths[0].edges[0].src =
nullptr;
1574 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
1601 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
1607<graphml xmlns="http://graphml.graphdrawing.org/xmlns">
1608 <graph id="Broken" edgedefault="undirected">
1611 <edge id="e0" source="n0" target="n1">
1612 <data key="k_edge_kind">path</data>
1613 <data key="k_edge_path_id">0</data>
1629 GTEST_SKIP() <<
"Skipped: Ruby, validator script, or python3 not found";
1647 const int has_nx = std::system(
1648 "python3 -c \"import importlib.util,sys; sys.exit(0 if importlib.util.find_spec('networkx') else 1)\"");
1662 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
1682 std::system(
"gephi --version > /dev/null 2>&1");
1697 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
1713 "ruby -e \"File.stat(ARGV[0])\" {input}";
1723 namespace fs = std::filesystem;
1727 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
1739 const fs::path dir = fs::temp_directory_path() /
"aleph planarity gephi spaces";
1740 fs::create_directories(dir);
1741 const std::string
graphml_path = (dir /
"k33 certificate.graphml").
string();
1745 "ruby -e \"File.stat(ARGV[0])\" {input}";
1757 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
1761 const std::string
lbl =
"list_templates";
1763 {},
false,
false,
false,
false,
"",
"--list-gephi-templates --json",
lbl);
1767 EXPECT_NE(
out.find(
"\"templates\""), std::string::npos);
1768 EXPECT_NE(
out.find(
"portable.ruby-file-exists"), std::string::npos);
1769 EXPECT_NE(
out.find(
"linux.gephi-0.10.smoke"), std::string::npos);
1770 EXPECT_NE(
out.find(
"macos.gephi-0.10.smoke"), std::string::npos);
1771 EXPECT_NE(
out.find(
"windows.gephi-0.10.smoke"), std::string::npos);
1779 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
1783 const std::string
lbl =
"filter_templates_os";
1785 {},
false,
false,
false,
false,
"",
1786 "--list-gephi-templates --template-os windows --json",
lbl);
1790 EXPECT_NE(
out.find(
"windows.gephi-0.10.smoke"), std::string::npos);
1791 EXPECT_EQ(
out.find(
"linux.gephi-0.10.smoke"), std::string::npos);
1799 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
1803 const std::string
lbl =
"list_profiles";
1805 {},
false,
false,
false,
false,
"",
1806 "--list-gephi-render-profiles --json",
lbl);
1810 EXPECT_NE(
out.find(
"\"profiles\""), std::string::npos);
1811 EXPECT_NE(
out.find(
"portable.ruby-render-svg"), std::string::npos);
1812 EXPECT_NE(
out.find(
"linux.gephi-0.10.render-svg"), std::string::npos);
1813 EXPECT_NE(
out.find(
"macos.gephi-0.10.render-svg"), std::string::npos);
1814 EXPECT_NE(
out.find(
"windows.gephi-0.10.render-svg"), std::string::npos);
1822 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
1826 const std::string
lbl =
"filter_profiles_os";
1828 {},
false,
false,
false,
false,
"",
1829 "--list-gephi-render-profiles --render-os windows --json",
lbl);
1833 EXPECT_NE(
out.find(
"windows.gephi-0.10.render-svg"), std::string::npos);
1834 EXPECT_EQ(
out.find(
"linux.gephi-0.10.render-svg"), std::string::npos);
1842 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
1859 "--gephi-template portable.ruby-file-exists");
1866 namespace fs = std::filesystem;
1870 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
1886 const std::string
lbl =
"render_svg";
1889 "--render-gephi --require-render "
1890 "--render-profile portable.ruby-render-svg "
1901 EXPECT_NE(
out.find(
"render_output_kind"), std::string::npos);
1908 namespace fs = std::filesystem;
1912 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
1930 "--render-gephi --require-render "
1931 "--render-profile portable.ruby-render-pdf "
1944 namespace fs = std::filesystem;
1948 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
1960 const fs::path dir = fs::temp_directory_path() /
"aleph planarity render spaces";
1961 fs::create_directories(dir);
1962 const std::string
graphml_path = (dir /
"k33 certificate.graphml").
string();
1963 const std::string
output_dir = (dir /
"render output").
string();
1968 "--render-gephi --require-render "
1969 "--render-profile portable.ruby-render-svg "
1984 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
2001 "--render-gephi --require-render --render-profile missing.profile");
2025 "--gephi --require-gephi --gephi-template portable.ruby-file-exists --print-summary");
2031 EXPECT_NE(
report.find(
"\"gephi_template\": \"portable.ruby-file-exists\""),
2053 "--render-gephi --require-render "
2054 "--render-profile portable.ruby-render-svg "
2059 EXPECT_NE(
report.find(
"\"render_profile\": \"portable.ruby-render-svg\""),
2082 {
"portable.ruby-render-svg",
"portable.ruby-render-pdf"},
2088 EXPECT_NE(
report.find(
"\"overall_passed\": true"), std::string::npos);
2089 EXPECT_NE(
report.find(
"\"profile_id\": \"portable.ruby-render-svg\""),
2091 EXPECT_NE(
report.find(
"\"profile_id\": \"portable.ruby-render-pdf\""),
2114 "schema_version": 1,
2117 "profile_id": "portable.ruby-render-svg",
2118 "output_ext": "svg",
2119 "sha256": "0000000000000000000000000000000000000000000000000000000000000000",
2128 {
"portable.ruby-render-svg"},
2135 EXPECT_NE(
report.find(
"\"overall_passed\": false"), std::string::npos);
2158 {
"portable.ruby-render-svg"},
2162 +
" --update-golden");
2168 if (
manifest.find(
"portable.ruby-render-svg") == std::string::npos)
2170 std::cerr <<
"[diag] manifest_path=" <<
manifest_path <<
"\n"
2171 <<
"[diag] manifest content (" <<
manifest.size() <<
" bytes):\n"
2173 <<
"[diag] report content (" <<
report.size() <<
" bytes):\n"
2179 EXPECT_NE(
manifest.find(
"0459f595d6268e7bdf9e8e273d4394fa50d23a89ec3d2449d10b7b47941b1327"),
2186 namespace fs = std::filesystem;
2194 const std::string & tag,
2199 fs::create_directories(dir);
2204 "asset_name=gephi-package-" + tag +
".zip\n"
2205 "gephi_executable=/tmp/gephi\n");
2209 <<
" \"os\": \"" <<
os_name <<
"\",\n"
2210 <<
" \"gephi_tag\": \"" << tag <<
"\",\n"
2211 <<
" \"asset_name\": \"gephi-package-" << tag <<
".zip\",\n"
2213 <<
" \"overall_valid\": " << (
overall_valid ?
"true" :
"false") <<
"\n"
2218 write_case(
"gephi-nightly-ubuntu-24.04-v0.9.7",
"ubuntu-24.04",
"v0.9.7", 0,
true);
2219 write_case(
"gephi-nightly-ubuntu-24.04-v0.10.1",
"ubuntu-24.04",
"v0.10.1", 0,
true);
2220 write_case(
"gephi-nightly-windows-2022-v0.9.7",
"windows-2022",
"v0.9.7", 0,
true);
2221 write_case(
"gephi-nightly-windows-2022-v0.10.1",
"windows-2022",
"v0.10.1", 0,
true);
2231 EXPECT_NE(json.find(
"\"num_entries\": 4"), std::string::npos);
2232 EXPECT_NE(json.find(
"\"num_regressions\": 0"), std::string::npos);
2233 EXPECT_NE(json.find(
"\"has_regressions\": false"), std::string::npos);
2243 namespace fs = std::filesystem;
2251 const std::string & tag,
2256 fs::create_directories(dir);
2261 "asset_name=gephi-package-" + tag +
".zip\n"
2262 "gephi_executable=/tmp/gephi\n");
2266 <<
" \"os\": \"" <<
os_name <<
"\",\n"
2267 <<
" \"gephi_tag\": \"" << tag <<
"\",\n"
2268 <<
" \"asset_name\": \"gephi-package-" << tag <<
".zip\",\n"
2270 <<
" \"overall_valid\": " << (
overall_valid ?
"true" :
"false") <<
"\n"
2275 write_case(
"gephi-nightly-ubuntu-24.04-v0.9.7",
"ubuntu-24.04",
"v0.9.7", 0,
true);
2276 write_case(
"gephi-nightly-ubuntu-24.04-v0.10.1",
"ubuntu-24.04",
"v0.10.1", 2,
false);
2286 EXPECT_NE(json.find(
"\"num_regressions\": 1"), std::string::npos);
2287 EXPECT_NE(json.find(
"\"has_regressions\": true"), std::string::npos);
2288 EXPECT_NE(json.find(
"overall_valid_regressed"), std::string::npos);
2289 EXPECT_NE(json.find(
"exit_code_regressed"), std::string::npos);
2305 "schema_version": 1,
2308 "git_sha": "abc123",
2309 "resolved_tags": "v0.9.7,v0.10.1",
2312 "num_regressions": 0,
2313 "has_regressions": false,
2335 "schema_version": 1,
2338 "git_sha": "def456",
2339 "resolved_tags": "v0.9.7,v0.10.1",
2342 "num_regressions": 1,
2343 "has_regressions": true,
2346 "os": "ubuntu-24.04",
2347 "from_tag": "v0.9.7",
2348 "to_tag": "v0.10.1",
2349 "from_overall_valid": true,
2350 "to_overall_valid": false,
2351 "from_exit_code": 0,
2353 "reason_codes": ["overall_valid_regressed", "exit_code_regressed"]
2381<graphml xmlns="http://graphml.graphdrawing.org/xmlns">
2382 <graph id="Broken" edgedefault="undirected">
2385 <edge id="e0" source="n0" target="n1">
2386 <data key="k_edge_kind">path</data>
2397 EXPECT_NE(
report.find(
"\"overall_valid\": false"), std::string::npos);
2403 namespace fs = std::filesystem;
2407 GTEST_SKIP() <<
"Skipped: Ruby or planarity_certificate_validator.rb not found";
2415 *
root /
"scripts" /
"fixtures" /
"planarity_k33_certificate.graphml";
Planarity testing on Aleph graphs.
Simple dynamic array with automatic resizing and functional operations.
Generic directed graph (digraph) wrapper template.
Graph implemented with double-linked adjacency lists.
_Graph_Node Node
The graph type.
_Graph_Arc Arc
The node class type.
constexpr size_t size() const noexcept
Returns the number of entries in the table.
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
DynArray< Graph::Node * > nodes
DynArray< Graph::Arc * > arcs
std::string nonplanar_certificate_to_gexf(const Planarity_Test_Result< GT > &result, Node_Label node_label=Node_Label(), const NonPlanar_Certificate_Export_Options &options=NonPlanar_Certificate_Export_Options())
Export non-planar certificate as GEXF.
Planar_Geometric_Drawing< GT > planar_geometric_drawing(const Planarity_Test_Result< GT > &result, const Planar_Geometric_Drawing_Options &options=Planar_Geometric_Drawing_Options())
Build embedding-aware 2D node coordinates from a planar result.
Planarity_Test_Result< GT > planarity_test(const GT &g, SA sa=SA(), const Planarity_Test_Options &options=Planarity_Test_Options())
Execute planarity test on an Aleph graph.
Planar_Dual_Metadata< GT > planar_dual_metadata(const Planarity_Test_Result< GT > &result)
Build face and dual-edge metadata from a planar embedding result.
std::string nonplanar_certificate_to_dot(const Planarity_Test_Result< GT > &result, Node_Label node_label=Node_Label(), const NonPlanar_Certificate_Export_Options &options=NonPlanar_Certificate_Export_Options())
Export non-planar certificate as GraphViz DOT.
bool is_planar_graph(const GT &g, SA sa=SA(), const Planarity_Test_Options &options=Planarity_Test_Options())
Convenience boolean API for planarity.
std::string nonplanar_certificate_to_graphml(const Planarity_Test_Result< GT > &result, Node_Label node_label=Node_Label(), const NonPlanar_Certificate_Export_Options &options=NonPlanar_Certificate_Export_Options())
Export non-planar certificate as GraphML.
std::string nonplanar_certificate_to_json(const Planarity_Test_Result< GT > &result, Node_Label node_label=Node_Label(), const NonPlanar_Certificate_Export_Options &options=NonPlanar_Certificate_Export_Options())
Export non-planar certificate as JSON.
NonPlanar_Certificate_Validation< GT > validate_nonplanar_certificate(const Planarity_Test_Result< GT > &result)
Validate structural consistency of a non-planar certificate.
bool nonplanar_certificate_is_valid(const Planarity_Test_Result< GT > &result)
Convenience predicate over validate_nonplanar_certificate().
DFSResult< typename Domain::Distance > dfs(Domain &domain, typename Domain::State &state, SearchPath< typename Domain::Move > &path, const typename Domain::Distance g, const typename Domain::Distance threshold, const size_t depth, IDAStarResult< Solution, typename Domain::Distance > &result, OnSolution &on_solution)
Core recursive DFS used by IDA* for a single threshold pass.
Main namespace for Aleph-w library functions.
and
Check uniqueness with explicit hash + equality functors.
size_t size(Node *root) noexcept
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
void next()
Advance all underlying iterators (bounds-checked).
Default node labeler for certificate export.
Arc of graph implemented with double-linked adjacency lists.
Export options for non-planar certificate serializers.
bool pretty_json
Pretty-print JSON with indentation/newlines.
bool graphml_include_paths
Include path overlays in GraphML output.
Dual-edge payload linked to a primal simplified edge.
Options for embedding-aware 2D drawing extraction.
size_t max_outer_faces_to_try
Max outer-face candidates evaluated per component.
Configuration for planarity test optional outputs.
bool embedding_allow_bruteforce_fallback
Allow exact embedding fallback if LR-constructive embedding fails validation.
bool compute_embedding
If true and graph is planar, tries to compute combinatorial embedding.
bool compute_nonplanar_certificate
If true and graph is non-planar, tries to extract witness.
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
Array-based graph implementation.
Generic graph and digraph implementations.