Permalink
Feb 6, 2018
Feb 6, 2018
Feb 6, 2018
Feb 6, 2018
Feb 6, 2018
Feb 6, 2018
Feb 6, 2018
Feb 6, 2018
Feb 6, 2018
Feb 6, 2018
Feb 6, 2018
Feb 6, 2018
Feb 10, 2018
Feb 6, 2018
Feb 10, 2018
Feb 6, 2018
Feb 13, 2018
Feb 10, 2018
Feb 13, 2018
Feb 13, 2018
Feb 6, 2018
Feb 6, 2018
Feb 6, 2018
Feb 6, 2018

Newer

100644
262 lines (233 sloc)
8.8 KB

3

#=

4

Parents <— {randomly generated population}

5

While not (termination criterion)

6

Calculate the fitness of each parent in the population

7

Children <- 0

8

While | Children | < | Parents |

9

Use fitnesses to probabilistically select a pair of parents for mating

10

Mate the parents to create children c\ and c<i

11

Children <— Children U {ci,C2}

12

Loop

13

Randomly mutate some of the children

14

Parents <— Children

15

Next generation

16

17

Use continuous GA, not binary

18

19

include array of independent variables along with associated range

20

21

=#

22

23

function initialize_population(populationSize::Int, chromosomeSize::Int, bounds::Array{Tuple{Float64, Float64},1})

24

"""

26

Values will be from lb to ub (lower to upper bound)

27

"""

28

29

# Check to see if we dont have enough bounds or have too many

30

if length(bounds) != chromosomeSize

31

println("Length of bounds ($(length(bounds))) not equal to specified chromosome size ($chromosomeSize)")

32

exit()

33

end

34

35

# Init population

37

38

# Foreach member in population

39

for i = 1:populationSize

40

# Init the member

41

row = []

42

# Create member elements based on bounds

43

for bound in bounds

45

end

46

# Add another element to the end to keep score

47

push!(row, 1.0)

48

49

# hcat row, append to 2D population matrix

51

end

52

return population

53

54

end

55

56

function score_sort_population(population::Array{Array{Float64}}, fitness_function::Function)

57

"""

58

Args

59

population: The population to score. Must be 2D array of Float64 elements

60

fitness_function: Function to score the population

61

Must be able to take array as argument

62

For example f(x,y) should be f(A) where A[1]=x, A[2]=y

63

Returns scored population. Score is the last element of each chromosome (row)

64

in population

65

"""

66

# Enumerate through population, set last element of each chromosome to score

67

for (index,member) in enumerate(population)

68

population[index][end] = fitness_function(member)

69

end

70

sort!(population, by = x -> x[end])

71

return population

72

end

73

74

function create_next_generation(population::Array{Array{Float64}}, recombRate::Float64)

75

"""

76

Creates children given a population and recombination rate

77

Uses an elite selection of 0.10 (rounded up)

78

Creates random chance

79

TODO: Implement ranking

80

"""

81

82

popSize = length(population)

83

memberSize = length(population[1])

84

# Init children array

85

children = Array{Array{Float64}}(0)

86

# Elite selection

87

for i in 1:Int(ceil(popSize*0.10))

88

push!(children, population[i])

89

end

90

91

# Generate rest of population

92

while length(children) < popSize

93

# Two random children

94

choices = sample(1:popSize, 2, replace=false)

95

# Check for crossover

96

if rand() < recombRate

97

# Choose xover point

98

# Use -2 since last one is score, and last actual element cant be crossedover since that means there is none

99

xover = rand(1:memberSize-2)

100

child1 = cat(1,population[choices[1]][1:xover],population[choices[2]][xover+1:end])

101

child2 = cat(1,population[choices[2]][1:xover],population[choices[1]][xover+1:end])

102

else

103

# Else no crossover, just copy

104

child1 = population[choices[1]]

105

child2 = population[choices[2]]

106

end

107

# Push child 1 and 2 to children array

108

push!(children, child1, child2)

109

end

110

111

# We might have one extra due to rounding in the elite selection, let's check

112

if length(children) != popSize

113

pop!(children)

114

end

115

return children

116

end

117

118

function mutate(population::Array{Array{Float64}}, mutateRate::Float64, bounds::Array{Tuple{Float64, Float64},1})

119

"""

120

Iterates through each chromosome and mutates if needed

121

"""

122

123

for member in population

124

for i = 1:length(member)-1

