def cross(self,
              father: IntIndividual,
              mother: IntIndividual,
              random_state=None):
        ''' Cross chromsomes of parent using uniform crossover method.
        :param population: Population where the selection operation occurs.
        :type population: :obj:`gaft.components.Population`
        :return: Selected parents (a father and a mother)
        :rtype: list of :obj:`gaft.components.IndividualBase`
        '''
        random_state = check_random_state(random_state)
        do_cross = True if random_state.random() <= self.pc else False

        if not do_cross:
            return father.clone(), mother.clone()

        # Chromsomes for two children.
        chrom1 = deepcopy(father.chromosome)
        chrom2 = deepcopy(mother.chromosome)

        for i in range(father.chromosome.length):
            g1, g2 = chrom1[i], chrom2[i]
            do_exchange = True if random_state.random() <= self.pe else False
            if do_exchange:
                chrom1[i], chrom2[i] = g2, g1

        child1, child2 = father.clone(), father.clone()
        child1.init(chromosome=chrom1)
        child2.init(chromosome=chrom2)

        return child1, child2
    def select(self, size: int,
               population: List[Individual],
               comparator: Callable[[Individual, Individual], bool] = None,
               random_state=None) -> List[Individual]:
        
        random_state = check_random_state(random_state)
        if not comparator:
            comparator = self.single_objective_comparator

        # Check validity of tournament size.
        if self.tournament_size > len(population):
            msg = 'Tournament size({}) is larger than population size({})'
            raise ValueError(msg.format(self.tournament_size, len(population)))

        selected_indvs = []

        for _ in range(size):
            chosen = None
            competitors = random_state.choice(population, self.tournament_size)
            random_state.shuffle(competitors)
            competitors = competitors.tolist()
            competitors.sort(key=cmp_to_key(comparator))

            for i in range(len(competitors)):
                if random_state.uniform(0, 1) <= self.p:
                    chosen = competitors[i]
                    break

            if not chosen:
                chosen = competitors[random_state.randint(0, len(competitors)-1)]

            selected_indvs.append(chosen)

        return selected_indvs
示例#3
0
    def sort(population: List[Individual],
             random_state=None) -> List[Individual]:
        random_state = check_random_state(random_state)
        # non-dominated sorting
        pareto_fronts = NSGAIIEngine.nondominated_sort(population)

        # assign nondominated rank
        for rank in range(len(pareto_fronts)):
            for i in range(len(pareto_fronts[rank])):
                pareto_fronts[rank][i].nondominated_rank = rank

        # compute and assign  crowding distance
        for rank in range(len(pareto_fronts)):
            crowding_distance_dict = NSGAIIEngine.calc_crowding_distance(
                pareto_fronts[rank])
            for i in range(len(pareto_fronts[rank])):
                pareto_fronts[rank][
                    i].crowding_distance = crowding_distance_dict[
                        pareto_fronts[rank][i]]

            random_state.shuffle(pareto_fronts[rank])

            pareto_fronts[rank].sort(key=lambda indv: indv.crowding_distance,
                                     reverse=True)

        flatten_population = list(itertools.chain.from_iterable(pareto_fronts))

        return flatten_population
示例#4
0
    def select(self,
               size: int,
               population: List[Individual],
               is_unique=False,
               random_state=None) -> List[Individual]:
        random_state = check_random_state(random_state)
        fits = [float(indv._objective) for indv in population]
        max_fit = max(fits)
        fits = [(max_fit - e_fit + 1) for e_fit in fits]
        sum_fit = sum(fits)
        wheel = list(accumulate([i / sum_fit for i in fits]))

        selected = [True] * len(population)

        selected_indvs = []

        for _ in range(size):
            idx = bisect_right(wheel, random_state.random())
            while is_unique and not selected[idx] and idx > -len(selected):
                idx -= 1

            if idx == -len(selected):
                idx = random_state.randint(0, len(selected) - 1)

            selected_indvs.append(population[idx])
            selected[idx] = False

        return selected_indvs
