Beispiel #1
0
def random_sample(G):
    """
    generates a random sampling, which is then returned
    as a bipartite graph, from the given graph
    the returned preference lists are symmetric
    :param G: bipartite graph
    :return: bipartite graph from a random sample
    """
    def order_by_master_list(l, master_list):
        return sorted(l, key=master_list.index)

    # prepare a master list
    master_list = list(h for h in G.B)
    random.shuffle(master_list)

    E = collections.defaultdict(
        list)  # to store the new sampled preference list
    for resident in G.A:
        pref_list = G.E[resident]
        E[resident] = order_by_master_list(pref_list[:], master_list)
        # for all the hospitals add the students to their preference list
        for hospital in pref_list:
            E[hospital].append(resident)

    # shuffle the preference list for the hospitals
    for hospital in G.B:
        random.shuffle(E[hospital])

    return graph.BipartiteGraph(G.A, G.B, E, G.capacities)
def blow_instance(G):
    """
    blow the bipartite graph G, by creating k copies
    for a vertex in G.B, where k is its capacity
    also correctly set the preference list for the
    vertices for the vertices in this blown up instance
    :param G: bipartite graph
    :return: blown up instance G'
    """
    copies, reverse_copies = blow_house_instances(G)
    # partition B now contains houses with copies of the instance
    B = set(h_copy for h in G.B for h_copy in copies[h])

    # all the houses and residents now have a capacity of 1
    capacities = dict((h, (0, 1)) for h in B)
    capacities.update(dict((r, (0, 1)) for r in G.A))

    # fix all the edges in the new graph
    E = collections.defaultdict(list)
    for r in G.A:
        for h_orig in G.E[r]:
            for h_copy in copies[h_orig]:
                E[r].append(h_copy)
                E[h_copy] = G.E[h_orig][:]

    return graph.BipartiteGraph(G.A, B, E, capacities), reverse_copies
Beispiel #3
0
def make_graph(student_preferences, course_preferences, course_capacities):
    cap = course_capacities
    cap.update(
        dict((student, (0, 1)) for student in student_preferences.keys()))
    E = copy.copy(student_preferences)
    E.update(course_preferences)
    return graph.BipartiteGraph(student_preferences.keys(),
                                course_preferences.keys(), E, cap)
Beispiel #4
0
def mahadian_k_model_generator_hospital_residents(n1, n2, k, cap):
    """
    create a graph with the partition R of size n1 and
    partition H of size n2 using the model as described in
    Marriage, Honesty, and Stability
    Immorlica, Nicole and Mahdian, Mohammad
    Sixteenth Annual ACM-SIAM Symposium on Discrete Algorithms
    :param n1: size of partition R
    :param n2: size of partition H
    :param k: length of preference list for the residents
    :param cap: capacity of the hospitals
    :return: bipartite graph with above properties
    """
    def order_by_master_list(l, master_list):
        return sorted(l, key=master_list.index)

    # create the sets R and H, r_1 ... r_n1, h_1 .. h_n2
    R = list('r{}'.format(i) for i in range(1, n1 + 1))
    H = list('h{}'.format(i) for i in range(1, n2 + 1))

    # prepare a master list
    master_list = list(r for r in R)
    random.shuffle(master_list)

    # setup the capacities for the vertices

    capacities = dict((r, (0, 1)) for r in R)

    for h in H:
        random_num_for_lowerQ = random.randint(0, cap)
        #random_num_for_lowerQ = random.randint(0, max_capacity)
        capacities[h] = (random_num_for_lowerQ, cap)

    # setup a probability distribution over the hospitals
    p = np.random.geometric(p=0.10, size=len(H))
    # normalize the distribution
    p = p / np.sum(p)  # p is a ndarray, so this operation is perfectly fine
    #print('n1 = {}, n2={}, k={}, p={}'.format(n1, n2, k, p))

    pref_lists_H, pref_lists_R = collections.defaultdict(list), {}
    for r in R:
        #min_val=random.randint((int)((3*len(H))/4), len(H))
        # sample women according to the probability distribution and without replacement
        pref_lists_R[r] = list(
            np.random.choice(H, size=min(len(H), k), replace=False, p=p))
        # add these man to the preference list for the corresponding women
        for h in pref_lists_R[r]:
            pref_lists_H[h].append(r)

    for h in H:
        pref_lists_H[h] = order_by_master_list(pref_lists_H[h], master_list)
        # random.shuffle(pref_lists_H[h])
    # create a dict with the preference lists for residents and hospitals
    E = pref_lists_R
    E.update(pref_lists_H)
    # only keep those hospitals which are in some resident's preference list
    H_ = set(h for h in H if h in E)
    return graph.BipartiteGraph(R, H_, E, capacities)
