Skip to main content

oxilean_std/parameterized_complexity/
functions.rs

1//! Auto-generated module
2//!
3//! πŸ€– Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use 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}
58/// `ParameterizedProblem : Type` β€” a problem with an associated parameter function.
59pub fn parameterized_problem_ty() -> Expr {
60    type0()
61}
62/// `Parameter : Type` β€” a natural-number parameter extracted from an instance.
63pub fn parameter_ty() -> Expr {
64    arrow(cst("String"), nat_ty())
65}
66/// `FPTAlgorithm : ParameterizedProblem β†’ Type`
67/// An algorithm running in f(k)Β·n^c time for some computable f and constant c.
68pub fn fpt_algorithm_ty() -> Expr {
69    arrow(parameterized_problem_ty(), type0())
70}
71/// `IsInFPT : ParameterizedProblem β†’ Prop`
72/// The problem is in FPT (Fixed-Parameter Tractable).
73pub fn is_in_fpt_ty() -> Expr {
74    arrow(parameterized_problem_ty(), prop())
75}
76/// `IsInXP : ParameterizedProblem β†’ Prop`
77/// The problem is in XP (solvable in n^f(k) time for each fixed k).
78pub fn is_in_xp_ty() -> Expr {
79    arrow(parameterized_problem_ty(), prop())
80}
81/// `IsWHard : Nat β†’ ParameterizedProblem β†’ Prop`
82/// The problem is W[i]-hard (for the given level i of W-hierarchy).
83pub fn is_w_hard_ty() -> Expr {
84    arrow(nat_ty(), arrow(parameterized_problem_ty(), prop()))
85}
86/// `IsWComplete : Nat β†’ ParameterizedProblem β†’ Prop`
87/// The problem is W[i]-complete.
88pub fn is_w_complete_ty() -> Expr {
89    arrow(nat_ty(), arrow(parameterized_problem_ty(), prop()))
90}
91/// `FPTReducible : ParameterizedProblem β†’ ParameterizedProblem β†’ Prop`
92/// There exists an FPT-time parameterized reduction between problems.
93pub fn fpt_reducible_ty() -> Expr {
94    arrow(
95        parameterized_problem_ty(),
96        arrow(parameterized_problem_ty(), prop()),
97    )
98}
99/// `WHierarchy : Nat β†’ Type` β€” the i-th level of the W-hierarchy.
100pub fn w_hierarchy_ty() -> Expr {
101    arrow(nat_ty(), type0())
102}
103/// `W1 : Type` β€” the class W[1] (contains k-clique, k-independent set).
104pub fn w1_ty() -> Expr {
105    type0()
106}
107/// `W2 : Type` β€” the class W[2] (contains k-dominating set, k-set cover).
108pub fn w2_ty() -> Expr {
109    type0()
110}
111/// `WP : Type` β€” the class W[P] (contains weighted circuit satisfiability).
112pub fn wp_ty() -> Expr {
113    type0()
114}
115/// `AW : Type` β€” the class AW[*] (alternating W hierarchy).
116pub fn aw_ty() -> Expr {
117    type0()
118}
119/// `FPT_subset_W1 : FPT βŠ† W[1]`
120pub 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}
126/// `Kernel : ParameterizedProblem β†’ Nat β†’ Type`
127/// A kernelization of size f(k): reduces any instance (x,k) to (x',k') with
128/// |x'| ≀ f(k) and (x,k) ∈ L ↔ (x',k') ∈ L.
129pub fn kernel_ty() -> Expr {
130    arrow(
131        parameterized_problem_ty(),
132        arrow(arrow(nat_ty(), nat_ty()), type0()),
133    )
134}
135/// `HasPolynomialKernel : ParameterizedProblem β†’ Prop`
136/// The problem has a polynomial kernel (|x'| ≀ k^c for some constant c).
137pub fn has_polynomial_kernel_ty() -> Expr {
138    arrow(parameterized_problem_ty(), prop())
139}
140/// `KernelSize : Kernel P f β†’ Nat β†’ Nat`
141/// The size of the kernel as a function of the parameter.
142pub fn kernel_size_ty() -> Expr {
143    arrow(nat_ty(), nat_ty())
144}
145/// `VertexCoverKernel2k : VertexCover has a 2k-vertex kernel`
146pub fn vertex_cover_kernel_2k_ty() -> Expr {
147    prop()
148}
149/// `VertexCoverKernelKSquared : VertexCover has a k^2-vertex kernel (Buss kernel)`
150pub fn vertex_cover_kernel_k_squared_ty() -> Expr {
151    prop()
152}
153/// `TreeDecomposition : Graph β†’ Type`
154/// A tree decomposition: a tree T with bags B_t βŠ† V such that every edge and
155/// vertex is covered, and the bags form connected subtrees.
156pub fn tree_decomposition_ty() -> Expr {
157    arrow(cst("Graph"), type0())
158}
159/// `Treewidth : Graph β†’ Nat`
160/// The treewidth of a graph: min over all tree decompositions of (max bag size βˆ’ 1).
161pub fn treewidth_ty() -> Expr {
162    arrow(cst("Graph"), nat_ty())
163}
164/// `PathDecomposition : Graph β†’ Type`
165/// A path decomposition: a path (sequence) of bags covering all vertices/edges.
166pub fn path_decomposition_ty() -> Expr {
167    arrow(cst("Graph"), type0())
168}
169/// `Pathwidth : Graph β†’ Nat`
170/// The pathwidth of a graph: min over all path decompositions of (max bag size βˆ’ 1).
171pub fn pathwidth_ty() -> Expr {
172    arrow(cst("Graph"), nat_ty())
173}
174/// `TreewidthLePathwidth : βˆ€ G, treewidth G ≀ pathwidth G`
175pub 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}
188/// `BranchDecomposition : Graph β†’ Type` β€” a branch decomposition.
189pub fn branch_decomposition_ty() -> Expr {
190    arrow(cst("Graph"), type0())
191}
192/// `Branchwidth : Graph β†’ Nat`
193pub fn branchwidth_ty() -> Expr {
194    arrow(cst("Graph"), nat_ty())
195}
196/// `FeedbackVertexSet : Graph β†’ Set Vertex β†’ Prop`
197/// S is a FVS if G βˆ’ S is a forest (acyclic).
198pub fn feedback_vertex_set_ty() -> Expr {
199    arrow(cst("Graph"), arrow(list_ty(nat_ty()), prop()))
200}
201/// `MinFVS : Graph β†’ Nat`
202/// The minimum feedback vertex set size of a graph.
203pub fn min_fvs_ty() -> Expr {
204    arrow(cst("Graph"), nat_ty())
205}
206/// `FVSParameterizedByK : ParameterizedProblem`
207/// The FVS problem parameterized by solution size k β€” in FPT.
208pub fn fvs_parameterized_ty() -> Expr {
209    parameterized_problem_ty()
210}
211/// `ColorCodingAlgorithm : Nat β†’ Graph β†’ Nat β†’ Bool`
212/// Color-coding for k-path/subgraph: randomly color vertices with k colors
213/// and check for a colorful copy using DP.
214pub fn color_coding_algorithm_ty() -> Expr {
215    arrow(nat_ty(), arrow(cst("Graph"), arrow(nat_ty(), bool_ty())))
216}
217/// `ColorCodingFPT : k-path is in FPT via color coding`
218/// Running time: 2^O(k) Β· n^O(1).
219pub fn color_coding_fpt_ty() -> Expr {
220    prop()
221}
222/// `PerfectHashFamily : Nat β†’ Nat β†’ Type`
223/// An (n,k)-perfect hash family: a set of functions [n]β†’[k] such that
224/// for every k-subset S βŠ† [n], some function is injective on S.
225pub fn perfect_hash_family_ty() -> Expr {
226    arrow(nat_ty(), arrow(nat_ty(), type0()))
227}
228/// `MSO2Logic : Type` β€” Monadic Second-Order Logic (MSOβ‚‚) formula.
229pub fn mso2_logic_ty() -> Expr {
230    type0()
231}
232/// `MSO2Satisfies : Graph β†’ MSO2Logic β†’ Prop`
233/// A graph satisfies an MSOβ‚‚ formula.
234pub fn mso2_satisfies_ty() -> Expr {
235    arrow(cst("Graph"), arrow(mso2_logic_ty(), prop()))
236}
237/// `CourcelleTheorem : βˆ€ Ο† : MSOβ‚‚, βˆ€ k : Nat, CheckMSO2 ∈ FPT(treewidth)`
238/// Every graph property definable in MSOβ‚‚ is decidable in linear FPT time
239/// on graphs of bounded treewidth.
240pub 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}
248/// `BoundedTreewidthDP : Graph β†’ Nat β†’ Prop`
249/// Bounded treewidth dynamic programming: many NP-hard problems are FPT
250/// when parameterized by treewidth.
251pub fn bounded_treewidth_dp_ty() -> Expr {
252    arrow(cst("Graph"), arrow(nat_ty(), prop()))
253}
254/// `ETH : Prop` β€” Exponential Time Hypothesis
255/// 3-SAT cannot be solved in 2^o(n) time.
256pub fn eth_ty() -> Expr {
257    prop()
258}
259/// `SETH : Prop` β€” Strong Exponential Time Hypothesis
260/// k-SAT cannot be solved in (2 βˆ’ Ξ΅)^n time for any Ξ΅ > 0 and all k.
261pub fn seth_ty() -> Expr {
262    prop()
263}
264/// `ETH_implies_no_subexp_fpt : ETH β†’ some problems have no 2^o(k)Β·poly(n) algorithm`
265pub fn eth_implies_no_subexp_ty() -> Expr {
266    arrow(eth_ty(), prop())
267}
268/// `SETH_implies_no_ons_vc : SETH β†’ VertexCover has no O(1.9999^k) alg unless SETH fails`
269pub fn seth_implies_vc_lb_ty() -> Expr {
270    arrow(seth_ty(), prop())
271}
272/// `SparsificationLemma : 3-SAT with n vars, m clauses reduces to 2^Ξ΅n instances with O(n) clauses`
273pub fn sparsification_lemma_ty() -> Expr {
274    prop()
275}
276/// `ETH_k_clique_lb : ETH β†’ k-clique needs n^Ξ©(k) time`
277pub fn eth_k_clique_lb_ty() -> Expr {
278    arrow(eth_ty(), arrow(nat_ty(), prop()))
279}
280/// `FineGrainedReduction : Problem β†’ Problem β†’ Prop`
281/// A fine-grained reduction preserving exact running time exponents.
282pub fn fine_grained_reduction_ty() -> Expr {
283    arrow(
284        parameterized_problem_ty(),
285        arrow(parameterized_problem_ty(), prop()),
286    )
287}
288/// `XPAlgorithm : ParameterizedProblem β†’ Type`
289/// An XP algorithm runs in n^f(k) time for computable f.
290pub fn xp_algorithm_ty() -> Expr {
291    arrow(parameterized_problem_ty(), type0())
292}
293/// `FPT_subset_XP : Every FPT problem is in XP`
294pub 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}
302/// `W1_in_XP : W[1] βŠ† XP (assuming W[1] β‰  FPT)`
303pub fn w1_in_xp_ty() -> Expr {
304    prop()
305}
306/// `ETHHardness : ParameterizedProblem β†’ Prop`
307/// The problem has no f(k)Β·2^o(n) algorithm under ETH.
308pub fn eth_hardness_ty() -> Expr {
309    arrow(parameterized_problem_ty(), prop())
310}
311/// `W1Hard_implies_ETH_hard : W[1]-hard implies no f(k)Β·n^g(1) FPT unless W[1]=FPT`
312pub 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}
323/// `kCliqueW1Hard : k-Clique is W[1]-complete`
324pub fn k_clique_w1_hard_ty() -> Expr {
325    prop()
326}
327/// `kIndependentSetW1Hard : k-IndependentSet is W[1]-complete`
328pub fn k_independent_set_w1_hard_ty() -> Expr {
329    prop()
330}
331/// `kDomSetW2Hard : k-DominatingSet is W[2]-complete`
332pub fn k_dom_set_w2_hard_ty() -> Expr {
333    prop()
334}
335/// Build a path decomposition (linear tree decomposition) for a path graph on n vertices.
336/// This gives pathwidth = 1 for a simple path.
337pub 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}
359/// Vertex cover solver using bounded search tree (exponential in k, polynomial in n).
360/// Returns Some(cover) if a vertex cover of size ≀ k exists, else None.
361pub 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}
409/// Apply the Crown reduction rule for vertex cover kernelization.
410/// Returns the reduced graph and the vertices already in the cover.
411pub 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}
428/// Color-coding for k-path detection (simplified randomized version).
429/// Colors vertices randomly with k colors, then checks for a colorful path of length k.
430pub 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}
477/// Naive treewidth computation for small graphs using elimination ordering.
478/// Returns an upper bound on treewidth via a greedy minimum-degree elimination.
479pub 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}
512/// Feedback Vertex Set approximation using iterative compression.
513/// Returns an approximate FVS (2-approximation via iterative removal of cycles).
514pub 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}
530/// Find a vertex on a cycle in the graph (ignoring removed vertices).
531pub 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}
571/// Check if a given set S is a feedback vertex set for the graph.
572pub 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}
582/// Solve k-clique detection by brute force (exponential in k, polynomial baseline).
583/// Used to validate color-coding results.
584pub 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}
623/// Pathwidth computation (exact for trees, upper bound for general graphs).
624pub fn pathwidth_upper_bound(adj: &[Vec<usize>]) -> usize {
625    treewidth_upper_bound(adj)
626}
627/// `CrownDecomposition : Graph β†’ Nat β†’ Prop`
628/// Crown decomposition for vertex cover: a partition V = H βˆͺ C βˆͺ R where H is
629/// the head, C is the crown (an independent set matching into H), R is the rest.
630pub fn crown_decomposition_ty() -> Expr {
631    arrow(cst("Graph"), arrow(nat_ty(), prop()))
632}
633/// `CrownReductionRule : Graph β†’ Nat β†’ Graph Γ— Nat`
634/// Given a crown (H, C), remove H and C and reduce k by |H|.
635pub fn crown_reduction_rule_ty() -> Expr {
636    arrow(
637        cst("Graph"),
638        arrow(nat_ty(), pair_ty(cst("Graph"), nat_ty())),
639    )
640}
641/// `LPRelaxationKernel : ParameterizedProblem β†’ Nat β†’ Prop`
642/// LP relaxation half-integrality gives a 2k-vertex kernel for vertex cover.
643pub fn lp_relaxation_kernel_ty() -> Expr {
644    arrow(parameterized_problem_ty(), arrow(nat_ty(), prop()))
645}
646/// `RandomizedKernel : ParameterizedProblem β†’ Nat β†’ Prop`
647/// A randomized kernelization algorithm (correct with high probability).
648pub fn randomized_kernel_ty() -> Expr {
649    arrow(parameterized_problem_ty(), arrow(nat_ty(), prop()))
650}
651/// `KernelComposition : ParameterizedProblem β†’ Prop`
652/// An OR-composition for cross-composition lower bounds on kernelization.
653pub fn kernel_composition_ty() -> Expr {
654    arrow(parameterized_problem_ty(), prop())
655}
656/// `PolynomialKernelLowerBound : ParameterizedProblem β†’ Nat β†’ Prop`
657/// No polynomial kernel of size < k^c unless NP βŠ† coNP/poly.
658pub fn poly_kernel_lower_bound_ty() -> Expr {
659    arrow(parameterized_problem_ty(), arrow(nat_ty(), prop()))
660}
661/// `IterativeCompression : ParameterizedProblem β†’ Prop`
662/// FPT via iterative compression: given a size-(k+1) solution, find a size-k one.
663pub fn iterative_compression_ty() -> Expr {
664    arrow(parameterized_problem_ty(), prop())
665}
666/// `IndependentSetFPT : k-IndependentSet is in FPT via iterative compression (for special graphs)`
667pub fn independent_set_fpt_ty() -> Expr {
668    prop()
669}
670/// `OddCycleTransversalFPT : Odd-Cycle Transversal is FPT via iterative compression`
671pub fn odd_cycle_transversal_fpt_ty() -> Expr {
672    prop()
673}
674/// `CompressionAlgorithm : ParameterizedProblem β†’ Nat β†’ Prop`
675/// Given a (k+1)-solution, the compression algorithm finds a k-solution or returns None.
676pub fn compression_algorithm_ty() -> Expr {
677    arrow(parameterized_problem_ty(), arrow(nat_ty(), prop()))
678}
679/// `UniversalSet : Nat β†’ Nat β†’ Type`
680/// An (n,k)-universal set: a family F of functions [n]β†’{0,1} such that for
681/// every k-subset S βŠ† [n], F restricted to S contains all 2^k patterns.
682pub fn universal_set_ty() -> Expr {
683    arrow(nat_ty(), arrow(nat_ty(), type0()))
684}
685/// `UniversalSetSize : Nat β†’ Nat β†’ Nat`
686/// |UniversalSet n k| = O(2^k Β· k^2 Β· log n) (Naor-Schulman-Srinivasan).
687pub fn universal_set_size_ty() -> Expr {
688    arrow(nat_ty(), arrow(nat_ty(), nat_ty()))
689}
690/// `DerandomizationViaPHF : k-Subgraph is FPT with deterministic algorithm via PHF`
691pub fn derandomization_via_phf_ty() -> Expr {
692    prop()
693}
694/// `SplittingLemma : Nat β†’ Prop`
695/// The splitting lemma for color-coding: an n-coloring witnesses a colorful copy
696/// with probability β‰₯ k!/k^k β‰₯ e^{-k}.
697pub fn splitting_lemma_ty() -> Expr {
698    arrow(nat_ty(), prop())
699}
700/// `MSO1Logic : Type` β€” Monadic Second-Order Logic MSO₁ (quantifies over vertex sets).
701pub fn mso1_logic_ty() -> Expr {
702    type0()
703}
704/// `MSO1Satisfies : Graph β†’ MSO1Logic β†’ Prop`
705pub fn mso1_satisfies_ty() -> Expr {
706    arrow(cst("Graph"), arrow(mso1_logic_ty(), prop()))
707}
708/// `CourcelleTreewidth : βˆ€ Ο† : MSOβ‚‚, every bounded-treewidth property is linear-time FPT`
709pub fn courcelle_treewidth_ty() -> Expr {
710    pi(
711        BinderInfo::Default,
712        "phi",
713        mso2_logic_ty(),
714        arrow(nat_ty(), prop()),
715    )
716}
717/// `CourcellePathwidth : MSO₁ model checking is FPT on bounded pathwidth graphs`
718pub fn courcelle_pathwidth_ty() -> Expr {
719    pi(
720        BinderInfo::Default,
721        "phi",
722        mso1_logic_ty(),
723        arrow(nat_ty(), prop()),
724    )
725}
726/// `SeeseSTheorem : MSOβ‚‚ model checking is decidable on graphs of bounded clique-width`
727pub fn seese_s_theorem_ty() -> Expr {
728    prop()
729}
730/// `CliqueWidth : Graph β†’ Nat` β€” the clique-width of a graph.
731pub fn clique_width_ty() -> Expr {
732    arrow(cst("Graph"), nat_ty())
733}
734/// `W1HardnessReduction : Problem β†’ k-Clique` β€” reduction from k-clique showing W[1]-hardness.
735pub fn w1_hardness_reduction_ty() -> Expr {
736    arrow(parameterized_problem_ty(), prop())
737}
738/// `W2HardnessReduction : Problem β†’ k-DominatingSet` β€” reduction to k-dominating set.
739pub fn w2_hardness_reduction_ty() -> Expr {
740    arrow(parameterized_problem_ty(), prop())
741}
742/// `MulticoloredCliqueW1Hard : Multicolored k-Clique is W[1]-complete`
743pub fn multicolored_clique_w1_hard_ty() -> Expr {
744    prop()
745}
746/// `kSetCoverW2Hard : k-SetCover is W[2]-complete`
747pub fn k_set_cover_w2_hard_ty() -> Expr {
748    prop()
749}
750/// `kHittingSetW2Hard : k-HittingSet is W[2]-complete`
751pub fn k_hitting_set_w2_hard_ty() -> Expr {
752    prop()
753}
754/// `WPHardnessViaCircuit : WP-hardness via weighted circuit satisfiability`
755pub fn wp_hardness_via_circuit_ty() -> Expr {
756    prop()
757}
758/// `GridRamsey : Nat β†’ Nat β†’ Prop`
759/// Grid Ramsey theorem: implications for lower bounds under ETH.
760pub fn grid_ramsey_ty() -> Expr {
761    arrow(nat_ty(), arrow(nat_ty(), prop()))
762}
763/// `ETHKVertexCoverLB : ETH β†’ VertexCover has no 2^o(k) * n algorithm`
764pub fn eth_k_vertex_cover_lb_ty() -> Expr {
765    arrow(eth_ty(), prop())
766}
767/// `ETHKFVSLowerBound : ETH β†’ FVS has no 2^o(k log k) * n algorithm`
768pub fn eth_fvs_lower_bound_ty() -> Expr {
769    arrow(eth_ty(), prop())
770}
771/// `SETHKSATLowerBound : SETH β†’ k-SAT lower bounds for each k`
772pub fn seth_ksat_lower_bound_ty() -> Expr {
773    arrow(seth_ty(), arrow(nat_ty(), prop()))
774}
775/// `ETHImpliesNoSubexpFVS : ETH implies FVS has no f(k)Β·2^o(sqrt(k)) algorithm`
776pub fn eth_implies_no_subexp_fvs_ty() -> Expr {
777    arrow(eth_ty(), prop())
778}
779/// `SETHImpliesEdgeDominatingSetLB : SETH β†’ Edge Dominating Set has tight lower bounds`
780pub fn seth_edge_dominating_set_lb_ty() -> Expr {
781    arrow(seth_ty(), prop())
782}
783/// `FPTApproximation : ParameterizedProblem β†’ Real β†’ Prop`
784/// An FPT r-approximation runs in f(k)Β·poly(n) and gives a solution within r of optimal.
785pub fn fpt_approximation_ty() -> Expr {
786    arrow(parameterized_problem_ty(), arrow(real_ty(), prop()))
787}
788/// `GapETH : Prop`
789/// Gap-ETH: there is no FPT approximation scheme for k-Clique unless Gap-ETH fails.
790pub fn gap_eth_ty() -> Expr {
791    prop()
792}
793/// `GapETHImpliesNoFPTAS : Gap-ETH β†’ no FPTAS for k-Clique`
794pub fn gap_eth_no_fptas_ty() -> Expr {
795    arrow(gap_eth_ty(), prop())
796}
797/// `EPTAS : ParameterizedProblem β†’ Prop`
798/// An EPTAS (Efficient PTAS): for each Ξ΅ > 0, runs in f(1/Ξ΅)Β·poly(n).
799pub fn eptas_ty() -> Expr {
800    arrow(parameterized_problem_ty(), prop())
801}
802/// `PTAS : ParameterizedProblem β†’ Prop`
803/// A PTAS: for each Ξ΅ > 0, runs in poly(n) (with constant depending on Ξ΅).
804pub fn ptas_ty() -> Expr {
805    arrow(parameterized_problem_ty(), prop())
806}
807/// `PlanarEPTAS : Many planar problems have EPTASes via bidimensionality`
808pub fn planar_eptas_ty() -> Expr {
809    prop()
810}
811/// `DualParameter : ParameterizedProblem β†’ Nat β†’ Prop`
812/// Dual parameterization: parameter = n - k (e.g., n - vertex cover size).
813pub fn dual_parameter_ty() -> Expr {
814    arrow(parameterized_problem_ty(), arrow(nat_ty(), prop()))
815}
816/// `AboveGuaranteeParam : ParameterizedProblem β†’ Nat β†’ Prop`
817/// Above-guarantee parameterization: k is the excess above a structural lower bound.
818pub fn above_guarantee_param_ty() -> Expr {
819    arrow(parameterized_problem_ty(), arrow(nat_ty(), prop()))
820}
821/// `StructuralParam : ParameterizedProblem β†’ Type β†’ Prop`
822/// Structural parameterization by a graph parameter (e.g., treewidth, clique-width).
823pub fn structural_param_ty() -> Expr {
824    arrow(parameterized_problem_ty(), arrow(type0(), prop()))
825}
826/// `MaxSATAboveGuarantee : Max-SAT is FPT above the n/2 guarantee`
827pub fn maxsat_above_guarantee_ty() -> Expr {
828    prop()
829}
830/// `VertexCoverAboveMMMatching : VertexCover FPT above max-matching lower bound`
831pub fn vc_above_matching_ty() -> Expr {
832    prop()
833}
834/// `CombinedParameter : ParameterizedProblem β†’ Nat β†’ Nat β†’ Prop`
835/// Combined parameterization: parameterize by both k and a structural parameter.
836pub fn combined_parameter_ty() -> Expr {
837    arrow(
838        parameterized_problem_ty(),
839        arrow(nat_ty(), arrow(nat_ty(), prop())),
840    )
841}
842/// `CountingFPT : ParameterizedProblem β†’ Prop`
843/// The counting version of an FPT problem (count solutions) is also FPT.
844pub fn counting_fpt_ty() -> Expr {
845    arrow(parameterized_problem_ty(), prop())
846}
847/// `SharpW1 : Type` β€” the class #W[1] (parameterized counting analogue of W[1]).
848pub fn sharp_w1_ty() -> Expr {
849    type0()
850}
851/// `SharpW2 : Type` β€” the class #W[2].
852pub fn sharp_w2_ty() -> Expr {
853    type0()
854}
855/// `CountingCliquesSharpW1Hard : counting k-cliques is #W[1]-complete`
856pub fn counting_cliques_sharp_w1_hard_ty() -> Expr {
857    prop()
858}
859/// `CountingMatchingsSharpW1Hard : counting perfect matchings is #W[1]-hard`
860pub fn counting_matchings_sharp_w1_hard_ty() -> Expr {
861    prop()
862}
863/// `CountingHomomorphismsSharpW1 : counting graph homomorphisms is #W[1]-complete`
864pub fn counting_homomorphisms_sharp_w1_ty() -> Expr {
865    prop()
866}
867/// `CountingOnBoundedTW : counting on bounded-treewidth graphs is FPT`
868pub fn counting_on_bounded_tw_ty() -> Expr {
869    prop()
870}
871/// `CrownReductionAxiom : Crown decomposition implies 2k-vertex kernel for VC`
872pub fn crown_reduction_axiom_ty() -> Expr {
873    prop()
874}
875/// `KoenigTheoremKernelization : KΓΆnig's theorem gives LP-based kernel`
876pub fn koenig_kernel_ty() -> Expr {
877    prop()
878}
879/// `NemhauserTrotterThm : Nemhauser-Trotter theorem for vertex cover LP kernel`
880pub fn nemhauser_trotter_ty() -> Expr {
881    prop()
882}
883/// `AboveGuaranteeParamVC : VC above matching is FPT (Razgon-O'Sullivan, Cygan et al.)`
884pub fn above_guarantee_vc_ty() -> Expr {
885    prop()
886}
887/// `MaxSNPHardnessInFPT : Max-SNP hard problems have EPTASes in FPT setting`
888pub fn max_snp_fpt_ty() -> Expr {
889    prop()
890}
891/// `MultiparamFPT : FPT algorithms using multiple parameters simultaneously`
892pub fn multiparam_fpt_ty() -> Expr {
893    arrow(nat_ty(), arrow(nat_ty(), prop()))
894}
895/// Alias for `build_parameterized_complexity_env` β€” simple entry point.
896pub fn build_env(env: &mut Environment) -> Result<(), String> {
897    build_parameterized_complexity_env(env)
898}
899/// Populate an `Environment` with parameterized complexity axioms.
900pub 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}