docs(rustdoc): add runnable examples across operators, metrics, and Pareto utilities
Completes the rustdoc audit — every public item now has at least one ```rust example block in its docstring, exercised by `cargo test --doc` (55 doctests, all passing). - Operators: BitFlipMutation, SwapMutation, RealBounds, GaussianMutation, BoundedGaussianMutation, SimulatedBinaryCrossover, PolynomialMutation, LevyMutation, ClampToBounds, ProjectToSimplex. - Metrics: hypervolume_2d, hypervolume_nd, spacing. - Pareto utilities: pareto_compare, pareto_front, best_candidate, non_dominated_sort, crowding_distance, das_dennis, ParetoArchive. Each example is short (5-15 lines) and self-contained — copy-paste into a fresh project and it runs.
This commit is contained in:
@@ -14,6 +14,26 @@ use crate::core::objective::ObjectiveSpace;
|
||||
///
|
||||
/// # Panics
|
||||
/// If `objectives` does not have exactly two objectives.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
/// use heuropt::metrics::hypervolume_2d;
|
||||
///
|
||||
/// let space = ObjectiveSpace::new(vec![
|
||||
/// Objective::minimize("f1"),
|
||||
/// Objective::minimize("f2"),
|
||||
/// ]);
|
||||
/// // Reference (4, 4); front at (1,3), (2,2), (3,1) → dominated area = 6.
|
||||
/// let front = [
|
||||
/// Candidate::new((), Evaluation::new(vec![1.0, 3.0])),
|
||||
/// Candidate::new((), Evaluation::new(vec![2.0, 2.0])),
|
||||
/// Candidate::new((), Evaluation::new(vec![3.0, 1.0])),
|
||||
/// ];
|
||||
/// let hv = hypervolume_2d(&front, &space, [4.0, 4.0]);
|
||||
/// assert!((hv - 6.0).abs() < 1e-12);
|
||||
/// ```
|
||||
pub fn hypervolume_2d<D>(
|
||||
front: &[Candidate<D>],
|
||||
objectives: &ObjectiveSpace,
|
||||
@@ -147,6 +167,24 @@ mod tests {
|
||||
///
|
||||
/// # Panics
|
||||
/// If `objectives.len() != reference_point.len()`, or if either is zero.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
/// use heuropt::metrics::hypervolume_nd;
|
||||
///
|
||||
/// let space = ObjectiveSpace::new(vec![
|
||||
/// Objective::minimize("f1"),
|
||||
/// Objective::minimize("f2"),
|
||||
/// Objective::minimize("f3"),
|
||||
/// ]);
|
||||
/// // Single corner point at the origin against a unit-cube reference:
|
||||
/// // dominated volume = 1.
|
||||
/// let front = [Candidate::new((), Evaluation::new(vec![0.0, 0.0, 0.0]))];
|
||||
/// let hv = hypervolume_nd(&front, &space, &[1.0, 1.0, 1.0]);
|
||||
/// assert!((hv - 1.0).abs() < 1e-12);
|
||||
/// ```
|
||||
pub fn hypervolume_nd<D>(
|
||||
front: &[Candidate<D>],
|
||||
objectives: &ObjectiveSpace,
|
||||
|
||||
@@ -11,6 +11,26 @@ use crate::core::objective::ObjectiveSpace;
|
||||
/// uniform front has spacing 0.
|
||||
///
|
||||
/// Returns `0.0` for empty or single-point fronts (spec §14.1).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
/// use heuropt::metrics::spacing;
|
||||
///
|
||||
/// let space = ObjectiveSpace::new(vec![
|
||||
/// Objective::minimize("f1"),
|
||||
/// Objective::minimize("f2"),
|
||||
/// ]);
|
||||
/// // Five points evenly spaced on a line — spacing should be 0.
|
||||
/// let front: Vec<Candidate<()>> = (0..5)
|
||||
/// .map(|i| {
|
||||
/// let t = i as f64;
|
||||
/// Candidate::new((), Evaluation::new(vec![t, 4.0 - t]))
|
||||
/// })
|
||||
/// .collect();
|
||||
/// assert!(spacing(&front, &space) < 1e-12);
|
||||
/// ```
|
||||
pub fn spacing<D>(front: &[Candidate<D>], objectives: &ObjectiveSpace) -> f64 {
|
||||
let n = front.len();
|
||||
if n < 2 {
|
||||
|
||||
@@ -9,6 +9,19 @@ use crate::traits::Variation;
|
||||
///
|
||||
/// Always returns exactly one child (spec §11.3). Panics if `probability` is
|
||||
/// outside `[0.0, 1.0]` or if no parents are provided.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let mut rng = rng_from_seed(42);
|
||||
/// let mut m = BitFlipMutation { probability: 0.5 };
|
||||
/// let parent = vec![true, false, true, false];
|
||||
/// let children = m.vary(std::slice::from_ref(&parent), &mut rng);
|
||||
/// assert_eq!(children.len(), 1);
|
||||
/// assert_eq!(children[0].len(), parent.len());
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BitFlipMutation {
|
||||
/// Per-bit flip probability. Must lie in `[0.0, 1.0]`.
|
||||
|
||||
@@ -8,6 +8,22 @@ use crate::traits::Variation;
|
||||
/// Swap two distinct random indices in the first parent (spec §11.4).
|
||||
///
|
||||
/// If the parent has length `< 2` the child is returned unchanged.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let mut rng = rng_from_seed(42);
|
||||
/// let mut m = SwapMutation;
|
||||
/// let parent: Vec<usize> = (0..6).collect();
|
||||
/// let children = m.vary(std::slice::from_ref(&parent), &mut rng);
|
||||
/// assert_eq!(children.len(), 1);
|
||||
/// // Still a permutation of [0, 1, 2, 3, 4, 5]:
|
||||
/// let mut sorted = children[0].clone();
|
||||
/// sorted.sort();
|
||||
/// assert_eq!(sorted, vec![0, 1, 2, 3, 4, 5]);
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct SwapMutation;
|
||||
|
||||
|
||||
@@ -10,6 +10,23 @@ use crate::traits::{Initializer, Variation};
|
||||
///
|
||||
/// Bounds are inclusive `(lo, hi)` ranges per dimension. Panics if any bound
|
||||
/// has `lo > hi` (spec §11.1).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let mut rng = rng_from_seed(42);
|
||||
/// let mut init = RealBounds::new(vec![(-1.0, 1.0); 3]);
|
||||
/// let decisions = init.initialize(5, &mut rng);
|
||||
/// assert_eq!(decisions.len(), 5);
|
||||
/// for d in &decisions {
|
||||
/// assert_eq!(d.len(), 3);
|
||||
/// for &v in d {
|
||||
/// assert!(v >= -1.0 && v <= 1.0);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RealBounds {
|
||||
/// Per-variable inclusive bounds in decision order.
|
||||
@@ -54,6 +71,19 @@ impl Initializer<Vec<f64>> for RealBounds {
|
||||
/// Add `Normal(0, sigma)` noise to every variable of the first parent.
|
||||
///
|
||||
/// Always returns exactly one child. Does not enforce bounds in v1 (spec §11.2).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let mut rng = rng_from_seed(42);
|
||||
/// let mut m = GaussianMutation { sigma: 0.1 };
|
||||
/// let parent = vec![0.0; 4];
|
||||
/// let children = m.vary(std::slice::from_ref(&parent), &mut rng);
|
||||
/// assert_eq!(children.len(), 1);
|
||||
/// assert_eq!(children[0].len(), parent.len());
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GaussianMutation {
|
||||
/// Standard deviation of the Gaussian noise. Must be positive.
|
||||
@@ -88,6 +118,26 @@ impl Variation<Vec<f64>> for GaussianMutation {
|
||||
///
|
||||
/// Panics on construction if any bound has `lo > hi`, or at run time if
|
||||
/// `parents.len() < 2` or any parent length differs from `bounds.len()`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let bounds = vec![(-1.0, 1.0); 3];
|
||||
/// let mut sbx = SimulatedBinaryCrossover::new(bounds.clone(), 15.0, 0.5);
|
||||
/// let mut rng = rng_from_seed(42);
|
||||
/// let parents = [vec![-0.5, 0.0, 0.5], vec![0.5, 0.5, -0.5]];
|
||||
/// let children = sbx.vary(&parents, &mut rng);
|
||||
/// assert_eq!(children.len(), 2);
|
||||
/// // Children stay in bounds.
|
||||
/// for c in &children {
|
||||
/// for (j, &v) in c.iter().enumerate() {
|
||||
/// let (lo, hi) = bounds[j];
|
||||
/// assert!(v >= lo && v <= hi);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SimulatedBinaryCrossover {
|
||||
/// Per-variable inclusive bounds. Length must match the parent decisions.
|
||||
@@ -180,6 +230,23 @@ impl Variation<Vec<f64>> for SimulatedBinaryCrossover {
|
||||
///
|
||||
/// This is the simple bound-rescale form; the bound-aware `δ_q` variant from
|
||||
/// the full paper is left as a future refinement.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let bounds = vec![(-1.0, 1.0); 3];
|
||||
/// let mut pm = PolynomialMutation::new(bounds.clone(), 20.0, 1.0 / 3.0);
|
||||
/// let mut rng = rng_from_seed(42);
|
||||
/// let parent = vec![0.0, 0.5, -0.5];
|
||||
/// let children = pm.vary(std::slice::from_ref(&parent), &mut rng);
|
||||
/// assert_eq!(children.len(), 1);
|
||||
/// for (j, &v) in children[0].iter().enumerate() {
|
||||
/// let (lo, hi) = bounds[j];
|
||||
/// assert!(v >= lo && v <= hi);
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PolynomialMutation {
|
||||
/// Per-variable inclusive bounds. Length must match the parent decision.
|
||||
@@ -254,6 +321,23 @@ impl Variation<Vec<f64>> for PolynomialMutation {
|
||||
/// Always returns exactly one child. Use this when you want feasibility
|
||||
/// maintained across generations without leaning on
|
||||
/// clamp-inside-`Problem::evaluate`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let bounds = vec![(-1.0, 1.0); 3];
|
||||
/// let mut m = BoundedGaussianMutation::new(0.3, bounds.clone());
|
||||
/// let mut rng = rng_from_seed(42);
|
||||
/// let parent = vec![0.0; 3];
|
||||
/// let children = m.vary(std::slice::from_ref(&parent), &mut rng);
|
||||
/// assert_eq!(children.len(), 1);
|
||||
/// for (j, &v) in children[0].iter().enumerate() {
|
||||
/// let (lo, hi) = bounds[j];
|
||||
/// assert!(v >= lo && v <= hi);
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BoundedGaussianMutation {
|
||||
/// Standard deviation of the Gaussian noise. Must be positive.
|
||||
@@ -315,6 +399,23 @@ impl Variation<Vec<f64>> for BoundedGaussianMutation {
|
||||
/// produce a Lévy(α) sample. `alpha` is the tail exponent in `(0, 2]`;
|
||||
/// typical value is `1.5`. `1.0` gives the Cauchy distribution (very
|
||||
/// heavy); `2.0` collapses to the Normal.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let bounds = vec![(-1.0, 1.0); 3];
|
||||
/// let mut m = LevyMutation::new(1.5, 0.1, bounds.clone());
|
||||
/// let mut rng = rng_from_seed(42);
|
||||
/// let parent = vec![0.0; 3];
|
||||
/// let children = m.vary(std::slice::from_ref(&parent), &mut rng);
|
||||
/// assert_eq!(children.len(), 1);
|
||||
/// for (j, &v) in children[0].iter().enumerate() {
|
||||
/// let (lo, hi) = bounds[j];
|
||||
/// assert!(v >= lo && v <= hi);
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LevyMutation {
|
||||
/// Tail exponent `α ∈ (0, 2]`. Smaller = heavier tail.
|
||||
|
||||
@@ -8,6 +8,17 @@ use crate::traits::Repair;
|
||||
/// The simplest possible repair — pair with `GaussianMutation` (which
|
||||
/// doesn't enforce bounds in v1) to produce a bounds-respecting variant
|
||||
/// without writing a custom Variation impl.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let mut r = ClampToBounds::new(vec![(-1.0, 1.0); 3]);
|
||||
/// let mut x = vec![-2.0, 0.5, 5.0];
|
||||
/// r.repair(&mut x);
|
||||
/// assert_eq!(x, vec![-1.0, 0.5, 1.0]);
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ClampToBounds {
|
||||
/// Per-variable inclusive bounds.
|
||||
@@ -46,6 +57,19 @@ impl Repair<Vec<f64>> for ClampToBounds {
|
||||
/// Perpiñán 2013. Useful for portfolio-style problems where the
|
||||
/// decision must sum to a budget, and for normalizing reference
|
||||
/// directions onto the unit simplex.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let mut r = ProjectToSimplex::new(1.0);
|
||||
/// let mut x = vec![0.6, 0.5, -0.1, 0.3];
|
||||
/// r.repair(&mut x);
|
||||
/// let sum: f64 = x.iter().sum();
|
||||
/// assert!((sum - 1.0).abs() < 1e-12);
|
||||
/// assert!(x.iter().all(|&v| v >= 0.0));
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ProjectToSimplex {
|
||||
/// Target sum (the simplex's "size"). Standard probability simplex
|
||||
|
||||
@@ -9,6 +9,23 @@ use crate::core::objective::ObjectiveSpace;
|
||||
/// archive insert/extend operations maintain the non-domination property among
|
||||
/// members; `truncate` enforces a maximum size by simple tail-truncation in
|
||||
/// v1.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let s = ObjectiveSpace::new(vec![
|
||||
/// Objective::minimize("f1"),
|
||||
/// Objective::minimize("f2"),
|
||||
/// ]);
|
||||
/// let mut a: ParetoArchive<u32> = ParetoArchive::new(s);
|
||||
/// a.insert(Candidate::new(1, Evaluation::new(vec![1.0, 4.0])));
|
||||
/// a.insert(Candidate::new(2, Evaluation::new(vec![3.0, 2.0])));
|
||||
/// // Dominated by both — should be discarded:
|
||||
/// a.insert(Candidate::new(3, Evaluation::new(vec![5.0, 5.0])));
|
||||
/// assert_eq!(a.members().len(), 2);
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ParetoArchive<D> {
|
||||
/// The current approximate non-dominated set.
|
||||
|
||||
@@ -11,6 +11,28 @@ use crate::core::objective::ObjectiveSpace;
|
||||
/// `f64::INFINITY`. If the front has 0 entries an empty vector is returned;
|
||||
/// 1 or 2 entries return all `f64::INFINITY`. All comparisons happen on
|
||||
/// minimization-oriented objective values (spec §9.6).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let s = ObjectiveSpace::new(vec![
|
||||
/// Objective::minimize("f1"),
|
||||
/// Objective::minimize("f2"),
|
||||
/// ]);
|
||||
/// // Three points along a Pareto-like trade-off; the interior point gets
|
||||
/// // a finite crowding distance, the boundaries get +∞.
|
||||
/// let pop = [
|
||||
/// Candidate::new((), Evaluation::new(vec![0.0, 4.0])),
|
||||
/// Candidate::new((), Evaluation::new(vec![2.0, 2.0])),
|
||||
/// Candidate::new((), Evaluation::new(vec![4.0, 0.0])),
|
||||
/// ];
|
||||
/// let d = crowding_distance(&pop, &[0, 1, 2], &s);
|
||||
/// assert!(d[0].is_infinite());
|
||||
/// assert!(d[1].is_finite() && d[1] > 0.0);
|
||||
/// assert!(d[2].is_infinite());
|
||||
/// ```
|
||||
pub fn crowding_distance<D>(
|
||||
population: &[Candidate<D>],
|
||||
front: &[usize],
|
||||
|
||||
@@ -29,6 +29,21 @@ pub enum Dominance {
|
||||
/// `constraint_violation` dominates.
|
||||
/// 3. Otherwise compare objective values after converting both to
|
||||
/// minimization orientation via [`ObjectiveSpace::as_minimization`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let s = ObjectiveSpace::new(vec![
|
||||
/// Objective::minimize("f1"),
|
||||
/// Objective::minimize("f2"),
|
||||
/// ]);
|
||||
/// let a = Evaluation::new(vec![1.0, 1.0]);
|
||||
/// let b = Evaluation::new(vec![2.0, 2.0]);
|
||||
/// assert_eq!(pareto_compare(&a, &b, &s), Dominance::Dominates);
|
||||
/// assert_eq!(pareto_compare(&b, &a, &s), Dominance::DominatedBy);
|
||||
/// ```
|
||||
pub fn pareto_compare(a: &Evaluation, b: &Evaluation, objectives: &ObjectiveSpace) -> Dominance {
|
||||
let a_feasible = a.is_feasible();
|
||||
let b_feasible = b.is_feasible();
|
||||
|
||||
@@ -8,6 +8,25 @@ use crate::pareto::dominance::{Dominance, pareto_compare};
|
||||
///
|
||||
/// O(N²·M) in v1 (spec §9.3). Input order is preserved among returned
|
||||
/// candidates.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let s = ObjectiveSpace::new(vec![
|
||||
/// Objective::minimize("f1"),
|
||||
/// Objective::minimize("f2"),
|
||||
/// ]);
|
||||
/// let pop = [
|
||||
/// Candidate::new(1u32, Evaluation::new(vec![1.0, 4.0])), // non-dominated
|
||||
/// Candidate::new(2u32, Evaluation::new(vec![3.0, 2.0])), // non-dominated
|
||||
/// Candidate::new(3u32, Evaluation::new(vec![5.0, 5.0])), // dominated
|
||||
/// ];
|
||||
/// let front = pareto_front(&pop, &s);
|
||||
/// let kept: Vec<u32> = front.iter().map(|c| c.decision).collect();
|
||||
/// assert_eq!(kept, vec![1, 2]);
|
||||
/// ```
|
||||
pub fn pareto_front<D: Clone>(
|
||||
population: &[Candidate<D>],
|
||||
objectives: &ObjectiveSpace,
|
||||
@@ -34,6 +53,21 @@ pub fn pareto_front<D: Clone>(
|
||||
///
|
||||
/// Returns `None` if there is not exactly one objective, if the population is
|
||||
/// empty, or if every candidate is infeasible (spec §9.4).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let s = ObjectiveSpace::new(vec![Objective::minimize("f")]);
|
||||
/// let pop = [
|
||||
/// Candidate::new(1u32, Evaluation::new(vec![3.0])),
|
||||
/// Candidate::new(2u32, Evaluation::new(vec![1.0])),
|
||||
/// Candidate::new(3u32, Evaluation::new(vec![2.0])),
|
||||
/// ];
|
||||
/// let best = best_candidate(&pop, &s).unwrap();
|
||||
/// assert_eq!(best.decision, 2);
|
||||
/// ```
|
||||
pub fn best_candidate<D: Clone>(
|
||||
population: &[Candidate<D>],
|
||||
objectives: &ObjectiveSpace,
|
||||
|
||||
@@ -10,6 +10,21 @@
|
||||
///
|
||||
/// # Panics
|
||||
/// If `num_objectives == 0`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// // 3 objectives, 4 divisions → binomial(6, 2) = 15 points.
|
||||
/// let pts = das_dennis(3, 4);
|
||||
/// assert_eq!(pts.len(), 15);
|
||||
/// for w in &pts {
|
||||
/// assert_eq!(w.len(), 3);
|
||||
/// let sum: f64 = w.iter().sum();
|
||||
/// assert!((sum - 1.0).abs() < 1e-12);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn das_dennis(num_objectives: usize, divisions: usize) -> Vec<Vec<f64>> {
|
||||
assert!(
|
||||
num_objectives > 0,
|
||||
|
||||
@@ -9,6 +9,26 @@ use crate::core::objective::ObjectiveSpace;
|
||||
/// non-dominated after removing `fronts[0]`, and so on. Each entry is an index
|
||||
/// into the input population. Equal-objective candidates land on the same
|
||||
/// front. O(N²·M) is acceptable for v1 (spec §9.5).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use heuropt::prelude::*;
|
||||
///
|
||||
/// let s = ObjectiveSpace::new(vec![
|
||||
/// Objective::minimize("f1"),
|
||||
/// Objective::minimize("f2"),
|
||||
/// ]);
|
||||
/// let pop = [
|
||||
/// Candidate::new((), Evaluation::new(vec![1.0, 5.0])), // front 0
|
||||
/// Candidate::new((), Evaluation::new(vec![2.0, 3.0])), // front 0
|
||||
/// Candidate::new((), Evaluation::new(vec![4.0, 1.0])), // front 0
|
||||
/// Candidate::new((), Evaluation::new(vec![3.0, 4.0])), // front 1
|
||||
/// Candidate::new((), Evaluation::new(vec![5.0, 6.0])), // front 2
|
||||
/// ];
|
||||
/// let fronts = non_dominated_sort(&pop, &s);
|
||||
/// assert_eq!(fronts.len(), 3);
|
||||
/// ```
|
||||
pub fn non_dominated_sort<D>(
|
||||
population: &[Candidate<D>],
|
||||
objectives: &ObjectiveSpace,
|
||||
|
||||
Reference in New Issue
Block a user