lawkit_python/subcommands/
integration_common.rs

1use crate::colors;
2use crate::common_options::{get_optimized_reader, setup_automatic_optimization_config};
3use chrono;
4use clap::ArgMatches;
5use lawkit_core::common::output::OutputConfig;
6use lawkit_core::error::Result;
7use lawkit_core::laws::integration::AnalysisPurpose;
8use std::io::Write;
9
10pub fn get_numbers_from_input(matches: &ArgMatches) -> Result<Vec<f64>> {
11    let (_parallel_config, _memory_config) = setup_automatic_optimization_config();
12
13    let buffer = if let Some(input) = matches.get_one::<String>("input") {
14        if input == "-" {
15            get_optimized_reader(None)
16        } else {
17            get_optimized_reader(Some(input))
18        }
19    } else {
20        get_optimized_reader(None)
21    };
22
23    let data = buffer.map_err(|e| lawkit_core::error::BenfError::IoError(e.to_string()))?;
24
25    if data.trim().is_empty() {
26        return Err(lawkit_core::error::BenfError::ParseError(
27            "No input data provided".to_string(),
28        ));
29    }
30
31    lawkit_core::common::input::parse_text_input(&data)
32}
33
34pub fn get_dataset_name(matches: &ArgMatches) -> String {
35    matches
36        .get_one::<String>("input")
37        .cloned()
38        .unwrap_or_else(|| "stdin".to_string())
39}
40
41pub fn parse_analysis_purpose(purpose_str: &str) -> AnalysisPurpose {
42    match purpose_str {
43        "quality" => AnalysisPurpose::QualityAudit,
44        "fraud" => AnalysisPurpose::FraudDetection,
45        "concentration" => AnalysisPurpose::ConcentrationAnalysis,
46        "anomaly" => AnalysisPurpose::AnomalyDetection,
47        "distribution" => AnalysisPurpose::DistributionFitting,
48        _ => AnalysisPurpose::GeneralAnalysis,
49    }
50}
51
52// Output functions
53pub fn output_integration_result(
54    writer: &mut Box<dyn Write>,
55    result: &lawkit_core::laws::integration::IntegrationResult,
56    config: &OutputConfig,
57) -> Result<()> {
58    match config.format.as_str() {
59        "json" => output_integration_json(writer, result),
60        "csv" => output_integration_csv(writer, result),
61        "yaml" => output_integration_yaml(writer, result),
62        _ => output_integration_text(writer, result, config),
63    }
64}
65
66fn output_integration_text(
67    writer: &mut Box<dyn Write>,
68    result: &lawkit_core::laws::integration::IntegrationResult,
69    config: &OutputConfig,
70) -> Result<()> {
71    if config.quiet {
72        writeln!(writer, "{:.3}", result.overall_quality_score)?;
73        return Ok(());
74    }
75
76    writeln!(writer, "Statistical Laws Integration Analysis")?;
77    writeln!(writer)?;
78
79    writeln!(
80        writer,
81        "{}: {}",
82        get_text("dataset", "en"),
83        result.dataset_name
84    )?;
85    writeln!(
86        writer,
87        "{}: {}",
88        get_text("numbers_analyzed", "en"),
89        result.numbers_analyzed
90    )?;
91    writeln!(
92        writer,
93        "{}: {} ({})",
94        get_text("laws_executed", "en"),
95        result.laws_executed.len(),
96        result.laws_executed.join(", ")
97    )?;
98
99    if let Some(ref focus) = result.focus {
100        writeln!(writer, "{}: {}", get_text("focus", "en"), focus)?;
101    }
102
103    writeln!(writer)?;
104
105    writeln!(writer, "{}:", get_text("integration_metrics", "en"))?;
106    writeln!(
107        writer,
108        "  {}: {:.3}",
109        get_text("overall_quality", "en"),
110        result.overall_quality_score
111    )?;
112    writeln!(
113        writer,
114        "  {}: {:.3}",
115        get_text("consistency", "en"),
116        result.consistency_score
117    )?;
118    writeln!(
119        writer,
120        "  {}: {}",
121        get_text("conflicts_detected", "en"),
122        result.conflicts_detected
123    )?;
124    writeln!(
125        writer,
126        "  {}: {:.3}",
127        get_text("recommendation_confidence", "en"),
128        result.recommendation_confidence
129    )?;
130    writeln!(writer)?;
131
132    writeln!(writer, "{}:", get_text("law_results", "en"))?;
133    for (law, score) in &result.law_scores {
134        let law_name = get_law_name(law, "en");
135        writeln!(writer, "  {law_name}: {score:.3}")?;
136    }
137    writeln!(writer)?;
138
139    if !result.conflicts.is_empty() {
140        writeln!(writer, "{}:", get_text("conflicts", "en"))?;
141        for conflict in &result.conflicts {
142            writeln!(
143                writer,
144                "  {}",
145                colors::level_conflict(&conflict.description)
146            )?;
147            writeln!(
148                writer,
149                "     {}: {}",
150                get_text("cause", "en"),
151                conflict.likely_cause
152            )?;
153            writeln!(
154                writer,
155                "     {}: {}",
156                get_text("suggestion", "en"),
157                conflict.resolution_suggestion
158            )?;
159        }
160        writeln!(writer)?;
161    }
162
163    writeln!(writer, "{}:", get_text("recommendations", "en"))?;
164    writeln!(
165        writer,
166        "  FOCUS: {}: {}",
167        get_text("primary_law", "en"),
168        get_law_name(&result.recommendations.primary_law, "en")
169    )?;
170
171    if !result.recommendations.secondary_laws.is_empty() {
172        let secondary_names: Vec<String> = result
173            .recommendations
174            .secondary_laws
175            .iter()
176            .map(|law| get_law_name(law, "en"))
177            .collect();
178        writeln!(
179            writer,
180            "  DETAIL: {}: {}",
181            get_text("secondary_laws", "en"),
182            secondary_names.join(", ")
183        )?;
184    }
185
186    writeln!(
187        writer,
188        "  METRIC: {}: {}",
189        get_text("rationale", "en"),
190        result.recommendations.rationale
191    )?;
192    writeln!(writer)?;
193
194    if config.verbose {
195        output_verbose_integration_details(writer, result, "en")?;
196    }
197
198    Ok(())
199}
200
201fn output_integration_json(
202    writer: &mut Box<dyn Write>,
203    result: &lawkit_core::laws::integration::IntegrationResult,
204) -> Result<()> {
205    let _json_value = serde_json::json!({
206        "dataset": result.dataset_name,
207        "numbers_analyzed": result.numbers_analyzed,
208        "laws_executed": result.laws_executed,
209        "focus": result.focus,
210        "integration_metrics": {
211            "overall_quality_score": result.overall_quality_score,
212            "consistency_score": result.consistency_score,
213            "conflicts_detected": result.conflicts_detected,
214            "recommendation_confidence": result.recommendation_confidence
215        },
216        "law_scores": result.law_scores,
217        "conflicts": result.conflicts.iter().map(|c| {
218            serde_json::json!({
219                "type": format!("{:?}", c.conflict_type),
220                "laws_involved": c.laws_involved,
221                "conflict_score": c.conflict_score,
222                "description": c.description,
223                "likely_cause": c.likely_cause,
224                "resolution_suggestion": c.resolution_suggestion
225            })
226        }).collect::<Vec<_>>(),
227        "recommendations": {
228            "primary_law": result.recommendations.primary_law,
229            "secondary_laws": result.recommendations.secondary_laws,
230            "confidence": result.recommendations.confidence,
231            "rationale": result.recommendations.rationale
232        },
233        "overall_assessment": format!("{:?}", result.overall_assessment),
234        "risk_level": format!("{:?}", result.risk_level)
235    });
236
237    let enhanced_json = create_enhanced_integration_json(result);
238    writeln!(writer, "{}", serde_json::to_string_pretty(&enhanced_json)?)?;
239    Ok(())
240}
241
242/// diffx-coreを活用してより構造化されたJSON出力を生成
243fn create_enhanced_integration_json(
244    result: &lawkit_core::laws::integration::IntegrationResult,
245) -> serde_json::Value {
246    // 基本のJSON構造を作成
247    let basic_json = serde_json::json!({
248        "dataset": result.dataset_name,
249        "numbers_analyzed": result.numbers_analyzed,
250        "laws_executed": result.laws_executed,
251        "focus": result.focus,
252        "integration_metrics": {
253            "overall_quality_score": result.overall_quality_score,
254            "consistency_score": result.consistency_score,
255            "conflicts_detected": result.conflicts_detected,
256            "recommendation_confidence": result.recommendation_confidence
257        },
258        "law_scores": result.law_scores,
259        "conflicts": result.conflicts.iter().map(|c| {
260            serde_json::json!({
261                "type": format!("{:?}", c.conflict_type),
262                "laws_involved": c.laws_involved,
263                "conflict_score": c.conflict_score,
264                "description": c.description,
265                "likely_cause": c.likely_cause,
266                "resolution_suggestion": c.resolution_suggestion
267            })
268        }).collect::<Vec<_>>(),
269        "recommendations": {
270            "primary_law": result.recommendations.primary_law,
271            "secondary_laws": result.recommendations.secondary_laws,
272            "confidence": result.recommendations.confidence,
273            "rationale": result.recommendations.rationale
274        },
275        "overall_assessment": format!("{:?}", result.overall_assessment),
276        "risk_level": format!("{:?}", result.risk_level)
277    });
278
279    // diffx-core拡張情報を追加
280    let mut enhanced_json = basic_json;
281
282    // 法則スコアの詳細解釈を追加
283    if let Some(law_scores_obj) = enhanced_json
284        .get_mut("law_scores")
285        .and_then(|v| v.as_object_mut())
286    {
287        for (law, score) in &result.law_scores {
288            if let Some(score_val) = law_scores_obj.get_mut(law) {
289                *score_val = serde_json::json!({
290                    "score": score,
291                    "tier": classify_score_tier(*score),
292                    "interpretation": interpret_score(*score)
293                });
294            }
295        }
296    }
297
298    // 矛盾の重要度分類を追加
299    if let Some(conflicts_array) = enhanced_json
300        .get_mut("conflicts")
301        .and_then(|v| v.as_array_mut())
302    {
303        for (i, conflict) in result.conflicts.iter().enumerate() {
304            if let Some(conflict_obj) = conflicts_array.get_mut(i).and_then(|v| v.as_object_mut()) {
305                conflict_obj.insert(
306                    "severity".to_string(),
307                    serde_json::Value::String(
308                        classify_conflict_severity(conflict.conflict_score).to_string(),
309                    ),
310                );
311
312                // diffx-core由来の矛盾には特別な情報を追加
313                if matches!(
314                    conflict.conflict_type,
315                    lawkit_core::laws::integration::ConflictType::ScoreDeviation
316                        | lawkit_core::laws::integration::ConflictType::UnexpectedConsistency
317                ) {
318                    conflict_obj.insert(
319                        "detection_method".to_string(),
320                        serde_json::Value::String("diffx-core structural analysis".to_string()),
321                    );
322                }
323            }
324        }
325    }
326
327    // メタデータを追加
328    enhanced_json.as_object_mut().unwrap().insert(
329        "metadata".to_string(),
330        serde_json::json!({
331            "tool": "lawkit",
332            "enhanced_with": "diffx-core",
333            "format_version": "2.2.0",
334            "generation_timestamp": chrono::Utc::now().to_rfc3339()
335        }),
336    );
337
338    enhanced_json
339}
340
341// ヘルパー関数群
342fn classify_score_tier(score: f64) -> &'static str {
343    match score {
344        s if s >= 0.9 => "excellent",
345        s if s >= 0.7 => "good",
346        s if s >= 0.5 => "fair",
347        s if s >= 0.3 => "poor",
348        _ => "very_poor",
349    }
350}
351
352fn interpret_score(score: f64) -> &'static str {
353    match score {
354        s if s >= 0.9 => "Strong adherence to statistical law",
355        s if s >= 0.7 => "Good fit with expected distribution",
356        s if s >= 0.5 => "Moderate alignment with pattern",
357        s if s >= 0.3 => "Weak correlation with expected behavior",
358        _ => "Minimal or no adherence to law",
359    }
360}
361
362fn classify_conflict_severity(score: f64) -> &'static str {
363    match score {
364        s if s >= 0.8 => "critical",
365        s if s >= 0.6 => "high",
366        s if s >= 0.4 => "medium",
367        s if s >= 0.2 => "low",
368        _ => "minimal",
369    }
370}
371
372fn output_integration_csv(
373    writer: &mut Box<dyn Write>,
374    result: &lawkit_core::laws::integration::IntegrationResult,
375) -> Result<()> {
376    writeln!(writer, "dataset,numbers_analyzed,laws_executed,focus,overall_quality_score,consistency_score,conflicts_detected,primary_law,overall_assessment,risk_level")?;
377    writeln!(
378        writer,
379        "{},{},{},{},{:.3},{:.3},{},{},{:?},{:?}",
380        result.dataset_name,
381        result.numbers_analyzed,
382        result.laws_executed.len(),
383        result.focus.as_deref().unwrap_or(""),
384        result.overall_quality_score,
385        result.consistency_score,
386        result.conflicts_detected,
387        result.recommendations.primary_law,
388        result.overall_assessment,
389        result.risk_level
390    )?;
391    Ok(())
392}
393
394fn output_integration_yaml(
395    writer: &mut Box<dyn Write>,
396    result: &lawkit_core::laws::integration::IntegrationResult,
397) -> Result<()> {
398    writeln!(writer, "dataset: \"{}\"", result.dataset_name)?;
399    writeln!(writer, "numbers_analyzed: {}", result.numbers_analyzed)?;
400    writeln!(writer, "laws_executed:")?;
401    for law in &result.laws_executed {
402        writeln!(writer, "  - \"{law}\"")?;
403    }
404    if let Some(ref focus) = result.focus {
405        writeln!(writer, "focus: \"{focus}\"")?;
406    }
407    writeln!(writer, "integration_metrics:")?;
408    writeln!(
409        writer,
410        "  overall_quality_score: {:.3}",
411        result.overall_quality_score
412    )?;
413    writeln!(
414        writer,
415        "  consistency_score: {:.3}",
416        result.consistency_score
417    )?;
418    writeln!(
419        writer,
420        "  conflicts_detected: {}",
421        result.conflicts_detected
422    )?;
423    writeln!(writer, "law_scores:")?;
424    for (law, score) in &result.law_scores {
425        writeln!(writer, "  {law}: {score:.3}")?;
426    }
427    writeln!(writer, "recommendations:")?;
428    writeln!(
429        writer,
430        "  primary_law: \"{}\"",
431        result.recommendations.primary_law
432    )?;
433    writeln!(
434        writer,
435        "  confidence: {:.3}",
436        result.recommendations.confidence
437    )?;
438    Ok(())
439}
440
441// Helper functions for verbose output
442fn output_verbose_integration_details(
443    writer: &mut Box<dyn Write>,
444    result: &lawkit_core::laws::integration::IntegrationResult,
445    _lang: &str,
446) -> Result<()> {
447    writeln!(writer, "=== {} ===", get_text("detailed_metrics", "en"))?;
448
449    output_data_characteristics(writer, result, "en")?;
450
451    if !result.recommendations.alternative_combinations.is_empty() {
452        output_alternative_combinations(writer, result, "en")?;
453    }
454
455    Ok(())
456}
457
458fn output_data_characteristics(
459    writer: &mut Box<dyn Write>,
460    result: &lawkit_core::laws::integration::IntegrationResult,
461    _lang: &str,
462) -> Result<()> {
463    let chars = &result.data_characteristics;
464
465    writeln!(writer, "{}:", get_text("data_characteristics", "en"))?;
466    writeln!(
467        writer,
468        "  {}: {:?}",
469        get_text("data_type", "en"),
470        chars.data_type
471    )?;
472    writeln!(
473        writer,
474        "  {}: {:?}",
475        get_text("distribution_shape", "en"),
476        chars.distribution_shape
477    )?;
478    writeln!(
479        writer,
480        "  {}: {:?}",
481        get_text("outlier_presence", "en"),
482        chars.outlier_presence
483    )?;
484    writeln!(
485        writer,
486        "  {}: {:?}",
487        get_text("scale_range", "en"),
488        chars.scale_range
489    )?;
490    writeln!(
491        writer,
492        "  {}: {:?}",
493        get_text("sample_size_category", "en"),
494        chars.sample_size_category
495    )?;
496    writeln!(writer)?;
497
498    Ok(())
499}
500
501fn output_alternative_combinations(
502    writer: &mut Box<dyn Write>,
503    result: &lawkit_core::laws::integration::IntegrationResult,
504    _lang: &str,
505) -> Result<()> {
506    writeln!(writer, "{}:", get_text("alternative_combinations", "en"))?;
507
508    for combo in &result.recommendations.alternative_combinations {
509        writeln!(writer, "• {} ({})", combo.purpose, combo.laws.join(" + "))?;
510        writeln!(
511            writer,
512            "  {}: {:.3}",
513            get_text("effectiveness", "en"),
514            combo.effectiveness_score
515        )?;
516        writeln!(
517            writer,
518            "  {}: {}",
519            get_text("description", "en"),
520            combo.description
521        )?;
522        writeln!(writer)?;
523    }
524
525    Ok(())
526}
527
528// Text localization
529fn get_text(key: &str, _lang: &str) -> String {
530    match key {
531        "integration_title" => "Integration Analysis Result",
532        "dataset" => "Dataset",
533        "numbers_analyzed" => "Numbers Analyzed",
534        "laws_executed" => "Laws Executed",
535        "integration_metrics" => "Integration Metrics",
536        "overall_quality" => "Overall Quality Score",
537        "consistency" => "Consistency Score",
538        "conflicts_detected" => "Conflicts Detected",
539        "recommendation_confidence" => "Recommendation Confidence",
540        "law_results" => "Law Results",
541        "conflicts" => "Conflicts",
542        "cause" => "Likely Cause",
543        "suggestion" => "Suggestion",
544        "recommendations" => "Recommendations",
545        "primary_law" => "Primary Law",
546        "secondary_laws" => "Secondary Laws",
547        "rationale" => "Rationale",
548        "focus" => "Focus",
549        "detailed_analysis" => "Detailed Analysis",
550        "detailed_metrics" => "Detailed Metrics",
551        "data_characteristics" => "Data Characteristics",
552        "data_type" => "Data Type",
553        "distribution_shape" => "Distribution Shape",
554        "outlier_presence" => "Outlier Presence",
555        "scale_range" => "Scale Range",
556        "sample_size_category" => "Sample Size Category",
557        "alternative_combinations" => "Alternative Combinations",
558        "effectiveness" => "Effectiveness",
559        "description" => "Description",
560        _ => key,
561    }
562    .to_string()
563}
564
565fn get_law_name(law: &str, _lang: &str) -> String {
566    match law {
567        "benf" => "Benford Law",
568        "pareto" => "Pareto Principle",
569        "zipf" => "Zipf Law",
570        "normal" => "Normal Distribution",
571        "poisson" => "Poisson Distribution",
572        _ => law,
573    }
574    .to_string()
575}