pub struct CachedChallenge<P, C>{ /* 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
ThreadLocalCachedChallengefor 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>
impl<P, C> CachedChallenge<P, C>
Sourcepub fn new(challenge: C) -> Self
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);Sourcepub fn with_cache(challenge: C, cache: HashMap<P::Key, f64>) -> Self
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);Sourcepub fn inner(&self) -> &C
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);Sourcepub fn cache_size(&self) -> usize
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);Sourcepub fn clear_cache(&self)
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);Sourcepub fn get_cache(&self) -> HashMap<P::Key, f64>
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>
impl<P, C> Challenge<P> for CachedChallenge<P, C>
Source§impl<P, C> Clone for CachedChallenge<P, C>
impl<P, C> Clone for CachedChallenge<P, C>
Source§fn clone(&self) -> CachedChallenge<P, C>
fn clone(&self) -> CachedChallenge<P, C>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto 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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<P, C> CachingChallenge<P> for C
impl<P, C> CachingChallenge<P> for C
Source§fn with_global_cache(&self) -> CachedChallenge<P, C>where
P: CacheKey,
fn with_global_cache(&self) -> CachedChallenge<P, C>where
P: CacheKey,
Source§fn with_thread_local_cache(&self) -> ThreadLocalCachedChallenge<P, C>where
P: CacheKey,
fn with_thread_local_cache(&self) -> ThreadLocalCachedChallenge<P, C>where
P: CacheKey,
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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