Struct CachedChallenge

Source
pub struct CachedChallenge<P, C>
where P: CacheKey, C: Challenge<P>,
{ /* private fields */ }
Expand description

A challenge wrapper that caches fitness evaluations.

This struct wraps a challenge and caches the results of fitness evaluations to avoid redundant calculations. It uses a thread-safe mutex-protected cache, making it suitable for both single-threaded and multi-threaded environments.

§Performance Considerations

  • The cache is protected by a mutex, which can become a bottleneck in highly parallel scenarios
  • Consider using ThreadLocalCachedChallenge for better parallel performance
  • The cache grows unbounded, so consider calling clear_cache() periodically for long-running evolutions

§Examples

use genalg::caching::{CacheKey, CachedChallenge};
use genalg::evolution::Challenge;
use genalg::phenotype::Phenotype;
use genalg::rng::RandomNumberGenerator;

// Define a phenotype
#[derive(Clone, Debug)]
struct MyPhenotype {
    value: f64,
}

impl Phenotype for MyPhenotype {
    fn crossover(&mut self, other: &Self) {
        self.value = (self.value + other.value) / 2.0;
    }

    fn mutate(&mut self, _rng: &mut RandomNumberGenerator) {
        self.value += 0.1;
    }
}

// Implement CacheKey for the phenotype
impl CacheKey for MyPhenotype {
    type Key = i64;

    fn cache_key(&self) -> Self::Key {
        (self.value * 1000.0).round() as i64
    }
}

// Define a challenge
struct ExpensiveChallenge;

impl Challenge<MyPhenotype> for ExpensiveChallenge {
    fn score(&self, phenotype: &MyPhenotype) -> f64 {
        // Simulate an expensive computation
        std::thread::sleep(std::time::Duration::from_millis(10));
        (phenotype.value - 5.0).powi(2)
    }
}

// Create a cached version of the challenge
let challenge = ExpensiveChallenge;
let cached_challenge = CachedChallenge::new(challenge);

// First evaluation (computed and cached)
let phenotype = MyPhenotype { value: 3.0 };
let score1 = cached_challenge.score(&phenotype);

// Second evaluation of the same phenotype (retrieved from cache)
let score2 = cached_challenge.score(&phenotype);

// The scores should be identical
assert_eq!(score1, score2);

// Check the cache size
assert_eq!(cached_challenge.cache_size(), 1);

// Clear the cache if needed
cached_challenge.clear_cache();
assert_eq!(cached_challenge.cache_size(), 0);

Implementations§

Source§

impl<P, C> CachedChallenge<P, C>
where P: CacheKey, C: Challenge<P>,

Source

pub fn new(challenge: C) -> Self

Creates a new cached challenge wrapper.

This constructor creates a new cached challenge with an empty cache. The cache will be populated as fitness evaluations are performed.

§Arguments
  • challenge - The challenge to wrap with caching functionality.
§Returns

A new CachedChallenge instance that wraps the provided challenge.

§Examples
let challenge = MyChallenge;
let cached_challenge = CachedChallenge::new(challenge);
Source

pub fn with_cache(challenge: C, cache: HashMap<P::Key, f64>) -> Self

Creates a new cached challenge with a pre-populated cache.

This constructor allows you to initialize the cache with pre-computed values, which can be useful for resuming a previous evolution or for testing.

§Arguments
  • challenge - The challenge to wrap with caching functionality.
  • cache - A HashMap containing pre-computed fitness values.
§Returns

A new CachedChallenge instance with the provided cache.

§Examples
// Create a pre-populated cache
let mut cache = HashMap::new();
cache.insert(3000, 4.0); // Key for value 3.0, pre-computed score 4.0

let challenge = MyChallenge;
let cached_challenge = CachedChallenge::with_cache(challenge, cache);

// The pre-computed value is already in the cache
let phenotype = MyPhenotype { value: 3.0 };
let score = cached_challenge.score(&phenotype);
assert_eq!(score, 4.0);
Source

pub fn inner(&self) -> &C

Returns a reference to the wrapped challenge.

This method provides access to the underlying challenge, which can be useful for inspecting or modifying its properties.

§Returns

A reference to the wrapped challenge.

§Examples
let challenge = MyChallenge { difficulty: 2.0 };
let cached_challenge = CachedChallenge::new(challenge);

