quantrs2_tytan/solution_debugger/
visualization.rs1use super::types::{ProblemInfo, Solution};
4use serde::Serialize;
5use std::collections::HashMap;
6
7pub struct SolutionVisualizer {
9 options: VisualizationOptions,
11 color_schemes: HashMap<String, ColorScheme>,
13}
14
15#[derive(Debug, Clone, Serialize)]
16pub struct VisualizationOptions {
17 pub show_values: bool,
19 pub show_energy: bool,
21 pub show_violations: bool,
23 pub show_relationships: bool,
25 pub layout: LayoutAlgorithm,
27}
28
29#[derive(Debug, Clone, Serialize)]
30pub enum LayoutAlgorithm {
31 Grid,
33 Circular,
35 ForceDirected,
37 Hierarchical,
39 Custom,
41}
42
43#[derive(Debug, Clone, Serialize)]
44pub struct ColorScheme {
45 pub variable_colors: HashMap<bool, String>,
47 pub constraint_colors: HashMap<String, String>,
49 pub energy_gradient: Vec<String>,
51}
52
53#[derive(Debug, Clone, Serialize)]
54pub struct Visualization {
55 pub viz_type: VisualizationType,
57 pub title: String,
59 pub data: VisualizationData,
61 pub options: VisualizationOptions,
63}
64
65#[derive(Debug, Clone, Serialize)]
66pub enum VisualizationType {
67 SolutionMatrix,
69 EnergyLandscape,
71 ConstraintGraph,
73 InteractionGraph,
75 EnergyBreakdown,
77}
78
79#[derive(Debug, Clone, Serialize)]
80pub struct VisualizationData {
81 pub nodes: Vec<Node>,
83 pub edges: Vec<Edge>,
85 pub metadata: HashMap<String, serde_json::Value>,
87}
88
89#[derive(Debug, Clone, Serialize)]
90pub struct Node {
91 pub id: String,
93 pub label: String,
95 pub node_type: String,
97 pub position: Option<(f64, f64)>,
99 pub size: f64,
101 pub color: String,
103 pub properties: HashMap<String, serde_json::Value>,
105}
106
107#[derive(Debug, Clone, Serialize)]
108pub struct Edge {
109 pub source: String,
111 pub target: String,
113 pub edge_type: String,
115 pub weight: f64,
117 pub color: String,
119 pub properties: HashMap<String, serde_json::Value>,
121}
122
123impl SolutionVisualizer {
124 pub fn new() -> Self {
126 let mut color_schemes = HashMap::new();
127
128 let mut default_scheme = ColorScheme {
130 variable_colors: HashMap::new(),
131 constraint_colors: HashMap::new(),
132 energy_gradient: vec![
133 "#FF0000".to_string(), "#FFFF00".to_string(), "#00FF00".to_string(), ],
137 };
138 default_scheme
139 .variable_colors
140 .insert(true, "#0066CC".to_string());
141 default_scheme
142 .variable_colors
143 .insert(false, "#CCCCCC".to_string());
144 color_schemes.insert("default".to_string(), default_scheme);
145
146 Self {
147 options: VisualizationOptions::default(),
148 color_schemes,
149 }
150 }
151
152 pub fn visualize_solution_matrix(
154 &self,
155 solution: &Solution,
156 problem_info: &ProblemInfo,
157 ) -> Visualization {
158 let mut nodes = Vec::new();
159 let mut edges = Vec::new();
160
161 for (var, &value) in &solution.assignments {
163 let color = if value {
164 self.color_schemes["default"].variable_colors[&true].clone()
165 } else {
166 self.color_schemes["default"].variable_colors[&false].clone()
167 };
168
169 nodes.push(Node {
170 id: var.clone(),
171 label: format!("{}: {}", var, if value { "1" } else { "0" }),
172 node_type: "variable".to_string(),
173 position: None,
174 size: 1.0,
175 color,
176 properties: HashMap::new(),
177 });
178 }
179
180 for i in 0..problem_info.qubo.nrows() {
182 for j in i + 1..problem_info.qubo.ncols() {
183 if problem_info.qubo[[i, j]].abs() > 1e-10 {
184 if let (Some(var1), Some(var2)) = (
185 problem_info.reverse_var_map.get(&i),
186 problem_info.reverse_var_map.get(&j),
187 ) {
188 edges.push(Edge {
189 source: var1.clone(),
190 target: var2.clone(),
191 edge_type: "interaction".to_string(),
192 weight: problem_info.qubo[[i, j]].abs(),
193 color: if problem_info.qubo[[i, j]] > 0.0 {
194 "#FF0000".to_string()
195 } else {
196 "#0000FF".to_string()
197 },
198 properties: HashMap::new(),
199 });
200 }
201 }
202 }
203 }
204
205 Visualization {
206 viz_type: VisualizationType::SolutionMatrix,
207 title: "Solution Variable Matrix".to_string(),
208 data: VisualizationData {
209 nodes,
210 edges,
211 metadata: HashMap::new(),
212 },
213 options: self.options.clone(),
214 }
215 }
216
217 pub fn visualize_energy_landscape(
219 &self,
220 solution: &Solution,
221 _problem_info: &ProblemInfo,
222 ) -> Visualization {
223 let mut nodes = Vec::new();
224 let edges = Vec::new();
225
226 nodes.push(Node {
228 id: "current".to_string(),
229 label: format!("Current Solution (E={:.2})", solution.energy),
230 node_type: "solution".to_string(),
231 position: Some((0.0, 0.0)),
232 size: 2.0,
233 color: "#FF0000".to_string(),
234 properties: HashMap::new(),
235 });
236
237 Visualization {
241 viz_type: VisualizationType::EnergyLandscape,
242 title: "Energy Landscape".to_string(),
243 data: VisualizationData {
244 nodes,
245 edges,
246 metadata: HashMap::new(),
247 },
248 options: self.options.clone(),
249 }
250 }
251
252 pub fn visualize_constraint_graph(
254 &self,
255 solution: &Solution,
256 problem_info: &ProblemInfo,
257 ) -> Visualization {
258 let mut nodes = Vec::new();
259 let mut edges = Vec::new();
260
261 for (var, &value) in &solution.assignments {
263 let color = if value {
264 self.color_schemes["default"].variable_colors[&true].clone()
265 } else {
266 self.color_schemes["default"].variable_colors[&false].clone()
267 };
268
269 nodes.push(Node {
270 id: var.clone(),
271 label: var.clone(),
272 node_type: "variable".to_string(),
273 position: None,
274 size: 1.0,
275 color,
276 properties: HashMap::new(),
277 });
278 }
279
280 for (i, constraint) in problem_info.constraints.iter().enumerate() {
282 let constraint_id = format!("constraint_{i}");
283 nodes.push(Node {
284 id: constraint_id.clone(),
285 label: constraint.name.as_ref().unwrap_or(&constraint_id).clone(),
286 node_type: "constraint".to_string(),
287 position: None,
288 size: 1.5,
289 color: "#FFAA00".to_string(),
290 properties: HashMap::new(),
291 });
292
293 for var in &constraint.variables {
295 edges.push(Edge {
296 source: constraint_id.clone(),
297 target: var.clone(),
298 edge_type: "constrains".to_string(),
299 weight: 1.0,
300 color: "#888888".to_string(),
301 properties: HashMap::new(),
302 });
303 }
304 }
305
306 Visualization {
307 viz_type: VisualizationType::ConstraintGraph,
308 title: "Constraint Graph".to_string(),
309 data: VisualizationData {
310 nodes,
311 edges,
312 metadata: HashMap::new(),
313 },
314 options: self.options.clone(),
315 }
316 }
317}
318
319impl Default for VisualizationOptions {
320 fn default() -> Self {
321 Self {
322 show_values: true,
323 show_energy: true,
324 show_violations: true,
325 show_relationships: true,
326 layout: LayoutAlgorithm::ForceDirected,
327 }
328 }
329}
330
331impl Default for SolutionVisualizer {
332 fn default() -> Self {
333 Self::new()
334 }
335}