Hide keyboard shortcuts

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 

6 

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) 

14 

15 

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) 

20 

21 

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. 

28 

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

33 

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

36 

37 def test_dummy_example(self, example): 

38 pass 

39 

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

41 

42 def test_dummy_example(self, example): 

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

44 """ 

45 

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

50 

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 

55 

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) 

64 

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) 

77 

78 def test_checking_result_changes(self, example): 

79 sol = example.sol 

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

81 

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

86 

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) 

91 

92 def test_external_constraint(self, example): 

93 pass 

94 

95 def test_external_function(self, example): 

96 external_code = example.external_code 

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

98 

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) 

103 

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

111 

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

116 

117 def test_gettingstarted(self, example): 

118 pass 

119 

120 

121 def test_loose_constraintsets(self, example): 

122 m = example.m 

123 sol = m.solve(verbosity=0) 

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

125 

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

135 

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) 

142 

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) 

147 

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

155 

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 

161 

162 def test_performance_modeling(self, example): 

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

164 

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

171 

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

178 

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) 

185 

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 

192 

193 def test_vectorize(self, example): 

194 pass 

195 

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) 

202 

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) 

209 

210 def test_docstringparsing(self, example): 

211 pass 

212 

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) 

222 

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) 

228 

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) 

234 

235 def test_simple_sp(self, example): 

236 pass 

237 

238 def test_simple_box(self, example): 

239 pass 

240 

241 def test_x_greaterthan_1(self, example): 

242 pass 

243 

244 def test_beam(self, example): 

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

246 

247 def test_water_tank(self, example): 

248 pass 

249 

250 def test_sin_approx_example(self, example): 

251 pass 

252 

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) 

287 

288 def test_relaxation(self, example): 

289 pass 

290 

291 def test_unbounded(self, example): 

292 pass 

293 

294 

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 = [] 

302 

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

304 # pylint:disable=wrong-import-position 

305 from gpkit.tests.helpers import run_tests 

306 run_tests(TESTS)