示例#5
0
    def __init__(self,
                 population: Population,
                 objective: Callable[[Individual], Union[float, int]] = None,
                 objectives: List[Callable[[Individual], Union[float,
                                                               int]]] = None,
                 selection: Selection = None,
                 selection_size: int = None,
                 crossover: Crossover = None,
                 mutation: Mutation = None,
                 replacement: Replacement = None,
                 callbacks: CallbackList = None,
                 generations: int = None,
                 random_state=None):

        self.population = population
        self.generations = generations
        self.selection = selection
        self.crossover = crossover
        self.mutation = mutation
        self.replacement = replacement
        self.objective = objective
        self.objectives = objectives
        self.selection_size = selection_size or self.population.size
        self.random_state = check_random_state(random_state)
        self.callbacks = callbacks
        self.callbacks.set_engine(self)
        self.metrics = None
        self.history = None
        self.stop_running = False
        self.coefficients = None
        self.coefficient = None
示例#6
0
    def create_random_walk_rst(self, random_state=None):
        random_state = check_random_state(random_state)
        if self.root is not None:
            root = self.root
        else:
            random_state.randint(0, self.number_of_vertices)

        self.initialize()
        if len(self.edges) != 0:
            raise Exception(
                'Default random init on Tree only accept empty Tree at initialization.\n\
                            Donot add_edge at initialize() or try other random init function.'
            )

        mark = [False] * self.number_of_vertices
        mark[root] = True
        visited_nodes = 1

        v0 = root
        while visited_nodes != self.number_of_vertices:
            v1 = random_state.choice(self.potential_adj[v0])
            if not mark[v1]:
                self.add_edge(v0, v1)
                mark[v1] = True
                visited_nodes += 1
            v0 = v1

        self.repair()
示例#7
0
    def mutate(self, indv : Individual, random_state=None):
        random_state = check_random_state(random_state)
        idx = bisect_right(self.acc_pm, random_state.random())
        if idx >= len(self.mutation_list):
            return indv.clone()

        ret_indv = self.mutation_list[idx].mutate(indv, random_state)
        return ret_indv
示例#8
0
 def init_population_randomly(self, random_state=None) -> List[Individual]:
     random_state = check_random_state(random_state)
     ret = []
     for _ in range(self.size):
         new_indiv = self.individual_temp.clone()
         new_indiv.random_init(random_state=random_state)
         ret.append(new_indiv)
     return ret
示例#9
0
 def init_genes(self, genes=None, random_state=None):
     if genes is not None:
         if (isinstance(genes,(tuple,list)) and len(genes) == self.length):
             self.genes = np.array(genes)
         elif isinstance(genes, np.ndarray) and genes.ndim == 1 and genes.shape[0] == self.length:
             self.genes = genes
         else:
             raise Exception("genes has to be an instance of tuple or list and has the same length as chromosome")
     else:             
         random_state = check_random_state(random_state)
         self.genes = np.array([
                 random_state.uniform(int(self.lower_bound[i]), int(self.upper_bound[i])) for i in range(self.length)
             ])       
示例#10
0
    def mutate(self, individual: BinaryIndividual, random_state=None):
        random_state = check_random_state(random_state)
        do_mutation = True if random_state.random() <= self.pm else False

        ret_individual = individual.clone()

        if do_mutation:
            for i, genome in enumerate(ret_individual.chromosome.genes):
                flip = True if random_state.random() <= self.pe else False
                if flip:
                    ret_individual.chromosome.genes[i] = genome ^ 1

        return ret_individual
