我正在运行用于网络流量优化的脚本,并且正在与另一个人进行协作。我正在使用networkx建立模型并将其馈送到pyomo。我的脚本未运行,并且未构建模型。报告的唯一错误是
ValueError:未初始化的NumericValue对象build_pipe [_s1_3,s]没有值
其中build_pipe[_s1_3,s]
是具有在csv
文件中定义的参数的边,该文件肯定定义了所有需要的输入。尽管此错误使我的脚本无法运行,但其他人也可以运行该脚本。在python 2.7上使用networkX 2.1和pyomo 5.6.1。
我们比较了软件包版本,它们是相同的。我能想到的唯一区别是,他在Spyder上运行脚本,而我在jupyter笔记本上运行我的脚本。过去曾出现此错误,但是一些编辑(用#**
标记)解决了该错误。不知道这次要更改什么。
def create_graph(nodefile, arcfile):
g = networkx.DiGraph()
# read the data files
# We assume the first column of the node file is the node name
# We also assume the arc file's first two columns are (node start, node end)
nodes = pandas.read_csv(nodefile)
arcs = pandas.read_csv(arcfile)
# create the nodes and associated data
nameCol = nodes.columns[0]
for num,arow in nodes.iterrows():
g.add_node( arow[nameCol], **(dict(arow)))
# create the arcs and associated data
firstNodeCol = arcs.columns[0]
secondNodeCol = arcs.columns[1]
for num,arow in arcs.iterrows():
g.add_edge( arow[firstNodeCol], arow[secondNodeCol], **(dict(arow)))
return g
def create_pyomo_network_lp_primal(g,cost_field='Cost',capacity_field='Capacity',node_imbalance_field='SupplyDemand', interdiction_field='xbar'):
# Create the model
model = pe.ConcreteModel()
# Tell pyomo to read in dual-variable information from the solver
model.dual = pe.Suffix(direction=pe.Suffix.IMPORT)
# Associate the graph with this model
model.g = g
# Create the problem data
model.node_set = pe.Set( initialize=g.nodes() )
model.edge_set = pe.Set( initialize=g.edges(), dimen=None) #**added ", dimen=None"
model.edge_cost = pe.Param( model.edge_set,
initialize=lambda model, i,j: model.g.adj[i][j].get(cost_field,0))
model.edge_capacity = pe.Param( model.edge_set,
initialize=lambda model, i,j: model.g.adj[i][j].get(capacity_field,0))
model.node_imbalance = pe.Param( model.node_set,
initialize=lambda model, i: model.g.node[i].get(node_imbalance_field,0))
model.edge_delay_on = pe.Param( model.edge_set,
initialize=lambda model, i,j: model.g.adj[i][j].get(interdiction_field,0), mutable=True)
# Compute nCmax
nCmax = model.g.number_of_nodes() * max([data.get(cost_field, 0) for e0,e1,data in model.g.edges(data=True) ])
model.nCmax = nCmax
model.delay = pe.Param(initialize= 2*nCmax + 1, mutable=True)
# Create the variables
model.y = pe.Var(model.edge_set, domain=pe.NonNegativeReals) #flow across each edge
model.build_pipe = pe.Var(model.edge_set, domain=pe.Binary) #binary whether we build a pipe for each edge #**added model.build_pipe which is a binary decision variable on whether or not the model chooses to build a pipe along a specific edge. Initialize it at 1 so that the model will solve (i.e. all pipes start with a 1, meaning that all pipes are initially built, then the model removes pipes to improve the objective)
model.UnsatSupply = pe.Var(model.node_set, domain=pe.NonNegativeReals)
model.UnsatDemand = pe.Var(model.node_set, domain=pe.NonNegativeReals)
# Create the objective
def obj_rule(model):
return pe.summation(model.edge_cost, model.build_pipe) + model.delay * pe.summation(model.edge_delay_on, model.y) + model.nCmax * pe.summation(model.UnsatDemand) #**removed " + model.nCmax * pe.summation(model.UnsatSupply)" which adds a penalty to the objective if not all of the supply is used. Updated the first OBJ term to use "model.build_pipe" instead of "model.y", which means that the objective depends on what piping network we build, not on the amount of flow we send over the pipes
model.OBJ = pe.Objective(rule=obj_rule, sense=pe.minimize)
# Create the constraints, one for each node
def flow_bal_rule(model, n):
expr = 0
if model.g.in_edges(n):
expr += pe.summation(model.y, index=model.g.in_edges(n))
if model.g.out_edges(n):
expr += - pe.summation(model.y, index=model.g.out_edges(n))
supply_node = (model.node_imbalance[n] < 0)
demand_node = (model.node_imbalance[n] > 0)
constr = (expr == model.node_imbalance[n] + model.UnsatSupply[n]*int(supply_node) - model.UnsatDemand[n]*int(demand_node) )
if isinstance(constr, bool):
if constr == True:
return pe.Constraint.Feasible
return pe.Constraint.Infeasible
return constr
model.FlowBalance = pe.Constraint(model.node_set, rule=flow_bal_rule)
# Create the capacity constraints, one for each edge
def capacity_rule(model, i, j):
return model.y[(i,j)] <= model.edge_capacity[(i,j)] * model.build_pipe[(i,j)] #** added " * model.build_pipe[(i,j)]" which means that the capacity of an edge is zero unless we choose to build it (if we choose to build pipe(i,j), then model.build_pipe[(i,j)] will equal 1, otherwise it equals 0)
model.Capacity = pe.Constraint(model.edge_set, rule=capacity_rule)
# Solve the model
#model.create()#** WARNING: DEPRECATION WARNING: the Model.create() method is deprecated. Call Model.create_instance() to create a concrete instance from an abstract model. You do not need to call Model.create() for a concrete model.
model= resolve_mip(model)
# Print the model objective
print 'Primal objective function value:', model.OBJ()
return model
# ============================================================================
# This is a useful function, in case you want to re-solve a model in the
# interpreter. Remember that if you dynamically want to change model
# parameters, you have to declare them as 'mutable' in the model. If you look
# above, we've declared edge_delay_on and delay as mutable in this case.
# ============================================================================
def resolve_mip(model, tee=False):
model.preprocess()
solver = pyomo.opt.SolverFactory('cplex')
results = solver.solve(model, tee=tee, keepfiles=False) #** removed " , options="mip_tolerances_integrality=1e-9 mip_tolerances_mipgap=0") "
# Check that we actually computed an optimal solution, load results
if (results.solver.status != pyomo.opt.SolverStatus.ok):
logging.warning('Check solver not ok?')
if (results.solver.termination_condition != pyomo.opt.TerminationCondition.optimal):
logging.warning('Check solver optimality?')
#model.load(results) #** WARNING: DEPRECATION WARNING: the Model.load() method is deprecated for loading solutions stored in SolverResults objects. By default, results from solvers are immediately loaded into the original model instance.
model.g.OBJ_val = model.OBJ()
# Load solution data back into the networkx object
if hasattr(model, 'y'):
for e in model.edge_set:
model.g.adj[e[0]][e[1]]['flow_val'] = model.y[e].value
model.g.adj[e[0]][e[1]]['build_pipe'] = model.build_pipe[e].value #**added build_pipe to the model output solution
#if hasattr(model, 'dual'): #** remove the following 3 lines. I'm not sure what this code snippet does, but it was throwing errors. I think it has to do with running the interdiction version of the model.
# for n in model.FlowBalance.iterkeys():
# model.g.node[n]['dual_val'] = model.dual[ model.FlowBalance[n] ]
if hasattr(model, 'x'):
for e in model.edge_set:
model.g.adj[e[0]][e[1]]['attackActive'] = model.x[e].value
if hasattr(model, 'UnsatDemand'):
for n in model.node_set:
model.g.node[n]['UnsatDemand'] = model.UnsatDemand[n].value
model.g.node[n]['UnsatSupply'] = model.UnsatSupply[n].value
return model
# ============================================================================
# Here, we are printing a nice report on the solution to the screen. You have
# to pass a networkx object, with the flow_val field loaded.
# ============================================================================
def print_solution(g):
edges = sorted(g.edges(data=True))
for e0,e1,data in edges:
if data.has_key('attackActive') and data['attackActive'] == 1:
print 'Interdict arc %s -> %s'%(str(e0), str(e1))
print
nodes = sorted(g.nodes(data=True))
for n,data in nodes:
if data.has_key('UnsatSupply') and data['UnsatSupply'] > 0:
print 'Remaining supply on node %s: %.2f'%(str(n), data['UnsatSupply'])
for n,data in nodes:
if data.has_key('UnsatDemand') and data['UnsatDemand'] > 0:
print 'Remaining demand on node %s: %.2f'%(str(n), data['UnsatDemand'])
print
for e0,e1,data in edges:
if data.has_key('flow_val') and data['flow_val'] > 0:
print 'Flow on arc %s -> %s: %.2f'%(str(e0), str(e1), data['flow_val'])
print
#** added the following printout
print "Pipes Built:"
for e0,e1,data in edges:
if data.has_key('build_pipe') and data['build_pipe'] > 0 and len(e0) > 3:
print ' %s: %s-inch'%(str(e0), str(e0)[-1])
print
print '----------'
print 'Total cost = ', g.OBJ_val
# ===============================================================
# Now that we've defined all our functions, lets do something....
#
# First, lets read the data.
# ===============================================================
g = create_graph('nodes_multi_pipe.csv', 'edges_multi_pipe.csv')
# ===============================================================
# Lets solve and print the flow when there are no
# interdictions.
# ===============================================================
mPrimal = create_pyomo_network_lp_primal(g, capacity_field='Capacity')
print 'Flow without interdictions:'
print_solution(mPrimal.g)