quantrs2_tytan/solution_debugger/
comparison.rs1use super::types::{ProblemInfo, Solution};
4use serde::Serialize;
5use std::collections::HashMap;
6
7pub struct SolutionComparator {
9 metrics: Vec<ComparisonMetric>,
11 reference_solutions: Vec<Solution>,
13}
14
15#[derive(Debug, Clone, Serialize)]
16pub enum ComparisonMetric {
17 HammingDistance,
19 EnergyDifference,
21 ConstraintSatisfaction,
23 StructuralSimilarity,
25 Custom { name: String },
27}
28
29#[derive(Debug, Clone, Serialize)]
30pub struct ComparisonResult {
31 pub solution1: String,
33 pub solution2: String,
34 pub metrics: HashMap<String, f64>,
36 pub differences: Vec<Difference>,
38 pub similarity: f64,
40}
41
42#[derive(Debug, Clone, Serialize)]
43pub struct Difference {
44 pub variable: String,
46 pub value1: bool,
48 pub value2: bool,
50 pub objective_impact: f64,
52 pub constraint_impact: Vec<String>,
54}
55
56impl SolutionComparator {
57 pub fn new() -> Self {
59 Self {
60 metrics: vec![
61 ComparisonMetric::HammingDistance,
62 ComparisonMetric::EnergyDifference,
63 ComparisonMetric::ConstraintSatisfaction,
64 ComparisonMetric::StructuralSimilarity,
65 ],
66 reference_solutions: Vec::new(),
67 }
68 }
69
70 pub fn add_reference(&mut self, solution: Solution) {
72 self.reference_solutions.push(solution);
73 }
74
75 pub fn compare(
77 &self,
78 sol1: &Solution,
79 sol2: &Solution,
80 problem_info: &ProblemInfo,
81 ) -> ComparisonResult {
82 let mut metrics = HashMap::new();
83 let mut differences = Vec::new();
84
85 for metric in &self.metrics {
87 let value = match metric {
88 ComparisonMetric::HammingDistance => self.hamming_distance(sol1, sol2),
89 ComparisonMetric::EnergyDifference => (sol1.energy - sol2.energy).abs(),
90 ComparisonMetric::ConstraintSatisfaction => {
91 self.constraint_satisfaction_diff(sol1, sol2)
92 }
93 ComparisonMetric::StructuralSimilarity => self.structural_similarity(sol1, sol2),
94 ComparisonMetric::Custom { name } => self.custom_metric(sol1, sol2, name),
95 };
96 metrics.insert(self.metric_name(metric), value);
97 }
98
99 for var in sol1.assignments.keys() {
101 let val1 = sol1.assignments.get(var).copied().unwrap_or(false);
102 let val2 = sol2.assignments.get(var).copied().unwrap_or(false);
103
104 if val1 != val2 {
105 differences.push(Difference {
106 variable: var.clone(),
107 value1: val1,
108 value2: val2,
109 objective_impact: self.calculate_objective_impact(
110 var,
111 val1,
112 val2,
113 problem_info,
114 ),
115 constraint_impact: self.calculate_constraint_impact(
116 var,
117 val1,
118 val2,
119 problem_info,
120 ),
121 });
122 }
123 }
124
125 let max_distance = sol1.assignments.len() as f64;
127 let hamming_dist = metrics.get("hamming_distance").copied().unwrap_or(0.0);
128 let similarity = 1.0 - (hamming_dist / max_distance);
129
130 ComparisonResult {
131 solution1: "sol1".to_string(), solution2: "sol2".to_string(),
133 metrics,
134 differences,
135 similarity,
136 }
137 }
138
139 fn hamming_distance(&self, sol1: &Solution, sol2: &Solution) -> f64 {
141 let mut distance = 0;
142
143 for var in sol1.assignments.keys() {
144 let val1 = sol1.assignments.get(var).copied().unwrap_or(false);
145 let val2 = sol2.assignments.get(var).copied().unwrap_or(false);
146
147 if val1 != val2 {
148 distance += 1;
149 }
150 }
151
152 distance as f64
153 }
154
155 const fn constraint_satisfaction_diff(&self, _sol1: &Solution, _sol2: &Solution) -> f64 {
157 0.0
159 }
160
161 fn structural_similarity(&self, sol1: &Solution, sol2: &Solution) -> f64 {
163 let total_vars = sol1.assignments.len() as f64;
166 let same_vars = sol1
167 .assignments
168 .iter()
169 .filter(|(var, &val1)| sol2.assignments.get(*var).copied().unwrap_or(false) == val1)
170 .count() as f64;
171
172 same_vars / total_vars
173 }
174
175 const fn custom_metric(&self, _sol1: &Solution, _sol2: &Solution, _name: &str) -> f64 {
177 0.0
179 }
180
181 fn metric_name(&self, metric: &ComparisonMetric) -> String {
183 match metric {
184 ComparisonMetric::HammingDistance => "hamming_distance".to_string(),
185 ComparisonMetric::EnergyDifference => "energy_difference".to_string(),
186 ComparisonMetric::ConstraintSatisfaction => "constraint_satisfaction".to_string(),
187 ComparisonMetric::StructuralSimilarity => "structural_similarity".to_string(),
188 ComparisonMetric::Custom { name } => name.clone(),
189 }
190 }
191
192 const fn calculate_objective_impact(
194 &self,
195 _var: &str,
196 _val1: bool,
197 _val2: bool,
198 _problem_info: &ProblemInfo,
199 ) -> f64 {
200 0.0
203 }
204
205 const fn calculate_constraint_impact(
207 &self,
208 _var: &str,
209 _val1: bool,
210 _val2: bool,
211 _problem_info: &ProblemInfo,
212 ) -> Vec<String> {
213 Vec::new()
216 }
217}
218
219impl Default for SolutionComparator {
220 fn default() -> Self {
221 Self::new()
222 }
223}