use super::{
find_optimal_coefficients_for_metrics_parallel, BruteForceComparisonMetrics, BruteForceConfig,
OptimizationResult,
};
use crate::results::analysis_results::AnalysisResults;
#[derive(Debug, Clone, Copy)]
pub struct SplitComparisonOptimizationResult {
pub group_1: OptimizationResult,
pub group_2: OptimizationResult,
}
pub fn find_optimal_split_result_coefficients(
individual_results: &mut [AnalysisResults],
config: Option<&BruteForceConfig>,
) -> Vec<(String, SplitComparisonOptimizationResult)> {
let default_config = BruteForceConfig::default();
let config = config.unwrap_or(&default_config);
let mut results: Vec<(String, SplitComparisonOptimizationResult)> = Vec::new();
for (comparison_idx, comparison) in individual_results[0].split_comparisons.iter().enumerate() {
results.push((
comparison.name.clone(),
find_optimal_split_result_coefficients_for_comparison(
comparison_idx,
config,
individual_results,
),
));
}
results
}
fn find_optimal_split_result_coefficients_for_comparison(
comparison_idx: usize,
config: &BruteForceConfig,
original_results: &[AnalysisResults], ) -> SplitComparisonOptimizationResult {
let group1_metrics = extract_group1_metrics(comparison_idx, original_results);
let group1_best = find_optimal_coefficients_for_metrics_parallel(&group1_metrics, config);
let group2_metrics = extract_group2_metrics(comparison_idx, original_results);
let group2_best = find_optimal_coefficients_for_metrics_parallel(&group2_metrics, config);
SplitComparisonOptimizationResult {
group_1: group1_best,
group_2: group2_best,
}
}
fn extract_group1_metrics(
comparison_idx: usize,
original_results: &[AnalysisResults], ) -> Box<[BruteForceComparisonMetrics]> {
original_results
.iter()
.map(|result| {
result.split_comparisons[comparison_idx]
.group1_metrics
.into()
})
.collect()
}
fn extract_group2_metrics(
comparison_idx: usize,
original_results: &[AnalysisResults], ) -> Box<[BruteForceComparisonMetrics]> {
original_results
.iter()
.map(|result| {
result.split_comparisons[comparison_idx]
.group2_metrics
.into()
})
.collect()
}
pub fn print_optimization_results<W: std::io::Write>(
writer: &mut W,
results: &[(String, SplitComparisonOptimizationResult)],
) -> std::io::Result<()> {
writeln!(
writer,
"=== Split Comparison Parameter Optimization Results ==="
)?;
writeln!(
writer,
"Comparison Name | Group | LZ Multiplier | Entropy Multiplier |"
)?;
writeln!(
writer,
"------------------------------|-------|---------------|--------------------|"
)?;
for (name, result) in results {
writeln!(
writer,
"{:<30}|{:<7}|{:<15.4}|{:<20.4}|",
name, "G1", result.group_1.lz_match_multiplier, result.group_1.entropy_multiplier
)?;
writeln!(
writer,
"{:<30}|{:<7}|{:<15.4}|{:<20.4}|",
"", "G2", result.group_2.lz_match_multiplier, result.group_2.entropy_multiplier
)?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
brute_force::calculate_error_for_bruteforce_metrics,
comparison::{
split_comparison::SplitComparisonResult, GroupComparisonMetrics, GroupDifference,
},
results::analysis_results::AnalysisResults,
};
#[allow(clippy::too_many_arguments)]
fn create_mock_analysis_results(
group1_lz_matches: u64,
group1_entropy: f64,
group1_zstd_size: u64,
group1_original_size: u64,
group2_lz_matches: u64,
group2_entropy: f64,
group2_zstd_size: u64,
group2_original_size: u64,
) -> AnalysisResults {
let group1_metrics = GroupComparisonMetrics {
lz_matches: group1_lz_matches,
entropy: group1_entropy,
estimated_size: 0, zstd_size: group1_zstd_size,
original_size: group1_original_size,
};
let group2_metrics = GroupComparisonMetrics {
lz_matches: group2_lz_matches,
entropy: group2_entropy,
estimated_size: 0, zstd_size: group2_zstd_size,
original_size: group2_original_size,
};
let difference = GroupDifference::from_metrics(&group1_metrics, &group2_metrics);
let split_comparison = SplitComparisonResult {
name: "test_comparison".to_string(),
description: "Test comparison for optimization".to_string(),
group1_metrics,
group2_metrics,
difference,
baseline_comparison_metrics: vec![],
split_comparison_metrics: vec![],
};
AnalysisResults {
split_comparisons: vec![split_comparison],
..Default::default()
}
}
#[test]
fn can_find_optimal_split_result_coefficients() {
let config = BruteForceConfig::default();
let results1 = create_mock_analysis_results(
100, 1.0, 110, 1000, 200, 1.5, 220, 1000, );
let results2 = create_mock_analysis_results(
110, 1.1, 120, 1000, 210, 1.6, 230, 1000, );
let original_results = vec![results1, results2];
let result = find_optimal_split_result_coefficients_for_comparison(
0, &config,
&original_results,
);
assert!(result.group_1.lz_match_multiplier >= config.min_lz_multiplier);
assert!(result.group_1.lz_match_multiplier <= config.max_lz_multiplier);
assert!(result.group_1.entropy_multiplier >= config.min_entropy_multiplier);
assert!(result.group_1.entropy_multiplier <= config.max_entropy_multiplier);
assert!(result.group_2.lz_match_multiplier >= config.min_lz_multiplier);
assert!(result.group_2.lz_match_multiplier <= config.max_lz_multiplier);
assert!(result.group_2.entropy_multiplier >= config.min_entropy_multiplier);
assert!(result.group_2.entropy_multiplier <= config.max_entropy_multiplier);
let group1_metrics = extract_group1_metrics(0, &original_results);
let group1_error = calculate_error_for_bruteforce_metrics(
&group1_metrics,
result.group_1.lz_match_multiplier,
result.group_1.entropy_multiplier,
);
assert!(group1_error < 5.0);
let group2_metrics = extract_group2_metrics(0, &original_results);
let group2_error = calculate_error_for_bruteforce_metrics(
&group2_metrics,
result.group_2.lz_match_multiplier,
result.group_2.entropy_multiplier,
);
assert!(group2_error < 5.0);
}
#[test]
fn handles_empty_split_results() {
let config = BruteForceConfig::default();
let empty_results: Vec<AnalysisResults> = vec![];
let result =
find_optimal_split_result_coefficients_for_comparison(0, &config, &empty_results);
assert_eq!(result.group_1.lz_match_multiplier, config.min_lz_multiplier);
assert_eq!(
result.group_1.entropy_multiplier,
config.min_entropy_multiplier
);
assert_eq!(result.group_2.lz_match_multiplier, config.min_lz_multiplier);
assert_eq!(
result.group_2.entropy_multiplier,
config.min_entropy_multiplier
);
}
}