-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmutate_random_synapse_weight.rs
More file actions
107 lines (100 loc) · 3.9 KB
/
mutate_random_synapse_weight.rs
File metadata and controls
107 lines (100 loc) · 3.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//! Command and handler for mutating the weight of a random synapse.
//!
//! The mutation adds Gaussian noise with a configurable standard deviation to
//! the existing weight. A corresponding [`SynapseWeightMutated`] event is
//! emitted, persisted, and applied to the domain.
use rand::{seq::SliceRandom, Rng};
use rand_distr::{Distribution, Normal};
use uuid::Uuid;
use super::NetworkHandlerBase;
use crate::domain::{Event, SynapseWeightMutated};
use crate::infrastructure::EventStore;
/// Command requesting mutation of a random synapse weight.
#[derive(Debug, Clone, Copy)]
pub struct MutateRandomSynapseWeightCommand {
/// Standard deviation of the Gaussian noise to add to the weight.
pub std_dev: f64,
}
/// Errors that can occur while mutating a synapse weight.
#[derive(Debug, Clone, PartialEq)]
pub enum MutateRandomSynapseWeightError {
/// The network does not contain any synapse to mutate.
NoSynapseAvailable,
/// The provided standard deviation is not valid (must be positive).
InvalidStdDev,
/// Persisting the event failed.
StorageError,
}
/// Handles [`MutateRandomSynapseWeightCommand`], emitting and applying
/// [`SynapseWeightMutated`] events.
pub struct MutateRandomSynapseWeightHandler<S: EventStore, R: Rng> {
/// Shared handler state including store, network and RNG.
pub base: NetworkHandlerBase<S, R>,
}
impl<S: EventStore, R: Rng> MutateRandomSynapseWeightHandler<S, R> {
/// Loads events from the store to initialize the handler.
pub fn new(store: S, rng: R) -> Result<Self, S::Error> {
Ok(Self {
base: NetworkHandlerBase::new(store, rng)?,
})
}
/// Handles the command and returns the identifier of the mutated synapse.
///
/// # Errors
/// Returns [`MutateRandomSynapseWeightError::NoSynapseAvailable`] if the
/// network contains no synapse, [`MutateRandomSynapseWeightError::InvalidStdDev`]
/// if the provided standard deviation is non-positive, and
/// [`MutateRandomSynapseWeightError::StorageError`] if persisting the event
/// fails.
///
/// # Examples
/// ```
/// use aei_framework::{
/// MutateRandomSynapseWeightCommand, MutateRandomSynapseWeightHandler, FileEventStore,
/// };
/// use rand::thread_rng;
/// use std::path::PathBuf;
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let store = FileEventStore::new(PathBuf::from("events.log"));
/// let mut handler = MutateRandomSynapseWeightHandler::new(store, thread_rng())?;
/// let _ = handler.handle(MutateRandomSynapseWeightCommand { std_dev: 0.1 });
/// # Ok(()) }
/// ```
pub fn handle(
&mut self,
cmd: MutateRandomSynapseWeightCommand,
) -> Result<Uuid, MutateRandomSynapseWeightError> {
if cmd.std_dev <= 0.0 {
return Err(MutateRandomSynapseWeightError::InvalidStdDev);
}
let base = &mut self.base;
let ids: Vec<Uuid> = base.network.synapses.keys().copied().collect();
if ids.is_empty() {
return Err(MutateRandomSynapseWeightError::NoSynapseAvailable);
}
let synapse_id = *ids
.choose(&mut base.rng)
.expect("candidate list is non-empty");
let old_weight = base
.network
.synapses
.get(&synapse_id)
.expect("synapse exists")
.weight;
let normal = Normal::new(0.0, cmd.std_dev)
.map_err(|_| MutateRandomSynapseWeightError::InvalidStdDev)?;
let noise = normal.sample(&mut base.rng);
let new_weight = old_weight + noise;
let event = Event::SynapseWeightMutated(SynapseWeightMutated {
synapse_id,
old_weight,
new_weight,
});
base.store
.append(&event)
.map_err(|_| MutateRandomSynapseWeightError::StorageError)?;
base.network.apply(&event);
Ok(synapse_id)
}
}