2016-08-10 00:07:52 -06:00
# Karoo GP Main (desktop)
2015-11-04 03:56:07 -07:00
# Use Genetic Programming for Classification and Symbolic Regression
2017-02-07 01:33:38 -07:00
# by Kai Staats, MSc; see LICENSE.md
# Thanks to Emmanuel Dufourq and Arun Kumar for support during 2014-15 devel; TensorFlow support provided by Iurii Milovanov
2017-07-03 16:47:04 -06:00
# version 1.0.4
2015-11-04 03:56:07 -07:00
'''
2016-07-13 22:43:06 -06:00
A word to the newbie , expert , and brave - -
2016-07-18 07:23:12 -06:00
Even if you are highly experienced in Genetic Programming , it is recommended that you review the ' Karoo User Guide '
2016-07-13 22:43:06 -06:00
before running this application . While your computer will not burst into flames nor will the sun collapse into a black
hole if you do not , you will likely find more enjoyment of this particular flavour of GP with a little understanding
of its intent and design .
KAROO GP DESKTOP
This is the Karoo GP desktop application . It presents a simple yet functional user interface for configuring each
Karoo GP run . While this can be launched on a remote server , you may find that once you get the hang of using Karoo ,
and are in more of a production mode than one of experimentation , using karoo_gp_server . py is more to your liking as
it provides both a scripted and / or command - line launch vehicle .
To launch Karoo GP desktop :
$ python karoo_gp_main . py
( or from iPython )
$ run karoo_gp_main . py
If you include the path to an external dataset , it will auto - load at launch :
$ python karoo_gp_main . py / [ path ] / [ to_your ] / [ filename ] . csv
2015-11-04 03:56:07 -07:00
'''
2016-07-13 22:43:06 -06:00
import sys # sys.path.append('modules/') to add the directory 'modules' to the current path
2015-11-04 03:56:07 -07:00
import karoo_gp_base_class ; gp = karoo_gp_base_class . Base_GP ( )
2017-06-06 22:12:55 -06:00
import time
2017-02-07 01:33:38 -07:00
2015-11-04 03:56:07 -07:00
#++++++++++++++++++++++++++++++++++++++++++
# User Defined Configuration |
#++++++++++++++++++++++++++++++++++++++++++
'''
Karoo GP queries the user for key parameters , some of which may be adjusted during run - time
at user invoked pauses . See the User Guide for meaning and value of each of the following parameters .
Future versions will enable all of these parameters to be configured via an external configuration file and / or
command - line arguments passed at launch .
'''
2016-07-13 22:43:06 -06:00
gp . karoo_banner ( )
2015-11-04 03:56:07 -07:00
print ' '
2017-02-07 01:33:38 -07:00
menu = [ ' c ' , ' r ' , ' m ' , ' p ' , ' ' ]
2015-11-04 03:56:07 -07:00
while True :
try :
2017-02-07 01:33:38 -07:00
gp . kernel = raw_input ( ' \t Select (c)lassification, (r)egression, (m)atching, or (p)lay (default m): ' )
2016-07-10 02:55:44 -06:00
if gp . kernel not in menu : raise ValueError ( )
2015-11-04 03:56:07 -07:00
gp . kernel = gp . kernel or ' m ' ; break
2016-07-10 02:55:44 -06:00
except ValueError : print ' \t \033 [32m Select from the options given. Try again ... \n \033 [0;0m '
except KeyboardInterrupt : sys . exit ( )
2015-11-04 03:56:07 -07:00
2016-08-10 00:07:52 -06:00
if gp . kernel == ' p ' :
menu = [ ' f ' , ' g ' , ' ' ]
while True :
try :
tree_type = raw_input ( ' \t Select (f)ull or (g)row method (default f): ' )
if tree_type not in menu : raise ValueError ( )
tree_type = tree_type or ' f ' ; break
except ValueError : print ' \t \033 [32m Select from the options given. Try again ... \n \033 [0;0m '
except KeyboardInterrupt : sys . exit ( )
else :
menu = [ ' f ' , ' g ' , ' r ' , ' ' ]
while True :
try :
tree_type = raw_input ( ' \t Select (f)ull, (g)row, or (r)amped 50/50 method (default r): ' )
if tree_type not in menu : raise ValueError ( )
tree_type = tree_type or ' r ' ; break
except ValueError : print ' \t \033 [32m Select from the options given. Try again ... \n \033 [0;0m '
except KeyboardInterrupt : sys . exit ( )
2015-11-04 03:56:07 -07:00
2016-07-10 02:55:44 -06:00
menu = range ( 1 , 11 )
2015-11-04 03:56:07 -07:00
while True :
try :
2016-07-11 01:53:18 -06:00
tree_depth_base = raw_input ( ' \t Enter depth of the \033 [3minitial \033 [0;0m population of Trees (default 3): ' )
if tree_depth_base not in str ( menu ) or tree_depth_base == ' 0 ' : raise ValueError ( )
tree_depth_base = tree_depth_base or 3 ; tree_depth_base = int ( tree_depth_base ) ; break
except ValueError : print ' \t \033 [32m Enter a number from 1 including 10. Try again ... \n \033 [0;0m '
2016-07-10 02:55:44 -06:00
except KeyboardInterrupt : sys . exit ( )
2015-11-04 03:56:07 -07:00
2016-07-10 02:55:44 -06:00
2015-11-04 03:56:07 -07:00
if gp . kernel == ' p ' : # if the Play kernel is selected
2016-07-11 01:53:18 -06:00
gp . tree_depth_max = tree_depth_base
2015-11-04 03:56:07 -07:00
gp . tree_pop_max = 1
gp . display = ' m '
else : # if any other kernel is selected
2016-07-11 01:53:18 -06:00
if tree_type == ' f ' : gp . tree_depth_max = tree_depth_base
else : # if type is Full, the maximum Tree depth for the full run is equal to the initial population
menu = range ( tree_depth_base , 11 )
while True :
try :
gp . tree_depth_max = raw_input ( ' \t Enter maximum Tree depth (default matches \033 [3minitial \033 [0;0m): ' )
if gp . tree_depth_max not in str ( menu ) or gp . tree_depth_max == ' 0 ' : raise ValueError ( )
gp . tree_depth_max = gp . tree_depth_max or tree_depth_base ; gp . tree_depth_max = int ( gp . tree_depth_max ) ; break
# gp.tree_depth_max = int(gp.tree_depth_max) - tree_depth_base; break
except ValueError : print ' \t \033 [32m Enter a number >= the maximum Tree depth. Try again ... \n \033 [0;0m '
except KeyboardInterrupt : sys . exit ( )
2016-07-10 02:55:44 -06:00
menu = range ( 3 , 101 )
2015-11-04 03:56:07 -07:00
while True :
try :
gp . tree_depth_min = raw_input ( ' \t Enter minimum number of nodes for any given Tree (default 3): ' )
2016-07-10 02:55:44 -06:00
if gp . tree_depth_min not in str ( menu ) or gp . tree_depth_min == ' 0 ' : raise ValueError ( )
2015-11-04 03:56:07 -07:00
gp . tree_depth_min = gp . tree_depth_min or 3 ; gp . tree_depth_min = int ( gp . tree_depth_min ) ; break
2016-07-10 02:55:44 -06:00
except ValueError : print ' \t \033 [32m Enter a number from 3 to 2^(depth + 1) - 1 including 100. Try again ... \n \033 [0;0m '
except KeyboardInterrupt : sys . exit ( )
2015-11-04 03:56:07 -07:00
2016-07-10 02:55:44 -06:00
menu = range ( 10 , 1001 )
2015-11-04 03:56:07 -07:00
while True :
try :
2016-07-11 23:07:44 -06:00
gp . tree_pop_max = raw_input ( ' \t Enter number of Trees in each population (default 100): ' )
2016-07-10 02:55:44 -06:00
if gp . tree_pop_max not in str ( menu ) or gp . tree_pop_max == ' 0 ' : raise ValueError ( )
2015-11-04 03:56:07 -07:00
gp . tree_pop_max = gp . tree_pop_max or 100 ; gp . tree_pop_max = int ( gp . tree_pop_max ) ; break
2016-07-10 02:55:44 -06:00
except ValueError : print ' \t \033 [32m Enter a number from 10 including 1000. Try again ... \n \033 [0;0m '
except KeyboardInterrupt : sys . exit ( )
2015-11-04 03:56:07 -07:00
2016-07-10 02:55:44 -06:00
menu = range ( 1 , 101 )
2015-11-04 03:56:07 -07:00
while True :
try :
2016-07-11 23:07:44 -06:00
gp . generation_max = raw_input ( ' \t Enter max number of generations (default 10): ' )
2016-07-10 02:55:44 -06:00
if gp . generation_max not in str ( menu ) or gp . generation_max == ' 0 ' : raise ValueError ( )
2015-11-04 03:56:07 -07:00
gp . generation_max = gp . generation_max or 10 ; gp . generation_max = int ( gp . generation_max ) ; break
2016-07-10 02:55:44 -06:00
except ValueError : print ' \t \033 [32m Enter a number from 1 including 100. Try again ... \n \033 [0;0m '
except KeyboardInterrupt : sys . exit ( )
2015-11-04 03:56:07 -07:00
2017-02-07 01:33:38 -07:00
menu = [ ' i ' , ' g ' , ' m ' , ' s ' , ' db ' , ' ' ]
2015-11-04 03:56:07 -07:00
while True :
try :
2017-02-09 10:00:16 -07:00
gp . display = raw_input ( ' \t Display (i)nteractive, (g)eneration, (m)iminal, (s)ilent, or (d)e(b)ug (default m): ' )
2016-07-10 02:55:44 -06:00
if gp . display not in menu : raise ValueError ( )
2015-11-04 03:56:07 -07:00
gp . display = gp . display or ' m ' ; break
2016-07-10 02:55:44 -06:00
except ValueError : print ' \t \033 [32m Select from the options given. Try again ... \n \033 [0;0m '
except KeyboardInterrupt : sys . exit ( )
2015-11-04 03:56:07 -07:00
# define the ratio between types of mutation, where all sum to 1.0; can be adjusted in 'i'nteractive mode
2017-02-07 01:33:38 -07:00
gp . evolve_repro = int ( 0.1 * gp . tree_pop_max ) # quantity of a population generated through Reproduction
2017-02-08 23:33:43 -07:00
gp . evolve_point = int ( 0.0 * gp . tree_pop_max ) # quantity of a population generated through Point Mutation
gp . evolve_branch = int ( 0.2 * gp . tree_pop_max ) # quantity of a population generated through Branch Mutation
2017-02-07 01:33:38 -07:00
gp . evolve_cross = int ( 0.7 * gp . tree_pop_max ) # quantity of a population generated through Crossover
2015-11-04 03:56:07 -07:00
gp . tourn_size = 10 # qty of individuals entered into each tournament (standard 10); can be adjusted in 'i'nteractive mode
2017-07-03 16:47:04 -06:00
gp . precision = 6 # the number of floating points for the round function in 'fx_fitness_eval'; hard coded
2015-11-04 03:56:07 -07:00
#++++++++++++++++++++++++++++++++++++++++++
# Construct First Generation of Trees |
#++++++++++++++++++++++++++++++++++++++++++
'''
Karoo GP constructs the first generation of Trees . All subsequent generations evolve from priors , with no new Trees
constructed from scratch . All parameters which define the Trees were set by the user in the previous section .
If the user has selected ' Play ' mode , this is the only generation to be constructed , and then GP Karoo terminates .
'''
2017-06-06 22:12:55 -06:00
start = time . time ( ) # start the clock for the timer
2016-07-13 22:43:06 -06:00
filename = ' ' # temp place holder
gp . fx_karoo_data_load ( tree_type , tree_depth_base , filename )
2015-11-04 03:56:07 -07:00
gp . generation_id = 1 # set initial generation ID
gp . population_a = [ ' Karoo GP by Kai Staats, Generation ' + str ( gp . generation_id ) ] # an empty list which will store all Tree arrays, one generation at a time
2016-07-11 01:53:18 -06:00
gp . fx_karoo_construct ( tree_type , tree_depth_base ) # construct the first population of Trees
2015-11-04 03:56:07 -07:00
if gp . kernel != ' p ' : print ' \n We have constructed a population of ' , gp . tree_pop_max , ' Trees for Generation 1 \n '
else : # EOL for Play mode
2017-02-07 01:33:38 -07:00
gp . fx_display_tree ( gp . tree ) # print the current Tree
gp . fx_archive_tree_write ( gp . population_a , ' a ' ) # save this one Tree to disk
2015-11-04 03:56:07 -07:00
sys . exit ( )
#++++++++++++++++++++++++++++++++++++++++++
# Evaluate First Generation of Trees |
#++++++++++++++++++++++++++++++++++++++++++
'''
Karoo GP evaluates the first generation of Trees . This process flattens each GP Tree into a standard
equation by means of a recursive algorithm and subsequent processing by the SymPy library which
simultaneously evaluates the Tree for its results , returns null for divide by zero , reorganises
and then rewrites the expression in its simplest form .
If the user has defined only 1 generation , then this is the end of the run . Else , Karoo GP
continues into multi - generational evolution .
'''
if gp . display != ' s ' :
print ' Evaluate the first generation of Trees ... '
if gp . display == ' i ' : gp . fx_karoo_pause ( 0 )
2017-06-06 22:12:55 -06:00
gp . fx_fitness_gym ( gp . population_a ) # generate expression, evaluate fitness, compare fitness
2017-02-07 01:33:38 -07:00
gp . fx_archive_tree_write ( gp . population_a , ' a ' ) # save the first generation of Trees to disk
2015-11-04 03:56:07 -07:00
# no need to continue if only 1 generation or fewer than 10 Trees were designated by the user
if gp . tree_pop_max < 10 or gp . generation_max == 1 :
2017-02-07 01:33:38 -07:00
gp . fx_archive_params_write ( ' Desktop ' ) # save run-time parameters to disk
gp . fx_karoo_eol ( )
sys . exit ( )
2015-11-04 03:56:07 -07:00
#++++++++++++++++++++++++++++++++++++++++++
# Evolve Multiple Generations |
#++++++++++++++++++++++++++++++++++++++++++
'''
Karoo GP moves into multi - generational evolution .
In the following four evolutionary methods , the global list of arrays ' gp.population_a ' is repeatedly recycled as
the prior generation from which the local list of arrays ' gp.population_b ' is created , one array at a time . The ratio of
invocation of the four evolutionary processes for each generation is set by the parameters in the ' User Defined
Configuration ' (top).
'''
for gp . generation_id in range ( 2 , gp . generation_max + 1 ) : # loop through 'generation_max'
print ' \n Evolve a population of Trees for Generation ' , gp . generation_id , ' ... '
2017-07-03 16:47:04 -06:00
gp . population_b = [ ' Karoo GP by Kai Staats, Evolving Generation ' ] # initialise population_b to host the next generation
2015-11-04 03:56:07 -07:00
gp . fx_fitness_gene_pool ( ) # generate the viable gene pool (compares against gp.tree_depth_min)
gp . fx_karoo_reproduce ( ) # method 1 - Reproduction
gp . fx_karoo_point_mutate ( ) # method 2 - Point Mutation
gp . fx_karoo_branch_mutate ( ) # method 3 - Branch Mutation
2016-07-10 02:55:44 -06:00
gp . fx_karoo_crossover ( ) # method 4 - Crossover Reproduction
2015-11-04 03:56:07 -07:00
gp . fx_eval_generation ( ) # evaluate all Trees in a single generation
2017-07-03 16:47:04 -06:00
gp . population_a = gp . fx_evolve_pop_copy ( gp . population_b , [ ' Karoo GP by Kai Staats, Generation ' + str ( gp . generation_id ) ] )
2015-11-04 03:56:07 -07:00
#++++++++++++++++++++++++++++++++++++++++++
# "End of line, man!" --CLU |
#++++++++++++++++++++++++++++++++++++++++++
2017-06-06 22:12:55 -06:00
print ' \n \033 [36m Karoo GP has an ellapsed time of \033 [0;0m \033 [31m %f \033 [0;0m ' % ( time . time ( ) - start ) , ' \033 [0;0m '
2017-02-07 01:33:38 -07:00
gp . fx_archive_tree_write ( gp . population_b , ' f ' ) # save the final generation of Trees to disk
2015-11-04 03:56:07 -07:00
gp . fx_karoo_eol ( )
2017-06-06 22:12:55 -06:00