示例#11
0
    def mutate(self, indv: FloatIndividual, random_state=None):
        random_state = check_random_state(random_state)
        ret_indv = indv.clone()

        genes = np.copy(ret_indv.chromosome.genes)
        length = ret_indv.chromosome.length

        xl, xu = ret_indv.chromosome.lower_bound, ret_indv.chromosome.upper_bound

        do_mutation = random_state.random(length) < self.pm
        genes = genes[do_mutation]
        xl = xl[do_mutation]
        xu = xu[do_mutation]

        delta1 = (genes - xl) / (xu - xl)
        delta2 = (xu - genes) / (xu - xl)

        mut_pow = 1.0 / (self.distribution_index + 1.0)

        u = random_state.random(genes.shape[0])

        mask = u <= 0.5
        mask_not = np.logical_not(mask)

        deltaq = np.zeros(genes.shape)

        xy = 1.0 - delta1
        val = 2.0 * u + (1.0 - 2.0 * u) * (np.power(
            xy, (self.distribution_index + 1.0)))
        d = np.power(val, mut_pow) - 1.0
        deltaq[mask] = d[mask]

        xy = 1.0 - delta2
        val = 2.0 * (1.0 - u) + 2.0 * (u - 0.5) * (np.power(
            xy, (self.distribution_index + 1.0)))
        d = 1.0 - (np.power(val, mut_pow))
        deltaq[mask_not] = d[mask_not]

        mutated_genes = genes + deltaq * (xu - xl)

        # fix out of boudary error
        mutated_genes[mutated_genes < xl] = xl[mutated_genes < xl]
        mutated_genes[mutated_genes > xu] = xu[mutated_genes > xu]

        ret_genes = ret_indv.chromosome.genes
        ret_genes[do_mutation] = mutated_genes

        ret_indv.update_genes(ret_genes)

        return ret_indv
示例#12
0
    def cross(self,
              father: PermutationIndividual,
              mother: PermutationIndividual,
              random_state=None):
        ''' Cross chromsomes of parent using single point crossover method.
        '''
        random_state = check_random_state(random_state)
        do_cross = True if random_state.random() <= self.pc else False

        if not do_cross:
            return father.clone(), mother.clone()

        # Chromsomes for two children.
        chrom1 = deepcopy(father.chromosome)
        chrom2 = deepcopy(mother.chromosome)
        # print(chrom1)
        # print(chrom2)
        if father.chromosome.length != mother.chromosome.length:
            raise ValueError("Father and mother have different length")

        length = father.chromosome.length

        slt_points = list(random_state.choice(length, 2, replace=False))
        slt_points.sort()
        p1, p2 = slt_points
        cs1 = set(father.chromosome.genes[p1:p2])
        cs2 = set(mother.chromosome.genes[p1:p2])

        j1, j2 = 0, 0
        for i in range(length):
            if mother.chromosome[i] not in cs1:
                if j1 == p1:
                    j1 = p2
                chrom1[j1] = mother.chromosome[i]
                j1 += 1
            if father.chromosome[i] not in cs2:
                if j2 == p1:
                    j2 = p2
                chrom2[j2] = father.chromosome[i]
                j2 += 1

        # print(chrom1)
        # print(chrom2)

        child1, child2 = father.clone(), father.clone()
        child1.init(chromosome=chrom1)
        child2.init(chromosome=chrom2)

        return child1, child2
示例#13
0
    def create_kruskal_rst(self, random_state=None):
        """random_init.

        Args:
            random_state:
        """

        random_state = check_random_state(random_state)
        # order = random_state.permutation(np.arange(len(self.potential_edges)))
        weight = random_state.random(len(self.potential_edges))
        order = np.argsort(-weight)
        self.initialize()
        for i in order:
            u, v = self.potential_edges[i]
            if self.try_add_edge(u, v):
                self.add_edge(u, v)

        self.repair()
示例#14
0
    def create_prim_rst(self, random_state=None):
        """create_prim_rst.
            This implementation is not good.
            I cannot find any data structure that support both random choice and insert, remove element
            This implementation does not take care unconnected graph (no tree)

        Args:
            random_state:
        """
        random_state = check_random_state(random_state)

        self.initialize()

        # Set of connected nodes
        C = set()
        # eligible edges
        A = rset()

        # Init tree
        for u in range(self.number_of_vertices):
            if self.parent[u] != -1:
                C.add(u)
                for v in self.potential_adj[u]:
                    if v not in C:
                        A.add((u, v))

        while len(C) < self.number_of_vertices:
            u, v = A.random_choice(random_state)
            A.remove((u, v))
            if v not in C:
                self.add_edge(u, v)
                C.add(v)
                for w in self.potential_adj[v]:
                    if w not in C:
                        A.add((v, w))

            if len(A) == 0 and len(C) != self.number_of_vertices:
                raise ValueError(
                    'Cannot create random spanning tree from unconnected tree')

        self.repair()
