Coverage for tests/test_coordinates.py: 11%

295 statements  

« prev     ^ index     » next       coverage.py v6.4.1, created at 2022-07-11 05:56 +0000

1# 

2# Developed for the LSST Data Management System. 

3# This product includes software developed by the LSST Project 

4# (https://www.lsst.org). 

5# See the COPYRIGHT file at the top-level directory of this distribution 

6# for details of code ownership. 

7# 

8# This program is free software: you can redistribute it and/or modify 

9# it under the terms of the GNU General Public License as published by 

10# the Free Software Foundation, either version 3 of the License, or 

11# (at your option) any later version. 

12# 

13# This program is distributed in the hope that it will be useful, 

14# but WITHOUT ANY WARRANTY; without even the implied warranty of 

15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

16# GNU General Public License for more details. 

17# 

18# You should have received a copy of the GNU General Public License 

19# along with this program. If not, see <https://www.gnu.org/licenses/>. 

20# 

21 

22""" 

23Tests for geom.Point, geom.Extent, geom.CoordinateExpr 

24 

25Run with: 

26 ./Coordinates.py 

27or 

28 python 

29 >>> import coordinates; coordinates.run() 

30""" 

31 

32import unittest 

33import math 

34import operator 

35 

36import numpy as np 

37 

38import lsst.utils.tests 

39import lsst.geom as geom 

40 

41 

42class CoordinateTestCase: 

43 """Mixin for some of the tests below. 

44 """ 

45 

46 def testAccessors(self): 

47 for dtype, cls, rnd in self.classes: 

48 vector1 = rnd() 

49 p = cls(*vector1) 

50 self.assertEqual(p.__class__, cls) 

51 self.assertEqual(tuple(p), tuple(vector1)) 

52 self.assertEqual(tuple(p.clone()), tuple(p)) 

53 self.assertIsNot(p.clone(), p) 

54 vector2 = rnd() 

55 for n in range(cls.dimensions): 

56 p[n] = vector2[n] 

57 self.assertEqual(tuple(p), tuple(vector2)) 

58 

59 def testComparison(self): 

60 for dtype, cls, rnd in self.classes: 

61 CoordinateExpr = geom.CoordinateExpr[cls.dimensions] 

62 vector1 = rnd() 

63 vector2 = rnd() 

64 p1 = cls(*vector1) 

65 p2 = cls(*vector2) 

66 

67 self.assertEqual(p1 == p2, all(p1.eq(p2))) 

68 self.assertEqual(p1 != p2, any(p1.ne(p2))) 

69 self.assertIsNotNone(p1) # should not throw 

70 self.assertNotEqual(p1, tuple(p1)) # should not throw 

71 

72 self.assertEqual( 

73 tuple(p1.eq(p2)), 

74 tuple([v1 == v2 for v1, v2 in zip(vector1, vector2)])) 

75 self.assertEqual( 

76 tuple(p1.ne(p2)), 

77 tuple([v1 != v2 for v1, v2 in zip(vector1, vector2)])) 

78 self.assertEqual( 

79 tuple(p1.lt(p2)), 

80 tuple([v1 < v2 for v1, v2 in zip(vector1, vector2)])) 

81 self.assertEqual( 

82 tuple(p1.le(p2)), 

83 tuple([v1 <= v2 for v1, v2 in zip(vector1, vector2)])) 

84 self.assertEqual( 

85 tuple(p1.gt(p2)), 

86 tuple([v1 > v2 for v1, v2 in zip(vector1, vector2)])) 

87 self.assertEqual( 

88 tuple(p1.ge(p2)), 

89 tuple([v1 >= v2 for v1, v2 in zip(vector1, vector2)])) 

90 self.assertEqual(type(p1.eq(p2)), CoordinateExpr) 

91 self.assertEqual(type(p1.ne(p2)), CoordinateExpr) 

92 self.assertEqual(type(p1.lt(p2)), CoordinateExpr) 

93 self.assertEqual(type(p1.le(p2)), CoordinateExpr) 

94 self.assertEqual(type(p1.gt(p2)), CoordinateExpr) 

95 self.assertEqual(type(p1.ge(p2)), CoordinateExpr) 

96 scalar = dtype(rnd()[0]) 

97 self.assertEqual(tuple(p1.eq(scalar)), 

98 tuple([v1 == scalar for v1 in vector1])) 

