Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: assign less than min threshold students to previous center #51

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
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
96 changes: 53 additions & 43 deletions school_center.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,52 @@ def is_allocated(scode1: str, scode2: str) -> bool:
return allocations.get(scode1, {}).get(scode2) is not None


def allocate_to_centers(centers: List[Dict[str, str]], school: Dict[str, str], to_allot: int, remaining_cap: Dict[str, int], stretch: bool=False):
allocated_centers = {}
per_center = calc_per_center(to_allot)

for center in centers:
school_code = school['scode']
center_code = center['cscode']
writer.writerow([
school_code,
school['count'],
school['name-address'],
school['lat'],
school['long'],
center_code,
center['name'],
center['address'],
center['capacity'],
center['distance_km']
])

if is_allocated(center_code, school_code):
continue

centers_cap_left = remaining_cap[center_code]

if stretch:
stretched_capacity = math.floor(int(center['capacity']) * STRETCH_CAPACITY_FACTOR + centers_cap_left)
next_allot = min(to_allot, max(stretched_capacity, MIN_STUDENT_IN_CENTER))
centers_cap_left = stretched_capacity
else:
next_allot = min(to_allot, per_center, max(centers_cap_left, MIN_STUDENT_IN_CENTER))

if to_allot > 0 and next_allot > 0 and centers_cap_left >= next_allot:
if next_allot < MIN_STUDENT_IN_CENTER and len(allocated_centers) > 0:
# get the first center code
allocate_center_code = centers[0]['cscode']
Comment on lines +214 to +216
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first center may not always be the best choice to allocate remaining students.

  • it may not have required capacity as we have used center_cap_left for current_center.
  • in my opinion assigning them to last allotted center might be preferable for registration number distribution. eg: school with 408 students - Case 1: Center A: registration no 1 - 200; Center B reg no 201 - 408. Case 2: Center A: registration no. 1 - 208; Center B reg no 209 - 408. Case 1 would be preferred as starting registration number for all centers is a easy number

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sapradhan Thank you for your feedback. I agree with your point that the distributed number might not be cleaner.

I have one question, so when assigning the registration number, we will not care about the offset as below:

  • Center A: reg number from 1 to 200
  • Center B: reg number from 201 to 400
  • Remaining reg number ( 401 to 408 )

Let me know and I will make changes to assign to the last center.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handling issue 1 should be good enough for now.

I realize now that issue 2 may not be that important.
Registration numbers distribution are not currently handled by this script. I only brought up registration numbers looking at notice published by NEB, so may be part of a future enhancement. Also centers can be ordered differently so as to make the registration no. distribution cleaner. eg - if we allot Center A - 208, Center B - 200, it does not mean we have to put first 208 students to Center A. We can distribute Center B 1 - 200, Center A 201 - 408. So I take back my previous opinion that assigning students to last allotted center is preferred.

else:
allocate_center_code = center_code
allocated_centers[allocate_center_code] = center

allocate(school_code, allocate_center_code, next_allot)
to_allot -= next_allot
remaining_cap[center_code] -= next_allot

return to_allot, allocated_centers

parser = argparse.ArgumentParser(
prog='center randomizer',
description='Assigns centers to exam centers to students')
Expand Down Expand Up @@ -234,49 +280,13 @@ def is_allocated(scode1: str, scode2: str) -> bool:
centers_for_school = centers_within_distance(
s, centers, PREF_DISTANCE_THRESHOLD)
to_allot = int(s['count'])
per_center = calc_per_center(to_allot)

allocated_centers = {}

# per_center = math.ceil(to_allot / min(calc_num_centers(to_allot), len(centers_for_school)))
for c in centers_for_school:
writer.writerow([s['scode'],
s['count'],
s['name-address'],
s['lat'],
s['long'],
c['cscode'],
c['name'],
c['address'],
c['capacity'],
c['distance_km']])
if is_allocated(c['cscode'], s['scode']):
continue
next_allot = min(to_allot, per_center, max(
centers_remaining_cap[c['cscode']], MIN_STUDENT_IN_CENTER))
if to_allot > 0 and next_allot > 0 and centers_remaining_cap[c['cscode']] >= next_allot:
allocated_centers[c['cscode']] = c
allocate(s['scode'], c['cscode'], next_allot)
# allocation.writerow([s['scode'], s['name-address'], c['cscode'], c['name'], c['address'], next_allot, c['distance_km']])
to_allot -= next_allot
centers_remaining_cap[c['cscode']] -= next_allot

if to_allot > 0: # try again with relaxed constraints and more capacity at centers
expanded_centers = centers_within_distance(
s, centers, ABS_DISTANCE_THRESHOLD)
for c in expanded_centers:
if is_allocated(c['cscode'], s['scode']):
continue
stretched_capacity = math.floor(
int(c['capacity']) * STRETCH_CAPACITY_FACTOR + centers_remaining_cap[c['cscode']])
next_allot = min(to_allot, max(
stretched_capacity, MIN_STUDENT_IN_CENTER))
if to_allot > 0 and next_allot > 0 and stretched_capacity >= next_allot:
allocated_centers[c['cscode']] = c
allocate(s['scode'], c['cscode'], next_allot)
# allocation.writerow([s['scode'], s['name-address'], c['cscode'], c['name'], c['address'], next_allot, c['distance_km']])
to_allot -= next_allot
centers_remaining_cap[c['cscode']] -= next_allot

# per_center = math.ceil(to_allot / min(calc_num_centers(to_allot), len(centers_for_school)))
to_allot, allocated_centers = allocate_to_centers(centers_for_school, s, to_allot, centers_remaining_cap)

if to_allot > 0: # try again with relaxed constraints and more capacity at centers
expanded_centers = centers_within_distance(s, centers, ABS_DISTANCE_THRESHOLD)
to_allot, allocated_centers = allocate_to_centers(expanded_centers, s, to_allot, centers_remaining_cap, stretch=True)

for c in allocated_centers.values():
allocation_file.writerow([s['scode'],
Expand Down