1#![feature(portable_simd)]
2
3use std::array;
4use std::fmt::Debug;
5use std::marker::PhantomData;
6use std::ops::{Add, AddAssign, Div, Index, IndexMut, Mul};
7
8mod linalg;
9use linalg::{vmdot, vvadd};
10
11fn sigmoid<E: linalg::Number>(x: E) -> E {
12 E::one() / (E::get_exp(-x) + E::one())
13}
14
15fn sigmoid_derivative<E: linalg::Number>(x: E) -> E {
16 x * (E::one() - x)
17}
18
19trait List {}
20
21#[derive(Default, Debug, Clone)]
22struct Nil;
23#[derive(Default, Debug, Clone)]
24struct Cons<H, T>(H, T);
25
26impl List for Nil {}
27impl<H, T: List> List for Cons<H, T> {}
28
29#[derive(Default)]
30struct Zero;
31#[derive(Default)]
32struct Succ<N>(PhantomData<N>);
33
34type S1<N = Zero> = Succ<N>;
35type S2<N = Zero> = S1<S1<N>>;
36type S4<N = Zero> = S2<S2<N>>;
37type S8<N = Zero> = S4<S4<N>>;
38type S16<N = Zero> = S8<S8<N>>;
39type S32<N = Zero> = S16<S16<N>>;
40type S64<N = Zero> = S32<S32<N>>;
41
42trait Prec {
43 type Output;
44}
45
46impl<N> Prec for Succ<N> {
47 type Output = N;
48}
49
50trait Repeat<N> {
51 type Output;
52}
53
54impl<H, T: List> Repeat<Zero> for Cons<H, T> {
55 type Output = T;
56}
57
58impl<H, T: List, N> Repeat<Succ<N>> for Cons<H, T>
59where
60 Cons<H, T>: Repeat<N>,
61{
62 type Output = Cons<H, <Cons<H, T> as Repeat<N>>::Output>;
63}
64
65trait Length {
66 type Output;
67}
68
69impl Length for Nil {
70 type Output = Zero;
71}
72
73impl<H, T: Length> Length for Cons<H, T> {
74 type Output = Succ<<T as Length>::Output>;
75}
76
77trait Nth<Idx> {
78 type Output;
79
80 fn nth(&self) -> &Self::Output;
81 fn nth_mut(&mut self) -> &mut Self::Output;
82}
83
84impl<H, T> Nth<Zero> for Cons<H, T> {
85 type Output = H;
86
87 fn nth(&self) -> &Self::Output {
88 &self.0
89 }
90
91 fn nth_mut(&mut self) -> &mut Self::Output {
92 &mut self.0
93 }
94}
95
96impl<Idx, H, T> Nth<Succ<Idx>> for Cons<H, T>
97where
98 T: Nth<Idx>,
99{
100 type Output = T::Output;
101
102 fn nth(&self) -> &Self::Output {
103 Nth::<Idx>::nth(&self.1)
104 }
105
106 fn nth_mut(&mut self) -> &mut Self::Output {
107 Nth::<Idx>::nth_mut(&mut self.1)
108 }
109}
110
111#[derive(Debug)]
112struct Layer<E, const S: usize>([E; S]);
113
114impl<E: Default, const S: usize> Default for Layer<E, S> {
115 fn default() -> Self {
116 Layer(array::from_fn(|_| E::default()))
117 }
118}
119
120trait Builder: Sized {
121 fn before<F>(self) -> Cons<F, Self>
122 where
123 F: Default,
124 {
125 Cons(F::default(), self)
126 }
127
128 fn repeat<N>(self) -> <Self as Repeat<N>>::Output
129 where
130 Self: List + Repeat<N>,
131 <Self as Repeat<N>>::Output: Default,
132 {
133 <Self as Repeat<N>>::Output::default()
134 }
135}
136
137impl Builder for Nil {}
138impl<H, T> Builder for Cons<H, T> {}
139
140trait ActivationFn<E> {
141 fn activate(e: E) -> E;
142}
143
144#[derive(Default)]
145struct Sigmoid;
146
147impl<E: linalg::Number> ActivationFn<E> for Sigmoid {
148 fn activate(x: E) -> E {
149 E::one() / (E::get_exp(-x) + E::one())
150 }
151}
152
153#[derive(Default)]
154struct Relu;
155
156impl<E: linalg::Number> ActivationFn<E> for Relu {
157 fn activate(x: E) -> E {
158 E::get_max(x, E::default())
159 }
160}
161
162trait FeedforwardTimes<Idx, Times> {
163 fn feedforward_times(&mut self) -> &mut Self;
164}
165
166struct NeuralNetwork<W: List, B: List, A: List, E, F: List> {
167 w: W,
168 b: B,
169 a: A,
170
171 f: F,
172 e: PhantomData<E>,
173}
174
175impl<Idx, W: List, B: List, A: List, E, F: List> FeedforwardTimes<Idx, Zero> for NeuralNetwork<W, B, A, E, F> {
176 fn feedforward_times(&mut self) -> &mut Self {
177 self
178 }
179}
180
181impl<Idx, Times, W, B, A, E, Fi, F, const AS: usize, const BS: usize, const CS: usize>
182 FeedforwardTimes<Idx, Succ<Times>> for NeuralNetwork<W, B, A, E, F>
183where
184 E: linalg::Number,
185 Fi: ActivationFn<E>,
186 F: List + Nth<Idx, Output = Fi>,
187 W: List + Nth<Idx, Output = Layer<E, AS>>,
188 B: List + Nth<Idx, Output = Layer<E, CS>>,
189 A: List + Nth<Idx, Output = Layer<E, BS>> + Nth<Succ<Idx>, Output = Layer<E, CS>>,
190 Self: FeedforwardTimes<Succ<Idx>, Times>,
191{
192 fn feedforward_times(&mut self) -> &mut Self {
193 let activate = Nth::<Idx>::nth(&self.f);
194 let activations = &Nth::<Idx>::nth(&self.a).0;
195 let weights = &Nth::<Idx>::nth(&self.w).0;
196 let bias = &Nth::<Idx>::nth(&self.b).0;
197
198 let activations = vvadd(&vmdot(activations, weights), bias).map(|e| Fi::activate(e));
199 Nth::<Succ<Idx>>::nth_mut(&mut self.a).0 = activations;
200
201 FeedforwardTimes::<Succ<Idx>, Times>::feedforward_times(self)
202 }
203}
204
205impl<W: List + Length, B: List, A: List, E, F: List> NeuralNetwork<W, B, A, E, F>
206where
207 Self: FeedforwardTimes<Zero, <W as Length>::Output>,
208{
209 fn feedforward(&mut self) -> &mut Self {
210 FeedforwardTimes::<Zero, <W as Length>::Output>::feedforward_times(self)
211 }
212}
213
214impl<W: List, B: List, A: List, E, F: List> NeuralNetwork<W, B, A, E, F>
215{
216 fn new(wba: (W, B, A), f: F) -> Self {
217 Self {
218 w: wba.0,
219 b: wba.1,
220 a: wba.2,
221 f,
222 e: PhantomData::<E>,
223 }
224 }
225}
226
227macro_rules! layers {
228 (@wbuilder $rt:expr; $t:ty; {$s:expr} $(x $r:ty)?) => {
229 $rt
230 };
231 (@wbuilder $rt:expr; $t:ty; {$sp:expr} $(x $rp:ty)?, {$sn:expr} $(x $rn:ty)? $(, {$s:expr} $(x $r:ty)?)*) => {
232 layers!(
233 @wbuilder
234 $rt
235 $(
236 .before::<Layer<$t, {$sp*$sp}>>()
237 .repeat::<<$rp as Prec>::Output>()
238 )*
239 .before::<Layer<$t, {$sp*$sn}>>();
240 $t;
241 {$sn} $(x $rn)* $(, {$s} $(x $r)*)*
242 )
243 };
244 (@bbuilder $rt:expr; $t:ty; {$s:expr} $(x $r:ty)?) => {
245 $rt
246 $(
247 .before::<Layer<$t, $s>>()
248 .repeat::<<$r as Prec>::Output>()
249 )*
250 };
251 (@bbuilder $rt:expr; $t:ty; {$sp:expr} $(x $rp:ty)? $(, {$s:expr} $(x $r:ty)?)*) => {
252 layers!(
253 @bbuilder
254 $rt
255 .before::<Layer<$t, $sp>>()
256 $(.repeat::<$rp>())*;
257 $t;
258 $({$s} $(x $r)*),*
259 )
260 };
261 ($t:ty; $({$s:expr} $(x $r:ty)?),+) => {
262 (
263 layers!(@wbuilder Nil; $t; $({$s} $(x $r)*),*),
264 layers!(@bbuilder Nil; $t; $({$s} $(x $r)*),*),
265 Nil
266 $(
267 .before::<Layer<$t, $s>>()
268 $(.repeat::<$r>())*
269 )*,
270 )
271 };
272}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277
278 #[test]
279 fn create_some_layers() {
280 let (w, b, a) = layers!(f32; {3}, {4} x S2<S1>, {7});
282
283 assert_eq!(w.0.0.len(), 28);
284 assert_eq!(w.1.0.0.len(), 16);
285 assert_eq!(w.1.1.0.0.len(), 16);
286 assert_eq!(w.1.1.1.0.0.len(), 12);
287
288 assert_eq!(b.0.0.len(), 4);
289 assert_eq!(b.1.0.0.len(), 4);
290 assert_eq!(b.1.1.0.0.len(), 4);
291 assert_eq!(b.1.1.1.0.0.len(), 3);
292
293 assert_eq!(a.0.0.len(), 7);
294 assert_eq!(a.1.0.0.len(), 4);
295 assert_eq!(a.1.1.0.0.len(), 4);
296 assert_eq!(a.1.1.1.0.0.len(), 4);
297 assert_eq!(a.1.1.1.1.0.0.len(), 3);
298 }
299
300 #[test]
301 fn some_feedforward() {
302 let wab = layers!(f32; {3}, {8}, {4});
303 let f = Nil
304 .before::<Sigmoid>()
305 .repeat::<S2>();
306
307 let mut nn = NeuralNetwork::new(wab, f);
308 nn.w.0.0 = [1.; 32];
309 nn.a.0.0 = [1.; 4];
310 nn.w.1.0.0 = [1.; 24];
311 nn.b.1.0.0 = [1.; 3];
312
313 nn.feedforward();
314
315 println!("{:?}", nn.a.0);
316 }
317
318 #[test]
319 fn feedforward_sum() {
320 let wab = layers!(f32; {1}, {2});
321 let f = Nil.before::<Relu>();
322
323 let mut nn = NeuralNetwork::new(wab, f);
324 nn.w.0.0 = [1., 1.];
325 nn.a.0.0 = [2., 3.];
326
327 nn.feedforward();
328 assert!(f32::abs(nn.a.1.0.0[0] - 5.) < 0.000001);
329 }
330}