I am implementing an Inverse Optimization Problem which instead of using KKT conditions applies the strong duality theorem (primal optimal objective and the dual optimal objective are equal). For this purpose, it is required to formulate the primal and the dual problem. I have 4 generators with 8 energy blocks (b) each and a fixed demand. This is a market clearing per hour.
The primal problem is an easy Market Clearing and it is as follows using the library Pyomo:
model = ConcreteModel()
model.g1=Var(b, within=NonNegativeReals)
model.g2=Var(b, within=NonNegativeReals)
model.g3=Var(b, within=NonNegativeReals)
model.g4=Var(b, within=NonNegativeReals)
model.obj = Objective(expr=
(sum(g1price[i]*model.g1[i] for i in b)+
sum(g2price[i]*model.g2[i] for i in b)+
sum(g3price[i]*model.g3[i] for i in b)+
sum(g4price[i]*model.g4[i] for i in b)))
model.con_power_balance=Constraint(
expr=
(sum(model.g1[i] for i in b)+
sum(model.g2[i] for i in b)+
sum(model.g3[i] for i in b)+
sum(model.g4[i] for i in b)- demand) == 0)
model.con_g1max=ConstraintList()
for i in b:
model.con_g1max.add(model.g1[i] <= gsize[i])
model.con_g2max=ConstraintList()
for i in b:
model.con_g2max.add(model.g2[i] <= gsize[i])
model.con_g3max=ConstraintList()
for i in b:
model.con_g3max.add(model.g3[i]< = gsize[i])
model.con_g4max=ConstraintList()
for i in b:
model.con_g4max.add(model.g4[i] <= gsize[i])
Let's say that the previous equations are named (1a-1f). When no stated, is set as default to minimize the objective function. As the primal problem is a minimization problem, its dual must be a maximization one. But it is equivalent max[F(x)] == min[-F(x)], and it is what I have applied. Here is the dual problem (equations 2a-2e):
model = ConcreteModel()
model.mu_g1max=Var(b, within=NonNegativeReals)
model.mu_g2max=Var(b, within=NonNegativeReals)
model.mu_g3max=Var(b, within=NonNegativeReals)
model.mu_g4max=Var(b, within=NonNegativeReals)
model.mu_g1min=Var(b, within=NonNegativeReals)
model.mu_g2min=Var(b, within=NonNegativeReals)
model.mu_g3min=Var(b, within=NonNegativeReals)
model.mu_g4min=Var(b, within=NonNegativeReals)
model.lambda=Var(b, within=NonNegativeReals)
model.obj = Objective(expr=
(sum(gsize[i]*model.mu_g1max[i] for i in b)+
sum(gsize[i]*model.mu_g2max[i] for i in b)+
sum(gsize[i]*model.mu_g3max[i] for i in b)+
sum(gsize[i]*model.mu_g4max[i] for i in b))
model.con_g1_dual=ConstraintList()
for i in b:
model.con_g1_dual.add(model.lambda[i]+model.mu_g1min[i]-model.mu_g1max <= gsize[i])
model.con_g2_dual=ConstraintList()
for i in b:
model.con_g2_dual.add(model.lambda[i]+model.mu_g2min[i]-model.mu_g2max <= gsize[i])
model.con_g3_dual=ConstraintList()
for i in b:
model.con_g3_dual.add(model.lambda[i]+model.mu_g3min[i]-model.mu_g3max <= gsize[i])
model.con_g4_dual=ConstraintList()
for i in b:
model.con_g4_dual.add(model.lambda[i]+model.mu_g4min[i]-model.mu_g4max <= gsize[i])
Once the primal and the dual problem are presented, the real problem that I have to solve is the following one:
model = ConcreteModel()
model.lambda=Var(b, within=NonNegativeReals)
model.obj = Objective(expr=
np.absolute(sum(model.lambda[i]-lambda_ini[i] for i in b*4)))
Here I have to put as constraints the ones from the dual problem (2b-2e) written before and moreover apply the strong duality constraint which would be:
min (objective function primal problem) = max (objective function dual problem)
Here is my problem: How would be this last constraint written??
model.dual = Suffix(direction=Suffix.IMPORT_EXPORT)suffix. I would not use a variable namedlambda, simply becauselambdain programming can have a very different meaning.