Binary Linear Programming#
In this section, we will show you how to model binary linear programming
Applications#
Linear programming problems with discrete variables, known as ‘Mixed integer programming (MIP)’, have many applications. You may be surprised at the wide range of applications, even though the objective function and constraints are all linear. Two applications are listed below, but there are too many applications to list here.
Capital Budgeting
Warehouse Location
A linear programming solver based on the branch-and-bound method is useful if the size is not too large. Of course, JijModeling supports linear programming solvers. However, for consistency with other tutorials, we will solve it here using Simulated annealing in JijZept.
Modeling by JijModeling#
import jijmodeling as jm
@jm.Problem.define('binary_lp', sense=jm.ProblemSense.MAXIMIZE)
def problem(problem: jm.DecoratedProblem):
# define variables
S = problem.Float(ndim=2)
M = problem.DependentVar(S.len_at(0))
N = problem.DependentVar(S.len_at(1))
b = problem.Float(shape=(M,))
c = problem.Float(shape=(N,))
x = problem.BinaryVar(shape=(N,))
# Objective
problem += jm.sum(c[i] * x[i] for i in N)
# Constraints
problem += problem.Constraint(
"eq_const",
[jm.sum(S[j, i] * x[i] for i in N) == b[j] for j in M]
)
problem
The meaning of @jm.Problem.define(..., sense=jm.ProblemSense.MAXIMIZE) is to explicitly choose that the optimization problem is to be solved by maximizing the objective function.
If sense is not specified, the default is to solve the problem by minimizing the objective function.
Prepare an instance#
Next, we set the instance of the problem. As an example, we set up the following instance:
# set S matrix
inst_S = [[0, 2, 0, 2, 0], [1, 0, 1, 0, 1], [1, 2, 3, 2, 1]]
# set b vector
inst_b = [2, 2, 6]
# set c vector
inst_c = [1, 2, 3, 4, 5]
instance_data = {'S': inst_S, 'b': inst_b, 'c': inst_c}
Be careful with variable names and scopes.
Variable names such as S, b, and c are used when modeling with JijModeling and cannot be used when preparing instances. To avoid this problem, we use the prefix inst_.
Solve by JijZeptSolver#
We solve that problem with jijzept_solver.
import jijzept_solver
instance = problem.eval(instance_data)
solution = jijzept_solver.solve(instance, solve_limit_sec=1.0)
Check the results and solution#
Let’s check the solution obtained.
The solution obtained from jijzept_solver is managed in OMMX format.
.objective, .decision_variables_df and .constraints_df allow us to get the information of objective function, decision variables and constraints in the problem, respectively.
# get the information of the result
obj = solution.objective
df = solution.decision_variables_df
const = solution.constraints_df
print(f"Objective value : {obj}")
print(f"Decision variakbles : \n {df}")
print(f"Constraints : \n {const}")
Objective value : 12.0
Decision variakbles :
kind lower upper name subscripts description substituted_value value
id
0 Binary 0.0 1.0 x [0] <NA> <NA> 0.0
1 Binary 0.0 1.0 x [1] <NA> <NA> 0.0
2 Binary 0.0 1.0 x [2] <NA> <NA> 1.0
3 Binary 0.0 1.0 x [3] <NA> <NA> 1.0
4 Binary 0.0 1.0 x [4] <NA> <NA> 1.0
Constraints :
equality value used_ids name subscripts description \
id
0 =0 0.0 {1, 3} eq_const [0] <NA>
1 =0 0.0 {0, 2, 4} eq_const [1] <NA>
2 =0 0.0 {0, 1, 2, 3, 4} eq_const [2] <NA>
dual_variable removed_reason
id
0 <NA> <NA>
1 <NA> <NA>
2 <NA> <NA>