Что вызывает сбой моего скрипта на моем компьютере, но работает нормально на другом? - PullRequest
0 голосов
/ 25 апреля 2019

Я запускаю сценарий для оптимизации потока сети и сотрудничаю с другим человеком.Я строю модель с использованием networkx и передаю ее в pyomo.Мой скрипт не запускается и модель не строится.Единственная сообщаемая ошибка:

ValueError: Нет значения для неинициализированного объекта NumericValue build_pipe [_s1_3, s]

, где build_pipe[_s1_3,s] - это ребро с параметрами, определенными в csv файл, который определенно определяет все необходимые входные данные.В то время как эта ошибка не позволяет моему сценарию работать, другой человек может нормально запустить сценарий.Использование networkX 2.1 и pyomo 5.6.1 на python 2.7.

Мы сравнили версии пакетов и они одинаковые.Единственное отличие, о котором я могу думать, это то, что он запускает свой скрипт на 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)
...