// Access the inner challenge
assert_eq!(cached_challenge.inner().difficulty, 2.0);
Source

pub fn cache_size(&self) -> usize

Returns the current size of the cache.

This method returns the number of entries in the cache, which can be useful for monitoring cache usage.

§Returns

The number of entries in the cache.

§Examples
let challenge = MyChallenge;
let cached_challenge = CachedChallenge::new(challenge);

// Initially, the cache is empty
assert_eq!(cached_challenge.cache_size(), 0);

// After scoring a phenotype, the cache has one entry
let phenotype = MyPhenotype { value: 3.0 };
cached_challenge.score(&phenotype);
assert_eq!(cached_challenge.cache_size(), 1);
Source

pub fn clear_cache(&self)

Clears the cache, removing all entries.

This method removes all entries from the cache, which can be useful for freeing memory or resetting the cache after a significant change in the fitness landscape.

§Examples
let challenge = MyChallenge;
let cached_challenge = CachedChallenge::new(challenge);

// Add some entries to the cache
let phenotype1 = MyPhenotype { value: 3.0 };
let phenotype2 = MyPhenotype { value: 4.0 };
cached_challenge.score(&phenotype1);
cached_challenge.score(&phenotype2);
assert_eq!(cached_challenge.cache_size(), 2);

// Clear the cache
cached_challenge.clear_cache();
assert_eq!(cached_challenge.cache_size(), 0);
Source

pub fn get_cache(&self) -> HashMap<P::Key, f64>

Returns a copy of the current cache.

This method provides access to the current state of the cache, which can be useful for inspecting the cached values, saving the cache state for later use, or transferring the cache to another CachedChallenge instance.

§Returns

A HashMap containing the cache keys and their corresponding fitness values.

§Examples
let challenge = MyChallenge;
let cached_challenge = CachedChallenge::new(challenge);

// Add some entries to the cache
let phenotype1 = MyPhenotype { value: 3.0 };
let phenotype2 = MyPhenotype { value: 4.0 };
cached_challenge.score(&phenotype1);
cached_challenge.score(&phenotype2);

// Get the current cache state
let cache = cached_challenge.get_cache();
assert_eq!(cache.len(), 2);
assert_eq!(*cache.get(&3000).unwrap(), 3.0); // Key is rounded value * 1000
assert_eq!(*cache.get(&4000).unwrap(), 4.0);

// The cache can be used to create a new CachedChallenge with the same cache state
let new_challenge = MyChallenge;
let new_cached_challenge = CachedChallenge::with_cache(new_challenge, cache);

Trait Implementations§

Source§

impl<P, C> Challenge<P> for CachedChallenge<P, C>
where P: CacheKey, C: Challenge<P>,

Source§

fn score(&self, phenotype: &P) -> f64

Calculates the fitness score of a given phenotype. Read more
Source§

impl<P, C> Clone for CachedChallenge<P, C>
where P: CacheKey + Clone, C: Challenge<P> + Clone, P::Key: Clone,

Source§

fn clone(&self) -> CachedChallenge<P, C>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<P, C> Debug for CachedChallenge<P, C>
where P: CacheKey + Debug, C: Challenge<P> + Debug, P::Key: Debug,

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<P, C> Freeze for CachedChallenge<P, C>
where C: Freeze,

§

impl<P, C> RefUnwindSafe for CachedChallenge<P, C>
where C: RefUnwindSafe,

§

impl<P, C> Send for CachedChallenge<P, C>

§

impl<P, C> Sync for CachedChallenge<P, C>

§

impl<P, C> Unpin for CachedChallenge<P, C>
where C: Unpin,

§

impl<P, C> UnwindSafe for CachedChallenge<P, C>
where C: UnwindSafe,

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<P, C> CachingChallenge<P> for C
where P: Phenotype, C: Challenge<P> + Clone,

Source§

fn with_global_cache(&self) -> CachedChallenge<P, C>
where P: CacheKey,

Wraps this challenge with a global cache. Read more
Source§

fn with_thread_local_cache(&self) -> ThreadLocalCachedChallenge<P, C>
where P: CacheKey,

Wraps this challenge with a thread-local cache. Read more
Source§

fn with_cache(&self, cache_type: CacheType) -> Box<dyn Challenge<P>>
where P: CacheKey + 'static, Self: 'static,

Wraps this challenge with a cache of the specified type. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. 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

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more