MinimizerCorpusScheduler skeleton

This commit is contained in:
Andrea Fioraldi 2021-02-25 15:34:35 +01:00
parent 58841ed82e
commit 705196fe32
3 changed files with 109 additions and 198 deletions

View File

@ -1,225 +1,127 @@
use alloc::{borrow::ToOwned, vec::Vec};
use core::{cell::RefCell, iter::Iterator, marker::PhantomData};
use serde::{Deserialize, Serialize};
use core::marker::PhantomData;
use crate::{
corpus::Corpus, corpus::HasTestcaseVec, corpus::Testcase, inputs::{HasLen, Input}, utils::Rand, Error,
corpus::{Corpus, CorpusScheduler, Testcase},
inputs::{HasLen, Input},
state::HasCorpus,
Error,
};
pub trait FavFactor: Serialize + serde::de::DeserializeOwned + 'static
{
fn compute<I>(testcase: &Testcase<I>) -> Result<u64, Error>
where
I: Input;
}
pub struct LenTimeMulFavFactor {}
// TODO time as Duration and put len into Testcase
impl FavFactor for LenTimeMulFavFactor {
fn compute<I>(entry: &Testcase<I>) -> Result<u64, Error>
where
I: Input + HasLen
{
entry.exec_time().as_usec() * (entry.cached_len()? as u64)
}
}
pub trait CorpusMinimizer {
fn update_score<C, I, R>(corpus: &mut C, idx: usize) -> Result<(), Error>
where
C: Corpus<I, R>,
I: Input,
R: Rand;
fn cull<C, I, R>(corpus: &mut C) -> Result<(), Error>
where
C: Corpus<I, R>,
I: Input,
R: Rand;
}
pub struct FavCorpusMinimizer<F>
pub trait FavFactor<I>
where
F: FavFactor
{
phantom: PhantomData<F>
}
impl<F> CorpusMinimizer for FavCorpusMinimizer<F>
where
F: FavFactor
{
fn update_score<C, I, R>(corpus: &mut C, idx: usize) -> Result<(), Error>
where
C: Corpus<I, R>,
I: Input,
R: Rand
{
}
fn cull<C, I, R>(corpus: &mut C) -> Result<(), Error>
where
C: Corpus<I, R>,
I: Input,
R: Rand
{
}
}
#[derive(Serialize, Deserialize)]
pub struct NoveltiesMeta {
novelties: Vec<usize>,
}
// impl Iterator<Item = usize>
/// A Queue-like corpus, wrapping an existing Corpus instance
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct MinSetCorpus<C, F, I, IT, R, T>
where
C: Corpus<I, R>,
F: FavFactor,
I: Input,
IT: Iterator<Item = T>,
R: Rand,
{
corpus: C,
pos: usize,
// TODO rebase minset on remove()
minset: HashSet<usize>,
top_rated: HashMap<T, usize>,
phantom: PhantomData<(F, I, IT, R)>,
fn compute(testcase: &mut Testcase<I>) -> Result<u64, Error>;
}
impl<C, I, R> HasTestcaseVec<I> for MinSetCorpus<C, I, R>
pub struct LenTimeMulFavFactor<I>
where
C: Corpus<I, R>,
I: Input,
R: Rand,
I: Input + HasLen,
{
#[inline]
fn entries(&self) -> &[RefCell<Testcase<I>>] {
self.corpus.entries()
}
#[inline]
fn entries_mut(&mut self) -> &mut Vec<RefCell<Testcase<I>>> {
self.corpus.entries_mut()
phantom: PhantomData<I>,
}
impl<I> FavFactor<I> for LenTimeMulFavFactor<I>
where
I: Input + HasLen,
{
fn compute(entry: &mut Testcase<I>) -> Result<u64, Error> {
Ok(entry.exec_time().map_or(1, |d| d.as_millis()) as u64 * entry.cached_len()? as u64)
}
}
impl<C, I, R> Corpus<I, R> for MinSetCorpus<C, I, R>
pub struct MinimizerCorpusScheduler<C, CS, F, I, S>
where
C: Corpus<I, R>,
I: Input,
R: Rand,
CS: CorpusScheduler<I, S>,
F: FavFactor<I>,
I: Input,
S: HasCorpus<C, I>,
C: Corpus<I>
{
/// Returns the number of elements
#[inline]
fn count(&self) -> usize {
self.corpus.count()
base: CS,
phantom: PhantomData<(C, F, I, S)>,
}
impl<C, CS, F, I, S> CorpusScheduler<I, S> for MinimizerCorpusScheduler<C, CS, F, I, S>
where
CS: CorpusScheduler<I, S>,
F: FavFactor<I>,
I: Input,
S: HasCorpus<C, I>,
C: Corpus<I>
{
/// Add an entry to the corpus and return its index
fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> {
self.base.on_add(state, idx)
}
// TODO change add to return Result
#[inline]
fn add(&mut self, entry: Testcase<I>) -> usize {
let idx = self.corpus.add(entry);
self.update_score(idx).unwrap();
idx
/// Replaces the testcase at the given idx
fn on_replace(&self, state: &mut S, idx: usize, testcase: &Testcase<I>) -> Result<(), Error> {
self.base.on_replace(state, idx, testcase)
}
/// Removes an entry from the corpus, returning it if it was present.
#[inline]
fn remove(&mut self, entry: &Testcase<I>) -> Option<Testcase<I>> {
self.corpus.remove(entry)
}
/// Gets a random entry
#[inline]
fn random_entry(&self, rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), Error> {
self.corpus.random_entry(rand)
}
/// Returns the testacase we currently use
#[inline]
fn current_testcase(&self) -> (&RefCell<Testcase<I>>, usize) {
(self.get(self.pos - 1), self.pos - 1)
fn on_remove(
&self,
state: &mut S,
idx: usize,
testcase: &Option<Testcase<I>>,
) -> Result<(), Error> {
self.base.on_remove(state, idx, testcase)
}
// TODO: IntoIter
/// Gets the next entry
#[inline]
fn next(&mut self, _rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), Error> {
self.cull();
self.pos += 1;
if self.corpus.count() == 0 {
return Err(Error::Empty("Corpus".to_owned()));
}
if self.pos > self.corpus.count() {
// TODO: Always loop or return informational error?
self.pos = 1;
self.cycles += 1;
}
Ok((&self.corpus.entries()[self.pos - 1], self.pos - 1))
fn next(&self, state: &mut S) -> Result<usize, Error> {
self.base.next(state)
}
}
impl<C, I, R> MinSetCorpus<C, I, R>
impl<C, CS, F, I, S> MinimizerCorpusScheduler<C, CS, F, I, S>
where
C: Corpus<I, R>,
CS: CorpusScheduler<I, S>,
F: FavFactor<I>,
I: Input,
R: Rand,
S: HasCorpus<C, I>,
C: Corpus<I>
{
pub fn new(corpus: C) -> Self {
Self {
corpus: corpus,
phantom: PhantomData,
}
}
#[inline]
pub fn corpus(&self) -> &C {
&self.corpus
}
#[inline]
pub fn corpus_mut(&mut self) -> &mut C {
&mut self.corpus
}
// TODO move this functions and top rated to another struct
// create something like MinSetCorpus<.., FavMinimizer<LenTimeMulFavFactor>>
pub fn update_score(&mut self, idx: usize) -> Result<(), Error> {
let factor = F::compute(self.entries()[idx].borrow())?;
/*pub fn update_score(&self, state: &mut S, idx: usize) -> Result<(), Error> {
let entry = state.corpus().get(idx)?.borrow_mut();
let factor = F::compute(&mut *entry)?;
for elem in entry.get::<IT>() {
if let val = self.top_rated.get_mut(elem) {
if factor > F::compute(self.entries()[val].borrow())? {
continue
}
}
let _ = self.top_rated.insert(elem, idx);
}
}
pub fn cull(&mut self) {
let mut acc = HashSet::new();
self.minset.clear();
}*/
for key in self.top_rated.keys() {
if !acc.contains(key) {
let idx = self.top_rated.get(key).unwrap();
let entry = self.entries()[idx].borrow();
for elem in entry.get::<IT>() {
acc.insert(elem);
}
self.minset.insert(idx);
}
pub fn new(base: CS) -> Self {
Self {
base: base,
phantom: PhantomData,
}
}
}
/*
pub fn cull(&mut self) {
let mut acc = HashSet::new();
self.minset.clear();
for key in self.top_rated.keys() {
if !acc.contains(key) {
let idx = self.top_rated.get(key).unwrap();
let entry = self.entries()[idx].borrow();
for elem in entry.get::<IT>() {
acc.insert(elem);
}
self.minset.insert(idx);
}
}
}
*/

View File

@ -14,6 +14,7 @@ pub use ondisk::OnDiskCorpus;
pub mod queue;
pub use queue::QueueCorpusScheduler;
pub mod minset;
use core::cell::RefCell;
use core::marker::PhantomData;
@ -56,7 +57,7 @@ where
I: Input,
{
/// Add an entry to the corpus and return its index
fn on_add(&self, _state: &mut S, _idx: usize, _testcase: &Testcase<I>) -> Result<(), Error> {
fn on_add(&self, _state: &mut S, _idx: usize) -> Result<(), Error> {
Ok(())
}

View File

@ -29,7 +29,7 @@ where
/// Time needed to execute the input
exec_time: Option<Duration>,
/// Cached len of the input, if any
cached_len: Option<usize>
cached_len: Option<usize>,
}
/// Impl of a testcase
@ -135,6 +135,16 @@ where
self.metadatas.insert(meta);
}
/// Get the execution time of the testcase
pub fn exec_time(&self) -> &Option<Duration> {
&self.exec_time
}
/// Get the execution time of the testcase (mut)
pub fn exec_time_mut(&mut self) -> &mut Option<Duration> {
&mut self.exec_time
}
/// Create a new Testcase instace given an input
#[inline]
pub fn new<T>(input: T) -> Self
@ -147,7 +157,7 @@ where
fitness: 0,
metadatas: SerdeAnyMap::new(),
exec_time: None,
cached_len: None
cached_len: None,
}
}
@ -160,7 +170,7 @@ where
fitness: 0,
metadatas: SerdeAnyMap::new(),
exec_time: None,
cached_len: None
cached_len: None,
}
}
@ -173,7 +183,7 @@ where
fitness: fitness,
metadatas: SerdeAnyMap::new(),
exec_time: None,
cached_len: None
cached_len: None,
}
}
@ -185,7 +195,7 @@ where
fitness: 0,
metadatas: SerdeAnyMap::new(),
exec_time: None,
cached_len: None
cached_len: None,
}
}
}
@ -203,17 +213,15 @@ where
let l = i.len();
self.cached_len = Some(l);
l
},
None => {
match self.cached_len {
Some(l) => l,
None => {
let l = self.load_input()?.len();
self.cached_len = Some(l);
l
}
}
}
None => match self.cached_len {
Some(l) => l,
None => {
let l = self.load_input()?.len();
self.cached_len = Some(l);
l
}
},
})
}
}