class CoordinateEncoderTest(unittest.TestCase): """Unit tests for CoordinateEncoder class""" def setUp(self): self.encoder = CoordinateEncoder(name="coordinate", n=33, w=3) def testInvalidW(self): # Even args = {"name": "coordinate", "n": 45, "w": 4} self.assertRaises(ValueError, CoordinateEncoder, **args) # 0 args = {"name": "coordinate", "n": 45, "w": 0} self.assertRaises(ValueError, CoordinateEncoder, **args) # Negative args = {"name": "coordinate", "n": 45, "w": -2} self.assertRaises(ValueError, CoordinateEncoder, **args) def testInvalidN(self): # Too small args = {"name": "coordinate", "n": 11, "w": 3} self.assertRaises(ValueError, CoordinateEncoder, **args) def testOrderForCoordinate(self): h1 = self.encoder._orderForCoordinate(np.array([2, 5, 10])) h2 = self.encoder._orderForCoordinate(np.array([2, 5, 11])) h3 = self.encoder._orderForCoordinate(np.array([2497477, -923478])) self.assertTrue(0 <= h1 and h1 < 1) self.assertTrue(0 <= h2 and h2 < 1) self.assertTrue(0 <= h3 and h3 < 1) self.assertTrue(h1 != h2) self.assertTrue(h2 != h3) def testBitForCoordinate(self): n = 1000 b1 = self.encoder._bitForCoordinate(np.array([2, 5, 10]), n) b2 = self.encoder._bitForCoordinate(np.array([2, 5, 11]), n) b3 = self.encoder._bitForCoordinate(np.array([2497477, -923478]), n) self.assertTrue(0 <= b1 and b1 < n) self.assertTrue(0 <= b2 and b2 < n) self.assertTrue(0 <= b3 and b3 < n) self.assertTrue(b1 != b2) self.assertTrue(b2 != b3) # Small n n = 2 b4 = self.encoder._bitForCoordinate(np.array([5, 10]), n) self.assertTrue(0 <= b4 < n) @patch.object(CoordinateEncoder, "_orderForCoordinate") def testTopWCoordinates(self, mockOrderForCoordinate): # Mock orderForCoordinate mockFn = lambda coordinate: np.sum(coordinate) / 5.0 mockOrderForCoordinate.side_effect = mockFn coordinates = np.array([[1], [2], [3], [4], [5]]) top = self.encoder._topWCoordinates(coordinates, 2).tolist() self.assertEqual(len(top), 2) self.assertTrue([5] in top) self.assertTrue([4] in top) def testNeighbors1D(self): coordinate = np.array([100]) radius = 5 neighbors = self.encoder._neighbors(coordinate, radius).tolist() self.assertEqual(len(neighbors), 11) self.assertTrue([95] in neighbors) self.assertTrue([100] in neighbors) self.assertTrue([105] in neighbors) def testNeighbors2D(self): coordinate = np.array([100, 200]) radius = 5 neighbors = self.encoder._neighbors(coordinate, radius).tolist() self.assertEqual(len(neighbors), 121) self.assertTrue([95, 195] in neighbors) self.assertTrue([95, 205] in neighbors) self.assertTrue([100, 200] in neighbors) self.assertTrue([105, 195] in neighbors) self.assertTrue([105, 205] in neighbors) def testNeighbors0Radius(self): coordinate = np.array([100, 200, 300]) radius = 0 neighbors = self.encoder._neighbors(coordinate, radius).tolist() self.assertEqual(len(neighbors), 1) self.assertTrue([100, 200, 300] in neighbors) def testEncodeIntoArray(self): n = 33 w = 3 encoder = CoordinateEncoder(name="coordinate", n=n, w=w) coordinate = np.array([100, 200]) radius = 5 output1 = encode(encoder, coordinate, radius) self.assertEqual(np.sum(output1), w) # Test that we get the same output for the same input output2 = encode(encoder, coordinate, radius) self.assertTrue(np.array_equal(output2, output1)) def testEncodeSaturateArea(self): n = 1999 w = 25 encoder = CoordinateEncoder(name="coordinate", n=n, w=w) outputA = encode(encoder, np.array([0, 0]), 2) outputB = encode(encoder, np.array([0, 1]), 2) self.assertEqual(overlap(outputA, outputB), 0.8) def testEncodeRelativePositions(self): # As you get farther from a coordinate, the overlap should decrease overlaps = overlapsForRelativeAreas(999, 25, np.array([100, 200]), 10, dPosition=np.array([2, 2]), num=5) self.assertDecreasingOverlaps(overlaps) def testEncodeRelativeRadii(self): # As radius increases, the overlap should decrease overlaps = overlapsForRelativeAreas(999, 25, np.array([100, 200]), 5, dRadius=1, num=5) self.assertDecreasingOverlaps(overlaps) # As radius decreases, the overlap should decrease overlaps = overlapsForRelativeAreas(999, 25, np.array([100, 200]), 20, dRadius=-2, num=5) self.assertDecreasingOverlaps(overlaps) def testEncodeRelativePositionsAndRadii(self): # As radius increases and positions change, the overlap should decrease overlaps = overlapsForRelativeAreas(999, 25, np.array([100, 200]), 5, dPosition=np.array([1, 1]), dRadius=1, num=5) self.assertDecreasingOverlaps(overlaps) def testEncodeUnrelatedAreas(self): """ assert unrelated areas don"t share bits (outside of chance collisions) """ avgThreshold = 0.3 maxThreshold = 0.12 overlaps = overlapsForUnrelatedAreas(1499, 37, 5) self.assertTrue(np.max(overlaps) < maxThreshold) self.assertTrue(np.average(overlaps) < avgThreshold) maxThreshold = 0.12 overlaps = overlapsForUnrelatedAreas(1499, 37, 10) self.assertTrue(np.max(overlaps) < maxThreshold) self.assertTrue(np.average(overlaps) < avgThreshold) maxThreshold = 0.17 overlaps = overlapsForUnrelatedAreas(999, 25, 10) self.assertTrue(np.max(overlaps) < maxThreshold) self.assertTrue(np.average(overlaps) < avgThreshold) maxThreshold = 0.25 overlaps = overlapsForUnrelatedAreas(499, 13, 10) self.assertTrue(np.max(overlaps) < maxThreshold) self.assertTrue(np.average(overlaps) < avgThreshold) def testEncodeAdjacentPositions(self, verbose=False): repetitions = 100 n = 999 w = 25 radius = 10 minThreshold = 0.75 avgThreshold = 0.90 allOverlaps = np.empty(repetitions) for i in range(repetitions): overlaps = overlapsForRelativeAreas(n, w, np.array([i * 10, i * 10]), radius, dPosition=np.array([0, 1]), num=1) allOverlaps[i] = overlaps[0] self.assertTrue(np.min(allOverlaps) > minThreshold) self.assertTrue(np.average(allOverlaps) > avgThreshold) if verbose: print( "===== Adjacent positions overlap " "(n = {0}, w = {1}, radius = {2}) ===").format(n, w, radius) print "Max: {0}".format(np.max(allOverlaps)) print "Min: {0}".format(np.min(allOverlaps)) print "Average: {0}".format(np.average(allOverlaps)) def assertDecreasingOverlaps(self, overlaps): self.assertEqual((np.diff(overlaps) >= 0).sum(), 0)
class CoordinateEncoderTest(unittest.TestCase): """Unit tests for CoordinateEncoder class""" def setUp(self): self.encoder = CoordinateEncoder(name="coordinate", n=33, w=3) def testInvalidW(self): # Even args = {"name": "coordinate", "n": 45, "w": 4} self.assertRaises(ValueError, CoordinateEncoder, **args) # 0 args = {"name": "coordinate", "n": 45, "w": 0} self.assertRaises(ValueError, CoordinateEncoder, **args) # Negative args = {"name": "coordinate", "n": 45, "w": -2} self.assertRaises(ValueError, CoordinateEncoder, **args) def testInvalidN(self): # Too small args = {"name": "coordinate", "n": 11, "w": 3} self.assertRaises(ValueError, CoordinateEncoder, **args) def testHashCoordinate(self): h1 = self.encoder._hashCoordinate(np.array([0])) self.assertEqual(h1, 7415141576215061722) h2 = self.encoder._hashCoordinate(np.array([0, 1])) self.assertEqual(h2, 6909411824118942936) def testOrderForCoordinate(self): h1 = self.encoder._orderForCoordinate(np.array([2, 5, 10])) h2 = self.encoder._orderForCoordinate(np.array([2, 5, 11])) h3 = self.encoder._orderForCoordinate(np.array([2497477, -923478])) self.assertTrue(0 <= h1 and h1 < 1) self.assertTrue(0 <= h2 and h2 < 1) self.assertTrue(0 <= h3 and h3 < 1) self.assertTrue(h1 != h2) self.assertTrue(h2 != h3) def testBitForCoordinate(self): n = 1000 b1 = self.encoder._bitForCoordinate(np.array([2, 5, 10]), n) b2 = self.encoder._bitForCoordinate(np.array([2, 5, 11]), n) b3 = self.encoder._bitForCoordinate(np.array([2497477, -923478]), n) self.assertTrue(0 <= b1 and b1 < n) self.assertTrue(0 <= b2 and b2 < n) self.assertTrue(0 <= b3 and b3 < n) self.assertTrue(b1 != b2) self.assertTrue(b2 != b3) # Small n n = 2 b4 = self.encoder._bitForCoordinate(np.array([5, 10]), n) self.assertTrue(0 <= b4 < n) @patch.object(CoordinateEncoder, "_orderForCoordinate") def testTopWCoordinates(self, mockOrderForCoordinate): # Mock orderForCoordinate mockFn = lambda coordinate: np.sum(coordinate) / 5.0 mockOrderForCoordinate.side_effect = mockFn coordinates = np.array([[1], [2], [3], [4], [5]]) top = self.encoder._topWCoordinates(coordinates, 2).tolist() self.assertEqual(len(top), 2) self.assertIn([5], top) self.assertIn([4], top) def testNeighbors1D(self): coordinate = np.array([100]) radius = 5 neighbors = self.encoder._neighbors(coordinate, radius).tolist() self.assertEqual(len(neighbors), 11) self.assertIn([95], neighbors) self.assertIn([100], neighbors) self.assertIn([105], neighbors) def testNeighbors2D(self): coordinate = np.array([100, 200]) radius = 5 neighbors = self.encoder._neighbors(coordinate, radius).tolist() self.assertEqual(len(neighbors), 121) self.assertIn([95, 195], neighbors) self.assertIn([95, 205], neighbors) self.assertIn([100, 200], neighbors) self.assertIn([105, 195], neighbors) self.assertIn([105, 205], neighbors) def testNeighbors0Radius(self): coordinate = np.array([100, 200, 300]) radius = 0 neighbors = self.encoder._neighbors(coordinate, radius).tolist() self.assertEqual(len(neighbors), 1) self.assertIn([100, 200, 300], neighbors) def testEncodeIntoArray(self): n = 33 w = 3 encoder = CoordinateEncoder(name="coordinate", n=n, w=w) coordinate = np.array([100, 200]) radius = 5 output1 = encode(encoder, coordinate, radius) self.assertEqual(np.sum(output1), w) # Test that we get the same output for the same input output2 = encode(encoder, coordinate, radius) self.assertTrue(np.array_equal(output2, output1)) def testEncodeSaturateArea(self): n = 1999 w = 25 encoder = CoordinateEncoder(name="coordinate", n=n, w=w) outputA = encode(encoder, np.array([0, 0]), 2) outputB = encode(encoder, np.array([0, 1]), 2) self.assertEqual(overlap(outputA, outputB), 0.8) def testEncodeRelativePositions(self): # As you get farther from a coordinate, the overlap should decrease overlaps = overlapsForRelativeAreas(999, 51, np.array([100, 200]), 10, dPosition=np.array([2, 2]), num=5) self.assertDecreasingOverlaps(overlaps) def testEncodeRelativeRadii(self): # As radius increases, the overlap should decrease overlaps = overlapsForRelativeAreas(999, 25, np.array([100, 200]), 5, dRadius=2, num=5) self.assertDecreasingOverlaps(overlaps) # As radius decreases, the overlap should decrease overlaps = overlapsForRelativeAreas(999, 51, np.array([100, 200]), 20, dRadius=-2, num=5) self.assertDecreasingOverlaps(overlaps) def testEncodeRelativePositionsAndRadii(self): # As radius increases and positions change, the overlap should decrease overlaps = overlapsForRelativeAreas(999, 25, np.array([100, 200]), 5, dPosition=np.array([1, 1]), dRadius=1, num=5) self.assertDecreasingOverlaps(overlaps) def testEncodeUnrelatedAreas(self): """ assert unrelated areas don"t share bits (outside of chance collisions) """ avgThreshold = 0.3 maxThreshold = 0.12 overlaps = overlapsForUnrelatedAreas(1499, 37, 5) self.assertLess(np.max(overlaps), maxThreshold) self.assertLess(np.average(overlaps), avgThreshold) maxThreshold = 0.12 overlaps = overlapsForUnrelatedAreas(1499, 37, 10) self.assertLess(np.max(overlaps), maxThreshold) self.assertLess(np.average(overlaps), avgThreshold) maxThreshold = 0.17 overlaps = overlapsForUnrelatedAreas(999, 25, 10) self.assertLess(np.max(overlaps), maxThreshold) self.assertLess(np.average(overlaps), avgThreshold) maxThreshold = 0.25 overlaps = overlapsForUnrelatedAreas(499, 13, 10) self.assertLess(np.max(overlaps), maxThreshold) self.assertLess(np.average(overlaps), avgThreshold) def testEncodeAdjacentPositions(self, verbose=False): repetitions = 100 n = 999 w = 25 radius = 10 minThreshold = 0.75 avgThreshold = 0.90 allOverlaps = np.empty(repetitions) for i in range(repetitions): overlaps = overlapsForRelativeAreas(n, w, np.array([i * 10, i * 10]), radius, dPosition=np.array([0, 1]), num=1) allOverlaps[i] = overlaps[0] self.assertGreater(np.min(allOverlaps), minThreshold) self.assertGreater(np.average(allOverlaps), avgThreshold) if verbose: print ("===== Adjacent positions overlap " "(n = {0}, w = {1}, radius = {2}) ===").format(n, w, radius) print "Max: {0}".format(np.max(allOverlaps)) print "Min: {0}".format(np.min(allOverlaps)) print "Average: {0}".format(np.average(allOverlaps)) def assertDecreasingOverlaps(self, overlaps): self.assertEqual((np.diff(overlaps) > 0).sum(), 0) @unittest.skipUnless( capnp, "pycapnp is not installed, skipping serialization test.") def testReadWrite(self): coordinate = np.array([100, 200]) radius = 5 output1 = encode(self.encoder, coordinate, radius) proto1 = CoordinateEncoderProto.new_message() self.encoder.write(proto1) # Write the proto to a temp file and read it back into a new proto with tempfile.TemporaryFile() as f: proto1.write(f) f.seek(0) proto2 = CoordinateEncoderProto.read(f) encoder = CoordinateEncoder.read(proto2) self.assertIsInstance(encoder, CoordinateEncoder) self.assertEqual(encoder.w, self.encoder.w) self.assertEqual(encoder.n, self.encoder.n) self.assertEqual(encoder.name, self.encoder.name) self.assertEqual(encoder.verbosity, self.encoder.verbosity) coordinate = np.array([100, 200]) radius = 5 output2 = encode(encoder, coordinate, radius) self.assertTrue(np.array_equal(output1, output2))
class CoordinateEncoderTest(unittest.TestCase): """Unit tests for CoordinateEncoder class""" def setUp(self): self.encoder = CoordinateEncoder(name="coordinate", n=33, w=3) def testInvalidW(self): # Even args = {"name": "coordinate", "n": 45, "w": 4} self.assertRaises(ValueError, CoordinateEncoder, **args) # 0 args = {"name": "coordinate", "n": 45, "w": 0} self.assertRaises(ValueError, CoordinateEncoder, **args) # Negative args = {"name": "coordinate", "n": 45, "w": -2} self.assertRaises(ValueError, CoordinateEncoder, **args) def testInvalidN(self): # Too small args = {"name": "coordinate", "n": 11, "w": 3} self.assertRaises(ValueError, CoordinateEncoder, **args) def testHashCoordinate(self): h1 = self.encoder._hashCoordinate(np.array([0])) self.assertEqual(h1, 7415141576215061722) h2 = self.encoder._hashCoordinate(np.array([0, 1])) self.assertEqual(h2, 6909411824118942936) def testOrderForCoordinate(self): h1 = self.encoder._orderForCoordinate(np.array([2, 5, 10])) h2 = self.encoder._orderForCoordinate(np.array([2, 5, 11])) h3 = self.encoder._orderForCoordinate(np.array([2497477, -923478])) self.assertTrue(0 <= h1 and h1 < 1) self.assertTrue(0 <= h2 and h2 < 1) self.assertTrue(0 <= h3 and h3 < 1) self.assertTrue(h1 != h2) self.assertTrue(h2 != h3) def testBitForCoordinate(self): n = 1000 b1 = self.encoder._bitForCoordinate(np.array([2, 5, 10]), n) b2 = self.encoder._bitForCoordinate(np.array([2, 5, 11]), n) b3 = self.encoder._bitForCoordinate(np.array([2497477, -923478]), n) self.assertTrue(0 <= b1 and b1 < n) self.assertTrue(0 <= b2 and b2 < n) self.assertTrue(0 <= b3 and b3 < n) self.assertTrue(b1 != b2) self.assertTrue(b2 != b3) # Small n n = 2 b4 = self.encoder._bitForCoordinate(np.array([5, 10]), n) self.assertTrue(0 <= b4 < n) @patch.object(CoordinateEncoder, "_orderForCoordinate") def testTopWCoordinates(self, mockOrderForCoordinate): # Mock orderForCoordinate mockFn = lambda coordinate: np.sum(coordinate) / 5.0 mockOrderForCoordinate.side_effect = mockFn coordinates = np.array([[1], [2], [3], [4], [5]]) top = self.encoder._topWCoordinates(coordinates, 2).tolist() self.assertEqual(len(top), 2) self.assertIn([5], top) self.assertIn([4], top) def testNeighbors1D(self): coordinate = np.array([100]) radius = 5 neighbors = self.encoder._neighbors(coordinate, radius).tolist() self.assertEqual(len(neighbors), 11) self.assertIn([95], neighbors) self.assertIn([100], neighbors) self.assertIn([105], neighbors) def testNeighbors2D(self): coordinate = np.array([100, 200]) radius = 5 neighbors = self.encoder._neighbors(coordinate, radius).tolist() self.assertEqual(len(neighbors), 121) self.assertIn([95, 195], neighbors) self.assertIn([95, 205], neighbors) self.assertIn([100, 200], neighbors) self.assertIn([105, 195], neighbors) self.assertIn([105, 205], neighbors) def testNeighbors0Radius(self): coordinate = np.array([100, 200, 300]) radius = 0 neighbors = self.encoder._neighbors(coordinate, radius).tolist() self.assertEqual(len(neighbors), 1) self.assertIn([100, 200, 300], neighbors) def testEncodeIntoArray(self): n = 33 w = 3 encoder = CoordinateEncoder(name="coordinate", n=n, w=w) coordinate = np.array([100, 200]) radius = 5 output1 = encode(encoder, coordinate, radius) self.assertEqual(np.sum(output1), w) # Test that we get the same output for the same input output2 = encode(encoder, coordinate, radius) self.assertTrue(np.array_equal(output2, output1)) # Test that a float radius raises an assertion error with self.assertRaises(AssertionError): encoder.encode((coordinate, float(radius))) def testEncodeSaturateArea(self): n = 1999 w = 25 encoder = CoordinateEncoder(name="coordinate", n=n, w=w) outputA = encode(encoder, np.array([0, 0]), 2) outputB = encode(encoder, np.array([0, 1]), 2) self.assertEqual(overlap(outputA, outputB), 0.8) def testEncodeRelativePositions(self): # As you get farther from a coordinate, the overlap should decrease overlaps = overlapsForRelativeAreas(999, 51, np.array([100, 200]), 10, dPosition=np.array([2, 2]), num=5) self.assertDecreasingOverlaps(overlaps) def testEncodeRelativeRadii(self): # As radius increases, the overlap should decrease overlaps = overlapsForRelativeAreas(999, 25, np.array([100, 200]), 5, dRadius=2, num=5) self.assertDecreasingOverlaps(overlaps) # As radius decreases, the overlap should decrease overlaps = overlapsForRelativeAreas(999, 51, np.array([100, 200]), 20, dRadius=-2, num=5) self.assertDecreasingOverlaps(overlaps) def testEncodeRelativePositionsAndRadii(self): # As radius increases and positions change, the overlap should decrease overlaps = overlapsForRelativeAreas(999, 25, np.array([100, 200]), 5, dPosition=np.array([1, 1]), dRadius=1, num=5) self.assertDecreasingOverlaps(overlaps) def testEncodeUnrelatedAreas(self): """ assert unrelated areas don"t share bits (outside of chance collisions) """ avgThreshold = 0.3 maxThreshold = 0.12 overlaps = overlapsForUnrelatedAreas(1499, 37, 5) self.assertLess(np.max(overlaps), maxThreshold) self.assertLess(np.average(overlaps), avgThreshold) maxThreshold = 0.12 overlaps = overlapsForUnrelatedAreas(1499, 37, 10) self.assertLess(np.max(overlaps), maxThreshold) self.assertLess(np.average(overlaps), avgThreshold) maxThreshold = 0.17 overlaps = overlapsForUnrelatedAreas(999, 25, 10) self.assertLess(np.max(overlaps), maxThreshold) self.assertLess(np.average(overlaps), avgThreshold) maxThreshold = 0.25 overlaps = overlapsForUnrelatedAreas(499, 13, 10) self.assertLess(np.max(overlaps), maxThreshold) self.assertLess(np.average(overlaps), avgThreshold) def testEncodeAdjacentPositions(self, verbose=False): repetitions = 100 n = 999 w = 25 radius = 10 minThreshold = 0.75 avgThreshold = 0.90 allOverlaps = np.empty(repetitions) for i in range(repetitions): overlaps = overlapsForRelativeAreas(n, w, np.array([i * 10, i * 10]), radius, dPosition=np.array([0, 1]), num=1) allOverlaps[i] = overlaps[0] self.assertGreater(np.min(allOverlaps), minThreshold) self.assertGreater(np.average(allOverlaps), avgThreshold) if verbose: print(("===== Adjacent positions overlap " "(n = {0}, w = {1}, radius = {2}) ===").format(n, w, radius)) print("Max: {0}".format(np.max(allOverlaps))) print("Min: {0}".format(np.min(allOverlaps))) print("Average: {0}".format(np.average(allOverlaps))) def assertDecreasingOverlaps(self, overlaps): self.assertEqual((np.diff(overlaps) > 0).sum(), 0) @unittest.skipUnless( capnp, "pycapnp is not installed, skipping serialization test.") def testReadWrite(self): coordinate = np.array([100, 200]) radius = 5 output1 = encode(self.encoder, coordinate, radius) proto1 = CoordinateEncoderProto.new_message() self.encoder.write(proto1) # Write the proto to a temp file and read it back into a new proto with tempfile.TemporaryFile() as f: proto1.write(f) f.seek(0) proto2 = CoordinateEncoderProto.read(f) encoder = CoordinateEncoder.read(proto2) self.assertIsInstance(encoder, CoordinateEncoder) self.assertEqual(encoder.w, self.encoder.w) self.assertEqual(encoder.n, self.encoder.n) self.assertEqual(encoder.name, self.encoder.name) self.assertEqual(encoder.verbosity, self.encoder.verbosity) coordinate = np.array([100, 200]) radius = 5 output2 = encode(encoder, coordinate, radius) self.assertTrue(np.array_equal(output1, output2))