99 self.assertEqual(tuple(p1.ne(scalar)), 

100 tuple([v1 != scalar for v1 in vector1])) 

101 self.assertEqual(tuple(p1.lt(scalar)), 

102 tuple([v1 < scalar for v1 in vector1])) 

103 self.assertEqual(tuple(p1.le(scalar)), 

104 tuple([v1 <= scalar for v1 in vector1])) 

105 self.assertEqual(tuple(p1.gt(scalar)), 

106 tuple([v1 > scalar for v1 in vector1])) 

107 self.assertEqual(tuple(p1.ge(scalar)), 

108 tuple([v1 >= scalar for v1 in vector1])) 

109 self.assertEqual(type(p1.eq(scalar)), CoordinateExpr) 

110 self.assertEqual(type(p1.ne(scalar)), CoordinateExpr) 

111 self.assertEqual(type(p1.lt(scalar)), CoordinateExpr) 

112 self.assertEqual(type(p1.le(scalar)), CoordinateExpr) 

113 self.assertEqual(type(p1.gt(scalar)), CoordinateExpr) 

114 self.assertEqual(type(p1.ge(scalar)), CoordinateExpr) 

115 

116 

117class PointTestCase(CoordinateTestCase, lsst.utils.tests.TestCase): 

118 """A test case for Point""" 

119 

120 def setUp(self): 

121 np.random.seed(1) 

122 self.classes = [ 

123 (float, geom.Point2D, lambda: [float(x) 

124 for x in np.random.randn(2)]), 

125 (int, geom.Point2I, lambda: [int(x) 

126 for x in np.random.randint(-5, 5, 2)]), 

127 (float, geom.Point3D, lambda: [float(x) 

128 for x in np.random.randn(3)]), 

129 (int, geom.Point3I, lambda: [int(x) 

130 for x in np.random.randint(-5, 5, 3)]), 

131 ] 

132 

133 def testConstructors(self): 

134 # test 2-d 

135 e1 = geom.Point2I(1, 2) 

136 e2 = geom.Point2I(e1) 

137 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

138 

139 e1 = geom.Point2D(1.2, 3.4) 

140 e2 = geom.Point2D(e1) 

141 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

142 

143 e1 = geom.Point2I(1, 3) 

144 e2 = geom.Point2D(e1) 

145 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

146 

147 # test 3-d 

148 e1 = geom.Point3I(1, 2, 3) 

149 e2 = geom.Point3I(e1) 

150 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

151 

152 e1 = geom.Point3D(1.2, 3.4, 5.6) 

153 e2 = geom.Point3D(e1) 

154 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

155 

156 e1 = geom.Point3I(1, 2, 3) 

157 e2 = geom.Point3D(e1) 

158 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

159 

160 # test rounding to integral coordinates 

161 e1 = geom.Point2D(1.2, 3.4) 

162 e2 = geom.Point2I(e1) 

163 self.assertAlmostEqual( 

164 tuple([math.floor(v + 0.5) for v in e1]), tuple(e2)) 

165 

166 e1 = geom.Point3D(1.2, 3.4, 5.6) 

167 e2 = geom.Point3I(e1) 

168 self.assertAlmostEqual( 

169 tuple([math.floor(v + 0.5) for v in e1]), tuple(e2)) 

170 

171 

172class ExtentTestCase(CoordinateTestCase, lsst.utils.tests.TestCase): 

173 """A test case for Extent""" 

174 

175 def setUp(self): 

176 np.random.seed(1) 

177 self.classes = [ 

178 (float, geom.Extent2D, lambda: [float(x) 

179 for x in np.random.randn(2)]), 

180 (int, geom.Extent2I, lambda: [int(x) 

181 for x in np.random.randint(-5, 5, 2)]), 

182 (float, geom.Extent3D, lambda: [float(x) 

183 for x in np.random.randn(3)]), 

184 (int, geom.Extent3I, lambda: [int(x) 

185 for x in np.random.randint(-5, 5, 3)]), 

186 ] 

187 

188 def testRounding(self): 

189 e1 = geom.Extent2D(1.2, -3.4) 

190 self.assertEqual(e1.floor(), geom.Extent2I(1, -4)) 

191 self.assertEqual(e1.ceil(), geom.Extent2I(2, -3)) 

192 self.assertEqual(e1.truncate(), geom.Extent2I(1, -3)) 

