def test_solver_minmax_respects_two_minimum():
    '''
    Tests 3 papers, 4 reviewers.   Reviewers review min: 2, max: 3 papers.   Each paper needs 3 reviews.
    Reviewer 4 has very high cost.  Other reviewers have 0 cost.
    Purpose:  Make sure all reviewers (including reviewer 4) get at least their minimum
    '''
    num_papers = 3
    num_reviewers = 4
    min_papers_per_reviewer = 2
    max_papers_per_reviewer = 3
    paper_revs_reqd = 3
    cost_matrix = np.transpose(
        np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0], [2000, 2000, 2000]]))
    constraint_matrix = np.transpose(
        np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]))

    rev_mins = [min_papers_per_reviewer] * num_reviewers
    rev_maxs = [max_papers_per_reviewer] * num_reviewers
    papers_reqd = [paper_revs_reqd] * num_papers
    solver = MinMaxSolver(rev_mins,
                          rev_maxs,
                          papers_reqd,
                          encoder(cost_matrix, constraint_matrix),
                          allow_zero_score_assignments=True)
    res = solver.solve()
    assert res.shape == (3, 4)
    # make sure every reviewer has at least 1 paper
    nrows, ncols = res.shape
    for rix in range(nrows):
        reviewer_count_reviews = 0
        for pix in range(ncols):
            if res[rix, pix] != 0:
                reviewer_count_reviews += 1
        assert reviewer_count_reviews >= 1
Beispiel #2
0
def test_solver_finds_lowest_cost_soln():
    '''
    4 reviewers 3 papers.   Papers 0,1 need 1 review; Paper 2 needs 2 reviews.  Reviewers can do max of 2 reviews
    Setup so that lowest cost solution should be
    Reviewer 0 reviews paper 0
             1 reviews paper 1
             2 reviews paper 2
             3 reviews paper 2
    Purpose:  Finds the lowest cost solution
    '''
    cost_matrix = np.transpose(np.array([
        [0, 1, 1],
        [1, 0, 1],
        [1, 1, 0],
        [2, 2, 0]
    ]))
    constraint_matrix = np.zeros(np.shape(cost_matrix))
    solver = MinMaxSolver(
        [1,1,1,1],
        [2,2,2,2],
        [1,1,2],
        encoder(cost_matrix, constraint_matrix)
    )
    res = solver.solve()
    assert res.shape == (3,4)

    expected_cost = 0
    check_solution(solver, expected_cost)
def test_solver_minmax_avoid_zero_scores_get_no_solution():
    '''
    Tests 3 papers, 4 reviewers.
    Reviewers review min: 2, max: 3 papers.
    Each paper needs 3 reviews.
    Reviewer 4 has very high cost.
    Other reviewers have 0 cost.
    Purpose:  Make sure all reviewers (including reviewer 4) get at least their minimum
    '''
    num_papers = 3
    num_reviewers = 4
    min_papers_per_reviewer = 2
    max_papers_per_reviewer = 3
    paper_revs_reqd = 3
    aggregate_score_matrix = np.transpose(
        np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 1, 0]]))
    constraint_matrix = np.transpose(
        np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]))

    rev_mins = [min_papers_per_reviewer] * num_reviewers
    rev_maxs = [max_papers_per_reviewer] * num_reviewers
    papers_reqd = [paper_revs_reqd] * num_papers
    solver = MinMaxSolver(rev_mins,
                          rev_maxs,
                          papers_reqd,
                          encoder(aggregate_score_matrix, constraint_matrix),
                          allow_zero_score_assignments=False)

    res = solver.solve()
    assert solver.solved == False
