Solutions to problems of mixed integer linear programming
This example shows how to solve the problem of mixed integer linear programming (English Mixed Integer Linear Programming, MILP). Here are the typical steps to formulate a problem using a problem-oriented approach.
We will use the functions of the [JuMP.jl] library(https://github.com/jump-dev/JuMP .jl) for the formulation of the optimization problem and the linear optimization library GLPK.jl.
Installing Libraries
If the latest version of the package is not installed in your environment JuMP, uncomment and run the cell below:
Pkg.add(["GLPK", "JuMP"])
#Pkg.add("JuMP");
To launch a new version of the library after the installation is complete, click on the "Personal Account" button:
Then click on the "Stop" button:
Restart the session by clicking the "Start Engee" button:
Task description
You need to mix steels with different chemical compositions to produce 25 tons of steel with a specific chemical composition. The result should be steel containing 5% carbon and 5% molybdenum of the total weight, which means 1.25 tons of carbon and 1.25 tons of molybdenum.
The purpose of the optimization task is to minimize the cost of mixing steel.
Four different steel bars are available for purchase. However, you can only buy one ingot of each type.
| Ingot | Weight in tons | % carbon | % molybdenum | Cost per ton |
|---|---|---|---|---|
| 1 | 5 | 5 | 3 | $350 |
| 2 | 3 | 4 | 3 | $330 |
| 3 | 4 | 5 | 4 | $310 |
| 4 | 6 | 3 | 4 | $280 |
Three grades of alloy steel and one grade of scrap steel are also available for sale. Alloy steels and scrap can be purchased in fractional quantities.
| Alloy | % carbon | % Molybdenum | Cost per ton |
|---|---|---|---|
| 1 | 8 | 6 | $500 |
| 2 | 7 | 7 | $450 |
| 3 | 6 | 8 | $400 |
| Лом | 3 | 9 | $100 |
Connecting libraries
Connect the library JuMP:
using JuMP;
Connect the solver library GLPK:
using GLPK;
Creating an optimization task
Create an optimization task using the function Model() and specify the name of the solver in parentheses.:
steel_prob = Model(GLPK.Optimizer)
Create a variable ingots, containing four values (according to the number of ingots available for purchase). Since ingots cannot be purchased in fractional quantities, specify the type of variable. Int. The lower bound for all variables will be 0, because we cannot purchase a negative quantity. Each of the bars is available in a single instance, so specify an upper bound of 1 for this variable.
@variable(steel_prob, ingots[1:4], Int; lower_bound = 0, upper_bound = 1);
Create a variable alloys, containing three values (according to the number of alloys available for purchase). We will separate the scrap steel into a separate variable. Since alloys can be purchased in fractional quantities, it is not necessary to specify the type of variable.
@variable(steel_prob, alloys[1:3], lower_bound = 0);
Create a variable scrap for scrap steel. Since scrap can be purchased in fractional quantities, you do not need to specify the type of variable.
@variable(steel_prob, scrap, lower_bound = 0);
Since the weight of each of the bars is different, to calculate the cost of purchasing the bars, you must first create a variable weightIngots. Calculate the costs for each of the components and create a variable cost, containing the total cost of purchasing components. As part of our task, we will find the minimum value of this variable.
weightIngots = [5,3,4,6];
costIngots = weightIngots.*[350,330,310,280];
costAlloys = [500,450,400];
costScrap = 100;
cost = sum(costIngots.*ingots) + sum(costAlloys.*alloys) + sum(costScrap*scrap)
Create an objective function to minimize costs to solve our optimization problem.:
@objective(steel_prob, Min, cost)
Create a variable totalWeight, containing the total weight of all components:
totalWeight = sum(weightIngots.*ingots) + sum(alloys) + scrap
Calculate the total mass of carbon in steel:
carbonIngots = [5,4,5,3]/100;
carbonAlloys = [8,7,6]/100;
carbonScrap = 3/100;
totalCarbon = sum((weightIngots.*carbonIngots).*ingots) + sum(carbonAlloys.*alloys) + sum(carbonScrap.*scrap)
Calculate the total mass of molybdenum in steel:
molybIngots = [3,3,4,4]/100;
molybAlloys = [6,7,8]/100;
molybScrap = 9/100;
totalMolyb = sum((weightIngots.*molybIngots).*ingots) + sum(molybAlloys.*alloys) + sum(molybScrap.*scrap)
Formulation of conditions
Set the first condition for solving the optimization problem, that the total weight of the steel obtained should be 25 tons.:
@constraint(steel_prob, C1, totalWeight == 25)
Set the second condition for solving the optimization problem, that the total carbon weight in the resulting steel should be 1.25 tons.:
@constraint(steel_prob, C2, totalCarbon == 1.25)
Set the third condition for solving the optimization problem, that the total weight of molybdenum in the resulting steel should be 1.25 tons.:
@constraint(steel_prob, C3, totalMolyb == 1.25)
Problem solving
Solve the optimization problem:
optimize!(steel_prob)
Check if an optimal solution has been found.:
if !is_solved_and_feasible(steel_prob)
error("Solver did not find an optimal solution")
end
Save the values of interest in variables. You can use the function round to round up overly precise values.
ingots_value = value.(ingots);
alloys_value = round.(value.(alloys); digits = 3);
scrap_value = round(value.(scrap); digits = 3);
fval = objective_value(steel_prob);
Output the optimization results:
println("Ingots: ", ingots_value)
println("Alloys: ", alloys_value)
println("Scrap: ", scrap_value)
println("Objective Value: ", fval)
The optimal purchase price is $8,495. Thus, it is necessary to purchase ingots 1, 2 and 4, but not 3. And also to purchase 7.25 tons of alloy 1, 0.25 tons of alloy 3 and 3.5 tons of steel scrap.
Conclusion
In this example, we solved the problem of mixed integer linear programming and found the optimal set and number of components to produce 25 tons of steel with the required chemical composition at the lowest price.