Source code for UFLP_test

"""Tests the UFLP-related machinery (:py:mod:`UFLP_2_cav` and :py:mod:`UFL`).

Note:
    The module requires Gurobi solver.
"""
import pytest
import numpy as np
from gurobipy import GRB
from BDD import simscore

import UFL
from UFLP_2_cav import gen_special_jUFLP


[docs]def gen_UFL_instance(n, m): """Generates a test facility location instance. Args: n (int): number of facilities m (int): number of customers Returns: A tuple with the following values. - S (list): neighborhood list - f (dict): costs of facility location (generated uniformly random int from `f_min` to `f_max`) - g (dict): overlap costs, keys: (customer, overlap) """ N = [i for i in range(1, n+1)] M = [j for j in range(1, m+1)] good_instance = False while not good_instance: S = [np.random.choice(N, np.random.randint(1, n+1), replace=False).tolist() for j in M] f = {i: np.random.randint(5, 10) for i in N} g = dict() for j in M: g[(j, 0)] = np.random.randint(2*n, 4*n) g[(j, 1)] = 0 for k in range(2, len(S[j-1])+1): g[(j, k)] = g[(j, k-1)] + \ np.random.randint(low=1, high=2+int(5*len(S[j-1])/j)) Sf = UFL.build_Sf(S) if np.sum([1 for i in N if i not in Sf]) == 0: good_instance = True return S, f, g
[docs]@pytest.mark.parametrize("test_inst", [gen_UFL_instance(np.random.randint(1, 15), np.random.randint(1, 15)) for _ in range(100)]) def test_MIPs(test_inst): """Tests that MIPs return the same objectives.""" S, f, g = test_inst print(f"S={S}; f={f}; g={g}") model = UFL.build_MIP(S, f, g) model.setParam("OutputFlag", 0) model.optimize() assert model.status == GRB.OPTIMAL plain_MIP_obj = model.objVal # Generate and solve CPP MIP C = UFL.create_covering_BDD_wg(S, g) A = UFL.create_availability_BDD(S, f) model, c, v, x = UFL.add_BDD_to_MIP(A, prefix="A_") model, c, v, x = UFL.add_BDD_to_MIP(C, model=model, x=x, prefix="C_") model.update() model.setParam("OutputFlag", 0) model.optimize() assert model.status == GRB.OPTIMAL CPP_MIP_obj = model.objVal assert abs(CPP_MIP_obj - plain_MIP_obj) < 1e-3
[docs]@pytest.mark.parametrize("test_inst", [gen_UFL_instance(np.random.randint(1, 15), np.random.randint(1, 15)) for _ in range(100)]) def test_DPs(test_inst): """Tests the DP-inspired diagrams.""" S, f, g = test_inst print(f"S={S}; f={f}; g={g}") model = UFL.build_MIP(S, f, g) model.setParam("OutputFlag", 0) model.optimize() assert model.status == GRB.OPTIMAL plain_MIP_obj = model.objVal # Generate and solve CPP MIP D, _ = UFL.build_DP_DD(S, f, g) model, c, v = UFL.create_NF(D) model.update() model.setParam("OutputFlag", 0) model.optimize() assert model.status == GRB.OPTIMAL assert abs(model.objVal - plain_MIP_obj) < 1e-3
[docs]@pytest.mark.parametrize("param", [np.random.rand() for _ in range(100)]) def test_cluster_reverse_custom(param): """Tests the jUFLP-instance-generation procedure (for the given number of inversions).""" i1, i2, jm = gen_special_jUFLP(2, 12, 0.35, "cluster-reverse-custom", "cavemen", param) _, _, _, ca1 = i1 _, _, _, ca2 = i2 for c in range(len(ca1)): assert abs(simscore(ca1[c], [jm[j] for j in ca1[c]]) - param) < 0.025