Beispiel #5
0
def random_model_generator(n1, n2, k, max_capacity):
    """
    create a graph with the partition A of size n1
    and partition B of size n2 using the random model
    :param n1: size of partition A
    :param n2: size of partition B
    :param k: length of preference list for vertices in A
    :param max_capacity: maximum capacity a vertex in partition B can have
    :return: bipartite graph with above properties
    """
    def order_by_master_list(l, master_list):
        return sorted(l, key=master_list.index)

    # create the sets R and H, r_1 ... r_n1, h_1 .. h_n2
    R = set('a{}'.format(i) for i in range(1, n1 + 1))

    H = set('b{}'.format(i) for i in range(1, n2 + 1))

    # prepare a master list
    # master_list = list(h for h in H)
    # random.shuffle(master_list)

    # setup the capacities for the vertices

    capacities = dict((r, (0, 1)) for r in R)
    #capacities.update(dict((h, 1) for h in H))

    for h in H:
        #random_num_for_lowerQ  = random.randint((int)((3*max_capacity)/4), max_capacity)
        random_num_for_lowerQ = random.randint(0, max_capacity)

        capacities[h] = (random_num_for_lowerQ, max_capacity)

    pref_lists_H, pref_lists_R = collections.defaultdict(list), {}
    for resident in R:
        #min_val=random.randint((int)((3*len(H))/4), len(H))
        #pref_list = random.sample(H, min(min_val, k))
        pref_list = random.sample(H, min(
            len(H), k))  # random.randint(1, len(H)))  # sample houses
        pref_lists_R[
            resident] = pref_list  # order_by_master_list(pref_list, master_list)
        # add these residents to the preference list for the corresponding hospital
        for hospital in pref_list:
            pref_lists_H[hospital].append(resident)
            # random.shuffle(pref_lists_R[hospital])  # shuffle the preference list

    for hospital in H:
        random.shuffle(pref_lists_H[hospital])
    # create a dict with the preference lists for residents and hospitals
    E = pref_lists_R
    E.update(pref_lists_H)
    # only keep those hospitals which are in some residents preference list
    H_ = set(hospital for hospital in H if hospital in E)
    return graph.BipartiteGraph(R, H_, E, capacities)
def hreduction(G):
    for r in G.A:
        pref_list = []
        for h in G.E[r]:
            if graph.lower_quota(G, h) > 0:
                pref_list.append(h)
        G.E[r] = pref_list

    B = set(h for h in G.B if graph.lower_quota(G, h) > 0)
    for h in B:
        G.capacities[h] = (0, graph.lower_quota(G, h))
    return graph.BipartiteGraph(G.A, B, G.E, G.capacities)
def random_sample(G):
    """
    generates a random sampling, which is then returned
    as a bipartite graph, from the given graph
    the returned preference lists are symmetric
    :param G: bipartite graph
    :return: bipartite graph from a random sample
    """
    E = collections.defaultdict(
        list)  # to store the new sampled preference list
    for student in G.A:
        pref_list = G.E[student]
        E[student] = pref_list[:]  # store the pref list of student in E
        for elective in pref_list:
            E[elective].append(student)

    for elective in G.B:
        random.shuffle(G.E[elective])
    return graph.BipartiteGraph(G.A, G.B, E, G.capacities)
