Passed
Push — master ( b4d881...21cb52 )
by Simon
02:57
created

gradient_free_optimizers.optimizers.pop_opt.genetic_algorithm   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 109
Duplicated Lines 20.18 %

Importance

Changes 0
Metric Value
wmc 14
eloc 78
dl 22
loc 109
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A GeneticAlgorithmOptimizer.evaluate() 0 3 1
A GeneticAlgorithmOptimizer.fittest_parents() 0 14 2
A GeneticAlgorithmOptimizer.__init__() 0 24 1
A GeneticAlgorithmOptimizer.iterate() 22 22 4
A GeneticAlgorithmOptimizer._constraint_loop() 0 5 3
A GeneticAlgorithmOptimizer.init_pos() 0 6 1
A GeneticAlgorithmOptimizer._crossover() 0 9 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
# Author: Simon Blanke
2
# Email: [email protected]
3
# License: MIT License
4
5
import random
6
import numpy as np
7
8
from ._evolutionary_algorithm import EvolutionaryAlgorithmOptimizer
9
from ._individual import Individual
10
11
12
class GeneticAlgorithmOptimizer(EvolutionaryAlgorithmOptimizer):
13
    name = "Genetic Algorithm"
14
    _name_ = "genetic_algorithm"
15
    __name__ = "GeneticAlgorithmOptimizer"
16
17
    optimizer_type = "population"
18
    computationally_expensive = False
19
20
    def __init__(
21
        self,
22
        *args,
23
        population=10,
24
        offspring=10,
25
        crossover="discrete-recombination",
26
        n_parents=2,
27
        mutation_rate=0.5,
28
        crossover_rate=0.5,
29
        **kwargs
30
    ):
31
        super().__init__(*args, **kwargs)
32
33
        self.population = population
34
        self.offspring = offspring
35
        self.crossover = crossover
36
        self.n_parents = n_parents
37
        self.mutation_rate = mutation_rate
38
        self.crossover_rate = crossover_rate
39
40
        self.individuals = self._create_population(Individual)
41
        self.optimizers = self.individuals
42
43
        self.offspring_l = []
44
45
    def fittest_parents(self):
46
        fittest_parents_f = 0.5
47
48
        self.sort_pop_best_score()
49
50
        n_fittest = int(len(self.pop_sorted) * fittest_parents_f)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable len does not seem to be defined.
Loading history...
51
52
        best_l = self.pop_sorted[:n_fittest]
53
        worst_l = self.pop_sorted[n_fittest:]
54
55
        if 0.01 >= random.random():
56
            best_l[random.randint(0, len(best_l) - 1)] = random.choice(worst_l)
57
58
        return best_l
59
60
    def _crossover(self):
61
        fittest_parents = self.fittest_parents()
62
        selected_parents = random.sample(fittest_parents, self.n_parents)
63
64
        for _ in range(self.offspring):
65
            parent_pos_l = [parent.pos_new for parent in selected_parents]
66
            offspring = self.discrete_recombination(parent_pos_l)
67
            offspring = self._constraint_loop(offspring)
68
            self.offspring_l.append(offspring)
69
70
    def _constraint_loop(self, position):
71
        while True:
72
            if self.conv.not_in_constraint(position):
73
                return position
74
            position = self.p_current.move_climb(position, epsilon_mod=0.3)
75
76
    @EvolutionaryAlgorithmOptimizer.track_new_pos
77
    def init_pos(self):
78
        nth_pop = self.nth_trial % len(self.individuals)
79
80
        self.p_current = self.individuals[nth_pop]
81
        return self.p_current.init_pos()
82
83 View Code Duplication
    @EvolutionaryAlgorithmOptimizer.track_new_pos
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
84
    def iterate(self):
85
        n_ind = len(self.individuals)
86
87
        if n_ind == 1:
88
            self.p_current = self.individuals[0]
89
            return self.p_current.iterate()
90
91
        self.sort_pop_best_score()
92
        rnd_int = random.randint(0, len(self.pop_sorted) - 1)
93
        self.p_current = self.pop_sorted[rnd_int]
94
95
        total_rate = self.mutation_rate + self.crossover_rate
96
        rand = np.random.uniform(low=0, high=total_rate)
97
98
        if rand <= self.mutation_rate:
99
            return self.p_current.iterate()
100
        else:
101
            if not self.offspring_l:
102
                self._crossover()
103
            self.p_current.pos_new = self.offspring_l.pop(0)
104
            return self.p_current.pos_new
105
106
    @EvolutionaryAlgorithmOptimizer.track_new_score
107
    def evaluate(self, score_new):
108
        self.p_current.evaluate(score_new)
109