moors 0.2.10

Solving multi-objective optimization problems using genetic algorithms.
Documentation
use ndarray::{Array1, Array2, Axis};

// ---------------------------------------------------------------------------
// Auxiliary Functions for Distance and Ranking Computations
// ---------------------------------------------------------------------------

/// Computes the ideal point from a fitness matrix.
/// Each element of the returned array is the minimum value along the corresponding column.
pub fn get_ideal(population_fitness: &Array2<f64>) -> Array1<f64> {
    population_fitness.fold_axis(Axis(0), f64::INFINITY, |a, &b| a.min(b))
}

/// Computes the nadir point from a fitness matrix.
/// Each element of the returned array is the maximum value along the corresponding column.
pub fn get_nadir(population_fitness: &Array2<f64>) -> Array1<f64> {
    population_fitness.fold_axis(Axis(0), f64::NEG_INFINITY, |a, &b| a.max(b))
}

pub fn normalize_fitness(population_fitness: &Array2<f64>) -> Array2<f64> {
    let ideal = get_ideal(population_fitness);
    let nadir = get_nadir(population_fitness);

    let mut range = &nadir - &ideal;

    let eps = 1e-12;
    range.mapv_inplace(|r| if r.abs() < eps { 1.0 } else { r });

    let (nrows, ncols) = population_fitness.dim();

    let ideal_b = ideal
        .broadcast((nrows, ncols))
        .expect("broadcast de ideal falló");
    let range_b = range
        .broadcast((nrows, ncols))
        .expect("broadcast de range falló");

    // f' = (f - ideal) / range
    let mut normalized = population_fitness - &ideal_b;
    normalized /= &range_b;

    normalized
}

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
#[cfg(test)]
mod tests {
    use super::*;
    use ndarray::array;

    #[test]
    fn test_get_ideal() {
        // Example fitness matrix (3 solutions, 2 objectives)
        let fitness = array![[1.0, 4.0], [2.0, 3.0], [0.5, 5.0]];
        let ideal = get_ideal(&fitness);
        // For each objective, the expected minimum value:
        // First objective: min(1.0, 2.0, 0.5) = 0.5
        // Second objective: min(4.0, 3.0, 5.0) = 3.0
        assert_eq!(ideal, array![0.5, 3.0]);
    }

    #[test]
    fn test_get_nadir() {
        // Example fitness matrix (3 solutions, 2 objectives)
        let fitness = array![[1.0, 4.0], [2.0, 3.0], [0.5, 5.0]];
        let nadir = get_nadir(&fitness);
        // For each objective, the expected maximum value:
        // First objective: max(1.0, 2.0, 0.5) = 2.0
        // Second objective: max(4.0, 3.0, 5.0) = 5.0
        assert_eq!(nadir, array![2.0, 5.0]);
    }
}