I'm using the employee scheduling quick start on optapy's github page. Only difference is I modified the Employee class to have the employee's home address included.
@optapy.problem_fact class Employee: name: str skill_set: list[str] address: str
def __init__(self, name: str = None, skill_set: list[str] = None, address: str = None):
self.name = name
self.skill_set = skill_set
self.address = address #new
def __str__(self):
return f'Employee(name={self.name})'
def to_dict(self):
return {
'name': self.name,
'skill_set': self.skill_set,
'address': self.address
}`
For example Instead of LOCATIONS = ["Ambulatory care", "Critical care", "Pediatric care"]
as locations, each shift has a certain patient address as a location which caregivers can visit. From the original repository, the employees are matched to shifts based on their job expertise and availability as well as other constraints, but I would like to add the additional constraint of employees being matched to caregivers by the shortest distance to the patient as well.
I was thinking of using google maps API to retrieve the shortest possible route between two addresses:
import googlemaps
api_key = 'API_KEY'
def find_distance_and_duration_of_route(origin, destination, mode='driving'):
gmaps = googlemaps.Client(api_key)
route = gmaps.directions(origin, destination, mode=mode)
return route[0]['legs'][0]['distance']['text']
I am looking for a way to incorporate this function into the existing constraints in optapy, so that I can match employees to shifts based on the shortest distance, or maybe a completely new solution by your suggestion.
I tried creating a constraint at constraints.py such as:
def closest_employee_to_shift(constraint_factory: ConstraintFactory):
return constraint_factory.for_each(Shift).join(Employee,
Joiners.equal(lambda shift: shift.location,
lambda employee: employee.address)
) \
.reward('Employee is too far from the shift', HardSoftScore.ONE_SOFT,
lambda shift, employee: find_distance_and_duration_of_route(shift, employee))
but unfortunately it didn't work.
Any suggestions on how to implement this would be greatly appreciated. Thank you.