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_autosweep(self, example):
52 from gpkit import ureg
53 bst1, tol1 = example.bst1, example.tol1
54 bst2, tol2 = example.bst2, example.tol2
56 l_ = np.linspace(1, 10, 100)
57 for bst in [bst1, example.bst1_loaded]:
58 sol1 = bst.sample_at(l_)
59 assert_logtol(sol1("l"), l_)
60 assert_logtol(sol1("A"), l_**2 + 1, tol1)
61 assert_logtol(sol1["cost"], (l_**2 + 1)**2, tol1)
62 self.assertEqual(Quantity(1.0, sol1("A").units),
63 Quantity(1.0, ureg.m)**2)
65 ndig = -int(np.log10(tol2))
66 self.assertAlmostEqual(bst2.cost_at("cost", 3), 1.0, ndig)
67 # before corner
68 A_bc = np.linspace(1, 3, 50)
69 sol_bc = bst2.sample_at(A_bc)
70 assert_logtol(sol_bc("A"), (A_bc/3)**0.5, tol2)
71 assert_logtol(sol_bc["cost"], A_bc/3, tol2)
72 # after corner
73 A_ac = np.linspace(3, 10, 50)
74 sol_ac = bst2.sample_at(A_ac)
75 assert_logtol(sol_ac("A"), (A_ac/3)**2, tol2)
76 assert_logtol(sol_ac["cost"], (A_ac/3)**4, tol2)
78 def test_treemap(self, example):
79 pass
81 def test_checking_result_changes(self, example):
82 sol = example.sol
83 self.assertAlmostEqual(sol["cost"], 0.48, 2)
85 def test_evaluated_fixed_variables(self, example):
86 sol = example.sol
87 t_night = example.t_night
88 self.assertTrue((sol["variables"][t_night] == [16, 12, 8]).all())
90 def test_evaluated_free_variables(self, example):
91 x2 = example.x2
92 sol = example.sol
93 self.assertTrue(abs(sol(x2) - 4) <= 1e-4)
95 def test_external_constraint(self, example):
96 pass
98 def test_migp(self, example):
99 if settings["default_solver"] == "mosek_conif":
100 assert_logtol(example.sol(example.x), [1]*3 + [2]*6 + [3]*2)
101 else:
102 assert_logtol(example.sol(example.x),
103 np.sqrt(example.sol(example.num)))
105 def test_external_function(self, example):
106 external_code = example.external_code
107 self.assertEqual(external_code(0), 0)
109 def test_external_sp(self, example):
110 m = example.m
111 sol = m.localsolve(verbosity=0)
112 self.assertAlmostEqual(sol["cost"], 0.707, places=3)
114 def test_freeing_fixed_variables(self, example):
115 x = example.x
116 y = Variable("y", 3)
117 m = Model(x, [x >= 1 + y, y >= 1])
118 sol = m.solve(verbosity=0)
119 self.assertTrue(abs(sol["cost"] - 4) <= 1e-4)
120 self.assertTrue(y in sol["constants"])
122 del m.substitutions["y"]
123 sol = m.solve(verbosity=0)
124 self.assertTrue(abs(sol["cost"] - 2) <= 1e-4)
125 self.assertTrue(y in sol["freevariables"])
127 def test_gettingstarted(self, example):
128 pass
131 def test_loose_constraintsets(self, example):
132 m = example.m
133 sol = m.solve(verbosity=0)
134 self.assertAlmostEqual(sol["cost"], 2, 3)
136 def test_sub_multi_values(self, example):
137 x = example.x
138 y = example.y
139 z = example.z
140 p = example.p
141 self.assertTrue(all(p.sub({x: 1, "y": 2}) == 2*z))
142 self.assertTrue(all(
143 p.sub({x: 1, y: 2, "z": [1, 2]}) == z.sub({z: [2, 4]})
144 ))
146 def test_substitutions(self, example):
147 x = example.x
148 p = example.p
149 self.assertTrue(p.sub({x: 3}) == 9)
150 self.assertTrue(p.sub({x.key: 3}) == 9)
151 self.assertTrue(p.sub({"x": 3}) == 9)
153 def test_tight_constraintsets(self, example):
154 m = example.m
155 sol = m.solve(verbosity=0)
156 self.assertAlmostEqual(sol["cost"], 2, places=2)
158 def test_vectorization(self, example):
159 x = example.x
160 y = example.y
161 z = example.z
162 self.assertEqual(y.shape, (5, 3))
163 self.assertEqual(x.shape, (2, 5, 3))
164 self.assertEqual(z.shape, (7, 3))
166 def test_model_var_access(self, example):
167 model = example.PS
168 _ = model["E"]
169 with self.assertRaises(ValueError):
170 _ = model["m"] # multiple variables called m
172 def test_performance_modeling(self, example):
173 m = Model(example.M.cost, Loose(example.M), example.M.substitutions)
175 sol = m.solve(verbosity=0)
176 sol.table()
177 sol.save("solution.pkl")
178 sol.table()
179 sol_loaded = pickle.load(open("solution.pkl", "rb"))
180 sol_loaded.table()
182 sweepsol = m.sweep({example.AC.fuse.W: (50, 100, 150)}, verbosity=0)
183 sweepsol.table()
184 sweepsol.save("sweepsolution.pkl")
185 sweepsol.table()
186 sol_loaded = pickle.load(open("sweepsolution.pkl", "rb"))
187 sol_loaded.table()
189 def test_sp_to_gp_sweep(self, example):
190 sol = example.sol
191 cost = sol["cost"]
192 self.assertAlmostEqual(cost[0], 4628.21, places=2)
193 self.assertAlmostEqual(cost[1], 6226.60, places=2)
194 self.assertAlmostEqual(cost[2], 7362.77, places=2)
196 def test_boundschecking(self, example): # pragma: no cover
197 if "mosek_cli" in settings["default_solver"]:
198 with self.assertRaises(UnknownInfeasible):
199 example.gp.solve(verbosity=0)
200 else:
201 example.gp.solve(verbosity=0) # mosek_conif and cvxopt solve it
203 def test_vectorize(self, example):
204 pass
206 def test_primal_infeasible_ex1(self, example):
207 primal_or_unknown = PrimalInfeasible
208 if "cvxopt" in settings["default_solver"]: # pragma: no cover
209 primal_or_unknown = UnknownInfeasible
210 with self.assertRaises(primal_or_unknown):
211 example.m.solve(verbosity=0)
213 def test_primal_infeasible_ex2(self, example):
214 primal_or_unknown = PrimalInfeasible
215 if "cvxopt" in settings["default_solver"]: # pragma: no cover
216 primal_or_unknown = UnknownInfeasible
217 with self.assertRaises(primal_or_unknown):
218 example.m.solve(verbosity=0)
220 def test_docstringparsing(self, example):
221 pass
223 def test_debug(self, example):
224 dual_or_primal = DualInfeasible
225 if "mosek_conif" == settings["default_solver"]: # pragma: no cover
226 dual_or_primal = PrimalInfeasible
227 with self.assertRaises(UnboundedGP):
228 example.m.gp()
229 with self.assertRaises(dual_or_primal):
230 gp = example.m.gp(checkbounds=False)
231 gp.solve(verbosity=0)
233 primal_or_unknown = PrimalInfeasible
234 if "cvxopt" == settings["default_solver"]: # pragma: no cover
235 primal_or_unknown = UnknownInfeasible
236 with self.assertRaises(primal_or_unknown):
237 example.m2.solve(verbosity=0)
239 with self.assertRaises(UnboundedGP):
240 example.m3.gp()
241 with self.assertRaises(DualInfeasible):
242 gp3 = example.m3.gp(checkbounds=False)
243 gp3.solve(verbosity=0)
245 def test_simple_sp(self, example):
246 pass
248 def test_simple_box(self, example):
249 pass
251 def test_x_greaterthan_1(self, example):
252 pass
254 def test_beam(self, example):
255 self.assertFalse(np.isnan(example.sol("w")).any())
257 def test_water_tank(self, example):
258 pass
260 def test_sin_approx_example(self, example):
261 pass
263 def test_simpleflight(self, example):
264 self.assertTrue(example.sol.almost_equal(example.sol_loaded))
265 for sol in [example.sol, example.sol_loaded]:
266 freevarcheck = {
267 "A": 8.46,
268 "C_D": 0.0206,
269 "C_f": 0.0036,
270 "C_L": 0.499,
271 "Re": 3.68e+06,
272 "S": 16.4,
273 "W": 7.34e+03,
274 "V": 38.2,
275 "W_w": 2.40e+03
276 }
277 # sensitivity values from p. 34 of W. Hoburg's thesis
278 senscheck = {
279 r"(\frac{S}{S_{wet}})": 0.4300,
280 "e": -0.4785,
281 "V_{min}": -0.3691,
282 "k": 0.4300,
283 r"\mu": 0.0860,
284 "(CDA0)": 0.0915,
285 "C_{L,max}": -0.1845,
286 r"\tau": -0.2903,
287 "N_{ult}": 0.2903,
288 "W_0": 1.0107,
289 r"\rho": -0.2275
290 }
291 for key in freevarcheck:
292 sol_rat = mag(sol["variables"][key])/freevarcheck[key]
293 self.assertTrue(abs(1-sol_rat) < 1e-2)
294 for key in senscheck:
295 sol_rat = sol["sensitivities"]["variables"][key]/senscheck[key]
296 self.assertTrue(abs(1-sol_rat) < 1e-2)
298 def test_relaxation(self, example):
299 pass
301 def test_unbounded(self, example):
302 pass
305FILE_DIR = os.path.dirname(os.path.realpath(__file__))
306EXAMPLE_DIR = os.path.abspath(FILE_DIR + '../../../docs/source/examples')
307SOLVERS = settings["installed_solvers"]
308if os.path.isdir(EXAMPLE_DIR):
309 TESTS = generate_example_tests(EXAMPLE_DIR, [TestExamples], SOLVERS)
310else: # pragma: no cover
311 TESTS = []
313if __name__ == "__main__": # pragma: no cover
314 # pylint:disable=wrong-import-position
315 from gpkit.tests.helpers import run_tests
316 run_tests(TESTS)