Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ackland_1_8.py 23.58 KiB
from graphics import *
import time
import random
import math
import csv
#-----global variables--------------------
visual = True
winWidth = 700
winHeight = 700
if visual:
window = GraphWin("Window", winWidth, winHeight)
else:
window = None
maxTime = 10000
agentNum = 80
predNum = 8#agentNum/10
generations = 100
foodCluster = 16
clusterSize = 8
clusterradius = 20
# choose simulation type
isFood = False
isPred = True
Both = False
t = 0.1
rr = 5
# area an agent can see
As = 5000 * (rr**2)
Am = 5 * (rr**2) * t
#mutate values
m_zoo_r = 5/2.0
m_zoa_r = 10/2.0
m_speed = 0.1/2.0
m_food = 0.1/2.0
m_pred = 0.1/2.0
m_noise = 0.05/2.0
#-----Agent class--------------------
class Agent:
def __init__(self, point, window ):
self.color = color_rgb(0,0,0)
self.point = point
self.window = window
self.Velocity_x = 1
self.Velocity_y = 1
self.tempV = [0,0]
self.line = Line(self.point, Point(self.point.getX() + self.Velocity_x, self.point.getY()+self.Velocity_y))
#evolvable
self.speed = 4
self.zor_r = 5#fix
self.zoo_r = 20
self.zoa_r = 200
self.attCircle = Circle(self.point, self.zoa_r)
self.blind_angle = 30
self.turn_angle = 50
self.food_pref = 5
self.anti_pred = 0
self.foodlevel = 0
self.noise = 2
def drawLine(self):
self.line.undraw()
self.line = Line(self.point, Point(self.point.getX() + self.Velocity_x, self.point.getY()+self.Velocity_y))
self.line.setArrow("last")
self.line.setFill(self.color)
self.line.draw(self.window)
def create_random_agent(self):
self.Velocity_x = random.uniform(-1, 1)
self.Velocity_y = random.uniform(-1, 1)
self.zor_r = rr
self.zoa_r = random.uniform( math.sqrt(As/(2*math.pi)), 1.5*math.sqrt(As/(2*math.pi)) )
self.zoo_r = random.uniform(rr, self.zoa_r)
self.speed = random.uniform(1, 5)
self.blind_angle = (360 - math.degrees(As/(self.zoa_r**2)) ) / 2
self.turn_angle = math.degrees(Am/(2*(self.speed**2)))
self.food_pref = random.uniform(0,5)
self.anti_pred = random.uniform(0,5)
self.noise = random.uniform(0,1)
r = random.randrange(256)
g = random.randrange(256)
b = random.randrange(256)
return self
#agent.color = color_rgb(r,g,b)
"""
self.attCircle.undraw()
self.attCircle = Circle(self.point, self.zoa_r)
self.attCircle.setOutline("black")
self.attCircle.draw(self.window)
"""
#-----Predator class--------------------
class Predator:
def __init__(self, point, window ):
self.color = "red"
self.point = point
self.window = window
self.Velocity_x = 1
self.Velocity_y = 1
self.tempV = [0,0]
self.line = Line(self.point, Point(self.point.getX() + self.Velocity_x, self.point.getY()+self.Velocity_y))
#evolvable
self.speed = 5.5
self.zor_r = 10#fix
#self.zoo_r = 20
self.zoa_r = 200
self.attCircle = Circle(self.point, self.zoa_r)
self.blind_angle = 135
self.turn_angle = 50
#self.food_pref = 5
#self.anti_pred = 0
#self.foodlevel = 0
self.noise = 2
self.hasEaten = False
self.lifeTime = 0
def drawLine(self):
self.line.undraw()
self.line = Line(self.point, Point(self.point.getX() + self.Velocity_x, self.point.getY()+self.Velocity_y))
self.line.setArrow("last")
self.line.setFill(self.color)
self.line.draw(self.window)
def create_random_predator(self):
self.Velocity_x = random.uniform(-1, 1)
self.Velocity_y = random.uniform(-1, 1)
self.zor_r = rr
view_angle = 360-(self.blind_angle*2)
self.zoa_r = 20*math.sqrt(As/view_angle)
#self.blind_angle = (360 - math.degrees(As/(self.zoa_r**2)) ) / 2
#self.turn_angle = math.degrees(1.5*Am/(2*(self.speed**2)))
self.turn_angle = 140
return(self)
#-----Food class--------------------
class Food:
def __init__(self, Point):
self.point = Point
def generate_food(widthTemp, heightTemp):
foods = []
for j in range (foodCluster):
x = random.uniform(widthTemp + clusterradius, winWidth-clusterradius)
y = random.uniform(heightTemp + clusterradius, winHeight- clusterradius)
for k in range (clusterSize):
xk = random.uniform(x - clusterradius, x + clusterradius)
yk = random.uniform(y - clusterradius, y + clusterradius)
f = Food(Point(xk, yk))
if visual:
f.point.setFill("blue")
f.point.draw(window)
foods.append(f)
return foods
#-----help functions--------------------
# Distance function betwen points xi, yi and xii,yii
def distance(xi,xii,yi,yii):
sq1 = (xi-xii)*(xi-xii)
sq2 = (yi-yii)*(yi-yii)
return math.sqrt(sq1 + sq2)
# absolute value of a vector (a,b)
def absvec(a, b):
m = math.sqrt(a*a + b*b)
if m == 0: m = 0.001
return m
# angle between two direction vectors
def calc_angle(x1, y1, x2, y2):
skalar = x1*x2 + y1*y2
abs1 = absvec(x1, y1)
abs2 = absvec(x2, y2)
erg = skalar/(abs1* abs2)
if erg > 1:
#print erg
erg=1
elif erg < -1:
#print erg
erg=-1
return math.degrees(math.acos(erg))
# returns nearest neighbour of a in aas
def nearest_neighbour(a,aas):
minDis = float('inf')
nn = None
for b in aas:
disVecX = b.point.getX() - a.point.getX()
disVecY = b.point.getY() - a.point.getY()
alpha = calc_angle(a.Velocity_x,a.Velocity_y, disVecX, disVecY)
if (a == b):
True
elif alpha < 180 - a.blind_angle and alpha > 180 + a.blind_angle:
True
elif (nn == None):
nn = b
else:
dis = distance(a.point.getX(),b.point.getX(), a.point.getY(), b.point.getY())
if(dis < minDis):
minDis = dis
nn = b
return nn
#-----couzin movement--------------------
# returns three lists, one for each zone,
# contaning all other agents in the zone.
# ignores all agents in the angle behind the current agent defined by blind.
def neigbour_in_zones(a, aas):
zor = []
zoo = []
zoa = []
for agent in aas:
disVecX = agent.point.getX() - a.point.getX()
disVecY = agent.point.getY() - a.point.getY()
alpha = calc_angle(a.Velocity_x, a.Velocity_y, disVecX, disVecY)
if (a == agent):
True
elif alpha < 180 - a.blind_angle and alpha > 180 + a.blind_angle:
True
else:
dis = absvec(agent.point.getX() - a.point.getX() , agent.point.getY() - a.point.getY() )
if dis <= a.zor_r:
zor.append(agent)
elif dis <= a.zoo_r:
zoo.append(agent)
elif dis <= a.zoa_r:
zoa.append(agent)
#print len(zoo)+len(zor)+len(zoa)
return [zor, zoo, zoa]
#update Velocity a la couzin
def updateV_couzin(a, matrix):
dx=0
dy=0
#zor
if matrix[0] != []:
for agent in matrix[0]:
disX = agent.point.getX() - a.point.getX()
disY = agent.point.getY() - a.point.getY()
rX = disX/absvec(disX, disY)
rY = disY/absvec(disX, disY)
dx += rX / absvec(rX, rY)
dy += rY / absvec(rX, rY)
dx = -dx
dy = -dy
# zoo ; zoa leer
elif matrix[1] != [] and matrix[2] == []:
for agent in matrix[1]:
dx += agent.Velocity_x / absvec(agent.Velocity_x, agent.Velocity_y)
dy += agent.Velocity_y / absvec(agent.Velocity_x, agent.Velocity_y)
dx += a.Velocity_x / absvec(a.Velocity_x, a.Velocity_y)
dy += a.Velocity_y / absvec(a.Velocity_x, a.Velocity_y)
# zoo leer ; zoa
elif matrix[1] == [] and matrix[2] != []:
for agent in matrix[2]:
disX = agent.point.getX() - a.point.getX()
disY = agent.point.getY() - a.point.getY()
rX = disX/absvec(disX, disY)
rY = disY/absvec(disX, disY)
dx += rX / absvec(rX, rY)
dy += rY / absvec(rX, rY)
# zoo ; zoa
elif matrix[1] != [] and matrix[2] != []:
for agent in matrix[1]:
dx += agent.Velocity_x / absvec(agent.Velocity_x, agent.Velocity_y)
dy += agent.Velocity_y / absvec(agent.Velocity_x, agent.Velocity_y)
dx += a.Velocity_x / absvec(a.Velocity_x, a.Velocity_y)
dy += a.Velocity_y / absvec(a.Velocity_x, a.Velocity_y)
for agent in matrix[2]:
disX = agent.point.getX() - a.point.getX()
disY = agent.point.getY() - a.point.getY()
rX = disX/absvec(disX, disY)
rY = disY/absvec(disX, disY)
dx += rX / absvec(rX, rY)
dy += rY / absvec(rX, rY)
dx = 0.5*dx
dy = 0.5*dy
# all zones empty
else:
dx = a.Velocity_x
dy = a.Velocity_y
# randomness factor / error
dx += random.uniform(-a.noise/2, a.noise/2)
dy += random.uniform(-a.noise/2, a.noise/2)
return [dx, dy]
# searches nearest food item, checks if it can be eaten,
# else returns direction vector pointing towards it
def check_food(agent, foods):
dX=0
dY=0
if foods == []:
return [dX,dY]
nf = nearest_neighbour(agent, foods)
dis = distance(agent.point.getX(), nf.point.getX(), agent.point.getY(), nf.point.getY())
if dis<=agent.zor_r:
nf.point.undraw()
foods.remove(nf)
agent.foodlevel += 1
elif dis<=agent.zoa_r:
disX = nf.point.getX() - agent.point.getX()
disY = nf.point.getY() - agent.point.getY()
rX = disX/absvec(disX, disY)
rY = disY/absvec(disX, disY)
dX = rX / absvec(rX, rY)
dY = rY / absvec(rX, rY)
return [dX, dY]
#same as checkfood, but can not eat a predator
def check_predator(agent, predators):
dX=0
dY=0
if predators == []:
return [dX,dY]
nf = nearest_neighbour(agent, predators)
dis = distance(agent.point.getX(), nf.point.getX(), agent.point.getY(), nf.point.getY())
if dis<=agent.zoa_r:
disX = nf.point.getX() - agent.point.getX()
disY = nf.point.getY() - agent.point.getY()
rX = disX/absvec(disX, disY)
rY = disY/absvec(disX, disY)
dX = rX / absvec(rX, rY)
dY = rY / absvec(rX, rY)
return [dX, dY]
#check for nearest prey in agents, and test if it can be eaten
def check_prey(predator, agents):
dX = predator.Velocity_x
dY = predator.Velocity_y
if agents == []:
return [dX,dY]
na = nearest_neighbour(predator, agents)
dis = distance(predator.point.getX(), na.point.getX(), predator.point.getY(), na.point.getY())
if dis <= predator.zor_r:
if visual:
na.point.undraw()
na.line.undraw()
agents.remove(na)
predator.hasEaten = True
elif dis <= predator.zoa_r:
disX = na.point.getX() - predator.point.getX()
disY = na.point.getY() - predator.point.getY()
rX = disX/absvec(disX, disY)
rY = disY/absvec(disX, disY)
dX = rX / absvec(rX, rY)
dY = rY / absvec(rX, rY)
return [dX, dY]
# updates velocity, taking food and predators and other agents into account
def updateV_final(agent, matrix,foods, predators):
vc = updateV_couzin(agent, matrix)
vf = check_food(agent, foods)
vp = check_predator(agent, predators)
vvX = vc[0] + agent.food_pref* vf[0] - agent.anti_pred * vp[0]
vvY = vc[1] + agent.food_pref* vf[1] - agent.anti_pred * vp[1]
return [vvX, vvY]
# check for window boundaries
def checkBoundary(agent, winWidth, winHeight):
point = agent.point
point.move(agent.Velocity_x,agent.Velocity_y)
x = point.getX()
y = point.getY()
if x > 0 and y < winHeight and x < winWidth and y > 0:
agent.point = point
else:
if x <= 0 or x >= winWidth:
agent.Velocity_x = agent.Velocity_x * (-1)
if y <= 0 or y >= winHeight:
agent.Velocity_y = agent.Velocity_y * (-1)
agent.point.move(agent.Velocity_x,agent.Velocity_y)
return agent
#update and draw agents
def update_couzin(agents,foods, predators,winWidth, winHeight, window):
# Velocity update
for agent in agents:
neigbour_matrix = neigbour_in_zones(agent, agents)
agent.tempV = updateV_final(agent, neigbour_matrix, foods, predators)
# move, draw
for agent in agents:
# alpha = calc_angle(agent[1], agent[2],agent.tempV[0],agent[4][1])
X = agent.Velocity_x
y = agent.Velocity_y
# test if in ragne of agent.turn_angle,
# if true, set velocity == new velocity
# else rotate angle by maxTurn in
# direction of new direction
radTurn = math.radians(agent.turn_angle)
negRadTurn = math.radians(360-agent.turn_angle)
angle_old = math.atan2(agent.Velocity_y, agent.Velocity_x)
angle_new = math.atan2(agent.tempV[1], agent.tempV[0])
alpha = math.degrees(angle_old - angle_new)
if abs(alpha) > 180:
if alpha < 0:
alpha += 360
else:
alpha -= 360
if abs(alpha)<agent.turn_angle:
x = agent.tempV[0]
y = agent.tempV[1]
elif alpha < 0:
x = agent.Velocity_x * math.cos(radTurn) - agent.Velocity_y * math.sin(radTurn)
y = agent.Velocity_x * math.sin(radTurn) + agent.Velocity_y * math.cos(radTurn)
else:
x = agent.Velocity_x * math.cos(negRadTurn) - agent.Velocity_y * math.sin(negRadTurn)
y = agent.Velocity_x * math.sin(negRadTurn) + agent.Velocity_y * math.cos(negRadTurn)
# normalise dirction vector to 1, and multiply by constant speed
absLen = absvec(x, y)
agent.Velocity_x= x/absLen * agent.speed
agent.Velocity_y = y/absLen * agent.speed
agent = checkBoundary(agent, winWidth, winHeight)
# draw arrow
if visual:
agent.drawLine()
return agents
#update and draw predator
def update_predator(predator, agents, winWidth, winHeight, window):
x = predator.Velocity_x
y = predator.Velocity_y
predator.tempV = check_prey(predator, agents)
# test if in ragne of agent.turn_angle,
# if true, set velocity == new velocity
# else rotate angle by maxTurn in
# direction of new direction
radTurn = math.radians(predator.turn_angle)
negRadTurn = math.radians(360-predator.turn_angle)
angle_old = math.atan2(predator.Velocity_y, predator.Velocity_x)
angle_new = math.atan2(predator.tempV[1], predator.tempV[0])
alpha = math.degrees(angle_old - angle_new)
if abs(alpha) > 180:
if alpha < 0:
alpha += 360
else:
alpha -= 360
if abs(alpha)<predator.turn_angle:
x = predator.tempV[0]
y = predator.tempV[1]
elif alpha < 0:
x = predator.Velocity_x * math.cos(radTurn) - predator.Velocity_y * math.sin(radTurn)
y = predator.Velocity_x * math.sin(radTurn) + predator.Velocity_y * math.cos(radTurn)
else:
x = predator.Velocity_x * math.cos(negRadTurn) - predator.Velocity_y * math.sin(negRadTurn)
y = predator.Velocity_x * math.sin(negRadTurn) + predator.Velocity_y * math.cos(negRadTurn)
# normalise diection vector to 1, and multiply by constant speed
absLen = absvec(x, y)
predator.Velocity_x = x/absLen * predator.speed
predator.Velocity_y = y/absLen * predator.speed
predator = checkBoundary(predator, winWidth, winHeight)
# draw arrow
if visual:
predator.drawLine()
return predator
# for choosing parent
def generateWheel(agents):
"""
foodsum = 0
for agent in agents:
foodsum += agent.foodlevel
"""
wheel = []
currentsum = 0
for agent in agents:
currentsum += agent.foodlevel
wheel.append(currentsum)
return wheel
# chooses parent to mutate
def pickParent(agents, wheel):
r = random.randrange(wheel[-1]) +1
for i in range(len(wheel)):
if r <= wheel[i]:
return agents[i]
# greates a new agent, and assinges random values close to those of the parent
def mutate(parent):
point = Point(random.uniform(0,winWidth/2), random.uniform(0,winHeight/2))
child = Agent(point, window)
child.Velocity_x = random.uniform(-1, 1)
child.Velocity_y = random.uniform(-1, 1)
child.zoa_r = random.uniform(parent.zoa_r - m_zoa_r, parent.zoa_r + m_zoa_r )
child.zoa_r = max (child.zoa_r, math.sqrt(As/(2*math.pi)) )
child.zoo_r = random.uniform(parent.zoo_r - m_zoo_r, parent.zoo_r + m_zoo_r)
child.zoo_r = min( child.zoa_r , max(child.zoo_r, child.zor_r))
child.speed = random.uniform(parent.speed - m_speed, parent.speed + m_speed)
child.speed = min( 5 , max(child.speed, 1))
child.blind_angle = (360 - math.degrees(As/(child.zoa_r**2)) ) / 2
child.turn_angle = math.degrees(Am/(2*(child.speed**2)))
child.food_pref = random.uniform(parent.food_pref - m_food, parent.food_pref + m_food)
child.anti_pred = random.uniform(parent.anti_pred - m_pred, parent.anti_pred + m_pred)
child.noise = random.uniform(parent.noise - m_noise, parent.noise + m_noise)
return child
# picks parents, creates new agents with mutated values,
# returns them in a new agents list
def nextGen_food(agents):
wheel = generateWheel(agents)
tempAgents = []
for i in range(agentNum):
if wheel[-1] == 0:
parent = pickParent_simple_random(agents)
else:
parent = pickParent(agents, wheel)
child = mutate(parent)
tempAgents.append(child)
return tempAgents
#----------new generation for predator simulation
def pickParent_simple_random(agents):
r = random.randrange(len(agents))
return agents[r]
# picks parents, creates new agents with mutated values,
# returns them in a new agents list
def nextGen_pred(agents):
tempAgents = []
for i in range(agentNum):
parent = pickParent_simple_random(agents)
child = mutate(parent)
tempAgents.append(child)
return tempAgents
# ------------main------------------------
def simulate():
# zones for couzin, vicsek
# radii of zones
# swarm: 10, 20, 200
# torus: 5, 60, 200
# dynamic parallel group: 5, 100, 200
# highly parallel group: 5, 180, 200
agents = []
foods = []
predators = []
with open('data_param.csv','w') as csvfile:
filewriter = csv.writer(csvfile, delimiter=',',quotechar='|',quoting = csv.QUOTE_MINIMAL)
filewriter.writerow(["Iterations","Speed","turn","food pref","zoa","zoo","blind","noise","antipred"])
with open('data_time.csv','w') as csvfile:
filewriter = csv.writer(csvfile, delimiter=',',quotechar='|',quoting = csv.QUOTE_MINIMAL)
filewriter.writerow(["x","y","x_velocity","y_velocity","foodlevel"])
widthTemp = winWidth
heightTemp = winHeight
maxLife = 1000
global window
# first generation , random
for i in range (agentNum):
agent = Agent(Point(random.uniform(0,winWidth/2), random.uniform(0,winHeight/2)) , window)
agents.append(agent.create_random_agent())
for j in range(generations):
if isPred or Both:
for i in range(predNum):
predator = Predator(Point(random.uniform(0,winWidth), random.uniform(0,winHeight)) , window)
predators.append(predator.create_random_predator())
# -----ausgabe------
print ("generation " + str(j))
avgSpeed = 0
avgTurn = 0
avgFood = 0
avgPred = 0
avgZOA = 0
avgZOO = 0
avgBlind = 0
avgNoise = 0
maxSpeed = 0
maxTurnAngle = 0
for agent in agents:
avgSpeed += agent.speed
avgPred += agent.anti_pred
avgTurn += agent.turn_angle
avgFood += agent.food_pref
avgZOA += agent.zoa_r
avgZOO += agent.zoo_r
avgBlind += agent.blind_angle
avgNoise += agent.noise
if agent.speed > maxSpeed:
maxSpeed = agent.speed
if agent.turn_angle > maxTurnAngle:
maxTurnAngle = agent.turn_angle
avgSpeed /= agentNum
avgTurn /= agentNum
avgFood /= agentNum
avgZOA /= agentNum
avgZOO /= agentNum
avgBlind /= agentNum
avgNoise /= agentNum
avgPred /= agentNum
#("speed: " +str(avgSpeed))
#print ("turn: " +str(avgTurn))
#print ("food pref: " +str(avgFood))
#print ("zoa: " +str(avgZOA))
#print ("zoo: " +str(avgZOO))
#print ("blind: " +str(avgBlind))
#print ("noise: "+str(avgNoise))
#print ("antipred: " + str(avgPred))
#print ("maxspeed " +str(maxSpeed) )
#print ("maxTurnAngle " +str(maxTurnAngle) )
for agent in agents:
with open('data_param.csv','a') as csvfile:
filewriter = csv.writer(csvfile, delimiter=',',quotechar='|',quoting = csv.QUOTE_MINIMAL)
filewriter.writerow([j, agent.speed, agent.turn, agent.food_pref, agent.zoa_r, agent.zoo_r, agent.blind_angle, agent.noise, agent.anti_pred])
# -----ausgabe ende------
#if visual:
# for agent in agents:
# agent.point.undraw()
# agent.point.draw(window)
if isFood or Both:
widthTemp = winWidth/2
heightTemp = winHeight/2
else:
widthTemp = winWidth
heightTemp = winHeight
#timeStep = 0
for timeStep in range(maxTime):
# generate food and release agents
if timeStep == maxTime * 0.025 and (isFood or Both):
foods = generate_food(widthTemp, heightTemp)
widthTemp = winWidth
heightTemp = winHeight
# exit generation if enough food has been eaten
if timeStep >= maxTime * 0.025 and isFood:
if len(foods) <= 1.0/8 * clusterSize * foodCluster:
#print ("done eating")
break
# start predating
if timeStep >= maxTime * 0.025 and (isPred or Both):
if predators == []:
#print ("preds are done")
break
else:
if(predators[-1].hasEaten or predators[-1].lifeTime >= maxLife):
print ("hasEaten")
if visual:
predators[-1].line.undraw()
predators.pop()
else:
predators[-1] = update_predator(predators[-1], agents, winWidth, winHeight, window)
predators[-1].lifeTime += 1
#print "pred absvec: " + str (absvec(predators[-1].Velocity_x, predators[-1].Velocity_y))
# update agents
agents = update_couzin(agents, foods, predators, widthTemp, heightTemp, window)
#if visual:
# time.sleep(0.01*t)
print ("eating time: " + str(timeStep))
# new windos + new generation
if visual:
window.close()
window = GraphWin("Window", winWidth, winHeight)
if isFood or Both:
agents = nextGen_food(agents)
elif isPred:
agents = nextGen_pred(agents)
simulate()