problemreductions/rules/
longestcommonsubsequence_maximumindependentset.rs1use crate::models::graph::MaximumIndependentSet;
14use crate::models::misc::LongestCommonSubsequence;
15use crate::reduction;
16use crate::rules::traits::{ReduceTo, ReductionResult};
17use crate::topology::SimpleGraph;
18use crate::types::One;
19
20#[derive(Debug, Clone)]
26pub struct ReductionLCSToIS {
27 target: MaximumIndependentSet<SimpleGraph, One>,
29 match_nodes: Vec<Vec<usize>>,
31 match_chars: Vec<usize>,
33 max_length: usize,
35 alphabet_size: usize,
37}
38
39impl ReductionResult for ReductionLCSToIS {
40 type Source = LongestCommonSubsequence;
41 type Target = MaximumIndependentSet<SimpleGraph, One>;
42
43 fn target_problem(&self) -> &Self::Target {
44 &self.target
45 }
46
47 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
52 let mut selected: Vec<(usize, usize)> = target_solution
54 .iter()
55 .enumerate()
56 .filter(|(_, &v)| v == 1)
57 .map(|(i, _)| (self.match_nodes[i][0], self.match_chars[i]))
58 .collect();
59 selected.sort_by_key(|&(pos, _)| pos);
61
62 let mut config = Vec::with_capacity(self.max_length);
64 for &(_, ch) in &selected {
65 config.push(ch);
66 }
67 while config.len() < self.max_length {
69 config.push(self.alphabet_size);
70 }
71 config
72 }
73}
74
75#[reduction(
76 overhead = {
77 num_vertices = "cross_frequency_product",
78 num_edges = "cross_frequency_product^2",
79 }
80)]
81impl ReduceTo<MaximumIndependentSet<SimpleGraph, One>> for LongestCommonSubsequence {
82 type Result = ReductionLCSToIS;
83
84 fn reduce_to(&self) -> Self::Result {
85 let strings = self.strings();
86 let k = self.num_strings();
87
88 let mut match_nodes: Vec<Vec<usize>> = Vec::new();
92 let mut match_chars: Vec<usize> = Vec::new();
93
94 for c in 0..self.alphabet_size() {
95 let positions_per_string: Vec<Vec<usize>> = strings
97 .iter()
98 .map(|s| {
99 s.iter()
100 .enumerate()
101 .filter(|(_, &sym)| sym == c)
102 .map(|(i, _)| i)
103 .collect()
104 })
105 .collect();
106
107 let tuples = cartesian_product(&positions_per_string);
109 for tuple in tuples {
110 match_nodes.push(tuple);
111 match_chars.push(c);
112 }
113 }
114
115 let num_vertices = match_nodes.len();
116
117 let mut edges: Vec<(usize, usize)> = Vec::new();
122
123 for i in 0..num_vertices {
124 for j in (i + 1)..num_vertices {
125 if nodes_conflict(&match_nodes[i], &match_nodes[j], k) {
126 edges.push((i, j));
127 }
128 }
129 }
130
131 let target = MaximumIndependentSet::new(
132 SimpleGraph::new(num_vertices, edges),
133 vec![One; num_vertices],
134 );
135
136 ReductionLCSToIS {
137 target,
138 match_nodes,
139 match_chars,
140 max_length: self.max_length(),
141 alphabet_size: self.alphabet_size(),
142 }
143 }
144}
145
146fn nodes_conflict(u: &[usize], v: &[usize], k: usize) -> bool {
151 let mut all_less = true;
152 let mut all_greater = true;
153 for i in 0..k {
154 if u[i] >= v[i] {
155 all_less = false;
156 }
157 if u[i] <= v[i] {
158 all_greater = false;
159 }
160 }
161 !all_less && !all_greater
162}
163
164fn cartesian_product(lists: &[Vec<usize>]) -> Vec<Vec<usize>> {
166 if lists.is_empty() {
167 return vec![vec![]];
168 }
169
170 let mut result = vec![vec![]];
171 for list in lists {
172 let mut new_result = Vec::new();
173 for prefix in &result {
174 for &item in list {
175 let mut new_tuple = prefix.clone();
176 new_tuple.push(item);
177 new_result.push(new_tuple);
178 }
179 }
180 result = new_result;
181 }
182 result
183}
184
185#[cfg(feature = "example-db")]
186pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
187 use crate::export::SolutionPair;
188
189 fn lcs_abac_baca() -> LongestCommonSubsequence {
191 LongestCommonSubsequence::new(
193 3,
194 vec![
195 vec![0, 1, 0, 2], vec![1, 0, 2, 0], ],
198 )
199 }
200
201 vec![crate::example_db::specs::RuleExampleSpec {
202 id: "longestcommonsubsequence_to_maximumindependentset",
203 build: || {
204 crate::example_db::specs::rule_example_with_witness::<
212 _,
213 MaximumIndependentSet<SimpleGraph, One>,
214 >(
215 lcs_abac_baca(),
216 SolutionPair {
217 source_config: vec![1, 0, 2, 3],
218 target_config: vec![0, 0, 1, 0, 1, 1],
219 },
220 )
221 },
222 }]
223}
224
225#[cfg(test)]
226#[path = "../unit_tests/rules/longestcommonsubsequence_maximumindependentset.rs"]
227mod tests;