def test_example_get_load_based_on_integral_solution(self):
     scenario = datamodel.Scenario("test_scenario", self.substrate, [self.request],
                                   objective=datamodel.Objective.MIN_COST)
     mc_mip = mip.ClassicMCFModel(scenario)
     mc_mip.init_model_creator()
     sol = mc_mip.compute_integral_solution().solution
     mc_ecg = modelcreator_ecg_decomposition.ModelCreatorCactusDecomposition(sol.scenario)
     mc_ecg.init_model_creator()
     mc_ecg.fix_mapping_variables_according_to_integral_solution(sol)
     mc_ecg.model.optimize()
     assert mc_mip.model.getAttr(GRB.Attr.ObjVal) == pytest.approx(mc_ecg.model.getAttr(GRB.Attr.ObjVal))
예제 #2
0
    def test_edge_mapping_on_multiple_edges_model(self):
        # SUBSTRATE: - NODES
        self.substrate.add_node('u', ["DPI"],
                                capacity={"DPI": 2},
                                cost={"DPI": 2})
        self.substrate.add_node('v', ["FW"],
                                capacity={"FW": 2},
                                cost={"FW": 2})
        self.substrate.add_node('w', ["X"], capacity={"X": 2}, cost={"X": 2})
        self.substrate.add_edge('u', 'v', capacity=9)
        self.substrate.add_edge('v', 'w', capacity=9)

        self.request.profit = 1
        self.request.add_node('i', 2, "DPI")
        self.request.add_node('j', 2, "X")
        # REQUEST LATENCY
        self.request.add_edge('i', 'j', 1)
        mc = mip.ClassicMCFModel(self.scenario)
        mc.init_model_creator()
예제 #3
0
 def test_init_model_cheap(self):
     # SUBSTRATE: - NODES
     self.substrate.add_node('v1', ["DPI"],
                             capacity={
                                 "FW": 2,
                                 "DPI": 2
                             },
                             cost={
                                 "FW": 2,
                                 "DPI": 2
                             })
     self.substrate.add_node('v2', ["FW"],
                             capacity={"FW": 2},
                             cost={"FW": 2})
     self.substrate.add_node('v3', ["FW"],
                             capacity={
                                 "FW": 2,
                                 "DPI": 2
                             },
                             cost={
                                 "FW": 2,
                                 "DPI": 2
                             })
     #           - EDGES
     self.substrate.add_edge('v1', 'v2', capacity=2)
     self.substrate.add_edge('v2', 'v3', capacity=2)
     self.substrate.add_edge('v3', 'v1', capacity=2)
     # REQUEST NODES AND EDGES
     self.request.profit = 5
     self.request.add_node('i1', 2, "FW", allowed_nodes=['v2'])
     self.request.add_node('i2', 2, "DPI")
     self.request.add_node('i3', 2, "FW")
     self.request.add_edge('i1', 'i2', 2)
     self.request.add_edge('i2', 'i3', 2)
     mc = mip.ClassicMCFModel(self.scenario)
     mc.init_model_creator()
예제 #4
0
 def test_no_edge_mapping_model(self):
     # SUBSTRATE: - NODES
     self.substrate.add_node('u', ["FW", "DPI"],
                             capacity={
                                 "FW": 2,
                                 "DPI": 2
                             },
                             cost={
                                 "FW": 2,
                                 "DPI": 2
                             })
     self.substrate.add_node('v', ["FW"],
                             capacity={"FW": 2},
                             cost={"FW": 2})
     #           - EDGES
     self.substrate.add_edge('u', 'v', capacity=2)
     # REQUEST NODES AND EDGES
     self.request.profit = 1
     self.request.add_node('i', 2, "FW")
     self.request.add_node('j', 2, "DPI")
     self.request.add_edge('i', 'j', 2)
     # REQUEST LATENCY
     mc = mip.ClassicMCFModel(self.scenario)
     mc.init_model_creator()
