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

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 

4 

5 

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 """ 

12 

13 def __init__(self, population_instance): 

14 self.pop = population_instance 

15 self.pops = {} 

16 

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 

22 

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) 

29 

30 

31class GenerationRepetitionConvergence(Convergence): 

32 """Returns True if the latest finished population is stagnated for 

33 number_of_generations. 

34 

35 Parameters: 

36 

37 number_of_generations: int 

38 How many generations need to be equal before convergence. 

39 

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. 

43 

44 max_generations: int 

45 The maximum number of generations the GA is allowed to run. 

46 Default is indefinite. 

47 """ 

48 

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 

55 

56 def converged(self): 

57 size = self.pop.pop_size 

58 cur_gen_num = self.pop.dc.get_generation_number(size) 

59 

60 if cur_gen_num >= self.maxgen: 

61 return True 

62 

63 if cur_gen_num <= 1: 

64 return False 

65 

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 

71 

72 self.populate_pops(cur_gen_num) 

73 

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 

83 

84 

85class RawScoreConvergence(Convergence): 

86 """Returns True if the supplied max_raw_score has been reached""" 

87 

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 

92 

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 

98 

99 

100class NeverConvergence: 

101 """Test class that never converges.""" 

102 

103 def __init__(self): 

104 pass 

105 

106 def converged(self): 

107 return False