SSP Logo

packages = ["numpy", "scipy", ] import js from js import document, FileReader from pyodide.ffi import create_proxy import asyncio from scipy.optimize import quadratic_assignment import numpy as np from math import ceil NUM_TABLES = 0 result_place = Element("outputDiv") number_of_predictions = 6 text = "" def read_complete(event): content = document.getElementById("temp"); for line in event.target.result.splitlines(): content.innerHTML += line + '
' text = content.innerHTML people = text.split('
') people.pop() ID_NAME = {} for i in range(len(people)): people[i] = people[i].split(", ") ID_NAME[i] = people[i][0] people[i] = [i, int(people[i][1]), int(people[i][2]) - 1] groups = [[0 for i in range(1)] for j in range(12)] for i in range(len(people)): groups[people[i][2]].append(people[i][0]) for i in range(len(groups)): del groups[i][0] for i in range(len(people)): for j in groups[people[i][2]]: if j != people[i][0]: people[i] = list(people[i]) people[i].append(j) for i in range(len(people)): del people[i][0] del people[i][1] NUM_ROAMERS = len(people) NUM_TABLES = int(Element("numberOfTables").value) #Create a distance matrix for the quadratic assignment problem table_distance_matrix = np.zeros((NUM_ROAMERS, NUM_ROAMERS)) #We can imagine table_distance_matrix as a collection of seats, each of which #has some connection weight with each other. #Seats at the same table should have weight 1. Seats at different tables should have weight zero. remaining_roamers = NUM_ROAMERS remaining_tables = NUM_TABLES startex = 0 for i in range(NUM_TABLES): people_per_table = ceil(remaining_roamers/remaining_tables) endex = people_per_table + startex remaining_tables -= 1 remaining_roamers -= people_per_table table_distance_matrix[startex:endex,startex:endex] = 1 startex += people_per_table #Before we make a familiarity matrix (explained below), we want two helper methods #First, we want a method that can increment directional weights of a matrix given a list. def update_familiarity(id, connection_ids, weight_increment): for person_id in connection_ids: familiarity_matrix[id, person_id] += weight_increment return True #Second, we want to initialize lists of genders. These lists will be passed into update_familiarity #to establish assumed familiarity between same genders. This can be a method or just a code block females = [] males = [] for i in range(len(people)): if(people[i][0] == 1): females.append(i) elif(people[i][0] == 0): males.append(i) #Now we want a familiarity matrix. Familiarity is where we take inputs like sex, previous seating, groups, etc. #The quadratic_assignment method minimizes the "fun," a metric found by adding together all the #familiarity*distances (not matrix multiplication, term-wise multiplication) familiarity_matrix = np.zeros((NUM_ROAMERS, NUM_ROAMERS)) for i in range(len(people)): #Make everyone familiar with their sex. This is arguably the most important determinator because #It is very easy for people to notice when tables are mismatched, especially compared to other metrics #We wouldn't to cause an uproar now would we :). That's why the weight of gender is 20 if(i in females): update_familiarity(i, females, 20) elif(i in males): update_familiarity(i, males, 20) #Make people familiar with people in their group. update_familiarity(i, people[i][1:],5) #Now we want to manage how many groups we want to create current_week = 1 for i in range(number_of_predictions): #Reset main diagonal to zero. This seems important for the optimization algorithm. #Main diagonal could be changed by "sitting at the same table" and "being the same sex" as yourself. for i in range(NUM_ROAMERS): familiarity_matrix[i,i] = 0 #Make the assignments. The algorithm is blackbox but know that 2opt is more accurate than the default #Basically, take in distance and flow (familiarity) matrices and minimizes the fun value (objective function) #fun is calculated by summing the term-wise multiplication of distance and flow res = quadratic_assignment(table_distance_matrix, familiarity_matrix, method = '2opt') res = res.col_ind #res is just a 1D array of all the people, we still need to bring back the structure of tables #Create a list of all the people at the table to update their familiarities (and print them out) #This table code should be familiar. We used the same algorithm to create the table_distance_matrix #which was where we first implemented the table concept to begin with. remaining_roamers = NUM_ROAMERS remaining_tables = NUM_TABLES #Note that table_array is a list, not an array. We need its size to be mutable table_list = [] index = 0 for i in range(NUM_TABLES): people_per_table = ceil(remaining_roamers/remaining_tables) remaining_roamers -= people_per_table remaining_tables -= 1 table_list.append([None]*people_per_table) for j in range(people_per_table): table_list[i][j] = res[index] index += 1 #DON'T DELETE OR OPEN OR LOOK OR READ OR COPY def ignore(): # what was here?!?!? return None #Now start printing Assignments # if current_week == 1: # ID_NAME[0] = "xx" + ID_NAME[0] result_place.element.innerHTML += "Week " + str(current_week) + " Assignments" + "
" current_table = 1 for table in table_list: result_place.element.innerHTML += "Table " + str(current_table) + ": " for person in table: result_place.element.innerHTML += ID_NAME[person] + ' ' result_place.element.innerHTML += "
" current_table += 1 #Now we update the familiarity matrix with last week's table assignments #Don't worry about "becoming familiar with yourself." #We're setting it back to zero at the top of the overarching loop! for table in table_list: for person in table_list: update_familiarity(person, table, 3) current_week += 1 result_place.element.innerHTML += "
" async def test(): fileList = document.getElementById('studentList').files file = 0 for f in fileList: file = f onload_event = create_proxy(read_complete) reader = FileReader.new() reader.onload = onload_event reader.readAsText(file)