Skip to content

Commit 195651c

Browse files
authored
Move algorithm (#365)
* refactor: removed mip-matching from this repo * docs: update readme * config: delete algorithm workflows
1 parent b4093bb commit 195651c

22 files changed

+90
-1222
lines changed

.github/workflows/algorithm.yml

Lines changed: 0 additions & 33 deletions
This file was deleted.

.github/workflows/match_interviews.yml

Lines changed: 0 additions & 26 deletions
This file was deleted.

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,20 @@ yarn dev
5151
```
5252

5353
Open <http://localhost:3000> with your browser to see the result.
54+
55+
### Running the matching algorithm
56+
57+
Setup Python virtual environment:
58+
59+
```bash
60+
cd algorithm
61+
python -m venv ".venv"
62+
.\.venv\Scripts\activate
63+
pip install -r requirements.txt
64+
```
65+
66+
Then, run the file [fetch_applicants_and_committees.py](algorithm/fetch_applicants_and_committees.py):
67+
68+
```bash
69+
python fetch_applicants_and_committees.py
70+
```
File renamed without changes.

algorithm/README.md

Lines changed: 0 additions & 16 deletions
This file was deleted.

algorithm/bridge/fetch_applicants_and_committees.py renamed to algorithm/fetch_applicants_and_committees.py

Lines changed: 73 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -10,112 +10,125 @@
1010
from mip_matching.Applicant import Applicant
1111
from mip_matching.match_meetings import match_meetings, MeetingMatch
1212

13+
1314
def main():
15+
print("Starting matching")
1416
periods = fetch_periods()
15-
17+
1618
for period in periods:
1719
periodId = str(period["_id"])
18-
application_end = datetime.fromisoformat(period["applicationPeriod"]["end"].replace("Z", "+00:00"))
19-
20+
application_end = datetime.fromisoformat(
21+
period["applicationPeriod"]["end"].replace("Z", "+00:00"))
22+
2023
now = datetime.now(timezone.utc)
2124

22-
#or period["name"] == "Juli Opptak"
23-
if (application_end < now and period["hasSentInterviewTimes"] == False):
25+
if (application_end < now and period["hasSentInterviewTimes"] == False):
2426
applicants = fetch_applicants(periodId)
2527
committee_times = fetch_committee_times(periodId)
26-
28+
2729
committee_objects = create_committee_objects(committee_times)
28-
29-
all_committees = {committee.name: committee for committee in committee_objects}
30-
31-
applicant_objects = create_applicant_objects(applicants, all_committees)
32-
33-
print(applicant_objects)
34-
print(committee_objects)
35-
30+
31+
all_committees = {
32+
committee.name: committee for committee in committee_objects}
33+
34+
applicant_objects = create_applicant_objects(
35+
applicants, all_committees)
36+
3637
match_result = match_meetings(applicant_objects, committee_objects)
37-
38+
print(
39+
f"Matching finished with status {match_result["solver_status"]}")
40+
print(
41+
f"Matched {match_result["matched_meetings"]}/{match_result["total_wanted_meetings"]} ({match_result["matched_meetings"]/match_result["total_wanted_meetings"]:.2f}) meetings")
42+
3843
send_to_db(match_result, applicants, periodId)
44+
print("Meetings sent to database")
3945
return match_result
40-
46+
47+
4148
def send_to_db(match_result: MeetingMatch, applicants: List[dict], periodId):
4249
load_dotenv()
43-
formatted_results = format_match_results(match_result, applicants, periodId)
50+
formatted_results = format_match_results(
51+
match_result, applicants, periodId)
4452
print("Sending to db")
4553
print(formatted_results)
46-
54+
4755
mongo_uri = os.getenv("MONGODB_URI")
4856
db_name = os.getenv("DB_NAME")
4957
client = MongoClient(mongo_uri, tlsCAFile=certifi.where())
50-
51-
db = client[db_name] # type: ignore
52-
58+
59+
db = client[db_name] # type: ignore
60+
5361
collection = db["interviews"]
54-
62+
5563
collection.insert_many(formatted_results)
56-
64+
5765
client.close()
5866

67+
5968
def connect_to_db(collection_name):
6069
load_dotenv()
61-
70+
6271
mongo_uri = os.getenv("MONGODB_URI")
6372
db_name = os.getenv("DB_NAME")
6473

6574
client = MongoClient(mongo_uri, tlsCAFile=certifi.where())
66-
67-
db = client[db_name] # type: ignore
68-
75+
76+
db = client[db_name] # type: ignore
77+
6978
collection = db[collection_name]
70-
79+
7180
return collection, client
7281

82+
7383
def fetch_periods():
7484
collection, client = connect_to_db("periods")
75-
85+
7686
periods = list(collection.find())
77-
87+
7888
client.close()
79-
89+
8090
return periods
8191

92+
8293
def fetch_applicants(periodId):
8394
collection, client = connect_to_db("applications")
84-
95+
8596
applicants = list(collection.find({"periodId": periodId}))
86-
97+
8798
client.close()
88-
99+
89100
return applicants
90101

102+
91103
def fetch_committee_times(periodId):
92104
collection, client = connect_to_db("committees")
93-
105+
94106
committee_times = list(collection.find({"periodId": periodId}))
95-
107+
96108
client.close()
97-
109+
98110
return committee_times
99111

112+
100113
def format_match_results(match_results: MeetingMatch, applicants: List[dict], periodId) -> List[Dict]:
101114
transformed_results = {}
102-
115+
103116
for result in match_results['matchings']:
104117
applicant_id = str(result[0])
105-
118+
106119
if applicant_id not in transformed_results:
107120
transformed_results[applicant_id] = {
108121
"periodId": periodId,
109122
"applicantId": applicant_id,
110123
"interviews": []
111124
}
112-
125+
113126
committee = result[1]
114127
time_interval = result[2]
115128
start = time_interval.start.isoformat()
116129
end = time_interval.end.isoformat()
117130
room = result[3]
118-
131+
119132
transformed_results[applicant_id]["interviews"].append({
120133
"start": start,
121134
"end": end,
@@ -125,37 +138,46 @@ def format_match_results(match_results: MeetingMatch, applicants: List[dict], pe
125138

126139
return list(transformed_results.values())
127140

141+
128142
def create_applicant_objects(applicants_data: List[dict], all_committees: dict[str, Committee]) -> set[Applicant]:
129143
applicants = set()
130144
for data in applicants_data:
131145
applicant = Applicant(name=str(data['_id']))
132-
146+
133147
optional_committee_names = data.get('optionalCommittees', [])
134-
optional_committees = {all_committees[name] for name in optional_committee_names if name in all_committees}
148+
optional_committees = {
149+
all_committees[name] for name in optional_committee_names if name in all_committees}
135150
applicant.add_committees(optional_committees)
136-
151+
137152
preferences = data.get('preferences', {})
138-
preference_committees = {all_committees[committee_name] for committee_name in preferences.values() if committee_name in all_committees}
153+
preference_committees = {all_committees[committee_name] for committee_name in preferences.values(
154+
) if committee_name in all_committees}
139155
applicant.add_committees(preference_committees)
140156

141157
for interval_data in data['selectedTimes']:
142158
interval = TimeInterval(
143-
start=datetime.fromisoformat(interval_data['start'].replace("Z", "+00:00")),
144-
end=datetime.fromisoformat(interval_data['end'].replace("Z", "+00:00"))
159+
start=datetime.fromisoformat(
160+
interval_data['start'].replace("Z", "+00:00")),
161+
end=datetime.fromisoformat(
162+
interval_data['end'].replace("Z", "+00:00"))
145163
)
146164
applicant.add_interval(interval)
147-
165+
148166
applicants.add(applicant)
149167
return applicants
150168

169+
151170
def create_committee_objects(committee_data: List[dict]) -> set[Committee]:
152171
committees = set()
153172
for data in committee_data:
154-
committee = Committee(name=data['committee'], interview_length=timedelta(minutes=int(data["timeslot"])))
173+
committee = Committee(name=data['committee'], interview_length=timedelta(
174+
minutes=int(data["timeslot"])))
155175
for interval_data in data['availabletimes']:
156176
interval = TimeInterval(
157-
start=datetime.fromisoformat(interval_data['start'].replace("Z", "+00:00")),
158-
end=datetime.fromisoformat(interval_data['end'].replace("Z", "+00:00"))
177+
start=datetime.fromisoformat(
178+
interval_data['start'].replace("Z", "+00:00")),
179+
end=datetime.fromisoformat(
180+
interval_data['end'].replace("Z", "+00:00"))
159181
)
160182
room = interval_data["room"]
161183
committee.add_interview_slot(interval, room)

algorithm/pyproject.toml

Lines changed: 0 additions & 20 deletions
This file was deleted.

algorithm/requirements.txt

-200 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)