Skip to content

Instantly share code, notes, and snippets.

@kolergy
Last active January 23, 2017 20:57
Show Gist options
  • Save kolergy/d488d20294374f7157c3977db1ca84f4 to your computer and use it in GitHub Desktop.
Save kolergy/d488d20294374f7157c3977db1ca84f4 to your computer and use it in GitHub Desktop.
Stupid Life: it's stupid but it moves, NN & GA
#!/usr/freeware/bin/python
## #!/home/QtPalmtop/bin/python
#-------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------
# Ustructured NN
# Kolergy
# Written in Python. See http://www.python.org/
#-------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------
import math
import random
import string
import time
from Tkinter import *
Version = "0.5.4"
#-------------------------------------------------------------------------------------------
# A Recursive Neural Network
class RNeurNet:
""" The unstructured network class"""
def __init__(self, layersNeurons, memNeurons):
self.layersNeurons = layersNeurons # Number of neurons on each layers
self.nLayers = len(layersNeurons) # Number of layers
self.nOutputs = self.layersNeurons[-1] # Number of outputs
self.layer = [] # Layers Storage
self.memNeurons = memNeurons # Number of memory neurons
self.layersNeurons[0] = self.layersNeurons[0] + 1 # Adding the biais Neuron
# Adding Mem Neuron on First & Last Layers
self.layersNeurons[ 0] = self.layersNeurons[ 0] + self.memNeurons
self.layersNeurons[-1] = self.layersNeurons[-1] + self.memNeurons
# Creating the network
for nl in range(self.nLayers): # Create the layer filed with neurons
lay = []
for nn in range(self.layersNeurons[nl]):
Nname = "Neur" + str(nl) + "-" + str(nn)
if nl==0: lay.append(Neuron(Nname, [] ) )
else: lay.append(Neuron(Nname, self.layer[nl-1]) )
self.layer.append(lay) # Add the new layer to the network
#print "Network created with Architecture: %s" % self.layersNeurons
#creating the memory link
inputs = []
for i in range(self.memNeurons): inputs = self.layer[-1][self.memNeurons:]
for i in range(self.memNeurons): self.layer[0][-1-i].addInputs(inputs)
# Runs an evaluation calculation of the network
def calc(self):
#print "Network evaluation calculation"
for l in self.layer: # Calc all layers
for n in l: n.calc() # Calc all neurons
# Evaluate a single pattern
def evaluateNet(self, inputPattern):
#print "Evaluating Pattern:%s" % inputPattern
for i in range(len(inputPattern)): self.layer[0][i].activation = inputPattern[i] # Application of the input pattern
self.calc() # Network evaluation calculation
#self.display()
output = []
for i in range(self.nOutputs): output.append(self.layer[-1][i].activation*2.0 -1) # corrected to be in the range [-1, 1]
return(output) # Return the output Neurons
# Display the total network
def display(self):
print ""
print "Displaying of the complete network layer by layer"
for l in self.layer:
for n in l: n.display()
print ""
# Exporting the total network
def exportLinks(self):
#print "Exporting the links"
links = []
for la in self.layer:
for n in la:
for li in n.inputsVector:
links.append(li.weight)
#print links
return(links)
# Importing the total network
def importLinks(self, links):
#print "Importing the links"
#print links
i = 0
for la in self.layer:
for n in la:
for li in n.inputsVector:
li.weight = links[i]
i += 1
#-------------------------------------------------------------------------------------------
# A Neuron
class Neuron:
' The Neuron Class'
def __init__(self, name, inputs):
self.activation = 0.0
self.sum = 0.0
self.inputsVector = []
self.outputsVector = []
self.name = name
self.addInputs(inputs)
# Create the input vector list filed with links to an other layer
def addInputs(self, inputs):
#print inputs
if len(inputs) != 0:
for i in inputs: self.inputsVector.append( Link(i, self) )
# Calculate activation of neuron output from inputs sum
def calc(self):
self.sum = 0
if len(self.inputsVector) != 0: # If not in input neuron
for c in self.inputsVector: # Sum the input values
c.calc()
self.sum += c.act
self.activation = 1/(1+math.exp(-self.sum)) # Sigmoid function
# Display the neuon characteristics : Name, Sum of inputs, Activation
def display(self): print "N:%s" % self.name + " S:%6.3f" % self.sum + " A:%6.3f" % self.activation
#-------------------------------------------------------------------------------------------
# A Link between a source neuron and a destination Neuron
class Link:
' A Link between two Neuron and its functions'
def __init__(self, source, destination, weightInit = -9999):
self.source = source
self.destination = destination
self.acti = 0.0
# Set the output vector of the source neuron
self.source.outputsVector.append(self)
# initialise the weight to the given value or randomly if no value is given
if weightInit == -9999: self.weight = random.uniform(-2, 2)
else: self.weight = weightInit
# Calculate the link activation
def calc(self):
self.act = self.source.activation * self.weight
#print"L Sa:%5.3f" % self.source.activation + " W%5.3f" % self.weight + " A:%5.3f" %self.act
#-------------------------------------------------------------------------------------------
# The Beast
class Beast:
def __init__(self, area, position=[0.0,0.0] ):
self.position = position # The X & Y position of the beast
self.HP = 100 # Beast Health points
self.SP = 100 # Beast Stamina points
self.area = area # Reference to the GameArea
self.net = RNeurNet([3,8,8,8,2], 8) # The Recursive Neural Net
self.geneMxRange = 10.0
self.repr = 10
self.rect = []
self.movment = [10, 10]
self.movmentPrev = [10, 10]
#print "initpos=%s" % self.position
def heartBeat(self):
#print "before:%s" % self.position
self.movmentPrev = self.movment
self.movment = self.net.evaluateNet(self.position) # Run the network with its inputs & get new pos
self.area.updatePos(self) # Ask the area to update the position
self.repr += 1
self.HP -= 1
#print "New Pos:%s" % self.position
def getGenes(self):
genes = self.net.exportLinks()
#print "Get GN"
#print genes
for i in range(len(genes)):genes[i] = 0.5 + genes[i] / self.geneMxRange # addimentioning
#print genes
return(genes)
def setGenes(self, genes):
for i in range(len(genes)):genes[i] = (genes[i]-0.5) * self.geneMxRange # redimentioning
self.net.importLinks(genes) # Set the network
self.repr = 0 # Child can not reproduce yet
#-------------------------------------------------------------------------------------------
# The Game Area
class GameArea:
def __init__(self, size=[20.0,10.0] ):
self.size = size # Size of the area in the X & Y directions origin is [0,0]
self.population = [] # Initialization of the empty population
self.TargetCorner1 = [0,0] # Initialization of the target zone lower corner
self.TargetCorner2 = [0,0] # Initialization of the target zone upper corner
self.heartBeat = 0.1 # Heart Beat in seconds
self.inTarget = [] # List of Beast in target
self.targetSize = 5
self.targetCenter = [3,4]
self.gen = 0 # Current generation
self.displayArea = 1000
self.zoomfact = self.displayArea / self.size[0]
self.root = Tk()
self.frame = Frame(self.root, bd=2, relief=SUNKEN)
self.deltaPop = 0
#self.canvas = []
self.frame.grid_rowconfigure(0, weight=1)
self.frame.grid_columnconfigure(0, weight=1)
self.xscrollbar = Scrollbar(self.frame, orient=HORIZONTAL)
self.xscrollbar.grid(row=1, column=0, sticky=E+W)
self.yscrollbar = Scrollbar(self.frame)
self.yscrollbar.grid(row=0, column=1, sticky=N+S)
self.canvas = Canvas(self.frame, bd=0, scrollregion=(0, 0, 1000, 1000), xscrollcommand = self.xscrollbar.set, yscrollcommand = self.yscrollbar.set)
self.button = Button(self.canvas, text="Quit", fg="red", command=self.quitArea )
self.run = Button(self.canvas, text="Run", command=self.setAndRun )
self.save = Button(self.canvas, text="Save", command=self.savePop )
self.load = Button(self.canvas, text="Load", command=self.loadPop )
self.button.pack(side=LEFT)
self.run.pack( side=LEFT)
self.save.pack( side=LEFT)
self.load.pack( side=LEFT)
self.canvas.grid(row=0, column=0, sticky=N+S+E+W)
#print self.zoomfact
self.area = self.canvas.create_rectangle(0, 0, self.displayArea, self.displayArea, fill="green")
self.xscrollbar.config(command=self.canvas.xview)
self.yscrollbar.config(command=self.canvas.yview)
self.frame.pack(fill=BOTH, expand=1)
print"B4 Display"
self.root.mainloop()
self.root.destroy()
print"After Display"
def quitArea(self):
self.population[:]
self.frame.quit
def setTargetZone(self): # Definition of a rectangular target zone
self.TargetCorner1 = [max(0, self.targetCenter[0]-self.targetSize/2), max(0, self.targetCenter[1]-self.targetSize/2)]
self.TargetCorner2 = [min(self.size[0], self.targetCenter[0]+self.targetSize/2), min(self.size[0], self.targetCenter[1]+self.targetSize/2)]
self.canvas.coords(self.target,
self.TargetCorner1[0] * self.zoomfact,
self.TargetCorner1[1] * self.zoomfact,
self.TargetCorner2[0] * self.zoomfact,
self.TargetCorner2[1] * self.zoomfact)
#self.canvas.update()
def updateTargetZone(self):
delta = 0.1
fact = 1
randDist= 0.5
borderMargin = 0.5
self.sizeOld = self.targetSize
if len(self.population) > 200: fact = 0.5
elif len(self.population) < 50: fact = 2
if self.deltaPop > 2 :
self.targetSize *= 1-(delta/fact)
if self.deltaPop > 0.2*len(self.population) and len(self.population) > 80 :
self.targetSize *= 1-(2/delta*fact)
if self.deltaPop < 0 :
self.targetSize *= 1+(delta*fact)
if self.deltaPop < 0.2*len(self.population) and len(self.population) < 100:
self.targetSize *= 1+(2*delta*fact)
if self.targetSize > self.size[0]*1.5: self.targetSize = self.size[0]*1.5
elif self.targetSize < 0.3: self.targetSize = 0.3
#if self.gen % 50 == 0: self.targetCenter = [random.uniform(1, self.size[0]-1),random.uniform(1, self.size[1]-1)]
#if self.gen % 50 == 0:
self.targetCenter = [min(self.size[0]-borderMargin, max(borderMargin, self.targetCenter[0] + random.uniform(-randDist, randDist))), \
min(self.size[1]-borderMargin, max(borderMargin, self.targetCenter[1] + random.uniform(-randDist, randDist)))]
#print "targetCenter" 71 83
#print self.targetCenter
self.setTargetZone()
def addBeast(self, position = [0, 0]): # Add a beast to the game area
if position == [0, 0]: position = [random.uniform(0, self.size[0]/2),random.uniform(0, self.size[1]/2)]
position.append(0.0) # Add the color value
beast = Beast(self, position )
beast.rect = self.canvas.create_line(position[0] * self.zoomfact, position[1] * self.zoomfact,
position[0] * self.zoomfact +2, position[1] * self.zoomfact +2, arrow=LAST, arrowshape=(2,3,2))
self.population.append(beast)
def addChild(self, genes): # Add a beast to the game area
if self.targetCenter[0] > 5: x = 1
else: x = self.size[0]-1
if self.targetCenter[1] > 5: y = 1
else: y = self.size[1]-1
beast = Beast(self, [random.uniform(x-1, x+1),random.uniform(y-1, y+1), 0.0] )
beast.setGenes(genes)
beast.rect = self.canvas.create_line(beast.position[0] * self.zoomfact, beast.position[1] * self.zoomfact,
beast.position[0] * self.zoomfact +2, beast.position[1] * self.zoomfact +2, arrow=LAST, arrowshape=(2,3,2))
self.population.append(beast)
def runAllBeasts(self): # Tick heart beat
while len(self.population) > 1:
self.gen += 1
self.inTarget = []
pop0 = len(self.population)
self.updateTargetZone()
for b in self.population: b.heartBeat()
self.mate()
pop1 = len(self.population)
self.deltaPop = pop1-pop0
dSize = self.targetSize / self.sizeOld
print "%6d" % self.gen +" :: Pop:%5d" %len(self.population) + " Dpop:%5d" % self.deltaPop + " DSize:%6.2f" % dSize
self.canvas.update()
#time.sleep(self.heartBeat)
def setAndRun(self):
self.target = self.canvas.create_rectangle(self.TargetCorner1[0] * self.zoomfact,
self.TargetCorner1[1] * self.zoomfact,
self.TargetCorner2[0] * self.zoomfact,
self.TargetCorner2[1] * self.zoomfact, fill="blue")
print "Create Networks"
for i in range(200): self.addBeast()
print "Go"
self.runAllBeasts()
def savePop(self):
path = "c:\\Users\\toto\\My Documents"
oFileName = 'StupidLife.sav'
oFile = open(path + "\\" + oFileName, "w+")
oFile.write("StupidLife V%s\n" % Version)
oFile.write(" Pos_X Pos_Y ")
for i in range(len(self.population[0].getGenes())): oFile.write(" Gen%2d " % i)
oFile.write("\n")
for b in self.population:
oFile.write("%6.4f" % b.position[0] + " %6.4f" % b.position[1])
for g in b.getGenes(): oFile.write(" %6.4f" % g)
oFile.write("\n")
#oFile.write("%8.0f" %dataTable['alt'][j] + "\t%8.2f" %dataTable['time'][j] + "\t%8.1f" %dataTable['dist'][j] + "\t%8.4f" %dataTable['fuel'][j] + "\n")
oFile.close()
del(self.population[:]) # empty population
#crash = 0.0 / 0.0
def loadPop(self):
position = [0.0, 0.0]
path = "c:\\Users\\toto\\My Documents"
iFileName = 'StupidLife.sav'
iFile = open(path + "\\" + iFileName, "r") #
rLines = iFile.read().splitlines() # Read the file & close it
iFile.close() #
for l in rLines[2:]: # population is all lines except the 2 first
l = map(float, l.split(" ")) # split the line string & transform to float
position[0] = l[0] # Set X Position
position[1] = l[1] # Set Y Position
self.addBeast(position) # Add the new memeber to the population
self.population[-1].setGenes(l[2:]) # Set Beast Genes (memory is not saved)
#crash = 0.0 / 0.0
self.runAllBeasts()
def mate(self): # reproduce beast in Target Zone
while len(self.inTarget) >= 2: # 2 parents needed
b1 = self.inTarget[0] # Set parents 1 & 2
b2 = self.inTarget[1]
b1.repr = 0 # re-init reproduction counter
b2.repr = 0
childs = self.modifyChrom(b1.getGenes(), b2.getGenes()) # Perform the crossover & get the childs genes
for genes in childs: self.addChild(genes) # Cheate the childs with the new genes
del self.inTarget[:2] # Parents removed from current reproduction pool
def isTargetZone(self, beast): # Check if Beast in Target Zone
position = beast.position
if ( (min(self.TargetCorner1[0], self.TargetCorner2[0]) < position[0] < max(self.TargetCorner1[0], self.TargetCorner2[0])) \
& (min(self.TargetCorner1[1], self.TargetCorner2[1]) < position[1] < max(self.TargetCorner1[1], self.TargetCorner2[1])) ):
beast.position.append(1.0)
if beast not in self.inTarget and beast.repr >= 4:
self.inTarget.append(beast)
self.canvas.itemconfig(beast.rect, fill="green")
#print "In target"
else:
if 1 < position[0] or 1 < position[1] or (self.size[0]-1) < position[0] or (self.size[1]-1) < position[1]:
beast.position.append(-1.0) # Warning approaching edge
self.canvas.itemconfig(beast.rect, fill="red")
#self.canvas.update()
else:
beast.position.append(0.0)
self.canvas.itemconfig(beast.rect, fill="blue")
#self.canvas.update()
if beast in self.inTarget:
self.inTarget.remove(beast)
#print "Out of target"
def updatePos(self, beast): # Update the beast position
oldPosition = beast.position
#print "OldPos:%s" % oldPosition
newPosition =[]
totMove = math.sqrt(math.pow(beast.movment[0],2)+math.pow(beast.movment[1],2)) + math.sqrt(math.pow(beast.movmentPrev[0],2)+math.pow(beast.movmentPrev[1],2))
for i in range(len(oldPosition)-1):
newPosition.append(oldPosition[i] + beast.movment[i]/5) # Update position
# if newPosition[i] < 0: newPosition[i] = 0 # Ensure Beast stays in range
# elif newPosition[i] > self.size[i]: newPosition[i] = self.size[i]
if newPosition[i] < 0 or newPosition[i] > self.size[i] or beast.HP <= 0 or totMove < 0.2:
#print "one killed"
#print len(self.population)
self.population.remove(beast) # Eliminate Beast that go out
self.canvas.delete(beast.rect)
self.canvas.update()
#print len(self.population)
return
beast.position = newPosition[:] # Set the new position
self.canvas.coords(beast.rect,
oldPosition[0] * self.zoomfact,
oldPosition[1] * self.zoomfact,
beast.position[0] * self.zoomfact,
beast.position[1] * self.zoomfact)
#print "NewPos:%s" % newPosition
#print "BeastPos:%s" % beast.position
self.isTargetZone(beast) # Check if in target zone
#print "BeastPos:%s" % beast.position
#---------------------------------------------------------------------------
# The BoundedSBXCrossover
# ref: Deb Agrawal, Simulated binary crossover for continous search space
# complex systems 9, 1995, pp115-148.
#---------------------------------------------------------------------------
def modifyChrom(self, parent1Gene, parent2Gene):
#print "*** Start BoundedSBXCrossover() ***"
# Settings -------------------------------------------------------------------------------
distibutionIndex = 1.0
geneCrossoverRate = 0.5
child1Gene = [0,]*len(parent1Gene)
child2Gene = [0,]*len(parent1Gene)
tempChroms = []
#print parent1Gene
#print parent2Gene
#print child1Gene
for i in range(len(parent1Gene)):
if(random.uniform(0.0, 1.0) <= geneCrossoverRate and parent1Gene[i] != parent2Gene[i]): # selecting only 1/2 genes
if(parent2Gene[i] > parent1Gene[i]): # Sort the parents
pGeneBig = parent2Gene[i]
pGeneSml = parent1Gene[i]
else:
pGeneBig = parent1Gene[i]
pGeneSml = parent2Gene[i]
if((pGeneSml - 0) > (1 - pGeneBig)): beta = 1 + (2*(1 - pGeneBig) / (pGeneBig - pGeneSml)) # find the shortest distance to the
else: beta = 1 + (2*(pGeneSml - 0) / (pGeneBig - pGeneSml)) # boundary & adapt the distribution
alpha = 2 - math.pow(beta, -(distibutionIndex + 1))
r = random.uniform(0.0, 1.0)
if (r <= 1/alpha): betaq = math.pow( alpha * r , 1 / (distibutionIndex + 1))
else: betaq = math.pow( 1 / (2 - alpha * r), 1 / (distibutionIndex + 1))
child1Gene[i] = 0.5*((pGeneSml+pGeneBig) - betaq*(pGeneBig-pGeneSml))
child2Gene[i] = 0.5*((pGeneSml+pGeneBig) + betaq*(pGeneBig-pGeneSml))
#print "alpha:%f" % alpha + "\beta:%f" % beta + "\betaq:%f" % betaq
else:
child1Gene[i] = parent1Gene[i] # if no mod copy the parents genes
child2Gene[i] = parent2Gene[i]
# make sure every thing is in bounds
if (child1Gene[i] < 0):
print "Cg1-%d" % i +" Low:%f" % child1Gene[i]
child1Gene[i] = 0
if (child2Gene[i] < 0):
print "Cg2-%d" % i +" Low:%f" % child1Gene[i]
child2Gene[i] = 0
if (child1Gene[i] > 1):
print "Cg1-%d" % i +" Hig:%f" % child1Gene[i]
child1Gene[i] = 1
if (child2Gene[i] > 1):
print "Cg2-%d" % i +" Hig:%f" % child1Gene[i]
child2Gene[i] = 1
#print child1Gene
#print child2Gene
tempChroms.append(child1Gene)
tempChroms.append(child2Gene)
return(tempChroms)
#-------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------
if __name__ == '__main__': # Testing Main
# Seed initialisation
random.seed(time.time())
print "NeuronLearn V0.5.4"
# Network Creation
area = GameArea([10.0,10.0])
#area.setTargetZone()
#print "Create Networks"
#for i in range(200): area.addBeast()
#print "Go"
#area.runAllBeasts()
print "Finished"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment