1use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
6
7use super::types::{
8 ColorCodingFPT, CourcelleMSOLChecker, CrownDecomposition, FPTAlgorithm, FPTMethod,
9 IterativeCompressionVC, Kernelization, ParamReduction, TreeDecomp, TreeDecomposition,
10 TreewidthAlgorithm, VertexCoverFPT, WClass,
11};
12
13pub fn app(f: Expr, a: Expr) -> Expr {
14 Expr::App(Box::new(f), Box::new(a))
15}
16pub fn app2(f: Expr, a: Expr, b: Expr) -> Expr {
17 app(app(f, a), b)
18}
19pub fn app3(f: Expr, a: Expr, b: Expr, c: Expr) -> Expr {
20 app(app2(f, a, b), c)
21}
22pub fn cst(s: &str) -> Expr {
23 Expr::Const(Name::str(s), vec![])
24}
25pub fn prop() -> Expr {
26 Expr::Sort(Level::zero())
27}
28pub fn type0() -> Expr {
29 Expr::Sort(Level::succ(Level::zero()))
30}
31pub fn pi(bi: BinderInfo, name: &str, dom: Expr, body: Expr) -> Expr {
32 Expr::Pi(bi, Name::str(name), Box::new(dom), Box::new(body))
33}
34pub fn arrow(a: Expr, b: Expr) -> Expr {
35 pi(BinderInfo::Default, "_", a, b)
36}
37pub fn bvar(n: u32) -> Expr {
38 Expr::BVar(n)
39}
40pub fn nat_ty() -> Expr {
41 cst("Nat")
42}
43pub fn bool_ty() -> Expr {
44 cst("Bool")
45}
46pub fn real_ty() -> Expr {
47 cst("Real")
48}
49pub fn list_ty(elem: Expr) -> Expr {
50 app(cst("List"), elem)
51}
52pub fn pair_ty(a: Expr, b: Expr) -> Expr {
53 app2(cst("Prod"), a, b)
54}
55pub fn option_ty(a: Expr) -> Expr {
56 app(cst("Option"), a)
57}
58pub fn parameterized_problem_ty() -> Expr {
60 type0()
61}
62pub fn parameter_ty() -> Expr {
64 arrow(cst("String"), nat_ty())
65}
66pub fn fpt_algorithm_ty() -> Expr {
69 arrow(parameterized_problem_ty(), type0())
70}
71pub fn is_in_fpt_ty() -> Expr {
74 arrow(parameterized_problem_ty(), prop())
75}
76pub fn is_in_xp_ty() -> Expr {
79 arrow(parameterized_problem_ty(), prop())
80}
81pub fn is_w_hard_ty() -> Expr {
84 arrow(nat_ty(), arrow(parameterized_problem_ty(), prop()))
85}
86pub fn is_w_complete_ty() -> Expr {
89 arrow(nat_ty(), arrow(parameterized_problem_ty(), prop()))
90}
91pub fn fpt_reducible_ty() -> Expr {
94 arrow(
95 parameterized_problem_ty(),
96 arrow(parameterized_problem_ty(), prop()),
97 )
98}
99pub fn w_hierarchy_ty() -> Expr {
101 arrow(nat_ty(), type0())
102}
103pub fn w1_ty() -> Expr {
105 type0()
106}
107pub fn w2_ty() -> Expr {
109 type0()
110}
111pub fn wp_ty() -> Expr {
113 type0()
114}
115pub fn aw_ty() -> Expr {
117 type0()
118}
119pub fn fpt_subset_w1_ty() -> Expr {
121 arrow(
122 arrow(parameterized_problem_ty(), cst("IsInFPT")),
123 arrow(parameterized_problem_ty(), app(cst("W1"), bvar(0))),
124 )
125}
126pub fn kernel_ty() -> Expr {
130 arrow(
131 parameterized_problem_ty(),
132 arrow(arrow(nat_ty(), nat_ty()), type0()),
133 )
134}
135pub fn has_polynomial_kernel_ty() -> Expr {
138 arrow(parameterized_problem_ty(), prop())
139}
140pub fn kernel_size_ty() -> Expr {
143 arrow(nat_ty(), nat_ty())
144}
145pub fn vertex_cover_kernel_2k_ty() -> Expr {
147 prop()
148}
149pub fn vertex_cover_kernel_k_squared_ty() -> Expr {
151 prop()
152}
153pub fn tree_decomposition_ty() -> Expr {
157 arrow(cst("Graph"), type0())
158}
159pub fn treewidth_ty() -> Expr {
162 arrow(cst("Graph"), nat_ty())
163}
164pub fn path_decomposition_ty() -> Expr {
167 arrow(cst("Graph"), type0())
168}
169pub fn pathwidth_ty() -> Expr {
172 arrow(cst("Graph"), nat_ty())
173}
174pub fn treewidth_le_pathwidth_ty() -> Expr {
176 pi(
177 BinderInfo::Default,
178 "G",
179 cst("Graph"),
180 app3(
181 cst("Le"),
182 app(cst("Treewidth"), bvar(0)),
183 app(cst("Pathwidth"), bvar(0)),
184 prop(),
185 ),
186 )
187}
188pub fn branch_decomposition_ty() -> Expr {
190 arrow(cst("Graph"), type0())
191}
192pub fn branchwidth_ty() -> Expr {
194 arrow(cst("Graph"), nat_ty())
195}
196pub fn feedback_vertex_set_ty() -> Expr {
199 arrow(cst("Graph"), arrow(list_ty(nat_ty()), prop()))
200}
201pub fn min_fvs_ty() -> Expr {
204 arrow(cst("Graph"), nat_ty())
205}
206pub fn fvs_parameterized_ty() -> Expr {
209 parameterized_problem_ty()
210}
211pub fn color_coding_algorithm_ty() -> Expr {
215 arrow(nat_ty(), arrow(cst("Graph"), arrow(nat_ty(), bool_ty())))
216}
217pub fn color_coding_fpt_ty() -> Expr {
220 prop()
221}
222pub fn perfect_hash_family_ty() -> Expr {
226 arrow(nat_ty(), arrow(nat_ty(), type0()))
227}
228pub fn mso2_logic_ty() -> Expr {
230 type0()
231}
232pub fn mso2_satisfies_ty() -> Expr {
235 arrow(cst("Graph"), arrow(mso2_logic_ty(), prop()))
236}
237pub fn courcelle_theorem_ty() -> Expr {
241 pi(
242 BinderInfo::Default,
243 "phi",
244 mso2_logic_ty(),
245 pi(BinderInfo::Default, "k", nat_ty(), prop()),
246 )
247}
248pub fn bounded_treewidth_dp_ty() -> Expr {
252 arrow(cst("Graph"), arrow(nat_ty(), prop()))
253}
254pub fn eth_ty() -> Expr {
257 prop()
258}
259pub fn seth_ty() -> Expr {
262 prop()
263}
264pub fn eth_implies_no_subexp_ty() -> Expr {
266 arrow(eth_ty(), prop())
267}
268pub fn seth_implies_vc_lb_ty() -> Expr {
270 arrow(seth_ty(), prop())
271}
272pub fn sparsification_lemma_ty() -> Expr {
274 prop()
275}
276pub fn eth_k_clique_lb_ty() -> Expr {
278 arrow(eth_ty(), arrow(nat_ty(), prop()))
279}
280pub fn fine_grained_reduction_ty() -> Expr {
283 arrow(
284 parameterized_problem_ty(),
285 arrow(parameterized_problem_ty(), prop()),
286 )
287}
288pub fn xp_algorithm_ty() -> Expr {
291 arrow(parameterized_problem_ty(), type0())
292}
293pub fn fpt_subset_xp_ty() -> Expr {
295 pi(
296 BinderInfo::Default,
297 "P",
298 parameterized_problem_ty(),
299 arrow(app(cst("IsInFPT"), bvar(0)), app(cst("IsInXP"), bvar(0))),
300 )
301}
302pub fn w1_in_xp_ty() -> Expr {
304 prop()
305}
306pub fn eth_hardness_ty() -> Expr {
309 arrow(parameterized_problem_ty(), prop())
310}
311pub fn w1_hard_eth_hard_ty() -> Expr {
313 pi(
314 BinderInfo::Default,
315 "P",
316 parameterized_problem_ty(),
317 arrow(
318 app2(cst("IsWHard"), cst("One"), bvar(0)),
319 arrow(eth_ty(), app(cst("ETHHardness"), bvar(1))),
320 ),
321 )
322}
323pub fn k_clique_w1_hard_ty() -> Expr {
325 prop()
326}
327pub fn k_independent_set_w1_hard_ty() -> Expr {
329 prop()
330}
331pub fn k_dom_set_w2_hard_ty() -> Expr {
333 prop()
334}
335pub fn path_graph_decomp(n: usize) -> TreeDecomp {
338 if n == 0 {
339 return TreeDecomp {
340 bags: vec![],
341 tree_adj: vec![],
342 root: 0,
343 };
344 }
345 let bags: Vec<Vec<usize>> = (0..n.saturating_sub(1)).map(|i| vec![i, i + 1]).collect();
346 let num_bags = bags.len().max(1);
347 let bags = if bags.is_empty() { vec![vec![0]] } else { bags };
348 let mut tree_adj = vec![vec![]; num_bags];
349 for i in 0..num_bags.saturating_sub(1) {
350 tree_adj[i].push(i + 1);
351 tree_adj[i + 1].push(i);
352 }
353 TreeDecomp {
354 bags,
355 tree_adj,
356 root: 0,
357 }
358}
359pub fn vertex_cover_bst(adj: &[Vec<usize>], k: usize) -> Option<Vec<usize>> {
362 fn solve(
363 adj: &[Vec<usize>],
364 cover: &mut Vec<usize>,
365 removed: &mut Vec<bool>,
366 k: usize,
367 ) -> bool {
368 let edge = (0..adj.len()).find_map(|u| {
369 if removed[u] {
370 return None;
371 }
372 adj[u].iter().find(|&&v| !removed[v]).map(|&v| (u, v))
373 });
374 match edge {
375 None => true,
376 Some((u, v)) => {
377 if k == 0 {
378 return false;
379 }
380 removed[u] = true;
381 cover.push(u);
382 if solve(adj, cover, removed, k - 1) {
383 removed[u] = false;
384 return true;
385 }
386 cover.pop();
387 removed[u] = false;
388 removed[v] = true;
389 cover.push(v);
390 if solve(adj, cover, removed, k - 1) {
391 removed[v] = false;
392 return true;
393 }
394 cover.pop();
395 removed[v] = false;
396 false
397 }
398 }
399 }
400 let n = adj.len();
401 let mut cover = Vec::new();
402 let mut removed = vec![false; n];
403 if solve(adj, &mut cover, &mut removed, k) {
404 Some(cover)
405 } else {
406 None
407 }
408}
409pub fn crown_reduction(adj: &[Vec<usize>]) -> (Vec<Vec<usize>>, Vec<usize>) {
412 let n = adj.len();
413 let high_deg: Vec<usize> = (0..n).filter(|&v| !adj[v].is_empty()).collect();
414 let mut in_cover = vec![false; n];
415 let mut new_adj: Vec<Vec<usize>> = adj.to_vec();
416 let _ = high_deg;
417 let cover_vertices: Vec<usize> = (0..n).filter(|&v| adj[v].len() > n / 2).collect();
418 for &v in &cover_vertices {
419 in_cover[v] = true;
420 let neighbors = new_adj[v].clone();
421 new_adj[v].clear();
422 for u in neighbors {
423 new_adj[u].retain(|&x| x != v);
424 }
425 }
426 (new_adj, cover_vertices)
427}
428pub fn color_coding_k_path(adj: &[Vec<usize>], k: usize, seed: u64) -> bool {
431 let n = adj.len();
432 if n == 0 || k == 0 {
433 return k == 0;
434 }
435 if k > n {
436 return false;
437 }
438 let mut rng_state = seed;
439 let next_rand = |state: &mut u64| -> u64 {
440 *state = state
441 .wrapping_mul(6364136223846793005)
442 .wrapping_add(1442695040888963407);
443 *state
444 };
445 let colors: Vec<usize> = (0..n)
446 .map(|_| (next_rand(&mut rng_state) as usize) % k)
447 .collect();
448 let k_capped = k.min(20);
449 let num_subsets = 1usize << k_capped;
450 let mut dp = vec![vec![false; num_subsets]; n];
451 for v in 0..n {
452 let c = colors[v];
453 if c < k_capped {
454 dp[v][1 << c] = true;
455 }
456 }
457 for _len in 1..k_capped {
458 let old_dp = dp.clone();
459 for u in 0..n {
460 for &w in &adj[u] {
461 let cw = colors[w];
462 if cw >= k_capped {
463 continue;
464 }
465 let cw_bit = 1 << cw;
466 for s in 0..num_subsets {
467 if old_dp[u][s] && (s & cw_bit == 0) {
468 dp[w][s | cw_bit] = true;
469 }
470 }
471 }
472 }
473 }
474 let full_mask = (1 << k_capped) - 1;
475 dp.iter().any(|row| row[full_mask])
476}
477pub fn treewidth_upper_bound(adj: &[Vec<usize>]) -> usize {
480 let n = adj.len();
481 if n == 0 {
482 return 0;
483 }
484 let mut remaining: Vec<bool> = vec![true; n];
485 let mut adj_copy: Vec<std::collections::HashSet<usize>> = adj
486 .iter()
487 .map(|nbrs| nbrs.iter().cloned().collect())
488 .collect();
489 let mut max_clique = 0usize;
490 for _ in 0..n {
491 let v = (0..n)
492 .filter(|&u| remaining[u])
493 .min_by_key(|&u| adj_copy[u].len())
494 .expect("at least one remaining vertex exists: loop runs n times for n vertices");
495 let deg = adj_copy[v].len();
496 max_clique = max_clique.max(deg);
497 let nbrs: Vec<usize> = adj_copy[v].iter().cloned().collect();
498 for i in 0..nbrs.len() {
499 for j in (i + 1)..nbrs.len() {
500 adj_copy[nbrs[i]].insert(nbrs[j]);
501 adj_copy[nbrs[j]].insert(nbrs[i]);
502 }
503 }
504 remaining[v] = false;
505 for &u in &nbrs {
506 adj_copy[u].remove(&v);
507 }
508 adj_copy[v].clear();
509 }
510 max_clique
511}
512pub fn fvs_approximation(adj: &[Vec<usize>]) -> Vec<usize> {
515 let n = adj.len();
516 let mut fvs = Vec::new();
517 let mut removed = vec![false; n];
518 loop {
519 let cycle_vertex = find_cycle_vertex(adj, &removed);
520 match cycle_vertex {
521 None => break,
522 Some(v) => {
523 fvs.push(v);
524 removed[v] = true;
525 }
526 }
527 }
528 fvs
529}
530pub fn find_cycle_vertex(adj: &[Vec<usize>], removed: &[bool]) -> Option<usize> {
532 let n = adj.len();
533 let mut color = vec![0u8; n];
534 let mut cycle_v = None;
535 fn dfs(
536 u: usize,
537 parent: usize,
538 adj: &[Vec<usize>],
539 removed: &[bool],
540 color: &mut Vec<u8>,
541 cycle_v: &mut Option<usize>,
542 ) {
543 color[u] = 1;
544 for &v in &adj[u] {
545 if removed[v] || v == parent {
546 continue;
547 }
548 if color[v] == 1 {
549 *cycle_v = Some(v);
550 return;
551 }
552 if color[v] == 0 {
553 dfs(v, u, adj, removed, color, cycle_v);
554 if cycle_v.is_some() {
555 return;
556 }
557 }
558 }
559 color[u] = 2;
560 }
561 for start in 0..n {
562 if !removed[start] && color[start] == 0 {
563 dfs(start, usize::MAX, adj, removed, &mut color, &mut cycle_v);
564 if cycle_v.is_some() {
565 return cycle_v;
566 }
567 }
568 }
569 None
570}
571pub fn is_fvs(adj: &[Vec<usize>], fvs: &[usize]) -> bool {
573 let n = adj.len();
574 let mut removed = vec![false; n];
575 for &v in fvs {
576 if v < n {
577 removed[v] = true;
578 }
579 }
580 find_cycle_vertex(adj, &removed).is_none()
581}
582pub fn k_clique_brute(adj: &[Vec<usize>], k: usize) -> Option<Vec<usize>> {
585 let n = adj.len();
586 if k == 0 {
587 return Some(vec![]);
588 }
589 if k > n {
590 return None;
591 }
592 fn is_clique(adj: &[Vec<usize>], clique: &[usize]) -> bool {
593 for i in 0..clique.len() {
594 for j in (i + 1)..clique.len() {
595 if !adj[clique[i]].contains(&clique[j]) {
596 return false;
597 }
598 }
599 }
600 true
601 }
602 fn backtrack(adj: &[Vec<usize>], clique: &mut Vec<usize>, k: usize, start: usize) -> bool {
603 if clique.len() == k {
604 return is_clique(adj, clique);
605 }
606 let n = adj.len();
607 for v in start..n {
608 clique.push(v);
609 if backtrack(adj, clique, k, v + 1) {
610 return true;
611 }
612 clique.pop();
613 }
614 false
615 }
616 let mut clique = Vec::new();
617 if backtrack(adj, &mut clique, k, 0) {
618 Some(clique)
619 } else {
620 None
621 }
622}
623pub fn pathwidth_upper_bound(adj: &[Vec<usize>]) -> usize {
625 treewidth_upper_bound(adj)
626}
627pub fn crown_decomposition_ty() -> Expr {
631 arrow(cst("Graph"), arrow(nat_ty(), prop()))
632}
633pub fn crown_reduction_rule_ty() -> Expr {
636 arrow(
637 cst("Graph"),
638 arrow(nat_ty(), pair_ty(cst("Graph"), nat_ty())),
639 )
640}
641pub fn lp_relaxation_kernel_ty() -> Expr {
644 arrow(parameterized_problem_ty(), arrow(nat_ty(), prop()))
645}
646pub fn randomized_kernel_ty() -> Expr {
649 arrow(parameterized_problem_ty(), arrow(nat_ty(), prop()))
650}
651pub fn kernel_composition_ty() -> Expr {
654 arrow(parameterized_problem_ty(), prop())
655}
656pub fn poly_kernel_lower_bound_ty() -> Expr {
659 arrow(parameterized_problem_ty(), arrow(nat_ty(), prop()))
660}
661pub fn iterative_compression_ty() -> Expr {
664 arrow(parameterized_problem_ty(), prop())
665}
666pub fn independent_set_fpt_ty() -> Expr {
668 prop()
669}
670pub fn odd_cycle_transversal_fpt_ty() -> Expr {
672 prop()
673}
674pub fn compression_algorithm_ty() -> Expr {
677 arrow(parameterized_problem_ty(), arrow(nat_ty(), prop()))
678}
679pub fn universal_set_ty() -> Expr {
683 arrow(nat_ty(), arrow(nat_ty(), type0()))
684}
685pub fn universal_set_size_ty() -> Expr {
688 arrow(nat_ty(), arrow(nat_ty(), nat_ty()))
689}
690pub fn derandomization_via_phf_ty() -> Expr {
692 prop()
693}
694pub fn splitting_lemma_ty() -> Expr {
698 arrow(nat_ty(), prop())
699}
700pub fn mso1_logic_ty() -> Expr {
702 type0()
703}
704pub fn mso1_satisfies_ty() -> Expr {
706 arrow(cst("Graph"), arrow(mso1_logic_ty(), prop()))
707}
708pub fn courcelle_treewidth_ty() -> Expr {
710 pi(
711 BinderInfo::Default,
712 "phi",
713 mso2_logic_ty(),
714 arrow(nat_ty(), prop()),
715 )
716}
717pub fn courcelle_pathwidth_ty() -> Expr {
719 pi(
720 BinderInfo::Default,
721 "phi",
722 mso1_logic_ty(),
723 arrow(nat_ty(), prop()),
724 )
725}
726pub fn seese_s_theorem_ty() -> Expr {
728 prop()
729}
730pub fn clique_width_ty() -> Expr {
732 arrow(cst("Graph"), nat_ty())
733}
734pub fn w1_hardness_reduction_ty() -> Expr {
736 arrow(parameterized_problem_ty(), prop())
737}
738pub fn w2_hardness_reduction_ty() -> Expr {
740 arrow(parameterized_problem_ty(), prop())
741}
742pub fn multicolored_clique_w1_hard_ty() -> Expr {
744 prop()
745}
746pub fn k_set_cover_w2_hard_ty() -> Expr {
748 prop()
749}
750pub fn k_hitting_set_w2_hard_ty() -> Expr {
752 prop()
753}
754pub fn wp_hardness_via_circuit_ty() -> Expr {
756 prop()
757}
758pub fn grid_ramsey_ty() -> Expr {
761 arrow(nat_ty(), arrow(nat_ty(), prop()))
762}
763pub fn eth_k_vertex_cover_lb_ty() -> Expr {
765 arrow(eth_ty(), prop())
766}
767pub fn eth_fvs_lower_bound_ty() -> Expr {
769 arrow(eth_ty(), prop())
770}
771pub fn seth_ksat_lower_bound_ty() -> Expr {
773 arrow(seth_ty(), arrow(nat_ty(), prop()))
774}
775pub fn eth_implies_no_subexp_fvs_ty() -> Expr {
777 arrow(eth_ty(), prop())
778}
779pub fn seth_edge_dominating_set_lb_ty() -> Expr {
781 arrow(seth_ty(), prop())
782}
783pub fn fpt_approximation_ty() -> Expr {
786 arrow(parameterized_problem_ty(), arrow(real_ty(), prop()))
787}
788pub fn gap_eth_ty() -> Expr {
791 prop()
792}
793pub fn gap_eth_no_fptas_ty() -> Expr {
795 arrow(gap_eth_ty(), prop())
796}
797pub fn eptas_ty() -> Expr {
800 arrow(parameterized_problem_ty(), prop())
801}
802pub fn ptas_ty() -> Expr {
805 arrow(parameterized_problem_ty(), prop())
806}
807pub fn planar_eptas_ty() -> Expr {
809 prop()
810}
811pub fn dual_parameter_ty() -> Expr {
814 arrow(parameterized_problem_ty(), arrow(nat_ty(), prop()))
815}
816pub fn above_guarantee_param_ty() -> Expr {
819 arrow(parameterized_problem_ty(), arrow(nat_ty(), prop()))
820}
821pub fn structural_param_ty() -> Expr {
824 arrow(parameterized_problem_ty(), arrow(type0(), prop()))
825}
826pub fn maxsat_above_guarantee_ty() -> Expr {
828 prop()
829}
830pub fn vc_above_matching_ty() -> Expr {
832 prop()
833}
834pub fn combined_parameter_ty() -> Expr {
837 arrow(
838 parameterized_problem_ty(),
839 arrow(nat_ty(), arrow(nat_ty(), prop())),
840 )
841}
842pub fn counting_fpt_ty() -> Expr {
845 arrow(parameterized_problem_ty(), prop())
846}
847pub fn sharp_w1_ty() -> Expr {
849 type0()
850}
851pub fn sharp_w2_ty() -> Expr {
853 type0()
854}
855pub fn counting_cliques_sharp_w1_hard_ty() -> Expr {
857 prop()
858}
859pub fn counting_matchings_sharp_w1_hard_ty() -> Expr {
861 prop()
862}
863pub fn counting_homomorphisms_sharp_w1_ty() -> Expr {
865 prop()
866}
867pub fn counting_on_bounded_tw_ty() -> Expr {
869 prop()
870}
871pub fn crown_reduction_axiom_ty() -> Expr {
873 prop()
874}
875pub fn koenig_kernel_ty() -> Expr {
877 prop()
878}
879pub fn nemhauser_trotter_ty() -> Expr {
881 prop()
882}
883pub fn above_guarantee_vc_ty() -> Expr {
885 prop()
886}
887pub fn max_snp_fpt_ty() -> Expr {
889 prop()
890}
891pub fn multiparam_fpt_ty() -> Expr {
893 arrow(nat_ty(), arrow(nat_ty(), prop()))
894}
895pub fn build_env(env: &mut Environment) -> Result<(), String> {
897 build_parameterized_complexity_env(env)
898}
899pub fn build_parameterized_complexity_env(env: &mut Environment) -> Result<(), String> {
901 for (name, ty) in [
902 ("ParameterizedProblem", parameterized_problem_ty()),
903 ("Parameter", parameter_ty()),
904 ("FPTAlgorithm", fpt_algorithm_ty()),
905 ("IsInFPT", is_in_fpt_ty()),
906 ("IsInXP", is_in_xp_ty()),
907 ("IsWHard", is_w_hard_ty()),
908 ("IsWComplete", is_w_complete_ty()),
909 ("FPTReducible", fpt_reducible_ty()),
910 ("WHierarchy", w_hierarchy_ty()),
911 ("W1", w1_ty()),
912 ("W2", w2_ty()),
913 ("WP", wp_ty()),
914 ("AW", aw_ty()),
915 ("Kernel", kernel_ty()),
916 ("HasPolynomialKernel", has_polynomial_kernel_ty()),
917 ("KernelSize", kernel_size_ty()),
918 ("TreeDecomposition", tree_decomposition_ty()),
919 ("Treewidth", treewidth_ty()),
920 ("PathDecomposition", path_decomposition_ty()),
921 ("Pathwidth", pathwidth_ty()),
922 ("BranchDecomposition", branch_decomposition_ty()),
923 ("Branchwidth", branchwidth_ty()),
924 ("FeedbackVertexSet", feedback_vertex_set_ty()),
925 ("MinFVS", min_fvs_ty()),
926 ("ColorCodingAlgorithm", color_coding_algorithm_ty()),
927 ("PerfectHashFamily", perfect_hash_family_ty()),
928 ("MSO2Logic", mso2_logic_ty()),
929 ("MSO2Satisfies", mso2_satisfies_ty()),
930 ("BoundedTreewidthDP", bounded_treewidth_dp_ty()),
931 ("ETH", eth_ty()),
932 ("SETH", seth_ty()),
933 ("ETHHardness", eth_hardness_ty()),
934 ("FineGrainedReduction", fine_grained_reduction_ty()),
935 ("XPAlgorithm", xp_algorithm_ty()),
936 ("kClique", parameterized_problem_ty()),
937 ("kIndependentSet", parameterized_problem_ty()),
938 ("kVertexCover", parameterized_problem_ty()),
939 ("kDominatingSet", parameterized_problem_ty()),
940 ("kFeedbackVertexSet", parameterized_problem_ty()),
941 ("kLongestPath", parameterized_problem_ty()),
942 ("kPathWidth", parameterized_problem_ty()),
943 ("kTreewidth", parameterized_problem_ty()),
944 ] {
945 env.add(Declaration::Axiom {
946 name: Name::str(name),
947 univ_params: vec![],
948 ty,
949 })
950 .ok();
951 }
952 for (name, ty) in [
953 ("ParamComplexity.fpt_subset_xp", fpt_subset_xp_ty()),
954 ("ParamComplexity.k_clique_w1_hard", k_clique_w1_hard_ty()),
955 (
956 "ParamComplexity.k_independent_set_w1_hard",
957 k_independent_set_w1_hard_ty(),
958 ),
959 ("ParamComplexity.k_dom_set_w2_hard", k_dom_set_w2_hard_ty()),
960 (
961 "ParamComplexity.vertex_cover_kernel_2k",
962 vertex_cover_kernel_2k_ty(),
963 ),
964 (
965 "ParamComplexity.vertex_cover_kernel_k_squared",
966 vertex_cover_kernel_k_squared_ty(),
967 ),
968 ("ParamComplexity.color_coding_fpt", color_coding_fpt_ty()),
969 ("ParamComplexity.courcelle_theorem", courcelle_theorem_ty()),
970 (
971 "ParamComplexity.eth_implies_no_subexp",
972 eth_implies_no_subexp_ty(),
973 ),
974 (
975 "ParamComplexity.seth_implies_vc_lb",
976 seth_implies_vc_lb_ty(),
977 ),
978 (
979 "ParamComplexity.sparsification_lemma",
980 sparsification_lemma_ty(),
981 ),
982 ("ParamComplexity.eth_k_clique_lb", eth_k_clique_lb_ty()),
983 ("ParamComplexity.w1_hard_eth_hard", w1_hard_eth_hard_ty()),
984 (
985 "ParamComplexity.treewidth_le_pathwidth",
986 treewidth_le_pathwidth_ty(),
987 ),
988 ("ParamComplexity.fvs_in_fpt", is_in_fpt_ty()),
989 ("ParamComplexity.w1_in_xp", w1_in_xp_ty()),
990 (
991 "ParamComplexity.crown_reduction_axiom",
992 crown_reduction_axiom_ty(),
993 ),
994 ("ParamComplexity.koenig_kernel", koenig_kernel_ty()),
995 ("ParamComplexity.nemhauser_trotter", nemhauser_trotter_ty()),
996 (
997 "ParamComplexity.above_guarantee_vc",
998 above_guarantee_vc_ty(),
999 ),
1000 (
1001 "ParamComplexity.iterative_compression",
1002 iterative_compression_ty(),
1003 ),
1004 (
1005 "ParamComplexity.independent_set_fpt",
1006 independent_set_fpt_ty(),
1007 ),
1008 (
1009 "ParamComplexity.odd_cycle_transversal_fpt",
1010 odd_cycle_transversal_fpt_ty(),
1011 ),
1012 (
1013 "ParamComplexity.derandomization_via_phf",
1014 derandomization_via_phf_ty(),
1015 ),
1016 (
1017 "ParamComplexity.courcelle_treewidth",
1018 courcelle_treewidth_ty(),
1019 ),
1020 (
1021 "ParamComplexity.courcelle_pathwidth",
1022 courcelle_pathwidth_ty(),
1023 ),
1024 ("ParamComplexity.seese_s_theorem", seese_s_theorem_ty()),
1025 (
1026 "ParamComplexity.multicolored_clique_w1_hard",
1027 multicolored_clique_w1_hard_ty(),
1028 ),
1029 (
1030 "ParamComplexity.k_set_cover_w2_hard",
1031 k_set_cover_w2_hard_ty(),
1032 ),
1033 (
1034 "ParamComplexity.k_hitting_set_w2_hard",
1035 k_hitting_set_w2_hard_ty(),
1036 ),
1037 (
1038 "ParamComplexity.wp_hardness_via_circuit",
1039 wp_hardness_via_circuit_ty(),
1040 ),
1041 (
1042 "ParamComplexity.eth_k_vertex_cover_lb",
1043 eth_k_vertex_cover_lb_ty(),
1044 ),
1045 (
1046 "ParamComplexity.eth_fvs_lower_bound",
1047 eth_fvs_lower_bound_ty(),
1048 ),
1049 ("ParamComplexity.gap_eth", gap_eth_ty()),
1050 ("ParamComplexity.gap_eth_no_fptas", gap_eth_no_fptas_ty()),
1051 (
1052 "ParamComplexity.maxsat_above_guarantee",
1053 maxsat_above_guarantee_ty(),
1054 ),
1055 ("ParamComplexity.vc_above_matching", vc_above_matching_ty()),
1056 (
1057 "ParamComplexity.counting_cliques_sharp_w1_hard",
1058 counting_cliques_sharp_w1_hard_ty(),
1059 ),
1060 (
1061 "ParamComplexity.counting_matchings_sharp_w1_hard",
1062 counting_matchings_sharp_w1_hard_ty(),
1063 ),
1064 (
1065 "ParamComplexity.counting_homomorphisms_sharp_w1",
1066 counting_homomorphisms_sharp_w1_ty(),
1067 ),
1068 (
1069 "ParamComplexity.counting_on_bounded_tw",
1070 counting_on_bounded_tw_ty(),
1071 ),
1072 ("ParamComplexity.planar_eptas", planar_eptas_ty()),
1073 ("ParamComplexity.max_snp_fpt", max_snp_fpt_ty()),
1074 ] {
1075 env.add(Declaration::Axiom {
1076 name: Name::str(name),
1077 univ_params: vec![],
1078 ty,
1079 })
1080 .ok();
1081 }
1082 for (name, ty) in [
1083 ("CrownDecomposition", crown_decomposition_ty()),
1084 ("CrownReductionRule", crown_reduction_rule_ty()),
1085 ("LPRelaxationKernel", lp_relaxation_kernel_ty()),
1086 ("RandomizedKernel", randomized_kernel_ty()),
1087 ("KernelComposition", kernel_composition_ty()),
1088 ("IterativeCompression", iterative_compression_ty()),
1089 ("CompressionAlgorithm", compression_algorithm_ty()),
1090 ("UniversalSet", universal_set_ty()),
1091 ("UniversalSetSize", universal_set_size_ty()),
1092 ("SplittingLemma", splitting_lemma_ty()),
1093 ("MSO1Logic", mso1_logic_ty()),
1094 ("MSO1Satisfies", mso1_satisfies_ty()),
1095 ("CliqueWidth", clique_width_ty()),
1096 ("W1HardnessReduction", w1_hardness_reduction_ty()),
1097 ("W2HardnessReduction", w2_hardness_reduction_ty()),
1098 ("GridRamsey", grid_ramsey_ty()),
1099 ("ETHKVertexCoverLB", eth_k_vertex_cover_lb_ty()),
1100 ("ETHKFVSLowerBound", eth_fvs_lower_bound_ty()),
1101 ("SETHKSATLowerBound", seth_ksat_lower_bound_ty()),
1102 ("FPTApproximation", fpt_approximation_ty()),
1103 ("GapETH", gap_eth_ty()),
1104 ("EPTAS", eptas_ty()),
1105 ("PTAS", ptas_ty()),
1106 ("DualParameter", dual_parameter_ty()),
1107 ("AboveGuaranteeParam", above_guarantee_param_ty()),
1108 ("StructuralParam", structural_param_ty()),
1109 ("CombinedParameter", combined_parameter_ty()),
1110 ("CountingFPT", counting_fpt_ty()),
1111 ("SharpW1", sharp_w1_ty()),
1112 ("SharpW2", sharp_w2_ty()),
1113 ("PolyKernelLowerBound", poly_kernel_lower_bound_ty()),
1114 ("MultiparamFPT", multiparam_fpt_ty()),
1115 ] {
1116 env.add(Declaration::Axiom {
1117 name: Name::str(name),
1118 univ_params: vec![],
1119 ty,
1120 })
1121 .ok();
1122 }
1123 Ok(())
1124}
1125#[cfg(test)]
1126mod tests {
1127 use super::*;
1128 #[test]
1129 fn test_vertex_cover_bst_small() {
1130 let adj = vec![vec![1, 2], vec![0, 2], vec![0, 1]];
1131 let result = vertex_cover_bst(&adj, 2);
1132 assert!(result.is_some(), "Triangle should have 2-vertex cover");
1133 let cover = result.expect("result should be valid");
1134 assert!(cover.len() <= 2);
1135 for u in 0..adj.len() {
1136 for &v in &adj[u] {
1137 assert!(
1138 cover.contains(&u) || cover.contains(&v),
1139 "Edge ({}, {}) not covered",
1140 u,
1141 v
1142 );
1143 }
1144 }
1145 }
1146 #[test]
1147 fn test_vertex_cover_bst_impossible() {
1148 let adj = vec![vec![1, 2, 3], vec![0, 2, 3], vec![0, 1, 3], vec![0, 1, 2]];
1149 assert!(vertex_cover_bst(&adj, 1).is_none());
1150 assert!(vertex_cover_bst(&adj, 3).is_some());
1151 }
1152 #[test]
1153 fn test_treewidth_upper_bound_path() {
1154 let adj = vec![vec![1], vec![0, 2], vec![1, 3], vec![2, 4], vec![3]];
1155 let tw = treewidth_upper_bound(&adj);
1156 assert!(tw <= 2, "Path should have treewidth β€ 2, got {}", tw);
1157 }
1158 #[test]
1159 fn test_treewidth_upper_bound_complete() {
1160 let adj = vec![vec![1, 2, 3], vec![0, 2, 3], vec![0, 1, 3], vec![0, 1, 2]];
1161 let tw = treewidth_upper_bound(&adj);
1162 assert!(tw >= 3, "K_4 should have treewidth β₯ 3, got {}", tw);
1163 }
1164 #[test]
1165 fn test_color_coding_k_path() {
1166 let adj = vec![
1167 vec![1],
1168 vec![0, 2],
1169 vec![1, 3],
1170 vec![2, 4],
1171 vec![3, 5],
1172 vec![4],
1173 ];
1174 let found = color_coding_k_path(&adj, 4, 42);
1175 assert!(found, "Should find a 4-path in a 6-path graph");
1176 }
1177 #[test]
1178 fn test_fvs_approximation() {
1179 let adj = vec![vec![1, 3], vec![0, 2], vec![1, 3], vec![2, 0]];
1180 let fvs = fvs_approximation(&adj);
1181 assert!(
1182 is_fvs(&adj, &fvs),
1183 "FVS approximation should produce a valid FVS"
1184 );
1185 }
1186 #[test]
1187 fn test_is_fvs() {
1188 let adj = vec![vec![1, 2], vec![0, 3], vec![0], vec![1]];
1189 assert!(is_fvs(&adj, &[]), "Tree should have empty FVS");
1190 let cycle = vec![vec![1, 3], vec![0, 2], vec![1, 3], vec![2, 0]];
1191 assert!(
1192 is_fvs(&cycle, &[0]),
1193 "Removing vertex 0 from C4 should break all cycles"
1194 );
1195 }
1196 #[test]
1197 fn test_k_clique_brute() {
1198 let adj = vec![vec![1, 2, 3], vec![0, 2, 3], vec![0, 1, 3], vec![0, 1, 2]];
1199 assert!(k_clique_brute(&adj, 3).is_some());
1200 assert!(k_clique_brute(&adj, 5).is_none());
1201 }
1202 #[test]
1203 fn test_build_parameterized_complexity_env() {
1204 let mut env = Environment::new();
1205 let result = build_parameterized_complexity_env(&mut env);
1206 assert!(result.is_ok(), "build should succeed");
1207 assert!(env.get(&Name::str("IsInFPT")).is_some());
1208 assert!(env.get(&Name::str("Treewidth")).is_some());
1209 assert!(env.get(&Name::str("ETH")).is_some());
1210 assert!(env.get(&Name::str("SETH")).is_some());
1211 }
1212 #[test]
1213 fn test_crown_decomposition_tree() {
1214 let adj = vec![vec![1, 2], vec![0, 3], vec![0], vec![1]];
1215 let cd = CrownDecomposition::compute(&adj, 2);
1216 assert!(cd.verify(&adj));
1217 }
1218 #[test]
1219 fn test_crown_decomposition_isolated() {
1220 let adj: Vec<Vec<usize>> = vec![vec![], vec![2], vec![1], vec![]];
1221 let cd = CrownDecomposition::compute(&adj, 1);
1222 assert!(cd.verify(&adj));
1223 assert!(cd.crown.contains(&0) || cd.crown.contains(&3));
1224 }
1225 #[test]
1226 fn test_crown_decomposition_head_size() {
1227 let adj: Vec<Vec<usize>> = vec![vec![], vec![2], vec![1]];
1228 let cd = CrownDecomposition::compute(&adj, 1);
1229 let _ = cd.head_size();
1230 }
1231 #[test]
1232 fn test_color_coding_fpt_construction() {
1233 let cc = ColorCodingFPT::new(4, false);
1234 assert_eq!(cc.k, 4);
1235 assert!(!cc.use_perfect_hash);
1236 assert!(cc.repetitions > 0);
1237 let rt = cc.running_time();
1238 assert!(rt.contains("4"));
1239 }
1240 #[test]
1241 fn test_color_coding_fpt_find_path() {
1242 let adj = vec![
1243 vec![1],
1244 vec![0, 2],
1245 vec![1, 3],
1246 vec![2, 4],
1247 vec![3, 5],
1248 vec![4],
1249 ];
1250 let cc = ColorCodingFPT::new(4, false);
1251 let found = cc.find_k_path(&adj);
1252 assert!(found, "Should find 4-path in 6-path graph");
1253 }
1254 #[test]
1255 fn test_color_coding_fpt_hamiltonian() {
1256 let cc = ColorCodingFPT::new(5, true);
1257 assert!(cc.can_detect_hamiltonian_path(4));
1258 assert!(!cc.can_detect_hamiltonian_path(6));
1259 }
1260 #[test]
1261 fn test_color_coding_fpt_deterministic() {
1262 let cc = ColorCodingFPT::new(3, true);
1263 assert!(cc.use_perfect_hash);
1264 assert_eq!(cc.repetitions, 1);
1265 let rt = cc.running_time();
1266 assert!(rt.contains("deterministic"));
1267 }
1268 #[test]
1269 fn test_courcelle_msol_checker_construction() {
1270 let checker = CourcelleMSOLChecker::new(3, "βS β V : |S| β€ k β§ S is dominating", 2);
1271 assert_eq!(checker.max_treewidth, 3);
1272 assert_eq!(checker.mso_version, 2);
1273 let rt = checker.running_time();
1274 assert!(rt.contains("treewidth"));
1275 }
1276 #[test]
1277 fn test_courcelle_msol_checker_on_path() {
1278 let adj = vec![vec![1], vec![0, 2], vec![1, 3], vec![2]];
1279 let checker = CourcelleMSOLChecker::new(2, "k-coloring", 1);
1280 assert!(checker.check(&adj));
1281 }
1282 #[test]
1283 fn test_courcelle_msol_checker_on_k4() {
1284 let adj = vec![vec![1, 2, 3], vec![0, 2, 3], vec![0, 1, 3], vec![0, 1, 2]];
1285 let checker_small = CourcelleMSOLChecker::new(2, "3-coloring", 2);
1286 assert!(!checker_small.check(&adj));
1287 let checker_large = CourcelleMSOLChecker::new(5, "3-coloring", 2);
1288 assert!(checker_large.check(&adj));
1289 }
1290 #[test]
1291 fn test_courcelle_decidable_properties() {
1292 let checker = CourcelleMSOLChecker::new(4, "Hamiltonicity", 2);
1293 let desc = checker.decidable_properties();
1294 assert!(desc.contains("treewidth"));
1295 }
1296 #[test]
1297 fn test_vertex_cover_fpt_solve_triangle() {
1298 let adj = vec![vec![1, 2], vec![0, 2], vec![0, 1]];
1299 let vc = VertexCoverFPT::new(2);
1300 let result = vc.solve(&adj);
1301 assert!(result.is_some(), "Triangle has a 2-vertex cover");
1302 let cover = result.expect("result should be valid");
1303 for u in 0..adj.len() {
1304 for &v in &adj[u] {
1305 assert!(cover.contains(&u) || cover.contains(&v));
1306 }
1307 }
1308 }
1309 #[test]
1310 fn test_vertex_cover_fpt_solve_k4() {
1311 let adj = vec![vec![1, 2, 3], vec![0, 2, 3], vec![0, 1, 3], vec![0, 1, 2]];
1312 let vc3 = VertexCoverFPT::new(3);
1313 assert!(vc3.solve(&adj).is_some());
1314 let vc1 = VertexCoverFPT::new(1);
1315 assert!(vc1.solve(&adj).is_none());
1316 }
1317 #[test]
1318 fn test_vertex_cover_fpt_running_time() {
1319 let vc = VertexCoverFPT::new(5);
1320 let rt = vc.running_time();
1321 assert!(rt.contains("5"));
1322 }
1323 #[test]
1324 fn test_vertex_cover_fpt_lp_kernel() {
1325 let adj = vec![vec![1, 2, 3, 4], vec![0], vec![0], vec![0], vec![0]];
1326 let vc = VertexCoverFPT::new(3);
1327 let (_, cover, _) = vc.lp_kernel(&adj);
1328 assert!(cover.contains(&0), "Center should be in LP kernel cover");
1329 }
1330 #[test]
1331 fn test_iterative_compression_vc_triangle() {
1332 let adj = vec![vec![1, 2], vec![0, 2], vec![0, 1]];
1333 let ic = IterativeCompressionVC::new(2);
1334 let over_cover = vec![0, 1, 2];
1335 let result = ic.compress(&adj, &over_cover);
1336 assert!(result.is_some(), "Triangle should compress to 2-cover");
1337 }
1338 #[test]
1339 fn test_iterative_compression_vc_impossible() {
1340 let adj = vec![vec![1, 2, 3], vec![0, 2, 3], vec![0, 1, 3], vec![0, 1, 2]];
1341 let ic = IterativeCompressionVC::new(1);
1342 let over_cover = vec![0, 1];
1343 let result = ic.compress(&adj, &over_cover);
1344 assert!(result.is_none(), "K_4 cannot be covered by 1 vertex");
1345 }
1346 #[test]
1347 fn test_build_parameterized_complexity_env_new() {
1348 let mut env = Environment::new();
1349 let result = build_parameterized_complexity_env(&mut env);
1350 assert!(result.is_ok());
1351 assert!(env.get(&Name::str("CrownDecomposition")).is_some());
1352 assert!(env.get(&Name::str("SharpW1")).is_some());
1353 assert!(env.get(&Name::str("GapETH")).is_some());
1354 assert!(env.get(&Name::str("EPTAS")).is_some());
1355 assert!(env.get(&Name::str("MSO1Logic")).is_some());
1356 assert!(env.get(&Name::str("CliqueWidth")).is_some());
1357 assert!(env.get(&Name::str("UniversalSet")).is_some());
1358 assert!(env.get(&Name::str("DualParameter")).is_some());
1359 }
1360}
1361#[cfg(test)]
1362mod tests_pc_extra {
1363 use super::*;
1364 #[test]
1365 fn test_fpt_algorithm() {
1366 let bst = FPTMethod::bounded_search_tree_vc();
1367 assert!(bst.is_single_exponential());
1368 let r = bst.runtime(5, 1000);
1369 assert!((r - 32000.0).abs() < 1e-6);
1370 }
1371 #[test]
1372 fn test_kernelization() {
1373 let vc = Kernelization::vertex_cover_2k();
1374 assert!(vc.is_polynomial_kernel());
1375 let sz = vc.kernel_size(10);
1376 assert_eq!(sz, Some(20.0));
1377 let fvs = Kernelization::feedback_vertex_set();
1378 assert!(fvs.is_polynomial_kernel());
1379 }
1380 #[test]
1381 fn test_w_hierarchy() {
1382 let vc = WClass::vertex_cover_class();
1383 assert!(vc.is_fpt());
1384 let cl = WClass::clique_class();
1385 assert!(!cl.is_fpt());
1386 assert!(!cl.harder_than_w1());
1387 let ds = WClass::dominating_set_class();
1388 assert!(ds.harder_than_w1());
1389 assert!(ds > cl);
1390 }
1391 #[test]
1392 fn test_treewidth_algorithm() {
1393 let sat = TreewidthAlgorithm::satisfiability_tw();
1394 assert!(sat.is_linear_time_in_n());
1395 let r = sat.runtime(3, 100);
1396 assert!((r - 800.0).abs() < 1e-6);
1397 }
1398 #[test]
1399 fn test_param_reduction() {
1400 let red = ParamReduction::new("IndependentSet", "Clique", "k", "k", "f(k)=k");
1401 assert!(red.is_fpt_reduction());
1402 let bad_red = ParamReduction::new("A", "B", "k", "k+log(n)", "k+log(n)");
1403 assert!(!bad_red.is_fpt_reduction());
1404 }
1405}