-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathtest_parameter_handling_mixin.cc
248 lines (207 loc) · 8.62 KB
/
test_parameter_handling_mixin.cc
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/*
* Copyright (C) 2018 Swift Navigation Inc.
* Contact: Swift Navigation <[email protected]>
*
* This source is subject to the license found in the file 'LICENSE' which must
* be distributed together with this source. All other rights reserved.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <gtest/gtest.h>
#include "test_utils.h"
namespace albatross {
/*
* Simply makes sure that a BaseModel that should be able to
* make perfect predictions compiles and runs as expected.
*/
TEST(test_parameter_handler, test_get_set) {
auto p = TestParameterHandler();
auto params = p.get_params();
for (auto &pair : params) {
pair.second.value += 1.;
}
// Make sure modifying the returned map doesn't modify the original;
auto unmodified_params = p.get_params();
EXPECT_EQ(unmodified_params["A"], 1.);
EXPECT_EQ(unmodified_params["B"], 2.);
// Then make sure after we set the new params they stick.
p.set_params(params);
auto modified_params = p.get_params();
EXPECT_EQ(modified_params["A"], 2.);
EXPECT_EQ(modified_params["B"], 3.);
};
/*
* Here we test to make sure that the parameters are in the same
* order regardless of how they're created. This is the case
* when using std::map as a store, but if we were to change backends
* we'd want to make sure this property held.
*/
TEST(test_parameter_handler, test_is_ordered) {
const ParameterStore ordered = {
{"1", Parameter(1.)}, {"2", Parameter(2.)}, {"3", Parameter(3.)}};
const ParameterStore unordered = {
{"2", Parameter(2.)}, {"1", Parameter(1.)}, {"3", Parameter(3.)}};
// march through each store one by one and make sure the keys are the same
typedef ParameterStore::const_iterator iter_t;
for (std::pair<iter_t, iter_t> p(ordered.begin(), unordered.begin());
p.first != ordered.end(); ++p.first, ++p.second) {
const auto ordered_pair = *p.first;
const auto unordered_pair = *p.second;
EXPECT_EQ(ordered_pair.first, unordered_pair.first);
}
EXPECT_EQ(ordered, unordered);
}
/*
* Test the helper functions that let you get and set parameters from
* a vector of values.
*/
TEST(test_parameter_handler, test_get_set_from_vector) {
const ParameterStore expected = {
{"1", Parameter(4.)}, {"2", Parameter(5.)}, {"3", Parameter(6.)}};
const std::vector<ParameterValue> expected_param_vector = {4., 5., 6.};
const ParameterStore original = {
{"2", Parameter(2.)}, {"1", Parameter(1.)}, {"3", Parameter(3.)}};
const std::vector<ParameterValue> original_param_vector = {1., 2., 3.};
MockParameterHandler original_handler(original);
// Make sure we start with the parameter vector we'd expect, even though
// it was initialized out of order.
expect_parameter_vector_equal(
original_param_vector, original_handler.get_tunable_parameters().values);
// Now set the parameters using a new vector and make sure they stick
original_handler.set_tunable_params_values(expected_param_vector);
expect_parameter_vector_equal(
expected_param_vector, original_handler.get_tunable_parameters().values);
}
/*
* Test the helper functions that let you get and set parameters from
* a vector of values.
*/
TEST(test_parameter_handler, test_get_set_from_vector_with_fixed) {
const ParameterStore expected = {{"1", Parameter(4.)},
{"2", Parameter(5.)},
{"foo", {1., FixedPrior()}},
{"3", Parameter(6.)}};
const std::vector<ParameterValue> expected_param_vector = {4., 5., 6.};
ParameterStore original(expected);
original["1"].value = 1.;
original["2"].value = 2.;
original["foo"].value = -2.;
original["3"].value = 3.;
const std::vector<ParameterValue> original_param_vector = {1., 2., 3.};
MockParameterHandler original_handler(original);
// Make sure we start with the parameter vector we'd expect, even though
// it was initialized out of order.
expect_parameter_vector_equal(
original_param_vector, original_handler.get_tunable_parameters().values);
// Now set the parameters using a new vector and make sure they stick
original_handler.set_tunable_params_values(expected_param_vector);
expect_parameter_vector_equal(
expected_param_vector, original_handler.get_tunable_parameters().values);
}
TEST(test_parameter_handler, test_prior_log_likelihood) {
auto p = TestParameterHandler();
auto params = p.get_params();
double expected;
{
ParameterPrior gaussian_prior = GaussianPrior(3., 5.);
ParameterPrior uninformative_prior = UninformativePrior();
expected = gaussian_prior.log_pdf(p.get_params().at("A").value) +
uninformative_prior.log_pdf(p.get_params().at("B").value);
p.set_prior("A", gaussian_prior);
p.set_prior("B", uninformative_prior);
}
EXPECT_DOUBLE_EQ(expected, p.prior_log_likelihood());
};
TEST(test_parameter_handler, test_set_prior) {
auto p = TestParameterHandler();
const auto orig_params = p.get_params();
const auto orig_param_vector = p.get_tunable_parameters().values;
for (const auto &pair : orig_params) {
ParameterPrior gaussian_prior = GaussianPrior(pair.second.value + 1., 1.);
p.set_prior(pair.first, gaussian_prior);
}
const auto params_with_priors = p.get_params();
// The actual parameters now have priors, so they shouldn't be the
// same.
EXPECT_NE(orig_params, params_with_priors);
// But the parameter values shouldn't have changed.
expect_parameter_vector_equal(orig_param_vector,
p.get_tunable_parameters().values);
// We should also be able to change the parameter values without
// modifying the prior.
for (const auto &pair : orig_params) {
p.set_param(pair.first, pair.second.value + 3.14159);
EXPECT_EQ(p.get_params().at(pair.first).prior,
params_with_priors.at(pair.first).prior);
}
};
TEST(test_parameter_handler, test_set_param_values_doesnt_overwrite_prior) {
auto p = TestParameterHandler();
const auto orig_params = p.get_params();
std::map<std::string, double> new_params;
for (const auto &pair : orig_params) {
new_params[pair.first] = pair.second.value + 1.;
}
p.set_param_values(new_params);
for (const auto &pair : orig_params) {
// Make sure we changed the parameter value
const auto new_param = p.get_params().at(pair.first);
EXPECT_NE(new_param.value, pair.second.value);
// but not the prior.
EXPECT_TRUE(pair.second.prior == new_param.prior);
}
};
class MacroParameterHandler : public ParameterHandlingMixin {
public:
ALBATROSS_DECLARE_PARAMS(foo, bar)
void expect_foo_equals(double x) { EXPECT_DOUBLE_EQ(this->foo.value, x); }
void expect_bar_equals(double x) { EXPECT_DOUBLE_EQ(this->bar.value, x); }
};
/*
* Simply makes sure that a BaseModel that should be able to
* make perfect predictions compiles and runs as expected.
*/
TEST(test_parameter_handler, test_get_set_with_macros) {
auto p = MacroParameterHandler();
p.set_param("foo", Parameter(3.14159));
p.set_param("bar", Parameter(sqrt(2.)));
auto params = p.get_params();
for (auto &pair : params) {
pair.second.value += 1.;
}
// Make sure modifying the returned map doesn't modify the original;
auto unmodified_params = p.get_params();
EXPECT_EQ(unmodified_params["foo"].value, 3.14159);
EXPECT_EQ(unmodified_params["bar"].value, sqrt(2.));
// Then make sure after we set the new params they stick.
p.set_params(params);
auto modified_params = p.get_params();
EXPECT_EQ(modified_params["foo"], 4.14159);
EXPECT_EQ(modified_params["bar"], sqrt(2.) + 1.);
p.expect_foo_equals(4.14159);
p.expect_bar_equals(sqrt(2.) + 1.);
};
TEST(test_parameter_handler, test_set_params_if_exists_in_any) {
MacroParameterHandler x;
TestParameterHandler y;
const auto x_params = x.get_params();
const auto y_params = y.get_params();
const auto all_params = map_join(x_params, y_params);
const Parameter dummy(std::sqrt(2.));
EXPECT_FALSE(set_param_if_exists_in_any("dummy", dummy, &x, &y));
EXPECT_EQ(all_params, map_join(x.get_params(), y.get_params()));
const double to_add = 3.14159;
for (const auto &pair : all_params) {
const double before = pair.second.value;
Parameter new_param(pair.second);
new_param.value += to_add;
EXPECT_TRUE(set_param_if_exists_in_any(pair.first, new_param, &x, &y));
const Parameter modified =
map_join(x.get_params(), y.get_params()).at(pair.first);
EXPECT_TRUE(modified == new_param);
EXPECT_TRUE(before + to_add == modified.value);
}
}
} // namespace albatross