Struct NSGA3

Source
pub struct NSGA3 { /* private fields */ }
Expand description

The Non-dominated Sorting Genetic Algorithm (NSGA3).

Implemented based on:

K. Deb and H. Jain, “An Evolutionary Many-Objective Optimization Algorithm Using Reference-Point-Based Non-dominated Sorting Approach, Part I: Solving Problems With Box Constraints,” in IEEE Transactions on Evolutionary Computation, vol. 18, no. 4, pp. 577-601, Aug. 2014, doi: 10.1109/TEVC.2013.2281535

See: https://10.1109/TEVC.2013.2281535

§Example - solve the DTLZ1 problem

use std::env;
use std::error::Error;
use std::path::PathBuf;

use log::LevelFilter;

use optirustic::algorithms::{
   Algorithm, NSGA3Arg, Nsga3NumberOfIndividuals, StoppingCondition, NSGA3,
};
use optirustic::core::builtin_problems::DTLZ1Problem;
use optirustic::operators::SimulatedBinaryCrossoverArgs;
use optirustic::utils::{DasDarren1998, NumberOfPartitions};

/// Solve the DTLZ1 problem from Deb et al. (2013) with 3 objectives. This is a problem where the
/// optimal solutions or objectives lie on the hyper-plane passing through the intercept point
/// at 0.5 on each objective axis. This code replicates the first testing problem in Deb et al.
/// (2013).
///
/// Make sure to compile this in release mode to speed up the calculation:
///
/// `cargo run --example nsga3_dtlz1 -p optirustic --release`
fn main() -> Result<(), Box<dyn Error>> {
   // Add log
   env_logger::builder().filter_level(LevelFilter::Info).init();

   let number_objectives: usize = 3;
   // Set the number of variables to use in the DTLZ1 problem
   let k: usize = 5;
   let number_variables: usize = number_objectives + k - 1;
   // Get the built-in problem
   let problem = DTLZ1Problem::create(number_variables, number_objectives, false)?;

   // Set the number of partitions to create the reference points for the NSGA3 algorithm. This
   // uses one layer of 12 uniform gaps
   let number_of_partitions = NumberOfPartitions::OneLayer(12);
   // NSGA3 internally uses the Das & Darren approach to generate the points. This is also
   // available using:
   let das_darren = DasDarren1998::new(number_objectives, &number_of_partitions)?;
   println!(
       "Number of reference points to generate: {}",
       das_darren.number_of_points()
   );

   // Customise the SBX and PM operators like in the paper
   let crossover_operator_options = SimulatedBinaryCrossoverArgs {
       distribution_index: 30.0,
       crossover_probability: 1.0,
       ..SimulatedBinaryCrossoverArgs::default()
   };

   // Set up the NSGA3 algorithm
   let args = NSGA3Arg {
       // number of individuals from the paper (possibly equal to number of reference points)
       number_of_individuals: Nsga3NumberOfIndividuals::Custom(92),
       number_of_partitions,
       crossover_operator_options: Some(crossover_operator_options),
       mutation_operator_options: None,
       // stop at generation 400
       stopping_condition: StoppingCondition::MaxGeneration(400),
       parallel: None,
       export_history: None,
       // to reproduce results
       seed: Some(1),
       resume_from_file: None,
   };

   // Initialise the algorithm
   let mut algo = NSGA3::new(problem, args, false).unwrap();

   // Run the algorithm
   algo.run()?;

   // Export the last results to a JSON file
   let destination = PathBuf::from(&env::current_dir().unwrap())
       .join("examples")
       .join("results");

   algo.save_to_json(&destination, Some("DTLZ1_3obj"))?;
   // algo.plot_objectives("examples/results/DTLZ1_3obj.png")?;

   Ok(())
}

Implementations§

Source§

impl NSGA3

Source

pub fn new( problem: Problem, options: NSGA3Arg, adaptive: bool, ) -> Result<Self, OError>

Initialise the NSGA3 algorithm.

§Arguments
  • problem: The problem being solved.
  • options: The NSGA3Arg arguments to customise the algorithm behaviour.
  • adaptive: Whether to use the adaptive approach to handle the reference points. Normally reference points are fixed and never change position, and NSGA3 will try to associate one individual to each reference point. However, there are some problems where the reference lines never intersects the Pareto front and no Pareto-optimal solutions are associated to those reference points. The reference points intersecting the front may have too many points associated and create crowded solutions. To improve the solutions for these kind of problems, when this option is set to true, new reference points will adaptively be added around the provided points to reduce crowding and force one solution to be associated to preferably only on reference direction. This option converts NSGA3 to crate::algorithms::AdaptiveNSGA3 (where A stands for adaptive) and it is explained in Section VII of Jain and Deb (2013). For a detailed explanation about the implementation see AdaptiveReferencePoints.

returns: NSGA3.

Source

