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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
use ndarray::{prelude::*, Data};

use crate::{Adaptable, Neural, NeuralLayer, Responsive, Topological, Trainable};

/// Public trait that defines the concept of self organization
pub trait Selforganizing: Neural {
    // Associated to topology

    /// Init the lateral connections according to network type
    fn init_lateral(&mut self); // -> Self;

    /// Get the distance/connection between a selected neuron
    /// and the rest of the layer
    fn get_lateral_distance(&mut self, index: usize) -> Array2<f64>;

    // Associated to the feature space

    /// Get the best matching neuron given a pattern
    fn get_best_matching(&mut self, pattern: &ArrayView1<f64>) -> usize;

    // Associated to adaptivity (Single Datapoints)
    // Ownership has to be transferred.
    // The object needs to be partially deconstructed to
    // grant write access to data and the adaptivity data structure
    // returns ownership.
    // The doubtfully best alternative is making adaptivity and training
    // Copyable

    // fn get_best_matching<S>(&mut self, pattern: &ArrayBase<S, Ix1>) -> usize
    // where
    //     S: Data<Elem = f64>;
    // fn adapt<S>(&mut self, pattern: &ArrayBase<S, Ix1>, influence: f64, rate: f64)
    // where
    //     S: Data<Elem = f64>;
    // fn train<S>(&mut self, patterns: &ArrayBase<S, Ix2>)
    // where
    //     S: Data<Elem = f64>;

    /// Adapt the layer to an input pattern. Note this consumes
    /// the current later and returns a new created (zero-copy)
    fn adapt(&mut self, pattern: &ArrayView1<f64>, influence: f64, rate: f64);
    //-> Self

    // Train a layer given a training set
    fn train(&mut self, patterns: &ArrayView2<f64>);
    //-> Self
}

/// Struct that implements structural composition
pub struct SelforganizingNetwork<A, T, R, L>
where
    A: Adaptable<NeuralLayer, R>,
    T: Topological<NeuralLayer>,
    R: Responsive<NeuralLayer>,
    L: Trainable<NeuralLayer, A, R>,
    // B: Trainable<D1,D2> + Copy,
{
    /// needs to be nested to share it with the algorithms
    pub neurons: NeuralLayer,
    /// Algorithm for adaptivity
    pub adaptivity: A,
    /// Algorithm related to topology
    pub topology: T,
    /// Algorithm to feature pattern matching and lateral inhibition
    pub responsiveness: R,
    /// Algorithm related to batch processing
    pub training: L, // Box<B>,
}

impl<A, T, R, B> Selforganizing for SelforganizingNetwork<A, T, R, B>
where
    A: Adaptable<NeuralLayer, R>,
    T: Topological<NeuralLayer>,
    R: Responsive<NeuralLayer>,
    B: Trainable<NeuralLayer, A, R>,
{
    fn init_lateral(&mut self) //-> Self
    {
        self.topology.init_lateral(&mut self.neurons);
        // self
    }

    fn get_lateral_distance(&mut self, index: usize) -> Array2<f64> {
        todo!()
    }

    fn get_best_matching(&mut self, pattern: &ArrayView1<f64>) -> usize {
        self.responsiveness
            .get_best_matching(&self.neurons, pattern)
    }

    fn adapt(&mut self, pattern: &ArrayView1<f64>, influence: f64, rate: f64) {
        self.adaptivity.adapt(
            &mut self.neurons,
            &mut self.responsiveness,
            pattern,
            influence,
            rate,
        );
        //self
    }

    fn train(&mut self, patterns: &ArrayView2<f64>) {
        self.training.train(
            &mut self.neurons,
            &mut self.adaptivity,
            &mut self.responsiveness,
            patterns,
        );
        // self
    }
}

// #[cfg(feature = "ndarray")]

impl<A, T, R, B> Neural for SelforganizingNetwork<A, T, R, B>
where
    A: Adaptable<NeuralLayer, R>,
    T: Topological<NeuralLayer>,
    R: Responsive<NeuralLayer>,
    B: Trainable<NeuralLayer, A, R>,
{
    fn get_lateral(&self) -> &Array2<f64> {
        &self.neurons.lateral
    }

    fn get_lateral_mut(&mut self) -> &mut Array2<f64> {
        todo!()
    }
    fn set_lateral(&mut self, lateral: Array2<f64>) {
        todo!()
    }

    fn get_patterns(&self) -> &Array2<f64> {
        &self.neurons.patterns
    }

    fn get_patterns_mut(&mut self) -> &mut Array2<f64> {
        todo!()
    }

    fn set_patterns(&mut self, patterns: Array2<f64>) {
        todo!()
    }
}

pub type BoxedSelforganizing = Box<dyn Selforganizing + Send>;

// pub trait SelforganizingNeural: SelfOrganizing + Neural {}
// impl<A, T, R, B> SelforganizingNeural for NeuralLayer<A, T, R, B>
// where
//     A: Adaptable<Neurons, R>,
//     T: Topological<Neurons>,
//     R: Responsive<Neurons>,
//     B: Trainable<Neurons, A, R>,
// {
// }
// pub type BoxedSelforganizingNeural = Box<dyn SelforganizingNeural + Send>;

// #[cfg(not(feature = "ndarray"))]

// #[cfg(test)]
// mod tests {

//     #[test]
//     fn it_works() {
//         let result = 2 + 2;
//         assert_eq!(result, 4);
//     }
// }