Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1b65d2f
Start making benchmarks
justino599 Mar 13, 2024
7db4e9e
Created run to benchmark mutations
Hedgemon4 Mar 13, 2024
113b67f
Changes url
Hedgemon4 Mar 13, 2024
f686d25
Fixed mock student provider to print a warning instead of throwing an…
Hedgemon4 Mar 13, 2024
60b4078
Updated simulation cache name
Hedgemon4 Mar 13, 2024
ff8dc57
Fix initial teams provider
justino599 Mar 13, 2024
322fb56
MERFGE
justino599 Mar 13, 2024
2b12cdd
Started fixing student provider
Hedgemon4 Mar 13, 2024
f86fe38
Merge branch '398-benchmark-new-mutations' of https://github.com/Team…
Hedgemon4 Mar 13, 2024
3351b7a
Fixed issues with run
Hedgemon4 Mar 14, 2024
390d112
Generated graphs
Hedgemon4 Mar 14, 2024
1d0f316
Removed simulation cache changes
Hedgemon4 Mar 14, 2024
bd954a9
Add runtime graph
justino599 Mar 14, 2024
17c4cfb
Adjust run to use K's configs
justino599 Mar 16, 2024
77b4442
Refactored mutations to new class
Hedgemon4 Mar 16, 2024
f3f51f5
Refactored runs to use new mutation structure
Hedgemon4 Mar 16, 2024
b54b2bb
Refactored local max to take a value for how many teams to mutate
Hedgemon4 Mar 16, 2024
f8f9ddb
Merged in mutation refactor and updated greedy local max
Hedgemon4 Mar 16, 2024
25f51cd
Updated run
Hedgemon4 Mar 16, 2024
3d866c7
Fix run settings
justino599 Mar 18, 2024
d1f3fd0
update simcache
justino599 Mar 25, 2024
1e8025e
Merge branch '398-benchmark-new-mutations' of github.com:Teamable-Ana…
justino599 Mar 25, 2024
ed709bf
Add missing parentheses
justino599 Mar 25, 2024
f6af4b7
Turn off default graph generation
justino599 Mar 25, 2024
dff34c0
Try more reasonable settings
justino599 Mar 25, 2024
9e308d4
Reduce parameters
justino599 Mar 26, 2024
7589d21
updated sim cache
justino599 Mar 26, 2024
c54e1e6
Merged main into branch
Hedgemon4 Mar 31, 2024
b28f469
Updated runs with mutation refactor
Hedgemon4 Mar 31, 2024
9da0483
Merge branch '398-benchmark-new-mutations' of https://github.com/Team…
justino599 Apr 1, 2024
716a780
Uncommented code
justino599 Apr 1, 2024
dc0d0d2
Reverted hacky change
justino599 Apr 1, 2024
6ca6b6a
Remove unnecessary function
justino599 Apr 1, 2024
fd49603
Merge branch 'main' of https://github.com/Teamable-Analytics/algorith…
justino599 Apr 1, 2024
397c186
Merge branch '398-benchmark-new-mutations' of https://github.com/Team…
justino599 Apr 1, 2024
4fa6ab1
Add run for team size mutations
justino599 Apr 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
url = https://github.com/Teamable-Analytics/algorithms-simulation-cache.git
[submodule "api/ai/external_algorithms/group_matcher_algorithm/group-matcher"]
path = api/ai/external_algorithms/group_matcher_algorithm/group-matcher
url = git@github.com:ketphan02/group-matcher.git
url = https://github.com/ketphan02/group-matcher.git
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ class TeamSizeLowDisruptionMutation(Mutation):
This minimizes the change in teams and hopefully won't tear apart teams that are doing well.
"""

def __init__(self, num_teams: int = 2, *args, **kwargs):
def __init__(self, number_of_teams: int = 2, *args, **kwargs):
super().__init__(*args, **kwargs)
self.num_teams = num_teams
self.num_teams = number_of_teams

def mutate_one(
self,
Expand Down
71 changes: 62 additions & 9 deletions benchmarking/data/simulated_data/realistic_class/providers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import itertools
from typing import List

import numpy as np
Expand All @@ -11,7 +12,12 @@
)
from api.dataclasses.project import Project, ProjectRequirement
from api.dataclasses.student import Student
from benchmarking.data.interfaces import StudentProvider
from api.dataclasses.team import TeamShell
from benchmarking.data.interfaces import StudentProvider, InitialTeamsProvider
from benchmarking.data.simulated_data.mock_initial_teams_provider import (
MockInitialTeamsProvider,
MockInitialTeamsProviderSettings,
)
from benchmarking.data.simulated_data.mock_student_provider import (
MockStudentProvider,
MockStudentProviderSettings,
Expand Down Expand Up @@ -92,16 +98,40 @@ def get(self, seed: int = None) -> List[Student]:
(4, 0.05),
],
GITHUB_EXPERIENCE: [
(GithubExperience.Beginner, 0.2),
(GithubExperience.Intermediate, 0.7),
(GithubExperience.Advanced, 0.1),
(
GithubExperience.Beginner,
0.2,
),
(
GithubExperience.Intermediate,
0.7,
),
(
GithubExperience.Advanced,
0.1,
),
],
WORK_EXPERIENCE: [
(WorkExperience.No_Experience, 0.4),
(WorkExperience.One_Semester, 0.05),
(WorkExperience.Two_Semesters, 0.2),
(WorkExperience.Three_Semesters, 0.3),
(WorkExperience.More_Than_Three_Semesters, 0.05),
(
WorkExperience.No_Experience,
0.4,
),
(
WorkExperience.One_Semester,
0.05,
),
(
WorkExperience.Two_Semesters,
0.2,
),
(
WorkExperience.Three_Semesters,
0.3,
),
(
WorkExperience.More_Than_Three_Semesters,
0.05,
),
],
},
)
Expand Down Expand Up @@ -132,6 +162,29 @@ def get(self, seed: int = None) -> List[Student]:
return [students[_] for _ in order]


class RealisticMockInitialTeamsProvider(InitialTeamsProvider):
def __init__(self, num_teams: int):
self.num_teams = num_teams

def get(self) -> List[TeamShell]:
projects = []
project_cycler = itertools.cycle(get_realistic_projects())
for i in range(self.num_teams):
next_project = next(project_cycler)
projects.append(
Project(
_id=i,
name=next_project.name + " " + str(i),
requirements=next_project.requirements,
)
)
return MockInitialTeamsProvider(
settings=MockInitialTeamsProviderSettings(
projects=projects,
)
).get()


def get_realistic_projects() -> List[Project]:
"""
A list of five projects with realistic requirements.
Expand Down
Empty file.
208 changes: 208 additions & 0 deletions benchmarking/runs/mutations/mutation_benchmarking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
from typing import Dict

