class CostPerformanceDatabase: """Maintain a database of maximal (cost,performance) pairs.""" def __init__(self): """Create an empty database.""" self._M = SortedTableMap() # or a more efficient sorted map def best(self, c): """Return (cost,performance) pair with largest cost not exceeding c. Return None if there is no such pair. """ return self._M.find_le(c) def add(self, c, p): """Add new entry with cost c and performance p.""" # determine if (c,p) is dominated by an existing pair other = self._M.find_le(c) # other is at least as cheap as c if other is not None and other[1] >= p: # if its performance is as good, return # (c,p) is dominated, so ignore self._M[c] = p # else, add (c,p) to database # and now remove any pairs that are dominated by (c,p) other = self._M.find_gt(c) # other more expensive than c while other is not None and other[1] <= p: del self._M[other[0]] other = self._M.find_gt(c)
def test_find_key_methods_return_none_when_table_empty(self): """Do the methods that find a key based on an arithmetic comparison criterion return None when the table is empty?""" empty_stmap = SortedTableMap() k = 1 self.assertIsNone(empty_stmap.find_min()) self.assertIsNone(empty_stmap.find_max()) self.assertIsNone(empty_stmap.find_ge(k)) self.assertIsNone(empty_stmap.find_lt(k)) self.assertIsNone(empty_stmap.find_gt(k))
class TestAccessorsWithAlphabetTable(unittest.TestCase): """Uses a table containing 26 (number, letter) k-v pairs to test the methods that return min, max, less than, etc.""" def setUp(self): self.stmap = SortedTableMap() for i in range(ord("a"), ord("a") + 26): key = i - ord("a") self.stmap[key] = chr(i) def test_find_min(self): expected_min = (0, "a") actual_min = self.stmap.find_min() self.assertEqual(expected_min, actual_min) def test_find_max(self): expected_max = (25, "z") actual_max = self.stmap.find_max() self.assertEqual(expected_max, actual_max) def test_find_ge(self): # least key greater than or equal to 15 should be 15. key = 15 expected = (15, "p") actual = self.stmap.find_ge(key) self.assertEqual(expected, actual) def test_find_lt(self): # Greatest key strictly less than 15 should be 14 key = 15 expected = (14, "o") actual = self.stmap.find_lt(key) self.assertEqual(expected, actual) def test_find_gt(self): # Least key strictly greater than 15 should be 16. key = 15 expected = (16, "q") actual = self.stmap.find_gt(key) self.assertEqual(expected, actual) def test_find_range(self): # No start and stop=14 should yield all kvps from (0, "a") to (14, "o") expected = [] for i in range(ord("a"), ord("a") + 15): expected_key = i - ord("a") expected_value = chr(i) expected.append((expected_key, expected_value)) actual = [i for i in self.stmap.find_range(start=None, stop=15)] assert len(actual) == 15 self.assertEqual(expected, actual) # start=10 and stop=20 should yield all k-v pairs from (10, "k") to # (19, "t") expected = [] for i in range(ord("a") + 10, ord("a") + 20): expected_key = i - ord("a") expected_value = chr(i) expected.append((expected_key, expected_value)) actual = [i for i in self.stmap.find_range(start=10, stop=20)] assert len(actual) == 10 self.assertEqual(expected, actual) def test_find_key_methods_return_none_when_table_empty(self): """Do the methods that find a key based on an arithmetic comparison criterion return None when the table is empty?""" empty_stmap = SortedTableMap() k = 1 self.assertIsNone(empty_stmap.find_min()) self.assertIsNone(empty_stmap.find_max()) self.assertIsNone(empty_stmap.find_ge(k)) self.assertIsNone(empty_stmap.find_lt(k)) self.assertIsNone(empty_stmap.find_gt(k))