def init_attribute(self): # check if the initial solutions have been set data_temp = self._parameter.get_init_samples() i = 0 if data_temp != None and self._best_solution == None: for j in range(len(data_temp)): x = self._objective.construct_solution(data_temp[j]) self._objective.eval(x) self._data.append(x) ToolFunction.log(" init solution %s, eval %s" % (i, x.get_value())) i += 1 # otherwise generate random solutions iteration_num = self._parameter.get_train_size() while i < iteration_num: # distinct_flag: True means sample is distinct(can be use), # False means sample is distinct, you should sample again. x, distinct_flag = self.distinct_sample_from_set( self._objective.get_dim(), self._data, data_num=iteration_num) # panic stop if x is None: break if distinct_flag: self._objective.eval(x) self._data.append(x) i += 1 self.selection() return
def distinct_sample(self, dim, data_list, check_distinct=True, data_num=0): """ Sample a distinct solution(compared with solutions in set) from dim. :param dim: a Dimension object :param set: a list containing other solutions :param check_distinct: whether to check the sampled solution is distinct :param data_num: the maximum number to sample :return: sampled solution and distinct_flag(True if distinct) """ objective = self._objective x = objective.construct_solution(dim.rand_sample()) times = 1 distinct_flag = True if check_distinct is True: while self.is_distinct(data_list, x) is False: x = objective.construct_solution(dim.rand_sample()) times += 1 if times % 10 == 0: limited, number = dim.limited_space() if limited is True: if number <= data_num: ToolFunction.log( 'racos_common.py: WARNING -- sample space has been fully enumerated. Stop early' ) return None, None if times > 100: distinct_flag = False break return x, distinct_flag
def distinct_sample_from_set(self, dim, set, check_distinct=True, data_num=0): objective = self._objective x = objective.construct_solution(dim.rand_sample()) times = 1 distinct_flag = True if check_distinct is True: while self.is_distinct(set, x) is False: x = objective.construct_solution(dim.rand_sample()) times += 1 if times % 10 == 0: limited, number = dim.limited_space() if limited is True: if number <= data_num: ToolFunction.log( 'racos_common.py: WARNING -- sample space has been fully enumerated. Stop early' ) return None, None if times > 100: distinct_flag = False break return x, distinct_flag
def min(objective, parameter): """ Minimization function. :param objective: an Objective object :param parameter: a Parameter object :return: the result of the optimization """ objective.parameter_set(parameter) Opt.set_global(parameter) constraint = objective.get_constraint() algorithm = parameter.get_algorithm() if algorithm: algorithm = algorithm.lower() result = None if constraint is not None and ((algorithm is None) or (algorithm == "poss")): optimizer = ParetoOptimization() elif constraint is None and ((algorithm is None) or (algorithm == "racos") or (algorithm == "sracos")) or (algorithm == "ssracos"): optimizer = RacosOptimization() else: ToolFunction.log( "opt.py: No proper algorithm found for %s" % algorithm) return result if objective.get_reducedim() is True: sre = SequentialRandomEmbedding(objective, parameter, optimizer) result = sre.opt() else: result = optimizer.opt(objective, parameter) return result
def rand_sample(self): """ Random sample in the search space. :return: a sampled x """ x = [] for i in range(self._size): if self._types[i]: __str_x = str(self._order_or_precision[i]) __precision_len = None if 'e' in __str_x or 'E' in __str_x: __precision_len = int(__str_x.split('e-')[-1]) elif '.' in __str_x: __precision_len = len(__str_x.split('.')[-1]) elif self._order_or_precision[i] == 1: __precision_len = 0 elif self._order_or_precision[ i] % 10 == 0 and self._order_or_precision[i] != 0: __precision_len = 1 - len(__str_x) else: ToolFunction.log( 'sample wrong, float_precision is invalid!') value = round( np.random.uniform(self._regions[i][0], self._regions[i][1]), __precision_len) else: value = np.random.randint(self._regions[i][0], self._regions[i][1] + 1) x.append(value) return x
def distinct_sample_classifier(self, classifier, data_list, check_distinct=True, data_num=0): """ Sample a distinct solution from a classifier. """ x = classifier.rand_sample() sol = self._objective.construct_solution(x) times = 1 distinct_flag = True if check_distinct is True: while self.is_distinct(data_list, sol) is False: x = classifier.rand_sample() sol = self._objective.construct_solution(x) times += 1 if times % 10 == 0: if times == 10: space = classifier.get_sample_space() limited, number = space.limited_space() if limited is True: if number <= data_num: ToolFunction.log( 'racos_common: WARNING -- sample space has been fully explored. Stop early' ) return None, None if times > 100: distinct_flag = False break return sol, distinct_flag
def auto_set(self, budget): """ Set train_size, positive_size, negative_size by following rules: budget < 3 --> error; budget: 4-50 --> train_size = 4, positive_size = 1; budget: 51-100 --> train_size = 6, positive_size = 1; budget: 101-1000 --> train_size = 12, positive_size = 2; budget > 1001 --> train_size = 22, positive_size = 2; :param budget: number of calls to the objective function :return: no return value """ if budget < 3: ToolFunction.log('parameter.py: budget too small') sys.exit(1) elif budget <= 50: self.__train_size = 4 self.__positive_size = 1 elif budget <= 100: self.__train_size = 6 self.__positive_size = 1 elif budget <= 1000: self.__train_size = 12 self.__positive_size = 2 else: self.__train_size = 22 self.__positive_size = 2 self.__negative_size = self.__train_size - self.__positive_size
def set_region(self, index, reg, ty): if index > self._size - 1: ToolFunction.log('dimension.py: index out of bound') return self._regions[index] = reg self._types[index] = ty return
def distinct_sample_classifier(self, classifier, check_distinct=True, data_num=0): x = classifier.rand_sample() ins = self._objective.construct_solution(x) times = 1 distinct_flag = True if check_distinct is True: while self.is_distinct(self._positive_data, ins) is False or \ self.is_distinct(self._negative_data, ins) is False: x = classifier.rand_sample() ins = self._objective.construct_solution(x) times += 1 if times % 10 == 0: if times == 10: space = classifier.get_sample_space() limited, number = space.limited_space() if limited is True: if number <= data_num: ToolFunction.log( 'racos_common: WARNING -- sample space has been fully enumerated. Stop early' ) return None, None if times > 100: distinct_flag = False break return ins, distinct_flag
def opt(self): """ Sequential random embedding optimization. :return: the best solution of the optimization """ dim = self.__objective.get_dim() res = [] iteration = self.__parameter.get_num_sre() new_obj = copy.deepcopy(self.__objective) new_par = copy.deepcopy(self.__parameter) new_par.set_budget(math.floor(self.__parameter.get_budget()/iteration)) new_obj.set_last_x(Solution(x=[0])) for i in range(iteration): ToolFunction.log('sequential random embedding %d' % i) new_obj.set_A(np.sqrt(self.__parameter.get_variance_A()) * np.random.randn(dim.get_size(), self.__parameter.get_low_dimension().get_size())) new_dim = Dimension.merge_dim(self.__parameter.get_withdraw_alpha(), self.__parameter.get_low_dimension()) new_obj.set_dim(new_dim) result = self.__optimizer.opt(new_obj, new_par) x = result.get_x() x_origin = x[0] * np.array(new_obj.get_last_x().get_x()) + np.dot(new_obj.get_A(), np.array(x[1:])) sol = Solution(x=x_origin, value=result.get_value()) new_obj.set_last_x(sol) res.append(sol) best_sol = res[0] for i in range(len(res)): if res[i].get_value() < best_sol.get_value(): best_sol = res[i] self.__objective.get_history().extend(new_obj.get_history()) return best_sol
def eval(self, solution, intermediate_print=False, times=0, freq=100): val = self.__func(solution) solution.set_value(val) self.__history.append(solution.get_value()) solution.set_post_attach(self.__post_inherit()) if intermediate_print is True and times % freq == 0: ToolFunction.log(("budget %d, fx result: " % times) + str(val)) ToolFunction.log("x: " + str(solution.get_x()))
def print_sample_region(self): """ Print sample region. :return: no return value """ ToolFunction.log('------print sample region------') ToolFunction.log(self.__sample_region)
def print_neg(self): """ Print negative population. :return: no return value """ ToolFunction.log('------print neg------') for x in self.__negative_solution: x.print_solution()
def parallel_init_attribute(self, unevaluated_queue, evaluated_queue): """ Init self._data, self._positive_data, self._negative_data by sampling. :return: no return value """ self._parameter.set_negative_size(self._parameter.get_train_size() - self._parameter.get_positive_size()) # check if the initial solutions have been set data_temp = self._parameter.get_init_samples() sampled_data = [] ini_size = 0 if data_temp is not None: ini_size = len(data_temp) eval_num = 0 iteration_num = self._parameter.get_train_size() if data_temp is not None and self._best_solution is None: for j in range(min(ini_size, iteration_num)): if isinstance(data_temp[j], Solution) is False: sol = self._objective.construct_solution(data_temp[j]) else: sol = data_temp[j] if math.isnan(sol.get_value()): unevaluated_queue.put(sol, block=True, timeout=None) eval_num += 1 else: self._data.append(sol) for i in range(0, eval_num): sol = evaluated_queue.get(block=True, timeout=None) ToolFunction.log("init solution %s, value: %s" % (i, sol.get_value())) self._data.append(sol) sampled_data.append(sol) # otherwise generate random solutions t = ini_size while t < iteration_num: # distinct_flag: True means sample is distinct(can be use), # False means sample is distinct, you should sample again. sol, distinct_flag = self.distinct_sample( self._objective.get_dim(), sampled_data, data_num=iteration_num) # panic stop if sol is None: break if distinct_flag: unevaluated_queue.put(sol, block=True, timeout=None) sampled_data.append(sol) t += 1 t = ini_size while t < iteration_num: sol = evaluated_queue.get(block=True, timeout=None) self._data.append(sol) t += 1 self.selection() return
def print_dim(self): """ Print the dimension information. :return: no return value """ ToolFunction.log('dim size: %d' % self._size) ToolFunction.log('dim regions is:') ToolFunction.log(self._regions) ToolFunction.log('dim types is:') ToolFunction.log(self._types)
def print_pos(self): """ Print positive population. :return: no return value """ ToolFunction.log('------print pos------') for x in self.__positive_solution: x.print_solution()
def print_solution_set(sol_set): """ Print the value of each solution in an solution set. :param sol_set: solution set :return: no return value """ for sol in sol_set: ToolFunction.log('value: %f' % (sol.get_value())) return
def judge_match(size, regs, tys): """ Check if the size of regs and tys are both the same as self._size. :return: True or False """ if size != len(regs) or size != len(tys): ToolFunction.log('dimension.py: dimensions do not match') return False else: return True
def show_best_solution(self, intermediate_print=False, times=0, freq=100): """ Show intermediate best solutions every 'freq' evaluation. :param intermediate_print: whether to show :param times: current iteration time :param freq: frequency :return: no return value """ if intermediate_print is True and times % freq == 0: ToolFunction.log(("budget %d, fx result: " % times) + str(self._best_solution.get_value())) ToolFunction.log("x: " + str(self._best_solution.get_x()))
def min(objective, parameter, repeat=1, best_n=None, plot=False, plot_file=None, seed=None): """ Minimization function. :param objective: an Objective object :param parameter: a Parameter object :param repeat: integer, repeat times of the optimization :param best_n: integer, ExpOpt.min will print average value and standard deviation of best_n optimal results among returned solution list. :param plot: whether to plot regret curve during the optimization :param plot_file: the file name to output the figure :param seed: random seed of the optimization :return: a best_solution set """ objective.parameter_set(parameter) ret = [] if best_n is None: best_n = repeat if seed is not None: gl.set_seed(seed) # set random seed result = [] for i in range(repeat): # perform the optimization solution = Opt.min(objective, parameter) ret.append(solution) ToolFunction.log('solved solution is:') solution.print_solution() # store the optimization result result.append(solution.get_value()) # for plotting the optimization history history = np.array( objective.get_history_bestsofar()) # init for reducing if plot is True: plt.plot(history) objective.clean_history() if plot is True: if plot_file is not None: plt.savefig(plot_file) else: plt.show() ExpOpt.result_analysis(result, best_n) return ret
def update_classifier(self, solution, strategy='WR'): stopping_criterion = self._parameter.get_stopping_criterion() bad_ele = self.replace(self._positive_data, solution, 'pos') self.replace(self._negative_data, bad_ele, 'neg', strategy) self._best_solution = self._positive_data[0] # terminal_value check if self._parameter.get_terminal_value() is not None: if self._best_solution.get_value() <= self._parameter.get_terminal_value(): ToolFunction.log('terminal function value reached') return self._best_solution if stopping_criterion.check(self) is True: return self._best_solution return self._best_solution
def min(objective, parameter): Opt.set_global(parameter) constraint = objective.get_constraint() algorithm = parameter.get_algorithm() if algorithm: algorithm = algorithm.lower() result = None if constraint is not None and ((algorithm is None) or (algorithm == "poss")): optimizer = ParetoOptimization() result = optimizer.opt(objective, parameter) elif constraint is None and ((algorithm is None) or (algorithm == "racos")): optimizer = RacosOptimization() result = optimizer.opt(objective, parameter) else: ToolFunction.log("opt.py: No proper algorithm find for %s" % algorithm) return result
def get_sample_space(self): if type(self.__solution_space) == Dimension: size = self.__solution_space.get_size() regions = self.__sample_region types = self.__solution_space.get_types() return Dimension(size, regions, types) elif type(self.__solution_space) == Dimension2: types = self.__solution_space.get_types() regions = self.__sample_region order_or_precision = self.__solution_space.get_order_or_precision() dim_li = [] for i in range(len(types)): dim_li.append((types[i], regions[i], order_or_precision[i])) return Dimension2(dim_li) else: ToolFunction.log('get sample space wrong')
def opt(self, objective, parameter, strategy='WR', ub=1): self.clear() self.set_objective(objective) self.set_parameters(parameter) self.init_attribute() i = 0 iteration_num = self._parameter.get_budget( ) - self._parameter.get_train_size() while i < iteration_num: if i == 0: time_log1 = time.time() if gl.rand.random() < self._parameter.get_probability(): classifier = RacosClassification(self._objective.get_dim(), self._positive_data, self._negative_data, ub) classifier.mixed_classification() ins, distinct_flag = self.distinct_sample_classifier( classifier, True, self._parameter.get_train_size()) else: ins, distinct_flag = self.distinct_sample( self._objective.get_dim()) # panic stop if ins is None: return self._best_solution if distinct_flag is False: continue # evaluate the solution objective.eval(ins) bad_ele = self.replace(self._positive_data, ins, 'pos') self.replace(self._negative_data, bad_ele, 'neg', strategy) self._best_solution = self._positive_data[0] #with open('/home/zhangc/ICRA/base_policy/Thrower/100test_best_action_solution.txt','a') as f: #f.write(str(self._best_solution.get_value())+'\n') #with open('/home/zhangc/AAAI/base_policy/Thrower/retrain_100Thrower30_solution.txt','a') as f: #f.write(str(self._best_solution.get_value())+'\n') if i == 4: time_log2 = time.time() expected_time = (self._parameter.get_budget() - self._parameter.get_train_size()) * \ (time_log2 - time_log1) / 5 if expected_time > 5: m, s = divmod(expected_time, 60) h, m = divmod(m, 60) ToolFunction.log( 'expected remaining running time: %02d:%02d:%02d' % (h, m, s)) i += 1 return self._best_solution
def __init__(self, dim_list=[]): """ Initialization. :param dim_list: a list of dimensions for continuous dimension: (type, range, float_precision) e.g.: (ValueType.CONTINUOUS, [0, 1], 1e-6) for discrete dimension: (type, range, has_partial_order) e.g.: (ValueType.DISCRETE, [0, 1], False) for grid dimension: (type, values) e.g.: (ValueType.GRID, ['first value', 'second value']) """ gl.float_precisions = [] self._size = len(dim_list) self._regions = list(map(lambda x: x[1], dim_list)) self._types = list(map(lambda x: x[0], dim_list)) self._order_or_precision = list( map(lambda x: x[2] if len(x) == 3 else None, dim_list)) # Note: for grid valuetype, len(x)=2 for _dim in dim_list: if _dim[0] == ValueType.CONTINUOUS: _str_x = str(_dim[2]) _precision_len = None if _dim[2] == 1: _precision_len = 0 elif _dim[2] > 1: if 'e+' in _str_x: _precision_len = 0 - int(_str_x.split('e+')[-1]) else: _precision_len = 1 - len(str(int(_dim[2]))) else: assert _dim[2] != 0, "input float_precision must not be 0!" if 'e-' in _str_x: _precision_len = int(_str_x.split('e-')[-1]) elif '.' in _str_x: _precision_len = len(_str_x.split('.')[-1]) else: ToolFunction.log( 'sample wrong, input float_precision is invalid!') gl.float_precisions.append(_precision_len) else: gl.float_precisions.append(None) return
def auto_set(self, budget): if budget < 3: ToolFunction.log('parameter.py: budget too small') sys.exit(1) elif budget <= 50: self.__train_size = 4 self.__positive_size = 1 elif budget <= 100: self.__train_size = 6 self.__positive_size = 1 elif budget <= 1000: self.__train_size = 12 self.__positive_size = 2 else: self.__train_size = 22 self.__positive_size = 2 self.__negative_size = self.__train_size - self.__positive_size
def opt(self, objective, parameter, ub=1): self.clear() self.set_objective(objective) self.set_parameters(parameter) self.init_attribute() t = self._parameter.get_budget() / self._parameter.get_negative_size() for i in range(t): if i == 0: time_log1 = time.time() j = 0 iteration_num = len(self._negative_data) while j < iteration_num: if gl.rand.random() < self._parameter.get_probability(): classifier = RacosClassification(self._objective.get_dim(), self._positive_data, self._negative_data, ub) classifier.mixed_classification() solution, distinct_flag = self.distinct_sample_classifier( classifier, True, self._parameter.get_train_size()) else: solution, distinct_flag = self.distinct_sample( self._objective.get_dim()) # panic stop if solution is None: return self._best_solution # If the solution had been sampled, skip it if distinct_flag is False: continue # evaluate the solution objective.eval(solution) self._data.append(solution) j += 1 self.selection() self._best_solution = self._positive_data[0] # display expected running time if i == 4: time_log2 = time.time() expected_time = t * (time_log2 - time_log1) / 5 if expected_time > 5: m, s = divmod(expected_time, 60) h, m = divmod(m, 60) ToolFunction.log( 'expected remaining running time: %02d:%02d:%02d' % (h, m, s)) return self._best_solution
def init_attribute(self): """ Init self._data, self._positive_data, self._negative_data by sampling. :return: no return value """ self._parameter.set_negative_size(self._parameter.get_train_size() - self._parameter.get_positive_size()) # check if the initial solutions have been set data_temp = self._parameter.get_init_samples() i = 0 iteration_num = self._parameter.get_train_size() if data_temp is not None and self._best_solution is None: size = len(data_temp) if iteration_num < size: size = iteration_num for j in range(size): if isinstance(data_temp[j], Solution) is False: x = self._objective.construct_solution(data_temp[j]) else: x = data_temp[j] if math.isnan(x.get_value()): self._objective.eval(x) self._data.append(x) ToolFunction.log("init solution %s, value: %s" % (i, x.get_value())) i += 1 # otherwise generate random solutions while i < iteration_num: # distinct_flag: True means sample is distinct(can be use), # False means sample is distinct, you should sample again. x, distinct_flag = self.distinct_sample(self._objective.get_dim(), self._data, data_num=iteration_num) # panic stop if x is None: break if distinct_flag: self._objective.eval(x) self._data.append(x) i += 1 self.selection() return
def result_analysis(results, top): """ Get mean value and standard deviation of best 'top' results. :param results: a list of results :param top: the number of best results used to calculate mean value and standard deviation :return: mean value and standard deviation of best 'top' results """ limit = top if top < len(results) else len(results) results.sort() top_k = results[0:limit] mean_r = np.mean(top_k, axis=0, dtype=np.float64) std_r = np.std(top_k, axis=0, dtype=np.float64) if limit <= 1: ToolFunction.log('Best %d result: %s +- %s' % (limit, mean_r, std_r)) else: ToolFunction.log('Best %d results: %s +- %s' % (limit, mean_r, std_r)) return mean_r, std_r
def rand_sample(self): """ Random sample from self.__solution_space.get_dim(). :return: sampled x """ if type(self.__solution_space) == Dimension: x = copy.deepcopy(self.__x_positive.get_x()) for index in self.__label_index: if self.__solution_space.get_type(index) is True: x[index] = np.random.uniform(self.__sample_region[index][0], self.__sample_region[index][1]) else: x[index] = np.random.randint(self.__sample_region[index][0], self.__sample_region[index][1] + 1) return x elif type(self.__solution_space) == Dimension2: x = copy.deepcopy(self.__x_positive.get_x()) all_precision = self.__solution_space.get_order_or_precision() for index in self.__label_index: # continuous if self.__solution_space.get_type(index): _str_x = str(all_precision[index]) _precision_len = None if 'e' in _str_x or 'E' in _str_x: _precision_len = int(_str_x.split('e-')[-1]) elif '.' in _str_x: _precision_len = len(_str_x.split('.')[-1]) elif all_precision[index] == 1: _precision_len = 0 elif all_precision[index] % 10 == 0 and all_precision[index] != 0: _precision_len = 1 - len(_str_x) else: ToolFunction.log('sample wrong, float_precision is invalid!') x[index] = round(np.random.uniform(self.__sample_region[index][0], self.__sample_region[index][1]), _precision_len) # discrete else: x[index] = np.random.randint(self.__sample_region[index][0], self.__sample_region[index][1] + 1) return x