roma_lib 0.1.1

A Rust metaheuristics framework inspired by jMetal for optimization and experimentation.
Documentation
use roma_lib::algorithms::{
    Algorithm, HillClimbing, HillClimbingParameters, TerminationCriteria, TerminationCriterion,
};
use roma_lib::observer::{HtmlReportObserver, Observable};
use roma_lib::operator::BitFlipMutation;
use roma_lib::problem::Problem;
use roma_lib::solution::Solution;
use roma_lib::utils::Random;
use std::time::{SystemTime, UNIX_EPOCH};

struct HtmlFormattingProblem {
    description: String,
    variables: usize,
}

impl Problem<bool> for HtmlFormattingProblem {
    fn new() -> Self {
        Self {
            description: "HTML formatting problem".to_string(),
            variables: 6,
        }
    }

    fn evaluate(&self, solution: &mut Solution<bool>) {
        let selected = solution.variables().iter().filter(|&&value| value).count() as f64;
        solution.set_quality(selected);
    }

    fn create_solution(&self, rng: &mut Random) -> Solution<bool> {
        let variables: Vec<bool> = (0..self.variables).map(|_| rng.coin_flip()).collect();
        Solution::new(variables)
    }

    fn set_problem_description(&mut self, description: String) {
        self.description = description;
    }

    fn get_problem_description(&self) -> String {
        self.description.clone()
    }

    fn dominates(&self, solution_a: &Solution<bool>, solution_b: &Solution<bool>) -> bool {
        solution_a.quality().copied().unwrap_or(f64::NEG_INFINITY)
            > solution_b.quality().copied().unwrap_or(f64::NEG_INFINITY)
    }

    fn better_fitness_fn(&self) -> fn(f64, f64) -> bool {
        fn maximizing_fitness(a: f64, b: f64) -> bool {
            a > b
        }
        maximizing_fitness
    }

    fn format_solution(&self, solution: &Solution<bool>) -> String {
        let selected = solution.variables().iter().filter(|&&value| value).count();
        format!("binary-summary: {}/{} selected", selected, self.variables)
    }
}

#[test]
fn html_report_includes_problem_specific_best_solution_rendering() {
    let problem = HtmlFormattingProblem::new();
    let run_id = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map(|duration| duration.as_nanos())
        .unwrap_or(0);
    let output_dir = std::env::temp_dir().join(format!("roma_html_rendering_test_{}", run_id));

    let observer = HtmlReportObserver::new(output_dir.clone()).with_flat_output();
    let parameters = HillClimbingParameters::new(
        BitFlipMutation::new(),
        0.35,
        TerminationCriteria::new(vec![TerminationCriterion::MaxIterations(3)]),
    )
    .with_seed(7);
    let mut algorithm = HillClimbing::new(parameters);
    algorithm.add_observer(Box::new(observer));

    let _ = algorithm
        .run(&problem)
        .expect("hill climbing execution should succeed");

    let report_path = output_dir.join("report.html");
    assert!(
        report_path.exists(),
        "html report should exist at {}",
        report_path.display()
    );

    let report = std::fs::read_to_string(&report_path).expect("report should be readable");
    assert!(
        report.contains("binary-summary:"),
        "report should include problem-specific presentation text"
    );
}