Решение двудольного b-сопоставления с максимальным весом

Мой вопрос касается проблемы B-Matching по максимальному весу.

Задачи Двудольного сопоставления объединяют два набора вершин в двудольный граф. Максимально взвешенное двустороннее соответствие (MWM) определяется как соответствие, при котором сумма значений ребер в сопоставлении имеет максимальное значение. Известный алгоритм полиномиального времени для MWM - венгерский алгоритм.

Что меня интересует, так это конкретное двустороннее сопоставление с максимальным весом, известное как проблема взвешенного двудольного B-сопоставления. Задача весового двудольного B-сопоставления (WBM) стремится сопоставить вершины так, чтобы каждая вершина сопоставлялась не с большим количеством вершин, чем позволяет ее емкость b.

введите описание изображения здесь

Этот рисунок (из Chen et al.) показывает проблему WBM. Входной граф имеет балл 2.2, сумму всех его весов. Синие края решения H дают наивысший балл 1,6 из всех подграфов, удовлетворяющих ограничениям красной степени.

Хотя есть несколько недавних работ, посвященных проблеме WBM (this и this), я не могу найти никакой реализации алгоритма. Кто-нибудь знает, существует ли проблема WBM в какой-либо библиотеке, такой как networkX?


person Sina    schedule 18.06.2018    source источник
comment
Не уверен, был ли реализован WBM. Этот вопрос / ответ SO должен дать вам некоторые идеи, если вы пойти по пути самостоятельной реализации.   -  person Ram Narasimhan    schedule 18.06.2018
comment
Спасибо, но, к сожалению, это не помогает. NetworkX имеет алгоритмы сопоставления для двудольных графов, но для этого конкретного случая нет ничего.   -  person Sina    schedule 18.06.2018
comment
Не знаю, полностью ли понимаю разницу между MWM и WBM. Не могли бы вы добавить поясняющий пример, где два решения разные? Тогда, возможно, найти способ реализовать, если с минимальными дополнительными усилиями   -  person Ram Narasimhan    schedule 18.06.2018
comment
Венгерский алгоритм решает проблему сопоставления без учета вместимости каждой вершины. Емкость b указывает, сколько ребер можно соединить с этой вершиной. Можно сказать, что MWM - это частный случай WBM, в котором емкость каждой вершины равна 1. Моделирование проблемы с использованием емкости для вершин помогает нам решать задачи типа «один ко многим», например, 1 рецензент может просматривать b статьи. .   -  person Sina    schedule 18.06.2018
comment
Извините, я все еще пытаюсь понять проблему: чем это отличается от задачи о рюкзаке (с несколькими рюкзаками) ?   -  person Paul Brodersen    schedule 19.06.2018
comment
Nvm, я думаю, это становится канонической проблемой с рюкзаком только в том случае, если граф полностью связан.   -  person Paul Brodersen    schedule 19.06.2018
comment
Спасибо, @Paul. На самом деле вы моделируете проблему по-другому, что кажется очень интересным. Однако проблема WBM так не думала. Это рассматривается как проблема сопоставления двудольных графов с ограничениями, конфликтами и разнообразием. Я проведу несколько экспериментов, используя вашу идею, и напишу здесь свои выводы.   -  person Sina    schedule 20.06.2018
comment
Да, есть несколько старых теорий дискретной оптимизации, которые можно элегантно выразить в виде графовых задач, но это не так. Это не значит, что они ничего не поняли. Рад, если ссылка дала вам новые идеи.   -  person Paul Brodersen    schedule 20.06.2018


Ответы (1)


Давайте попробуем сделать это шаг за шагом, написав нашу собственную функцию для решения проблемы WBM, как указано в вопросе.

Используя pulp, не так сложно сформулировать и решить взвешенное двудольное сопоставление (WBM), когда нам даны два набора узлов (u и v, веса ребер и емкости вершин).

На шаге 2 ниже вы найдете (надеюсь, легко усвоить) функцию для формулирования WBM как ILP и решения с помощью pulp. Просмотрите ее, чтобы увидеть, помогает ли она. (Вам нужно pip install pulp)

Шаг 1. Настройте пропускную способность и веса ребер двудольного графа.

import networkx as nx
from pulp import *
import matplotlib.pyplot as plt

from_nodes = [1, 2, 3]
to_nodes = [1, 2, 3, 4]
ucap = {1: 1, 2: 2, 3: 2} #u node capacities
vcap = {1: 1, 2: 1, 3: 1, 4: 1} #v node capacities

wts = {(1, 1): 0.5, (1, 3): 0.3,
       (2, 1): 0.4, (2, 4): 0.1,
       (3, 2): 0.7, (3, 4): 0.2}

#just a convenience function to generate a dict of dicts
def create_wt_doubledict(from_nodes, to_nodes):

    wt = {}
    for u in from_nodes:
        wt[u] = {}
        for v in to_nodes:
            wt[u][v] = 0

    for k,val in wts.items():
        u,v = k[0], k[1]
        wt[u][v] = val
    return(wt)

