Hello @odow ! I appreciate your response and your interest in helping me.
I will share with you the fragments of my code that involve the error I mentioned. In particular, i am using the following data from a simple example of stochastic two-stage linear planning: (just to give you some context) This involves an optimal planning problem for generation expansion, which means determining the optimal investment in generation. There are various types of candidate generators available to meet demand over several periods. The first period has random demand. The investment decision must be consistent across all periods. Additionally, there is a budget constraint on total investment and a minimum power requirement for installation.
# Data:
# Number of scenarios of the problem
scenarios = 3
# Probability of each scenario
probabiliity = [0.2, 0.5, 0.3]
# Demand for each period j under a scenario s
demand = []
push!(demand, [3.0, 3.0, 2.0])
push!(demand, [5.0, 3.0, 2.0])
push!(demand, [7.0, 3.0, 2.0])
# Number of generators
generators = 4
# Number of periods
periods = 3
# Fixed cost of installing generator i
fixed_cost = [10, 7, 16, 6]
# Variable cost of production of generator i in period j
variable_cost =[40 24 4;
45 27 4.5;
32 19.2 3.2;
55 33 5.5]
# Minimum power to be installed
minimum_power = 12
# Budget of the decision maker
budget = 120
Then, the following function takes an input scenario index "s" and is responsible for creating the subproblem (or the deterministic version of the stochastic model for that scenario).
# Dictionary that will store the first-stage variables of the stochastic problem
first_stage_variables = Dict()
# Function that will build a subproblem depending of the data of the scenario "s"
function Build_Subproblem(s::Int)
# Attributes of the solver (Gurobi)
subproblem = Model(Gurobi.Optimizer)
set_optimizer_attribute(subproblem, "OutputFlag", 0)
set_optimizer_attribute(subproblem, "LogFile", "")
set_optimizer_attribute(subproblem, "LogToConsole", 0)
# Decision variables:
@variable(subproblem, x[1:generators] >= 0)
@variable(subproblem, y[1:generators, 1:periods] >= 0)
# We add the first-stage variables to the dictionary:
first_stage_variables[1] = x
# Subproblem constraints for any given scenario:
@constraint(subproblem, sum(x[i] for i in 1:generators) >= minimum_power)
@constraint(subproblem, sum(fixed_cost[i] * x[i] for i in 1:generators) <= budget)
for i in 1:generators
for j in 1:periods
@constraint(subproblem, y[i, j] <= x[i])
end
end
for j in 1:periods
@constraint(subproblem, sum(y[i, j] for i in 1:generators) >= demand[s][j])
end
# Objective function of the subproblem for any given scenario:
@objective(subproblem, Min, sum(fixed_cost[i] * x[i] for i in 1:generators) + sum(sum(variable_cost[i, j] * y[i, j] for i in 1:generators) for j in 1:periods))
# The function returns the subproblem (an optimization model created with JuMP):
return subproblem
end
And finally, this function takes as input an optimization model (in particular, the subproblems we have created) and is responsible for solving it and delivering the solution for the decision variables of the first stage for the corresponding scenario.
function Solve_Subproblem(subproblem::Model)
# First we optimize the subproblem:
optimize!(subproblem)
# An array is created to store the solutions of the first-stage variables:
first_stage_solutions = []
# Let's go through all the variables of the first stage:
for i in 1:length(first_stage_variables)
# We call the variables saved in the dictionary:
variable = first_stage_variables[i]
# We save the solution of the first stage variable:
push!(first_stage_solutions, JuMP.value.(variable))
end
# The solutions of all the variables of the first stage of the subproblem are delivered:
return first_stage_solutions
end
Now is when you can see the error I mentioned. I would like to be able to create all the subproblems only once and then work with them, for example:
# We create all the subproblems:
subproblems = Model[]
for s in 1:scenarios
push!(subproblems, Build_Subproblem(s))
end
# We want to solve the subproblems:
solutions = []
for s in 1:scenarios
push!(solutions, Solve_Subproblem(subproblems[s]))
end
Then we obtein the error: OptimizeNotCalled()
I know I could join the creation and solving of subproblems in a single “for” loop, but the reality is that later in my code, it deals with modifying the subproblems by creating their augmented Lagrangian relaxations (very similar to the Progressive Hedging algorithm). So, in the iterations of my algorithm, I need to solve the subproblems multiple times, and it’s not optimal to have to create the subproblems for all scenarios in each iteration. I would like to be able to create them only once.
I hope I explained myself well. I would appreciate it if you could review the code. Thank you very much!