193 

194 def testConstructors(self): 

195 # test extent from extent 2-d 

196 e1 = geom.Extent2I(1, 2) 

197 e2 = geom.Extent2I(e1) 

198 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

199 

200 e1 = geom.Extent2D(1.2, 3.4) 

201 e2 = geom.Extent2D(e1) 

202 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

203 

204 e1 = geom.Extent2I(1, 2) 

205 e2 = geom.Extent2D(e1) 

206 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

207 

208 # test extent from extent 3-d 

209 e1 = geom.Extent3I(1, 2, 3) 

210 e2 = geom.Extent3I(e1) 

211 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

212 

213 e1 = geom.Extent3D(1.2, 3.4, 5.6) 

214 e2 = geom.Extent3D(e1) 

215 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

216 

217 e1 = geom.Extent3I(1, 2, 3) 

218 e2 = geom.Extent3D(e1) 

219 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

220 

221 # test extent from point 2-d 

222 e1 = geom.Point2I(1, 2) 

223 e2 = geom.Extent2I(e1) 

224 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

225 

226 e1 = geom.Point2D(1.2, 3.4) 

227 e2 = geom.Extent2D(e1) 

228 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

229 

230 e1 = geom.Point2I(1, 2) 

231 e2 = geom.Extent2D(e1) 

232 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

233 

234 # test extent from point 3-d 

235 e1 = geom.Point3I(1, 2, 3) 

236 e2 = geom.Extent3I(e1) 

237 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

238 

239 e1 = geom.Point3D(1.2, 3.4, 5.6) 

240 e2 = geom.Extent3D(e1) 

241 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

242 

243 e1 = geom.Point3I(1, 2, 3) 

244 e2 = geom.Extent3D(e1) 

245 self.assertAlmostEqual(tuple(e1), tuple(e2)) 

246 

247 

248class OperatorTestCase(lsst.utils.tests.TestCase): 

249 

250 @staticmethod 

251 def makeRandom(cls): 

252 """Make a random Point, Extent, int, or float of the given type.""" 

253 if cls is int: 

254 v = 0 

255 while v == 0: 

256 v = int(np.random.randn()*10) 

257 elif cls is float: 

258 v = float(np.random.randn()*10) 

259 else: 

260 v = cls() 

261 t = type(v[0]) 

262 for i in range(len(v)): 

263 while v[i] == 0: 

264 v[i] = t(np.random.randn()*10) 

265 return v 

266 

267 def checkOperator(self, op, lhs, rhs, expected, inPlace=False): 

268 """Check that the type and result of applying operator 'op' to types 'lhs' and 'rhs' 

269 yield a result of type 'expected', and that the computed value is correct. If 

270 'expected' is an Exception subclass, instead check that attempting to apply the 

271 operator raises that exception. 

272 """ 

273 v1 = self.makeRandom(lhs) 

274 v2 = self.makeRandom(rhs) 

275 if issubclass(expected, Exception): 

276 with self.assertRaises(expected): 

277 op(v1, v2) 

278 else: 

279 check = op(np.array(v1), np.array(v2)) 

280 result = op(v1, v2) 

281 if type(result) != expected: 

282 self.fail("%s(%s, %s): expected %s, got %s" % 

283 (op.__name__, lhs.__name__, rhs.__name__, 

284 expected.__name__, type(result).__name__)) 

285 if not np.allclose(result, check): 

286 self.fail("%s(%s, %s): expected %s, got %s" % 

287 (op.__name__, lhs.__name__, rhs.__name__, tuple(check), tuple(result))) 

288 if inPlace and result is not v1: 

289 self.fail("%s(%s, %s): result is not self" % 

290 (op.__name__, lhs.__name__, rhs.__name__)) 

291 

292 def testPointAsExtent(self): 

293 for n in (2, 3): 

294 for t in (int, float): 

295 p = self.makeRandom(geom.Point[t, n]) 

296 e = p.asExtent() 

297 self.assertEqual(type(e), geom.Extent[t, n]) 

298 self.assertFloatsAlmostEqual( 

299 np.array(p), np.array(e), rtol=0.0, atol=0.0) 

300 

301 def testExtentAsPoint(self): 

302 for n in (2, 3): 

303 for t in (int, float): 

304 e = self.makeRandom(geom.Extent[t, n]) 

305 p = e.asPoint() 