예제 #5
0
def test_opt_dynvmp_and_classic_mcf_agree_for_unambiguous_scenario(
        request_id, random_seed, allowed_nodes_ratio, allowed_edges_ratio):
    random.seed(random_seed)
    print("allowed nodes: {} %, allowed edges: {} %".format(
        100 * allowed_nodes_ratio, 100 * allowed_edges_ratio))
    req = create_test_request(request_id, set_allowed_nodes=False)
    node_type = "test_type"
    sub = create_test_substrate_topology_zoo(node_types=[node_type])
    assert set(sub.get_types()) == {node_type}

    num_allowed_nodes = int(allowed_nodes_ratio * len(sub.nodes))
    for i in req.nodes:
        assert req.get_type(i) == node_type
        req.node[i]["allowed_nodes"] = random.sample(list(sub.nodes),
                                                     num_allowed_nodes)

    num_allowed_edges = int(allowed_edges_ratio * len(sub.edges))
    for ij in req.edges:
        req.edge[ij]["allowed_edges"] = random.sample(list(sub.edges),
                                                      num_allowed_edges)

    snode_costs = {}
    sedge_costs = {}

    def randomize_substrate_costs():
        # randomize all costs to force unambiguous cost-optimal embedding
        for u in sub.nodes:
            for t in sub.get_supported_node_types(u):
                sub.node[u]["cost"][t] = random.random()
                snode_costs[u] = sub.node[u]["cost"][t]
        for uv in sub.edges:
            sub.edge[uv]["cost"] = random.random()
            sedge_costs[uv] = sub.edge[uv]["cost"]

    randomize_substrate_costs()

    td_comp = treewidth_model.TreeDecompositionComputation(req)
    tree_decomp = td_comp.compute_tree_decomposition()
    sntd = treewidth_model.SmallSemiNiceTDArb(tree_decomp, req)
    opt_dynvmp = treewidth_model.OptimizedDynVMP(sub, req, sntd, snode_costs,
                                                 sedge_costs)
    times_dynvmp = []
    start_time = time.time()
    opt_dynvmp.initialize_data_structures()
    opt_dynvmp.compute_solution()
    root_cost, mapping = opt_dynvmp.recover_mapping()
    times_dynvmp.append(time.time() - start_time)

    number_of_tests = 10

    times_gurobi = []

    for x in range(number_of_tests):

        def compare_solutions():
            if root_cost is not None:  # solution exists
                assert gurobi_solution is not None
                gurobi_obj = gurobi_solution.status.objValue
                assert abs(root_cost - gurobi_obj) <= 0.0001
                assert mapping.mapping_nodes == gurobi_solution.solution.request_mapping[
                    req].mapping_nodes
                assert mapping.mapping_edges == gurobi_solution.solution.request_mapping[
                    req].mapping_edges
            else:
                assert gurobi_solution is None

        start_time = time.time()
        gurobi = mip.ClassicMCFModel(
            dm.Scenario("test", sub, [req], objective=dm.Objective.MIN_COST))
        gurobi.init_model_creator()
        gurobi_solution = gurobi.compute_integral_solution()
        times_gurobi.append(time.time() - start_time)

        compare_solutions()

        randomize_substrate_costs()

        start_time = time.time()
        opt_dynvmp.reinitialize(snode_costs, sedge_costs)
        opt_dynvmp.compute_solution()
        root_cost, mapping = opt_dynvmp.recover_mapping()
        times_dynvmp.append(time.time() - start_time)

    gurobi = mip.ClassicMCFModel(
        dm.Scenario("test", sub, [req], objective=dm.Objective.MIN_COST))
    gurobi.init_model_creator()
    gurobi_solution = gurobi.compute_integral_solution()

    compare_solutions()

    initial_computation_time = times_dynvmp[0]
    other_computation_times = times_dynvmp[1:]
    average_of_others = sum(other_computation_times) / float(
        len(other_computation_times))
    print(
        ("        Request graph size (|V|,|E|):  ({},{})\n"
         "             Width of the request is:  {}\n"
         "      Runtime of initial computation:  {:02.4f} s\n"
         "Runtime of later computations (avg.):  {:02.4f} s\n"
         "               This is a speed-up of:  {:02.2f} times\n"
         "               Total time in Dyn-VMP:  {:02.4f} s\n"
         "                Total time in Gurobi:  {:02.4f} s\n"
         "         Speedup Dyn-VMP over Gurobi:  {:02.2f} times (>1 is good)\n"
         .format(len(req.nodes), len(req.edges), sntd.width,
                 initial_computation_time, average_of_others,
                 initial_computation_time / average_of_others,
                 sum(times_dynvmp), sum(times_gurobi),
                 sum(times_gurobi) / sum(times_dynvmp))))
