def prepare_once(self, project_name : str, form : str, method : str, option : Dict[str, Any] = None) -> None: self.__project = project_name self.__method = method self.__form = form if method in self.jmetal_solvers: type = 'jmetal' # dump config in /dump/ folder Runner.dump_config(project_name, form, option) else: type = 'default' self.__nrp = NextReleaseProblem(project_name, type) self.__problem = self.__nrp.model(form, option) self.__solver = Solver(method, option) self.__solver.load(self.__problem) # empty solutions self.__solutions = None
def test_single_general(self): for project_name in ALL_FILES_DICT.keys(): if not project_name.startswith('classic'): continue # get content and modelling nrp = NextReleaseProblem(project_name) moip = nrp.model('single', {'b': 0.5}) cost, profit, _, requests = nrp.content() # check for counts assert moip.objectiveCount == 1 assert moip.featureCount == len(cost) + len(profit) constant_id = moip.featureCount # check for equations assert moip.sparseEquationsMapList == [dict()] # check for objective assert len(moip.objectiveSparseMapList) == 1 neo_profit = { k: -v for k, v in moip.objectiveSparseMapList[0].items() } assert neo_profit == profit # check for inequations assert len(moip.sparseInequationsMapList) == len( moip.sparseInequationSensesList) assert moip.sparseInequationSensesList == ['L'] * len( moip.sparseInequationSensesList) # construct new requests from inequations neo_requests = [] cost_inequation = None for inequation in moip.sparseInequationsMapList: if len(inequation) == 3: # constant == 0 assert inequation[constant_id] == 0 # request neo_requests.append(self.unzip_inequation(inequation)) else: assert not cost_inequation cost_inequation = inequation assert set(neo_requests) == set(requests) # check for cost_inequation assert not cost_inequation[constant_id] - sum( cost.values()) * 0.5 > 10e-6 assert not cost_inequation[constant_id] - sum( cost.values()) * 0.5 < -10e-6 del cost_inequation[constant_id] assert cost_inequation == cost
def test_bi_general(self): for project_name in ALL_FILES_DICT.keys(): if not project_name.startswith( 'classic') and not project_name.startswith('realistic'): continue # get content nrp = NextReleaseProblem(project_name) # modelling moip = nrp.model('binary') cost, profit, _, requests = nrp.content() # check for counts assert moip.objectiveCount == 2 assert moip.featureCount == len(cost) + len(profit) constant_id = moip.featureCount # check for objective assert len(moip.objectiveSparseMapList) == 2 neo_profit = { k: -v for k, v in moip.objectiveSparseMapList[0].items() } assert neo_profit == profit neo_cost = { k: v for k, v in moip.objectiveSparseMapList[1].items() } assert neo_cost == cost # check for inequations assert len(moip.sparseInequationsMapList) == len( moip.sparseInequationSensesList) assert moip.sparseInequationSensesList == ['L'] * len( moip.sparseInequationSensesList) # construct new requests from inequations neo_requests = [] for inequation in moip.sparseInequationsMapList: # length == 3 assert len(inequation) == 3 # constant == 0 assert inequation[constant_id] == 0 # request neo_requests.append(self.unzip_inequation(inequation)) assert set(neo_requests) == set(requests)
def test_xuan_encoding(self): for project_name in ALL_FILES_DICT.keys(): if not project_name.startswith( 'classic') and not project_name.startswith('realistic'): continue # get content nrp = NextReleaseProblem(project_name) if project_name.startswith('classic'): nrp.flatten() cost, profit, dependencies, requests = deepcopy(nrp.content()) # encoding req_encoder, cus_encoder = nrp.xuan_reencode() # get content again neo_cost, neo_profit, neo_dependencies, neo_requests = nrp.content( ) # check if encoding is one-one mapping assert len(set(req_encoder.values())) == len(req_encoder) assert len(set(cus_encoder.values())) == len(cus_encoder) assert not dependencies and not neo_dependencies # construct decoder of encoder req_decoder = dict( zip(list(req_encoder.values()), list(req_encoder.keys()))) cus_decoder = dict( zip(list(cus_encoder.values()), list(cus_encoder.keys()))) # decode neo_cost de_cost = dict() for req, req_cost in neo_cost.items(): de_cost[req_decoder[req]] = req_cost # decode neo_profit de_profit = dict() for cus, cus_profit in neo_profit.items(): de_profit[cus_decoder[cus]] = cus_profit # decode requests de_requests = [] for cus, req in neo_requests: de_requests.append((cus_decoder[cus], req_decoder[req])) # compare assert cost == de_cost assert profit == de_profit assert set(requests) == set(de_requests)
def test_case_3(self): # prepare raw problem variables = [0, 1, 2, 3] objectives = [{0: -10, 1: -5, 2: -1, 3: -5}, {0: 3, 1: 2, 2: 3, 3: 0}] constraints = dict() # prepare solvers for solver_name in self.binary_solver: if solver_name == 'epsilon': problem = NextReleaseProblem.MOIP( \ variables, objectives, constraints, \ dict(), dict() \ ) else: constraints = JNRP.regularize_constraints( constraints, len(variables)) problem = JNRP(variables, objectives, constraints) solver = Solver(solver_name) # prepare and solve solver.load(problem) solver.execute() # get the solutions solutions = solver.solutions() print(solver_name + '\t\t' + str(len(solutions))) self.display(solutions, 5)
def test_case_2(self): # prepare raw problem variables = [0, 1, 2, 3] objectives = [{0: -10, 1: -5, 2: -1, 3: 5}] constraints = [{2: 1, 4: 0}, {0: 1, 3: -1, 4: 0}] # prepare solvers for solver_name in self.single_solver: if solver_name == 'single': problem = NextReleaseProblem.MOIP( \ variables, objectives, constraints, \ ['L' for _ in range(len(constraints))], dict() \ ) else: constraints = JNRP.regularize_constraints( constraints, len(variables)) problem = JNRP(variables, objectives, constraints) solver = Solver(solver_name) # prepare and solve solver.load(problem) solver.execute() # get the solutions solutions = solver.solutions() print(solver_name + '\t\t' + str(len(solutions))) self.display(solutions, 5)
def test_flatten(self): for project_name in ALL_FILES_DICT.keys(): # get content nrp = NextReleaseProblem(project_name) cost, profit, dependencies, requests = deepcopy(nrp.content()) # only test who has dependencies if not dependencies or len(dependencies) == 0: continue # flatten nrp.flatten() # get content again neo_cost, neo_profit, neo_dependencies, neo_requests = nrp.content( ) # cost and profit should not be changed assert neo_cost == cost assert neo_profit == profit # dependencies should be empty assert not neo_dependencies or len(neo_dependencies) == 0 # now check requests # depdencies, request => neo_requests for cus, req in requests: # this cus, req should in new requests assert (cus, req) in neo_requests # find all requirement that require this req requesters = self.requester(dependencies, req) # find all customers for requester in list(requesters): assert (cus, requester) in neo_requests # neo_requests, dependencies => requests for cus, req in neo_requests: if (cus, req) in requests: pass # no problem else: # find all requestees requestees = self.requestee(dependencies, req) # print(list(requestees)) flag = False for requestee in list(requestees): if (cus, requestee) in requests: flag = True break assert flag
def test_find_demands(self): for project_name in ALL_FILES_DICT.keys(): if not project_name.startswith( 'classic') and not project_name.startswith('realistic'): continue # get content nrp = NextReleaseProblem(project_name) if project_name.startswith('classic'): nrp.flatten() # construct demands requests = nrp.content()[3] demands = NextReleaseProblem.find_demands(requests) # demands => requests for key, values in demands.items(): for value in values: assert (value, key) in requests # requests => demands for key, value in requests: assert value in demands assert key in demands[value]
class Runner: # initialize def __init__(self, configs : List[ConfigType], out_path : str): # not changed member self.__result = dict() # prepare const members # jmetal solvers self.jmetal_solvers = MOEA_METHOD # prepare members self.__project : str = None self.__method : str = None self.__form : str = None self.__nrp : NextReleaseProblem = None self.__problem : ProblemType = None self.__solver : Solver = None self.__solutions : Set[Any] = None # config should be a list assert isinstance(configs, list) # check out_path if exists os.makedirs(os.path.dirname(out_path), exist_ok=True) # run the configurations for one_config in configs: # get the ite_num from config ite_num = one_config['ite_num'] del one_config['ite_num'] assert ite_num > 0 # config name config_name = self.name(**one_config) print(config_name + ' will run ' + str(ite_num) + ' times') # check the config if not self.check_config(**one_config): print('FATAL: illegal config input ' + config_name) continue # each config run ite_num times for ind in range(ite_num): # run this config print('round: ', ind) self.run_once(one_config, config_name, ind) # dump solutions each round self.dump_once(out_path, config_name, ind) # print out message that each round has ended print('\r\t\t\t\t\t\t\t\t\t\t\t\t\r' + config_name + ' finished') # dump result self.dump(out_path, ite_num, False) # check config def check_config(self, project_name : str, form : str, method : str, option : Dict[str, Any] = None) -> bool: check = True # check config if project_name not in ALL_FILES_DICT: check = False if form not in NRP_FORMS: check = False if method not in SOLVING_METHOD: check = False # prepare message message = 'config: project:' + project_name + ' form: ' + form + ' method: ' + method if option: message += ' option: ' + str(option) if not check: # print out print(message, ' fail') return False else: print(message, ' start') return True # clear def clear(self) -> None: self.__project = None self.__method = None self.__form = None self.__nrp = None self.__problem = None self.__solver = None self.__solutions = None # run once def run_once(self, config : ConfigType, name : str, ind : int) -> None: # this config name # print('\r\t\t\t\t\t\t\t\t\t\t\t\t\r' + name + ' round: ' + str(ind), end='') print(name + ' round: ' + str(ind)) # clear all members self.clear() # prepare_config self.prepare_once(**config) # run elapsed_time = self.run() # collect results self.__solutions = self.__solver.solutions() if ind == 0: # first round, initialize self.__result[name] = dict() # record self.__result[name][str(ind)] = dict() self.__result[name][str(ind)]['runtime'] = elapsed_time self.__result[name][str(ind)]['solution number'] = len(self.__solutions) self.__result[name][str(ind)]['solutions'] = self.__solutions # just for debug # self.__result[name][str(ind)] = dict() # self.__result[name][str(ind)] ['runtime'] = 3.33 # self.__result[name][str(ind)] ['solution number'] = 100 # self.__result[name][str(ind)] ['solutions'] = set([(1,2), (3,4), (5,6), (7,8), (9,0)]) # prepare once def prepare_once(self, project_name : str, form : str, method : str, option : Dict[str, Any] = None) -> None: self.__project = project_name self.__method = method self.__form = form if method in self.jmetal_solvers: type = 'jmetal' # dump config in /dump/ folder Runner.dump_config(project_name, form, option) else: type = 'default' self.__nrp = NextReleaseProblem(project_name, type) self.__problem = self.__nrp.model(form, option) self.__solver = Solver(method, option) self.__solver.load(self.__problem) # empty solutions self.__solutions = None # dump solutions once def dump_once(self, out_path : str, name : str, ind : int): # exact output path exact_path = os.path.join(out_path, name) # check if result folder exists if not os.path.exists(exact_path): os.makedirs(exact_path) # prepare the solution file file_name = os.path.join(exact_path, str(ind)+'.txt') assert name in self.__result assert str(ind) in self.__result[name] assert 'solutions' in self.__result[name][str(ind)] # write to file with open(file_name, 'w') as file_out: for solution in list(self.__result[name][str(ind)]['solutions']): file_out.write(str(solution)+'\n') # delete it in checklist for saving memory del self.__result[name][str(ind)]['solutions'] # write a runtime info. file file_name = os.path.join(exact_path, 'info_'+str(ind)+'.json') with open(file_name, 'w') as info_file: json_object = json.dumps(self.__result[name][str(ind)], indent = 4) info_file.write(json_object) info_file.close() # run! just run! def run(self) -> float: start = time.clock() self.__solver.execute() end = time.clock() return end - start # display solutions def display(self, mode : bool = False) -> None: # print solution number found print('number of solutions found: ' + str(len(self.__solutions))) if not mode: return # print each solution for solution in self.__solutions: print(str(solution) + ', ') # dump jmetal config @staticmethod def dump_config(project_name : str, form : str, option : Dict[str, Any]) -> None: # prepare the new option dict neo_option = dict() for key, value in option.items(): if not value: # None neo_option[key] = 'n' elif isinstance(value, int): # int neo_option[key] = 'i' + str(value) elif isinstance(value, float): # float neo_option[key] = 'f' + str(value) else: assert False # end for json_object = json.dumps(neo_option, indent=4) # create DUMP PATH if not exists if not os.path.exists(os.path.dirname(DUMP_PATH)): os.makedirs(DUMP_PATH) # prepare file name file_name = os.path.join(DUMP_PATH, ('config_' + project_name + '_' + form + '.json')) # create config file with open(file_name, 'w+') as file_out: file_out.write(json_object) file_out.close() # end with # config name @staticmethod def name(project_name : str, form : str, method : str, option : Dict[str, Any] = None) -> str: name_str = project_name + '_' + form + '_' + method option_str = '' if option: for k, v in option.items(): option_str += '_' + str(k) + str(v) return name_str + option_str # parse name to config # Note that if there are options, it will just return the string # because we cannot know it's structure here @staticmethod def dename(name : str) -> None: # name should be a string assert isinstance(name, str) # parse the project name first project_name = None for project in ALL_FILES_DICT: if name.startswith(project): project_name = project name = name[len(project)+1:] assert project_name # split by '_' args = name.split('_') assert len(args) >= 2 # note that if length == 2, [2:] will be an empty list return {'project' : project_name, 'form' : args[0], 'method' : args[1], 'option' : args[2:]} # dump all solutions def dump(self, out_path : str, ite_num : int, write_solutions : bool = False) -> None: # result folder should already there assert os.path.exists(os.path.dirname(out_path)) # wirte solution if mode is True if write_solutions: for name, content in self.__result.items(): # prepare each result folder exact_path = os.path.join(out_path, name) os.makedirs(exact_path, exist_ok=True) for ind in range(ite_num): # simple check assert ind in content assert 'solutions' in content[ind] # prepare file solution_file = open(os.path.join(exact_path, str(ind)+'.txt'), "w+") # write into file for solution in list(content[str(ind)]['solutions']): solution_file.write(str(solution) + '\n') solution_file.close() del content[str(ind)]['solutions'] # write checklist checklist_file = open(os.path.join(out_path, 'checklist.json'), 'w+') json_object = json.dumps(self.__result, indent = 4) checklist_file.write(json_object) checklist_file.close()
def test_single_stakeholder(self): for project_name in ALL_FILES_DICT.keys(): if not project_name.startswith('realistic'): continue # get content nrp = NextReleaseProblem(project_name) # modelling moip = nrp.model('single', {'b': 0.5}) cost, profit, _, requests = nrp.content() # check for counts assert moip.objectiveCount == 1 assert moip.featureCount == len(cost) + len(profit) constant_id = moip.featureCount # check for equations assert moip.sparseEquationsMapList == [dict()] # check for objective assert len(moip.objectiveSparseMapList) == 1 neo_profit = { k: -v for k, v in moip.objectiveSparseMapList[0].items() } assert neo_profit == profit # check for inequations assert len(moip.sparseInequationsMapList) == len( moip.sparseInequationSensesList) assert moip.sparseInequationSensesList == ['L'] * len( moip.sparseInequationSensesList) # construct new requests from inequations neo_requests = [] neo_demands = dict() cost_inequation = None # get demands demands = NextReleaseProblem.find_demands(requests) for inequation in moip.sparseInequationsMapList: if inequation[constant_id] != 0: assert not cost_inequation cost_inequation = inequation else: # either request or xj - Sum yi <= 0 # get a positive key to have a look key = self.positive_one(inequation) assert key != None if key in cost: # xj - Sum yi <= 0 demands_list = self.negative_ones(inequation) assert demands_list neo_demands[key] = demands_list elif key in profit: # request # length == 3 assert len(inequation) == 3 # constant == 0 assert inequation[constant_id] == 0 # request neo_requests.append(self.unzip_inequation(inequation)) else: assert False assert neo_demands == demands assert set(neo_requests) == set(requests) # check for cost_inequation assert not cost_inequation[constant_id] - sum( cost.values()) * 0.5 > 10e-6 assert not cost_inequation[constant_id] - sum( cost.values()) * 0.5 < -10e-6 del cost_inequation[constant_id] assert cost_inequation == cost
def test_inventory(self): for project_name in ALL_FILES_DICT.keys(): # assert is in NRP initialization nrp = NextReleaseProblem(project_name)