Module tutorial4
[hide private]
[frames] | no frames]

Source Code for Module tutorial4

  1  """ 
  2  tutorial4 
  3  ========= 
  4  Contains all parameters for the evolutionary run, grammar rules, constraints,  
  5  and specifics about the terminal and function set of the trees in tutorial4. 
  6  This example file gather all the settings for a 'multiple' polynomial regression. 
  7  We want to evolve a system of ordered polynomial equations by using the 
  8  mathematical operators: '+','*' and the ADF: ADF1 and ADF2, in the said order. 
  9  an ADF2 branch could then call for an ADF1 terminal, but not the opposite.   
 10  We try to find the following model being shaped as a system of polynomials:  
 11   
 12  |ADF1=x+y 
 13   
 14  |ADF2=ADF1^3 
 15   
 16  from 1 set of 1000 testing data (1000 different values for x and y). 
 17  This time, each tree does not have to be evaluated 1000 times. We will input 
 18  a list of 1000 data points in the variable leafs of the tree. There is not much time 
 19  difference to process 1000 data-points than 5 when we use this trick! 
 20  Considering the constraints for building the trees, the root node will have 2  
 21  children ADF1 and ADF2 (in order), and ADF2 must be able to reuse ADF1 as a  
 22  terminal... A typical way to run the tutorial would be to: 
 23      - modify the settings file so that: 
 24       
 25      >>>     # setup for running tutorial 4 
 26              functions = tutorial4.functions 
 27              crossover_mapping=tutorial4.crossover_mapping 
 28              nb_eval=tutorial4.nb_eval 
 29              nb_ex=tutorial4.nb_ex 
 30              ideal_results=tutorial4.GetIdealResultsData() 
 31              terminals =tutorial4.terminals 
 32              Strongly_Typed_Crossover_degree=tutorial4.Strongly_Typed_Crossover_degree 
 33              Substitute_Mutation=tutorial4.Substitute_Mutation 
 34              treeRules = tutorial4.treeRules 
 35              adfOrdered = tutorial4.adfOrdered 
 36              FitnessFunction = tutorial4.FitnessFunction 
 37       
 38      - use a different fitness function for the evaluation of a list 
 39       of values instead of a value. We create 2 new fitness functions: 
 40           - EvalTreeForOneListInputSet is a modification of the original  
 41           EvalTreeForOneInputSet. 
 42           - FinalFitness2 is a modification of FinalFitness that take as input 
 43           the result returned by the new EvalTreeForOneListInputSet 
 44            
 45           These fitness functions are called in FitnessFunction in the tutorial4 module.  
 46            
 47           >>>    def FitnessFunction(my_tree): 
 48           >>>        return evalfitness.FinalFitness2(evalfitness.EvalTreeForOneListInputSet(my_tree))   
 49           
 50      - run the evolution in the main method, and make sure that the root node parameter 
 51      only have two children.e.g. 
 52       
 53      >>>    import evolver 
 54      if __name__ == "__main__": 
 55      >>>    dbname=r'C:\pop_db' 
 56      >>>    evolver.EvolutionRun(2000,(0,2,'root'),2,8,'AddHalfNode',100, 0.00001 ,0.5,0.49,7,0.8,dbname,True) 
 57   
 58      This means that we define: 
 59      - a population size of 2000 individuals, 
 60      - a root node with 2 children 
 61      - a minimum tree depth of 2 
 62      - a maximum tree depth of 8 
 63      - the use of a Ramped half and Half Koza tree building method 
 64      - a maximum number of runs of 100 generations before we stop 
 65      - a stoping fitness criteria of 0.1 (if the fitness<=0.1, solution found) 
 66      - a crossover probability of 0.5 
 67      - a mutation probability of 0.49 
 68      - a reproduction probability of 0.01 (automatically deduced from the 2 previous values) 
 69      - the size of the tournament selection 
 70      - the probability of selecting the fitttest during tournament selection  
 71      - a database of name and path dbname 
 72      - a run done in verbose mode (printing the fittest element of each generation)  
 73       
 74  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 75  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 76  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 77  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 78  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 79  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
 80  THE SOFTWARE. 
 81   
 82  @author: by Mehdi Khoury 
 83  @version: 1.20 
 84  @copyright: (c) 2009 Mehdi Khoury under the mit license 
 85  http://www.opensource.org/licenses/mit-license.html 
 86  @contact: mehdi.khoury at gmail.com 
 87  """ 
 88   
 89  import array 
 90  import psyco 
 91  import random 
 92  import math 
 93  from treeutil import PostOrder_Search 
 94  from collections import deque 
 95  import evalfitness 
 96   
 97  psyco.profile() 
 98   
 99  # first, we create result processing methods for each function: 