示例#15
0
    def mutate(self, individual: IntIndividual, random_state=None):
        random_state = check_random_state(random_state)
        do_mutation = True if random_state.random() <= self.pm else False

        ret_individual = individual.clone()

        if not do_mutation:
            return ret_individual

        length = individual.chromosome.length
        points = np.arange(length-1)
        if self.n_points * 2 > length:
            raise ValueError('SwapMutation: n_points * 2 > length')
        slt_points = random_state.choice(points, self.n_points * 2, replace=False)

        for i in range(0, len(slt_points), 2):
            x, y = slt_points[i], slt_points[i+1]
            g1, g2 = ret_individual.chromosome[x], ret_individual.chromosome[y]
            ret_individual.chromosome[x], ret_individual.chromosome[y] = g2, g1

        return ret_individual
示例#16
0
    def create_random_walk_rst(self, random_state=None):
        random_state = check_random_state(random_state)

        self.initialize()
        mark = [False] * self.number_of_vertices
        visited_nodes = 0
        for u in range(self.number_of_vertices):
            if self.parent[u] != -1:
                mark[u] = True
                visited_nodes += 1

        v0 = self.root
        while visited_nodes != self.number_of_vertices:
            v1 = random_state.choice(self.potential_adj[v0])
            if not mark[v1]:
                self.add_edge(v0, v1)
                mark[v1] = True
                visited_nodes += 1
            v0 = v1

        self.repair()
示例#17
0
    def create_prim_rst(self, random_state=None):
        random_state = check_random_state(random_state)
        if self.root is not None:
            root = self.root
        else:
            random_state.randint(0, self.number_of_vertices)

        self.initialize()
        if len(self.edges) != 0:
            raise Exception(
                'Default random init on Tree only accept empty Tree at initialization.\n\
                            Donot add_edge at initialize() or try other random init function.'
            )
        # Set of connected nodes
        C = set()
        # eligible edges
        A = rset(
        )  # my implementation of set that helps get random in set in O(1)

        # Init tree
        C.add(root)
        for v in self.potential_adj[root]:
            A.add((root, v))

        while len(C) < self.number_of_vertices:
            u, v = A.random_choice(random_state)
            A.remove((u, v))

            if v not in C:
                self.add_edge(u, v)
                C.add(v)
                for w in self.potential_adj[v]:
                    if w not in C:
                        A.add((v, w))

            if len(A) == 0:
                raise ValueError(
                    'Cannot create random spanning tree from unconnected tree')
        self.repair()
示例#18
0
    def cross(self, father: Individual, mother: Individual, random_state=None):
        ''' Cross chromsomes of parent using single point crossover method.
        '''
        random_state = check_random_state(random_state)
        do_cross = True if random_state.random() <= self.pc else False

        if not do_cross:
            return father.clone(), mother.clone()

        # Chromsomes for two children.
        chrom1 = deepcopy(father.chromosome)
        chrom2 = deepcopy(mother.chromosome)
        if father.chromosome.length != mother.chromosome.length:
            raise ValueError("Father and mother have different length")

        length = father.chromosome.length

        points = np.arange(length - 1)
        points = points[self.point_filter(points)]
        slt_points = list(
            random_state.choice(points, self.n_points, replace=False))
        slt_points.append(length)
        slt_points.sort()

        do_exchange = False
        j = 0
        for i in range(father.chromosome.length):
            if i > slt_points[j]:
                do_exchange ^= 1
                j += 1
            if do_exchange:
                chrom1[i], chrom2[i] = chrom2[i], chrom1[i]

        child1, child2 = father.clone(), father.clone()
        child1.init(chromosome=chrom1)
        child2.init(chromosome=chrom2)

        return child1, child2
