quantrs2_tytan/solution_debugger/
reporting.rs

1//! Reporting functionality for the solution debugger.
2
3use super::analysis::{ConstraintAnalysis, EnergyAnalysis};
4use super::comparison::ComparisonResult;
5use super::types::Solution;
6use super::visualization::Visualization;
7use serde::Serialize;
8
9/// Debug report
10#[derive(Debug, Clone, Serialize)]
11pub struct DebugReport {
12    /// Solution being debugged
13    pub solution: Solution,
14    /// Constraint analysis results
15    pub constraint_analysis: Option<ConstraintAnalysis>,
16    /// Energy analysis results
17    pub energy_analysis: Option<EnergyAnalysis>,
18    /// Comparison results
19    pub comparison_results: Vec<ComparisonResult>,
20    /// Generated visualizations
21    pub visualizations: Vec<Visualization>,
22    /// Identified issues
23    pub issues: Vec<Issue>,
24    /// Suggested improvements
25    pub suggestions: Vec<Suggestion>,
26    /// Summary
27    pub summary: DebugSummary,
28}
29
30/// Debug summary
31#[derive(Debug, Clone, Serialize)]
32pub struct DebugSummary {
33    /// Overall solution score (0.0 to 1.0)
34    pub overall_score: f64,
35    /// Total energy
36    pub total_energy: f64,
37    /// Constraint satisfaction rate
38    pub constraint_satisfaction_rate: f64,
39    /// Number of issues found
40    pub total_issues: usize,
41    /// Number of critical issues
42    pub critical_issues: usize,
43    /// Number of suggestions
44    pub suggestions_count: usize,
45    /// Improvement potential (0.0 to 1.0)
46    pub improvement_potential: f64,
47    /// Analysis timestamp
48    pub timestamp: String,
49}
50
51/// Issue identified in solution
52#[derive(Debug, Clone, Serialize)]
53pub struct Issue {
54    /// Issue severity
55    pub severity: IssueSeverity,
56    /// Issue category
57    pub category: String,
58    /// Issue description
59    pub description: String,
60    /// Location where issue was found
61    pub location: String,
62    /// Suggested action to fix
63    pub suggested_action: String,
64}
65
66#[derive(Debug, Clone, Serialize)]
67pub enum IssueSeverity {
68    /// Critical issue that prevents solution validity
69    Critical,
70    /// High priority issue
71    High,
72    /// Medium priority issue
73    Medium,
74    /// Low priority issue
75    Low,
76    /// Informational
77    Info,
78}
79
80/// Suggestion for improvement
81#[derive(Debug, Clone, Serialize)]
82pub struct Suggestion {
83    /// Suggestion category
84    pub category: String,
85    /// Description of suggestion
86    pub description: String,
87    /// Expected impact (higher is better)
88    pub impact: f64,
89    /// Feasibility of implementing (0.0 to 1.0)
90    pub feasibility: f64,
91    /// Specific action steps
92    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    /// Generate text summary of the debug report
112    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        // Add constraint analysis
139        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        // Add energy analysis
154        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        // Add issues
179        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        // Add suggestions
194        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    /// Generate JSON report
213    pub fn to_json(&self) -> Result<String, serde_json::Error> {
214        serde_json::to_string_pretty(self)
215    }
216
217    /// Save report to file
218    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    /// Generate HTML report
238    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        // Summary section
258        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        // Issues section
275        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        // Suggestions section
293        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    /// Generate Markdown report
312    fn generate_markdown_report(&self) -> String {
313        let mut md = String::new();
314
315        md.push_str("# Solution Debug Report\n\n");
316
317        // Summary
318        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        // Issues
345        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        // Suggestions
363        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}