Struct HyperVolume

Source
pub struct HyperVolume;
Expand description

Struct with methods to calculate the exact hyper-volume metric. Depending on the number of problem objectives n, a different method is used to ensure a correct and fast calculation:

The hyper-volume can be calculated from the following sources:

§Example

The following example shows how to calculate the hyper-volume and track convergence.

use std::env;
use std::path::PathBuf;

use optirustic::algorithms::{Algorithm, ExportHistory, NSGA2Arg, StoppingCondition, NSGA2};
use optirustic::core::builtin_problems::SCHProblem;
use optirustic::core::OError;
use optirustic::metrics::HyperVolume;

/// This example shows how to track the algorithm convergence by calculating the hyper-volume metric.
/// This library employs different and fast methods, depending on the number of problem objectives,
/// such as [Fonseca et al. (2006)](http://dx.doi.org/10.1109/CEC.2006.1688440) or
/// [While et al. (2012)](http://dx.doi.org/10.1109/TEVC.2010.2077298).
///
/// Convergence can be tracked while an algorithm runs by saving the evolution history of the
/// population. This is useful if you have an evaluation  function, that evaluates the problem
/// objectives and constraints (this is the `evaluate()` function in the `Evaluator` trait),
/// that takes very long to run .
///
/// The example below solves the SCH problem, export the evolution history as JSON every 100
/// generations and calculate the hyper-volume at different generations.
///
/// Make sure to compile this in release mode to speed up the calculation:
///
/// `cargo run --example convergence -p optirustic --release`
fn main() -> Result<(), OError> {
    let problem = SCHProblem::create()?;
    let out_path = PathBuf::from(&env::current_dir().expect("Cannot fetch current directory"))
        .join("examples")
        .join("results")
        .join("convergence");

    // this exports a JSON file every 100 generations
    let export_history = ExportHistory::new(100, &out_path)?;
    let args = NSGA2Arg {
        number_of_individuals: 10,
        stopping_condition: StoppingCondition::MaxGeneration(1000),
        crossover_operator_options: None,
        mutation_operator_options: None,
        parallel: Some(false),
        export_history: Some(export_history),
        resume_from_file: None,
        seed: Some(10),
    };
    let mut algo = NSGA2::new(problem, args)?;
    algo.run()?;
    let mut results = algo.get_results();

    let serialised_data = NSGA2::read_json_files(&out_path)?;
    let ref_point = HyperVolume::estimate_reference_point_from_files(&serialised_data, None)?;
    println!("Reference point: {:?}", ref_point);

    // calculate metric from the history file
    let serialised_data = NSGA2::read_json_file(&out_path.join("History_NSGA2_gen200.json"))?;
    let hv = HyperVolume::from_file(&serialised_data, &ref_point)?;
    println!(
        "Hyper-volume at generation #{} is {}",
        hv.generation, hv.value
    );

    // calculate metric at the last iteration
    let hv = HyperVolume::from_individual(&mut results.individuals, &ref_point)?;
    println!("Hyper-volume at last generation is {}", hv);

    // calculate the hyper-volume at all generations to check the overall convergence
    let all_serialise_data = NSGA2::read_json_files(&out_path)?;
    let hvs = HyperVolume::from_files(&all_serialise_data, &ref_point)?;
    println!("Hyper-volumes generations: {:?}", hvs.generations());
    println!("Hyper-volumes values: {:?}", hvs.values());

    Ok(())
}

Implementations§

Source§

impl HyperVolume

Source

pub fn from_individual( individuals: &mut [Individual], reference_point: &[f64], ) -> Result<f64, OError>

Calculate the exact hyper-volume metric for the objective values stored in the vector of Individual. If you have an array of objective values instead of Individual, you can use HyperVolume::from_values instead.

