quantrs2_tytan/solution_debugger/
reporting.rs1use super::analysis::{ConstraintAnalysis, EnergyAnalysis};
4use super::comparison::ComparisonResult;
5use super::types::Solution;
6use super::visualization::Visualization;
7use serde::Serialize;
8
9#[derive(Debug, Clone, Serialize)]
11pub struct DebugReport {
12 pub solution: Solution,
14 pub constraint_analysis: Option<ConstraintAnalysis>,
16 pub energy_analysis: Option<EnergyAnalysis>,
18 pub comparison_results: Vec<ComparisonResult>,
20 pub visualizations: Vec<Visualization>,
22 pub issues: Vec<Issue>,
24 pub suggestions: Vec<Suggestion>,
26 pub summary: DebugSummary,
28}
29
30#[derive(Debug, Clone, Serialize)]
32pub struct DebugSummary {
33 pub overall_score: f64,
35 pub total_energy: f64,
37 pub constraint_satisfaction_rate: f64,
39 pub total_issues: usize,
41 pub critical_issues: usize,
43 pub suggestions_count: usize,
45 pub improvement_potential: f64,
47 pub timestamp: String,
49}
50
51#[derive(Debug, Clone, Serialize)]
53pub struct Issue {
54 pub severity: IssueSeverity,
56 pub category: String,
58 pub description: String,
60 pub location: String,
62 pub suggested_action: String,
64}
65
66#[derive(Debug, Clone, Serialize)]
67pub enum IssueSeverity {
68 Critical,
70 High,
72 Medium,
74 Low,
76 Info,
78}
79
80#[derive(Debug, Clone, Serialize)]
82pub struct Suggestion {
83 pub category: String,
85 pub description: String,
87 pub impact: f64,
89 pub feasibility: f64,
91 pub action_steps: Vec<String>,
93}
94
95impl Default for DebugSummary {
96 fn default() -> Self {
97 Self {
98 overall_score: 0.0,
99 total_energy: 0.0,
100 constraint_satisfaction_rate: 0.0,
101 total_issues: 0,
102 critical_issues: 0,
103 suggestions_count: 0,
104 improvement_potential: 0.0,
105 timestamp: chrono::Utc::now().to_rfc3339(),
106 }
107 }
108}
109
110impl DebugReport {
111 pub fn generate_text_summary(&self) -> String {
113 let mut summary = String::new();
114
115 summary.push_str("=== Solution Debug Report ===\n");
116 summary.push_str(&format!(
117 "Overall Score: {:.2}\n",
118 self.summary.overall_score
119 ));
120 summary.push_str(&format!("Total Energy: {:.4}\n", self.summary.total_energy));
121 summary.push_str(&format!(
122 "Constraint Satisfaction: {:.1}%\n",
123 self.summary.constraint_satisfaction_rate * 100.0
124 ));
125 summary.push_str(&format!(
126 "Issues Found: {} (Critical: {})\n",
127 self.summary.total_issues, self.summary.critical_issues
128 ));
129 summary.push_str(&format!(
130 "Suggestions: {}\n",
131 self.summary.suggestions_count
132 ));
133 summary.push_str(&format!(
134 "Improvement Potential: {:.1}%\n\n",
135 self.summary.improvement_potential * 100.0
136 ));
137
138 if let Some(ref constraint_analysis) = self.constraint_analysis {
140 summary.push_str("=== Constraint Analysis ===\n");
141 summary.push_str(&format!(
142 "Total Constraints: {}\n",
143 constraint_analysis.total_constraints
144 ));
145 summary.push_str(&format!("Satisfied: {}\n", constraint_analysis.satisfied));
146 summary.push_str(&format!("Violated: {}\n", constraint_analysis.violated));
147 summary.push_str(&format!(
148 "Penalty Incurred: {:.4}\n\n",
149 constraint_analysis.penalty_incurred
150 ));
151 }
152
153 if let Some(ref energy_analysis) = self.energy_analysis {
155 summary.push_str("=== Energy Analysis ===\n");
156 summary.push_str(&format!(
157 "Total Energy: {:.4}\n",
158 energy_analysis.total_energy
159 ));
160 summary.push_str(&format!(
161 "Linear Terms: {:.4}\n",
162 energy_analysis.breakdown.linear_terms
163 ));
164 summary.push_str(&format!(
165 "Quadratic Terms: {:.4}\n",
166 energy_analysis.breakdown.quadratic_terms
167 ));
168 summary.push_str(&format!(
169 "Critical Variables: {}\n",
170 energy_analysis.critical_variables.len()
171 ));
172 summary.push_str(&format!(
173 "Critical Interactions: {}\n\n",
174 energy_analysis.critical_interactions.len()
175 ));
176 }
177
178 if !self.issues.is_empty() {
180 summary.push_str("=== Issues Found ===\n");
181 for (i, issue) in self.issues.iter().enumerate() {
182 summary.push_str(&format!(
183 "{}. [{:?}] {}: {}\n",
184 i + 1,
185 issue.severity,
186 issue.category,
187 issue.description
188 ));
189 }
190 summary.push('\n');
191 }
192
193 if !self.suggestions.is_empty() {
195 summary.push_str("=== Suggestions ===\n");
196 for (i, suggestion) in self.suggestions.iter().enumerate() {
197 summary.push_str(&format!(
198 "{}. {}: {} (Impact: {:.2}, Feasibility: {:.2})\n",
199 i + 1,
200 suggestion.category,
201 suggestion.description,
202 suggestion.impact,
203 suggestion.feasibility
204 ));
205 }
206 summary.push('\n');
207 }
208
209 summary
210 }
211
212 pub fn to_json(&self) -> Result<String, serde_json::Error> {
214 serde_json::to_string_pretty(self)
215 }
216
217 pub fn save_to_file(
219 &self,
220 filename: &str,
221 format: &super::config::DebugOutputFormat,
222 ) -> Result<(), Box<dyn std::error::Error>> {
223 use std::io::Write;
224
225 let content = match format {
226 super::config::DebugOutputFormat::Json => self.to_json()?,
227 super::config::DebugOutputFormat::Console => self.generate_text_summary(),
228 super::config::DebugOutputFormat::Html => self.generate_html_report(),
229 super::config::DebugOutputFormat::Markdown => self.generate_markdown_report(),
230 };
231
232 let mut file = std::fs::File::create(filename)?;
233 file.write_all(content.as_bytes())?;
234 Ok(())
235 }
236
237 fn generate_html_report(&self) -> String {
239 let mut html = String::new();
240
241 html.push_str("<!DOCTYPE html>\n<html>\n<head>\n");
242 html.push_str("<title>Solution Debug Report</title>\n");
243 html.push_str("<style>\n");
244 html.push_str("body { font-family: Arial, sans-serif; margin: 20px; }\n");
245 html.push_str(".summary { background: #f0f0f0; padding: 10px; border-radius: 5px; }\n");
246 html.push_str(
247 ".issue { margin: 10px 0; padding: 10px; border-left: 4px solid #ff0000; }\n",
248 );
249 html.push_str(
250 ".suggestion { margin: 10px 0; padding: 10px; border-left: 4px solid #00aa00; }\n",
251 );
252 html.push_str("</style>\n");
253 html.push_str("</head>\n<body>\n");
254
255 html.push_str("<h1>Solution Debug Report</h1>\n");
256
257 html.push_str("<div class='summary'>\n");
259 html.push_str("<h2>Summary</h2>\n");
260 html.push_str(&format!(
261 "<p><strong>Overall Score:</strong> {:.2}</p>\n",
262 self.summary.overall_score
263 ));
264 html.push_str(&format!(
265 "<p><strong>Total Energy:</strong> {:.4}</p>\n",
266 self.summary.total_energy
267 ));
268 html.push_str(&format!(
269 "<p><strong>Constraint Satisfaction:</strong> {:.1}%</p>\n",
270 self.summary.constraint_satisfaction_rate * 100.0
271 ));
272 html.push_str("</div>\n");
273
274 if !self.issues.is_empty() {
276 html.push_str("<h2>Issues</h2>\n");
277 for issue in &self.issues {
278 html.push_str("<div class='issue'>\n");
279 html.push_str(&format!(
280 "<h3>{:?}: {}</h3>\n",
281 issue.severity, issue.category
282 ));
283 html.push_str(&format!("<p>{}</p>\n", issue.description));
284 html.push_str(&format!(
285 "<p><em>Suggested Action:</em> {}</p>\n",
286 issue.suggested_action
287 ));
288 html.push_str("</div>\n");
289 }
290 }
291
292 if !self.suggestions.is_empty() {
294 html.push_str("<h2>Suggestions</h2>\n");
295 for suggestion in &self.suggestions {
296 html.push_str("<div class='suggestion'>\n");
297 html.push_str(&format!("<h3>{}</h3>\n", suggestion.category));
298 html.push_str(&format!("<p>{}</p>\n", suggestion.description));
299 html.push_str(&format!(
300 "<p><em>Impact:</em> {:.2}, <em>Feasibility:</em> {:.2}</p>\n",
301 suggestion.impact, suggestion.feasibility
302 ));
303 html.push_str("</div>\n");
304 }
305 }
306
307 html.push_str("</body>\n</html>");
308 html
309 }
310
311 fn generate_markdown_report(&self) -> String {
313 let mut md = String::new();
314
315 md.push_str("# Solution Debug Report\n\n");
316
317 md.push_str("## Summary\n\n");
319 md.push_str(&format!(
320 "- **Overall Score:** {:.2}\n",
321 self.summary.overall_score
322 ));
323 md.push_str(&format!(
324 "- **Total Energy:** {:.4}\n",
325 self.summary.total_energy
326 ));
327 md.push_str(&format!(
328 "- **Constraint Satisfaction:** {:.1}%\n",
329 self.summary.constraint_satisfaction_rate * 100.0
330 ));
331 md.push_str(&format!(
332 "- **Issues Found:** {} (Critical: {})\n",
333 self.summary.total_issues, self.summary.critical_issues
334 ));
335 md.push_str(&format!(
336 "- **Suggestions:** {}\n",
337 self.summary.suggestions_count
338 ));
339 md.push_str(&format!(
340 "- **Improvement Potential:** {:.1}%\n\n",
341 self.summary.improvement_potential * 100.0
342 ));
343
344 if !self.issues.is_empty() {
346 md.push_str("## Issues\n\n");
347 for (i, issue) in self.issues.iter().enumerate() {
348 md.push_str(&format!(
349 "### {}. [{:?}] {}\n\n",
350 i + 1,
351 issue.severity,
352 issue.category
353 ));
354 md.push_str(&format!("{}\n\n", issue.description));
355 md.push_str(&format!(
356 "**Suggested Action:** {}\n\n",
357 issue.suggested_action
358 ));
359 }
360 }
361
362 if !self.suggestions.is_empty() {
364 md.push_str("## Suggestions\n\n");
365 for (i, suggestion) in self.suggestions.iter().enumerate() {
366 md.push_str(&format!("### {}. {}\n\n", i + 1, suggestion.category));
367 md.push_str(&format!("{}\n\n", suggestion.description));
368 md.push_str(&format!("- **Impact:** {:.2}\n", suggestion.impact));
369 md.push_str(&format!(
370 "- **Feasibility:** {:.2}\n\n",
371 suggestion.feasibility
372 ));
373 }
374 }
375
376 md
377 }
378}