problemreductions/models/graph/
kernel.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
9use crate::topology::DirectedGraph;
10use crate::traits::Problem;
11use serde::{Deserialize, Serialize};
12
13inventory::submit! {
14 ProblemSchemaEntry {
15 name: "Kernel",
16 display_name: "Kernel",
17 aliases: &[],
18 dimensions: &[],
19 category: crate::registry::ProblemCategory::Graph,
20 module_path: module_path!(),
21 description: "Does the directed graph contain a kernel (independent and absorbing vertex subset)?",
22 fields: &[
23 FieldInfo { name: "graph", type_name: "DirectedGraph", description: "The directed graph G=(V,A)" },
24 ],
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct Kernel {
58 graph: DirectedGraph,
59}
60
61impl Kernel {
62 pub fn new(graph: DirectedGraph) -> Self {
64 Self { graph }
65 }
66
67 pub fn graph(&self) -> &DirectedGraph {
69 &self.graph
70 }
71
72 pub fn num_vertices(&self) -> usize {
74 self.graph.num_vertices()
75 }
76
77 pub fn num_arcs(&self) -> usize {
79 self.graph.num_arcs()
80 }
81}
82
83impl Problem for Kernel {
84 const NAME: &'static str = "Kernel";
85 type Solution = Vec<bool>;
86 type Value = crate::types::Or;
87
88 crate::problem_parameters![("num_arcs", num_arcs), ("num_vertices", num_vertices),];
89
90 fn variant() -> Vec<(&'static str, &'static str)> {
91 crate::variant_params![]
92 }
93
94 fn evaluate(
95 &self,
96 config: &Self::Solution,
97 ) -> Result<crate::types::Or, crate::traits::EvaluationError> {
98 if config.len() != self.graph.num_vertices() {
99 return Err(crate::traits::EvaluationError::InvalidConfiguration(
100 "vertex-selection length does not match the graph".into(),
101 ));
102 }
103 Ok({
104 let n = self.graph.num_vertices();
105
106 let selected = config;
108
109 for u in 0..n {
111 if !selected[u] {
112 continue;
113 }
114 for &v in &self.graph.successors(u) {
116 if selected[v] {
117 return Ok(crate::types::Or(false));
118 }
119 }
120 }
121
122 for u in 0..n {
124 if selected[u] {
125 continue;
126 }
127 let has_arc_to_selected = self.graph.successors(u).iter().any(|&v| selected[v]);
128 if !has_arc_to_selected {
129 return Ok(crate::types::Or(false));
130 }
131 }
132
133 crate::types::Or(true)
134 })
135 }
136}
137
138impl crate::solvers::BruteForceProblem for Kernel {
139 fn dimensions(&self) -> Vec<usize> {
140 vec![2; self.graph.num_vertices()]
141 }
142}
143
144#[cfg(feature = "example-db")]
145pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
146 let graph = DirectedGraph::new(
149 5,
150 vec![(0, 1), (0, 2), (1, 3), (2, 3), (3, 4), (4, 0), (4, 1)],
151 );
152 let optimal_config = vec![true, false, false, true, false];
153 vec![crate::example_db::specs::ModelExampleSpec {
154 id: "kernel",
155 instance: Box::new(Kernel::new(graph)),
156 optimal_config: serde_json::to_value(optimal_config)
157 .expect("solution serialization must succeed"),
158 optimal_value: serde_json::json!(true),
159 }]
160}
161
162crate::declare_variants! {
163 default Kernel => "2^num_vertices",
164}
165
166crate::register_brute_force! {
167 Kernel decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
168}
169
170#[cfg(test)]
171#[path = "../../unit_tests/models/graph/kernel.rs"]
172mod tests;