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_checking_result_changes(self, example):
79 sol = example.sol
80 self.assertAlmostEqual(sol["cost"], 0.48, 2)
82 def test_evaluated_fixed_variables(self, example):
83 sol = example.sol
84 t_night = example.t_night
85 self.assertTrue((sol["variables"][t_night] == [16, 12, 8]).all())
87 def test_evaluated_free_variables(self, example):
88 x2 = example.x2
89 sol = example.sol
90 self.assertTrue(abs(sol(x2) - 4) <= 1e-4)
92 def test_external_constraint(self, example):
93 pass
95 def test_migp(self, example):
96 if settings["default_solver"] == "mosek_conif":
97 assert_logtol(example.sol(example.x), [1]*3 + [2]*6 + [3]*2)
98 else:
99 assert_logtol(example.sol(example.x),
100 np.sqrt(example.sol(example.num)))
102 def test_external_function(self, example):
103 external_code = example.external_code
104 self.assertEqual(external_code(0), 0)
106 def test_external_sp(self, example):
107 m = example.m
108 sol = m.localsolve(verbosity=0)
109 self.assertAlmostEqual(sol["cost"], 0.707, places=3)
111 def test_freeing_fixed_variables(self, example):
112 x = example.x
113 y = Variable("y", 3)
114 m = Model(x, [x >= 1 + y, y >= 1])
115 sol = m.solve(verbosity=0)
116 self.assertTrue(abs(sol["cost"] - 4) <= 1e-4)
117 self.assertTrue(y in sol["constants"])
119 del m.substitutions["y"]
120 sol = m.solve(verbosity=0)
121 self.assertTrue(abs(sol["cost"] - 2) <= 1e-4)
122 self.assertTrue(y in sol["freevariables"])
124 def test_gettingstarted(self, example):
125 pass
128 def test_loose_constraintsets(self, example):
129 m = example.m
130 sol = m.solve(verbosity=0)
131 self.assertAlmostEqual(sol["cost"], 2, 3)
133 def test_sub_multi_values(self, example):
134 x = example.x
135 y = example.y
136 z = example.z
137 p = example.p
138 self.assertTrue(all(p.sub({x: 1, "y": 2}) == 2*z))
139 self.assertTrue(all(
140 p.sub({x: 1, y: 2, "z": [1, 2]}) == z.sub({z: [2, 4]})
141 ))
143 def test_substitutions(self, example):
144 x = example.x
145 p = example.p
146 self.assertTrue(p.sub({x: 3}) == 9)
147 self.assertTrue(p.sub({x.key: 3}) == 9)
148 self.assertTrue(p.sub({"x": 3}) == 9)
150 def test_tight_constraintsets(self, example):
151 m = example.m
152 sol = m.solve(verbosity=0)
153 self.assertAlmostEqual(sol["cost"], 2, places=2)
155 def test_vectorization(self, example):
156 x = example.x
157 y = example.y
158 z = example.z
159 self.assertEqual(y.shape, (5, 3))
160 self.assertEqual(x.shape, (2, 5, 3))
161 self.assertEqual(z.shape, (7, 3))
163 def test_model_var_access(self, example):
164 model = example.PS
165 _ = model["E"]
166 with self.assertRaises(ValueError):
167 _ = model["m"] # multiple variables called m
169 def test_performance_modeling(self, example):
170 m = Model(example.M.cost, Loose(example.M), example.M.substitutions)
172 sol = m.solve(verbosity=0)
173 sol.table()
174 sol.save("solution.pkl")
175 sol.table()
176 sol_loaded = pickle.load(open("solution.pkl", "rb"))
177 sol_loaded.table()
179 sweepsol = m.sweep({example.AC.fuse.W: (50, 100, 150)}, verbosity=0)
180 sweepsol.table()
181 sweepsol.save("sweepsolution.pkl")
182 sweepsol.table()
183 sol_loaded = pickle.load(open("sweepsolution.pkl", "rb"))
184 sol_loaded.table()
186 def test_sp_to_gp_sweep(self, example):
187 sol = example.sol
188 cost = sol["cost"]
189 self.assertAlmostEqual(cost[0], 4628.21, places=2)
190 self.assertAlmostEqual(cost[1], 6226.60, places=2)
191 self.assertAlmostEqual(cost[2], 7362.77, places=2)
193 def test_boundschecking(self, example): # pragma: no cover
194 if "mosek_cli" in settings["default_solver"]:
195 with self.assertRaises(UnknownInfeasible):
196 example.gp.solve(verbosity=0)
197 else:
198 example.gp.solve(verbosity=0) # mosek_conif and cvxopt solve it
200 def test_vectorize(self, example):
201 pass
203 def test_primal_infeasible_ex1(self, example):
204 primal_or_unknown = PrimalInfeasible
205 if "cvxopt" in settings["default_solver"]: # pragma: no cover
206 primal_or_unknown = UnknownInfeasible
207 with self.assertRaises(primal_or_unknown):
208 example.m.solve(verbosity=0)
210 def test_primal_infeasible_ex2(self, example):
211 primal_or_unknown = PrimalInfeasible
212 if "cvxopt" in settings["default_solver"]: # pragma: no cover
213 primal_or_unknown = UnknownInfeasible
214 with self.assertRaises(primal_or_unknown):
215 example.m.solve(verbosity=0)
217 def test_docstringparsing(self, example):
218 pass
220 def test_debug(self, example):
221 dual_or_primal = DualInfeasible
222 if "mosek_conif" == settings["default_solver"]: # pragma: no cover
223 dual_or_primal = PrimalInfeasible
224 with self.assertRaises(UnboundedGP):
225 example.m.gp()
226 with self.assertRaises(dual_or_primal):
227 gp = example.m.gp(checkbounds=False)
228 gp.solve(verbosity=0)
230 primal_or_unknown = PrimalInfeasible
231 if "cvxopt" == settings["default_solver"]: # pragma: no cover
232 primal_or_unknown = UnknownInfeasible
233 with self.assertRaises(primal_or_unknown):
234 example.m2.solve(verbosity=0)
236 with self.assertRaises(UnboundedGP):
237 example.m3.gp()
238 with self.assertRaises(DualInfeasible):
239 gp3 = example.m3.gp(checkbounds=False)
240 gp3.solve(verbosity=0)
242 def test_simple_sp(self, example):
243 pass
245 def test_simple_box(self, example):
246 pass
248 def test_x_greaterthan_1(self, example):
249 pass
251 def test_beam(self, example):
252 self.assertFalse(np.isnan(example.sol("w")).any())
254 def test_water_tank(self, example):
255 pass
257 def test_sin_approx_example(self, example):
258 pass
260 def test_simpleflight(self, example):
261 self.assertTrue(example.sol.almost_equal(example.sol_loaded))
262 for sol in [example.sol, example.sol_loaded]:
263 freevarcheck = {
264 "A": 8.46,
265 "C_D": 0.0206,
266 "C_f": 0.0036,
267 "C_L": 0.499,
268 "Re": 3.68e+06,
269 "S": 16.4,
270 "W": 7.34e+03,
271 "V": 38.2,
272 "W_w": 2.40e+03
273 }
274 # sensitivity values from p. 34 of W. Hoburg's thesis
275 senscheck = {
276 r"(\frac{S}{S_{wet}})": 0.4300,
277 "e": -0.4785,
278 "V_{min}": -0.3691,
279 "k": 0.4300,
280 r"\mu": 0.0860,
281 "(CDA0)": 0.0915,
282 "C_{L,max}": -0.1845,
283 r"\tau": -0.2903,
284 "N_{ult}": 0.2903,
285 "W_0": 1.0107,
286 r"\rho": -0.2275
287 }
288 for key in freevarcheck:
289 sol_rat = mag(sol["variables"][key])/freevarcheck[key]
290 self.assertTrue(abs(1-sol_rat) < 1e-2)
291 for key in senscheck:
292 sol_rat = sol["sensitivities"]["variables"][key]/senscheck[key]
293 self.assertTrue(abs(1-sol_rat) < 1e-2)
295 def test_relaxation(self, example):
296 pass
298 def test_unbounded(self, example):
299 pass
302FILE_DIR = os.path.dirname(os.path.realpath(__file__))
303EXAMPLE_DIR = os.path.abspath(FILE_DIR + '../../../docs/source/examples')
304SOLVERS = settings["installed_solvers"]
305if os.path.isdir(EXAMPLE_DIR):
306 TESTS = generate_example_tests(EXAMPLE_DIR, [TestExamples], SOLVERS)
307else: # pragma: no cover
308 TESTS = []
310if __name__ == "__main__": # pragma: no cover
311 # pylint:disable=wrong-import-position
312 from gpkit.tests.helpers import run_tests
313 run_tests(TESTS)