def test_solver4_minmax():
    '''
    Tests 6 papers, 6 reviewers.   Reviewers review min: 2, max: 3 papers.   Each paper needs 2 reviews.
    All scores set to 1 so that any match that does not violate constraints is optimal
    Purpose:  Honors minimums == 2 for all reviewers
    '''
    cost_matrix = np.array([[1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1],
                            [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1],
                            [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1]])
    constraint_matrix = np.array([[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
                                  [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
                                  [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]])

    solver = MinMaxSolver([2, 2, 2, 2, 2, 2], [3, 3, 3, 3, 3, 3],
                          [2, 2, 2, 2, 2, 2],
                          encoder(cost_matrix, constraint_matrix))
    res = solver.solve()
    assert res.shape == (6, 6)
    # make sure every reviewer is reviewing 2 papers
    nrows, ncols = res.shape
    for rix in range(nrows):
        reviewer_count_reviews = 0
        for pix in range(ncols):
            if res[rix, pix] != 0:
                reviewer_count_reviews += 1
        assert reviewer_count_reviews == 2
    check_solution(solver, solver.optimal_cost)
def test_solver_minmax_find_lowest_cost_and_respect_constraints():
    '''
    Tests 5 papers, 4 reviewers.   Reviewers review min: 1, max: 3 papers.   Each paper needs 2 reviews.
    Constrained such that:
    Reviewer 0: available for all papers
             1: cannot review papers 0,3
             2: cannot review papers 3,4
             3: cannot review papers 1,2
    Scores set such that a lowest-cost solution can be found along all reviewer-paper arcs with cost = -10 and no others.
    Purpose:  Finds the lowest cost solution in combination with honoring constraints (i.e. ignores lower-cost paths that are constrained to be ommitted)
    '''
    cost_matrix = np.transpose(
        np.array([[-10, 1, 1, -10, -10], [-100, -10, -10, -100, 1],
                  [1, -10, -10, -100, -100], [-10, -100, -100, -10, -10]]))
    constraint_matrix = np.transpose(
        np.array([[0, 0, 0, 0, 0], [-1, 0, 0, -1, 0], [0, 0, 0, -1, -1],
                  [0, -1, -1, 0, 0]]))

    solver = MinMaxSolver([1, 1, 1, 1], [3, 3, 3, 3], [2, 2, 2, 2, 2],
                          encoder(cost_matrix, constraint_matrix))
    res = solver.solve()
    assert res.shape == (5, 4)
    # make sure result does not violate constraints (i.e. no flow at i,j if there is a -1 constraint at i,j
    # make sure the score at i,j = -10 if there is flow there.
    nrows, ncols = res.shape
    for i in range(nrows):
        for j in range(ncols):
            assert not (constraint_matrix[i, j] == -1 and res[i, j] > 0
                        ), "Solution violates constraint at [{},{}]".format(
                            i, j)
            assert not (
                res[i, j] > 0 and cost_matrix[i, j] > -10
            ), "Solution contains an arc that is not part of an lowest-cost solution"
    check_solution(solver, solver.optimal_cost)
def test_solver_minmax_respects_constraints():
    '''
    Tests 5 papers, 4 reviewers.   Reviewers review min: 1, max: 3 papers.   Each paper needs 2 reviews.
    Constrained such that:
    Reviewer 0: available for all papers
             1: cannot review papers 2,3
             2: cannot review papers 2,3
             3: cannot review papers 0, 1
    All scores set to 1 so that any match that does not violate constraints is optimal
    Purpose:  Honors constraints in its solution
    '''
    cost_matrix = np.transpose(
        np.array([[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1],
                  [1, 1, 1, 1, 1]]))
    constraint_matrix = np.transpose(
        np.array([[0, 0, 0, 0, 0], [0, 0, -1, -1, 0], [0, 0, -1, -1, 0],
                  [-1, -1, 0, 0, 0]]))

    solver = MinMaxSolver([1, 1, 1, 1], [3, 3, 3, 3], [2, 2, 2, 2, 2],
                          encoder(cost_matrix, constraint_matrix))

    res = solver.solve()
    assert res.shape == (5, 4)
    # make sure result does not violate constraints (i.e. no flow at i,j if there is a -1 constraint at i,j
    nrows, ncols = res.shape
    for i in range(nrows):
        for j in range(ncols):
            assert not (constraint_matrix[i, j] == -1 and res[i, j] > 0
                        ), "Solution violates constraint at [{},{}]".format(
                            i, j)

    check_solution(solver, solver.optimal_cost)
def test_solver_minmax_custom_supply():
    aggregate_score_matrix_A = np.transpose(
        np.array([[0.2, 0.1, 0.4], [0.5, 0.2, 0.3], [0.2, 0.0, 0.6],
                  [0.7, 0.9, 0.3]]))
    constraint_matrix = np.zeros(np.shape(aggregate_score_matrix_A))
    solver_A = MinMaxSolver([1, 1, 1, 1], [2, 1, 3, 1], [2, 2, 2],
                            encoder(aggregate_score_matrix_A,
                                    constraint_matrix))
    res_A = solver_A.solve()
    assert res_A.shape == (3, 4)
def test_solver_minmax_custom_demands_paper_with_0_demand():
    aggregate_score_matrix_A = np.transpose(
        np.array([[0.2, 0.1, 0.4], [0.5, 0.2, 0.3], [0.2, 0.0, 0.6],
                  [0.7, 0.9, 0.3]]))
    constraint_matrix = np.zeros(np.shape(aggregate_score_matrix_A))
    solver_A = MinMaxSolver([0, 0, 0, 0], [2, 2, 2, 2], [2, 1, 0],
                            encoder(aggregate_score_matrix_A,
                                    constraint_matrix))
    res_A = solver_A.solve()
    assert res_A.shape == (3, 4)
    assert np.sum(res_A, axis=1)[2] == 0
Beispiel #9
0
def test_solver5():
    '''
    Tests 3 papers, 4 reviewers.   Reviewers review min: 1, max: 3 papers.   Each paper needs 3 reviews.
    Reviewer 4 has very high cost.  Other reviewers have 0 cost.
    Purpose:  Make sure all reviewers get at least their minimum
    '''
    num_papers = 3
    num_reviewers = 4
    min_papers_per_reviewer = 1
    max_papers_per_reviewer = 3
    paper_revs_reqd = 3
    cost_matrix = np.transpose(np.array([
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0],
        [2000, 2000, 2000]]))
    constraint_matrix = np.transpose(np.array([
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]]))


    rev_mins = [min_papers_per_reviewer] * num_reviewers
    rev_maxs = [max_papers_per_reviewer] * num_reviewers
    papers_reqd = [paper_revs_reqd] * num_papers
    solver = MinMaxSolver(
        rev_mins,
        rev_maxs,
        papers_reqd,
        encoder(cost_matrix, constraint_matrix)
    )
    res = solver.solve()
    assert res.shape == (3, 4)
    # make sure every reviewer has at least 1 paper
    nrows, ncols = res.shape
    for rix in range(nrows):
        reviewer_count_reviews = 0
        for pix in range(ncols):
            if res[rix,pix] != 0:
                reviewer_count_reviews += 1
        assert reviewer_count_reviews >= 1
    # TestSolver.silent = False
    check_solution(solver,solver.optimal_cost)
