Coverage for /builds/kinetik161/ase/ase/ga/convergence.py: 26.42%
53 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
1"""Classes that determine convergence of an algorithm run
2based on population stagnation or max raw score reached"""
3from ase.ga import get_raw_score
6class Convergence:
7 """
8 Base class for all convergence object to be based on.
9 It is necessary to supply the population instance, to be
10 able to obtain current and former populations.
11 """
13 def __init__(self, population_instance):
14 self.pop = population_instance
15 self.pops = {}
17 def converged(self):
18 """This function is called to find out if the algorithm
19 run has converged, it should return True or False.
20 Overwrite this in the inherited class."""
21 raise NotImplementedError
23 def populate_pops(self, to_gen):
24 """Populate the pops dictionary with how the population
25 looked after i number of generations."""
26 for i in range(to_gen):
27 if i not in self.pops.keys():
28 self.pops[i] = self.pop.get_population_after_generation(i)
31class GenerationRepetitionConvergence(Convergence):
32 """Returns True if the latest finished population is stagnated for
33 number_of_generations.
35 Parameters:
37 number_of_generations: int
38 How many generations need to be equal before convergence.
40 number_of_individuals: int
41 How many of the fittest individuals should be included in the
42 convergence test. Default is -1 meaning all in the population.
44 max_generations: int
45 The maximum number of generations the GA is allowed to run.
46 Default is indefinite.
47 """
49 def __init__(self, population_instance, number_of_generations,
50 number_of_individuals=-1, max_generations=100000000):
51 Convergence.__init__(self, population_instance)
52 self.numgens = number_of_generations
53 self.numindis = number_of_individuals
54 self.maxgen = max_generations
56 def converged(self):
57 size = self.pop.pop_size
58 cur_gen_num = self.pop.dc.get_generation_number(size)
60 if cur_gen_num >= self.maxgen:
61 return True
63 if cur_gen_num <= 1:
64 return False
66 cur_pop = self.pop.get_current_population()
67 newest = max([i.info['key_value_pairs']['generation']
68 for i in cur_pop[:self.numindis]])
69 if newest + self.numgens > cur_gen_num:
70 return False
72 self.populate_pops(cur_gen_num)
74 duplicate_gens = 1
75 latest_pop = self.pops[cur_gen_num - 1]
76 for i in range(cur_gen_num - 2, -1, -1):
77 test_pop = self.pops[i]
78 if test_pop[:self.numindis] == latest_pop[:self.numindis]:
79 duplicate_gens += 1
80 if duplicate_gens >= self.numgens:
81 return True
82 return False
85class RawScoreConvergence(Convergence):
86 """Returns True if the supplied max_raw_score has been reached"""
88 def __init__(self, population_instance, max_raw_score, eps=1e-3):
89 Convergence.__init__(self, population_instance)
90 self.max_raw_score = max_raw_score
91 self.eps = eps
93 def converged(self):
94 cur_pop = self.pop.get_current_population()
95 if abs(get_raw_score(cur_pop[0]) - self.max_raw_score) <= self.eps:
96 return True
97 return False
100class NeverConvergence:
101 """Test class that never converges."""
103 def __init__(self):
104 pass
106 def converged(self):
107 return False