306 self.assertEqual(type(p), geom.Point[t, n]) 

307 self.assertFloatsAlmostEqual( 

308 np.array(p), np.array(e), rtol=0.0, atol=0.0) 

309 

310 def testUnaryOperators(self): 

311 for n in (2, 3): 

312 for t in (int, float): 

313 e1 = self.makeRandom(geom.Extent[t, n]) 

314 e2 = +e1 

315 self.assertEqual(type(e1), type(e2)) 

316 self.assertFloatsAlmostEqual( 

317 np.array(e1), np.array(e2), rtol=0.0, atol=0.0) 

318 e3 = -e1 

319 self.assertEqual(type(e1), type(e3)) 

320 self.assertFloatsAlmostEqual( 

321 np.array(e3), -np.array(e1), rtol=0.0, atol=0.0) 

322 

323 def testBinaryOperators(self): 

324 for n in (2, 3): 

325 pD = geom.Point[float, n] 

326 pI = geom.Point[int, n] 

327 eD = geom.Extent[float, n] 

328 eI = geom.Extent[int, n] 

329 # Addition 

330 self.checkOperator(operator.add, pD, pD, TypeError) 

331 self.checkOperator(operator.add, pD, pI, TypeError) 

332 self.checkOperator(operator.add, pD, eD, pD) 

333 self.checkOperator(operator.add, pD, eI, pD) 

334 self.checkOperator(operator.add, pI, pD, TypeError) 

335 self.checkOperator(operator.add, pI, pI, TypeError) 

336 self.checkOperator(operator.add, pI, eD, pD) 

337 self.checkOperator(operator.add, pI, eI, pI) 

338 self.checkOperator(operator.add, eD, pD, pD) 

339 self.checkOperator(operator.add, eD, pI, pD) 

340 self.checkOperator(operator.add, eD, eI, eD) 

341 self.checkOperator(operator.add, eD, eD, eD) 

342 self.checkOperator(operator.add, eI, pD, pD) 

343 self.checkOperator(operator.add, eI, pI, pI) 

344 self.checkOperator(operator.add, eI, eD, eD) 

345 self.checkOperator(operator.add, eI, eI, eI) 

346 # Subtraction 

347 self.checkOperator(operator.sub, pD, pD, eD) 

348 self.checkOperator(operator.sub, pD, pI, eD) 

349 self.checkOperator(operator.sub, pD, eD, pD) 

350 self.checkOperator(operator.sub, pD, eI, pD) 

351 self.checkOperator(operator.sub, pI, pD, eD) 

352 self.checkOperator(operator.sub, pI, pI, eI) 

353 self.checkOperator(operator.sub, pI, eD, pD) 

354 self.checkOperator(operator.sub, pI, eI, pI) 

355 self.checkOperator(operator.sub, eD, pD, TypeError) 

356 self.checkOperator(operator.sub, eD, pI, TypeError) 

357 self.checkOperator(operator.sub, eD, eD, eD) 

358 self.checkOperator(operator.sub, eD, eI, eD) 

359 self.checkOperator(operator.sub, eI, pD, TypeError) 

360 self.checkOperator(operator.sub, eI, pI, TypeError) 

361 self.checkOperator(operator.sub, eI, eD, eD) 

362 self.checkOperator(operator.sub, eI, eI, eI) 

363 # Multiplication 

364 self.checkOperator(operator.mul, eD, int, eD) 

365 self.checkOperator(operator.mul, eD, float, eD) 

366 self.checkOperator(operator.mul, eI, int, eI) 

367 self.checkOperator(operator.mul, eI, float, eD) 

368 self.checkOperator(operator.mul, int, eD, eD) 

369 self.checkOperator(operator.mul, float, eD, eD) 

370 self.checkOperator(operator.mul, int, eI, eI) 

371 self.checkOperator(operator.mul, float, eI, eD) 

372 # New-Style Division 

373 self.checkOperator(operator.truediv, eD, int, eD) 

374 self.checkOperator(operator.truediv, eD, float, eD) 

375 self.checkOperator(operator.truediv, eI, int, eD) 

376 self.checkOperator(operator.truediv, eI, float, eD) 

377 # Floor Division 

378 self.checkOperator(operator.floordiv, eD, int, TypeError) 

379 self.checkOperator(operator.floordiv, eD, float, TypeError) 

380 self.checkOperator(operator.floordiv, eI, int, eI) 