def test_solver_minmax_impossible_constraints():
    '''
    Test to ensure that the MinMaxSolver's 'solved' attribute is correctly set
    when no solution is possible due to constraints.
    '''

    # 20 papers, 5 reviewers
    num_papers = 20
    num_reviewers = 5
    cost_matrix = np.zeros((num_papers, num_reviewers))
    constraint_matrix = -1 * np.ones(
        (num_papers,
         num_reviewers))  # all pairs are constrained! should be impossible

    minimums = [5] * 5
    maximums = [20] * 5
    demands = [3] * 20

    solver = MinMaxSolver(minimums, maximums, demands,
                          encoder(cost_matrix, constraint_matrix))

    solver.solve()
    assert not solver.solved
def test_solver_minmax_random():
    '''When costs are all zero, compute random assignments'''
    cost_matrix_A = np.transpose(
        np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]))
    constraint_matrix = np.zeros(np.shape(cost_matrix_A))
    solver_A = MinMaxSolver([1, 1, 1, 1], [2, 2, 2, 2], [1, 1, 2],
                            encoder(cost_matrix_A, constraint_matrix))
    res_A = solver_A.solve()
    assert res_A.shape == (3, 4)

    cost_matrix_B = np.transpose(
        np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]))
    constraint_matrix = np.zeros(np.shape(cost_matrix_B))
    solver_B = MinMaxSolver([1, 1, 1, 1], [2, 2, 2, 2], [1, 1, 2],
                            encoder(cost_matrix_B, constraint_matrix))
    res_B = solver_B.solve()
    assert res_B.shape == (3, 4)

    # ensure that the cost matrices are random
    # (i.e. overwhelmingly likely to be different)
    assert not np.array_equal(solver_A.cost_matrix, solver_B.cost_matrix)