100 -def add(listElem):
101 try: 102 result=[] 103 for i in xrange(len(listElem[0])): 104 result.append(listElem[0][i]+listElem[1][i]) 105 return result 106 except: 107 raise WrongValues, "Wrong values sent to function node.\nCan't get result" 108 exit
109 110
111 -def multiply(listElem):
112 try: 113 result=[] 114 for i in xrange(len(listElem[0])): 115 result.append(listElem[0][i]*listElem[1][i]) 116 return result 117 except: 118 raise WrongValues, "Wrong values sent to function node.\nCan't get result" 119 exit
120
121 -def adfBranch(x):
122 try: 123 return x 124 except: 125 raise WrongValues, "Wrong values sent to function node.\nCan't get result" 126 exit
127
128 -def rootBranch(x):
129 try: 130 return x 131 except: 132 raise WrongValues, "Wrong values sent to function node.\nCan't get result" 133 exit
134 135 # then, we create a set of functions and associate them with the corresponding 136 # processing methods 137 functions = {'+':add, 138 '*':multiply, 139 'adf2_+':add, 140 'adf2_*':multiply, 141 'adf1':adfBranch, 142 'adf2':adfBranch, 143 'root':rootBranch 144 } 145 # when swapping subtrees during crossover, we can transform the following branches: 146 # + can be transformed into ADF2_+, and so on... 147 crossover_mapping=[('+','adf2_+'),('adf2_+','+'),('*','adf2_*'),('adf2_*','*')] 148 149 150 # we create the list of all possible values a variable can have 151 # Here we tell the system it only learn from one example, so it will 152 # only evaluate the tree one time. The difference will be that this unique 153 # variable will be an array of 200 of format 'double' ! These 200 variables 154 # will then be evaluated at once when a tree is evaluated. 155 nb_eval=1 156 all_x=[] 157 all_y=[] 158 159 nb_ex=1000 160 for i in xrange(nb_ex): 161 all_x.append(random.random()*10) 162 all_y.append(random.random()*10) 163 #print all_x 164 #print all_y 165 #print add([all_x,all_y]) 166 #print multiply([all_x,all_y]) 167 # encapsulate all data of x and y inside arrays so that the tree 168 # will evaluate a whole array in one go... 169 170 ideal_results=[] 171
172 -def GetIdealResultsData():
173 temp1=[] 174 for nb in xrange(nb_ex): 175 temp1.append(all_x[nb]+all_y[nb]) 176 temp2=[] 177 for nb in xrange(nb_ex): 178 temp2.append((all_x[nb]+all_y[nb])**3) 179 ideal_results.append(temp1) 180 ideal_results.append(temp2) 181 return ideal_results
182 # then, we create a mapping of terminals 183 # the variables will be given a value coming from a set of examples 184 # the constants will just be given as such or produced by a 185 # random producer 186 terminals = { 187 'x':all_x, 188 'y':all_y 189 } 190 191 #MaxDepth=5 192 Strongly_Typed_Crossover_degree=1 193
194 -def FitnessFunction(my_tree):
195 return evalfitness.FinalFitness2(evalfitness.EvalTreeForOneListInputSet(my_tree))
196 197 # default function set applicable by for branches: 198 defaultFunctionSet= [(1,2,'+'),(1,2,'*')] 199 # default terminal set applicable by for branches: 200 defaultTerminalSet= [(3,0,'x'),(3,0,'y')] 201 Adf2DefaultFunctionSet= [(1,2,'adf2_+'),(1,2,'adf2_*')] 202 Adf2DefaultTerminalSet= [(3,0,'x'),(3,0,'y'),(5,0,'adf1')] 203 treeRules = {'root':[ ([(2,1,'adf1')],[]) , ([(2,1,'adf2')],[]) ], 204 'adf1':[(defaultFunctionSet,defaultTerminalSet)], 205 'adf2':[(Adf2DefaultFunctionSet,Adf2DefaultTerminalSet)], 206 '+':[(defaultFunctionSet,defaultTerminalSet),(defaultFunctionSet,defaultTerminalSet)], 207 '*':[(defaultFunctionSet,defaultTerminalSet),(defaultFunctionSet,defaultTerminalSet)], 208 'adf2_+':[(Adf2DefaultFunctionSet,Adf2DefaultTerminalSet),(Adf2DefaultFunctionSet,Adf2DefaultTerminalSet)], 209 'adf2_*':[(Adf2DefaultFunctionSet,Adf2DefaultTerminalSet),(Adf2DefaultFunctionSet,Adf2DefaultTerminalSet)], 210 } 211 212 Strongly_Typed_Crossover_degree=1 213 Substitute_Mutation=0 214 adfOrdered = True 215