Models a capacitated facility location problem and solves it with idol's branch-and-bound algorithm. Each node is solved by GLPK. Reduced cost fixing is used.
We consider the capacitated Facility Location Problem (FLP). Given a set of potential facility locations \(V_1\) and a set of customers \(V_2\), the goal is to select a subset of facility location to activate so as to serve the customers' demand. In doing so, costs should be minimized.
\[
\begin{aligned}
\min_{x,y} \quad & \sum_{i\in V_1} f_ix_i + \sum_{i\in V_1} \sum_{j\in V_2} c_{ij} d_j y_{ij} \\
\text{s.t.} \quad & \sum_{j\in V_2} d_jy_{ij} \le q_i x_i, \quad \text{for all } i\in V_1, \\
& \sum_{i\in V_1} y_{ij} = 1, \quad \text{for all } j\in V_2, \\
& x_i \in \{0,1\}, \quad \text{for all } i\in V_1, \\
& y_{ij} \in \{0,1\}, \quad \text{for all } i\in V_1, j\in V_2.
\end{aligned}
\]
In the following code, we show how this problem can be solved using idol's branch-and-bound algorithm.
#include <iostream>
#include "idol/modeling.h"
#include "idol/mixed-integer/optimizers/branch-and-bound/BranchAndBound.h"
#include "idol/mixed-integer/optimizers/branch-and-bound/branching-rules/factories/PseudoCost.h"
#include "idol/mixed-integer/optimizers/branch-and-bound/node-selection-rules/factories/BestBound.h"
#include "idol/mixed-integer/optimizers/branch-and-bound/branching-rules/factories/MostInfeasible.h"
#include "idol/mixed-integer/optimizers/callbacks/ReducedCostFixing.h"
#include "idol/mixed-integer/optimizers/wrappers/GLPK/GLPK.h"
using namespace idol;
int main(int t_argc, const char** t_argv) {
const Vector<double> fixed_costs { 109.6, 169.5, 24.8, 150.3, 140.7, 68.8, 5.4, 123.2, 118.5, 27.6, };
const Vector<double> capacities { 131.5, 103.5, 41.8, 156.5, 128.5, 66.1, 33.7, 114.0, 152.3, 125.6, };
const Vector<double> demands { 36.2, 5.6, 10.0, 20.2, 17.5, 35.8, 14.9, 2.8, 36.7, 2.8, 12.1, 16.3, 11.4, 9.0, 32.2, 13.8, 0.6, 26.9, 36.5, 10.0, };
const Vector<double, 2> transportation_costs {
{0.7, 0.4, 0.6, 0.7, 0.3, 0.6, 0.6, 0.6, 0.3, 0.3, 0.4, 0.6, 0.8, 0.6, 0.4, 0.2, 0.4, 0.3, 0.5, 0.4, },
{0.8, 0.1, 0.3, 0.8, 0.7, 0.5, 0.7, 0.8, 0.2, 0.5, 0.2, 0.8, 0.8, 0.5, 0.6, 0.2, 0.6, 0.1, 0.8, 0.7, },
{1.0, 0.5, 0.7, 1.0, 0.4, 0.9, 0.9, 0.9, 0.2, 0.6, 0.6, 0.9, 1.1, 0.9, 0.7, 0.3, 0.7, 0.4, 0.7, 0.5, },
{0.8, 0.9, 1.1, 1.0, 0.3, 1.1, 0.9, 0.6, 0.8, 0.5, 0.9, 0.7, 1.0, 1.1, 0.6, 0.7, 0.5, 0.8, 0.1, 0.2, },
{0.0, 0.7, 0.7, 0.2, 0.8, 0.6, 0.2, 0.2, 0.9, 0.4, 0.6, 0.1, 0.2, 0.5, 0.2, 0.7, 0.3, 0.7, 0.6, 0.8, },
{0.4, 0.4, 0.4, 0.3, 0.7, 0.3, 0.2, 0.5, 0.6, 0.3, 0.3, 0.4, 0.4, 0.3, 0.3, 0.4, 0.3, 0.3, 0.7, 0.7, },
{1.0, 0.6, 0.9, 1.1, 0.3, 1.0, 1.0, 0.9, 0.3, 0.6, 0.7, 1.0, 1.1, 1.0, 0.7, 0.4, 0.7, 0.5, 0.7, 0.4, },
{0.1, 0.6, 0.6, 0.2, 0.8, 0.5, 0.2, 0.3, 0.8, 0.3, 0.5, 0.1, 0.2, 0.4, 0.2, 0.6, 0.2, 0.6, 0.6, 0.8, },
{0.8, 0.6, 0.9, 0.9, 0.1, 0.9, 0.8, 0.7, 0.5, 0.4, 0.7, 0.8, 0.9, 0.9, 0.5, 0.4, 0.5, 0.5, 0.4, 0.2, },
{0.7, 0.3, 0.5, 0.7, 0.4, 0.6, 0.7, 0.7, 0.2, 0.4, 0.3, 0.7, 0.8, 0.6, 0.5, 0.0, 0.5, 0.2, 0.6, 0.5, },
};
const auto n_facilities = fixed_costs.size();
const auto n_customers = demands.size();
const bool use_reduced_cost_fixing = true;
auto x = model.add_vars(
Dim<1>(n_facilities), 0., 1., Binary, 0.,
"x");
auto y = model.add_vars(
Dim<2>(n_facilities, n_customers), 0., 1., Binary, 0.,
"y");
for (unsigned int i = 0 ; i < n_facilities ; ++i) {
model.add_ctr(idol_Sum(j,
Range(n_customers), demands[j] * y[i][j]) <= capacities[i] * x[i]);
}
for (unsigned int j = 0 ; j < n_customers ; ++j) {
model.add_ctr(idol_Sum(i,
Range(n_facilities), y[i][j]) == 1);
}
model.set_obj_expr(idol_Sum(i,
Range(n_facilities),
fixed_costs[i] * x[i]
+ idol_Sum(j,
Range(n_customers),
transportation_costs[i][j] * demands[j] * y[i][j]
)
)
);
branch_and_bound.with_node_optimizer(GLPK::ContinuousRelaxation());
branch_and_bound.with_node_selection_rule(
BestBound());
branch_and_bound.with_branching_rule(
PseudoCost());
if (use_reduced_cost_fixing) {
}
model.use(branch_and_bound);
model.optimize();
std::cout << "Status: " << model.get_status() << std::endl;
std::cout << "Objective value:\n" << model.get_best_obj() << std::endl;
return 0;
}