pub fn reference_points(&self) -> Vec<Vec<f64>>

Get the reference points used in the evolution.

return: Vec<Vec<f64>>

Trait Implementations§

Source§

impl Algorithm<NSGA3Arg> for NSGA3

Implementation of Section IV of the paper.

Source§

fn initialise(&mut self) -> Result<(), OError>

This assesses the initial random population.

return: Result<(), OError>

Source§

fn evolve(&mut self) -> Result<(), OError>

Evolve the population. The first part of this code comes from NSGA2::evolve(). NSGA3 mainly differs in the survival method.

Source§

fn additional_export_data(&self) -> Option<HashMap<String, DataValue>>

Export additional data stored by the algorithm. Read more
Source§

fn stopping_condition(&self) -> &StoppingCondition

Return the stopping condition. Read more
Source§

fn name(&self) -> String

Return the algorithm name. Read more
Source§

fn start_time(&self) -> &Instant

Get the time when the algorithm started. Read more
Source§

fn problem(&self) -> Arc<Problem>

Return the problem. Read more
Source§

fn population(&self) -> &Population

Return the evolved population. Read more
Source§

fn export_history(&self) -> Option<&ExportHistory>

Return the history export configuration, if provided by the algorithm. Read more
Source§

fn generation(&self) -> u32

Return the current step of the algorithm evolution. Read more
Source§

fn number_of_function_evaluations(&self) -> u32

Return the number of function evaluations. This is the number of times the algorithm evaluates an individual’s objectives and constraints using Algorithm::evaluate_individual. If no new solutions/individuals are chosen by an algorithm, this counter will not increase, as past solutions are already evaluated. Read more
Source§

fn algorithm_options(&self) -> NSGA3Arg

Source§

fn elapsed(&self) -> [u64; 3]

Get the elapsed hours, minutes and seconds since the start of the algorithm. Read more
Source§

fn elapsed_as_string(&self) -> String

Format the elapsed time as string. Read more
Source§

fn do_parallel_evaluation( individuals: &mut [Individual], nfe: &mut u32, ) -> Result<(), OError>

Evaluate the objectives and constraints for unevaluated individuals in the population. This updates the individual data only, runs the evaluation function in threads and increase the nfe counter by the number of evaluated individuals. This returns an error if the evaluation function fails or the evaluation function does not provide a value for a problem constraints or objectives for one individual. Read more
Source§

fn do_evaluation( individuals: &mut [Individual], nfe: &mut u32, ) -> Result<(), OError>

Evaluate the objectives and constraints for unevaluated individuals in the population. This updates the individual data only, runs the evaluation function in a plain loop and increase the nfe counter by the number of evaluated individuals. This returns an error if the evaluation function fails or the evaluation function does not provide a value for a problem constraints or objectives for one individual. Evaluation may be performed in threads using Self::do_parallel_evaluation. Read more
Source§

fn evaluate_individual(idx: usize, i: &mut Individual) -> Result<(), OError>

Evaluate the objectives and constraints for one unevaluated individual. This returns an error if the evaluation function fails or the evaluation function does not provide a value for a problem constraints or objectives. Read more
Source§

fn count_unevaluated(individuals: &[Individual]) -> u32

Count the number on unevaluated individuals. Read more
Source§

fn run(&mut self) -> Result<(), OError>

Run the algorithm. Read more
Source§

fn is_stopping_condition_met( &self, condition: &StoppingCondition, ) -> Result<bool, OError>

Check if the given stopping condition is met. Read more
Source§

fn get_results(&self) -> AlgorithmExport

Get the results of the run. Read more
Source§

fn save_to_json( &self, destination: &PathBuf, file_prefix: Option<&str>, ) -> Result<(), OError>

Save the algorithm data (individuals’ objective, variables and constraints, the problem, …) to a JSON file. This returns an error if the file cannot be saved. Read more
Source§

fn read_json_file( file: &PathBuf, ) -> Result<AlgorithmSerialisedExport<AlgorithmOptions>, OError>

Read the results previously exported with Self::save_to_json. Read more
Source§

fn read_json_files( folder: &PathBuf, ) -> Result<Vec<AlgorithmSerialisedExport<AlgorithmOptions>>, OError>

Read the results from files exported during an algorithm evolution. This returns an error if the path does not exist or does not contain valid JSON files. Read more
Source§

fn seed_population_from_file( problem: Arc<Problem>, name: &str, expected_individuals: usize, file: &PathBuf, ) -> Result<Population, OError>

Seed the population using the values of variables, objectives and constraints exported to a JSON file. Read more
Source§

impl Display for NSGA3

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for NSGA3

§

impl !RefUnwindSafe for NSGA3

§

impl !Send for NSGA3

§

impl !Sync for NSGA3

§

impl Unpin for NSGA3

§

impl !UnwindSafe for NSGA3

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> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
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