§Arguments
  • individuals: The individuals to use in the calculation. The algorithm will use the objective vales stored in each individual.
  • reference_point: The reference or anti-optimal point to use in the calculation. If you are not sure about the point to use you could pick the worst value of each objective from the individual’s values using HyperVolume::estimate_reference_point.

returns: Result<f64, OError>

Source

pub fn from_values( problem: Problem, individuals: &[HashMap<String, f64>], reference_point: &[f64], ) -> Result<f64, OError>

Calculate the exact hyper-volume metric for the objectives.

§Arguments
  • problem: The problem to solve.
  • individuals: The objectives values; each array represents an individual, each nested map contains the objective names and values instead.
  • reference_point: The reference or anti-optimal point to use in the calculation. If you are not sure about the point to use you could pick the worst value of each objective from the individual’s values using the HyperVolume::estimate_reference_point method.

returns: Result<f64, OError>

Source

pub fn from_file<AlgorithmOptions: Serialize + DeserializeOwned>( data: &AlgorithmSerialisedExport<AlgorithmOptions>, reference_point: &[f64], ) -> Result<HyperVolumeFileData, OError>

Calculate the hyper-volume using serialised objective values (i.e. exported in a JSON file using crate::algorithms::Algorithm::save_to_json).

§Arguments

returns: Result<HyperVolumeFileData, OError>: the hyper-volume value and the file information.

Source

pub fn from_files<AlgorithmOptions: Serialize + DeserializeOwned>( data: &[AlgorithmSerialisedExport<AlgorithmOptions>], reference_point: &[f64], ) -> Result<AllHyperVolumeFileData, OError>

Calculate the hyper-volume using the serialised objective values (i.e. exported in a JSON file using crate::algorithms::Algorithm::save_to_json).

§Arguments

returns: Result<AllHyperVolumeFileData, OError>: the hyper-volume values and the file information.

Source

pub fn estimate_reference_point( individuals: &[Individual], offset: Option<Vec<f64>>, ) -> Result<Vec<f64>, OError>

Calculates a reference point by taking the maximum of each objective (or minimum if the objective is maximised) from the calculated individual’s objective values, so that the point will be dominated by all other points. An optional offset for all objectives could also be added or removed to enforce strict dominance (if the objective is minimised the offset is added to the calculated reference point, otherwise it is subtracted).

§Arguments
  • individuals: The individuals to use in the calculation.
  • offset: The offset to add to each objective coordinate of the calculated reference point. This must have a size equal to the number of objectives in the problem (Problem::number_of_objectives).

returns: Result<Vec<f64>, OError> The reference point. This returns an error if there are no individuals or the size of the offset does not match Problem::number_of_objectives.

Source

pub fn estimate_reference_point_from_file<AlgorithmOptions: Serialize + DeserializeOwned>( data: &AlgorithmSerialisedExport<AlgorithmOptions>, offset: Option<Vec<f64>>, ) -> Result<Vec<f64>, OError>

Calculates a reference point by taking the maximum of each objective (or minimum if the objective is maximised) from the objective values exported in a JSON file. See HyperVolume::estimate_reference_point for a detailed description of the estimation.

§Arguments

returns: Result<Vec<f64>, OError> The reference point. This returns an error if there are no individuals or the size of the offset does not match Problem::number_of_objectives.

Source

pub fn estimate_reference_point_from_files<AlgorithmOptions: Serialize + DeserializeOwned>( data: &[AlgorithmSerialisedExport<AlgorithmOptions>], offset: Option<Vec<f64>>, ) -> Result<Vec<f64>, OError>

Calculates a reference point by taking the maximum of each objective (or minimum if the objective is maximised) from the objective values exported in a JSON files. This may be use to estimate the reference point when convergence is being tracked and one dominated reference point is needed. See HyperVolume::estimate_reference_point for a detailed description of the estimation.

§Arguments

returns: Result<Vec<f64>, OError> The reference point. This returns an error if there are no individuals or the size of the offset does not match Problem::number_of_objectives.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> Ungil for T
where T: Send,