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;
}