Interval tree with added dimension of subset matching?

前端 未结 3 876
孤城傲影
孤城傲影 2021-01-01 14:54

This is an algorithmic question about a somewhat complex problem. The foundation is this:

A scheduling system based on available slots and reserved slot

3条回答
  •  清歌不尽
    2021-01-01 15:17

    Here's a solution, I'll include all the code below.

    1. Create a table of slots, and a table of reservations

    example tables

    2. Create a matrix of reservations x slots

    which is populated by true or false values based on whether that reservation-slot combination are possible

    example boolean combinations matrix

    3. Figure out the best mapping that allows for the most Reservation-Slot Combinations

    Note: my current solution scales poorly with very large arrays as it involves looping through all possible permutations of a list with size = number of slots. I've posted another question to see if anyone can find a better way of doing this. However, this solution is accurate and can be optimized

    Python Code Source

    Part 1

    from IPython.display import display
    import pandas as pd
    import datetime
    
    available_data = [
        ['SlotA', datetime.time(11, 0, 0), datetime.time(12, 30, 0), set(list('ABD'))],
        ['SlotB',datetime.time(12, 0, 0), datetime.time(13, 30, 0), set(list('C'))],
        ['SlotC',datetime.time(12, 0, 0), datetime.time(13, 30, 0), set(list('ABCD'))],
        ['SlotD',datetime.time(12, 0, 0), datetime.time(13, 30, 0), set(list('AD'))],
    ]
    
    reservation_data = [
        ['ReservationA', datetime.time(11, 15, 0), datetime.time(12, 15, 0), set(list('AD'))],
        ['ReservationB', datetime.time(11, 15, 0), datetime.time(12, 15, 0), set(list('A'))],
        ['ReservationC', datetime.time(12, 0, 0), datetime.time(12, 15, 0), set(list('C'))],
        ['ReservationD', datetime.time(12, 0, 0), datetime.time(12, 15, 0), set(list('C'))],
        ['ReservationE', datetime.time(12, 0, 0), datetime.time(12, 15, 0), set(list('D'))]
    ]
    
    reservations = pd.DataFrame(data=reservation_data, columns=['reservations', 'begin', 'end', 'tags']).set_index('reservations')
    slots = pd.DataFrame(data=available_data, columns=['slots', 'begin', 'end', 'tags']).set_index('slots')
    
    display(slots)
    display(reservations)
    

    Part 2

    def is_possible_combination(r):
        return (r['begin'] >= slots['begin']) & (r['end'] <= slots['end']) & (r['tags'] <= slots['tags'])
    
    solution_matrix = reservations.apply(is_possible_combination, axis=1).astype(int)
    display(solution_matrix)
    

    Part 3

    import numpy as np
    from itertools import permutations
    
    # add dummy columns to make the matrix square if it is not
    sqr_matrix = solution_matrix
    if sqr_matrix.shape[0] > sqr_matrix.shape[1]:
        # uhoh, there are more reservations than slots... this can't be good
        for i in range(sqr_matrix.shape[0] - sqr_matrix.shape[1]):
            sqr_matrix.loc[:,'FakeSlot' + str(i)] = [1] * sqr_matrix.shape[0]
    elif sqr_matrix.shape[0] < sqr_matrix.shape[1]:
        # there are more slots than customers, why doesn't anyone like us?
        for i in range(sqr_matrix.shape[0] - sqr_matrix.shape[1]):
            sqr_matrix.loc['FakeCustomer' + str(i)] = [1] * sqr_matrix.shape[1]
    
    # we only want the values now
    A = solution_matrix.values.astype(int)
    
    # make an identity matrix (the perfect map)
    imatrix = np.diag([1]*A.shape[0])
    
    # randomly swap columns on the identity matrix until they match. 
    n = A.shape[0]
    
    # this will hold the map that works the best
    best_map_so_far = np.zeros([1,1])
    
    for column_order in permutations(range(n)):
        # this is an identity matrix with the columns swapped according to the permutation
        imatrix = np.zeros(A.shape)
        for row, column in enumerate(column_order):
            imatrix[row,column] = 1
    
        # is this map better than the previous best?
        if sum(sum(imatrix * A)) > sum(sum(best_map_so_far)):
            best_map_so_far = imatrix
    
        # could it be? a perfect map??
        if sum(sum(imatrix * A)) == n:
            break
    
    if sum(sum(imatrix * A)) != n:
        print('a perfect map was not found')
    
    output = pd.DataFrame(A*imatrix, columns=solution_matrix.columns, index=solution_matrix.index, dtype=int)
    display(output)
    

提交回复
热议问题