1515import random
1616
1717import bitstring as bs
18- import scipy as sp
18+ from scipy import stats
1919import numpy as np
2020
2121import ffs
@@ -50,38 +50,38 @@ def __init__(self, args, logger):
5050self .l = args .l
5151self .N = args .N
5252self .G = args .G
53- self .pr_mutation = args .pr_mutation
54- self .pr_crossover = args .pr_crossover
53+ self .pr_mutation = args .pm
54+ self .pr_crossover = args .pc
5555self .population = []
5656self .current_offspring = []
5757self .nruns = args .nruns
5858self .NG = args .NG
5959self .learn = args .learn
6060self .ff = args .ff
6161self .ce = args .ce
62+ self .max_recovery = 100
6263
6364# Helper objects
6465self .logger = logger
65- self .orig_fitness_vals = np .zeros ((self .G , self .N ))
66- self .norm_fitness_vals = np .zeros ((self .G , self .N ))
67- self .total_fitness_vals = np .zeros ((self .G , self .N ))
68- self .parents = np . zeros (( self .G , 2 ))
66+ self .orig_fitness_vals = np .zeros ((self .G + self . max_recovery , self .N ))
67+ self .norm_fitness_vals = np .zeros ((self .G + self . max_recovery , self .N ))
68+ self .total_fitness_vals = np .zeros ((self .G + self . max_recovery , self .N ))
69+ self .parents = [[ None , None ] for x in xrange ( self .G + self . max_recovery )]
6970self .pr_mut_dist = None
7071self .pr_cr_dist = None
7172self .env_state = 0
7273
7374# Statistics Objects
74- self .avg_fitness_vals = np .zeros ((self .nruns , 2 , self .G ))
75- self .best_fitness_vals = np .zeros ((self .nruns , 2 , self .G ))
76- self .num_correct_bits = np .zeros ((self .nruns , 2 , self .G ))
75+ self .avg_fitness_vals = np .zeros ((self .nruns , 2 , self .G + self . max_recovery ))
76+ self .best_fitness_vals = np .zeros ((self .nruns , 2 , self .G + self . max_recovery ))
77+ self .num_correct_bits = np .zeros ((self .nruns , 2 , self .G + self . max_recovery ))
7778self .recovery_time = 0
7879
7980
8081def initialize_algorithm (self ):
8182# Initialize the population
82- self .logger .info ("Initializing population and genetic environment ..." )
83+ self .logger .info ("Initializing population..." )
8384self .initialize_pop ()
84- self .initialize_env ()
8585self .logger .info ("Initialization Complete." )
8686
8787# Generate probablility distributions for mutation and crossover
@@ -94,6 +94,8 @@ def initialize_algorithm(self):
9494# Initialize the Population
9595def initialize_pop (self ):
9696# Generate N random bitstrings
97+ self .population = []
98+ self .current_offspring = []
9799for i in range (self .N ):
98100tmp_bitstring = '' .join (random .choice ('01' ) for _ in range (self .N ))
99101tmp_bitstring = bs .BitArray (bin = tmp_bitstring )
@@ -102,9 +104,10 @@ def initialize_pop(self):
102104# Initialize the genetic environment
103105def initialize_env (self ):
104106# Get the appropriate fitness function
107+ self .logger .info ("Initializing environment..." )
105108if self .env_state != 0 :
106109self .recovery_time = 0
107- self .ff = random . choice ([ 'fitness_func_2' ] )
110+ self .logger . info ( "Initialized environment." )
108111
109112# Generate probability distributions for mutation and crossover
110113def generate_prob_distributions (self ):
@@ -119,52 +122,118 @@ def generate_prob_distributions(self):
119122
120123# Generate the object that will be used to get random numbers
121124# according to each distribution.
122- self .pr_mut_dist = sp . stats .rv_discrete (name = 'pr_mut_dist' ,
125+ self .pr_mut_dist = stats .rv_discrete (name = 'pr_mut_dist' ,
123126values = (xk , pk1 ))
124- self .pr_cr_dist = sp . stats .rv_discrete (name = 'pr_cr_dist' ,
127+ self .pr_cr_dist = stats .rv_discrete (name = 'pr_cr_dist' ,
125128values = (xk , pk2 ))
126129
127130# Calculate the fitness of each individual of the population
128131def fitness (self , g , nrun , ff = ffs .fitness_func_1 ):
129132total_fitness = 0
130133
134+ self .logger .debug ("Getting fitness of generation %d" % g )
135+
131136# Step through each bitstring in the population
132137for i , bitstring in enumerate (self .population ):
133138# Get the integer value of the string
134139bit_sum = bitstring .uint
135- fitness_val = ff (bit_sum , self .l )
140+ self .logger .debug ("Sum of bitstring at %d of population: %d" % (i , bit_sum ))
141+ fitness_val = self .ff (bit_sum , self .l )
136142self .orig_fitness_vals [g ][i ] = fitness_val
143+ self .logger .debug ("Fitness Value at index %d in population: %lf" % (i , fitness_val ))
137144total_fitness += fitness_val
138145
146+ self .logger .debug ("Total fitness from step 1: %lf" % total_fitness )
147+
148+ self .norm_fitness_vals [g ] = self .orig_fitness_vals [g ] / total_fitness
149+ self .logger .debug ("Sum of norm fitness vals: %lf" % np .sum (self .norm_fitness_vals [g ]))
150+
151+ prev_norm_fitness_val = 0
139152for i in range (self .N ):
140- norm_fitness_val = (self .orig_fitness_vals [g ][i ] / total_fitness )
141- self .norm_fitness_vals [g ][i ] = norm_fitness_val
142- if i != 0 :
143- self .total_fitness_vals [g ][i ] = (
144- self .norm_fitness_vals [g ][i - 1 ] + norm_fitness_val )
145- else :
146- self .total_fitness_vals [g ][i ] = norm_fitness_val
153+ self .logger .debug ("Normalized Fitness Value at index %d in population: %lf" % (i , self .norm_fitness_vals [g ][i ]))
154+ self .total_fitness_vals [g ][i ] = (
155+ self .norm_fitness_vals [g ][i ] + prev_norm_fitness_val )
156+ prev_norm_fitness_val = self .total_fitness_vals [g ][i ]
157+ self .logger .debug ("Total Fitness Value at index %d in population: %lf" % (i , self .total_fitness_vals [g ][i ]))
147158
148159# Select parents from population
149160def select (self , g ):
150161rand_nums = np .random .uniform (0 , 1 , 2 )
151162
152163# Select the first parent
164+ self .logger .info ("Selecting the first parent..." )
153165prev_individual_fit = 0
154- for j , individual_fit in enumerate (self .total_fitness_vals [g ]):
166+ j = 0
167+ while True :
168+ if j >= self .N :
169+ j = 0
170+ rand_nums = np .random .uniform (0 , 1 , 2 )
171+
172+ individual_fit = self .total_fitness_vals [g ][j ]
173+ if rand_nums [0 ] < self .total_fitness_vals [g ][0 ]:
174+ self .logger .debug ("1: Prev_Individual Fit: %lf" % prev_individual_fit )
175+ self .logger .debug ("1: Individual Fit: %lf" % individual_fit )
176+ self .logger .debug ("1: Rand Num: %lf" % rand_nums [0 ])
177+ self .logger .debug ("1: Population at %d: %s" % (j , self .population [j ].bin ))
178+ self .parents [g ][0 ] = self .population [0 ]
179+ break
180+
155181if j != 0 :
182+ self .logger .debug ("1: Prev_Individual Fit: %lf" % prev_individual_fit )
183+ self .logger .debug ("1: Individual Fit: %lf" % individual_fit )
184+ self .logger .debug ("1: Rand Num: %lf" % rand_nums [0 ])
185+ self .logger .debug ("1: Population at %d: %s" % (j , self .population [j ].bin ))
186+
156187if (prev_individual_fit <= rand_nums [0 ] <= individual_fit ):
157- self .parents [g ][0 ] = individual_fit
188+ self .logger .debug ("1: selected individuval from population at %d: %s" % (j , self .population [j ].bin ))
189+ self .parents [g ][0 ] = self .population [j ]
190+ self .logger .debug ("1: parents[%d][0]: %s" % (g , str (self .parents [g ][0 ])))
191+ break
158192prev_individual_fit = individual_fit
193+ j += 1
194+ self .logger .info ("First parent has been selected." )
159195
160- # Select the second parents
196+ # Select the second parent
197+ self .logger .info ("Selecting the second parent..." )
161198prev_individual_fit = 0
162- for j , individual_fit in enumerate (self .total_fitness_vals [g ]):
199+ j = 0
200+ cycles = 0
201+ while True :
202+ if j >= self .N :
203+ cycles += j
204+ if cycles >= 100 :
205+ self .parents [g ][1 ] = self .parents [g ][0 ]
206+ break
207+ else :
208+ j = 0
209+ rand_nums = np .random .uniform (0 , 1 , 2 )
210+
211+ individual_fit = self .total_fitness_vals [g ][j ]
212+ if rand_nums [1 ] < self .total_fitness_vals [g ][0 ]:
213+ self .logger .debug ("2: prev_individual fit: %lf" % prev_individual_fit )
214+ self .logger .debug ("2: individual fit: %lf" % individual_fit )
215+ self .logger .debug ("2: rand num: %lf" % rand_nums [1 ])
216+ self .logger .debug ("2: population at %d: %s" % (j , self .population [j ].bin ))
217+ self .parents [g ][1 ] = self .population [0 ]
218+ break
219+
163220if j != 0 :
221+ self .logger .debug ("2: prev_individual fit: %lf" % prev_individual_fit )
222+ self .logger .debug ("2: individual fit: %lf" % individual_fit )
223+ self .logger .debug ("2: rand num: %lf" % rand_nums [1 ])
224+ self .logger .debug ("2: population at %d: %s" % (j , self .population [j ].bin ))
225+
164226if (prev_individual_fit <= rand_nums [1 ] <= individual_fit ):
165- if (individual_fit != self .parents [g ][0 ]):
166- self .parents [g ][1 ] = individual_fit
227+ if (self .population [j ] != self .parents [g ][0 ]):
228+ self .logger .debug ("2: selected individuval from population at %d: %s" % (j , self .population [j ].bin ))
229+ self .parents [g ][1 ] = self .population [j ]
230+ self .logger .debug ("1: parents[%d][0]: %s" % (g , str (self .parents [g ][1 ])))
231+ break
232+
167233prev_individual_fit = individual_fit
234+ j += 1
235+
236+ self .logger .info ("Second parent has been selected." )
168237
169238# Mutate the parents
170239def mutate (self , g ):
@@ -178,9 +247,10 @@ def mutate(self, g):
178247if to_mutate :
179248parent .invert (index_bit )
180249
250+
181251# Crossover the parents
182252def crossover (self , g ):
183- to_crossover = self .pr_cross_dist .rvs (size = 1 )
253+ to_crossover = self .pr_cr_dist .rvs (size = 1 )
184254
185255# Crossover the parents if to_crossover is 1, otherwise copy the
186256# parents exactly into the children
@@ -190,13 +260,13 @@ def crossover(self, g):
190260c2 = bs .BitArray (length = self .N )
191261
192262# Select the bit at which to crossover the parents
193- crossover_bit = random .randint (0 , self .N )
263+ crossover_bit = random .randint (0 , self .l )
194264
195265# Perform the crossover
196266c1 .overwrite (self .parents [g ][0 ][:crossover_bit ], 0 )
197- c1 .overwrite (self .parents [g ][1 ][:crossover_bit ], crossover_bit )
267+ c1 .overwrite (self .parents [g ][1 ][:( self . l - crossover_bit ) ], crossover_bit )
198268c2 .overwrite (self .parents [g ][1 ][:crossover_bit ], 0 )
199- c2 .overwrite (self .parents [g ][0 ][:crossover_bit ], crossover_bit )
269+ c1 .overwrite (self .parents [g ][0 ][:( self . l - crossover_bit ) ], crossover_bit )
200270
201271self .current_offspring .append (c1 )
202272self .current_offspring .append (c2 )
@@ -229,7 +299,7 @@ def learn_offspring(self, g, ff=ffs.fitness_func_1):
229299if current_fitness == max_fitness :
230300child = current_child
231301
232- def compute_statistics (self , g , nrun , env_state ):
302+ def compute_statistics (self , g , nrun ):
233303# Get the number of correct bits in the best individual
234304index_bi = self .orig_fitness_vals [g ].argmax ()
235305bi_bitstring = self .population [index_bi ]
@@ -253,8 +323,10 @@ def compute_statistics(self, g, nrun, env_state):
253323# Check if the population has recovered from an environment change
254324def check_population_recovery (self , g , nrun ):
255325checks = []
256- checks .append (self .best_fitness_vals [nrun ][self .env_state ][g ] > self .best_fitness_vals [nrun ][self .env_state - 1 ][self .G - 1 ])
257- checks .append (self .avg_fitness_vals [nrun ][self .env_state ][g ] > self .avg_fitness_vals [nrun ][self .env_state - 1 ][self .G - 1 ])
326+ checks .append ((self .best_fitness_vals [nrun ][1 ][g ] > self .best_fitness_vals [nrun ][0 ][self .G - 1 ]))
327+ checks .append ((self .avg_fitness_vals [nrun ][1 ][g ] > self .avg_fitness_vals [nrun ][0 ][self .G - 1 ]))
328+ for check in checks :
329+ print check
258330if all (checks ):
259331return True
260332
@@ -291,38 +363,48 @@ def reproduce(self, nrun, g):
291363" of generation %d finished." % g )
292364
293365# Compute statistics for this generation
294- self .logger .info ("Computing statistics for Run %d, " +
295- "Generation %d..." % nrun , g )
366+ self .logger .info ("Computing statistics for Run %d, Generation %d..." % (nrun , g ))
296367self .compute_statistics (g , nrun )
297- self .logger .info ("Computing statistics for Run %d, " +
298- "Generation %d." % nrun , g )
368+ self .logger .info ("Computation of statistics finished for Run %d, Generation %d." % (nrun , g ))
299369
300370# Replace the old population with the new population
301371self .population = self .current_offspring
302- self .logger . info ( "Generation %d finished." % g )
372+ self .current_offspring = []
303373
304374# Run through the total runs specified
305375def run (self ):
306- for nrun in xrange ( 0 , self .nruns ):
376+ for nrun in range ( self .nruns ):
307377self .logger .info ("Starting run %d..." % nrun )
308378self .initialize_algorithm ()
309379
310- for g in xrange (0 , self .G ):
380+ self .env_state = 0
381+ self .ff = ffs .fitness_func_1
382+ self .logger .info ("Fitness Function before normal generation run: %s" % str (self .ff .__name__ ))
383+
384+ for g in range (self .G ):
385+ self .logger .info ("Generation %d running..." % g )
311386self .reproduce (nrun , g )
387+ self .logger .info ("Generation %d finished." % g )
312388
313389if self .ce :
314- self .logger .info ("Running Sudden change in environment test..." )
390+ self .logger .info ("Running Sudden change in environment test starting at generation %d ..." % g )
315391self .env_state = 1
316392self .initialize_env ()
393+ self .ff = ffs .fitness_func_2
394+ self .logger .info ("Fitness Function before changed environment generation run: %s" % str (self .ff .__name__ ))
317395
318396while True :
397+ g += 1
398+ self .recovery_time += 1
399+ self .logger .info ("Recovery Time: %d, Max Recovery: %d, Generation %d In Changed Environment" % (self .recovery_time , self .max_recovery , g ))
400+ if self .recovery_time >= self .max_recovery :
401+ self .logger .info ("Population has not recovered after %d iterations. Quitting now." % self .recovery_time )
402+ break
319403self .reproduce (nrun , g )
320404if self .check_population_recovery (g , nrun ):
321- self .logger .info ("Population has recovered after %d " +
322- "iterations." % self .recovery_time )
405+ self .logger .info ("Population has recovered after %d iterations." % self .recovery_time )
323406break
324407self .logger .info ("Population has not recovered...continuing generation." )
325- self .recovery_time += 1
326408
327409self .logger .info ("Finished run %d." % nrun )
328410
0 commit comments