Skip to content

Commit

Permalink
Merge pull request #268 from appKom/267-søkere-kan-bli-tildelt-overla…
Browse files Browse the repository at this point in the history
…ppende-intervjuer

Søkere kan ikke lenger bli tildelt overlappende intervjuer
  • Loading branch information
jorgengaldal authored Aug 15, 2024
2 parents dd515cd + 8f8d568 commit 7464579
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 11 deletions.
21 changes: 11 additions & 10 deletions algorithm/src/mip_matching/match_meetings.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
from mip_matching.Applicant import Applicant
import mip

from itertools import combinations


class MeetingMatch(TypedDict):
"""Type definition of a meeting match object"""
solver_status: mip.OptimizationStatus
Expand Down Expand Up @@ -41,19 +44,17 @@ def match_meetings(applicants: set[Applicant], committees: set[Committee]) -> Me
# type: ignore
for interval in applicant.get_fitting_committee_slots(committee)) <= 1

# Legger inn begrensninger for at en person kun kan ha ett intervju på hvert tidspunkt
# Legger inn begrensninger for at en søker ikke kan ha overlappende intervjutider
for applicant in applicants:
potential_intervals = set()
potential_interviews: set[tuple[Committee, TimeInterval]] = set()
for applicant_candidate, committee, interval in m:
if applicant == applicant_candidate:
potential_intervals.add(interval)

for interval in potential_intervals:
potential_interviews.add((committee, interval))

model += mip.xsum(m[(applicant, committee, interval)]
for committee in applicant.get_committees()
# type: ignore
if (applicant, committee, interval) in m) <= 1
for interview_a, interview_b in combinations(potential_interviews, r=2):
if interview_a[1].intersects(interview_b[1]):
model += m[(applicant, *interview_a)] + \
m[(applicant, *interview_b)] <= 1

# Setter mål til å være maksimering av antall møter
model.objective = mip.maximize(mip.xsum(m.values()))
Expand All @@ -80,4 +81,4 @@ def match_meetings(applicants: set[Applicant], committees: set[Committee]) -> Me
"matchings": matchings,
}

return match_object
return match_object
16 changes: 15 additions & 1 deletion algorithm/tests/mip_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations
from datetime import datetime, timedelta, date, time
# import ..algorithm.mip_matching.core.Applicant.py as applicant

from mip_matching.TimeInterval import TimeInterval
from mip_matching.Committee import Committee
Expand All @@ -12,6 +11,7 @@

import unittest
import random
from itertools import combinations


def print_matchings(committees: list[Committee],
Expand Down Expand Up @@ -59,6 +59,20 @@ def check_constraints(self, matchings: list[tuple[Applicant, Committee, TimeInte
self.assertGreaterEqual(committee.get_capacity(interval), load,
f"Constraint \"Number of interviews per slot per committee cannot exceed capacity\" failed for Committee {committee} and interval {interval}")

# Overlapping interviews per applicant
interviews_per_applicant: dict[Applicant,
set[tuple[Committee, TimeInterval]]] = {}
for applicant, committee, interval in matchings:
if applicant not in interviews_per_applicant:
interviews_per_applicant[applicant] = set()

interviews_per_applicant[applicant].add((committee, interval))

for applicant, interviews in interviews_per_applicant.items():
for interview_a, interview_b in combinations(interviews, r=2):
self.assertFalse(interview_a[1].intersects(interview_b[1]), f"Constraint \"Applicant cannot have time-overlapping interviews\" failed for {
applicant}'s interviews with {interview_a[0]} ({interview_a[1]}) and {interview_b[0]} ({interview_b[1]})")

def test_fixed_small(self):
"""Small, fixed test with all capacities set to one"""

Expand Down

0 comments on commit 7464579

Please sign in to comment.