import typer

from api.ai.interfaces.algorithm_config import PriorityAlgorithmConfig
from api.ai.priority_algorithm.mutations.greedy_local_max import GreedyLocalMaxMutation
from api.ai.priority_algorithm.mutations.local_max import LocalMaxMutation
from api.ai.priority_algorithm.mutations.local_max_random import LocalMaxRandomMutation
from api.ai.priority_algorithm.mutations.random_slice import RandomSliceMutation
from api.ai.priority_algorithm.mutations.random_swap import RandomSwapMutation
from api.ai.priority_algorithm.mutations.robinhood import RobinhoodMutation
from api.ai.priority_algorithm.mutations.robinhood_holistic import (
RobinhoodHolisticMutation,
)
from api.dataclasses.enums import ScenarioAttribute, Gender, Race, AlgorithmType
from benchmarking.data.simulated_data.realistic_class.providers import (
RealisticMockInitialTeamsProvider,
RealisticMockStudentProvider,
)
from benchmarking.evaluations.graphing.graph_metadata import GraphData, GraphAxisRange
from benchmarking.evaluations.graphing.line_graph import line_graph
from benchmarking.evaluations.graphing.line_graph_metadata import LineGraphMetadata
from benchmarking.evaluations.metrics.average_project_requirements_coverage import (
AverageProjectRequirementsCoverage,
)
from benchmarking.evaluations.metrics.average_solo_status import AverageSoloStatus
from benchmarking.evaluations.metrics.cosine_similarity import AverageCosineDifference
from benchmarking.evaluations.metrics.priority_satisfaction import PrioritySatisfaction
from benchmarking.evaluations.scenarios.satisfy_project_requirements_and_diversify_female_min_of_2_and_diversify_african_min_of_2 import (
SatisfyProjectRequirementsAndDiversifyFemaleMinOf2AndDiversifyAfricanMinOf2,
)
from benchmarking.runs.interfaces import Run
from benchmarking.simulation.goal_to_priority import goals_to_priorities
from benchmarking.simulation.insight import Insight
from benchmarking.simulation.simulation_set import SimulationSetArtifact, SimulationSet
from benchmarking.simulation.simulation_settings import SimulationSettings


class MutationBenchmarking(Run):
def start(self, num_trials: int = 100, generate_graphs: bool = False):
class_sizes = [40, 100, 240, 500, 1000]
team_size = 5

scenario = (
SatisfyProjectRequirementsAndDiversifyFemaleMinOf2AndDiversifyAfricanMinOf2()
)

metrics = {
"PrioritySatisfaction": PrioritySatisfaction(
goals_to_priorities(scenario.goals),
False,
),
"AverageProjectRequirementsCoverage": AverageProjectRequirementsCoverage(),
"AverageCosineDifferenceGender": AverageCosineDifference(
attribute_filter=[ScenarioAttribute.GENDER.value],
name="AverageCosineDifferenceGender",
),
"AverageCosineDifferenceRace": AverageCosineDifference(
attribute_filter=[ScenarioAttribute.RACE.value],
name="AverageCosineDifferenceRace",
),
"AverageSoloStatus": AverageSoloStatus(
minority_groups_map={
ScenarioAttribute.GENDER.value: [Gender.FEMALE.value],
ScenarioAttribute.RACE.value: [Race.African.value],
},
),
Insight.KEY_RUNTIMES: "runtime",
}