def read_graph(rdr):
    n_1 = int(readline(rdr))  # number of residents
    n_2 = int(readline(rdr))  # number of hospitals
    _ = readline(rdr)  # number of couples
    _ = readline(rdr)  # number of posts
    _ = readline(rdr)  # min resident pref list length
    _ = readline(rdr)  # max resident pref list length
    _ = readline(rdr)  # posts distributed evenly?
    _ = readline(rdr)  # resident popularity
    _ = readline(rdr)  # hospital popularity
    _ = readline(rdr)  # skip empty line

    # read the preferences of the residents
    A, E = set(), {}
    capacities = {}
    for i in range(n_1):
        data = readline(rdr).split()
        u = 'r{}'.format(data[0])
        # pref list for couples may contains duplicate
        # do not include them more than once in the original order
        pref_list = []
        for h in data[1:]:
            h_rep = 'h{}'.format(h)
            if h_rep not in pref_list:
                pref_list.append(h_rep)
        A.add(u)  # add this vertex to partition A
        E[u] = pref_list  # set its preference list
        capacities[u] = (0, 1)

    _ = readline(rdr)  # skip empty line

    # read the preferences of the hospitals
    B = set()
    for i in range(n_2):
        data = readline(rdr).split()
        u, capacity, = 'h{}'.format(data[0]), int(data[1])
        pref_list = ['r{}'.format(r) for r in data[2:]]
        B.add(u)  # add this vertex to partition B
        E[u] = pref_list  # set its preference list
        capacities[u] = (0, int(data[1]))

    return graph.BipartiteGraph(A, B, E, capacities)
Beispiel #9
0
def mahadian_k_model_generator_man_woman(n1, n2, k):
    """
    create a graph with the partition A of size n1 and
    partition B of size n2 using the model as described in
    Marriage, Honesty, and Stability
    Immorlica, Nicole and Mahdian, Mohammad
    Sixteenth Annual ACM-SIAM Symposium on Discrete Algorithms
    :param n1: size of partition A
    :param n2: size of partition B
    :param k: length of preference list for vertices in A
    :return: bipartite graph with above properties
    """
    # create the sets M and W, m_1 ... m_n1, w_1 .. w_n2
    M = list('m{}'.format(i) for i in range(1, n1 + 1))
    W = list('w{}'.format(i) for i in range(1, n2 + 1))

    # setup the capacities for the vertices
    capacities = dict((m, 1) for m in M)
    capacities.update(dict((w, 1) for w in W))

    # setup a probability distribution over the women
    p = np.random.random_sample((len(W), ))
    # normalize the distribution
    p = p / np.sum(p)  # p is a ndarray, so this operation is perfectly fine

    pref_lists_W, pref_lists_M = collections.defaultdict(list), {}
    for m in M:
        # sample women according to the probability distribution and without replacement
        pref_lists_M[m] = list(
            np.random.choice(W, size=min(len(W), k), replace=False, p=p))
        # add these man to the preference list for the corresponding women
        for w in pref_lists_M[m]:
            pref_lists_W[w].append(m)

    for w in W:
        random.shuffle(pref_lists_W[w])
    # create a dict with the preference lists for men and women
    E = pref_lists_M
    E.update(pref_lists_W)
    # only keep those women which are in some man's preference list
    W_ = set(w for w in W if w in E)
    return graph.BipartiteGraph(M, W_, E, capacities)
def augment_graph(G):
    """
    create graph G' as described in KavAgnes2015
    :param G: bipartite graph G
    :return: augmented graph G'
    """
    # corresponding to every man a \in A, two men a_0 and a_1 in A'
    # and one woman d(a) in B'
    A_ = set(Vertex(r, 0) for r in G.A) | set(Vertex(r, 1) for r in G.A)
    dummies = set(dummy_hospital(r) for r in G.A)  # dummy women
    B_ = G.B | dummies
    capacities = copy.copy(G.capacities)  # capacities for new graph
    # dummy vertices have capacity 1
    capacities.update(dict((dummy, (0, 1)) for dummy in dummies))
    # add preference list for the residents
    E_ = dict((r, preflist_resident(r, G)) for r in A_)
    # preference list for the dummies
    E_.update(dict((dummy_hospital(r), preflist_dummy(r)) for r in G.A))
    # preference list for hospital
    E_.update(dict((h, preflist_hospital(h, G)) for h in G.B))
    return graph.BipartiteGraph(A_, B_, E_, capacities)
