Skip to main content

lawkit_python/subcommands/
diagnose.rs

1use crate::common_options;
2use crate::subcommands::integration_common::{
3    get_dataset_name, get_numbers_from_input, output_integration_result, parse_analysis_purpose,
4};
5use clap::{ArgMatches, Command};
6use lawkit_core::common::output::{create_output_writer, OutputConfig};
7use lawkit_core::error::Result;
8use lawkit_core::laws::integration::{
9    analyze_all_laws, detect_conflicts_detailed, generate_detailed_recommendations, AnalysisPurpose,
10};
11use std::io::Write;
12
13pub fn command() -> Command {
14    common_options::add_integration_options(common_options::add_common_options(
15        common_options::add_input_arg(
16            Command::new("diagnose").about("Conflict detection and detailed analysis report"),
17        ),
18    ))
19}
20
21pub fn run(matches: &ArgMatches) -> Result<()> {
22    if matches.get_flag("recommend") {
23        return run_recommendation_mode(matches);
24    }
25
26    let report_type = matches.get_one::<String>("report").unwrap();
27    match report_type.as_str() {
28        "conflicting" => run_conflict_analysis_mode(matches),
29        "detailed" => run_detailed_analysis_mode(matches),
30        _ => run_detailed_analysis_mode(matches), // Default to detailed
31    }
32}
33
34fn run_detailed_analysis_mode(matches: &ArgMatches) -> Result<()> {
35    let numbers = get_numbers_from_input(matches)?;
36    let dataset_name = get_dataset_name(matches);
37
38    let result = analyze_all_laws(&numbers, &dataset_name)?;
39
40    let mut writer = create_output_writer(matches)?;
41    let output_config = OutputConfig::from_matches(matches);
42
43    output_detailed_integration_result(&mut writer, &result, &output_config)?;
44
45    std::process::exit(result.risk_level.exit_code());
46}
47
48fn run_conflict_analysis_mode(matches: &ArgMatches) -> Result<()> {
49    let numbers = get_numbers_from_input(matches)?;
50    let dataset_name = get_dataset_name(matches);
51    let threshold = *matches.get_one::<f64>("threshold").unwrap();
52
53    let conflict_result = detect_conflicts_detailed(&numbers, &dataset_name, threshold)?;
54
55    let mut writer = create_output_writer(matches)?;
56    let output_config = OutputConfig::from_matches(matches);
57
58    output_conflict_analysis_result(&mut writer, &conflict_result, &output_config)?;
59
60    std::process::exit(conflict_result.integration_result.risk_level.exit_code());
61}
62
63fn run_recommendation_mode(matches: &ArgMatches) -> Result<()> {
64    let numbers = get_numbers_from_input(matches)?;
65    let dataset_name = get_dataset_name(matches);
66
67    let analysis_purpose = matches
68        .get_one::<String>("purpose")
69        .map(|p| parse_analysis_purpose(p))
70        .unwrap_or(AnalysisPurpose::GeneralAnalysis);
71
72    let recommendation_result =
73        generate_detailed_recommendations(&numbers, &dataset_name, analysis_purpose)?;
74
75    let mut writer = create_output_writer(matches)?;
76    let output_config = OutputConfig::from_matches(matches);
77
78    output_recommendation_result(&mut writer, &recommendation_result, &output_config)?;
79
80    std::process::exit(
81        recommendation_result
82            .integration_result
83            .risk_level
84            .exit_code(),
85    );
86}
87
88fn output_detailed_integration_result(
89    writer: &mut Box<dyn Write>,
90    result: &lawkit_core::laws::integration::IntegrationResult,
91    config: &OutputConfig,
92) -> Result<()> {
93    output_integration_result(writer, result, config)?;
94
95    if config.format == "text" {
96        writeln!(writer)?;
97        writeln!(writer, "=== Detailed Analysis ===")?;
98        writeln!(writer, "Additional analysis details would be shown here.")?;
99    }
100
101    Ok(())
102}
103
104fn output_conflict_analysis_result(
105    writer: &mut Box<dyn Write>,
106    result: &lawkit_core::laws::integration::ConflictAnalysisResult,
107    _config: &OutputConfig,
108) -> Result<()> {
109    writeln!(writer, "Conflict Analysis Results")?;
110    writeln!(writer)?;
111    writeln!(writer, "Dataset: {}", result.dataset_name)?;
112    writeln!(writer, "Threshold: {:.3}", result.threshold)?;
113    writeln!(writer, "Conflict Severity: {:?}", result.conflict_severity)?;
114    writeln!(writer)?;
115
116    if !result.detailed_conflicts.is_empty() {
117        writeln!(writer, "Detailed Conflicts:")?;
118        for (i, conflict) in result.detailed_conflicts.iter().enumerate() {
119            writeln!(writer, "{}. {}", i + 1, conflict.base_conflict.description)?;
120            writeln!(
121                writer,
122                "   Significance: {:.3}",
123                conflict.statistical_significance
124            )?;
125            writeln!(writer, "   Impact: {:?}", conflict.impact_assessment)?;
126            writeln!(writer, "   Root Cause: {}", conflict.root_cause_analysis)?;
127            writeln!(writer)?;
128        }
129    }
130
131    if !result.resolution_strategies.is_empty() {
132        writeln!(writer, "Resolution Strategies:")?;
133        for strategy in &result.resolution_strategies {
134            writeln!(
135                writer,
136                "• {} ({:?})",
137                strategy.strategy_name, strategy.priority
138            )?;
139            writeln!(writer, "  Expected Outcome: {}", strategy.expected_outcome)?;
140            writeln!(writer, "  Confidence: {:.3}", strategy.confidence)?;
141            writeln!(writer)?;
142        }
143    }
144
145    Ok(())
146}
147
148fn output_recommendation_result(
149    writer: &mut Box<dyn Write>,
150    result: &lawkit_core::laws::integration::DetailedRecommendationResult,
151    _config: &OutputConfig,
152) -> Result<()> {
153    writeln!(writer, "{}", get_text("recommendation_title", "en"))?;
154    writeln!(writer)?;
155    writeln!(
156        writer,
157        "{}: {}",
158        get_text("dataset", "en"),
159        result.dataset_name
160    )?;
161    writeln!(
162        writer,
163        "{}: {:?}",
164        get_text("analysis_purpose", "en"),
165        result.analysis_purpose
166    )?;
167    writeln!(writer)?;
168
169    writeln!(writer, "{}:", get_text("purpose_recommendations", "en"))?;
170    for rec in &result.purpose_specific_recommendations {
171        writeln!(
172            writer,
173            "• {:?}: {}",
174            rec.purpose,
175            rec.recommended_laws.join(", ")
176        )?;
177        writeln!(
178            writer,
179            "  {}: {}",
180            get_text("rationale", "en"),
181            rec.rationale
182        )?;
183        writeln!(
184            writer,
185            "  {}: {:.3}",
186            get_text("effectiveness", "en"),
187            rec.effectiveness
188        )?;
189        writeln!(writer)?;
190    }
191
192    if !result.combination_analysis.is_empty() {
193        writeln!(writer, "{}:", get_text("combination_analysis", "en"))?;
194        for combo in result.combination_analysis.iter().take(3) {
195            writeln!(
196                writer,
197                "• {}: {:.3}",
198                combo.laws.join(" + "),
199                combo.synergy_score
200            )?;
201        }
202        writeln!(writer)?;
203    }
204
205    Ok(())
206}
207
208#[allow(dead_code)]
209fn output_detailed_law_results(
210    writer: &mut Box<dyn Write>,
211    result: &lawkit_core::laws::integration::IntegrationResult,
212    _lang: &str,
213) -> Result<()> {
214    writeln!(writer, "{}:", get_text("individual_law_results", "en"))?;
215
216    if let Some(ref benf_result) = result.benford_result {
217        writeln!(
218            writer,
219            "• {}: {:.3} ({:?})",
220            get_law_name("benf", "en"),
221            1.0 - (benf_result.mean_absolute_deviation / 100.0),
222            benf_result.risk_level
223        )?;
224    }
225
226    if let Some(ref pareto_result) = result.pareto_result {
227        writeln!(
228            writer,
229            "• {}: {:.3} ({:?})",
230            get_law_name("pareto", "en"),
231            pareto_result.concentration_index,
232            pareto_result.risk_level
233        )?;
234    }
235
236    if let Some(ref zipf_result) = result.zipf_result {
237        writeln!(
238            writer,
239            "• {}: {:.3} ({:?})",
240            get_law_name("zipf", "en"),
241            zipf_result.distribution_quality,
242            zipf_result.risk_level
243        )?;
244    }
245
246    if let Some(ref normal_result) = result.normal_result {
247        writeln!(
248            writer,
249            "• {}: {:.3} ({:?})",
250            get_law_name("normal", "en"),
251            normal_result.normality_score,
252            normal_result.risk_level
253        )?;
254    }
255
256    if let Some(ref poisson_result) = result.poisson_result {
257        writeln!(
258            writer,
259            "• {}: {:.3} ({:?})",
260            get_law_name("poisson", "en"),
261            poisson_result.goodness_of_fit_score,
262            poisson_result.risk_level
263        )?;
264    }
265
266    writeln!(writer)?;
267    Ok(())
268}
269
270#[allow(dead_code)]
271fn output_data_characteristics(
272    writer: &mut Box<dyn Write>,
273    result: &lawkit_core::laws::integration::IntegrationResult,
274    _lang: &str,
275) -> Result<()> {
276    let chars = &result.data_characteristics;
277
278    writeln!(writer, "{}:", get_text("data_characteristics", "en"))?;
279    writeln!(
280        writer,
281        "  {}: {:?}",
282        get_text("data_type", "en"),
283        chars.data_type
284    )?;
285    writeln!(
286        writer,
287        "  {}: {:?}",
288        get_text("distribution_shape", "en"),
289        chars.distribution_shape
290    )?;
291    writeln!(
292        writer,
293        "  {}: {:?}",
294        get_text("outlier_presence", "en"),
295        chars.outlier_presence
296    )?;
297    writeln!(
298        writer,
299        "  {}: {:?}",
300        get_text("scale_range", "en"),
301        chars.scale_range
302    )?;
303    writeln!(
304        writer,
305        "  {}: {:?}",
306        get_text("sample_size_category", "en"),
307        chars.sample_size_category
308    )?;
309    writeln!(writer)?;
310
311    Ok(())
312}
313
314#[allow(dead_code)]
315fn output_alternative_combinations(
316    writer: &mut Box<dyn Write>,
317    result: &lawkit_core::laws::integration::IntegrationResult,
318    _lang: &str,
319) -> Result<()> {
320    writeln!(writer, "{}:", get_text("alternative_combinations", "en"))?;
321
322    for combo in &result.recommendations.alternative_combinations {
323        writeln!(writer, "• {} ({})", combo.purpose, combo.laws.join(" + "))?;
324        writeln!(
325            writer,
326            "  {}: {:.3}",
327            get_text("effectiveness", "en"),
328            combo.effectiveness_score
329        )?;
330        writeln!(
331            writer,
332            "  {}: {}",
333            get_text("description", "en"),
334            combo.description
335        )?;
336        writeln!(writer)?;
337    }
338
339    Ok(())
340}
341
342fn get_text(key: &str, _lang: &str) -> String {
343    match key {
344        "detailed_analysis" => "Detailed Analysis",
345        "conflict_analysis_title" => "Conflict Analysis",
346        "threshold" => "Threshold",
347        "conflict_severity" => "Conflict Severity",
348        "detailed_conflicts" => "Detailed Conflicts",
349        "significance" => "Significance",
350        "impact" => "Impact",
351        "root_cause" => "Root Cause",
352        "resolution_strategies" => "Resolution Strategies",
353        "expected_outcome" => "Expected Outcome",
354        "confidence" => "Confidence",
355        "recommendation_title" => "Recommendations",
356        "analysis_purpose" => "Analysis Purpose",
357        "purpose_recommendations" => "Purpose-Based Recommendations",
358        "combination_analysis" => "Combination Analysis",
359        "individual_law_results" => "Individual Law Results",
360        "data_characteristics" => "Data Characteristics",
361        "data_type" => "Data Type",
362        "distribution_shape" => "Distribution Shape",
363        "outlier_presence" => "Outlier Presence",
364        "scale_range" => "Scale Range",
365        "sample_size_category" => "Sample Size Category",
366        "alternative_combinations" => "Alternative Combinations",
367        "effectiveness" => "Effectiveness",
368        "rationale" => "Rationale",
369        "dataset" => "Dataset",
370        _ => key,
371    }
372    .to_string()
373}
374
375#[allow(dead_code)]
376fn get_law_name(law: &str, _lang: &str) -> String {
377    match law {
378        "benf" => "Benford's Law",
379        "pareto" => "Pareto Principle",
380        "zipf" => "Zipf's Law",
381        "normal" => "Normal Distribution",
382        "poisson" => "Poisson Distribution",
383        _ => law,
384    }
385    .to_string()
386}