Coverage for gpkit/tests/t_examples.py: 99%

199 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-01-03 16:49 -0500

1"""Unit testing of tests in docs/source/examples""" 

2import unittest 

3import os 

4import pickle 

5import json 

6import numpy as np 

7 

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) 

15 

16 

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) 

21 

22 

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. 

29 

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") 

34 

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.: 

37 

38 def test_dummy_example(self, example): 

39 pass 

40 

41 But it's good practice to ensure the example's solution as well, e.g.: 

42 

43 def test_dummy_example(self, example): 

44 self.assertAlmostEqual(example.sol["cost"], 3.121) 

45 """ 

46 

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") 

51 

52 def test_breakdowns(self, example): 

53 pass 

54 

55 def test_issue_1513(self, example): 

56 pass 

57 

58 def test_issue_1522(self, example): 

59 pass 

60 

61 def test_autosweep(self, example): 

62 from gpkit import ureg 

63 bst1, tol1 = example.bst1, example.tol1 

64 bst2, tol2 = example.bst2, example.tol2 

65 

66 l_ = np.linspace(1, 10, 100) 

67 for bst in [bst1, example.bst1_loaded]: 

68 sol1 = bst.sample_at(l_) 

69 assert_logtol(sol1("l"), l_) 

70 assert_logtol(sol1("A"), l_**2 + 1, tol1) 

71 assert_logtol(sol1["cost"], (l_**2 + 1)**2, tol1) 

72 self.assertEqual(Quantity(1.0, sol1("A").units), 

73 Quantity(1.0, ureg.m)**2) 

74 

75 ndig = -int(np.log10(tol2)) 

76 self.assertAlmostEqual(bst2.cost_at("cost", 3), 1.0, ndig) 

77 # before corner 

78 A_bc = np.linspace(1, 3, 50) 

79 sol_bc = bst2.sample_at(A_bc) 

80 assert_logtol(sol_bc("A"), (A_bc/3)**0.5, tol2) 

81 assert_logtol(sol_bc["cost"], A_bc/3, tol2) 

82 # after corner 

83 A_ac = np.linspace(3, 10, 50) 

84 sol_ac = bst2.sample_at(A_ac) 

85 assert_logtol(sol_ac("A"), (A_ac/3)**2, tol2) 

86 assert_logtol(sol_ac["cost"], (A_ac/3)**4, tol2) 

87 

88 def test_treemap(self, example): 

89 pass 

90 

91 def test_checking_result_changes(self, example): 

92 sol = example.sol 

93 self.assertAlmostEqual(sol["cost"], 0.48, 2) 

94 

95 def test_evaluated_fixed_variables(self, example): 

96 sol = example.sol 

97 t_night = example.t_night 

98 self.assertTrue((sol["variables"][t_night] == [16, 12, 8]).all()) 

99 

100 def test_evaluated_free_variables(self, example): 

101 x2 = example.x2 

102 sol = example.sol 

103 self.assertTrue(abs(sol(x2) - 4) <= 1e-4) 

104 

105 def test_external_constraint(self, example): 

106 pass 

107 

108 def test_migp(self, example): 

109 if settings["default_solver"] == "mosek_conif": 

110 assert_logtol(example.sol(example.x), [1]*3 + [2]*6 + [3]*2) 

111 else: 

112 assert_logtol(example.sol(example.x), 

113 np.sqrt(example.sol(example.num))) 

114 

115 def test_external_function(self, example): 

116 external_code = example.external_code 

117 self.assertEqual(external_code(0), 0) 

118 

119 def test_external_sp(self, example): 

120 m = example.m 

121 sol = m.localsolve(verbosity=0) 

122 self.assertAlmostEqual(sol["cost"], 0.707, places=3) 

123 

124 def test_freeing_fixed_variables(self, example): 

125 x = example.x 

126 y = Variable("y", 3) 

127 m = Model(x, [x >= 1 + y, y >= 1]) 

128 sol = m.solve(verbosity=0) 

129 self.assertTrue(abs(sol["cost"] - 4) <= 1e-4) 

130 self.assertTrue(y in sol["constants"]) 

131 

132 del m.substitutions["y"] 

133 sol = m.solve(verbosity=0) 

134 self.assertTrue(abs(sol["cost"] - 2) <= 1e-4) 

135 self.assertTrue(y in sol["freevariables"]) 

136 

137 def test_gettingstarted(self, example): 

138 pass 

139 

140 

141 def test_loose_constraintsets(self, example): 

142 m = example.m 

143 sol = m.solve(verbosity=0) 

144 self.assertAlmostEqual(sol["cost"], 2, 3) 

145 

146 def test_sub_multi_values(self, example): 

147 x = example.x 

148 y = example.y 

149 z = example.z 

150 p = example.p 

151 self.assertTrue(all(p.sub({x: 1, "y": 2}) == 2*z)) 

152 self.assertTrue(all( 

153 p.sub({x: 1, y: 2, "z": [1, 2]}) == z.sub({z: [2, 4]}) 

154 )) 

155 

156 def test_substitutions(self, example): 

157 x = example.x 

158 p = example.p 

159 self.assertTrue(p.sub({x: 3}) == 9) 

160 self.assertTrue(p.sub({x.key: 3}) == 9) 

161 self.assertTrue(p.sub({"x": 3}) == 9) 

162 

163 def test_tight_constraintsets(self, example): 

164 m = example.m 

165 sol = m.solve(verbosity=0) 

166 self.assertAlmostEqual(sol["cost"], 2, places=2) 

167 

168 def test_vectorization(self, example): 

169 x = example.x 

170 y = example.y 

171 z = example.z 

172 self.assertEqual(y.shape, (5, 3)) 

173 self.assertEqual(x.shape, (2, 5, 3)) 

174 self.assertEqual(z.shape, (7, 3)) 

175 

176 def test_model_var_access(self, example): 

177 model = example.PS 

178 _ = model["E"] 

179 with self.assertRaises(ValueError): 

180 _ = model["m"] # multiple variables called m 

181 

182 def test_performance_modeling(self, example): 

183 m = Model(example.M.cost, Loose(example.M), example.M.substitutions) 

184 sol = m.solve(verbosity=0) 

185 sol.table() 

186 sol.save("solution.pkl") 

187 sol.table() 

188 sol_loaded = pickle.load(open("solution.pkl", "rb")) 

189 sol_loaded.table() 

190 

191 sweepsol = m.sweep({example.AC.fuse.W: (50, 100, 150)}, verbosity=0) 

192 sweepsol.table() 

193 sweepsol.save("sweepsolution.pkl") 

194 sweepsol.table() 

195 sol_loaded = pickle.load(open("sweepsolution.pkl", "rb")) 

196 sol_loaded.table() 

197 

198 # testing savejson 

199 sol.savejson("solution.json") 

200 json_dict = {} 

201 with open("solution.json", "r") as rf: 

202 json_dict = json.load(rf) 

203 for var in sol["variables"]: 

204 self.assertTrue(np.all(json_dict[str(var.key)]['v'] 

205 == sol["variables"][var.key])) 

206 self.assertEqual(json_dict[str(var.key)]['u'], var.unitstr()) 

207 

208 def test_sp_to_gp_sweep(self, example): 

209 sol = example.sol 

210 cost = sol["cost"] 

211 self.assertAlmostEqual(cost[0], 4628.21, places=2) 

212 self.assertAlmostEqual(cost[1], 6226.60, places=2) 

213 self.assertAlmostEqual(cost[2], 7362.77, places=2) 

214 

215 def test_boundschecking(self, example): # pragma: no cover 

216 if "mosek_cli" in settings["default_solver"]: 

217 with self.assertRaises(UnknownInfeasible): 

218 example.gp.solve(verbosity=0) 

219 else: 

220 example.gp.solve(verbosity=0) # mosek_conif and cvxopt solve it 

221 

222 def test_vectorize(self, example): 

223 pass 

224 

225 def test_primal_infeasible_ex1(self, example): 

226 primal_or_unknown = PrimalInfeasible 

227 if "cvxopt" in settings["default_solver"]: # pragma: no cover 

228 primal_or_unknown = UnknownInfeasible 

229 with self.assertRaises(primal_or_unknown): 

230 example.m.solve(verbosity=0) 

231 

232 def test_primal_infeasible_ex2(self, example): 

233 primal_or_unknown = PrimalInfeasible 

234 if "cvxopt" in settings["default_solver"]: # pragma: no cover 

235 primal_or_unknown = UnknownInfeasible 

236 with self.assertRaises(primal_or_unknown): 

237 example.m.solve(verbosity=0) 

238 

239 def test_docstringparsing(self, example): 

240 pass 

241 

242 def test_debug(self, example): 

243 dual_or_primal = DualInfeasible 

244 if "mosek_conif" == settings["default_solver"]: # pragma: no cover 

245 dual_or_primal = PrimalInfeasible 

246 with self.assertRaises(UnboundedGP): 

247 example.m.gp() 

248 with self.assertRaises(dual_or_primal): 

249 gp = example.m.gp(checkbounds=False) 

250 gp.solve(verbosity=0) 

251 

252 primal_or_unknown = PrimalInfeasible 

253 if "cvxopt" == settings["default_solver"]: # pragma: no cover 

254 primal_or_unknown = UnknownInfeasible 

255 with self.assertRaises(primal_or_unknown): 

256 example.m2.solve(verbosity=0) 

257 

258 with self.assertRaises(UnboundedGP): 

259 example.m3.gp() 

260 with self.assertRaises(DualInfeasible): 

261 gp3 = example.m3.gp(checkbounds=False) 

262 gp3.solve(verbosity=0) 

263 

264 def test_simple_sp(self, example): 

265 pass 

266 

267 def test_simple_box(self, example): 

268 pass 

269 

270 def test_x_greaterthan_1(self, example): 

271 pass 

272 

273 def test_beam(self, example): 

274 self.assertFalse(np.isnan(example.sol("w")).any()) 

275 

276 def test_water_tank(self, example): 

277 pass 

278 

279 def test_sin_approx_example(self, example): 

280 pass 

281 

282 def test_simpleflight(self, example): 

283 self.assertTrue(example.sol.almost_equal(example.sol_loaded)) 

284 for sol in [example.sol, example.sol_loaded]: 

285 freevarcheck = { 

286 "A": 8.46, 

287 "C_D": 0.0206, 

288 "C_f": 0.0036, 

289 "C_L": 0.499, 

290 "Re": 3.68e+06, 

291 "S": 16.4, 

292 "W": 7.34e+03, 

293 "V": 38.2, 

294 "W_w": 2.40e+03 

295 } 

296 # sensitivity values from p. 34 of W. Hoburg's thesis 

297 senscheck = { 

298 r"(\frac{S}{S_{wet}})": 0.4300, 

299 "e": -0.4785, 

300 "V_{min}": -0.3691, 

301 "k": 0.4300, 

302 r"\mu": 0.0860, 

303 "(CDA0)": 0.0915, 

304 "C_{L,max}": -0.1845, 

305 r"\tau": -0.2903, 

306 "N_{ult}": 0.2903, 

307 "W_0": 1.0107, 

308 r"\rho": -0.2275 

309 } 

310 for key in freevarcheck: 

311 sol_rat = mag(sol["variables"][key])/freevarcheck[key] 

312 self.assertTrue(abs(1-sol_rat) < 1e-2) 

313 for key in senscheck: 

314 sol_rat = sol["sensitivities"]["variables"][key]/senscheck[key] 

315 self.assertTrue(abs(1-sol_rat) < 1e-2) 

316 

317 def test_relaxation(self, example): 

318 pass 

319 

320 def test_unbounded(self, example): 

321 pass 

322 

323 

324FILE_DIR = os.path.dirname(os.path.realpath(__file__)) 

325EXAMPLE_DIR = os.path.abspath(FILE_DIR + '../../../docs/source/examples') 

326SOLVERS = settings["installed_solvers"] 

327if os.path.isdir(EXAMPLE_DIR): 

328 TESTS = generate_example_tests(EXAMPLE_DIR, [TestExamples], SOLVERS) 

329else: # pragma: no cover 

330 TESTS = [] 

331 

332if __name__ == "__main__": # pragma: no cover 

333 # pylint:disable=wrong-import-position 

334 from gpkit.tests.helpers import run_tests 

335 run_tests(TESTS)