Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""Unit testing of tests in docs/source/examples"""
2import unittest
3import os
4import pickle
5import numpy as np
7from gpkit import settings, Model, Variable
8from gpkit.tests.helpers import generate_example_tests
9from gpkit.small_scripts import mag
10from gpkit.small_classes import Quantity
11from gpkit.constraints.loose import Loose
12from gpkit.exceptions import (UnknownInfeasible,
13 PrimalInfeasible, DualInfeasible, UnboundedGP)
16def assert_logtol(first, second, logtol=1e-6):
17 "Asserts that the logs of two arrays have a given abstol"
18 np.testing.assert_allclose(np.log(mag(first)), np.log(mag(second)),
19 atol=logtol, rtol=0)
22# pylint: disable=too-many-public-methods
23class TestExamples(unittest.TestCase):
24 """
25 To test a new example, add a function called `test_$EXAMPLENAME`, where
26 $EXAMPLENAME is the name of your example in docs/source/examples without
27 the file extension.
29 This function should accept two arguments (e.g. 'self' and 'example').
30 The imported example script will be passed to the second: anything that
31 was a global variable (e.g, "sol") in the original script is available
32 as an attribute (e.g., "example.sol")
34 If you don't want to perform any checks on the example besides making
35 sure it runs, just put "pass" as the function's body, e.g.:
37 def test_dummy_example(self, example):
38 pass
40 But it's good practice to ensure the example's solution as well, e.g.:
42 def test_dummy_example(self, example):
43 self.assertAlmostEqual(example.sol["cost"], 3.121)
44 """
46 # TODO: allow enabling plotting examples, make plots in correct folder...
47 # def test_plot_sweep1d(self, _):
48 # import matplotlib.pyplot as plt
49 # plt.close("all")
51 def test_issue_1513(self, example):
52 pass
54 def test_issue_1522(self, example):
55 pass
57 def test_autosweep(self, example):
58 from gpkit import ureg
59 bst1, tol1 = example.bst1, example.tol1
60 bst2, tol2 = example.bst2, example.tol2
62 l_ = np.linspace(1, 10, 100)
63 for bst in [bst1, example.bst1_loaded]:
64 sol1 = bst.sample_at(l_)
65 assert_logtol(sol1("l"), l_)
66 assert_logtol(sol1("A"), l_**2 + 1, tol1)
67 assert_logtol(sol1["cost"], (l_**2 + 1)**2, tol1)
68 self.assertEqual(Quantity(1.0, sol1("A").units),
69 Quantity(1.0, ureg.m)**2)
71 ndig = -int(np.log10(tol2))
72 self.assertAlmostEqual(bst2.cost_at("cost", 3), 1.0, ndig)
73 # before corner
74 A_bc = np.linspace(1, 3, 50)
75 sol_bc = bst2.sample_at(A_bc)
76 assert_logtol(sol_bc("A"), (A_bc/3)**0.5, tol2)
77 assert_logtol(sol_bc["cost"], A_bc/3, tol2)
78 # after corner
79 A_ac = np.linspace(3, 10, 50)
80 sol_ac = bst2.sample_at(A_ac)
81 assert_logtol(sol_ac("A"), (A_ac/3)**2, tol2)
82 assert_logtol(sol_ac["cost"], (A_ac/3)**4, tol2)
84 def test_treemap(self, example):
85 pass
87 def test_checking_result_changes(self, example):
88 sol = example.sol
89 self.assertAlmostEqual(sol["cost"], 0.48, 2)
91 def test_evaluated_fixed_variables(self, example):
92 sol = example.sol
93 t_night = example.t_night
94 self.assertTrue((sol["variables"][t_night] == [16, 12, 8]).all())
96 def test_evaluated_free_variables(self, example):
97 x2 = example.x2
98 sol = example.sol
99 self.assertTrue(abs(sol(x2) - 4) <= 1e-4)
101 def test_external_constraint(self, example):
102 pass
104 def test_migp(self, example):
105 if settings["default_solver"] == "mosek_conif":
106 assert_logtol(example.sol(example.x), [1]*3 + [2]*6 + [3]*2)
107 else:
108 assert_logtol(example.sol(example.x),
109 np.sqrt(example.sol(example.num)))
111 def test_external_function(self, example):
112 external_code = example.external_code
113 self.assertEqual(external_code(0), 0)
115 def test_external_sp(self, example):
116 m = example.m
117 sol = m.localsolve(verbosity=0)
118 self.assertAlmostEqual(sol["cost"], 0.707, places=3)
120 def test_freeing_fixed_variables(self, example):
121 x = example.x
122 y = Variable("y", 3)
123 m = Model(x, [x >= 1 + y, y >= 1])
124 sol = m.solve(verbosity=0)
125 self.assertTrue(abs(sol["cost"] - 4) <= 1e-4)
126 self.assertTrue(y in sol["constants"])
128 del m.substitutions["y"]
129 sol = m.solve(verbosity=0)
130 self.assertTrue(abs(sol["cost"] - 2) <= 1e-4)
131 self.assertTrue(y in sol["freevariables"])
133 def test_gettingstarted(self, example):
134 pass
137 def test_loose_constraintsets(self, example):
138 m = example.m
139 sol = m.solve(verbosity=0)
140 self.assertAlmostEqual(sol["cost"], 2, 3)
142 def test_sub_multi_values(self, example):
143 x = example.x
144 y = example.y
145 z = example.z
146 p = example.p
147 self.assertTrue(all(p.sub({x: 1, "y": 2}) == 2*z))
148 self.assertTrue(all(
149 p.sub({x: 1, y: 2, "z": [1, 2]}) == z.sub({z: [2, 4]})
150 ))
152 def test_substitutions(self, example):
153 x = example.x
154 p = example.p
155 self.assertTrue(p.sub({x: 3}) == 9)
156 self.assertTrue(p.sub({x.key: 3}) == 9)
157 self.assertTrue(p.sub({"x": 3}) == 9)
159 def test_tight_constraintsets(self, example):
160 m = example.m
161 sol = m.solve(verbosity=0)
162 self.assertAlmostEqual(sol["cost"], 2, places=2)
164 def test_vectorization(self, example):
165 x = example.x
166 y = example.y
167 z = example.z
168 self.assertEqual(y.shape, (5, 3))
169 self.assertEqual(x.shape, (2, 5, 3))
170 self.assertEqual(z.shape, (7, 3))
172 def test_model_var_access(self, example):
173 model = example.PS
174 _ = model["E"]
175 with self.assertRaises(ValueError):
176 _ = model["m"] # multiple variables called m
178 def test_performance_modeling(self, example):
179 m = Model(example.M.cost, Loose(example.M), example.M.substitutions)
181 sol = m.solve(verbosity=0)
182 sol.table()
183 sol.save("solution.pkl")
184 sol.table()
185 sol_loaded = pickle.load(open("solution.pkl", "rb"))
186 sol_loaded.table()
188 sweepsol = m.sweep({example.AC.fuse.W: (50, 100, 150)}, verbosity=0)
189 sweepsol.table()
190 sweepsol.save("sweepsolution.pkl")
191 sweepsol.table()
192 sol_loaded = pickle.load(open("sweepsolution.pkl", "rb"))
193 sol_loaded.table()
195 def test_sp_to_gp_sweep(self, example):
196 sol = example.sol
197 cost = sol["cost"]
198 self.assertAlmostEqual(cost[0], 4628.21, places=2)
199 self.assertAlmostEqual(cost[1], 6226.60, places=2)
200 self.assertAlmostEqual(cost[2], 7362.77, places=2)
202 def test_boundschecking(self, example): # pragma: no cover
203 if "mosek_cli" in settings["default_solver"]:
204 with self.assertRaises(UnknownInfeasible):
205 example.gp.solve(verbosity=0)
206 else:
207 example.gp.solve(verbosity=0) # mosek_conif and cvxopt solve it
209 def test_vectorize(self, example):
210 pass
212 def test_primal_infeasible_ex1(self, example):
213 primal_or_unknown = PrimalInfeasible
214 if "cvxopt" in settings["default_solver"]: # pragma: no cover
215 primal_or_unknown = UnknownInfeasible
216 with self.assertRaises(primal_or_unknown):
217 example.m.solve(verbosity=0)
219 def test_primal_infeasible_ex2(self, example):
220 primal_or_unknown = PrimalInfeasible
221 if "cvxopt" in settings["default_solver"]: # pragma: no cover
222 primal_or_unknown = UnknownInfeasible
223 with self.assertRaises(primal_or_unknown):
224 example.m.solve(verbosity=0)
226 def test_docstringparsing(self, example):
227 pass
229 def test_debug(self, example):
230 dual_or_primal = DualInfeasible
231 if "mosek_conif" == settings["default_solver"]: # pragma: no cover
232 dual_or_primal = PrimalInfeasible
233 with self.assertRaises(UnboundedGP):
234 example.m.gp()
235 with self.assertRaises(dual_or_primal):
236 gp = example.m.gp(checkbounds=False)
237 gp.solve(verbosity=0)
239 primal_or_unknown = PrimalInfeasible
240 if "cvxopt" == settings["default_solver"]: # pragma: no cover
241 primal_or_unknown = UnknownInfeasible
242 with self.assertRaises(primal_or_unknown):
243 example.m2.solve(verbosity=0)
245 with self.assertRaises(UnboundedGP):
246 example.m3.gp()
247 with self.assertRaises(DualInfeasible):
248 gp3 = example.m3.gp(checkbounds=False)
249 gp3.solve(verbosity=0)
251 def test_simple_sp(self, example):
252 pass
254 def test_simple_box(self, example):
255 pass
257 def test_x_greaterthan_1(self, example):
258 pass
260 def test_beam(self, example):
261 self.assertFalse(np.isnan(example.sol("w")).any())
263 def test_water_tank(self, example):
264 pass
266 def test_sin_approx_example(self, example):
267 pass
269 def test_simpleflight(self, example):
270 self.assertTrue(example.sol.almost_equal(example.sol_loaded))
271 for sol in [example.sol, example.sol_loaded]:
272 freevarcheck = {
273 "A": 8.46,
274 "C_D": 0.0206,
275 "C_f": 0.0036,
276 "C_L": 0.499,
277 "Re": 3.68e+06,
278 "S": 16.4,
279 "W": 7.34e+03,
280 "V": 38.2,
281 "W_w": 2.40e+03
282 }
283 # sensitivity values from p. 34 of W. Hoburg's thesis
284 senscheck = {
285 r"(\frac{S}{S_{wet}})": 0.4300,
286 "e": -0.4785,
287 "V_{min}": -0.3691,
288 "k": 0.4300,
289 r"\mu": 0.0860,
290 "(CDA0)": 0.0915,
291 "C_{L,max}": -0.1845,
292 r"\tau": -0.2903,
293 "N_{ult}": 0.2903,
294 "W_0": 1.0107,
295 r"\rho": -0.2275
296 }
297 for key in freevarcheck:
298 sol_rat = mag(sol["variables"][key])/freevarcheck[key]
299 self.assertTrue(abs(1-sol_rat) < 1e-2)
300 for key in senscheck:
301 sol_rat = sol["sensitivities"]["variables"][key]/senscheck[key]
302 self.assertTrue(abs(1-sol_rat) < 1e-2)
304 def test_relaxation(self, example):
305 pass
307 def test_unbounded(self, example):
308 pass
311FILE_DIR = os.path.dirname(os.path.realpath(__file__))
312EXAMPLE_DIR = os.path.abspath(FILE_DIR + '../../../docs/source/examples')
313SOLVERS = settings["installed_solvers"]
314if os.path.isdir(EXAMPLE_DIR):
315 TESTS = generate_example_tests(EXAMPLE_DIR, [TestExamples], SOLVERS)
316else: # pragma: no cover
317 TESTS = []
319if __name__ == "__main__": # pragma: no cover
320 # pylint:disable=wrong-import-position
321 from gpkit.tests.helpers import run_tests
322 run_tests(TESTS)