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_external_function(self, example):
96 external_code = example.external_code
97 self.assertEqual(external_code(0), 0)
99 def test_external_sp(self, example):
100 m = example.m
101 sol = m.localsolve(verbosity=0)
102 self.assertAlmostEqual(sol["cost"], 0.707, places=3)
104 def test_freeing_fixed_variables(self, example):
105 x = example.x
106 y = Variable("y", 3)
107 m = Model(x, [x >= 1 + y, y >= 1])
108 sol = m.solve(verbosity=0)
109 self.assertTrue(abs(sol["cost"] - 4) <= 1e-4)
110 self.assertTrue(y in sol["constants"])
112 del m.substitutions["y"]
113 sol = m.solve(verbosity=0)
114 self.assertTrue(abs(sol["cost"] - 2) <= 1e-4)
115 self.assertTrue(y in sol["freevariables"])
117 def test_gettingstarted(self, example):
118 pass
121 def test_loose_constraintsets(self, example):
122 m = example.m
123 sol = m.solve(verbosity=0)
124 self.assertAlmostEqual(sol["cost"], 2, 3)
126 def test_sub_multi_values(self, example):
127 x = example.x
128 y = example.y
129 z = example.z
130 p = example.p
131 self.assertTrue(all(p.sub({x: 1, "y": 2}) == 2*z))
132 self.assertTrue(all(
133 p.sub({x: 1, y: 2, "z": [1, 2]}) == z.sub({z: [2, 4]})
134 ))
136 def test_substitutions(self, example):
137 x = example.x
138 p = example.p
139 self.assertTrue(p.sub({x: 3}) == 9)
140 self.assertTrue(p.sub({x.key: 3}) == 9)
141 self.assertTrue(p.sub({"x": 3}) == 9)
143 def test_tight_constraintsets(self, example):
144 m = example.m
145 sol = m.solve(verbosity=0)
146 self.assertAlmostEqual(sol["cost"], 2, places=2)
148 def test_vectorization(self, example):
149 x = example.x
150 y = example.y
151 z = example.z
152 self.assertEqual(y.shape, (5, 3))
153 self.assertEqual(x.shape, (2, 5, 3))
154 self.assertEqual(z.shape, (7, 3))
156 def test_model_var_access(self, example):
157 model = example.PS
158 _ = model["E"]
159 with self.assertRaises(ValueError):
160 _ = model["m"] # multiple variables called m
162 def test_performance_modeling(self, example):
163 m = Model(example.M.cost, Loose(example.M), example.M.substitutions)
165 sol = m.solve(verbosity=0)
166 sol.table()
167 sol.save("solution.pkl")
168 sol.table()
169 sol_loaded = pickle.load(open("solution.pkl", "rb"))
170 sol_loaded.table()
172 sweepsol = m.sweep({example.AC.fuse.W: (50, 100, 150)}, verbosity=0)
173 sweepsol.table()
174 sweepsol.save("sweepsolution.pkl")
175 sweepsol.table()
176 sol_loaded = pickle.load(open("sweepsolution.pkl", "rb"))
177 sol_loaded.table()
179 def test_sp_to_gp_sweep(self, example):
180 sol = example.sol
181 cost = sol["cost"]
182 self.assertAlmostEqual(cost[0], 4628.21, places=2)
183 self.assertAlmostEqual(cost[1], 6226.60, places=2)
184 self.assertAlmostEqual(cost[2], 7362.77, places=2)
186 def test_boundschecking(self, example): # pragma: no cover
187 if "mosek_cli" in settings["default_solver"]:
188 with self.assertRaises(UnknownInfeasible):
189 example.gp.solve(verbosity=0)
190 else:
191 example.gp.solve(verbosity=0) # mosek_conif and cvxopt solve it
193 def test_vectorize(self, example):
194 pass
196 def test_primal_infeasible_ex1(self, example):
197 primal_or_unknown = PrimalInfeasible
198 if "cvxopt" in settings["default_solver"]: # pragma: no cover
199 primal_or_unknown = UnknownInfeasible
200 with self.assertRaises(primal_or_unknown):
201 example.m.solve(verbosity=0)
203 def test_primal_infeasible_ex2(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_docstringparsing(self, example):
211 pass
213 def test_debug(self, example):
214 dual_or_primal = DualInfeasible
215 if "mosek_conif" == settings["default_solver"]: # pragma: no cover
216 dual_or_primal = PrimalInfeasible
217 with self.assertRaises(UnboundedGP):
218 example.m.gp()
219 with self.assertRaises(dual_or_primal):
220 gp = example.m.gp(checkbounds=False)
221 gp.solve(verbosity=0)
223 primal_or_unknown = PrimalInfeasible
224 if "cvxopt" == settings["default_solver"]: # pragma: no cover
225 primal_or_unknown = UnknownInfeasible
226 with self.assertRaises(primal_or_unknown):
227 example.m2.solve(verbosity=0)
229 with self.assertRaises(UnboundedGP):
230 example.m3.gp()
231 with self.assertRaises(DualInfeasible):
232 gp3 = example.m3.gp(checkbounds=False)
233 gp3.solve(verbosity=0)
235 def test_simple_sp(self, example):
236 pass
238 def test_simple_box(self, example):
239 pass
241 def test_x_greaterthan_1(self, example):
242 pass
244 def test_beam(self, example):
245 self.assertFalse(np.isnan(example.sol("w")).any())
247 def test_water_tank(self, example):
248 pass
250 def test_sin_approx_example(self, example):
251 pass
253 def test_simpleflight(self, example):
254 self.assertTrue(example.sol.almost_equal(example.sol_loaded))
255 for sol in [example.sol, example.sol_loaded]:
256 freevarcheck = {
257 "A": 8.46,
258 "C_D": 0.0206,
259 "C_f": 0.0036,
260 "C_L": 0.499,
261 "Re": 3.68e+06,
262 "S": 16.4,
263 "W": 7.34e+03,
264 "V": 38.2,
265 "W_w": 2.40e+03
266 }
267 # sensitivity values from p. 34 of W. Hoburg's thesis
268 senscheck = {
269 r"(\frac{S}{S_{wet}})": 0.4300,
270 "e": -0.4785,
271 "V_{min}": -0.3691,
272 "k": 0.4300,
273 r"\mu": 0.0860,
274 "(CDA0)": 0.0915,
275 "C_{L,max}": -0.1845,
276 r"\tau": -0.2903,
277 "N_{ult}": 0.2903,
278 "W_0": 1.0107,
279 r"\rho": -0.2275
280 }
281 for key in freevarcheck:
282 sol_rat = mag(sol["variables"][key])/freevarcheck[key]
283 self.assertTrue(abs(1-sol_rat) < 1e-2)
284 for key in senscheck:
285 sol_rat = sol["sensitivities"]["variables"][key]/senscheck[key]
286 self.assertTrue(abs(1-sol_rat) < 1e-2)
288 def test_relaxation(self, example):
289 pass
291 def test_unbounded(self, example):
292 pass
295FILE_DIR = os.path.dirname(os.path.realpath(__file__))
296EXAMPLE_DIR = os.path.abspath(FILE_DIR + '../../../docs/source/examples')
297SOLVERS = settings["installed_solvers"]
298if os.path.isdir(EXAMPLE_DIR):
299 TESTS = generate_example_tests(EXAMPLE_DIR, [TestExamples], SOLVERS)
300else: # pragma: no cover
301 TESTS = []
303if __name__ == "__main__": # pragma: no cover
304 # pylint:disable=wrong-import-position
305 from gpkit.tests.helpers import run_tests
306 run_tests(TESTS)