def obtainWassersteinProblem( roadnet, length='length', weight1='weight1', weight2='weight2' ) : """ input: a road network, with weights on its elements output: returns a graph summarizing the network optimization problem instance; roadnets are multi-digraph, where edge 'keys' are assumed to be unique, i.e., road names; and should be different from node labels too; """ # for convenience #ROADS = [ key for u,v,key in roadnet.edges_iter( keys=True ) ] class node : pass node_s = node() ; node_t = node() digraph = nx.DiGraph() digraph.add_node( node_s ) digraph.add_node( node_t ) """ insert supply and demand of roads """ for u,v, road, data in roadnet.edges_iter( keys=True, data=True ) : roadlen = data.get( length, 1. ) assert roadlen >= 0. oneway = data.get( 'oneway', False ) surplus = data.get( weight1, 0. ) - data.get( weight2, 0. ) deficit = -surplus # supply layer if surplus > 0. : digraph.add_edge( node_s, road, capacity=surplus ) w = roadlen / surplus if oneway : ends = [ v ] else : ends = [ u, v ] for node in ends : digraph.add_edge( road, node, decision_weight=w ) # demand layers if deficit > 0. : digraph.add_edge( road, node_t, capacity=deficit ) w = roadlen / deficit if oneway : ends = [ u ] else : ends = [ u, v ] for node in ends : digraph.add_edge( node, road, decision_weight=w ) """ insert supply and demand of nodes """ for u, data in roadnet.nodes_iter( data=True ) : surplus = data.get( weight1, 0. ) - data.get( weight2, 0. ) deficit = -surplus # supply layer if surplus > 0. : digraph.add_edge( node_s, u, capacity=surplus ) if deficit > 0. : digraph.add_edge( u, node_t, capacity=deficit ) """ setup the network flow structure """ conns = roadmap_basic.connectivity_graph( roadnet, length_in=length ) for u, v, data in conns.edges_iter( data=True ) : w = data.get( 'length', 1 ) digraph.add_edge( u, v, weight=w ) #return digraph, node_s, node_t # this *just* produced a flowgraph; no problem flowgraph = flownets.obtainFlowNetwork( digraph, node_s, node_t ) costgraph = flownets.obtainWeightedCosts( flowgraph, digraph ) # cute trick #return flowgraph, costgraph for u,v, data in digraph.edges_iter( data=True ) : dec_weight = data.get( 'decision_weight', None ) if dec_weight is None : continue # fdata = flowgraph.get_edge_data( u, v, 0 ) # key=0, because we have tightly controlled this construction flow = fdata.get( 'flow' ) cost = .5 * dec_weight * cvxpy.square( flow ) #print dec_weight, flow, cost cdata = costgraph.get_edge_data( u, v, 0 ) #print cdata cdata['cost'] = cost return flowgraph, costgraph
def measurenx_to_approxnx(roadnet, epsilon, length="length", weight1="weight1", weight2="weight2"): """ input: a road network, with weights on its elements output: returns a graph summarizing the network optimization problem instance; roadnets are multi-digraph, where edge 'keys' are assumed to be unique, i.e., road names; and should be different from node labels too; """ digraph = nx.DiGraph() digraph.add_node("s") digraph.add_node("t") """ insert supply and demand of roads """ for u, v, road, data in roadnet.edges_iter(keys=True, data=True): roadlen = float(data.get(length, 1)) # float() just in case assert roadlen >= 0.0 oneway = data.get("oneway", False) surplus = float(data.get(weight1, 0.0)) - data.get(weight2, 0.0) deficit = -surplus """ split the road into equal-length segments; create a node for each segment; """ N = int(np.ceil(roadlen / epsilon)) eps = roadlen / N if surplus > 0.0: NODES = [(road, k, "supply") for k in range(N)] for node in NODES: digraph.add_edge( "s", node, flow=cvxpy.variable(), minflow=0.0, maxflow=surplus / N, w_lo=-eps, w_hi=0.0 ) SEQ = [u] + NODES + [v] for lnode, rnode in zip(SEQ[:-1], SEQ[1:]): digraph.add_edge(lnode, rnode, flow=cvxpy.variable(), minflow=0.0, w_lo=eps, w_hi=eps) if not oneway: digraph.add_edge(rnode, lnode, flow=cvxpy.variable(), minflow=0.0, w_lo=eps, w_hi=eps) if deficit > 0.0: NODES = [(road, k, "demand") for k in range(N)] for node in NODES: digraph.add_edge( node, "t", flow=cvxpy.variable(), minflow=0.0, maxflow=deficit / N, w_lo=-eps, w_hi=0.0 ) SEQ = [u] + NODES + [v] for lnode, rnode in zip(SEQ[:-1], SEQ[1:]): digraph.add_edge(lnode, rnode, flow=cvxpy.variable(), minflow=0.0, w_lo=eps, w_hi=eps) if not oneway: digraph.add_edge(rnode, lnode, flow=cvxpy.variable(), minflow=0.0, w_lo=eps, w_hi=eps) """ insert supply and demand of nodes """ for u, data in roadnet.nodes_iter(data=True): surplus = data.get(weight1, 0.0) - data.get(weight2, 0.0) deficit = -surplus # supply layer if surplus > 0.0: digraph.add_edge("s", u, flow=cvxpy.variable(), minflow=0.0, maxflow=surplus) if deficit > 0.0: digraph.add_edge(u, "t", flow=cvxpy.variable(), minflow=0.0, maxflow=deficit) """ setup the network flow structure """ conns = roadmaps.connectivity_graph(roadnet) for u, v, data in conns.edges_iter(data=True): weight = data.get(length, 1) flowvar = cvxpy.variable() digraph.add_edge(u, v, flow=cvxpy.variable(), minflow=0.0, w_lo=weight, w_hi=weight) """ turn the weights into costs """ for _, __, data in digraph.edges_iter(data=True): flowvar = data["flow"] if "w_lo" in data: data["cost_lo"] = data["w_lo"] * flowvar if "w_hi" in data: data["cost_hi"] = data["w_hi"] * flowvar nxopt.attach_flownx_constraints(digraph) return digraph # a flownx