max_keep = 30
max_spread = 100
max_iterate = 250
max_time = 1_000_000
mutation_sets = {
"mutate_random": [RandomSwapMutation(max_spread)],
"mutate_local_max": [
LocalMaxMutation(num_mutations=1),
RandomSwapMutation(num_mutations=max_spread - 1),
],
"mutate_local_max_random": [
LocalMaxRandomMutation(num_mutations=5),
RandomSwapMutation(num_mutations=(max_spread - 5)),
],
"mutate_random_slice": [RandomSliceMutation(max_spread)],
"mutate_half_random_slice": [
RandomSliceMutation(num_mutations=(max_spread // 2)),
RandomSwapMutation(num_mutations=(max_spread // 2)),
],
"mutate_greedy_local_max_n_2": [
GreedyLocalMaxMutation(number_of_teams=2, num_mutations=max_spread)
],
"mutate_greedy_local_max_n_4": [
GreedyLocalMaxMutation(number_of_teams=4, num_mutations=max_spread)
],
"mutate_greedy_local_max_n_8": [
GreedyLocalMaxMutation(number_of_teams=8, num_mutations=max_spread)
],
"mutate_greedy_local_max_with_random_swap": [
GreedyLocalMaxMutation(num_mutations=(max_spread // 2)),
RandomSwapMutation(num_mutations=(max_spread // 2)),
],
"mutate_greedy_local_max_with_random_slice_n_2": [
GreedyLocalMaxMutation(num_mutations=(max_spread // 2)),
RandomSliceMutation(num_mutations=(max_spread // 2)),
],
"mutate_greedy_local_max_with_random_slice_n_4": [
GreedyLocalMaxMutation(
number_of_teams=4, num_mutations=(max_spread // 2)
),
RandomSliceMutation(max_spread // 2),
],
"mutate_greedy_local_max_with_random_slice_n_8": [
GreedyLocalMaxMutation(
number_of_teams=8, num_mutations=(max_spread // 2)
),
(RandomSliceMutation(), max_spread // 2),
],
"mutate_robinhood": [RobinhoodMutation(max_spread)],
"mutate_robinhood_half_random_swap": [
RobinhoodMutation(max_spread // 2),
RandomSwapMutation(max_spread // 2),
],
"mutate_robinhood_holistic": [RobinhoodHolisticMutation(max_spread)],
"mutate_robinhood_holistic_half_random_swap": [
RobinhoodHolisticMutation(max_spread // 2),
RandomSwapMutation(max_spread // 2),
],
}

artifacts: Dict[int, Dict[str, SimulationSetArtifact]] = {}

for class_size in class_sizes:
if class_size not in artifacts:
artifacts[class_size] = {}
for mutation_name, mutations in mutation_sets.items():
artifacts[class_size][mutation_name] = SimulationSet(
settings=SimulationSettings(
scenario=scenario,
student_provider=RealisticMockStudentProvider(class_size),
cache_key=f"mutations/mutation_benchmarking/{mutation_name}/class_size_{class_size}/",
initial_teams_provider=RealisticMockInitialTeamsProvider(
class_size // team_size
),
),
algorithm_set={
AlgorithmType.PRIORITY: [
PriorityAlgorithmConfig(
MAX_KEEP=max_keep,
MAX_SPREAD=max_spread,
MAX_ITERATE=max_iterate,
MAX_TIME=max_time,
MUTATIONS=mutations,
),
]
},
).run(num_runs=num_trials)

if generate_graphs:
for metric_name, metric in metrics.items():
data = {}
for class_size, _ in artifacts.items():
if class_size not in data:
data[class_size] = {}
for mutation_name, artifact in _.items():
insight_output_set = Insight.get_output_set(
artifact=artifact,
metrics=[
metric
if metric != "runtime"
else AverageProjectRequirementsCoverage()
],
)
avg_metric = list(
Insight.average_metric(
insight_output_set=insight_output_set,
metric_name=metric_name
if metric_name == Insight.KEY_RUNTIMES
else metric.name,
).values()
)[0]
data[class_size][mutation_name] = avg_metric

graph_data = [
GraphData(
x_data=class_sizes,
y_data=[
data[class_size][mutation_name]
for class_size in class_sizes
],
name=mutation_name,
)
for mutation_name in mutation_sets.keys()
]

line_graph(
LineGraphMetadata(
x_label="Class size",
y_label=metric_name,
title=f"Class Size vs. {metric_name}",
data=graph_data,
y_lim=GraphAxisRange(0, 1),
)
)


if __name__ == "__main__":
typer.run(MutationBenchmarking().start)
Loading