5

My question is regarding the Maximum Weight B-Matching problem.

Bipartite matching problems pair two sets of vertices in a bipartite graph. A maximum weighted bipartite matching (MWM) is defined as a matching where the sum of the values of the edges in the matching have a maximal value. A famous polynomial time algorithm for MWM is the Hungarian algorithm.

What I am interested in is a specific maximum weighted bipartite matching known as weight bipartite B-matching problem. A weight bipartite B-matching problem (WBM) seeks to match vertices so that each vertex is matched with no more vertices than its capacity b allows.

enter image description here

This figure (from Chen et al.) shows the WBM problem. The input graph has score 2.2, the sum of all its edge weights. The blue edges of the solution H yield the highest score, 1.6, of all sub-graphs satisfying the red degree constraints.

Although there are a few recent works addressing the WBM problem (this and this), I cannot find any implementation of the algorithm. Does anybody know if the WBM problem already exists in any library like networkX?

4

1 回答 1

3

让我们一步一步地尝试,编写我们自己的函数来解决问题中指定的 WBM 问题。

pulp当给定两组节点(u 和 v、边权重和顶点容量)时,使用它来制定和求解加权二分匹配 (WBM) 并不难。

在下面的第 2 步中,您将找到一个(希望很容易理解)函数来将 WBM 表述为 ILP,并使用pulp.Go through 来解决它,看看它是否有帮助。(你需要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 是指派问题的一种变体。
  • 我们将 RHS 的节点“匹配”到 LHS。
  • 边缘有权重
  • 目标是最大化所选边的权重之和。
  • 附加约束集:对于每个节点,所选边的数量必须小于其指定的“容量”。
  • 如果您不熟悉纸浆文档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 选择的边缘。希望这可以帮助您继续前进。

于 2018-06-21T02:16:57.227 回答