Esempio n. 1
0
    def test_all_students_paired_up_with_even_amount_of_students(
            self, num_students):
        teams = constants.STUDENTS[:num_students]

        allocations = pairwise.generate_review_allocations(teams,
                                                           num_reviews=1)

        assert len(allocations) == num_students
        for review_team, reviewed_team in allocations:
            expected_counter_review = plug.ReviewAllocation(
                review_team=reviewed_team, reviewed_team=review_team)
            assert allocations.index(expected_counter_review) >= 0
Esempio n. 2
0
def generate_review_allocations(
    teams: List[plug.StudentTeam], num_reviews: int = 1
) -> List[plug.ReviewAllocation]:
    """Generate peer review allocations such that if team_a reviews team_b,
    then team_b reviews team_a, and no others!

    The ``num_reviews`` argument is ignored by this plugin.

    Args:
        teams: Student teams for which to allocate reviews.
        num_reviews: Ignored by this plugin.
    Returns:
        A list of allocations that
    """
    teams = list(teams)
    if num_reviews != 1:
        plug.log.warning(
            f"num_reviews specified to {num_reviews}, but in pairwise assignment "
            f"num_reviews is ignored"
        )
    if len(teams) < 2:
        raise ValueError(
            f"there must be at least 2 teams for peer review, "
            f"but {len(teams)} were provided"
        )

    random.shuffle(teams)

    groups = [(teams[i - 1], teams[i]) for i in range(1, len(teams), 2)]
    # odd number of teams necessitates 3 teams in last group
    last_review_group = (
        (*groups[-1], teams[-1]) if len(teams) % 2 else groups[-1]
    )
    finalized_groups = [*groups[:-1], last_review_group]

    allocations = []
    for group in finalized_groups:
        for i, review_team in enumerate(group):
            reviewed_team = group[(i + 1) % len(group)]
            allocations.append(
                plug.ReviewAllocation(
                    review_team=review_team, reviewed_team=reviewed_team
                )
            )
    return allocations
Esempio n. 3
0
def generate_review_allocations(
    teams: List[plug.StudentTeam], num_reviews: int
) -> List[plug.ReviewAllocation]:
    if num_reviews >= len(teams):
        raise ValueError("num_reviews must be less than len(teams)")
    if num_reviews <= 0:
        raise ValueError("num_reviews must be greater than 0")
    if len(teams) < 2:
        raise ValueError(
            f"there must be at least 2 teams for peer review, "
            f"but {len(teams)} were provided"
        )

    random.shuffle(teams)

    # create a list of lists, where each non-first list is a left-shifted
    # version of the previous list (lists wrap around)
    # e.g. for teams [4, 3, 1] and num_reviews = 2, the result is
    # allocations = [[4, 3, 1], [3, 1, 4], [1, 4, 3]] and means that
    # student 4 gets reviewed by 3 and 1, 3 by 1 and 4 etc.
    allocations = [teams]
    for _ in range(num_reviews):
        next_reviewers = list(allocations[-1])
        next_reviewers.append(next_reviewers.pop(0))  # shift list left
        allocations.append(next_reviewers)

    def merge_teams(teams):
        members = list(
            itertools.chain.from_iterable([team.members for team in teams])
        )
        return plug.StudentTeam(members=members)

    transposed_allocations = zip(*allocations)
    review_allocations = [
        plug.ReviewAllocation(
            review_team=merge_teams(reviewers), reviewed_team=reviewed_team
        )
        for reviewed_team, *reviewers in transposed_allocations
    ]

    return review_allocations