mathhook-core 0.2.0

Core mathematical engine for MathHook - expressions, algebra, and solving
Documentation
use mathhook_core::parser::{config::ParserConfig, Parser};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs;
#[derive(Debug, Deserialize, Serialize)]
struct TestCase {
    id: String,
    language: String,
    category: String,
    input: String,
    description: String,
}
#[test]
fn analyze_all_parsing_cases() {
    let content =
        fs::read_to_string("tests/parsing/cases.json").expect("Failed to read cases.json");
    let cases: Vec<TestCase> = serde_json::from_str(&content).expect("Failed to parse JSON");
    println!("\n========== PARSING ANALYSIS ==========");
    println!("Total test cases: {}\n", cases.len());
    let mut total = 0;
    let mut success = 0;
    let mut failed = 0;
    let mut failures_by_category: HashMap<String, Vec<String>> = HashMap::new();
    let mut failures_by_language: HashMap<String, usize> = HashMap::new();
    for case in &cases {
        total += 1;
        let parser = Parser::new(&ParserConfig {
            enable_implicit_multiplication: true,
        });
        match parser.parse(&case.input) {
            Ok(_expr) => {
                success += 1;
            }
            Err(e) => {
                failed += 1;
                failures_by_category
                    .entry(case.category.clone())
                    .or_default()
                    .push(case.id.clone());
                *failures_by_language
                    .entry(case.language.clone())
                    .or_insert(0) += 1;
                println!(
                    "FAILED: {} [{}] [{}]",
                    case.id, case.language, case.category
                );
                println!("   Input: {}", case.input);
                println!("   Error: {:?}\n", e);
            }
        }
    }
    println!("\n========== SUMMARY ==========");
    println!("Total: {}", total);
    println!(
        "Success: {} ({:.1}%)",
        success,
        (success as f64 / total as f64) * 100.0
    );
    println!(
        "Failed: {} ({:.1}%)",
        failed,
        (failed as f64 / total as f64) * 100.0
    );
    println!("\n========== FAILURES BY LANGUAGE ==========");
    for (lang, count) in &failures_by_language {
        println!("{}: {} failures", lang, count);
    }
    println!("\n========== FAILURES BY CATEGORY (Top 20) ==========");
    let mut sorted_categories: Vec<_> = failures_by_category.iter().collect();
    sorted_categories.sort_by_key(|(_, v)| -(v.len() as i32));
    for (category, ids) in sorted_categories.iter().take(20) {
        println!("{}: {} failures", category, ids.len());
    }
    println!("\n========== TOP 10 MOST PROBLEMATIC CATEGORIES WITH EXAMPLES ==========");
    for (category, ids) in sorted_categories.iter().take(10) {
        println!("\n{}:", category);
        for id in ids.iter().take(3) {
            if let Some(case) = cases.iter().find(|c| &c.id == id) {
                println!("  - [{}] {}: \"{}\"", case.language, case.id, case.input);
            }
        }
        if ids.len() > 3 {
            println!("  ... and {} more", ids.len() - 3);
        }
    }
    println!("\n========== Analysis complete! ==========\n");
}