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)
Beispiel #2
0
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
Beispiel #5
0
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
Beispiel #6
0
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)
Beispiel #7
0
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)
Beispiel #8
0
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)
Beispiel #9
0
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)]
Beispiel #10
0
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
Beispiel #13
0
    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
Beispiel #14
0
    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