59 lines
1.6 KiB
Rust
59 lines
1.6 KiB
Rust
#![no_main]
|
|
//! Fuzz `ParetoArchive` for the non-domination invariant under arbitrary
|
|
//! insertion/truncation sequences.
|
|
|
|
use arbitrary::Arbitrary;
|
|
use libfuzzer_sys::fuzz_target;
|
|
|
|
use heuropt::core::candidate::Candidate;
|
|
use heuropt::core::evaluation::Evaluation;
|
|
use heuropt::core::objective::{Objective, ObjectiveSpace};
|
|
use heuropt::pareto::archive::ParetoArchive;
|
|
use heuropt::pareto::dominance::{Dominance, pareto_compare};
|
|
|
|
#[derive(Arbitrary, Debug)]
|
|
enum Op {
|
|
Insert(f64, f64),
|
|
Truncate(u8),
|
|
}
|
|
|
|
#[derive(Arbitrary, Debug)]
|
|
struct Input {
|
|
ops: Vec<Op>,
|
|
}
|
|
|
|
fuzz_target!(|input: Input| {
|
|
if input.ops.len() > 64 {
|
|
return;
|
|
}
|
|
let space = ObjectiveSpace::new(vec![Objective::minimize("f1"), Objective::minimize("f2")]);
|
|
let mut archive: ParetoArchive<()> = ParetoArchive::new(space.clone());
|
|
|
|
for op in input.ops {
|
|
match op {
|
|
Op::Insert(a, b) => {
|
|
let cand = Candidate::new((), Evaluation::new(vec![a, b]));
|
|
archive.insert(cand);
|
|
}
|
|
Op::Truncate(n) => archive.truncate(n as usize),
|
|
}
|
|
}
|
|
|
|
// Members must be pairwise non-dominated.
|
|
let m = archive.members();
|
|
for i in 0..m.len() {
|
|
for j in 0..m.len() {
|
|
if i == j {
|
|
continue;
|
|
}
|
|
let r = pareto_compare(&m[i].evaluation, &m[j].evaluation, &space);
|
|
assert!(
|
|
!matches!(r, Dominance::DominatedBy),
|
|
"archive member {i} dominated by {j}: {:?} vs {:?}",
|
|
m[i].evaluation.objectives,
|
|
m[j].evaluation.objectives,
|
|
);
|
|
}
|
|
}
|
|
});
|