381 self.checkOperator(operator.floordiv, eI, float, TypeError) 

382 

383 def testInPlaceOperators(self): 

384 for n in (2, 3): 

385 pD = geom.Point[float, n] 

386 pI = geom.Point[int, n] 

387 eD = geom.Extent[float, n] 

388 eI = geom.Extent[int, n] 

389 # Addition 

390 self.checkOperator(operator.iadd, pD, pD, TypeError) 

391 self.checkOperator(operator.iadd, pD, pI, TypeError) 

392 self.checkOperator(operator.iadd, pD, eD, pD, inPlace=True) 

393 self.checkOperator(operator.iadd, pD, eI, pD, inPlace=True) 

394 self.checkOperator(operator.iadd, pI, pD, TypeError) 

395 self.checkOperator(operator.iadd, pI, pI, TypeError) 

396 self.checkOperator(operator.iadd, pI, eD, TypeError) 

397 self.checkOperator(operator.iadd, pI, eI, pI, inPlace=True) 

398 self.checkOperator(operator.iadd, eD, pD, TypeError) 

399 self.checkOperator(operator.iadd, eD, pI, TypeError) 

400 self.checkOperator(operator.iadd, eD, eI, eD, inPlace=True) 

401 self.checkOperator(operator.iadd, eD, eD, eD, inPlace=True) 

402 self.checkOperator(operator.iadd, eI, pD, TypeError) 

403 self.checkOperator(operator.iadd, eI, pI, TypeError) 

404 self.checkOperator(operator.iadd, eI, eD, TypeError) 

405 self.checkOperator(operator.iadd, eI, eI, eI, inPlace=True) 

406 # Subtraction 

407 self.checkOperator(operator.isub, pD, pD, TypeError) 

408 self.checkOperator(operator.isub, pD, pI, TypeError) 

409 self.checkOperator(operator.isub, pD, eD, pD, inPlace=True) 

410 self.checkOperator(operator.isub, pD, eI, pD, inPlace=True) 

411 self.checkOperator(operator.isub, pI, pD, TypeError) 

412 self.checkOperator(operator.isub, pI, pI, TypeError) 

413 self.checkOperator(operator.isub, pI, eD, TypeError) 

414 self.checkOperator(operator.isub, pI, eI, pI, inPlace=True) 

415 self.checkOperator(operator.isub, eD, pD, TypeError) 

416 self.checkOperator(operator.isub, eD, pI, TypeError) 

417 self.checkOperator(operator.isub, eD, eD, eD, inPlace=True) 

418 self.checkOperator(operator.isub, eD, eI, eD, inPlace=True) 

419 self.checkOperator(operator.isub, eI, pD, TypeError) 

420 self.checkOperator(operator.isub, eI, pI, TypeError) 

421 self.checkOperator(operator.isub, eI, eD, TypeError) 

422 self.checkOperator(operator.isub, eI, eI, eI, inPlace=True) 

423 # Multiplication 

424 self.checkOperator(operator.imul, eD, int, eD, inPlace=True) 

425 self.checkOperator(operator.imul, eD, float, eD, inPlace=True) 

426 self.checkOperator(operator.imul, eI, int, eI, inPlace=True) 

427 self.checkOperator(operator.imul, eI, float, TypeError) 

428 # New-Style Division 

429 self.checkOperator(operator.itruediv, eD, int, eD, inPlace=True) 

430 self.checkOperator(operator.itruediv, eD, float, eD, inPlace=True) 

431 self.checkOperator(operator.itruediv, eI, int, TypeError) 

432 self.checkOperator(operator.itruediv, eI, float, TypeError) 

433 # Floor Division 

434 self.checkOperator(operator.floordiv, eD, int, TypeError) 

435 self.checkOperator(operator.floordiv, eD, float, TypeError) 

436 self.checkOperator(operator.floordiv, eI, int, eI) 

437 self.checkOperator(operator.floordiv, eI, float, TypeError) 

438 

439 

440class MemoryTester(lsst.utils.tests.MemoryTestCase): 

441 pass 

442 

443 

444def setup_module(module): 

445 lsst.utils.tests.init() 

446 

447 

448if __name__ == "__main__": 448 ↛ 449line 448 didn't jump to line 449, because the condition on line 448 was never true

449 lsst.utils.tests.init() 

450 unittest.main()