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 json
6import numpy as np
8from gpkit import settings, Model, Variable
9from gpkit.tests.helpers import generate_example_tests
10from gpkit.small_scripts import mag
11from gpkit.small_classes import Quantity
12from gpkit.constraints.loose import Loose
13from gpkit.exceptions import (UnknownInfeasible,
14 PrimalInfeasible, DualInfeasible, UnboundedGP)
17def assert_logtol(first, second, logtol=1e-6):
18 "Asserts that the logs of two arrays have a given abstol"
19 np.testing.assert_allclose(np.log(mag(first)), np.log(mag(second)),
20 atol=logtol, rtol=0)
23# pylint: disable=too-many-public-methods
24class TestExamples(unittest.TestCase):
25 """
26 To test a new example, add a function called `test_$EXAMPLENAME`, where
27 $EXAMPLENAME is the name of your example in docs/source/examples without
28 the file extension.
30 This function should accept two arguments (e.g. 'self' and 'example').
31 The imported example script will be passed to the second: anything that
32 was a global variable (e.g, "sol") in the original script is available
33 as an attribute (e.g., "example.sol")
35 If you don't want to perform any checks on the example besides making
36 sure it runs, just put "pass" as the function's body, e.g.:
38 def test_dummy_example(self, example):
39 pass
41 But it's good practice to ensure the example's solution as well, e.g.:
43 def test_dummy_example(self, example):
44 self.assertAlmostEqual(example.sol["cost"], 3.121)
45 """
47 # TODO: allow enabling plotting examples, make plots in correct folder...
48 # def test_plot_sweep1d(self, _):
49 # import matplotlib.pyplot as plt
50 # plt.close("all")
52 def test_issue_1513(self, example):
53 pass
55 def test_issue_1522(self, example):
56 pass
58 def test_autosweep(self, example):
59 from gpkit import ureg
60 bst1, tol1 = example.bst1, example.tol1
61 bst2, tol2 = example.bst2, example.tol2
63 l_ = np.linspace(1, 10, 100)
64 for bst in [bst1, example.bst1_loaded]:
65 sol1 = bst.sample_at(l_)
66 assert_logtol(sol1("l"), l_)
67 assert_logtol(sol1("A"), l_**2 + 1, tol1)
68 assert_logtol(sol1["cost"], (l_**2 + 1)**2, tol1)
69 self.assertEqual(Quantity(1.0, sol1("A").units),
70 Quantity(1.0, ureg.m)**2)
72 ndig = -int(np.log10(tol2))
73 self.assertAlmostEqual(bst2.cost_at("cost", 3), 1.0, ndig)
74 # before corner
75 A_bc = np.linspace(1, 3, 50)
76 sol_bc = bst2.sample_at(A_bc)
77 assert_logtol(sol_bc("A"), (A_bc/3)**0.5, tol2)
78 assert_logtol(sol_bc["cost"], A_bc/3, tol2)
79 # after corner
80 A_ac = np.linspace(3, 10, 50)
81 sol_ac = bst2.sample_at(A_ac)
82 assert_logtol(sol_ac("A"), (A_ac/3)**2, tol2)
83 assert_logtol(sol_ac["cost"], (A_ac/3)**4, tol2)
85 def test_treemap(self, example):
86 pass
88 def test_checking_result_changes(self, example):
89 sol = example.sol
90 self.assertAlmostEqual(sol["cost"], 0.48, 2)
92 def test_evaluated_fixed_variables(self, example):
93 sol = example.sol
94 t_night = example.t_night
95 self.assertTrue((sol["variables"][t_night] == [16, 12, 8]).all())
97 def test_evaluated_free_variables(self, example):
98 x2 = example.x2
99 sol = example.sol
100 self.assertTrue(abs(sol(x2) - 4) <= 1e-4)
102 def test_external_constraint(self, example):
103 pass
105 def test_migp(self, example):
106 if settings["default_solver"] == "mosek_conif":
107 assert_logtol(example.sol(example.x), [1]*3 + [2]*6 + [3]*2)
108 else:
109 assert_logtol(example.sol(example.x),
110 np.sqrt(example.sol(example.num)))
112 def test_external_function(self, example):
113 external_code = example.external_code
114 self.assertEqual(external_code(0), 0)
116 def test_external_sp(self, example):
117 m = example.m
118 sol = m.localsolve(verbosity=0)
119 self.assertAlmostEqual(sol["cost"], 0.707, places=3)
121 def test_freeing_fixed_variables(self, example):
122 x = example.x
123 y = Variable("y", 3)
124 m = Model(x, [x >= 1 + y, y >= 1])
125 sol = m.solve(verbosity=0)
126 self.assertTrue(abs(sol["cost"] - 4) <= 1e-4)
127 self.assertTrue(y in sol["constants"])
129 del m.substitutions["y"]
130 sol = m.solve(verbosity=0)
131 self.assertTrue(abs(sol["cost"] - 2) <= 1e-4)
132 self.assertTrue(y in sol["freevariables"])
134 def test_gettingstarted(self, example):
135 pass
138 def test_loose_constraintsets(self, example):
139 m = example.m
140 sol = m.solve(verbosity=0)
141 self.assertAlmostEqual(sol["cost"], 2, 3)
143 def test_sub_multi_values(self, example):
144 x = example.x
145 y = example.y
146 z = example.z
147 p = example.p
148 self.assertTrue(all(p.sub({x: 1, "y": 2}) == 2*z))
149 self.assertTrue(all(
150 p.sub({x: 1, y: 2, "z": [1, 2]}) == z.sub({z: [2, 4]})
151 ))
153 def test_substitutions(self, example):
154 x = example.x
155 p = example.p
156 self.assertTrue(p.sub({x: 3}) == 9)
157 self.assertTrue(p.sub({x.key: 3}) == 9)
158 self.assertTrue(p.sub({"x": 3}) == 9)
160 def test_tight_constraintsets(self, example):
161 m = example.m
162 sol = m.solve(verbosity=0)
163 self.assertAlmostEqual(sol["cost"], 2, places=2)
165 def test_vectorization(self, example):
166 x = example.x
167 y = example.y
168 z = example.z
169 self.assertEqual(y.shape, (5, 3))
170 self.assertEqual(x.shape, (2, 5, 3))
171 self.assertEqual(z.shape, (7, 3))
173 def test_model_var_access(self, example):
174 model = example.PS
175 _ = model["E"]
176 with self.assertRaises(ValueError):
177 _ = model["m"] # multiple variables called m
179 def test_performance_modeling(self, example):
180 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 # testing savejson
196 sol.savejson("solution.json")
197 json_dict = {}
198 with open("solution.json", "r") as rf:
199 json_dict = json.load(rf)
200 for var in sol["variables"]:
201 self.assertTrue(np.all(json_dict[str(var.key)]['v']
202 == sol["variables"][var.key]))
203 self.assertEqual(json_dict[str(var.key)]['u'], var.unitstr())
205 def test_sp_to_gp_sweep(self, example):
206 sol = example.sol
207 cost = sol["cost"]
208 self.assertAlmostEqual(cost[0], 4628.21, places=2)
209 self.assertAlmostEqual(cost[1], 6226.60, places=2)
210 self.assertAlmostEqual(cost[2], 7362.77, places=2)
212 def test_boundschecking(self, example): # pragma: no cover
213 if "mosek_cli" in settings["default_solver"]:
214 with self.assertRaises(UnknownInfeasible):
215 example.gp.solve(verbosity=0)
216 else:
217 example.gp.solve(verbosity=0) # mosek_conif and cvxopt solve it
219 def test_vectorize(self, example):
220 pass
222 def test_primal_infeasible_ex1(self, example):
223 primal_or_unknown = PrimalInfeasible
224 if "cvxopt" in settings["default_solver"]: # pragma: no cover
225 primal_or_unknown = UnknownInfeasible
226 with self.assertRaises(primal_or_unknown):
227 example.m.solve(verbosity=0)
229 def test_primal_infeasible_ex2(self, example):
230 primal_or_unknown = PrimalInfeasible
231 if "cvxopt" in settings["default_solver"]: # pragma: no cover
232 primal_or_unknown = UnknownInfeasible
233 with self.assertRaises(primal_or_unknown):
234 example.m.solve(verbosity=0)
236 def test_docstringparsing(self, example):
237 pass
239 def test_debug(self, example):
240 dual_or_primal = DualInfeasible
241 if "mosek_conif" == settings["default_solver"]: # pragma: no cover
242 dual_or_primal = PrimalInfeasible
243 with self.assertRaises(UnboundedGP):
244 example.m.gp()
245 with self.assertRaises(dual_or_primal):
246 gp = example.m.gp(checkbounds=False)
247 gp.solve(verbosity=0)
249 primal_or_unknown = PrimalInfeasible
250 if "cvxopt" == settings["default_solver"]: # pragma: no cover
251 primal_or_unknown = UnknownInfeasible
252 with self.assertRaises(primal_or_unknown):
253 example.m2.solve(verbosity=0)
255 with self.assertRaises(UnboundedGP):
256 example.m3.gp()
257 with self.assertRaises(DualInfeasible):
258 gp3 = example.m3.gp(checkbounds=False)
259 gp3.solve(verbosity=0)
261 def test_simple_sp(self, example):
262 pass
264 def test_simple_box(self, example):
265 pass
267 def test_x_greaterthan_1(self, example):
268 pass
270 def test_beam(self, example):
271 self.assertFalse(np.isnan(example.sol("w")).any())
273 def test_water_tank(self, example):
274 pass
276 def test_sin_approx_example(self, example):
277 pass
279 def test_simpleflight(self, example):
280 self.assertTrue(example.sol.almost_equal(example.sol_loaded))
281 for sol in [example.sol, example.sol_loaded]:
282 freevarcheck = {
283 "A": 8.46,
284 "C_D": 0.0206,
285 "C_f": 0.0036,
286 "C_L": 0.499,
287 "Re": 3.68e+06,
288 "S": 16.4,
289 "W": 7.34e+03,
290 "V": 38.2,
291 "W_w": 2.40e+03
292 }
293 # sensitivity values from p. 34 of W. Hoburg's thesis
294 senscheck = {
295 r"(\frac{S}{S_{wet}})": 0.4300,
296 "e": -0.4785,
297 "V_{min}": -0.3691,
298 "k": 0.4300,
299 r"\mu": 0.0860,
300 "(CDA0)": 0.0915,
301 "C_{L,max}": -0.1845,
302 r"\tau": -0.2903,
303 "N_{ult}": 0.2903,
304 "W_0": 1.0107,
305 r"\rho": -0.2275
306 }
307 for key in freevarcheck:
308 sol_rat = mag(sol["variables"][key])/freevarcheck[key]
309 self.assertTrue(abs(1-sol_rat) < 1e-2)
310 for key in senscheck:
311 sol_rat = sol["sensitivities"]["variables"][key]/senscheck[key]
312 self.assertTrue(abs(1-sol_rat) < 1e-2)
314 def test_relaxation(self, example):
315 pass
317 def test_unbounded(self, example):
318 pass
321FILE_DIR = os.path.dirname(os.path.realpath(__file__))
322EXAMPLE_DIR = os.path.abspath(FILE_DIR + '../../../docs/source/examples')
323SOLVERS = settings["installed_solvers"]
324if os.path.isdir(EXAMPLE_DIR):
325 TESTS = generate_example_tests(EXAMPLE_DIR, [TestExamples], SOLVERS)
326else: # pragma: no cover
327 TESTS = []
329if __name__ == "__main__": # pragma: no cover
330 # pylint:disable=wrong-import-position
331 from gpkit.tests.helpers import run_tests
332 run_tests(TESTS)