def binary_tournament(pop, P, algorithm): if P.shape[1] != 2: raise ValueError("Only implemented for binary tournament!") tournament_type = algorithm.tournament_type S = np.full(P.shape[0], np.nan) for i in range(P.shape[0]): a, b = P[i, 0], P[i, 1] if tournament_type == 'comp_by_dom_and_crowding': rel = Dominator.get_relation(pop[a].F, pop[b].F) if rel == 1: S[i] = a elif rel == -1: S[i] = b elif tournament_type == 'comp_by_rank_and_crowding': S[i] = compare(a, pop[a].rank, b, pop[b].rank, method='smaller_is_better') else: raise Exception("Unknown tournament type.") if np.isnan(S[i]): S[i] = compare(a, pop[a].get("crowding"), b, pop[b].get("crowding"), method='larger_is_better', return_random_if_equal=True) return S[:, None].astype(np.int)
def update_PCpop(pc_pop, off): pc_objs = pc_pop.get("F") off_objs = off.get("F") n = pc_objs.shape[0] del_ind = [] for i in range(n): flag = Dominator.get_relation(off_objs[0, :], pc_objs[i, :]) if flag == 1: # off dominates pc_pop[i] del_ind.append(i) break elif flag == -1: # pc_pop[i] dominates off return pc_pop else: # flag == 0 # off and pc_pop[i] are nondominated break if len(del_ind) > 0: pc_index = np.arange(n) # Delete element at index positions given by the list 'del_ind' pc_index = np.delete(pc_index, del_ind) pc_pop = pc_pop[pc_index.tolist()] pc_pop = Population.merge(pc_pop, off) return pc_pop
def sequential_search(F, i, fronts) -> int: """ Find the front rank for the i-th individual through sequential search Parameters ---------- F: np.ndarray the objective values i: int the index of the individual fronts: list individuals in each front """ num_found_fronts = len(fronts) k = 0 # the front now checked current = F[i] while True: if num_found_fronts == 0: return 0 # solutions in the k-th front, examine in reverse order fk_indices = fronts[k] solutions = F[fk_indices[::-1]] non_dominated = True for f in solutions: relation = Dominator.get_relation(current, f) if relation == -1: non_dominated = False break if non_dominated: return k else: k += 1 if k >= num_found_fronts: # move the individual to a new front return num_found_fronts
def naive_non_dominated_sort(F, **kwargs): M = Dominator.calc_domination_matrix(F) fronts = [] remaining = set(range(M.shape[0])) while len(remaining) > 0: front = [] for i in remaining: is_dominated = False dominating = set() for j in front: rel = M[i, j] if rel == 1: dominating.add(j) elif rel == -1: is_dominated = True break if is_dominated: continue else: front = [x for x in front if x not in dominating] front.append(i) [remaining.remove(e) for e in front] fronts.append(front) return fronts
def comp_by_dom_and_crowding(pop, P, crowding, **kwargs): if P.shape[1] != 2: raise ValueError("Only implemented for binary tournament!") S = np.zeros((P.shape[0], 1), dtype=np.int) for i, p in enumerate(P): rel = Dominator.get_relation(pop.F[P[i, 0], :], pop.F[P[i, 1], :]) # first by domination if rel == 1: S[i, 0] = P[i, 0] elif rel == -1: S[i, 0] = P[i, 1] # then by crowding else: if crowding[P[i, 0]] > crowding[P[i, 1]]: S[i, 0] = P[i, 0] elif crowding[P[i, 1]] > crowding[P[i, 0]]: S[i, 0] = P[i, 1] else: S[i, 0] = P[i, random.randint(0, 2)] return S
def binary_tournament(pop, P, algorithm, **kwargs): n_tournaments, n_parents = P.shape if n_parents != 2: raise ValueError("Only implemented for binary tournament!") tournament_type = algorithm.tournament_type S = np.full(n_tournaments, np.nan) for i in range(n_tournaments): a, b = P[i, 0], P[i, 1] a_cv, a_f, b_cv, b_f, = pop[a].CV[0], pop[a].F, pop[b].CV[0], pop[b].F rank_a, cd_a = pop[a].get("rank", "crowding") rank_b, cd_b = pop[b].get("rank", "crowding") # if at least one solution is infeasible if a_cv > 0.0 or b_cv > 0.0: S[i] = compare(a, a_cv, b, b_cv, method='smaller_is_better', return_random_if_equal=True) # both solutions are feasible else: if tournament_type == 'comp_by_dom_and_crowding': rel = Dominator.get_relation(a_f, b_f) if rel == 1: S[i] = a elif rel == -1: S[i] = b elif tournament_type == 'comp_by_rank_and_crowding': S[i] = compare(a, rank_a, b, rank_b, method='smaller_is_better') else: raise Exception("Unknown tournament type.") # if rank or domination relation didn't make a decision compare by crowding if np.isnan(S[i]): S[i] = compare(a, cd_a, b, cd_b, method='larger_is_better', return_random_if_equal=True) return S[:, None].astype(int, copy=False)
def binary_tournament(pop, P, algorithm, **kwargs): if P.shape[1] != 2: raise ValueError("Only implemented for binary tournament!") tournament_type = algorithm.tournament_type S = np.full(P.shape[0], np.nan) for i in range(P.shape[0]): a, b = P[i, 0], P[i, 1] # if at least one solution is infeasible if pop[a].CV > 0.0 or pop[b].CV > 0.0: S[i] = compare( a, pop[a].CV, b, pop[b].CV, method="smaller_is_better", return_random_if_equal=True, ) # both solutions are feasible else: if tournament_type == "comp_by_dom_and_crowding": rel = Dominator.get_relation(pop[a].F, pop[b].F) if rel == 1: S[i] = a elif rel == -1: S[i] = b elif tournament_type == "comp_by_rank_and_crowding": S[i] = compare( a, pop[a].rank, b, pop[b].rank, method="smaller_is_better" ) else: raise Exception("Unknown tournament type.") # if rank or domination relation didn't make a decision compare by crowding if np.isnan(S[i]): S[i] = compare( a, pop[a].get("crowding"), b, pop[b].get("crowding"), method="larger_is_better", return_random_if_equal=True, ) return S[:, None].astype(np.int)
def binary_search(F, i, fronts): """ Find the front rank for the i-th individual through binary search. Parameters ---------- F: np.ndarray the objective values i: int the index of the individual fronts: list individuals in each front """ num_found_fronts = len(fronts) if num_found_fronts == 0: return 0 k_min = 0 # the lower bound for checking k_max = num_found_fronts # the upper bound for checking k = floor((k_max + k_min) / 2 + 0.5) # the front now checked current = F[i] while True: # solutions in the k-th front, examine in reverse order fk_indices = fronts[k - 1] solutions = F[fk_indices[::-1]] non_dominated = True for f in solutions: relation = Dominator.get_relation(current, f) if relation == -1: non_dominated = False break # binary search if non_dominated: if k == k_min + 1: return k - 1 else: k_max = k k = floor((k_max + k_min) / 2 + 0.5) else: k_min = k if k_max == k_min + 1 and k_max < num_found_fronts: return k_max - 1 elif k_min == num_found_fronts: return num_found_fronts else: k = floor((k_max + k_min) / 2 + 0.5)
def comp_by_dom_and_crowding(pop, indices, data): if len(indices) != 2: raise ValueError("Only implemented for binary tournament!") first = indices[0] second = indices[1] rel = Dominator.get_relation(pop.F[first, :], pop.F[second, :]) if rel == 1: return first elif rel == -1: return second else: if data.crowding[first] > data.crowding[second]: return first elif data.crowding[second] > data.crowding[first]: return second else: return indices[random.randint(0, 2)]
def comp_by_cv_dom_then_random(pop, P, **kwargs): S = np.full(P.shape[0], np.nan) for i in range(P.shape[0]): a, b = P[i, 0], P[i, 1] if pop[a].CV <= 0.0 and pop[b].CV <= 0.0: rel = Dominator.get_relation(pop[a].F, pop[b].F) if rel == 1: S[i] = a elif rel == -1: S[i] = b else: S[i] = np.random.choice([a, b]) elif pop[a].CV <= 0.0: S[i] = a elif pop[b].CV <= 0.0: S[i] = b else: S[i] = np.random.choice([a, b]) return S[:, None].astype(np.int)
def find_non_dominated(F, _F=None): M = Dominator.calc_domination_matrix(F, _F) I = np.where(np.all(M >= 0, axis=1))[0] return I
def fast_non_dominated_sort(F, **kwargs): M = Dominator.calc_domination_matrix(F) # calculate the dominance matrix n = M.shape[0] fronts = [] if n == 0: return fronts # final rank that will be returned n_ranked = 0 ranked = np.zeros(n, dtype=int) # for each individual a list of all individuals that are dominated by this one is_dominating = [[] for _ in range(n)] # storage for the number of solutions dominated this one n_dominated = np.zeros(n) current_front = [] for i in range(n): for j in range(i + 1, n): rel = M[i, j] if rel == 1: is_dominating[i].append(j) n_dominated[j] += 1 elif rel == -1: is_dominating[j].append(i) n_dominated[i] += 1 if n_dominated[i] == 0: current_front.append(i) ranked[i] = 1.0 n_ranked += 1 # append the first front to the current front fronts.append(current_front) # while not all solutions are assigned to a pareto front while n_ranked < n: next_front = [] # for each individual in the current front for i in current_front: # all solutions that are dominated by this individuals for j in is_dominating[i]: n_dominated[j] -= 1 if n_dominated[j] == 0: next_front.append(j) ranked[j] = 1.0 n_ranked += 1 fronts.append(next_front) current_front = next_front return fronts
def train(self, x, f, cross_val=False, *args, **kwargs): # f = (f - np.min(f))/(np.max(f)-np.min(f)) f_normalized = self.normalize.normalize(f, self.dataset_func) kf = KFold(n_splits=self.n_splits) best_acc = 0 best_loss = np.inf if self.dataset_func is False: cv = np.copy(f_normalized) index = np.any(f_normalized > 0, axis=1) cv[f_normalized <= 0] = 0 cv = np.sum(cv, axis=1) acv = np.sum(f_normalized, axis=1) acv[index] = np.copy(cv[index]) g_label = cv > 0 g_label[cv <= 0] = -1 # g_label = g > 0 # g_label[g <= 0] = -1 g_label = g_label.astype(int) g_label = np.vstack(g_label) # cross-validation for train_index, test_index in kf.split(x): train_data_x, test_data_x, train_data_f, test_data_f \ = x[train_index], x[test_index], f_normalized[train_index], f_normalized[test_index] if self.dataset_func: self.train_dominance_matrix = Dominator.calc_domination_matrix( f_normalized[train_index]) self.test_dominance_matrix = Dominator.calc_domination_matrix( f_normalized[test_index]) else: train_data_cv, test_data_cv, train_g_label, test_g_label, \ = torch.from_numpy(cv[train_index]), torch.from_numpy(cv[test_index]), \ torch.from_numpy(g_label[train_index]), torch.from_numpy(g_label[test_index]) train_data_x, test_data_x, train_data_f, test_data_f \ = torch.from_numpy(train_data_x), torch.from_numpy(test_data_x), torch.from_numpy(train_data_f), \ torch.from_numpy(test_data_f) train_indices = torch.from_numpy( np.asarray(range(0, train_data_x.shape[0]))) test_indices = torch.from_numpy( np.asarray(range(0, test_data_x.shape[0]))) if self.dataset_func: self.trainset = DatasetFunction(train_indices, train_data_x, train_data_f) self.testset = DatasetFunction(test_indices, test_data_x, test_data_f) else: self.trainset = DatasetConstraint(train_indices, train_data_x, train_data_f, train_g_label) self.testset = DatasetConstraint(test_indices, test_data_x, test_data_f, test_g_label) self.trainloader = torch.utils.data.DataLoader( self.trainset, batch_size=self.batch_size, shuffle=True) self.testloader = torch.utils.data.DataLoader( self.testset, batch_size=self.batch_size, shuffle=True) self.net = copy.deepcopy(self.neuralnet) self.optimizer = optim.Adam(self.net.parameters(), lr=0.01, weight_decay=5e-1, betas=(0.9, 0.999)) self.scheduler = CosineAnnealingLR(self.optimizer, T_max=self.total_epoch, eta_min=1e-7) model, acc, loss = self.train_partition() if self.best_accuracy_model: if acc > best_acc: self.model = model else: if loss < best_loss: self.model = model if not self.cross_val: break return self.model
def calc_as_fronts(F, G=None, only_pareto_front=False): """ try: import pygmo as pg ndf, dl, dc, ndr = pg.fast_non_dominated_sorting(F) except ImportError: pass """ # calculate the dominance matrix n = F.shape[0] M = Dominator.calc_domination_matrix(F, G) fronts = [] # final rank that will be returned n_ranked = 0 ranked = np.zeros(n, dtype=np.int) # for each individual a list of all individuals that are dominated by this one is_dominating = [[] for _ in range(n)] # storage for the number of solutions dominated this one n_dominated = np.zeros(n) current_front = [] for i in range(n): for j in range(i + 1, n): rel = M[i, j] if rel == 1: is_dominating[i].append(j) n_dominated[j] += 1 elif rel == -1: is_dominating[j].append(i) n_dominated[i] += 1 if n_dominated[i] == 0: current_front.append(i) ranked[i] = 1.0 n_ranked += 1 if only_pareto_front: return current_front # append the first front to the current front fronts.append(current_front) # while not all solutions are assigned to a pareto front while n_ranked < n: next_front = [] # for each individual in the current front for i in current_front: # all solutions that are dominated by this individuals for j in is_dominating[i]: n_dominated[j] -= 1 if n_dominated[j] == 0: next_front.append(j) ranked[j] = 1.0 n_ranked += 1 fronts.append(next_front) current_front = next_front return fronts