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))
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()
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()
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()
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))))
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