I have an issue as the problem is not optimaze and I am trying to use a binary variable x to identify if the edge is used or not as the number of edges used should be minimized. The issue is that I cannot assign the correct value to x=1 when the Q of the edge is greater then zero. There is surely an issue or in the objective function or in the contraint 7. This is the code I am running:
import matplotlib.pyplot as plt
import networkx as nx
import pyomo.environ as pe
import pyomo.opt as po
import pandas as pd
import numpy as np
d = pd.read_excel("Grafo9Nodi_Bil.xlsx",header=0, index_col=0) #importo le posizioni dal file Excel
#impongo una lunghezza massima del singolo arco
LunMax=8
nodes = range(0,len((d["X"])))
distance = {}
pos={}
edges={}
for i in sorted(nodes):
pos[i]=(d["X"][i],d["Y"][i])
for j in sorted(nodes):
if i!=j and np.round(pe.sqrt((d["X"][i]-d["X"][j])**2+(d["Y"][i]-d["Y"][j])**2),2)<=LunMax:
distance [i,j]=np.round(pe.sqrt((d["X"][i]-d["X"][j])**2+(d["Y"][i]-d["Y"][j])**2),2)
edges={(i,j) for i in sorted(nodes) for j in sorted(nodes) if i!=j and np.round(pe.sqrt((d["X"][i]-d["X"][j])**2+(d["Y"][i]-d["Y"][j])**2),2)<=LunMax}
model = pe.ConcreteModel()
path_edges = []
model.nodes = pe.Set(initialize=nodes)
model.edges = pe.Set(within=model.nodes*model.nodes, initialize=edges)
model.IN = pe.Var(model.nodes, domain=pe.NonNegativeReals,initialize=0)
IN=model.IN
model.x = pe.Var(model.nodes*model.nodes, domain=pe.Binary,initialize=0)
x=model.x
model.Q = pe.Var(model.nodes*model.nodes, domain=pe.NonNegativeReals)
Q=model.Q
model.OUT = pe.Var(model.nodes, domain=pe.NonNegativeReals,initialize=0)
OUT=model.OUT
#funzione obiettivo
def obj_rule(model):
TCC=sum(d["OpexC"][i]*IN[i] for i in model.nodes)
TTC=sum(Q[i,j]*1*distance[i,j] if Q[i,j] is not None and Q[i,j].value != 0 else 0 for [i,j] in model.edges)+sum(distance [i,j]*4*x[i,j] for [i,j] in model.edges if x[i,j].value != None and x[i,j].value != 0)
TSC=sum(d["OpexS"][i]*OUT[i] for i in model.nodes)
return TCC+TTC+TSC
model.Objf= pe.Objective (rule=obj_rule, sense = pe.minimize)
#vincoli
def constraint1(model,nodes):
return IN[nodes] <= d["IN"][nodes]
model.Const1=pe.Constraint(model.nodes, rule=constraint1)
def constraint2(model,nodes):
return sum(IN[nodes] for nodes in model.nodes) >= 1*sum(d["IN"][nodes] for nodes in model.nodes)
model.Const2=pe.Constraint(model.nodes, rule=constraint2)
def constraint4(model,nodes):
return IN[nodes]+sum(Q[i,nodes] for i in model.nodes if [i,nodes] in model.edges) == sum(Q[nodes,i] for i in model.nodes if [i,nodes] in model.edges) +OUT[nodes]
model.Const4=pe.Constraint(model.nodes, rule=constraint4)
def constraint5(model,nodes):
return OUT[nodes] <= d["OUT"][nodes]
model.Const5=pe.Constraint(model.nodes, rule=constraint5)
def constraint6(model,nodes):
return sum(IN[nodes] for nodes in model.nodes) == sum(OUT[nodes] for nodes in model.nodes)
model.Const6=pe.Constraint(model.nodes, rule=constraint6)
def constraint7(model, i, j):
if Q[i,j].value != 0:
return x[i,j] == 1
else:
return x[i,j] == 0
model.Const7 = pe.Constraint(model.edges, rule=constraint7)
Solver = po.SolverFactory ('gurobi', tee=True)
results = Solver.solve(model)
The result is not optimazed as x[i,j] are all equal to 1 while Q[i,j] have different values. Thanks in advance for the help
Here's a couple things to help you along. This sure looks like a homework project, so I'm reluctant to write the whole thing for you.
Some
pyomoerrors / tips:You cannot use conditional (
if) statements or.valuein constructing the model. The values of the variables are unknown when the model is written. That's the solver's job. You will need to re-formulate some of the constraints and objective statements. This can be done for this type of model.Your constraints have "name collision" in the variables. You are over-writing the variable that you take in from the function parameters. For instance in you constraint:
... what does
nodesrefer to? You are capturing it, but then you are using the same variable names in your summations. If you want to write a constraint for each node, you need to not over-write if you are going to use a sum.model.pprint()Model structure
Your setup for the edges looks good, so why aren't you using that for the flow and usage variables to restrict them to the edges you made? I would expect:
In order to deal with the balance of flow constraints, you are going to need to organize your edges such that you can find the ones that flow in or out of each node. There are several ways to do that, but perhaps the simplest is just make some dictionaries... Here are a couple ideas:
Output: