@@ -61,13 +61,14 @@ func (ea *EA) validate() error {
6161
6262func (ea * EA ) imports () string {
6363 return strings .Join ([]string {
64- "import random" ,
64+ "import random, os " ,
6565 "from deap import base, creator, tools, algorithms" ,
6666 "import numpy" ,
6767 "import matplotlib.pyplot as plt" ,
6868 "from functools import reduce" ,
6969 "from scoop import futures" ,
7070 "from deap import benchmarks" ,
71+ "from itertools import chain" ,
7172 }, "\n " )
7273}
7374
@@ -111,11 +112,16 @@ func (ea *EA) initialGenerator() string {
111112 case "initRepeat" :
112113 return fmt .Sprintf ("toolbox.register(\" individual\" , tools.%s, creator.Individual, toolbox.attr, %d)\n " , ea .PopulationFunction , ea .IndividualSize ) + fmt .Sprintf ("toolbox.register(\" population\" , tools.%s, list, toolbox.individual)\n " , ea .PopulationFunction )
113114 default :
114- return ea .PopulationFunction
115+ return fmt . Sprintf ( "toolbox.register( \" individual \" , tools.%s, creator.Individual, toolbox.attr, %d) \n " , "initRepeat" , ea .IndividualSize ) + fmt . Sprintf ( "toolbox.register( \" population \" , tools.%s, list, toolbox.individual) \n " , "initRepeat" )
115116 }
116117}
117118
118119func (ea * EA ) mutationFunction () string {
120+ // TODO: Remove this later on.
121+ if ea .Algorithm == "de" {
122+ return fmt .Sprintf ("toolbox.register(\" mutate\" , mutDE, f=%f)\n " , ea .Indpb )
123+ }
124+
119125 // TODO: Add support for more mutation functions.
120126 switch ea .MutationFunction {
121127 case "mutFlipBit" :
@@ -167,7 +173,7 @@ func (ea *EA) plots() string {
167173 plots += "\t plt.xlabel(\" Generation\" )\n "
168174 plots += "\t plt.ylabel(\" Fitness\" )\n "
169175 plots += "\t plt.legend(loc=\" lower right\" )\n "
170- plots += "\t plt.savefig(f\" fitness_plot.png\" , dpi=300)\n "
176+ plots += "\t plt.savefig(f\" {rootPath}/ fitness_plot.png\" , dpi=300)\n "
171177 plots += "\t plt.close()\n "
172178 plots += "\n \n "
173179
@@ -179,15 +185,34 @@ func (ea *EA) plots() string {
179185 plots += "\t plt.ylabel(\" Fitness Change\" )\n "
180186 plots += "\t plt.title(\" Effect of Mutation and Crossover on Fitness\" )\n "
181187 plots += "\t plt.legend()\n "
182- plots += "\t plt.savefig(f\" mutation_crossover_effect.png\" , dpi=300)\n "
188+ plots += "\t plt.savefig(f\" {rootPath}/ mutation_crossover_effect.png\" , dpi=300)\n "
183189 plots += "\t plt.close()\n "
184190 return plots
185191}
186192
193+ func (ea * EA ) deCrossOverFunctions () string {
194+ return strings .Join ([]string {
195+ "def cxBinomial(x, y, cr):" ,
196+ "\t size = len(x)" ,
197+ "\t index = random.randrange(size)" ,
198+ "\t for i in range(size):" ,
199+ "\t \t if i == index or random.random() < cr:" ,
200+ "\t \t \t x[i] = y[i]" ,
201+ "\t return x" ,
202+ "\n " ,
203+ "def cxExponential(x, y, cr):" ,
204+ "\t size = len(x)" ,
205+ "\t index = random.randrange(size)" ,
206+ "\t for i in chain(range(index, size), range(0, index)):" ,
207+ "\t \t x[i] = y[i]" ,
208+ "\t \t if random.random() < cr:" ,
209+ "\t \t \t break" ,
210+ "\t return x" ,
211+ }, "\n " )
212+ }
213+
187214func (ea * EA ) differentialEvolution () string {
188215 return strings .Join ([]string {
189- fmt .Sprintf ("\t CR = %f" , ea .CrossOverRate ),
190- fmt .Sprintf ("F = %f" , ea .ScalingFactor ),
191216 "\n " ,
192217 "logbook = tools.Logbook()" ,
193218 "logbook.header = 'gen', 'evals', 'std', 'min', 'avg', 'max'" ,
@@ -198,24 +223,101 @@ func (ea *EA) differentialEvolution() string {
198223 "logbook.record(gen=0, evals=len(pop), **record)" ,
199224 "print(logbook.stream)" ,
200225 "for g in range(1, generations):" ,
201- "\t for k, agent in enumerate(pop):" ,
202- "\t \t a,b,c = toolbox.select(pop, 3)" ,
226+ "\t children = []" ,
227+ "\t for agent in pop:" ,
228+ "\t \t a, b, c = [toolbox.clone(ind) for ind in toolbox.select(pop, 3)]" ,
229+ "\t \t x = toolbox.clone(agent)" ,
203230 "\t \t y = toolbox.clone(agent)" ,
204- "\t \t index = random.randrange(N)" ,
205- "\t \t for i, value in enumerate(agent):" ,
206- "\t \t \t if i == index or random.random() < CR:" ,
207- "\t \t \t \t y[i] = a[i] + F*(b[i]-c[i])" ,
208- "\t \t y.fitness.values = toolbox.evaluate(y)" ,
209- "\t \t if y.fitness > agent.fitness:" ,
210- "\t \t \t pop[k] = y" ,
231+ "\t \t y = toolbox.mutate(y, a, b, c)" ,
232+ "\t \t z = toolbox.mate(x, y)" ,
233+ "\t \t del z.fitness.values" ,
234+ "\t \t children.append(z)" ,
235+ "\n " ,
236+ "\t fitnesses = toolbox.map(toolbox.evaluate, children)" ,
237+ "\t for (i, ind), fit in zip(enumerate(children), fitnesses):" ,
238+ "\t \t ind.fitness.values = fit" ,
239+ "\t \t if ind.fitness > pop[i].fitness:" ,
240+ "\t \t \t pop[i] = ind" ,
241+ "\n " ,
211242 "\t hof.update(pop)" ,
212243 "\t record = stats.compile(pop)" ,
213244 "\t logbook.record(gen=g, evals=len(pop), **record)" ,
214245 "\t print(logbook.stream)" ,
215- "\n " ,
216246 }, "\n \t " )
217247}
218248
249+ func (ea * EA ) deMutationFunction () string {
250+ switch ea .MutationFunction {
251+ case "DE/rand/1" :
252+ return strings .Join ([]string {
253+ "def mutDE(y, a, b, c, f):" ,
254+ "\t size = len(y)" ,
255+ "\t for i in range(len(y)):" ,
256+ "\t \t y[i] = a[i] + f*(b[i]-c[i])" ,
257+ "\t return y" ,
258+ }, "\n " )
259+ case "DE/rand/2" :
260+ return strings .Join ([]string {
261+ "def mutDE_rand2(y, a, b, c, d, e, f):" ,
262+ "\t size = len(y)" ,
263+ "\t for i in range(size):" ,
264+ "\t \t y[i] = a[i] + f * (b[i] - c[i]) + f * (d[i] - e[i])" ,
265+ "\t return y" ,
266+ }, "\n " )
267+ case "DE/best/1" :
268+ return strings .Join ([]string {
269+ "def mutDE_best1(y, best, b, c, f):" ,
270+ "\t size = len(y)" ,
271+ "\t for i in range(size):" ,
272+ "\t \t y[i] = best[i] + f * (b[i] - c[i])" ,
273+ "\t return y" ,
274+ }, "\n " )
275+ case "DE/best/2" :
276+ return strings .Join ([]string {
277+ "def mutDE_best2(y, best, b, c, d, e, f):" ,
278+ "\t size = len(y)" ,
279+ "\t for i in range(size):" ,
280+ "\t \t y[i] = best[i] + f * (b[i] - c[i]) + f * (d[i] - e[i])" ,
281+ "\t return y" ,
282+ }, "\n " )
283+ case "DE/current-to-best/1" :
284+ return strings .Join ([]string {
285+ "def mutDE_current_to_best1(y, x, best, b, c, f):" ,
286+ "\t size = len(y)" ,
287+ "\t for i in range(size):" ,
288+ "\t \t y[i] = x[i] + f * (best[i] - x[i]) + f * (b[i] - c[i])" ,
289+ "\t return y" ,
290+ }, "\n " )
291+ case "DE/current-to-rand/1" :
292+ return strings .Join ([]string {
293+ "def mutDE_current_to_rand1(y, x, a, b, c, f):" ,
294+ "\t size = len(y)" ,
295+ "\t K = random.uniform(0, 1) # Random number in [0, 1]" ,
296+ "\t for i in range(size):" ,
297+ "\t \t y[i] = x[i] + K * (a[i] - x[i]) + f * (b[i] - c[i])" ,
298+ "\t return y" ,
299+ }, "\n " )
300+ case "DE/rand-to-best/1" :
301+ return strings .Join ([]string {
302+ "def mutDE_rand_to_best1(y, a, best, b, c, f):" ,
303+ "\t size = len(y)" ,
304+ "\t for i in range(size):" ,
305+ "\t \t y[i] = a[i] + f * (best[i] - a[i]) + f * (b[i] - c[i])" ,
306+ "\t return y" ,
307+ }, "\n " )
308+ default :
309+ return strings .Join ([]string {
310+ "def mutDE(y, a, b, c, f):" ,
311+ "\t size = len(y)" ,
312+ "\t for i in range(len(y)):" ,
313+ "\t \t y[i] = a[i] + f*(b[i]-c[i])" ,
314+ "\t return y" ,
315+ }, "\n " )
316+
317+ }
318+
319+ }
320+
219321func (ea * EA ) Code () (string , error ) {
220322 if err := ea .validate (); err != nil {
221323 return "" , err
@@ -224,6 +326,19 @@ func (ea *EA) Code() (string, error) {
224326 var code string
225327 code += ea .imports () + "\n \n "
226328 code += ea .evalFunction () + "\n \n "
329+
330+ if ea .Algorithm == "de" {
331+ code += strings .Join ([]string {
332+ "def mutDE(y, a, b, c, f):" ,
333+ "\t size = len(y)" ,
334+ "\t for i in range(len(y)):" ,
335+ "\t \t y[i] = a[i] + f*(b[i]-c[i])" ,
336+ "\t return y" ,
337+ }, "\n " ) + "\n \n "
338+ code += ea .deMutationFunction () + "\n \n "
339+ }
340+
341+ code += ea .deCrossOverFunctions () + "\n \n "
227342 code += ea .CustomPop + "\n "
228343 code += ea .CustomMutation + "\n "
229344 code += ea .CustomSelection + "\n \n "
@@ -237,7 +352,14 @@ func (ea *EA) Code() (string, error) {
237352 code += ea .initialGenerator () + "\n "
238353 code += fmt .Sprintf ("toolbox.register(\" evaluate\" , %s)\n " , ea .EvaluationFunction )
239354 code += ea .mutationFunction () + "\n "
240- code += fmt .Sprintf ("toolbox.register(\" mate\" , tools.%s)\n " , ea .CrossoverFunction )
355+
356+ if ea .Algorithm == "de" {
357+ code += fmt .Sprintf ("CR = %f\n " , ea .CrossOverRate )
358+ code += fmt .Sprintf ("F = %f\n " , ea .ScalingFactor )
359+ code += fmt .Sprintf ("toolbox.register(\" mate\" , %s, cr=CR)\n " , ea .CrossoverFunction )
360+ } else {
361+ code += fmt .Sprintf ("toolbox.register(\" mate\" , tools.%s)\n " , ea .CrossoverFunction )
362+ }
241363 code += ea .selectionFunction () + "\n "
242364 code += "\n toolbox.register(\" map\" , futures.map)\n \n "
243365
@@ -261,7 +383,17 @@ func (ea *EA) Code() (string, error) {
261383 code += ea .callAlgo () + "\n "
262384 }
263385
264- code += "\t print(f'Best individual is: {hof[0]}\\ nwith fitness: {hof[0].fitness}')"
386+ code += "\n \t rootPath = os.path.dirname(os.path.abspath(__file__))\n "
387+ code += "\t with open(f\" {rootPath}/logbook.txt\" , \" w\" ) as f:\n "
388+ code += "\t \t f.write(str(logbook))\n "
389+ code += "\n "
390+
391+ // Write best individual to file.
392+ code += "\t out_file = open(f\" {rootPath}/best.txt\" , \" w\" )\n "
393+ code += "\t out_file.write(f\" Best individual fitness: {hof[0].fitness.values}\\ n\" )\n "
394+ code += "\n "
395+ code += "\t out_file.write(f\" Best individual: {hof[0]}\\ n\" )\n "
396+ code += "\t out_file.close()\n "
265397 code += "\n \n "
266398 code += ea .plots ()
267399 code += "\n \n "
0 commit comments