def __init__(self): # Init from settings self.max_pop_size = int(settings.Get_Setting("max_pop_size")) self.mutation_rate = float(settings.Get_Setting("mutation_rate")) self.num_cross_points = int( settings.Get_Setting("number_crossover_points")) self.intra_swap_rate = int(settings.Get_Setting("intra_swap_rate")) # Init the rest... self.is_init = false self.average_fitness = 0 self.current_pop = {} self.culled_pop = {} self.eval_cache = {} self.breeders = [] self.offspring = [] self.evaluators = [] # Init the offspring and current population self.Genesis() # Init the evaluators num_procs = int(settings.Get_Setting("number_cpus")) eval_type = "smp" for i in range(0, num_procs): self.evaluators.append(eval.Evaluator(eval_type))
def Run_Onevar(self): onev_exe_path = os.path.join(settings.Get_Setting("home_dir"), "onevar.exe") onev_dir_path = settings.Get_Setting("onevar_dir") """ Each command is a [name].1v file. The commands setting is stored as one long string. The string is split by whitespace into separate words so that the files may be processed one by one. They should be processed front to back in case a later command requires output from a prior command(s). """ commands = settings.Get_Setting("onevar_commands").split() for cmd in commands: # Generate the command. Supress errors--they need to be checked for in a non-generic way. # sample: command = [onevar exe path] dir=[run path] in=[.1v path] onev_file_path = os.path.join(onev_dir_path, cmd) cmd_line = onev_exe_path + " dir=" + self.run_path + " in=" + onev_file_path + " NoClick" """ Start the onev processing. We'll wait for each to finish since they run pretty quickly. Sort of INCOMPLETE: For a long running onevar file, our parallelization efficiency will take a hit because our 'main' process is the process waiting around after each run for all of the onev's to be processed. To change this behavior: this function, the Update() function, and the evaluator.progress states will need revision. """ onev_proc = subprocess.Popen([cmd_line], shell=True) onev_proc.wait()
def Dump_Uniques(self): uniques_path = os.path.join(settings.Get_Setting("output_dir"), settings.Get_Setting("uniques_filename")) uniques_dump = open(uniques_path, "w") uniques_dump.write("Current Population:\n") for unique in self.Get_Current_Pop(): uniques_dump.write(unique.To_String() + "\n") uniques_dump.write("Culled Population:\n") for unique in self.Get_Culled_Pop(): uniques_dump.write(unique.To_String() + "\n") uniques_dump.write("Done") uniques_dump.close()
def Genesis(self): # If specified, load uniques from a file. load_uniques = int(settings.Get_Setting("seed_uniques")) if load_uniques: self.Load_Uniques() # Scrape individuals out of the spreadsheet and append them to the offspring. workbook_name = settings.GA_book unscored_inds = utils.Parse_Individuals(workbook_name, "Solver", 18) # Screen out repeats using a local dictionary new_unscored_inds = {} for ind in unscored_inds: ind_tup = utils.Individual_To_Tuple(ind) if ind_tup not in new_unscored_inds: # then we've got a unique unscored individual # add the unscored unique to the offspring and to the 'screening' dictionary self.offspring.append(ind) new_unscored_inds[ind_tup] = 1 # We need at least two offspring or at least two scored individuals for # the ga to get going. Exit if this is not the case. if len(self.offspring) < 2 and len(self.current_pop) < 2: error = len(self.offspring), "offspring and", len(self.current_pop), \ """ in the current population is insufficient to get the ga running. At least two unique unscored OR two unique scored individuals are required.""" print error sys.exit() self.is_init = true
def Update_Console(): Clear_Console() print "\n" * 2 print "--------------------------------------" print "\n" * 2 print "Evaluated " + str(settings.num_evals) + " of " + str(int(settings.Get_Setting("max_evals"))) + "\n\n" print "\n" print "--------------------------------------"
def Prep_Directory(self): run_path = settings.Get_Setting("run_dir") template_dname = settings.Get_Setting("template_dir") src_path = os.path.join(run_path, template_dname) # Generate a directory name. dname = str(random.randint(0, 1000)) + "_ga_run" dest_path = os.path.join(run_path, dname) # Ensure our directory name is unique. while os.path.isdir(dest_path): dname = str(random.randint(0, 1000)) + "_ga_run" dest_path = os.path.join(run_path, dname) # Copy template run into new directory shutil.copytree(src_path, dest_path) self.run_path = dest_path
def Timed_Out(self): timeout_limit = settings.Get_Setting("eval_timeout") # Determine whether we've timed out. curr_time = dt.datetime.now() # Calculate elapsed time in seconds. time_evalling = (curr_time - self.start_time).seconds if time_evalling >= timeout_limit: # then we've timed out... return True return False
def __init__(self, chromosomes, raw_fitness=0.0, state="queue"): self.num_chromosomes = int(settings.Get_Setting("number_chromosomes")) # Ensure the correct number of chromosomes if len(chromosomes) != self.num_chromosomes: print "Error:", self.num_chromosomes, \ "chromosomes needed and", len(chromosomes), "were given." sys.exit() self.chromosomes = chromosomes[:] self.state = state self.raw_fitness = raw_fitness self.fitness = 0
def Set_Score(self): err_score = str(settings.Get_Setting("error_fitness")) # Spawn set_score.py to find the score by some unknown means... proc = subprocess.Popen( ['python set_score.py', self.run_path, err_score], shell=True) proc.wait() # Set the score to the value in the output file final_score.txt score_path = os.path.join(self.run_path, "final_score.txt") for line in utils.Lines_In_File(score_path): if "score" in line: line = line.split(":") self.individual.raw_fitness = float(line[-1])
def Mutate(self): mutation_rate = float(settings.Get_Setting("mutation_rate")) new_genes = [] for gene in self.genes: # Roll the dice to see whether we mutate the gene if random.random() < (mutation_rate / 100): # Parse the gene # gene format: # ([val]*[lower bound]*[upper bound]*[type] gene_members = gene.split("*") type = gene_members[3].strip(")") if type == "f": value = float(gene_members[0].strip("(")) elif type == "i": value = int(gene_members[0].strip("(")) else: print "Unknown gene type: ", type lower_bound = float(gene_members[1]) upper_bound = float(gene_members[2]) # Do the mutation if type == "f": # Mutate the float value = utils.Rand_In_Range(lower_bound, upper_bound) elif type == "i": # Mutate the integer value = random.randint(lower_bound, upper_bound) else: print "Unknown gene type: ", type # Round decimals to two places. Read up on float limitations in Python # for an explanation as to why we cannot simply round the value to two # decimal places. Also, check out the decimal object. if type == "f": rounded_val = "%.3f" % value #print rounded_val, value #raw_input("") new_genes.append("(" + rounded_val + "*" + str(lower_bound) + "*" + str(upper_bound) + "*" + str(type) + ")") else: new_genes.append("(" + str(value) + "*" + str(lower_bound) + "*" + str(upper_bound) + "*" + str(type) + ")") else: new_genes.append(gene) self.genes = new_genes
def Run_Model(self): # generate command home_path = settings.Get_Setting("home_dir") cmd = os.path.join(home_path, "model.exe") + " dir=" + self.run_path # Suppress model.exe msgbox errors for all runs after the first if settings.first_eval: settings.first_eval = False else: # add the flag to supress errors cmd += " NoClick" self.start_time = dt.datetime.now() self.process = subprocess.Popen(cmd, shell=True) # # INCOMPLETE - remove sleep if errors persist. # time.sleep(.25)
def Cull(self): max_pop_size = int(settings.Get_Setting("max_pop_size")) if len(self.current_pop) <= max_pop_size: # then don't cull anyone return # The new population will comprise the top individuals of the # current population. Cull the rest. saved_pop = self.Get_Best_Individuals(max_pop_size) culled_pop = self.Get_Worst_Individuals( len(self.current_pop) - max_pop_size) # Dump the current population to a list and then empty it current_pop_list = self.current_pop.items() self.current_pop.clear() # Rebuild the current population and add to the culled population for saved in saved_pop: self.current_pop[utils.Individual_To_Tuple( saved)] = saved.raw_fitness for culled in culled_pop: self.culled_pop[utils.Individual_To_Tuple( culled)] = culled.raw_fitness
def Crossover(self): # Setup offspring1 = [] offspring2 = [] mate1 = self.breeders[0] mate2 = self.breeders[1] have_not_crossed = false num_chroms = int(settings.Get_Setting("number_chromosomes")) crossover_pts = utils.Generate_Random_Indices(self.num_cross_points, num_chroms) i = 0 # Do the normal crosses and intra chromosomal gene swaps for i in range(0, num_chroms): if i in crossover_pts: # do a cross # Do an intra-chromosomal swap if the rate is >0, otherwise # just do a basic crossover swap of entire chromosomes. if self.intra_swap_rate > 0: chrom1 = mate2.chromosomes[i] chrom2 = mate1.chromosomes[i] # Check for swappability and compatibility if chrom1.Intra_Swappable( ) == True and chrom1.form == chrom2.form: random.seed() chance = random.random() # 'Rolled the dice', now see if we swap... if chance < (self.intra_swap_rate / 100.0): """ Intra-swap logic: In essence, we pick a random swap point and then swap the genes of the two chromosomes from the swap point to the end of the list of genes. """ swap_point = random.randint( 0, len(chrom1.genes) - 1) genes_1a = chrom1.genes[:swap_point] genes_1b = chrom2.genes[swap_point:] genes_1new = genes_1a + genes_1b genes_2a = chrom2.genes[:swap_point] genes_2b = chrom1.genes[swap_point:] genes_2new = genes_2a + genes_2b offspring1.append( chro.Chromosome(genes_1new, chrom1.form, chrom1.swappable)) offspring2.append( chro.Chromosome(genes_2new, chrom2.form, chrom2.swappable)) else: have_not_crossed = true else: have_not_crossed = true else: have_not_crossed = true if have_not_crossed: # Do a basic crossover offspring1.append(mate2.chromosomes[i]) offspring2.append(mate1.chromosomes[i]) else: # No crossing here... offspring1.append(mate1.chromosomes[i]) offspring2.append(mate2.chromosomes[i]) self.offspring.append(ind.Individual(offspring1)) self.offspring.append(ind.Individual(offspring2))
def __init__(self): self.max_evals = int(settings.Get_Setting("max_evals")) self.current_iter = 1 self.population = pop.Population() settings.Log_Setup()
def Set_Error_Score(self): self.individual.raw_fitness = settings.Get_Setting("error_fitness")