psyche_core/
brain.rs

1use crate::config::Config;
2use crate::effector::{Effector, EffectorID};
3use crate::error::*;
4use crate::id::ID;
5use crate::neuron::{Impulse, Neuron, NeuronID, Position, Synapse};
6use crate::sensor::{Sensor, SensorID};
7use crate::Scalar;
8use rand::{thread_rng, Rng};
9#[cfg(feature = "parallel")]
10use rayon::prelude::*;
11use serde::{Deserialize, Serialize};
12use std::ops::Range;
13
14#[cfg(feature = "parallel")]
15macro_rules! iter {
16    ($v:expr) => {
17        $v.par_iter()
18    };
19}
20#[cfg(not(feature = "parallel"))]
21macro_rules! iter {
22    ($v:expr) => {
23        $v.iter()
24    };
25}
26
27#[cfg(feature = "parallel")]
28macro_rules! iter_mut {
29    ($v:expr) => {
30        $v.par_iter_mut()
31    };
32}
33#[cfg(not(feature = "parallel"))]
34macro_rules! iter_mut {
35    ($v:expr) => {
36        $v.iter_mut()
37    };
38}
39
40pub mod activity {
41    pub const NONE: usize = 0;
42    pub const CONNECTIONS: usize = 1;
43    pub const IMPULSES: usize = 1 << 1;
44    pub const SENSORS: usize = 1 << 2;
45    pub const EFFECTORS: usize = 1 << 3;
46    pub const NEURONS: usize = 1 << 4;
47    pub const ALL: usize = 0xFF;
48}
49
50pub type BrainID = ID<Brain>;
51
52#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
53#[repr(C)]
54pub struct BrainActivityMap {
55    // (point from, point to, receptors)
56    pub connections: Vec<(Position, Position, Scalar)>,
57    // (point from, point to, factor)
58    pub impulses: Vec<(Position, Position, Scalar)>,
59    // point
60    pub sensors: Vec<Position>,
61    // point
62    pub effectors: Vec<Position>,
63    // point
64    pub neurons: Vec<Position>,
65}
66
67#[derive(Debug, Clone)]
68#[repr(C)]
69pub struct BrainActivityStats {
70    pub neurons_count: usize,
71    pub synapses_count: usize,
72    pub impulses_count: usize,
73    // (current, min..max)
74    pub neurons_potential: (Scalar, Range<Scalar>),
75    // (current, min..max)
76    pub impulses_potential: (Scalar, Range<Scalar>),
77    // (current, min..max)
78    pub all_potential: (Scalar, Range<Scalar>),
79    // min..max
80    pub incoming_neuron_connections: Range<usize>,
81    // min..max
82    pub outgoing_neuron_connections: Range<usize>,
83    // min..max
84    pub synapses_receptors: Range<Scalar>,
85}
86
87impl Default for BrainActivityStats {
88    fn default() -> Self {
89        Self {
90            neurons_count: 0,
91            synapses_count: 0,
92            impulses_count: 0,
93            neurons_potential: (0.0, 0.0..0.0),
94            impulses_potential: (0.0, 0.0..0.0),
95            all_potential: (0.0, 0.0..0.0),
96            incoming_neuron_connections: 0..0,
97            outgoing_neuron_connections: 0..0,
98            synapses_receptors: 0.0..0.0,
99        }
100    }
101}
102
103#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
104pub struct Brain {
105    id: BrainID,
106    neurons: Vec<Neuron>,
107    synapses: Vec<Synapse>,
108    sensors: Vec<Sensor>,
109    effectors: Vec<Effector>,
110    config: Config,
111    new_connections_accum: Scalar,
112}
113
114impl Brain {
115    pub fn new() -> Self {
116        Self::default()
117    }
118
119    pub fn duplicate(&self) -> Self {
120        let id = Default::default();
121        let neuron_indices = iter!(self.neurons).map(|n| n.id()).collect::<Vec<_>>();
122        let neurons = iter!(self.neurons)
123            .map(|n| Neuron::new(id, n.position()))
124            .collect::<Vec<_>>();
125        let synapses = iter!(self.synapses)
126            .map(|s| {
127                #[cfg(feature = "parallel")]
128                let sindex = neuron_indices
129                    .par_iter()
130                    .position_any(|n| *n == s.source)
131                    .unwrap();
132                #[cfg(not(feature = "parallel"))]
133                let sindex = neuron_indices.iter().position(|n| *n == s.source).unwrap();
134                #[cfg(feature = "parallel")]
135                let nindex = neuron_indices
136                    .par_iter()
137                    .position_any(|n| *n == s.target)
138                    .unwrap();
139                #[cfg(not(feature = "parallel"))]
140                let nindex = neuron_indices.iter().position(|n| *n == s.target).unwrap();
141                Synapse {
142                    source: neurons[sindex].id(),
143                    target: neurons[nindex].id(),
144                    distance: s.distance,
145                    receptors: s.receptors,
146                    impulses: vec![],
147                    inactivity: 0.0,
148                }
149            })
150            .collect::<Vec<_>>();
151        let sensors = iter!(self.sensors)
152            .map(|s| {
153                #[cfg(feature = "parallel")]
154                let index = neuron_indices
155                    .par_iter()
156                    .position_any(|n| *n == s.target)
157                    .unwrap();
158                #[cfg(not(feature = "parallel"))]
159                let index = neuron_indices.iter().position(|n| *n == s.target).unwrap();
160                Sensor {
161                    id: s.id,
162                    target: neurons[index].id(),
163                }
164            })
165            .collect::<Vec<_>>();
166        let effectors = iter!(self.effectors)
167            .map(|e| {
168                #[cfg(feature = "parallel")]
169                let index = neuron_indices
170                    .par_iter()
171                    .position_any(|n| *n == e.source)
172                    .unwrap();
173                #[cfg(not(feature = "parallel"))]
174                let index = neuron_indices.iter().position(|n| *n == e.source).unwrap();
175                Effector {
176                    id: e.id,
177                    source: neurons[index].id(),
178                    potential: 0.0,
179                }
180            })
181            .collect::<Vec<_>>();
182        Self {
183            id,
184            neurons,
185            synapses,
186            sensors,
187            effectors,
188            config: self.config.clone(),
189            new_connections_accum: 0.0,
190        }
191    }
192
193    pub fn merge(&self, other: &Self) -> Self {
194        let mut rng = thread_rng();
195        let id = Default::default();
196        let brain_a = self.duplicate();
197        let brain_b = other.duplicate();
198        let neurons_count = (brain_a.neurons.len() + brain_b.neurons.len()) / 2;
199        let synapses_count = (brain_a.synapses.len() + brain_b.synapses.len()) / 2;
200        let sensors_count = (brain_a.sensors.len() + brain_b.sensors.len()) / 2;
201        let effectors_count = (brain_a.effectors.len() + brain_b.effectors.len()) / 2;
202        let neurons = brain_a
203            .neurons
204            .iter()
205            .chain(brain_b.neurons.iter())
206            .map(|n| Neuron::with_id(n.id(), id, n.position()))
207            .collect();
208        let synapses = brain_a
209            .synapses
210            .iter()
211            .chain(brain_b.synapses.iter())
212            .cloned()
213            .collect();
214        let sensors = brain_a
215            .sensors
216            .iter()
217            .chain(brain_b.sensors.iter())
218            .cloned()
219            .collect();
220        let effectors = brain_a
221            .effectors
222            .iter()
223            .chain(brain_b.effectors.iter())
224            .cloned()
225            .collect();
226        let mut brain = Self {
227            id,
228            neurons,
229            synapses,
230            sensors,
231            effectors,
232            config: brain_a.config().merge(brain_b.config()),
233            new_connections_accum: 0.0,
234        };
235        while brain.neurons.len() > neurons_count {
236            if brain
237                .kill_neuron(
238                    brain.neurons[rng.gen_range(0, brain.neurons.len()) % brain.neurons.len()].id(),
239                )
240                .is_err()
241            {
242                break;
243            }
244        }
245        while brain.sensors.len() > sensors_count {
246            let id = brain.sensors[rng.gen_range(0, brain.sensors.len()) % brain.sensors.len()].id;
247            if brain.kill_sensor(id).is_err() {
248                break;
249            }
250        }
251        while brain.effectors.len() > effectors_count {
252            let id =
253                brain.effectors[rng.gen_range(0, brain.effectors.len()) % brain.effectors.len()].id;
254            if brain.kill_effector(id).is_err() {
255                break;
256            }
257        }
258        while brain.synapses.len() > synapses_count {
259            let (from, to) = {
260                let index = rng.gen_range(0, brain.synapses.len()) % brain.synapses.len();
261                let synapse = &brain.synapses[index];
262                (synapse.source, synapse.target)
263            };
264            if brain.unbind_neurons(from, to).is_err() {
265                break;
266            }
267        }
268        brain
269    }
270
271    #[inline]
272    pub fn id(&self) -> BrainID {
273        self.id
274    }
275
276    #[inline]
277    pub fn get_neurons(&self) -> Vec<NeuronID> {
278        iter!(self.neurons).map(|n| n.id()).collect()
279    }
280
281    #[inline]
282    pub fn get_sensors(&self) -> Vec<SensorID> {
283        iter!(self.sensors).map(|s| s.id).collect()
284    }
285
286    #[inline]
287    pub fn get_effectors(&self) -> Vec<EffectorID> {
288        iter!(self.effectors).map(|e| e.id).collect()
289    }
290
291    #[inline]
292    pub fn synapses_count(&self) -> usize {
293        self.synapses.len()
294    }
295
296    #[inline]
297    pub fn get_impulses_count(&self) -> usize {
298        iter!(self.synapses).map(|s| s.impulses.len()).sum()
299    }
300
301    #[inline]
302    pub fn get_impulses_potential(&self) -> Scalar {
303        iter!(self.synapses)
304            .map(|s| iter!(s.impulses).map(|i| i.potential).sum::<Scalar>())
305            .sum::<Scalar>()
306    }
307
308    #[inline]
309    pub fn get_neurons_potential(&self) -> Scalar {
310        iter!(self.neurons).map(|n| n.potential()).sum()
311    }
312
313    #[inline]
314    pub fn get_potential(&self) -> Scalar {
315        self.get_neurons_potential() + self.get_impulses_potential()
316    }
317
318    pub fn clear(&mut self) {
319        self.neurons.clear();
320        self.synapses.clear();
321        self.sensors.clear();
322        self.effectors.clear();
323    }
324
325    #[inline]
326    pub fn config(&self) -> &Config {
327        &self.config
328    }
329
330    #[inline]
331    pub fn config_mut(&mut self) -> &mut Config {
332        &mut self.config
333    }
334
335    #[inline]
336    pub fn set_config(&mut self, config: Config) {
337        self.config = config;
338    }
339
340    #[inline]
341    pub fn neuron(&self, id: NeuronID) -> Option<&Neuron> {
342        #[cfg(feature = "parallel")]
343        {
344            self.neurons.par_iter().find_any(|n| n.id() == id)
345        }
346        #[cfg(not(feature = "parallel"))]
347        {
348            self.neurons.iter().find(|n| n.id() == id)
349        }
350    }
351
352    #[inline]
353    pub fn neuron_mut(&mut self, id: NeuronID) -> Option<&mut Neuron> {
354        #[cfg(feature = "parallel")]
355        {
356            self.neurons.par_iter_mut().find_any(|n| n.id() == id)
357        }
358        #[cfg(not(feature = "parallel"))]
359        {
360            self.neurons.iter_mut().find(|n| n.id() == id)
361        }
362    }
363
364    #[inline]
365    pub fn neurons(&self) -> &[Neuron] {
366        &self.neurons
367    }
368
369    #[inline]
370    pub fn are_neurons_connected(&self, from: NeuronID, to: NeuronID) -> bool {
371        iter!(self.synapses).any(|s| s.source == from && s.target == to)
372    }
373
374    #[inline]
375    pub fn does_neuron_has_connections(&self, id: NeuronID) -> bool {
376        iter!(self.synapses).any(|s| s.source == id || s.target == id)
377    }
378
379    #[inline]
380    pub fn get_neuron_connections_count(&self, id: NeuronID) -> (usize, usize) {
381        let incoming = iter!(self.synapses).filter(|s| s.target == id).count();
382        let outgoing = iter!(self.synapses).filter(|s| s.source == id).count();
383        (incoming, outgoing)
384    }
385
386    #[inline]
387    pub fn get_neuron_connections(&self, id: NeuronID) -> (Vec<NeuronID>, Vec<NeuronID>) {
388        let incoming = iter!(self.synapses)
389            .filter_map(|s| if s.target == id { Some(s.source) } else { None })
390            .collect();
391        let outgoing = iter!(self.synapses)
392            .filter_map(|s| if s.source == id { Some(s.target) } else { None })
393            .collect();
394        (incoming, outgoing)
395    }
396
397    pub fn create_sensor(&mut self, target: NeuronID) -> Result<SensorID> {
398        #[cfg(feature = "parallel")]
399        let sensor = self.sensors.par_iter().find_any(|s| s.target == target);
400        #[cfg(not(feature = "parallel"))]
401        let sensor = self.sensors.iter().find(|s| s.target == target);
402        if let Some(sensor) = sensor {
403            return Err(Error::NeuronIsAlreadyConnectedToSensor(target, sensor.id));
404        }
405        #[cfg(feature = "parallel")]
406        let effector = self.effectors.par_iter().find_any(|e| e.source == target);
407        #[cfg(not(feature = "parallel"))]
408        let effector = self.effectors.iter().find(|e| e.source == target);
409        if let Some(effector) = effector {
410            return Err(Error::NeuronIsAlreadyConnectedToEffector(
411                target,
412                effector.id,
413            ));
414        }
415        let sensor = Sensor {
416            id: Default::default(),
417            target,
418        };
419        let id = sensor.id;
420        self.sensors.push(sensor);
421        Ok(id)
422    }
423
424    pub fn kill_sensor(&mut self, id: SensorID) -> Result<()> {
425        #[cfg(feature = "parallel")]
426        let index = self.sensors.par_iter().position_any(|s| s.id == id);
427        #[cfg(not(feature = "parallel"))]
428        let index = self.sensors.iter().position(|s| s.id == id);
429        if let Some(index) = index {
430            self.sensors.swap_remove(index);
431            Ok(())
432        } else {
433            Err(Error::SensorDoesNotExists(id))
434        }
435    }
436
437    pub fn sensor_trigger_impulse(&mut self, id: SensorID, potential: Scalar) -> Result<()> {
438        #[cfg(feature = "parallel")]
439        let sensor = self.sensors.par_iter().find_any(|s| s.id == id);
440        #[cfg(not(feature = "parallel"))]
441        let sensor = self.sensors.iter().find(|s| s.id == id);
442        if let Some(sensor) = sensor {
443            #[cfg(feature = "parallel")]
444            let neuron = self
445                .neurons
446                .par_iter_mut()
447                .find_any(|n| n.id() == sensor.target);
448            #[cfg(not(feature = "parallel"))]
449            let neuron = self.neurons.iter_mut().find(|n| n.id() == sensor.target);
450            if let Some(neuron) = neuron {
451                neuron.push_potential(potential);
452                Ok(())
453            } else {
454                Err(Error::NeuronDoesNotExists(sensor.target))
455            }
456        } else {
457            Err(Error::SensorDoesNotExists(id))
458        }
459    }
460
461    pub fn create_effector(&mut self, source: NeuronID) -> Result<EffectorID> {
462        #[cfg(feature = "parallel")]
463        let sensor = self.sensors.par_iter().find_any(|s| s.target == source);
464        #[cfg(not(feature = "parallel"))]
465        let sensor = self.sensors.iter().find(|s| s.target == source);
466        if let Some(sensor) = sensor {
467            return Err(Error::NeuronIsAlreadyConnectedToSensor(source, sensor.id));
468        }
469        #[cfg(feature = "parallel")]
470        let effector = self.effectors.par_iter().find_any(|e| e.source == source);
471        #[cfg(not(feature = "parallel"))]
472        let effector = self.effectors.iter().find(|e| e.source == source);
473        if let Some(effector) = effector {
474            return Err(Error::NeuronIsAlreadyConnectedToEffector(
475                source,
476                effector.id,
477            ));
478        }
479        let effector = Effector {
480            id: Default::default(),
481            source,
482            potential: 0.0,
483        };
484        let id = effector.id;
485        self.effectors.push(effector);
486        Ok(id)
487    }
488
489    pub fn kill_effector(&mut self, id: EffectorID) -> Result<()> {
490        #[cfg(feature = "parallel")]
491        let index = self.effectors.par_iter().position_any(|e| e.id == id);
492        #[cfg(not(feature = "parallel"))]
493        let index = self.effectors.iter().position(|e| e.id == id);
494        if let Some(index) = index {
495            self.effectors.swap_remove(index);
496            Ok(())
497        } else {
498            Err(Error::EffectorDoesNotExists(id))
499        }
500    }
501
502    pub fn effector_potential_release(&mut self, id: EffectorID) -> Result<Scalar> {
503        #[cfg(feature = "parallel")]
504        let effector = self.effectors.par_iter_mut().find_any(|e| e.id == id);
505        #[cfg(not(feature = "parallel"))]
506        let effector = self.effectors.iter_mut().find(|e| e.id == id);
507        if let Some(effector) = effector {
508            let potential = effector.potential;
509            effector.potential = 0.0;
510            Ok(potential)
511        } else {
512            Err(Error::EffectorDoesNotExists(id))
513        }
514    }
515
516    pub fn create_neuron(&mut self, position: Position) -> NeuronID {
517        let neuron = Neuron::new(self.id, position);
518        let id = neuron.id();
519        self.neurons.push(neuron);
520        id
521    }
522
523    pub fn kill_neuron(&mut self, id: NeuronID) -> Result<()> {
524        #[cfg(feature = "parallel")]
525        let index = self.neurons.par_iter().position_any(|n| n.id() == id);
526        #[cfg(not(feature = "parallel"))]
527        let index = self.neurons.iter().position(|n| n.id() == id);
528        if let Some(index) = index {
529            self.neurons.swap_remove(index);
530            while let Some(index) = self
531                .synapses
532                .iter()
533                .position(|s| s.source == id || s.target == id)
534            {
535                self.synapses.swap_remove(index);
536            }
537            #[cfg(feature = "parallel")]
538            let index = self.sensors.par_iter().position_any(|s| s.target == id);
539            #[cfg(not(feature = "parallel"))]
540            let index = self.sensors.iter().position(|s| s.target == id);
541            while let Some(index) = index {
542                self.sensors.swap_remove(index);
543            }
544            #[cfg(feature = "parallel")]
545            let index = self.effectors.par_iter().position_any(|e| e.source == id);
546            #[cfg(not(feature = "parallel"))]
547            let index = self.effectors.iter().position(|e| e.source == id);
548            while let Some(index) = index {
549                self.effectors.swap_remove(index);
550            }
551            Ok(())
552        } else {
553            Err(Error::NeuronDoesNotExists(id))
554        }
555    }
556
557    pub fn bind_neurons(&mut self, from: NeuronID, to: NeuronID) -> Result<Option<Scalar>> {
558        if from == to {
559            return Err(Error::BindingNeuronToItSelf(from));
560        }
561        if let Some(source) = self.neuron(from) {
562            if let Some(target) = self.neuron(to) {
563                if self.are_neurons_connected(from, to) {
564                    return Ok(None);
565                }
566                #[cfg(feature = "parallel")]
567                let sensor = self.sensors.par_iter().find_any(|s| s.target == to);
568                #[cfg(not(feature = "parallel"))]
569                let sensor = self.sensors.iter().find(|s| s.target == to);
570                if let Some(sensor) = sensor {
571                    return Err(Error::BindingNeuronToSensor(to, sensor.id));
572                }
573                #[cfg(feature = "parallel")]
574                let effector = self.effectors.par_iter().find_any(|e| e.source == from);
575                #[cfg(not(feature = "parallel"))]
576                let effector = self.effectors.iter().find(|e| e.source == from);
577                if let Some(effector) = effector {
578                    return Err(Error::BindingEffectorToNeuron(effector.id, from));
579                }
580                let distance = source.position().distance(target.position());
581                let receptors = thread_rng().gen_range(
582                    self.config.default_receptors.start,
583                    self.config.default_receptors.end,
584                );
585                self.synapses.push(Synapse {
586                    source: from,
587                    target: to,
588                    distance,
589                    receptors,
590                    impulses: vec![],
591                    inactivity: 0.0,
592                });
593                Ok(Some(receptors))
594            } else {
595                Err(Error::NeuronDoesNotExists(to))
596            }
597        } else {
598            Err(Error::NeuronDoesNotExists(from))
599        }
600    }
601
602    pub fn unbind_neurons(&mut self, from: NeuronID, to: NeuronID) -> Result<bool> {
603        if from == to {
604            return Err(Error::UnbindingNeuronFromItSelf(from));
605        }
606        if iter!(self.neurons).any(|n| n.id() == from) {
607            if iter!(self.neurons).any(|n| n.id() == to) {
608                #[cfg(feature = "parallel")]
609                let index = self
610                    .synapses
611                    .par_iter()
612                    .position_any(|s| s.source == from && s.target == to);
613                #[cfg(not(feature = "parallel"))]
614                let index = self
615                    .synapses
616                    .iter()
617                    .position(|s| s.source == from && s.target == to);
618                if let Some(index) = index {
619                    self.synapses.swap_remove(index);
620                    Ok(true)
621                } else {
622                    Ok(false)
623                }
624            } else {
625                Err(Error::NeuronDoesNotExists(to))
626            }
627        } else {
628            Err(Error::NeuronDoesNotExists(from))
629        }
630    }
631
632    pub fn kill_impulses(&mut self) {
633        for neuron in &mut self.neurons {
634            neuron.fire();
635        }
636        for synapse in &mut self.synapses {
637            synapse.impulses.len();
638        }
639        for effector in &mut self.effectors {
640            effector.potential = 0.0;
641        }
642    }
643
644    pub fn process(&mut self, delta_time: Scalar) -> Result<()> {
645        if self.neurons.is_empty() {
646            return Ok(());
647        }
648
649        let Config {
650            propagation_speed,
651            action_potential_treshold,
652            synapse_inactivity_time,
653            neuron_potential_decay,
654            synapse_overdose_receptors,
655            receptors_excitation,
656            receptors_inhibition,
657            synapse_propagation_decay,
658            synapse_new_connection_receptors,
659            ..
660        } = self.config;
661
662        // potential summation phase.
663        {
664            let dtpd = delta_time * neuron_potential_decay;
665            let neurons_triggering = iter_mut!(self.neurons)
666                .filter_map(|neuron| {
667                    let potential = neuron.potential();
668                    let status = if potential >= action_potential_treshold {
669                        neuron.fire();
670                        true
671                    } else {
672                        false
673                    };
674                    neuron.process_potential(dtpd);
675                    if status {
676                        Some((neuron.id(), potential))
677                    } else {
678                        None
679                    }
680                })
681                .collect::<Vec<_>>();
682            for (id, p) in neurons_triggering {
683                let count = iter!(self.synapses)
684                    .filter(|s| s.inactivity <= 0.0 && s.source == id)
685                    .count();
686                if count > 0 {
687                    let p = p / count as Scalar;
688                    iter_mut!(self.synapses)
689                        .filter(|s| s.inactivity <= 0.0 && s.source == id)
690                        .for_each(|s| {
691                            let under = if let Some(o) = synapse_overdose_receptors {
692                                s.receptors < o
693                            } else {
694                                true
695                            };
696                            if under {
697                                s.impulses.push(Impulse {
698                                    potential: p,
699                                    timeout: s.distance,
700                                });
701                            }
702                            s.inactivity = synapse_inactivity_time;
703                        });
704                }
705            }
706        }
707
708        // impulse propagation phase.
709        {
710            let s = propagation_speed * delta_time;
711            let r = receptors_excitation * delta_time;
712            let d = synapse_propagation_decay * s;
713            let neurons_to_trigger = iter_mut!(self.synapses)
714                .flat_map(|synapse| {
715                    let mut estimated_count = 0;
716                    for impulse in &mut synapse.impulses {
717                        impulse.potential -= d;
718                        impulse.timeout -= s;
719                        if impulse.timeout <= 0.0 {
720                            estimated_count += 1;
721                        }
722                    }
723                    synapse.receptors += estimated_count as Scalar * r;
724                    let mut neurons_to_trigger = Vec::with_capacity(estimated_count);
725                    if estimated_count > 0 {
726                        synapse.impulses = synapse
727                            .impulses
728                            .iter()
729                            .filter_map(|impulse| {
730                                if impulse.potential <= 0.0 {
731                                    None
732                                } else if impulse.timeout > 0.0 {
733                                    Some(*impulse)
734                                } else {
735                                    neurons_to_trigger.push((synapse.target, impulse.potential));
736                                    None
737                                }
738                            })
739                            .collect();
740                    }
741                    synapse.inactivity = (synapse.inactivity - delta_time).max(0.0);
742                    neurons_to_trigger
743                })
744                .collect::<Vec<_>>();
745            iter_mut!(self.neurons).for_each(|neuron| {
746                let nid = neuron.id();
747                for (id, potential) in &neurons_to_trigger {
748                    if nid == *id {
749                        neuron.push_potential(*potential);
750                    }
751                }
752            });
753        }
754
755        // inhibition and reconnection phase.
756        if receptors_inhibition > 0.0 {
757            let r = receptors_inhibition * delta_time;
758            let synapses_to_remove = iter_mut!(self.synapses)
759                .enumerate()
760                .filter_map(|(i, synapse)| {
761                    synapse.receptors -= r;
762                    if synapse.receptors <= 0.0 {
763                        Some(i)
764                    } else {
765                        None
766                    }
767                })
768                .collect::<Vec<_>>();
769            let neurons_to_reconnect = iter!(synapses_to_remove)
770                .filter_map(|index| {
771                    let s = &self.synapses[*index];
772                    if s.receptors <= 0.0 {
773                        #[cfg(feature = "parallel")]
774                        let neuron = self.neurons.par_iter().find_any(|n| n.id() == s.source);
775                        #[cfg(not(feature = "parallel"))]
776                        let neuron = self.neurons.iter().find(|n| n.id() == s.source);
777                        if let Some(neuron) = neuron {
778                            let mut rng = thread_rng();
779                            if let Some(id) = self.select_neuron(neuron.position(), &mut rng) {
780                                if s.source != id
781                                    && !self.are_neurons_connected(s.source, id)
782                                    && !self.are_neurons_connected(id, s.source)
783                                {
784                                    return Some((s.source, id));
785                                }
786                            }
787                        }
788                    }
789                    None
790                })
791                .collect::<Vec<_>>();
792            for index in synapses_to_remove.into_iter().rev() {
793                self.synapses.swap_remove(index);
794            }
795            for (from, to) in neurons_to_reconnect {
796                self.bind_neurons(from, to)?;
797            }
798        }
799
800        // removing dead neurons phase.
801        {
802            let neurons_to_remove = iter!(self.neurons)
803                .enumerate()
804                .filter_map(|(i, n)| {
805                    let id = n.id();
806                    if !iter!(self.synapses).any(|s| s.source == id || s.target == id) {
807                        Some(i)
808                    } else {
809                        None
810                    }
811                })
812                .collect::<Vec<_>>();
813            for index in neurons_to_remove.into_iter().rev() {
814                let id = self.neurons.swap_remove(index).id();
815                #[cfg(feature = "parallel")]
816                let index = self
817                    .synapses
818                    .par_iter()
819                    .position_any(|s| s.source == id || s.target == id);
820                #[cfg(not(feature = "parallel"))]
821                let index = self
822                    .synapses
823                    .iter()
824                    .position(|s| s.source == id || s.target == id);
825                while let Some(index) = index {
826                    self.synapses.swap_remove(index);
827                }
828                #[cfg(feature = "parallel")]
829                let index = self.sensors.par_iter().position_any(|s| s.target == id);
830                #[cfg(not(feature = "parallel"))]
831                let index = self.sensors.iter().position(|s| s.target == id);
832                while let Some(index) = index {
833                    self.sensors.swap_remove(index);
834                }
835                #[cfg(feature = "parallel")]
836                let index = self.effectors.par_iter().position_any(|e| e.source == id);
837                #[cfg(not(feature = "parallel"))]
838                let index = self.effectors.iter().position(|e| e.source == id);
839                while let Some(index) = index {
840                    self.effectors.swap_remove(index);
841                }
842            }
843        }
844
845        // accumulating effector potentials phase.
846        {
847            for effector in &mut self.effectors {
848                #[cfg(feature = "parallel")]
849                let neuron = self
850                    .neurons
851                    .par_iter()
852                    .find_any(|n| n.id() == effector.source);
853                #[cfg(not(feature = "parallel"))]
854                let neuron = self.neurons.iter().find(|n| n.id() == effector.source);
855                if let Some(neuron) = neuron {
856                    effector.potential = neuron.potential();
857                }
858            }
859        }
860
861        // creating new connections phase.
862        if let Some(r) = synapse_new_connection_receptors {
863            let synapses_to_connect = iter!(self.synapses)
864                .enumerate()
865                .filter_map(|(i, s)| {
866                    if s.receptors > r {
867                        if let Some(neuron) = self.neuron(s.source) {
868                            let mut rng = thread_rng();
869                            if let Some(id) = self.select_neuron(neuron.position(), &mut rng) {
870                                if s.source != id
871                                    && !self.are_neurons_connected(s.source, id)
872                                    && !self.are_neurons_connected(id, s.source)
873                                {
874                                    return Some((i, s.source, id));
875                                }
876                            }
877                        }
878                    }
879                    None
880                })
881                .collect::<Vec<_>>();
882            for (index, from, to) in synapses_to_connect.into_iter().rev() {
883                if let Some(receptors) = self.bind_neurons(from, to)? {
884                    self.synapses[index].receptors -= receptors;
885                }
886            }
887        }
888
889        Ok(())
890    }
891
892    fn select_neuron<R>(&self, position: Position, rng: &mut R) -> Option<NeuronID>
893    where
894        R: Rng,
895    {
896        let srr = self.config.synapse_reconnection_range;
897        let filtered = iter!(self.neurons)
898            .filter_map(|neuron| {
899                if iter!(self.sensors).any(|s| s.target == neuron.id()) {
900                    return None;
901                }
902                if let Some(srr) = srr {
903                    if neuron.position().distance(position) < srr {
904                        return None;
905                    }
906                }
907                Some(neuron.id())
908            })
909            .collect::<Vec<_>>();
910        if filtered.is_empty() {
911            None
912        } else {
913            Some(filtered[rng.gen_range(0, filtered.len()) % filtered.len()])
914        }
915    }
916
917    #[inline]
918    pub fn build_activity_map_default(&self) -> BrainActivityMap {
919        self.build_activity_map(activity::ALL)
920    }
921
922    pub fn build_activity_map(&self, flags: usize) -> BrainActivityMap {
923        let connections = if flags & activity::CONNECTIONS != 0 {
924            iter!(self.synapses)
925                .map(|s| {
926                    let from = self.neuron(s.source).unwrap().position();
927                    let to = self.neuron(s.target).unwrap().position();
928                    (from, to, s.receptors)
929                })
930                .collect()
931        } else {
932            vec![]
933        };
934        let impulses = if flags & activity::IMPULSES != 0 {
935            iter!(self.synapses)
936                .map(|s| {
937                    let from = self.neuron(s.source).unwrap().position();
938                    let to = self.neuron(s.target).unwrap().position();
939                    let distance = from.distance(to);
940                    iter!(s.impulses)
941                        .map(|i| {
942                            let factor = if distance > 0.0 {
943                                1.0 - i.timeout.max(0.0).min(distance) / distance
944                            } else {
945                                0.0
946                            };
947                            (from, to, factor)
948                        })
949                        .collect::<Vec<_>>()
950                })
951                .flatten()
952                .collect()
953        } else {
954            vec![]
955        };
956        let sensors = if flags & activity::SENSORS != 0 {
957            iter!(self.sensors)
958                .map(|s| self.neuron(s.target).unwrap().position())
959                .collect()
960        } else {
961            vec![]
962        };
963        let effectors = if flags & activity::EFFECTORS != 0 {
964            iter!(self.effectors)
965                .map(|e| self.neuron(e.source).unwrap().position())
966                .collect()
967        } else {
968            vec![]
969        };
970        let neurons = if flags & activity::NEURONS != 0 {
971            iter!(self.neurons).map(|n| n.position()).collect()
972        } else {
973            vec![]
974        };
975
976        BrainActivityMap {
977            connections,
978            impulses,
979            sensors,
980            effectors,
981            neurons,
982        }
983    }
984
985    pub fn build_activity_stats(&self) -> BrainActivityStats {
986        let neurons_potential = self.get_neurons_potential();
987        let neurons_potential_min = iter!(self.neurons)
988            .map(|n| n.potential())
989            .min_by(|a, b| a.partial_cmp(&b).unwrap())
990            .unwrap_or(0.0);
991        let neurons_potential_max = iter!(self.neurons)
992            .map(|n| n.potential())
993            .max_by(|a, b| a.partial_cmp(&b).unwrap())
994            .unwrap_or(0.0);
995        let impulses_potential = self.get_impulses_potential();
996        let impulses_potential_min = iter!(self.synapses)
997            .map(|s| {
998                iter!(s.impulses)
999                    .map(|i| i.potential)
1000                    .min_by(|a, b| a.partial_cmp(&b).unwrap())
1001                    .unwrap_or(0.0)
1002            })
1003            .min_by(|a, b| a.partial_cmp(&b).unwrap())
1004            .unwrap_or(0.0);
1005        let impulses_potential_max = iter!(self.synapses)
1006            .map(|s| {
1007                iter!(s.impulses)
1008                    .map(|i| i.potential)
1009                    .max_by(|a, b| a.partial_cmp(&b).unwrap())
1010                    .unwrap_or(0.0)
1011            })
1012            .max_by(|a, b| a.partial_cmp(&b).unwrap())
1013            .unwrap_or(0.0);
1014        let neuron_connections = iter!(self.neurons)
1015            .map(|n| self.get_neuron_connections_count(n.id()))
1016            .collect::<Vec<_>>();
1017        #[cfg(feature = "parallel")]
1018        let neuron_connections_min = neuron_connections
1019            .par_iter()
1020            .cloned()
1021            .reduce(|| (0, 0), |a, b| (a.0.min(b.0), a.1.min(b.1)));
1022        #[cfg(not(feature = "parallel"))]
1023        let neuron_connections_min = neuron_connections
1024            .iter()
1025            .cloned()
1026            .fold((0, 0), |a, b| (a.0.min(b.0), a.1.min(b.1)));
1027        #[cfg(feature = "parallel")]
1028        let neuron_connections_max = neuron_connections
1029            .par_iter()
1030            .cloned()
1031            .reduce(|| (0, 0), |a, b| (a.0.max(b.0), a.1.max(b.1)));
1032        #[cfg(not(feature = "parallel"))]
1033        let neuron_connections_max = neuron_connections
1034            .iter()
1035            .cloned()
1036            .fold((0, 0), |a, b| (a.0.max(b.0), a.1.max(b.1)));
1037        let synapses_receptors_min = iter!(self.synapses)
1038            .map(|s| s.receptors)
1039            .min_by(|a, b| a.partial_cmp(&b).unwrap())
1040            .unwrap_or(0.0);
1041        let synapses_receptors_max = iter!(self.synapses)
1042            .map(|s| s.receptors)
1043            .max_by(|a, b| a.partial_cmp(&b).unwrap())
1044            .unwrap_or(0.0);
1045
1046        BrainActivityStats {
1047            neurons_count: self.neurons.len(),
1048            synapses_count: self.synapses.len(),
1049            impulses_count: self.get_impulses_count(),
1050            neurons_potential: (
1051                neurons_potential,
1052                neurons_potential_min..neurons_potential_max,
1053            ),
1054            impulses_potential: (
1055                impulses_potential,
1056                impulses_potential_min..impulses_potential_max,
1057            ),
1058            all_potential: (
1059                neurons_potential + impulses_potential,
1060                neurons_potential_min.min(impulses_potential_min)
1061                    ..neurons_potential_max.max(impulses_potential_max),
1062            ),
1063            incoming_neuron_connections: neuron_connections_min.0..neuron_connections_max.0,
1064            outgoing_neuron_connections: neuron_connections_min.1..neuron_connections_max.1,
1065            synapses_receptors: synapses_receptors_min..synapses_receptors_max,
1066        }
1067    }
1068
1069    pub fn ignite_random_synapses(&mut self, count: usize, potential: Range<Scalar>) {
1070        let mut rng = thread_rng();
1071        for _ in 0..count {
1072            let index = rng.gen_range(0, self.synapses.len()) % self.synapses.len();
1073            let synapse = &mut self.synapses[index];
1074            synapse.impulses.push(Impulse {
1075                potential: if potential.end <= potential.start {
1076                    potential.end
1077                } else {
1078                    rng.gen_range(potential.start, potential.end)
1079                },
1080                timeout: rng.gen_range(0.0, synapse.distance),
1081            });
1082        }
1083    }
1084}