impl BigOAnalyzer {
fn build_report(
&self,
functions: Vec<FunctionComplexity>,
pattern_counts: rustc_hash::FxHashMap<String, usize>,
) -> BigOAnalysisReport {
let mut distribution = ComplexityDistribution {
constant: 0,
logarithmic: 0,
linear: 0,
linearithmic: 0,
quadratic: 0,
cubic: 0,
exponential: 0,
unknown: 0,
};
let total_functions = functions.len();
for func in &functions {
Self::increment_distribution(&mut distribution, &func.time_complexity.class);
}
let mut high_complexity: Vec<_> = functions
.into_iter()
.filter(|f| {
matches!(
f.time_complexity.class,
BigOClass::Quadratic
| BigOClass::Cubic
| BigOClass::Exponential
| BigOClass::Factorial
)
})
.collect();
high_complexity.sort_by_key(|f| f.time_complexity.class as u8);
let pattern_matches: Vec<_> = pattern_counts
.into_iter()
.map(|(name, count)| PatternMatch {
pattern_name: name,
occurrences: count,
typical_complexity: BigOClass::Linear, })
.collect();
let recommendations =
Self::generate_recommendations(&distribution, total_functions);
BigOAnalysisReport {
analyzed_functions: total_functions,
complexity_distribution: distribution,
high_complexity_functions: high_complexity,
pattern_matches,
recommendations,
}
}
fn increment_distribution(distribution: &mut ComplexityDistribution, class: &BigOClass) {
match class {
BigOClass::Constant => distribution.constant += 1,
BigOClass::Logarithmic => distribution.logarithmic += 1,
BigOClass::Linear => distribution.linear += 1,
BigOClass::Linearithmic => distribution.linearithmic += 1,
BigOClass::Quadratic => distribution.quadratic += 1,
BigOClass::Cubic => distribution.cubic += 1,
BigOClass::Exponential => distribution.exponential += 1,
BigOClass::Factorial => distribution.exponential += 1,
BigOClass::Unknown => distribution.unknown += 1,
}
}
fn generate_recommendations(
distribution: &ComplexityDistribution,
total_functions: usize,
) -> Vec<String> {
let mut recommendations = Vec::new();
if distribution.quadratic > 0 {
recommendations.push(format!(
"Found {} functions with O(n^2) complexity. Consider optimization.",
distribution.quadratic
));
}
if distribution.exponential > 0 {
recommendations.push(format!(
"Found {} functions with exponential complexity! These need immediate attention.",
distribution.exponential
));
}
if distribution.unknown > total_functions / 4 {
recommendations.push(
"Many functions have unknown complexity. Consider adding more explicit patterns."
.to_string(),
);
}
recommendations
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn format_as_json(&self, report: &BigOAnalysisReport) -> Result<String> {
let json = serde_json::json!({
"summary": {
"analyzed_functions": report.analyzed_functions,
"high_complexity_count": report.high_complexity_functions.len(),
},
"distribution": {
"O(1)": report.complexity_distribution.constant,
"O(log n)": report.complexity_distribution.logarithmic,
"O(n)": report.complexity_distribution.linear,
"O(n log n)": report.complexity_distribution.linearithmic,
"O(n^2)": report.complexity_distribution.quadratic,
"O(n^3)": report.complexity_distribution.cubic,
"O(2^n)": report.complexity_distribution.exponential,
"O(?)": report.complexity_distribution.unknown,
},
"high_complexity_functions": report.high_complexity_functions.iter().map(|f| {
serde_json::json!({
"file": f.file_path.display().to_string(),
"function": f.function_name,
"line": f.line_number,
"time_complexity": f.time_complexity.notation(),
"space_complexity": f.space_complexity.notation(),
"confidence": f.confidence,
})
}).collect::<Vec<_>>(),
"pattern_matches": report.pattern_matches.iter().map(|p| {
serde_json::json!({
"pattern": p.pattern_name,
"occurrences": p.occurrences,
})
}).collect::<Vec<_>>(),
"recommendations": report.recommendations,
});
Ok(serde_json::to_string_pretty(&json)?)
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn format_as_markdown(&self, report: &BigOAnalysisReport) -> String {
let mut md = String::with_capacity(1024);
md.push_str("# Big-O Complexity Analysis Report\n\n");
md.push_str("## Summary\n\n");
md.push_str(&format!(
"- **Total Functions Analyzed**: {}\n",
report.analyzed_functions
));
md.push_str(&format!(
"- **High Complexity Functions**: {}\n\n",
report.high_complexity_functions.len()
));
Self::format_distribution_table(&mut md, report);
if !report.high_complexity_functions.is_empty() {
Self::format_high_complexity_table(&mut md, report);
}
if !report.recommendations.is_empty() {
md.push_str("## Recommendations\n\n");
for rec in &report.recommendations {
md.push_str(&format!("- {rec}\n"));
}
}
md
}
fn format_distribution_table(md: &mut String, report: &BigOAnalysisReport) {
md.push_str("## Complexity Distribution\n\n");
md.push_str("| Complexity | Count | Percentage |\n");
md.push_str("|------------|-------|------------|\n");
let total = report.analyzed_functions as f64;
let dist = &report.complexity_distribution;
let rows: &[(&str, usize)] = &[
("O(1)", dist.constant),
("O(log n)", dist.logarithmic),
("O(n)", dist.linear),
("O(n log n)", dist.linearithmic),
("O(n^2)", dist.quadratic),
("O(n^3)", dist.cubic),
("O(2^n)", dist.exponential),
("Unknown", dist.unknown),
];
for (label, count) in rows {
let suffix = if *label == "Unknown" { "\n" } else { "" };
md.push_str(&format!(
"| {} | {} | {:.1}% |{}\n",
label,
count,
(*count as f64 / total) * 100.0,
suffix
));
}
}
fn format_high_complexity_table(md: &mut String, report: &BigOAnalysisReport) {
md.push_str("## High Complexity Functions\n\n");
md.push_str(
"| File | Function | Line | Time Complexity | Space Complexity | Confidence |\n",
);
md.push_str(
"|------|----------|------|-----------------|------------------|------------|\n",
);
for func in &report.high_complexity_functions {
md.push_str(&format!(
"| {} | {} | {} | {} | {} | {}% |\n",
func.file_path
.file_name()
.unwrap_or_default()
.to_string_lossy(),
func.function_name,
func.line_number,
func.time_complexity.notation(),
func.space_complexity.notation(),
func.confidence
));
}
md.push('\n');
}
}