125

if rand() < mutateRate

131

return population

132

end

133

134

function GA(populationSize::Int, chromosomeSize::Int, fitness_function::Function, bounds::Array{Tuple{Float64, Float64},1})

135

"""

136

Args

137

populationSize: Total number of chromosomes

138

chromosomeSize: How long each chromosome should be (variables in fitness function)

139

fitness_function: Function to determine fitness of each solution

140

Should take an array as an arg

141

Example: f(x,y,z) = x+y+z

142

should be f(X) = X[1]+X[2]+X[3]

143

in order to allow GA to take in any function with any

144

amount of args to the fitness function

145

bounds: 1D array of tuples, each tuple is the (lower, upper) bounds

146

for each variable. Both lower and upper need to be Float64 types

147

Length should match chromosomeSize

148

e.g: [(1.0,2.0), (3.5,4.5)]

149

"""

150

151

# Set recombination and mutation rate, lower and upper bound

152

recombRate = 0.7

153

mutateRate = 0.05

156

# First initialize the population

159

# Initialize iteration counter, run counter, and array to hold generations of best population

160

i = 0

161

run = 0

162

bestGenerations = [[[0.0,0.0,Inf]]]

163

generations = Array{Array{Array{Float64}}}(0)

164

165

# For each run

166

while run < runs

167

nextPopulation = initialize_population(populationSize, chromosomeSize, bounds)

168

# Iterate through max amount of generations

169

while i < maxIterations

170

# Score and sort the population

171

population = score_sort_population(nextPopulation, fitness_function)

172

# Push current population to generations array

173

push!(generations, deepcopy(population))

174

# Create children

175

nextPopulation = create_next_generation(population, recombRate)

176

# Mutate children

177

nextPopulation = mutate(nextPopulation, mutateRate, bounds)

178

i += 1

179

end

180

#=

181

At the end of the run, if the last generations best solution

182

# is better than that of the best of all runs so far

183

set new best run so we can graph later

184

=#

185

if generations[end][1][end] < bestGenerations[end][1][end]

186

bestGenerations = deepcopy(generations)

187

end

188

clear!(:generations)

189

clear!(:population)

190

run += 1

191

end

192

193

# Reporting and plotting

194

# Report best solution and value

195

bestVariables = bestGenerations[end][1][1:end-1]

196

bestScore = bestGenerations[end][1][end]

197

println("Best solution\nVariables: $bestVariables\nScore: $bestScore")

198

199

# Generate best fitness vs. # generation

200

# Init score array

201

y = Array{Float64}(0)

202

# Get scores, push to array

203

for g in bestGenerations

204

push!(y,g[1][end])

205

end

206

# Plot and label

207

PyPlot.plot(y)

208

xlabel("Generation #")

209

ylabel("Fitness")

210

# Save and close

211

PyPlot.savefig("BestFitness.png")

212

PyPlot.close()

213

214

# Contour

215

# Check to make sure we only have two variables, otherwise exit

216

if length(bestGenerations[1][1]) > 3

217

println("Plotting the 4th dimension currently disabled to avoid tearing the space-time continuum")

218

quit()

219

end

221

222

# Pick X and Y range for contour plot based on bounds

223

xrange = bounds[1][1]:0.01:bounds[1][2]

224

yrange = bounds[2][1]:0.01:bounds[2][2]

225

size = length(xrange)

226

# Init z array for values of fitness function

227

z = zeros(size,size)

228

for i in 1:size

229

for j in 1:size

230

# Generate a z value for each x and y value

231

z[i,j] = fitness_function([xrange[i],yrange[j]])

232

end

233

end

234

# If we are at 1st gen or evry 10th, plot

235

for (index, gen) in enumerate(bestGenerations)

236

if (index == 1) || (mod(index,10) == 0)

237

# Re-init x and y for the generation

238

x = Array{Float64}(0)

239

y = Array{Float64}(0)

240

# Push x and y to separate arrays

245

# Plt the contour plot

246

contour(xrange,yrange,z)

247

# Then plot the scatter underneath

248

scatter(x,y)

249

title("Generation $index")

255

end

256

258

return e - 20*exp(-0.2*sqrt((X[1]^2 + X[2]^2)/2)) - exp((cos(2*pi*X[1]) + cos(2*pi*X[2]))/2)

259

end

261

bounds = [(-2.0,2.0), (-2.0,2.0)]