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, "=== {} ===", get_text("detailed_analysis", "en"))?;
98
99        output_detailed_law_results(writer, result, "en")?;
100        output_data_characteristics(writer, result, "en")?;
101        output_alternative_combinations(writer, result, "en")?;
102    }
103
104    Ok(())
105}
106
107fn output_conflict_analysis_result(
108    writer: &mut Box<dyn Write>,
109    result: &lawkit_core::laws::integration::ConflictAnalysisResult,
110    _config: &OutputConfig,
111) -> Result<()> {
112    writeln!(writer, "{}", get_text("conflict_analysis_title", "en"))?;
113    writeln!(writer)?;
114    writeln!(
115        writer,
116        "{}: {}",
117        get_text("dataset", "en"),
118        result.dataset_name
119    )?;
120    writeln!(
121        writer,
122        "{}: {:.3}",
123        get_text("threshold", "en"),
124        result.threshold
125    )?;
126    writeln!(
127        writer,
128        "{}: {:?}",
129        get_text("conflict_severity", "en"),
130        result.conflict_severity
131    )?;
132    writeln!(writer)?;
133
134    if !result.detailed_conflicts.is_empty() {
135        writeln!(writer, "{}:", get_text("detailed_conflicts", "en"))?;
136        for (i, conflict) in result.detailed_conflicts.iter().enumerate() {
137            writeln!(writer, "{}. {}", i + 1, conflict.base_conflict.description)?;
138            writeln!(
139                writer,
140                "   {}: {:.3}",
141                get_text("significance", "en"),
142                conflict.statistical_significance
143            )?;
144            writeln!(
145                writer,
146                "   {}: {:?}",
147                get_text("impact", "en"),
148                conflict.impact_assessment
149            )?;
150            writeln!(
151                writer,
152                "   {}: {}",
153                get_text("root_cause", "en"),
154                conflict.root_cause_analysis
155            )?;
156            writeln!(writer)?;
157        }
158    }
159
160    if !result.resolution_strategies.is_empty() {
161        writeln!(writer, "{}:", get_text("resolution_strategies", "en"))?;
162        for strategy in &result.resolution_strategies {
163            writeln!(
164                writer,
165                "• {} ({:?})",
166                strategy.strategy_name, strategy.priority
167            )?;
168            writeln!(
169                writer,
170                "  {}: {}",
171                get_text("expected_outcome", "en"),
172                strategy.expected_outcome
173            )?;
174            writeln!(
175                writer,
176                "  {}: {:.3}",
177                get_text("confidence", "en"),
178                strategy.confidence
179            )?;
180            writeln!(writer)?;
181        }
182    }
183
184    Ok(())
185}
186
187fn output_recommendation_result(
188    writer: &mut Box<dyn Write>,
189    result: &lawkit_core::laws::integration::DetailedRecommendationResult,
190    _config: &OutputConfig,
191) -> Result<()> {
192    writeln!(writer, "{}", get_text("recommendation_title", "en"))?;
193    writeln!(writer)?;
194    writeln!(
195        writer,
196        "{}: {}",
197        get_text("dataset", "en"),
198        result.dataset_name
199    )?;
200    writeln!(
201        writer,
202        "{}: {:?}",
203        get_text("analysis_purpose", "en"),
204        result.analysis_purpose
205    )?;
206    writeln!(writer)?;
207
208    writeln!(writer, "{}:", get_text("purpose_recommendations", "en"))?;
209    for rec in &result.purpose_specific_recommendations {
210        writeln!(
211            writer,
212            "• {:?}: {}",
213            rec.purpose,
214            rec.recommended_laws.join(", ")
215        )?;
216        writeln!(
217            writer,
218            "  {}: {}",
219            get_text("rationale", "en"),
220            rec.rationale
221        )?;
222        writeln!(
223            writer,
224            "  {}: {:.3}",
225            get_text("effectiveness", "en"),
226            rec.effectiveness
227        )?;
228        writeln!(writer)?;
229    }
230
231    if !result.combination_analysis.is_empty() {
232        writeln!(writer, "{}:", get_text("combination_analysis", "en"))?;
233        for combo in result.combination_analysis.iter().take(3) {
234            writeln!(
235                writer,
236                "• {}: {:.3}",
237                combo.laws.join(" + "),
238                combo.synergy_score
239            )?;
240        }
241        writeln!(writer)?;
242    }
243
244    Ok(())
245}
246
247fn output_detailed_law_results(
248    writer: &mut Box<dyn Write>,
249    result: &lawkit_core::laws::integration::IntegrationResult,
250    _lang: &str,
251) -> Result<()> {
252    writeln!(writer, "{}:", get_text("individual_law_results", "en"))?;
253
254    if let Some(ref benf_result) = result.benford_result {
255        writeln!(
256            writer,
257            "• {}: {:.3} ({:?})",
258            get_law_name("benf", "en"),
259            1.0 - (benf_result.mean_absolute_deviation / 100.0),
260            benf_result.risk_level
261        )?;
262    }
263
264    if let Some(ref pareto_result) = result.pareto_result {
265        writeln!(
266            writer,
267            "• {}: {:.3} ({:?})",
268            get_law_name("pareto", "en"),
269            pareto_result.concentration_index,
270            pareto_result.risk_level
271        )?;
272    }
273
274    if let Some(ref zipf_result) = result.zipf_result {
275        writeln!(
276            writer,
277            "• {}: {:.3} ({:?})",
278            get_law_name("zipf", "en"),
279            zipf_result.distribution_quality,
280            zipf_result.risk_level
281        )?;
282    }
283
284    if let Some(ref normal_result) = result.normal_result {
285        writeln!(
286            writer,
287            "• {}: {:.3} ({:?})",
288            get_law_name("normal", "en"),
289            normal_result.normality_score,
290            normal_result.risk_level
291        )?;
292    }
293
294    if let Some(ref poisson_result) = result.poisson_result {
295        writeln!(
296            writer,
297            "• {}: {:.3} ({:?})",
298            get_law_name("poisson", "en"),
299            poisson_result.goodness_of_fit_score,
300            poisson_result.risk_level
301        )?;
302    }
303
304    writeln!(writer)?;
305    Ok(())
306}
307
308fn output_data_characteristics(
309    writer: &mut Box<dyn Write>,
310    result: &lawkit_core::laws::integration::IntegrationResult,
311    _lang: &str,
312) -> Result<()> {
313    let chars = &result.data_characteristics;
314
315    writeln!(writer, "{}:", get_text("data_characteristics", "en"))?;
316    writeln!(
317        writer,
318        "  {}: {:?}",
319        get_text("data_type", "en"),
320        chars.data_type
321    )?;
322    writeln!(
323        writer,
324        "  {}: {:?}",
325        get_text("distribution_shape", "en"),
326        chars.distribution_shape
327    )?;
328    writeln!(
329        writer,
330        "  {}: {:?}",
331        get_text("outlier_presence", "en"),
332        chars.outlier_presence
333    )?;
334    writeln!(
335        writer,
336        "  {}: {:?}",
337        get_text("scale_range", "en"),
338        chars.scale_range
339    )?;
340    writeln!(
341        writer,
342        "  {}: {:?}",
343        get_text("sample_size_category", "en"),
344        chars.sample_size_category
345    )?;
346    writeln!(writer)?;
347
348    Ok(())
349}
350
351fn output_alternative_combinations(
352    writer: &mut Box<dyn Write>,
353    result: &lawkit_core::laws::integration::IntegrationResult,
354    _lang: &str,
355) -> Result<()> {
356    writeln!(writer, "{}:", get_text("alternative_combinations", "en"))?;
357
358    for combo in &result.recommendations.alternative_combinations {
359        writeln!(writer, "• {} ({})", combo.purpose, combo.laws.join(" + "))?;
360        writeln!(
361            writer,
362            "  {}: {:.3}",
363            get_text("effectiveness", "en"),
364            combo.effectiveness_score
365        )?;
366        writeln!(
367            writer,
368            "  {}: {}",
369            get_text("description", "en"),
370            combo.description
371        )?;
372        writeln!(writer)?;
373    }
374
375    Ok(())
376}
377
378fn get_text(key: &str, _lang: &str) -> String {
379    match key {
380        "detailed_analysis" => "Detailed Analysis",
381        "conflict_analysis_title" => "Conflict Analysis",
382        "threshold" => "Threshold",
383        "conflict_severity" => "Conflict Severity",
384        "detailed_conflicts" => "Detailed Conflicts",
385        "significance" => "Significance",
386        "impact" => "Impact",
387        "root_cause" => "Root Cause",
388        "resolution_strategies" => "Resolution Strategies",
389        "expected_outcome" => "Expected Outcome",
390        "confidence" => "Confidence",
391        "recommendation_title" => "Recommendations",
392        "analysis_purpose" => "Analysis Purpose",
393        "purpose_recommendations" => "Purpose-Based Recommendations",
394        "combination_analysis" => "Combination Analysis",
395        "individual_law_results" => "Individual Law Results",
396        "data_characteristics" => "Data Characteristics",
397        "data_type" => "Data Type",
398        "distribution_shape" => "Distribution Shape",
399        "outlier_presence" => "Outlier Presence",
400        "scale_range" => "Scale Range",
401        "sample_size_category" => "Sample Size Category",
402        "alternative_combinations" => "Alternative Combinations",
403        "effectiveness" => "Effectiveness",
404        "rationale" => "Rationale",
405        "dataset" => "Dataset",
406        _ => key,
407    }
408    .to_string()
409}
410
411fn get_law_name(law: &str, _lang: &str) -> String {
412    match law {
413        "benf" => "Benford's Law",
414        "pareto" => "Pareto Principle",
415        "zipf" => "Zipf's Law",
416        "normal" => "Normal Distribution",
417        "poisson" => "Poisson Distribution",
418        _ => law,
419    }
420    .to_string()
421}