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
extern crate ndarray;
extern crate ndarray_linalg;
use ndarray::*;
use crate::feature_collection::*;
use crate::linalg_utils::*;
use rand::prelude::*;
use crate::params::*;
#[derive(Clone)]
pub struct FourierFeatureCollection {
in_dimensions : usize,
num_features : usize,
alpha : f32,
ws : Array2<f32>
}
impl FourierFeatureCollection {
pub fn new(in_dimensions: usize, num_features : usize,
alpha : f32,
generator : fn(&mut ThreadRng, usize) -> Array1<f32>) -> FourierFeatureCollection {
let mut ws = Array::zeros((num_features, in_dimensions));
let mut rng = rand::thread_rng();
for i in 0..num_features {
let feature = generator(&mut rng, in_dimensions);
for j in 0..in_dimensions {
ws[[i, j]] = feature[[j,]];
}
}
FourierFeatureCollection {
in_dimensions,
num_features,
alpha,
ws
}
}
}
impl FeatureCollection for FourierFeatureCollection {
fn get_features(&self, in_vec: ArrayView1<f32>) -> Array1<f32> {
let dotted = self.ws.dot(&in_vec);
let sine = dotted.mapv(f32::sin);
let cosine = dotted.mapv(f32::cos);
let result = stack(Axis(0), &[sine.view(), cosine.view()]).unwrap();
self.alpha * result
}
fn get_jacobian(&self, in_vec: ArrayView1<f32>) -> Array2<f32> {
let dotted = self.ws.dot(&in_vec);
let cos = dotted.mapv(f32::cos);
let neg_sine = -dotted.mapv(f32::sin);
let part_one = scale_rows(self.ws.view(), cos.view());
let part_two = scale_rows(self.ws.view(), neg_sine.view());
let result = stack(Axis(0), &[part_one.view(), part_two.view()]).unwrap()
.into_dimensionality::<Ix2>().unwrap();
self.alpha * result
}
fn get_in_dimensions(&self) -> usize {
self.in_dimensions
}
fn get_dimension(&self) -> usize {
self.num_features * 2
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::*;
use crate::rand_utils::*;
#[test]
fn empirical_jacobian_is_jacobian() {
let mut successes : usize = 0;
for _ in 0..10 {
let fourier_feature_collection = FourierFeatureCollection::new(10, 15, 1.0f32, gen_nsphere_random);
let in_vec = random_vector(10);
let jacobian = fourier_feature_collection.get_jacobian(in_vec.view());
let empirical_jacobian = empirical_jacobian(|x| fourier_feature_collection.get_features(x),
in_vec.view());
let test = are_equal_matrices_to_within(jacobian.view(), empirical_jacobian.view(), 1.0f32, false);
if (test) {
successes += 1;
}
}
if (successes < 5) {
panic!();
}
}
}