File size: 7,250 Bytes
8e7d8ae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
from model.Schedule import Schedule
import random
from random import randrange
from time import time


# Lakshmi, R. et al. “A New Biological Operator in Genetic Algorithm for Class Scheduling Problem.” 
# International Journal of Computer Applications 60 (2012): 6-11.


# Genetic algorithm
class GeneticAlgorithm:
    def initAlgorithm(self, prototype, numberOfChromosomes=100, replaceByGeneration=8, trackBest=5):
        # Number of best chromosomes currently saved in best chromosome group
        self._currentBestSize = 0
        # Prototype of chromosomes in population
        self._prototype = prototype

        # there should be at least 2 chromosomes in population
        if numberOfChromosomes < 2:
            numberOfChromosomes = 2

        # and algorithm should track at least on of best chromosomes
        if trackBest < 1:
            trackBest = 1

        # Population of chromosomes
        self._chromosomes = numberOfChromosomes * [None]
        # Inidicates whether chromosome belongs to best chromosome group
        self._bestFlags = numberOfChromosomes * [False]

        # Indices of best chromosomes
        self._bestChromosomes = trackBest * [0]
        # Number of chromosomes which are replaced in each generation by offspring
        self.set_replace_by_generation(replaceByGeneration)

    # Initializes genetic algorithm
    def __init__(self, configuration, numberOfCrossoverPoints=2, mutationSize=2, crossoverProbability=80,
                 mutationProbability=3):
        self.initAlgorithm(Schedule(configuration))
        self._mutationSize = mutationSize
        self._numberOfCrossoverPoints = numberOfCrossoverPoints
        self._crossoverProbability = crossoverProbability
        self._mutationProbability = mutationProbability

    @property
    # Returns pointer to best chromosomes in population
    def result(self):
        return self._chromosomes[self._bestChromosomes[0]]

    def set_replace_by_generation(self, value):
        numberOfChromosomes = len(self._chromosomes)
        trackBest = len(self._bestChromosomes)
        if (value > numberOfChromosomes - trackBest):
            value = numberOfChromosomes - trackBest
        self._replaceByGeneration = value

    # Tries to add chromosomes in best chromosome group
    def addToBest(self, chromosomeIndex):
        bestChromosomes = self._bestChromosomes
        length_best = len(bestChromosomes)
        bestFlags = self._bestFlags
        chromosomes = self._chromosomes

        # don't add if new chromosome hasn't fitness big enough for best chromosome group
        # or it is already in the group?
        if (self._currentBestSize == length_best and chromosomes[bestChromosomes[self._currentBestSize - 1]].fitness >=
            chromosomes[chromosomeIndex].fitness) or bestFlags[chromosomeIndex]:
            return

        # find place for new chromosome
        j = self._currentBestSize
        for i in range(j, -1, -1):
            j = i
            pos = bestChromosomes[i - 1]
            # group is not full?
            if i < length_best:
                # position of new chromosomes is found?
                if chromosomes[pos].fitness > chromosomes[chromosomeIndex].fitness:
                    break

                # move chromosomes to make room for new
                bestChromosomes[i] = pos
            else:
                # group is full remove worst chromosomes in the group
                bestFlags[pos] = False

        # store chromosome in best chromosome group
        bestChromosomes[j] = chromosomeIndex
        bestFlags[chromosomeIndex] = True

        # increase current size if it has not reached the limit yet
        if self._currentBestSize < length_best:
            self._currentBestSize += 1

    # Returns TRUE if chromosome belongs to best chromosome group
    def isInBest(self, chromosomeIndex) -> bool:
        return self._bestFlags[chromosomeIndex]

    # Clears best chromosome group
    def clearBest(self):
        self._bestFlags = len(self._bestFlags) * [False]
        self._currentBestSize = 0

    # initialize new population with chromosomes randomly built using prototype
    def initialize(self, population):
        # addToBest = self.addToBest
        prototype = self._prototype
        length_chromosomes = len(population)

        for i in range(0, length_chromosomes):
            # add new chromosome to population
            population[i] = prototype.makeNewFromPrototype()
            # addToBest(i)

    def selection(self, population):
        length_chromosomes = len(population)
        return (population[randrange(32768) % length_chromosomes],  population[randrange(32768) % length_chromosomes])

    def replacement(self, population, replaceByGeneration) -> []:
        mutationSize = self._mutationSize
        numberOfCrossoverPoints = self._numberOfCrossoverPoints
        crossoverProbability = self._crossoverProbability
        mutationProbability = self._mutationProbability
        selection = self.selection
        isInBest = self.isInBest
        length_chromosomes = len(population)
        # produce offspring
        offspring = replaceByGeneration * [None]
        for j in range(replaceByGeneration):
            # selects parent randomly
            parent = selection(population)

            offspring[j] = parent[0].crossover(parent[1], numberOfCrossoverPoints, crossoverProbability)
            offspring[j].mutation(mutationSize, mutationProbability)

            # replace chromosomes of current operation with offspring
            # select chromosome for replacement randomly
            ci = randrange(32768) % length_chromosomes
            while isInBest(ci):
                ci = randrange(32768) % length_chromosomes

            # replace chromosomes
            population[ci] = offspring[j]

            # try to add new chromosomes in best chromosome group
            self.addToBest(ci)
        return offspring

    # Starts and executes algorithm
    def run(self, maxRepeat=9999, minFitness=0.999):
        # clear best chromosome group from previous execution
        self.clearBest()
        length_chromosomes = len(self._chromosomes)

        self.initialize(self._chromosomes)
        random.seed(round(time() * 1000))

        # Current generation
        currentGeneration = 0

        repeat = 0
        lastBestFit = 0.0

        while 1:
            best = self.result
            print("Fitness:", "{:f}\t".format(best.fitness), "Generation:", currentGeneration, end="\r")

            # algorithm has reached criteria?
            if best.fitness > minFitness:
                break

            difference = abs(best.fitness - lastBestFit)
            if difference <= 0.0000001:
                repeat += 1
            else:
                repeat = 0

            if repeat > (maxRepeat / 100):
                random.seed(round(time() * 1000))
                self.set_replace_by_generation(self._replaceByGeneration * 3)
                self._crossoverProbability += 1

            self.replacement(self._chromosomes, self._replaceByGeneration)

            lastBestFit = best.fitness
            currentGeneration += 1

    def __str__(self):
        return "Genetic Algorithm"