Skip to content

Commit cd9ff04

Browse files
Fix same centre chosen every time (#37)
* Fix same centre chosen every time modified the "centers_within_distance" function to consider the preference cutoff (PREF_CUTOFF) even when no centers are within the absolute distance threshold. Additionally, ensuring that the closest center is not always chosen in such cases. * slightly re-organized the code --------- Co-authored-by: sumanashrestha <[email protected]>
1 parent 6e4746f commit cd9ff04

File tree

1 file changed

+24
-26
lines changed

1 file changed

+24
-26
lines changed

school_center.py

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ def haversine_distance(lat1, lon1, lat2, lon2):
4040
return distance
4141

4242

43-
def centers_within_distance(school: Dict[str, str], centers: Dict[str, str], distance_threshold: float) -> List[Dict[str, any]]:
43+
def centers_within_distance(school: Dict[str, str], centers: Dict[str, str], distance_threshold: float, relax_threshold: bool) -> List[Dict[str, any]]:
4444
"""
4545
Return List of centers that are within given distance from school.
46-
If there are no centers within given distance return one that is closest
46+
relax_threshold: If there are no centers within given distance return one that is closest
4747
Returned params :
4848
{'cscode', 'name', 'address', 'capacity', 'lat', 'long', 'distance_km'}
4949
@@ -60,33 +60,35 @@ def center_to_dict(c, distance):
6060
def sort_key(c):
6161
# intent: sort by preference score DESC then by distance_km ASC
6262
# leaky abstraction - sorted requires a single numeric value for each element
63-
return c['distance_km'] * random.uniform(1, 5) - get_pref(school['scode'], c['cscode'])*100
64-
63+
return c['distance_km'] * random.uniform(1, 5) - get_pref(school['scode'], c['cscode']) * 100
64+
6565
school_lat = school.get('lat')
6666
school_long = school.get('long')
6767
if len(school_lat) == 0 or len(school_long) == 0:
6868
return []
6969

70-
within_distance = []
71-
nearest_distance = None
72-
nearest_center = None
70+
qualifying_centers = []
71+
# nearest_distance = None
72+
# nearest_center = None
7373
for c in centers:
74+
if school['scode'] == c['cscode'] \
75+
or is_allocated(c['cscode'], s['scode']) \
76+
or get_pref(school['scode'], c['cscode']) <= PREF_CUTOFF:
77+
continue
7478
distance = haversine_distance(float(school_lat), float(
7579
school_long), float(c.get('lat')), float(c.get('long')))
76-
if school['scode'] == c['cscode']:
77-
continue
78-
if nearest_center is None or distance < nearest_distance:
79-
nearest_center = c
80-
nearest_distance = distance
81-
82-
if distance <= distance_threshold and get_pref(school['scode'], c['cscode']) > PREF_CUTOFF:
83-
within_distance.append(center_to_dict(c, distance))
80+
# if nearest_center is None or distance < nearest_distance:
81+
# nearest_center = c
82+
# nearest_distance = distance
83+
qualifying_centers.append(center_to_dict(c, distance))
8484

85+
within_distance = [ c for c in qualifying_centers if c['distance_km'] <= distance_threshold ]
8586
if len(within_distance) > 0:
86-
return sorted(within_distance, key=sort_key)
87-
else: # if there are no centers within given threshold, return one that is closest
88-
return [center_to_dict(nearest_center, nearest_distance)]
89-
87+
return sorted(within_distance, key=sort_key)
88+
elif relax_threshold: # if there are no centers within given threshold, return one that is closest
89+
return sorted(qualifying_centers, key=sort_key)
90+
else:
91+
return []
9092

9193
def read_tsv(file_path: str) -> List[Dict[str, str]]:
9294
"""
@@ -271,7 +273,7 @@ def get_output_filename():
271273

272274
for s in schools:
273275
centers_for_school = centers_within_distance(
274-
s, centers, PREF_DISTANCE_THRESHOLD)
276+
s, centers, PREF_DISTANCE_THRESHOLD, False)
275277
to_allot = int(s['count'])
276278
per_center = calc_per_center(to_allot)
277279

@@ -289,8 +291,6 @@ def get_output_filename():
289291
c['address'],
290292
c['capacity'],
291293
c['distance_km']])
292-
if is_allocated(c['cscode'], s['scode']):
293-
continue
294294
next_allot = min(to_allot, per_center, max(
295295
centers_remaining_cap[c['cscode']], MIN_STUDENT_IN_CENTER))
296296
if to_allot > 0 and next_allot > 0 and centers_remaining_cap[c['cscode']] >= next_allot:
@@ -302,10 +302,8 @@ def get_output_filename():
302302

303303
if to_allot > 0: # try again with relaxed constraints and more capacity at centers
304304
expanded_centers = centers_within_distance(
305-
s, centers, ABS_DISTANCE_THRESHOLD)
305+
s, centers, ABS_DISTANCE_THRESHOLD, True)
306306
for c in expanded_centers:
307-
if is_allocated(c['cscode'], s['scode']):
308-
continue
309307
stretched_capacity = math.floor(
310308
int(c['capacity']) * STRETCH_CAPACITY_FACTOR + centers_remaining_cap[c['cscode']])
311309
next_allot = min(to_allot, max(
@@ -330,7 +328,7 @@ def get_output_filename():
330328

331329
if to_allot > 0:
332330
remaining += to_allot
333-
logger.warn(
331+
logger.warning(
334332
f"{to_allot}/{s['count']} left for {s['scode']} {s['name-address']} centers: {len(centers_for_school)}")
335333

336334
logger.info("Remaining capacity at each center (remaining_capacity cscode):")

0 commit comments

Comments
 (0)