concision_neural/layout/
features.rs

1/*
2    Appellation: layout <module>
3    Contrib: @FL03
4*/
5use super::{ModelFormat, ModelLayout};
6
7/// verify if the input and hidden dimensions are compatible by checking:
8///
9/// 1. they have the same dimensionality
10/// 2. if the the number of dimensions is greater than one, the hidden layer should be square
11/// 3. the finaly dimension of the input is equal to one hidden dimension
12pub fn _verify_input_and_hidden_shape<D>(input: D, hidden: D) -> bool
13where
14    D: ndarray::Dimension,
15{
16    let mut valid = true;
17    // // check that the hidden dimension is square
18    // if hidden.ndim() > 1 && hidden.shape().iter().any(|&d| d != hidden.shape()[0]) {
19    //     valid = false;
20    // }
21    // check that the input and hidden dimensions are compatible
22    if input.ndim() != hidden.ndim() {
23        valid = false;
24    }
25    valid
26}
27
28/// The [`ModelFeatures`] provides a common way of defining the layout of a model. This is
29/// used to define the number of input features, the number of hidden layers, the number of
30/// hidden features, and the number of output features.
31#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
32#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
33pub struct ModelFeatures {
34    /// the number of input features
35    pub(crate) input: usize,
36    /// the features of the "inner" layers
37    pub(crate) inner: ModelFormat,
38    /// the number of output features
39    pub(crate) output: usize,
40}
41
42impl ModelFeatures {
43    /// creates a new instance of [`ModelFeatures`] for a deep neurao network, using the given
44    /// input, hidden, and output features with the given number of hidden layers
45    pub const fn deep(input: usize, hidden: usize, output: usize, layers: usize) -> Self {
46        Self {
47            input,
48            output,
49            inner: ModelFormat::deep(hidden, layers),
50        }
51    }
52    /// returns a new instance of [`ModelFeatures`] for a shallow neural network, using the
53    /// given features for the input, output, and single hidden layer
54    pub const fn shallow(input: usize, hidden: usize, output: usize) -> Self {
55        Self {
56            input,
57            output,
58            inner: ModelFormat::shallow(hidden),
59        }
60    }
61    /// returns a copy of the input features for the model
62    pub const fn input(&self) -> usize {
63        self.input
64    }
65    /// returns a mutable reference to the input features for the model
66    pub const fn input_mut(&mut self) -> &mut usize {
67        &mut self.input
68    }
69    /// returns a copy of the inner format for the model
70    pub const fn inner(&self) -> ModelFormat {
71        self.inner
72    }
73    /// returns a mutable reference to the inner format for the model
74    pub const fn inner_mut(&mut self) -> &mut ModelFormat {
75        &mut self.inner
76    }
77    /// returns a copy of the hidden features for the model
78    pub const fn hidden(&self) -> usize {
79        self.inner().hidden()
80    }
81    /// returns a mutable reference to the hidden features for the model
82    pub const fn hidden_mut(&mut self) -> &mut usize {
83        self.inner_mut().hidden_mut()
84    }
85    /// returns a copy of the number of hidden layers for the model
86    pub const fn layers(&self) -> usize {
87        self.inner().layers()
88    }
89    /// returns a mutable reference to the number of hidden layers for the model
90    pub const fn layers_mut(&mut self) -> &mut usize {
91        self.inner_mut().layers_mut()
92    }
93    /// returns a copy of the output features for the model
94    pub const fn output(&self) -> usize {
95        self.output
96    }
97    /// returns a mutable reference to the output features for the model
98    pub const fn output_mut(&mut self) -> &mut usize {
99        &mut self.output
100    }
101    #[inline]
102    /// sets the input features for the model
103    pub fn set_input(&mut self, input: usize) -> &mut Self {
104        self.input = input;
105        self
106    }
107    #[inline]
108    /// sets the hidden features for the model
109    pub fn set_hidden(&mut self, hidden: usize) -> &mut Self {
110        self.inner_mut().set_hidden(hidden);
111        self
112    }
113    #[inline]
114    /// sets the number of hidden layers for the model
115    pub fn set_layers(&mut self, layers: usize) -> &mut Self {
116        self.inner_mut().set_layers(layers);
117        self
118    }
119    #[inline]
120    /// sets the output features for the model
121    pub fn set_output(&mut self, output: usize) -> &mut Self {
122        self.output = output;
123        self
124    }
125    /// consumes the current instance and returns a new instance with the given input
126    pub fn with_input(self, input: usize) -> Self {
127        Self { input, ..self }
128    }
129    /// consumes the current instance and returns a new instance with the given hidden
130    /// features
131    pub fn with_hidden(self, hidden: usize) -> Self {
132        Self {
133            inner: self.inner.with_hidden(hidden),
134            ..self
135        }
136    }
137    /// consumes the current instance and returns a new instance with the given number of
138    /// hidden layers
139    pub fn with_layers(self, layers: usize) -> Self {
140        Self {
141            inner: self.inner.with_layers(layers),
142            ..self
143        }
144    }
145    /// consumes the current instance and returns a new instance with the given output
146    /// features
147    pub fn with_output(self, output: usize) -> Self {
148        Self { output, ..self }
149    }
150    /// the dimension of the input layer; (input, hidden)
151    pub fn dim_input(&self) -> (usize, usize) {
152        (self.input(), self.hidden())
153    }
154    /// the dimension of the hidden layers; (hidden, hidden)
155    pub fn dim_hidden(&self) -> (usize, usize) {
156        (self.hidden(), self.hidden())
157    }
158    /// the dimension of the output layer; (hidden, output)
159    pub fn dim_output(&self) -> (usize, usize) {
160        (self.hidden(), self.output())
161    }
162    /// the total number of parameters in the model
163    pub fn size(&self) -> usize {
164        self.size_input() + self.size_hidden() + self.size_output()
165    }
166    /// the total number of input parameters in the model
167    pub fn size_input(&self) -> usize {
168        self.input() * self.hidden()
169    }
170    /// the total number of hidden parameters in the model
171    pub fn size_hidden(&self) -> usize {
172        self.hidden() * self.hidden() * self.layers()
173    }
174    /// the total number of output parameters in the model
175    pub fn size_output(&self) -> usize {
176        self.hidden() * self.output()
177    }
178}
179
180impl ModelLayout for ModelFeatures {
181    fn input(&self) -> usize {
182        self.input()
183    }
184
185    fn input_mut(&mut self) -> &mut usize {
186        self.input_mut()
187    }
188
189    fn hidden(&self) -> usize {
190        self.hidden()
191    }
192
193    fn hidden_mut(&mut self) -> &mut usize {
194        self.hidden_mut()
195    }
196
197    fn layers(&self) -> usize {
198        self.layers()
199    }
200
201    fn layers_mut(&mut self) -> &mut usize {
202        self.layers_mut()
203    }
204
205    fn output(&self) -> usize {
206        self.output()
207    }
208
209    fn output_mut(&mut self) -> &mut usize {
210        self.output_mut()
211    }
212}
213
214impl Default for ModelFeatures {
215    fn default() -> Self {
216        Self {
217            input: 16,
218            inner: ModelFormat::Deep {
219                hidden: 16,
220                layers: 1,
221            },
222            output: 16,
223        }
224    }
225}
226impl core::fmt::Display for ModelFeatures {
227    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
228        write!(
229            f,
230            "{{ input: {i}, hidden: {h}, output: {o}, layers: {l} }}",
231            i = self.input(),
232            h = self.hidden(),
233            l = self.layers(),
234            o = self.output()
235        )
236    }
237}