forked from scikit-learn/scikit-learn
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Creates changes in _base.py and creates an initial boolean subclass
- Loading branch information
1 parent
a3edd63
commit 73c603c
Showing
3 changed files
with
131 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
|
||
|
||
import random | ||
|
||
# Boolean Non-Semantic Genetic Operators | ||
class GeneticProgram: | ||
def __init__(self, numvars, depth, pop_size, generations, trunc, target_output) -> None: | ||
self.numvars = numvars | ||
self.depth = depth | ||
self.pop_size = pop_size | ||
self.generations = generations | ||
self.trunc = trunc | ||
self.target_output = target_output | ||
self.vars = [] | ||
pass | ||
|
||
def create_vars(self): | ||
self.vars = ['x'+str(i) for i in range(self.numvars)] | ||
|
||
def crossover(self, f1, f2): | ||
'Crossover operator.' | ||
return f1, f2 | ||
|
||
def mutation(self, f): | ||
'Mutation operator.' | ||
return f | ||
|
||
def fitness(self, f): | ||
'Fitness function.' | ||
return f | ||
|
||
def selection(self, f): | ||
'Selection operator.' | ||
return f | ||
|
||
def create_boolean_expression(self, depth): | ||
'Create a random Boolean expression using recursion.' | ||
if depth == 1 or random.random() < 1.0 / (2 ** depth - 1): | ||
return random.choice(self.vars) | ||
if random.random() < 1.0 / 3: | ||
return 'not' + ' ' + self.create_boolean_expression(depth - 1) | ||
pass | ||
|
||
def create_boolean_function(self): | ||
'Create a random Boolean function.' | ||
pass | ||
|
||
def create_boolean_population(self): | ||
'Create initial population of Boolean functions.' | ||
pass | ||
|
||
def run(self): | ||
'Run the genetic program.' | ||
# Create initial population |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,73 @@ | ||
# Author: Adarsh Prusty | ||
|
||
import _base | ||
import itertools | ||
import random | ||
|
||
def targetfunct(*args): | ||
'Parity function of any number of input variables' | ||
return args.count(True) % 2 == 1 | ||
|
||
class GeometricSemanticGeneticProgram: | ||
def __init__(self) -> None: | ||
pass | ||
def __init__(self, GENERATIONS, POPSIZE) -> None: | ||
self.GENERATIONS = GENERATIONS | ||
self.POPSIZE = POPSIZE | ||
self.TRUNC = 0.5 | ||
self.depth = 4 | ||
self.vars = ['x1', 'x2', 'x3', 'x4', 'x5'] | ||
self.boo = _base.BooleanPopulation() | ||
|
||
def boolean_fitness(self, p): | ||
pass | ||
# Uses an error value to determine the fitness of the individual | ||
fit = 0 | ||
somelists = [[True, False] for i in range(5)] | ||
# generate all possible combinations of inputs from somelists | ||
for element in itertools.product(*somelists): | ||
if p(*element) != targetfunct(*element): | ||
fit = fit + 1 | ||
return fit | ||
|
||
def boolean_crossover(self, p1, p2): | ||
pass | ||
mask = self.boo.create_boolean_function(self.depth, self.vars) | ||
offspring = lambda *x: (p1(*x) and mask(*x)) or (p2(*x) and not mask(*x)) | ||
offspring = self.boo.memoize(offspring) # add cache | ||
offspring.geno = lambda: '(('+ p1.geno() + ' and ' + mask.geno() + ') or (' + p2.geno() + ' and not ' + mask.geno() + '))' | ||
return offspring | ||
|
||
def boolean_mutation(self, p): | ||
pass | ||
mintermexpr = ' and '.join([random.choice([x,'not ' + x]) for x in self.vars]) # random minterm expression of n variables | ||
minterm = eval('lambda ' + ', '.join(vars) + ': ' + mintermexpr) # turn minterm into a function | ||
if random.random()<0.5: | ||
offspring = lambda *x: p(*x) or minterm(*x) | ||
offspring = self.boo.memoize(offspring) # add cache | ||
offspring.geno = lambda: '(' + p.geno() + ' or ' + mintermexpr + ')' # to reconstruct genotype | ||
else: | ||
offspring = lambda *x: p(*x) and not minterm(*x) | ||
offspring = self.boo.memoize(offspring) # add cache | ||
offspring.geno = lambda: '(' + p.geno() + ' and not ' + mintermexpr + ')' # to reconstruct genotype | ||
return offspring | ||
|
||
def boolean_selection(self, p): | ||
pass | ||
|
||
|
||
def main(self): | ||
'Main function.' | ||
pop = [self.boo.create_boolean_function(self.depth, self.vars) for _ in range(self.POPSIZE) ] # initialise population | ||
for gen in range(self.GENERATIONS+1): | ||
graded_pop = [ (self.boolean_fitness(ind), ind) for ind in pop ] # evaluate population fitness | ||
sorted_pop = [ ind[1] for ind in sorted(graded_pop)] # sort population on fitness | ||
print ('gen: ', gen , ' min fit: ', self.boolean_fitness(sorted_pop[0]), ' avg fit: ', sum(ind[0] for ind in graded_pop)/(self.POPSIZE*1.0)) # print stats | ||
parent_pop = sorted_pop[:int(self.TRUNC*self.POPSIZE)] # selected parents | ||
if gen == self.GENERATIONS: | ||
break | ||
for i in range(self.POPSIZE): # create offspring population | ||
par = random.sample(parent_pop, 2) # pick two random parents | ||
pop[i] = self.boolean_mutation(self.boolean_crossover(par[0],par[1])) # create offspring | ||
|
||
print ('Best individual in last population: ') | ||
#print (sorted_pop[0]).geno() # reconstruct genotype of final solution (WARNING: EXPONENTIALLY LONG IN NUMBER OF GENERATIONS!) | ||
print ('Query best individual in last population with all True inputs:') | ||
print (sorted_pop[0](*([True] * 5))) # however querying it to make predictions is quick | ||
|
||
gsgp = GeometricSemanticGeneticProgram(10, 10) | ||
gsgp.main() |