Problem description
I am trying to do a mixed-integer optimization for a "Unit Commitment" problem in Julia with Jump. But JuMP expects my introduction of the unit activation variable, x[1:N]
, to be a number and not a variable. However, the unit activation is a binary integer decision variable for the optimization problem so I have trouble including the variable into the optimization problem.
What am I doing wrong?
My approaches have been:
Approach 1: Include
x[1:N]
as part of@variable
macro forP_G
.
m = Model(Cbc.Optimizer) # Model
@variable(m, x[1:N], Bin) # Unit activation
@variable(m, P_C[i,1]*x[i] <= P_G[i=1:N,1:T] <= P_C[i,2]*x[i]) # Unit generation limit
for i in 1:T # Load balance
@constraint(m, sum(P_G[:,i]) == P_D[i])
end
@objective(m,Min,sum(P_G[:,1:T].*F[1:N]*x[1:N])) # Objective function
optimize!(m) # Solve
This leads to the following error:
LoadError: InexactError: convert(Float64, 50 x[1])
.
Approach 2: Define the feasible region for
P_G
as a constraint includingx[1:N]
:
m = Model(Cbc.Optimizer) # Model
@variable(m, x[1:N]) # Unit activation
@variable(m, P_G[i=1:N,1:T] ) # Unit generation limit
for i in 1:T # Load balance
@constraint(m, sum(P_G[:,i]) == P_D[i])
end
for i in 1:N # Unit generation limit
for j in 1:T
@constraint(m, P_C[i,1]*x[i] <= P_G[i,j] <= P_C[i,2]*x[i])
end
end
@objective(m,Min,sum(P_G[:,1:T].*F[1:N]*x[1:N])) # Objective function
optimize!(m) # Solve
This leads to: LoadError: [..] '@constraint(m, $(Expr(:escape, :(P_C[i, 1]))) * $(Expr(:escape, :(x[i]))) <= P_G[i, j] <= $(Expr(:escape, :(P_C[i, 2]))) * $(Expr(:escape, :(x[i]))))': Expected 50 x[1] to be a number.
NB: there might be more proper iteration methods but this should be idiot proof to Julia and JuMP newbies like me.
Working code without mixed-integer optimization
using JuMP, Cbc # Optimization and modelling
using Plots, LaTeXStrings # Plotting
# DATA
P_C = [50 200; # Power capacity [:, (min, max)]
25 200;
100 200;
120 500;
10 500;
20 500;
200 800;
200 800;
100 800;
200 1000;]
P_D = LinRange(sum(P_C[:,1]), sum(P_C[:,2]), 100) # Power demand
F = rand(100:500,10) # Random prod. prices
T = length(P_D) # Number of time steps
N = length(P_C[:,1]) # Number of generators
# MODEL
m = Model(Cbc.Optimizer) # Model
@variable(m, x[1:N], Bin) # Unit activation
@variable(m, P_C[i,1] <= P_G[i=1:N,1:T] <= P_C[i,2]) # Unit generation limit
for i in 1:T # Load balance
@constraint(m, sum(P_G[:,i]) == P_D[i])
end
@objective(m,Min,sum(P_G[:,1:T].*F[1:N])) # Objective function
optimize!(m) # Solve
# PLOT
plt = plot(P_D[:],value.(P_G[:,1:T])', xlab = L"P_{load} [MW]", ylab = L"P_{unit} [MW]")
@show plt
Which should produce something similar:
The expected outcome of introducing the unit activation variable would be that each unit is not required to generate power in the the lower region of the P_load
.
Preliminary
I have introduced the basics of the problem with success:
P_G
: for power generation (feasible region defined by min and max capacity, P_C
)F
(as constant only!)P_D
, is set to be a linear space from the min power cap. to the max cap.Mathematically expressed:
Variable bounds cannot include other variables. Do:
m = Model(Cbc.Optimizer)
@variable(m, x[1:N], Bin)
@variable(m, P_G[i=1:N,1:T])
@constraint(m, [i=1:N, t=1:T], P_C[i, 1] * x[i] <= P_G[i, t])
@constraint(m, [i=1:N, t=1:T], P_G[i, t] <= P_C[I, 2] * x[i])