1extern crate ndarray;
2extern crate ndarray_linalg;
3
4use ndarray::*;
5use crate::context::*;
6use crate::space_info::*;
7use crate::term_model::*;
8use crate::type_id::*;
9use crate::data_point::*;
10use crate::schmear::*;
11use crate::func_schmear::*;
12use crate::inverse_schmear::*;
13use crate::params::*;
14use rand::prelude::*;
15use ndarray_linalg::*;
16use ndarray_rand::RandomExt;
17use ndarray_rand::rand_distr::StandardNormal;
18use crate::func_scatter_tensor::*;
19use crate::model::*;
20use crate::normal_inverse_wishart::*;
21use crate::term_reference::*;
22use crate::prior_specification::*;
23use crate::array_utils::*;
24use crate::feature_space_info::*;
25use crate::feature_collection::*;
26use crate::fourier_feature_collection::*;
27use crate::sketched_linear_feature_collection::*;
28use crate::primitive_directory::*;
29use crate::rand_utils::*;
30
31pub const TEST_VECTOR_T : TypeId = 1 as TypeId;
34pub const TEST_SCALAR_T : TypeId = 0 as TypeId;
35pub const TEST_VECTOR_SIZE : usize = 2;
36
37fn get_test_vector_only_type_info_directory() -> TypeInfoDirectory {
38 let mut result = TypeInfoDirectory::new();
39 result.add(Type::VecType(1));
40 result.add(Type::VecType(TEST_VECTOR_SIZE));
41 result
42}
43
44pub fn get_test_vector_only_feature_space_info(base_dimensions : usize) -> FeatureSpaceInfo {
45 let sketcher = Option::None;
46 let mut feature_collections = Vec::<Box<dyn FeatureCollection>>::new();
47 let fourier_feature_collection = FourierFeatureCollection::new(base_dimensions, base_dimensions * 2, 1.0f32,
48 gen_nsphere_random);
49 let sketched_linear_feature_collection = SketchedLinearFeatureCollection::new(base_dimensions, base_dimensions * 2, 1.0f32);
50 feature_collections.push(Box::new(fourier_feature_collection));
51 feature_collections.push(Box::new(sketched_linear_feature_collection));
52
53 let feature_dimensions = get_total_feat_dims(&feature_collections);
54
55 FeatureSpaceInfo {
56 base_dimensions,
57 feature_dimensions,
58 feature_collections,
59 sketcher
60 }
61}
62
63fn get_test_vector_only_space_info_directory() -> SpaceInfoDirectory {
64 let mut feature_spaces = Vec::new();
65
66 feature_spaces.push(get_test_vector_only_feature_space_info(1));
67 feature_spaces.push(get_test_vector_only_feature_space_info(TEST_VECTOR_SIZE));
68
69 SpaceInfoDirectory {
70 feature_spaces
71 }
72}
73
74pub fn get_test_vector_only_context() -> Context {
75 let type_info_directory = get_test_vector_only_type_info_directory();
76 let space_info_directory = get_test_vector_only_space_info_directory();
77 let primitive_directory = PrimitiveDirectory::new(&type_info_directory);
78 Context {
79 type_info_directory,
80 space_info_directory,
81 primitive_directory
82 }
83}
84
85pub fn random_scalar() -> f32 {
86 let mut rng = rand::thread_rng();
87 let result : f32 = rng.gen();
88 result
89}
90
91pub fn random_data_point(in_dimensions : usize, out_dimensions : usize) -> DataPoint {
92 let in_vec = random_vector(in_dimensions);
93 let out_vec = random_vector(out_dimensions);
94
95 let mut rng = rand::thread_rng();
96 let weight_sqrt : f32 = rng.gen();
97 let weight = weight_sqrt * weight_sqrt;
98
99 DataPoint {
100 in_vec,
101 out_vec,
102 weight
103 }
104}
105
106pub fn standard_normal_inverse_wishart(feature_dimensions : usize, out_dimensions : usize) -> NormalInverseWishart {
107 let mean = Array::zeros((out_dimensions, feature_dimensions));
108
109 let in_precision = Array::eye(feature_dimensions);
110 let out_precision = Array::eye(out_dimensions);
111 let little_v = (out_dimensions as f32) + 2.0f32;
112
113 NormalInverseWishart::new(mean, in_precision, out_precision, little_v)
114}
115
116pub fn random_normal_inverse_wishart(feature_dimensions : usize, out_dimensions : usize) -> NormalInverseWishart {
117 let mean = random_matrix(out_dimensions, feature_dimensions);
118 let precision = random_psd_matrix(feature_dimensions);
119 let big_v = random_psd_matrix(out_dimensions);
120 let little_v = (out_dimensions as f32) + 4.0f32;
121
122 NormalInverseWishart::new(mean, precision, big_v, little_v)
123}
124pub fn random_model_app<'a>(ctxt : &'a Context, func_type_id : TypeId) -> (Model<'a>, Model<'a>) {
127 let arg_type_id = ctxt.get_arg_type_id(func_type_id);
128
129 let in_type_id = ctxt.get_arg_type_id(arg_type_id);
130 let middle_type_id = ctxt.get_ret_type_id(arg_type_id);
131
132 let ret_type_id = ctxt.get_ret_type_id(func_type_id);
133 let arg_model = random_model(ctxt, in_type_id, middle_type_id);
134 let func_model = random_model(ctxt, arg_type_id, ret_type_id);
135 (func_model, arg_model)
136}
137
138pub struct TestPriorSpecification { }
139impl PriorSpecification for TestPriorSpecification {
140 fn get_in_precision_multiplier(&self, _feat_dims : usize) -> f32 {
141 1.0f32
142 }
143 fn get_out_covariance_multiplier(&self, _out_dims : usize) -> f32 {
144 1.0f32
145 }
146 fn get_out_pseudo_observations(&self, out_dims : usize) -> f32 {
147 (out_dims as f32) + 4.0f32
148 }
149}
150
151pub fn random_model<'a>(ctxt : &'a Context, arg_type_id : TypeId, ret_type_id : TypeId) -> Model {
152 let prior_specification = TestPriorSpecification { };
153
154 let mut result = Model::new(&prior_specification, arg_type_id, ret_type_id, ctxt);
155 let arg_feat_space_info = ctxt.get_feature_space_info(arg_type_id);
156 let ret_feat_space_info = ctxt.get_feature_space_info(ret_type_id);
157 result.data = random_normal_inverse_wishart(arg_feat_space_info.feature_dimensions,
158 ret_feat_space_info.base_dimensions);
159 result
160}
161
162pub fn assert_equal_schmears(one : &Schmear, two : &Schmear) {
163 assert_equal_matrices(one.covariance.view(), two.covariance.view());
164 assert_equal_vectors(one.mean.view(), two.mean.view());
165}
166
167pub fn assert_equal_inv_schmears(one : &InverseSchmear, two : &InverseSchmear) {
168 assert_equal_matrices(one.precision.view(), two.precision.view());
169 assert_equal_vectors(one.mean.view(), two.mean.view());
170}
171
172pub fn relative_frob_norm_error(actual : ArrayView2<f32>, expected : ArrayView2<f32>) -> f32 {
173 let denominator = expected.opnorm_fro().unwrap();
174 let diff = &actual - &expected;
175 let diff_norm = diff.opnorm_fro().unwrap();
176 diff_norm / denominator
177}
178
179pub fn are_equal_matrices_to_within(one : ArrayView2<f32>, two : ArrayView2<f32>, within : f32, print : bool) -> bool {
180 let diff = &one - &two;
181 let frob_norm = diff.opnorm_fro().unwrap();
182 if (frob_norm > within) {
183 if (print) {
184 println!("Actual: {}", one);
185 println!("Expected: {}", two);
186 println!("Diff: {}", diff);
187 println!("Frob norm: {}", frob_norm);
188 }
189 false
190 } else {
191 true
192 }
193}
194
195pub fn assert_equal_distributions_to_within(one : &NormalInverseWishart, two : &NormalInverseWishart, within : f32) {
196 assert_equal_matrices_to_within(one.mean.view(), two.mean.view(), within);
197 assert_equal_matrices_to_within(one.precision.view(), two.precision.view(), within);
198 assert_equal_matrices_to_within(one.big_v.view(), two.big_v.view(), within);
199 assert_eps_equals_to_within(one.little_v, two.little_v, within);
200}
201
202pub fn assert_equal_matrices_to_within(one : ArrayView2<f32>, two : ArrayView2<f32>, within : f32) {
203 if (!are_equal_matrices_to_within(one, two, within, true)) {
204 panic!();
205 }
206}
207
208pub fn assert_equal_matrices(one : ArrayView2<f32>, two : ArrayView2<f32>) {
209 assert_equal_matrices_to_within(one, two, DEFAULT_TEST_THRESH);
210}
211
212pub fn are_equal_vectors_to_within(one : ArrayView1<f32>, two : ArrayView1<f32>, within : f32, print : bool) -> bool {
213 let diff = &one - &two;
214 let sq_norm = diff.dot(&diff);
215 let norm = sq_norm.sqrt();
216 if (norm > within) {
217 if (print) {
218 println!("Actual: {}", one);
219 println!("Expected: {}", two);
220 println!("Diff: {}", diff);
221 println!("Norm: {}", norm);
222 }
223 false
224 } else {
225 true
226 }
227}
228
229pub fn assert_equal_vectors_to_within(one : ArrayView1<f32>, two : ArrayView1<f32>, within : f32) {
230 if(!are_equal_vectors_to_within(one, two, within, true)) {
231 panic!();
232 }
233}
234
235pub fn assert_equal_vector_term(actual : TermReference, expected : ArrayView1<f32>) {
236 if let TermReference::VecRef(_, vec) = actual {
237 assert_equal_vectors(from_noisy(vec.view()).view(), expected);
238 } else {
239 panic!();
240 }
241}
242
243pub fn assert_equal_vectors(one : ArrayView1<f32>, two : ArrayView1<f32>) {
244 assert_equal_vectors_to_within(one, two, DEFAULT_TEST_THRESH);
245}
246
247pub fn assert_eps_equals_to_within(one : f32, two : f32, epsilon : f32) {
248 let diff = one - two;
249 if (diff.abs() > epsilon) {
250 println!("Actual: {} Expected: {}", one, two);
251 panic!();
252 }
253}
254
255pub fn assert_eps_equals(one : f32, two : f32) {
256 assert_eps_equals_to_within(one, two, DEFAULT_TEST_THRESH);
257}
258pub fn assert_greater(one : f32, two : f32) {
259 if (two >= one) {
260 println!("{} is greater than {}", two, one);
261 panic!();
262 }
263}
264pub fn random_vector(t : usize) -> Array1<f32> {
265 Array::random((t,), StandardNormal)
266}
267pub fn random_matrix(t : usize, s : usize) -> Array2<f32> {
268 Array::random((t, s), StandardNormal)
269}
270pub fn random_diag_matrix(t : usize) -> Array2<f32> {
271 let mut result = Array::zeros((t, t));
272 let diag = Array::random((t,), StandardNormal);
273 for i in 0..t {
274 result[[i, i]] = diag[[i,]];
275 }
276 result
277}
278pub fn random_psd_matrix(t : usize) -> Array2<f32> {
279 let mut result = Array::zeros((t, t));
280 for _ in 0..t {
281 let matrix_sqrt = random_matrix(t, t);
282 let matrix = matrix_sqrt.t().dot(&matrix_sqrt);
283 result += &matrix;
284 }
285 result
286}
287
288pub fn random_schmear(t : usize) -> Schmear {
289 let covariance = random_psd_matrix(t);
290 let mean = random_vector(t);
291 Schmear {
292 mean,
293 covariance
294 }
295}
296pub fn random_inv_schmear(t : usize) -> InverseSchmear {
297 let precision = random_psd_matrix(t);
298 let mean = random_vector(t);
299 InverseSchmear {
300 mean,
301 precision
302 }
303}
304
305pub fn random_func_scatter_tensor(t : usize, s : usize) -> FuncScatterTensor {
306 let in_scatter = random_psd_matrix(s);
307 let out_scatter = random_psd_matrix(t);
308 FuncScatterTensor {
309 in_scatter,
310 out_scatter
311 }
312}
313
314pub fn random_func_schmear(t : usize, s : usize) -> FuncSchmear {
315 let scatter_tensor = random_func_scatter_tensor(t, s);
316 let mean = random_matrix(t, s);
317 let result = FuncSchmear {
318 mean : mean,
319 covariance : scatter_tensor
320 };
321 result
322}
323
324pub fn empirical_gradient<F>(f : F, x : ArrayView1<f32>) -> Array1<f32>
325 where F : Fn(ArrayView1<f32>) -> f32 {
326
327 let epsilon = 0.001f32;
328 let y = f(x);
329
330 let s = x.shape()[0];
331
332 let mut result = Array::zeros((s,));
333 for i in 0..s {
334 let mut delta_x : Array1<f32> = Array::zeros((s,));
335 delta_x[[i,]] = epsilon;
336
337 let new_x = &x + &delta_x;
338 let new_y = f(new_x.view());
339 let delta_y = new_y - y;
340
341 let grad = delta_y / epsilon;
342
343 result[[i,]] = grad;
344 }
345 result
346}
347
348pub fn empirical_jacobian<F>(f : F, x : ArrayView1<f32>) -> Array2<f32>
349 where F : Fn(ArrayView1<f32>) -> Array1<f32> {
350 let epsilon = 0.001f32;
351 let y = f(x);
352 let s = x.shape()[0];
353 let t = y.shape()[0];
354
355 let mut result = Array::zeros((t, s));
356 for i in 0..s {
357 let mut delta_x : Array1<f32> = Array::zeros((s,));
358 delta_x[[i,]] = epsilon;
359
360 let new_x = &x + &delta_x;
361 let new_y = f(new_x.view());
362 let delta_y = &new_y - &y;
363
364 let grad = delta_y / epsilon;
365 for j in 0..t {
366 result[[j, i]] = grad[[j,]];
367 }
368 }
369 result
370}