Exemplo n.º 1
0
def count_ways_to_obtain_largest_subpopulation(n, m):
    """Return dict of number of ways to obtain largest subpopulation.

    Inputs
      :n: total number (e.g., total number of highest scoring results)
      :m: number of non-negative integers to sum to n (e.g., number of
          workers)

    Output
      :ways: dictionary whose keys are the maximum value of a multiset
             and whose values are the sum of each distinct ordering of
             results, corresponding to an arrangement of a multiset,
             computed over all arrangements of all multisets sharing
             a maximum value.

    Implementation
        Although Multiset.uniq_msets() returns tuples in lexicographical
        order, this implementation would function regardless of order.

    """
    mset = Multiset(n)
    ways = defaultdict(int)
    for grp in mset.uniq_msets(n, m):
        ways[max(grp)] += (mset.multinomial_coeff(grp) *
                           mset.number_of_arrangements(grp))
    return ways
Exemplo n.º 2
0
class TestMultisetMath(unittest.TestCase):
    """Test Multiset calculations."""
    def setUp(self):
        self.mset = Multiset()

    def tearDown(self):
        self.mset.clear()
        self.mset = None

    def test_factorial_random_inputs(self):
        """Test factorial random inputs."""
        for val in random.sample(xrange(300), 5):
            result = self.mset.factorial(val)
            expected = math.factorial(val)
            self.assertEqual(result, expected)

    def test_factorial_bad_inputs(self):
        """Test factorial bad inputs."""
        inputs = (-1, None)
        for value in inputs:
            self.assertRaises(ValueError, self.mset.factorial, value)

    def test_factorial_small_inputs(self):
        """Test factorial small inputs."""
        pairs = ((0, 1), (1, 1), (2, 2), (3, 6))
        for (value, expected) in pairs:
            self.assertEqual(self.mset.factorial(value), expected)

    def test_clear_method(self):
        """Test clear method."""
        self.mset.factorial(10)
        self.assertTrue(len(self.mset._data) > 10)
        self.mset.clear()
        self.assertTrue(len(self.mset._data) == 1)

    def test_is_nonneg_int_on_several_inputs(self):
        """Test is_nonneg_int on several inputs."""
        pairs = ((None, False), (-1, False), (0, True), (1, True), (5.0, True))
        for (value, expected) in pairs:
            self.assertEqual(is_nonneg_int(value), expected)

    def test_uniq_msets_on_bad_input(self):
        """Test uniq_msets on on bad input."""
        f = lambda total, length: list(self.mset.uniq_msets(total, length))
        self.assertRaises(TypeError, f, 10, None)
        self.assertRaises(ValueError, f, -3, 2)

    def test_uniq_msets_on_several_inputs(self):
        """Test uniq_msets on on several inputs."""
        pairs = {(10, 0): [()], (10, 1): [(10, )]}
        for (value, expected) in pairs.items():
            result = list(self.mset.uniq_msets(*value))
            self.assertEqual(result, expected)

    def test_uniq_msets_contains_unique_elements(self):
        """Test uniq_msets contains unique elements."""
        expected = set([(3, 2), (4, 1), (5, 0)])
        result = set(self.mset.uniq_msets(5, 2))
        self.assertEqual(result, expected)

    def test_uniq_msets_contains_correct_number_of_elements(self):
        """Test uniq_msets contains correct number of elements."""
        result = list(self.mset.uniq_msets(5, 2))
        self.assertEqual(len(result), len(set(result)))

    def test_num_ways_n_tuple_key(self):
        """Test num_ways n tuple key."""
        expected = (4, 5, 5)
        num_ways = self.mset.num_ways
        result = tuple(len(list(num_ways(4, 4, x))) for x in xrange(1, 4))
        self.assertEqual(result, expected)

    def test_number_of_arrangements_bad_input(self):
        """Test number_of_arrangements bad input."""
        num_arrange = self.mset.number_of_arrangements
        self.assertRaises(TypeError, num_arrange, 5)
        self.assertRaises(TypeError, num_arrange, None)
        self.assertRaises(ValueError, num_arrange, ())

    def test_number_of_arrangements_good_input(self):
        """Test number_of_arrangements good input."""
        pairs = (((3, ), 1), ((2, 3), 2), ((1, 2, 3), 6))
        num_arrange = self.mset.number_of_arrangements
        for (value, expected) in pairs:
            self.assertEqual(num_arrange(value), expected)

    def test_iterate_through_number_of_arrangements_list_input(self):
        """Test iterate through number_of_arrangements list input."""
        groups = [(0, 5), (1, 4), (2, 3)]
        result = dict(
            (grp, self.mset.number_of_arrangements(grp)) for grp in groups)
        expected = {(0, 5): 2, (1, 4): 2, (2, 3): 2}
        self.assertEqual(result, expected)

    def test_iterate_through_number_of_arrangements_by_uniq_msets(self):
        """Test iterate through number_of_arrangements by uniq_msets."""
        result = dict((grp, self.mset.number_of_arrangements(grp))
                      for grp in self.mset.uniq_msets(5, 2))
        expected = {(5, 0): 2, (4, 1): 2, (3, 2): 2}
        self.assertEqual(result, expected)

    def test_multinomial_coeff_bad_inputs(self):
        """Test multinomial_coeff bad inputs."""
        m_coeff = self.mset.multinomial_coeff
        self.assertRaises(TypeError, m_coeff, None)
        self.assertRaises(ValueError, m_coeff, ())

    def test_multinomial_coeff_good_inputs(self):
        """Test multinomial_coeff good inputs."""
        pairs = (((0, ), 1), ((3, ), 1), ((2, 3), 10), ((1, 2, 3), 60))
        m_coeff = self.mset.multinomial_coeff
        for (value, expected) in pairs:
            self.assertEqual(m_coeff(value), expected)

    def test_number_arrangements_of_uniq_msets_is_mset_number(self):
        """Test number_arrangements of uniq_msets is mset number."""
        for n in (5, 15, 30):
            for m in (3, 6):
                l1 = self.mset.multiset_number(n, m)
                l2 = sum(
                    self.mset.number_of_arrangements(ms)
                    for ms in self.mset.uniq_msets(n, m))
                self.assertEqual(l1, l2)

    def test_num_uniq_msets_is_equal_to_calculated_number(self):
        """Test num_uniq_msets is equal to calculated number."""
        for n in (5, 15, 30):
            for m in (3, 6):
                l1 = self.mset.num_uniq_msets(n, m)
                l2 = sum(1 for ms in self.mset.uniq_msets(n, m))
                self.assertEqual(l1, l2)