Шаг 2: Решите WBM (сформулированную как целочисленную программу)

Вот некоторое описание, чтобы упростить понимание следующего кода:

  • WBM - это разновидность задачи присваивания.
  • Мы «сопоставляем» узлы из правой и левой.
  • Края имеют веса
  • Цель состоит в том, чтобы максимизировать сумму весов выбранных ребер.
  • Дополнительный набор ограничений: для каждого узла количество выбранных ребер должно быть меньше его указанной «емкости».
  • Документация PuLP, если вы не знакомы с puLP

.

def solve_wbm(from_nodes, to_nodes, wt):
''' A wrapper function that uses pulp to formulate and solve a WBM'''

    prob = LpProblem("WBM Problem", LpMaximize)

    # Create The Decision variables
    choices = LpVariable.dicts("e",(from_nodes, to_nodes), 0, 1, LpInteger)

    # Add the objective function 
    prob += lpSum([wt[u][v] * choices[u][v] 
                   for u in from_nodes
                   for v in to_nodes]), "Total weights of selected edges"


    # Constraint set ensuring that the total from/to each node 
    # is less than its capacity
    for u in from_nodes:
        for v in to_nodes:
            prob += lpSum([choices[u][v] for v in to_nodes]) <= ucap[u], ""
            prob += lpSum([choices[u][v] for u in from_nodes]) <= vcap[v], ""


    # The problem data is written to an .lp file
    prob.writeLP("WBM.lp")

    # The problem is solved using PuLP's choice of Solver
    prob.solve()

    # The status of the solution is printed to the screen
    print( "Status:", LpStatus[prob.status])
    return(prob)


def print_solution(prob):
    # Each of the variables is printed with it's resolved optimum value
    for v in prob.variables():
        if v.varValue > 1e-3:
            print(f'{v.name} = {v.varValue}')
    print(f"Sum of wts of selected edges = {round(value(prob.objective), 4)}")


def get_selected_edges(prob):

    selected_from = [v.name.split("_")[1] for v in prob.variables() if v.value() > 1e-3]
    selected_to   = [v.name.split("_")[2] for v in prob.variables() if v.value() > 1e-3]

    selected_edges = []
    for su, sv in list(zip(selected_from, selected_to)):
        selected_edges.append((su, sv))
    return(selected_edges)        

Шаг 3: укажите график и вызовите решатель WBM

wt = create_wt_doubledict(from_nodes, to_nodes)
p = solve_wbm(from_nodes, to_nodes, wt)
print_solution(p)

Это дает:

Status: Optimal
e_1_3 = 1.0
e_2_1 = 1.0
e_3_2 = 1.0
e_3_4 = 1.0
Sum of wts of selected edges = 1.6

Шаг 4. При желании постройте график с помощью Networkx.

selected_edges = get_selected_edges(p)


#Create a Networkx graph. Use colors from the WBM solution above (selected_edges)
graph = nx.Graph()
colors = []
for u in from_nodes:
    for v in to_nodes:
        edgecolor = 'blue' if (str(u), str(v)) in selected_edges else 'gray'
        if wt[u][v] > 0:
            graph.add_edge('u_'+ str(u), 'v_' + str(v))
            colors.append(edgecolor)


def get_bipartite_positions(graph):
    pos = {}
    for i, n in enumerate(graph.nodes()):
        x = 0 if 'u' in n else 1 #u:0, v:1
        pos[n] = (x,i)
    return(pos)

pos = get_bipartite_positions(graph)


nx.draw_networkx(graph, pos, with_labels=True, edge_color=colors,
       font_size=20, alpha=0.5, width=3)

plt.axis('off')
plt.show() 

print("done")

введите описание изображения здесь

Синие края - это те, которые были выбраны для WBM. Надеюсь, это поможет вам двигаться вперед.

person Ram Narasimhan    schedule 21.06.2018
comment
Рам, большое спасибо за подробные объяснения. Хотя ваше решение действительно интересно, оно, похоже, игнорирует характерную для проблемы двудольную форму соответствия. Проблема заключается не только в оптимизации параметров, но и в сохранении двудольного графа с учетом пропускной способности каждой вершины. В противном случае ваше решение может быть идеальным в том случае, если двудольность не важна. Просто чтобы уточнить, если мы установим емкость каждой вершины равной 1, у нас должен быть согласованный двудольный граф на выходе, чего нет в вашем решении. - person Sina; 27.06.2018
comment
SIna, у двудольных графов (или двудольного сопоставления) есть какое-то тонкое свойство, которое я должен упустить. Можете ли вы указать, какое свойство нарушено и почему в приведенном выше примере? Я починю это. - person Ram Narasimhan; 28.06.2018
comment
Рам, установите пропускную способность вершин равной 1. Ваше решение должно давать двудольный согласованный граф, аналогичный выходному результату венгерского алгоритма. Можете ли вы принять свое решение на выходе венгерского алгоритма, чтобы оптимизация производилась в отношении мощностей? - person Sina; 06.07.2018