示例#19
0
    def cross(self, father : FloatIndividual, mother : FloatIndividual, random_state=None):
        random_state = check_random_state(random_state)
        do_crossover = True if random_state.random() <= self.pc else False

        if not do_crossover:
            return father.clone(), mother.clone()

        length = father.chromosome.length
        xl, xu = father.chromosome.lower_bound, father.chromosome.upper_bound

        # Chromsomes for two children.
        y1 = deepcopy(father.chromosome.genes)
        y2 = deepcopy(mother.chromosome.genes)
        
        cross_element = np.full(length, True)
        cross_element[random_state.random(length) > self.pc] = False
        cross_element[np.abs(y1 - y2) <= self.__EPS] = False

        # ensure chromo1 < chromo2
        for i in range(length):
            if y1[i] > y2[i]:
                y1[i], y2[i] = y2[i], y1[i]
        
        u = random_state.random(length)

        def calc_betaq(beta):
            alpha = 2.0 - np.power(beta, -(self.distribution_index + 1.0))

            mask, mask_not = (u <= (1.0 / alpha)), (u > (1.0 / alpha))
            betaq = np.zeros(mask.shape)
            betaq[mask] = np.power((u * alpha), (1.0 / (self.distribution_index + 1.0)))[mask]
            betaq[mask_not] = np.power((1.0 / (2.0 - u * alpha)), (1.0 / (self.distribution_index + 1.0)))[mask_not]

            return betaq

        delta = (y2 - y1)
        delta[delta < 1.0e-10] = 1.0e-10

        beta = 1.0 + (2.0 * (y1 - xl) / delta)
        betaq = calc_betaq(beta)
        c1 = 0.5 * ((y1 + y2) - betaq * delta)

        beta = 1.0 + (2.0 * (xu - y2) / delta)
        betaq = calc_betaq(beta)
        c2 = 0.5 * ((y1 + y2) + betaq * delta)

        # do randomly a swap of variables
        b = random_state.random(length) <= 0.5
        val = np.copy(c1[b])
        c1[b] = c2[b]
        c2[b] = val

        genes1 = np.copy(father.chromosome.genes)
        genes2 = np.copy(mother.chromosome.genes)

        # copy the positions where the crossover was done
        genes1[cross_element] = c1[cross_element]
        genes2[cross_element] = c2[cross_element]

        # repair boundary
        genes1[genes1 < xl] = xl[genes1 < xl]
        genes1[genes1 > xu] = xu[genes1 > xu]

        genes2[genes2 < xl] = xl[genes2 < xl]
        genes2[genes2 > xu] = xu[genes2 > xu]

        offspring1, offspring2 = father.clone(), mother.clone()

        offspring1.update_genes(genes1)
        offspring2.update_genes(genes2)

        return offspring1, offspring2
示例#20
0
    def cross(self, father: Individual, mother: Individual, random_state=None):
        """ Cross chromsomes of parent using kruskal crossover method.
            + join 2 tree
            + keep the edges that appear in both
            + random weight for the remaining edges
            + use kruskal algorithm create offspring 1
            + random another weight for the remaining edges
            + use kruskal algorithm to create offspring 2
        """
        random_state = check_random_state(random_state)
        do_cross = True if random_state.random() <= self.pc else False

        if not do_cross:
            return father.clone(), mother.clone()

        tree1, tree2 = father.decode(), mother.decode()
        if not (isinstance(tree1, KruskalTree)
                and isinstance(tree2, KruskalTree)):
            raise ValueError(
                f"The KruskalCrossover is only used on the individual that \
                             decodes to an instance of KruskallTree. \
                             got father type: {type(tree1)} and mother type {type(tree2)}"
            )

        intersection = set()
        remaining_edges = set()
        tree1_edges = set(tree1.edges)
        tree2_edges = set(tree2.edges)

        for u, v in tree1_edges:
            if (u, v) in tree2_edges or (v, u) in tree2_edges:
                intersection.add((u, v))
            elif (v, u) not in remaining_edges:
                remaining_edges.add((u, v))

        for u, v in tree2_edges:
            if (u, v) not in tree1_edges and (v, u) not in tree1_edges \
                    and (v, u) not in remaining_edges:
                remaining_edges.add((u, v))

        remaining_edges = list(remaining_edges)
        children = [tree1.clone(), tree2.clone()]

        for i in range(len(children)):
            # renew offspring tree
            children[i].initialize()
            # add edges that appear in both tree to offsprings
            for u, v in intersection:
                children[i].add_edge(u, v)

            # random weight for remaining_edges
            order = random_state.permutation(np.arange(len(remaining_edges)))
            for j in order:
                u, v = remaining_edges[j]
                children[i].add_edge(u, v)

            children[i].repair()

        offspring1, offspring2 = father.clone(), mother.clone()
        try:
            offspring1.encode(children[0])
            offspring2.encode(children[1])
        except NotImplementedError:
            raise ValueError(
                "Cannot call encode method. PrimCrossover requires encode method in Individual"
            )
        except Exception as e:
            raise e

        return offspring1, offspring2