def read_course_allotment_graph(file, skip_header, split_index):
    """
    reads the course allotment graph from the given csv_file
    :param file: file having the graph in CSV format
    :param split_index: where to split a pref list
    :return: bipartite graph with the
    """
    # TODO: lot of hard coded values
    students, electives = set(), set()
    E = collections.defaultdict(list)  # dict to store the preference list

    # skip the header if needed
    if skip_header:
        file.readline()

    # read data
    for row in csv.reader(file):
        # FIXME: ugly code
        student_id, preferences = row[split_index - 1], row[split_index:]

        # sanitize the preference list for the student
        pref_list, chosen = [], set()  # preferences already chosen by student
        for pref in preferences:
            if pref and pref not in chosen:  # only add non empty preferences
                chosen.add(pref)
                electives.add(pref)
                pref_list.append(pref)

        # do not add an isolated vertex, assume roll numbers are unique
        if pref_list:
            students.add(student_id)
            E[student_id] = pref_list

    capacities = dict((student, 1) for student in students)
    #print(electives)
    # TODO: fix this
    # cap = {'MA2010': 80, 'MA2020': 80, 'MA2030': 210, 'MA2040': 350}
    # cap = {'HS1100': 1, 'HS1120': 1, 'HS2200': 13, 'HS2320': 50,
    #       'HS3060': 4, 'HS3420': 4, 'HS4004': 21, 'HS4180': 11,
    #       'HS4330': 22, 'HS4370': 37, 'HS5612': 36, 'HS6140': 50}
    # original capacities for slot F
    # cap = {'HS1090': 60, 'HS2130': 26, 'HS2210': 106, 'HS2370': 53,
    #       'HS3002': 250, 'HS3005': 53, 'HS3007': 36, 'HS3029': 23,
    #       'HS4050': 53, 'HS4350': 25, 'HS4410': 50, 'HS4480': 45,
    #       'HS5080': 44, 'HS5920': 53, 'HS5930': 53, 'HS6130': 53,
    #       'HS7004': 41}
    # cap = {'HS1090': 45, 'HS2130': 20, 'HS2210': 80, 'HS2370': 40,
    #        'HS3002': 188, 'HS3005': 40, 'HS3007': 27, 'HS3029': 18,
    #        'HS4050': 40, 'HS4350': 19, 'HS4410': 38, 'HS4480': 34,
    #        'HS5080': 33, 'HS5920': 40, 'HS5930': 40, 'HS6130': 40,
    #        'HS7004': 31}
    #cap = {'HS1060': 50, 'HS2030': 50, 'HS2370': 50, 'HS3002A': 60,
    #       'HS3002B': 60, 'HS3002C': 60, 'HS3002D': 70, 'HS3420': 96,
    #       'HS4002': 50, 'HS4070': 50, 'HS4540': 50, 'HS5920': 50,
    #       'HS5930': 50}
    cap1 = {
        'HS1090': 20,  #10,
        'HS1090+': 20,  #50,
        'HS1110': 20,
        'HS2050': 20,
        'HS3002': 20,
        'HS3002A': 20,
        'HS3002B': 20,
        'HS3002C': 20,
        'HS3002D': 20,
        'HS3280': 20,
        'HS3420A': 20,
        'HS4002': 20,
        'HS4540': 20,
        'HS5070': 20,
        'HS5920': 20,
        'HS5930': 20,
        'HS4005': 20,
        'HS4006': 20
    }
    cap = {
        'MA2010': 85,
        'MA2020': 560,
        'MA2031': 140,
        'MA2040': 80,
        'MA2130': 85,
        'PH2170': 50,
        'PH3500': 50
    }

    capacities.update(cap)
    return graph.BipartiteGraph(students, electives, E, capacities)