problemreductions/rules/traits.rs
1//! Core traits for problem reductions.
2
3use crate::traits::Problem;
4use std::any::Any;
5use std::marker::PhantomData;
6
7/// Result of reducing a source problem to a target problem.
8///
9/// This trait encapsulates the target problem and provides methods
10/// to extract solutions back to the source problem space.
11pub trait ReductionResult {
12 /// The source problem type.
13 type Source: Problem;
14 /// The target problem type.
15 type Target: Problem;
16
17 /// Get a reference to the target problem.
18 fn target_problem(&self) -> &Self::Target;
19
20 /// Extract a solution from target problem space to source problem space.
21 ///
22 /// # Arguments
23 /// * `target_solution` - A solution to the target problem
24 ///
25 /// # Returns
26 /// The corresponding solution in the source problem space
27 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize>;
28}
29
30/// Trait for problems that can be reduced to target type T.
31///
32/// # Example
33/// ```text
34/// // Example showing reduction workflow
35/// use problemreductions::prelude::*;
36/// use problemreductions::rules::ReduceTo;
37///
38/// let sat_problem: Satisfiability = Satisfiability::new(
39/// 3, // 3 variables
40/// vec![
41/// CNFClause::new(vec![0, 1]), // (x0 OR x1)
42/// CNFClause::new(vec![1, 2]), // (x1 OR x2)
43/// ]
44/// );
45///
46/// // Reduce to Independent Set
47/// let reduction = sat_problem.reduce_to();
48/// let is_problem = reduction.target_problem();
49///
50/// // Solve and extract solutions
51/// let solver = BruteForce::new();
52/// let solutions = solver.find_all_best(is_problem);
53/// let sat_solutions: Vec<_> = solutions.iter()
54/// .map(|s| reduction.extract_solution(s))
55/// .collect();
56/// ```
57pub trait ReduceTo<T: Problem>: Problem {
58 /// The reduction result type.
59 type Result: ReductionResult<Source = Self, Target = T>;
60
61 /// Reduce this problem to the target problem type.
62 fn reduce_to(&self) -> Self::Result;
63}
64
65/// Generic reduction result for natural-edge (subtype) reductions.
66///
67/// Used when a problem on a specific graph type is trivially reducible to
68/// the same problem on a more general graph type (e.g., `MIS<Triangular>` →
69/// `MIS<SimpleGraph>`). The solution mapping is identity — vertex indices
70/// are preserved.
71#[derive(Debug, Clone)]
72pub struct ReductionAutoCast<S: Problem, T: Problem> {
73 target: T,
74 _phantom: PhantomData<S>,
75}
76
77impl<S: Problem, T: Problem> ReductionAutoCast<S, T> {
78 /// Create a new auto-cast reduction result.
79 pub fn new(target: T) -> Self {
80 Self {
81 target,
82 _phantom: PhantomData,
83 }
84 }
85}
86
87impl<S: Problem, T: Problem> ReductionResult for ReductionAutoCast<S, T> {
88 type Source = S;
89 type Target = T;
90
91 fn target_problem(&self) -> &Self::Target {
92 &self.target
93 }
94
95 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
96 target_solution.to_vec()
97 }
98}
99
100/// Type-erased reduction result for runtime-discovered paths.
101///
102/// Implemented automatically for all `ReductionResult` types via blanket impl.
103/// Used internally by `ReductionChain`.
104pub trait DynReductionResult {
105 /// Get the target problem as a type-erased reference.
106 fn target_problem_any(&self) -> &dyn Any;
107 /// Extract a solution from target space to source space.
108 fn extract_solution_dyn(&self, target_solution: &[usize]) -> Vec<usize>;
109}
110
111impl<R: ReductionResult + 'static> DynReductionResult for R
112where
113 R::Target: 'static,
114{
115 fn target_problem_any(&self) -> &dyn Any {
116 self.target_problem() as &dyn Any
117 }
118 fn extract_solution_dyn(&self, target_solution: &[usize]) -> Vec<usize> {
119 self.extract_solution(target_solution)
120 }
121}
122
123#[cfg(test)]
124#[path = "../unit_tests/rules/traits.rs"]
125mod tests;