示例#21
0
 def pop(self, random_state=None):
     random_state = check_random_state(random_state)
     index = random_state.randint(0, len(self.__arr))
     self.remove(self.__arr[index])
示例#22
0
 def random_choice(self, random_state=None):
     random_state = check_random_state(random_state)
     index = random_state.randint(0, len(self.__arr))
     return self.__arr[index]
 def random_init(self, random_state=None):
     random_state = check_random_state(random_state)
     genes = random_state.permutation(self.length)
     genes = genes + self.start
     self.update_genes(genes)
示例#24
0
    def cross(self, father: Individual, mother: Individual, random_state=None):
        random_state = check_random_state(random_state)
        do_cross = True if random_state.random() <= self.pc else False

        children = father.clone(), mother.clone()
        if not do_cross:
            return children

        trees = children[0].decode(), children[1].decode()
        if not (isinstance(trees[0], Tree) and isinstance(trees[1], Tree)):
            raise ValueError(f"The PrimCrossover is only used on the individual that \
                             decodes to an instance of Tree. \
                             got father type: {type(trees[0])} and mother type {type(trees[1])}")

        edge_union = set() 
        potential_adj = [list() for _ in range(trees[0].number_of_vertices)]
        for i in range(2):
            for u, v in trees[i].edges:
                if (v, u) not in edge_union:
                    edge_union.add((u, v))
                    potential_adj[u].append(v)
                    potential_adj[v].append(u)

        for i in range(2):
            trees[i].initialize()

            # This is tricky, 
            # I'm trying to make this method can work both cases  
            # one when you add_edge in initialize() function, and one is not
            # I'm using parent attribute to do this. 
            # But this only work when you update parent attribute after add_edge in initialize()
            # or you this crossover method with RootedTree, it supports update parent attribute in add_edge
            if not isinstance(trees[i], RootedTree) and len(trees[i].edges) != 0:
                raise Exception("Unexpected error occurred when running PrimCrossover")

            if trees[i].root is not None:
                root = trees[i].root
            else:
                random_state.randint(0, trees[i].number_of_vertices)

            trees[i].parent[root] = root
            # Set of connected nodes
            C = set()
            # eligible edges
            A = rset()

            # Init tree 
            for u in range(trees[i].number_of_vertices):
                if trees[i].parent[u] != -1:
                    C.add(u)
                    for v in potential_adj[u]:
                        if v not in C:
                            A.add((u, v))

            while len(C) < trees[i].number_of_vertices:
                u, v = A.random_choice(random_state)
                A.remove((u, v))
                if v not in C:
                    trees[i].add_edge(u, v)
                    C.add(v)
                    for w in potential_adj[v]:
                        if w not in C:
                            A.add((v, w))
                if len(A) == 0 and len(C) != trees[i].number_of_vertices:
                    raise ValueError('Cannot create random spanning tree from unconnected tree')
            trees[i].repair()

        try:
            children[0].encode(trees[0])
            children[1].encode(trees[1])
        except NotImplementedError:
            raise ValueError("Cannot call encode method. PrimCrossover requires encode method in Individual")
        except Exception as e:
            raise e

        return children[0], children[1]
示例#25
0
 def random_init(self, random_state=None):
     random_state = check_random_state(random_state or self.random_state)
     self.chromosome.init_genes(random_state=random_state)