Exemplo n.º 3
0
class TestMultisetMath(unittest.TestCase):

    """Test Multiset calculations."""

    def setUp(self):
        self.mset = Multiset()

    def tearDown(self):
        self.mset.clear()
        self.mset = None

    def test_factorial_random_inputs(self):
        """Test factorial random inputs."""
        for val in random.sample(xrange(300), 5):
            result = self.mset.factorial(val)
            expected = math.factorial(val)
            self.assertEqual(result, expected)

    def test_factorial_bad_inputs(self):
        """Test factorial bad inputs."""
        inputs = (-1, None)
        for value in inputs:
            self.assertRaises(ValueError, self.mset.factorial, value)

    def test_factorial_small_inputs(self):
        """Test factorial small inputs."""
        pairs = ((0, 1), (1, 1), (2, 2), (3, 6))
        for (value, expected) in pairs:
            self.assertEqual(self.mset.factorial(value), expected)

    def test_clear_method(self):
        """Test clear method."""
        self.mset.factorial(10)
        self.assertTrue(len(self.mset._data) > 10)
        self.mset.clear()
        self.assertTrue(len(self.mset._data) == 1)

    def test_is_nonneg_int_on_several_inputs(self):
        """Test is_nonneg_int on several inputs."""
        pairs = ((None, False), (-1, False),
            (0, True), (1, True), (5.0, True))
        for (value, expected) in pairs:
            self.assertEqual(is_nonneg_int(value), expected)

    def test_uniq_msets_on_bad_input(self):
        """Test uniq_msets on on bad input."""
        f = lambda total, length: list(self.mset.uniq_msets(total, length))
        self.assertRaises(TypeError, f, 10, None)
        self.assertRaises(ValueError, f, -3, 2)

    def test_uniq_msets_on_several_inputs(self):
        """Test uniq_msets on on several inputs."""
        pairs = {(10, 0): [()], (10, 1): [(10,)]}
        for (value, expected) in pairs.items():
            result = list(self.mset.uniq_msets(*value))
            self.assertEqual(result, expected)

    def test_uniq_msets_contains_unique_elements(self):
        """Test uniq_msets contains unique elements."""
        expected = set([(3, 2), (4, 1), (5, 0)])
        result = set(self.mset.uniq_msets(5, 2))
        self.assertEqual(result, expected)

    def test_uniq_msets_contains_correct_number_of_elements(self):
        """Test uniq_msets contains correct number of elements."""
        result = list(self.mset.uniq_msets(5, 2))
        self.assertEqual(len(result), len(set(result)))

    def test_num_ways_n_tuple_key(self):
        """Test num_ways n tuple key."""
        expected = (4, 5, 5)
        num_ways = self.mset.num_ways
        result = tuple(len(list(num_ways(4, 4, x))) for x in xrange(1,4))
        self.assertEqual(result, expected)

    def test_number_of_arrangements_bad_input(self):
        """Test number_of_arrangements bad input."""
        num_arrange = self.mset.number_of_arrangements
        self.assertRaises(TypeError, num_arrange, 5)
        self.assertRaises(TypeError, num_arrange, None)
        self.assertRaises(ValueError, num_arrange, ())

    def test_number_of_arrangements_good_input(self):
        """Test number_of_arrangements good input."""
        pairs = (((3,), 1), ((2, 3), 2), ((1, 2, 3), 6))
        num_arrange = self.mset.number_of_arrangements
        for (value, expected) in pairs:
            self.assertEqual(num_arrange(value), expected)

    def test_iterate_through_number_of_arrangements_list_input(self):
        """Test iterate through number_of_arrangements list input."""
        groups = [(0, 5), (1, 4), (2, 3)]
        result = dict((grp, self.mset.number_of_arrangements(grp))
                    for grp in groups)
        expected = {(0, 5): 2, (1, 4): 2, (2, 3): 2}
        self.assertEqual(result, expected)

    def test_iterate_through_number_of_arrangements_by_uniq_msets(self):
        """Test iterate through number_of_arrangements by uniq_msets."""
        result = dict((grp, self.mset.number_of_arrangements(grp))
                    for grp in self.mset.uniq_msets(5, 2))
        expected = {(5, 0): 2, (4, 1): 2, (3, 2): 2}
        self.assertEqual(result, expected)

    def test_multinomial_coeff_bad_inputs(self):
        """Test multinomial_coeff bad inputs."""
        m_coeff = self.mset.multinomial_coeff
        self.assertRaises(TypeError, m_coeff, None)
        self.assertRaises(ValueError, m_coeff, ())

    def test_multinomial_coeff_good_inputs(self):
        """Test multinomial_coeff good inputs."""
        pairs = (((0,), 1), ((3,), 1), ((2, 3), 10), ((1, 2, 3), 60))
        m_coeff = self.mset.multinomial_coeff
        for (value, expected) in pairs:
            self.assertEqual(m_coeff(value), expected)

    def test_number_arrangements_of_uniq_msets_is_mset_number(self):
        """Test number_arrangements of uniq_msets is mset number."""
        for n in (5, 15, 30):
            for m in (3, 6):
                l1 = self.mset.multiset_number(n, m)
                l2 = sum(self.mset.number_of_arrangements(ms)
                    for ms in self.mset.uniq_msets(n, m))
                self.assertEqual(l1, l2)

    def test_num_uniq_msets_is_equal_to_calculated_number(self):
        """Test num_uniq_msets is equal to calculated number."""
        for n in (5, 15, 30):
            for m in (3, 6):
                l1 = self.mset.num_uniq_msets(n, m)
                l2 = sum(1 for ms in self.mset.uniq_msets(n, m))
                self.assertEqual(l1, l2)