예제 #6
0
def test_opt_dynvmp(request_id):
    req = create_test_request(request_id, set_allowed_nodes=False)
    sub = create_test_substrate_topology_zoo()
    # assert that all nodes and all edges may be mapped anywhere...
    substrate_node_set = set(sub.nodes)
    substrate_edge_set = set(sub.edges)

    # set substrate node and edge capacities high
    for snode in sub.nodes:
        for type in list(sub.node[snode]['capacity'].keys()):
            sub.node[snode]['capacity'][type] = 100

    for sedge in sub.edges:
        sub.edge[sedge]['capacity'] = 100

    snode_list = list(sub.nodes)
    sedge_list = list(sub.edges)
    valid_reqnode_list = [
        snode for snode in sub.nodes if sub.get_node_capacity(snode) > 1.01
    ]

    # # now additionally also introduce some mapping restrictions
    for reqnode in req.nodes:
        random.shuffle(valid_reqnode_list)

        selected_nodes = []
        while len(selected_nodes) == 0:
            print("selected nodes are {}".format(selected_nodes))
            selected_nodes = valid_reqnode_list[
                0:random.randint(10, len(valid_reqnode_list))]
        req.set_allowed_nodes(reqnode, selected_nodes)
        print("Allowd nodes for {} are {}.".format(
            reqnode, req.get_allowed_nodes(reqnode)))
    for reqedge in req.edges:
        random.shuffle(sedge_list)
        req.set_allowed_edges(
            reqedge, sedge_list[0:random.randint(20, len(sedge_list))])
        print("Allowd edges for {} are {}.".format(
            reqedge, req.get_allowed_edges(reqedge)))

    # random edge costs
    edge_costs = {
        sedge: max(1, 1000.0 * random.random())
        for sedge in sub.edges
    }
    for sedge in sub.edges:
        sub.edge[sedge]['cost'] = 1  # edge_costs[sedge]
    for snode in sub.nodes:
        for type in list(sub.node[snode]['cost'].keys()):
            sub.node[snode]['cost'][type] = 1

    scenario = dm.Scenario("test", sub, [req])
    gurobi = mip.ClassicMCFModel(scenario)
    gurobi.init_model_creator()
    gurobi.model.setParam("LogToConsole", 1)
    gurobi.compute_integral_solution()

    td_comp = treewidth_model.TreeDecompositionComputation(req)
    tree_decomp = td_comp.compute_tree_decomposition()
    assert tree_decomp.is_tree_decomposition(req)
    sntd = treewidth_model.SmallSemiNiceTDArb(tree_decomp, req)
    assert sntd.is_tree_decomposition(req)

    opt_dynvmp = treewidth_model.OptimizedDynVMP(sub, req, sntd)
    opt_dynvmp.initialize_data_structures()
    opt_dynvmp.compute_solution()

    obj = opt_dynvmp.get_optimal_solution_cost()
    if obj is not None:
        costs, mapping_indices = opt_dynvmp.get_ordered_root_solution_costs_and_mapping_indices(
            maximum_number_of_solutions_to_return=100)
        for index, cost in np.ndenumerate(costs):
            if index == 0:
                assert cost == obj
            print("{}-th best cost is: {} and index is {}".format(
                index, cost, mapping_indices[index]))
        corresponding_mappings = opt_dynvmp.recover_list_of_mappings(
            mapping_indices)
        print("Number of obtained mappings: {}, mappings: {}".format(
            len(corresponding_mappings), corresponding_mappings))

    result_mapping = opt_dynvmp.recover_mapping()
    print("Returned mapping! Namely, the following: {}".format(result_mapping))

    # change costs
    snode_costs = opt_dynvmp.snode_costs
    sedge_costs = opt_dynvmp.sedge_costs
    for snode in list(snode_costs.keys()):
        snode_costs[snode] *= 2
    for sedge in list(sedge_costs.keys()):
        sedge_costs[sedge] *= 2

    opt_dynvmp.reinitialize(snode_costs, sedge_costs)
    opt_dynvmp.compute_solution()
    result_mapping = opt_dynvmp.recover_mapping()
    print("Returned mapping! Namely, the following: {}".format(result_mapping))
    def test_ecg_and_mcf_should_obtain_same_solution_when_variables_are_fixed(
            self):
        real_scenario = self.make_real_scenario()
        real_scenario.objective = datamodel.Objective.MAX_PROFIT
        time_limit = 200

        mc_preprocess = mip.ClassicMCFModel(real_scenario)
        mc_preprocess.init_model_creator()
        mc_preprocess.set_gurobi_parameter(modelcreator.Param_TimeLimit,
                                           time_limit)
        sol_preprocess = mc_preprocess.compute_integral_solution().solution

        usable_requests = [
            req for req in real_scenario.requests
            if sol_preprocess.request_mapping[req].is_embedded
        ]
        assert len(usable_requests) != 0

        real_scenario.requests = usable_requests
        real_scenario.objective = datamodel.Objective.MIN_COST

        # First, compute solution using MCF model and fix variables of Decomposition
        mc_mcf = mip.ClassicMCFModel(real_scenario)
        mc_mcf.init_model_creator()
        mc_mcf.set_gurobi_parameter(modelcreator.Param_TimeLimit, time_limit)
        sol_mcf = mc_mcf.compute_integral_solution().get_solution()
        sol_mcf.validate_solution_fulfills_capacity()

        assert any(m.is_embedded
                   for m in list(sol_mcf.request_mapping.values()))

        mc_ecg_fixed_mapping = modelcreator_ecg_decomposition.ModelCreatorCactusDecomposition(
            real_scenario)
        mc_ecg_fixed_mapping.init_model_creator()
        mc_ecg_fixed_mapping.set_gurobi_parameter(modelcreator.Param_TimeLimit,
                                                  time_limit)
        mc_ecg_fixed_mapping.fix_mapping_variables_according_to_integral_solution(
            sol_mcf)
        sol_ecg_fixed_mapping = mc_ecg_fixed_mapping.compute_integral_solution(
        )

        assert mc_mcf.model.objVal == pytest.approx(
            mc_ecg_fixed_mapping.model.objVal)
        for req in usable_requests:
            mcf_mapping = sol_mcf.request_mapping[req]
            ecg_mapping = sol_ecg_fixed_mapping.get_solution(
            ).request_mapping[req]
            print(mcf_mapping.mapping_nodes)
            print(ecg_mapping.mapping_nodes)
            assert mcf_mapping.mapping_nodes == ecg_mapping.mapping_nodes
            assert mcf_mapping.mapping_edges == ecg_mapping.mapping_edges

        # compute solution using Decomposition and fix variables of MCF model
        mc_ecg_fixed_mapping = modelcreator_ecg_decomposition.ModelCreatorCactusDecomposition(
            real_scenario)
        mc_ecg_fixed_mapping.init_model_creator()
        mc_ecg_fixed_mapping.set_gurobi_parameter(modelcreator.Param_TimeLimit,
                                                  time_limit)
        sol_ecg = mc_ecg_fixed_mapping.compute_integral_solution(
        ).get_solution()

        assert any(m.is_embedded
                   for m in list(sol_ecg.request_mapping.values()))

        mc_mcf_fixed_mapping = mip.ClassicMCFModel(real_scenario)
        mc_mcf_fixed_mapping.init_model_creator()
        mc_mcf_fixed_mapping.set_gurobi_parameter(modelcreator.Param_TimeLimit,
                                                  time_limit)
        mc_mcf_fixed_mapping.fix_mapping_variables_according_to_integral_solution(
            sol_ecg)
        sol_mcf_fixed_mapping = mc_mcf_fixed_mapping.compute_integral_solution(
        ).solution
        sol_mcf_fixed_mapping.validate_solution_fulfills_capacity()

        assert mc_mcf_fixed_mapping.model.objVal == pytest.approx(
            mc_ecg_fixed_mapping.model.objVal)
        for req in usable_requests:
            mcf_mapping = sol_mcf_fixed_mapping.request_mapping[req]
            ecg_mapping = sol_ecg.request_mapping[req]
            assert mcf_mapping.mapping_nodes == ecg_mapping.mapping_nodes
            assert mcf_mapping.mapping_edges == ecg_mapping.mapping_edges