I've programmed Conways Game of Life in Python and now I'm trying to display the simple data that it gives me as an output in a heat map.
This is my current code:
from Tkinter import *
import matplotlib.pyplot as plt
import time
import numpy as np
import random
size_x = 100
size_y = 10
# create the matrices
cell = [[0 for row in range(0, size_y)] for col in range(0, size_x)]
live = [[0 for row in range(0, size_y)] for col in range(0, size_x)]
temp = [[0 for row in range(0, size_y)] for col in range(0, size_x)]
# process and draw the next frame
def frame():
process()
draw()
root.after(100, frame)
# load the initial data
def load(initial=0.5):
for y in range(0, size_y):
for x in range(0, size_x):
if random.random()<initial: live[x][y] = 1
temp[x][y] = 0
# Applying rules
def process():
for y in range(0, size_y):
for x in range(0, size_x):
lives = live_neighbors(x,y)
if live[x][y] == 1:
if lives < 2 or lives > 3:
temp[x][y] = 0
else:
temp[x][y] = 1
if live[x][y] == 0:
if lives == 3:
temp[x][y] = 1
else:
temp[x][y] = 0
for y in range(0, size_y):
for x in range(0, size_x):
live[x][y] = temp[x][y]
# live = temp
# Count live neighbors
def live_neighbors(a,b):
lives = 0
if live[a][(b+1)%size_y] == 1: lives += 1
if live[a][(b-1)%size_y] == 1: lives += 1
if live[(a+1)%size_x][b] == 1: lives += 1
if live[(a+1)%size_x][(b+1)%size_y] == 1: lives += 1
if live[(a+1)%size_x][(b-1)%size_y] == 1: lives += 1
if live[(a-1)%size_x][b] == 1: lives += 1
if live[(a-1)%size_x][(b+1)%size_y] == 1: lives += 1
if live[(a-1)%size_x][(b-1)%size_y] == 1: lives += 1
return lives
# Draw all cells
def draw():
nLiving = 0
nDead = 0
for y in range(size_y):
for x in range(size_x):
if live[x][y]==0:
canvas.itemconfig(cell[x][y], fill="black")
nDead+=1
if live[x][y]==1:
canvas.itemconfig(cell[x][y], fill="white")
nLiving+=1
print nLiving,nDead
# count cells
def count():
nLiving = 0
nDead = 0
for y in range(size_y):
for x in range(size_x):
if live[x][y]==0:
nDead+=1
if live[x][y]==1:
nLiving+=1
z = nLiving / 10.0
print z,
print "%"
def one_game(initial):
load(initial)
for gen in range(1, 101):
print str(gen) + ":",
count()
process()
def many_games():
numbers = range(1,51)
for initial in numbers:
print initial/100.0
one_game(initial/100.0)
many_games()
#one_game(0.5)
The code for making a normal heat map with given input would be:
fig, ax = plt.subplots(1)
x = np.array( [[11,12,13], [21,22,23], [31,32,33]] )
p = ax.pcolormesh(x)
fig.colorbar(p)
plt.show()
How do I get my data (which in this case would be, the generations, the value which initializes the one_game() function, and nLiving) into an array?
I'm not 100% sure this is what you're intending, but it produced a pretty output heat map :)
def count():
nLiving = 0
nDead = 0
for y in range(size_y):
for x in range(size_x):
if live[x][y]==0:
nDead+=1
if live[x][y]==1:
nLiving+=1
z = nLiving / 10.0
print("nLiving over ten is: ", z,)
print("%")
return nLiving
def one_game(initial):
load(initial)
gen_array = []
for gen in range(1, 101):
print("Gen: ", str(gen) + ":",)
nLiving = count()
process()
gen_array.append(nLiving)
return gen_array
def many_games():
gen_output = []
numbers = range(1,51)
for initial in numbers:
print(initial/100.0)
gen_array = one_game(initial/100.0)
gen_output.append(gen_array)
return gen_output
gen_output = many_games()
#one_game(0.5)
fig, ax = plt.subplots(1)
x = np.array( gen_output )
p = ax.pcolormesh(x)
fig.colorbar(p)
plt.show()
That is just code modified from your count function to the end of the file. Basically you just need to return the output from the functions that you're calling into the right kind of data structures, I think...
Related
I have a rather long question I hope I can get help with.
I have a code that runs a simulation by a "while true" loop and after that a "for" loop that saves data from the simulation and restart the sim after given time. This code works fine, but now Im trying to convert this into a multiprocess where I can get 4 simultaneous simulations and for loops. So I tried to put most of the code into a function and then called it but it does not seem to work. Sorry for the long code I appreciate any help!
The first working code without multiprocessing
for z in range(8):
for q in range(100):
time_re = time_re + 3000
tk.after(time_re,appender)
tk.after(time_re,restart)
ava(avaR1)
while True:
time_steps = range(0,iterations+1)
B = Beta.get()
G = Gamma.get()
D = Diff.get()
M = Mor.get()
steps_x_or_y = np.random.rand(n)
steps_x = steps_x_or_y < D/2
steps_y = (steps_x_or_y > D/2) & (steps_x_or_y < D)
nx = (x + np.sign(np.random.randn(n)) * steps_x) % l
ny = (y + np.sign(np.random.randn(n)) * steps_y) % l
for i in np.where( (S==1) & ( np.random.rand(n) < B ))[0]: # loop over infecting agents
S[(x==x[i]) & (y==y[i]) & (S==0)] = 1 # Susceptiples together with infecting agent becomes infected
S[ (S==1) & (np.random.rand(n) < G) ] = 2 # Recovery
S[ (S==1) & (np.random.rand(n) < M) ] = 3 # Death
nrInf1 = sum(S==1)
nrSus.append(sum(S==0))
nrInf.append(sum(S==1))
nrRec.append(sum(S==2))
nrRec1 = sum(S==2)
nrDea = sum(S == 3)
iterations += 1
tk.update()
tk.title('Infected:' + str(np.sum(S==1)))
x = nx # Update x
y = ny # Update y
The second code with me trying to change it to multiprocessing
def main1(i):
# Physical parameters of the system
x = np.floor(np.random.rand(n)*l) # x coordinates
y = np.floor(np.random.rand(n)*l) # y coordinates
S = np.zeros(n) # status array, 0: Susceptiple, 1: Infected, 2: recovered
I = np.argsort((x-l/2)**2 + (y-l/2)**2)
S[I[1:initial_infected]] = 1 # Infect agents that are close to center
nrRec1 = 0
nrDea = []
time_re = 0
particles = []
R = .5 # agent plot radius
nx = x # udpated x
ny = y # updated y
def restart():
global S
I = np.argsort((x-l/2)**2 + (y-l/2)**2)
S = np.zeros(n)
S[I[1:initial_infected]] = 1
rest = Button(tk, text='Restart',command= restart)
rest.place(relx=0.05, rely=.85, relheight= 0.12, relwidth= 0.15 )
def ava(k,o):
global b
k.append(sum(o)/3)
Beta.set(b) # Parameter slider for mortality rate
b += 0.03125
#bSaver.append(b)
def appender(o):
nrDea1.append(nrDea)
o.append(nrRec1)
for j in range(n): # Generate animated particles in Canvas
particles.append( canvas.create_oval( (x[j] )*res/l,
(y[j] )*res/l,
(x[j]+2*R )*res/l,
(y[j]+2*R )*res/l,
outline=ccolor[0], fill=ccolor[0]) )
if i == 1:
b=0
for z in range(3):
for q in range(3):
time_re = time_re + 1000
tk.after(time_re,appender(nrSRec1))
tk.after(time_re,restart)
tk.after(9000,ava(avaR1,nrSRec1))
elif i == 2:
b=0.25
for z in range(3):
for q in range(3):
time_re = time_re + 1000
tk.after(time_re,appender(nrSRec2))
tk.after(time_re,restart)
tk.after(9000,ava(avaR2,nrSRec2))
elif i == 3:
b=.50
for z in range(3):
for q in range(3):
time_re = time_re + 1000
tk.after(time_re,appender(nrSRec3))
tk.after(time_re,restart)
tk.after(9000,ava(avaR3,nrSRec3))
else:
b=.75
for z in range(3):
for q in range(3):
time_re = time_re + 1000
tk.after(time_re,appender(nrSRec4))
tk.after(time_re,restart)
tk.after(9000,ava(avaR4,nrSRec4))
while True:
B = Beta.get()
G = Gamma.get()
D = Diff.get()
steps_x_or_y = np.random.rand(n)
steps_x = steps_x_or_y < D/2
steps_y = (steps_x_or_y > D/2) & (steps_x_or_y < D)
nx = (x + np.sign(np.random.randn(n)) * steps_x) % l
ny = (y + np.sign(np.random.randn(n)) * steps_y) % l
for i in np.where( (S==1) & ( np.random.rand(n) < B ))[0]: # loop over infecting agents
S[(x==x[i]) & (y==y[i]) & (S==0)] = 1 # Susceptiples together with infecting agent becomes infected
S[ (S==1) & (np.random.rand(n) < G) ] = 2 # Recovery
nrDea= sum(S == 3)
nrRec1 = sum(S==2)
tk.update()
tk.title('Infected:' + str(np.sum(S==1)))
x = nx # Update x
y = ny # Update y
if __name__ == '__main__':
p1=mp.Process(target=main1, args=(1,))
p1.start()
p2=mp.Process(target=main1, args=(2,))
p2.start()
p3=mp.Process(target=main1, args=(3,))
p3.start()
p4=mp.Process(target=main1, args=(4,))
p4.start()
joinedList = avaR1+avaR2+avaR3+avaR4
print(joinedList)
Tk.mainloop(canvas)
I'm trying to do the elitism method to get the best fitness value of each of the generations I generate, keeping beyond the fitness the values of X and Y to be an individual of the next generation, however, I can't apply a logic using dict that Solve the problem. It remains to get this detail right to be able to finalize the complete implementation and carry out the general revisions.
import random
def generate_population(size, x_boundaries, y_boundaries):
lower_x_boundary, upper_x_boundary = x_boundaries
lower_y_boundary, upper_y_boundary = y_boundaries
population = []
for i in range(size):
individual = {
'x': random.uniform(lower_x_boundary, upper_x_boundary),
'y': random.uniform(lower_y_boundary, upper_y_boundary),
}
population.append(individual)
return population
def fitness(individual):
x = individual['x']
y = individual['y']
return abs((-(100*(x*x - y)*(x*x - y) + (1 - x)*(1-x))))
def sort_population_by_fitness(population):
return sorted(population, key=fitness)
def choice_by_roulette(sorted_population, fitness_sum):
drawn = random.uniform(0, 1)
accumulated = 0
for individual in sorted_population:
fitnessX = fitness(individual)
probability = fitnessX / fitness_sum
accumulated += probability
if drawn <= accumulated:
return individual
def crossover(choice_a, choice_b):
xa = choice_a['x']
ya = choice_a['y']
xb = choice_b['x']
yb = choice_b['y']
#xa = xa*xb
#xa = xa**0.5
#ya = ya*yb
#ya = ya**0.5
return {'x': xa+0.01, 'y': ya+0.01}
def mutate(new_individual):
x = new_individual['x']
y = new_individual['y']
flagx = 0
flagy = 0
new_x = x*(1+random.uniform(-0.01/2, 0.01/2))
new_y = y*(1+random.uniform(-0.01/2, 0.01/2))
while flagx == 1:
if (new_x > 2) or (new_x < -2):
new_x = x*(1+random.uniform(-0.01/2, 0.01/2))
flagx = 1
else:
flagx = 0
while flagy == 1:
if (new_y > 2) or (new_y < -2):
new_y = y*(1+random.uniform(-0.01/2, 0.01/2))
flagy = 1
else:
flagy = 0
return {'x': new_x, 'y': new_y}
def eletism(x_gen, milior):
pior = sort_population_by_fitness(x_gen)
fitness(pior)
print(pior)
#for i in x_gen:
#print(teste['x'])
#x = teste['x']
#y = teste['y']
#print(milior)
return pior
def make_next_gen(population):
next_gen = []
sorted_population = sort_population_by_fitness(population)
soma_fitness = sum(fitness(individual)for individual in population)
for i in range(9):
first_choice = choice_by_roulette(sorted_population, soma_fitness)
second_choice = choice_by_roulette(sorted_population, soma_fitness)
new_individual = crossover(first_choice, second_choice)
drawn = random.randint(1,5)
if drawn == 1:
new_individual = mutate(new_individual)
next_gen.append(new_individual)
return next_gen
generations = 100
population = generate_population(size=10, x_boundaries=(-2, 2), y_boundaries=(-2, 2))
i = 0
while i!= generations:
for individual in population:
print(individual, fitness(individual))
population = make_next_gen(population)
i += 1
best_individual = sort_population_by_fitness(population)[-1]
print(best_individual, fitness(best_individual))
Whenever k = 2, the code runs in a loop
if k > 2 it sets all, but one of the centroids location to 0,0
I've reviewed it a couple of times , and it doesn't seem like there are any errors probably some sort of logic flaw. The code starts by having a class and its methods which initiate the centroids, calculate the Euclidean distance, and reassign centroids to the average positions of the points that are in the cluster. It then runs a loop that consists of reassigning and calculating distance until a list of the assignments are equal and then plots it.
class Kmeans:
def __init__(self, K, dataset, centroids, sorting):
self.K = K
self.dataset = dataset
self.centroids = centroids
self.sorting = sorting
#sets starting position of centroids
def initializeCentroids(self):
bigX = 0
bigY = 0
self.centroids = []
for i in self.dataset:
if i[0] > bigX:
bigX = i[0]
if i[1] > bigY:
bigY = i[1]
for q in range(self.K):
self.centroids.append([random.randint(0, bigX), random.randint(0, bigY)])
plt.scatter((self.centroids[0][0], self.centroids[1][0]), (self.centroids[0][1], self.centroids[1][1]))
return self.centroids
#calculates euclidean distance
def calcDistance(self):
self.sorting = []
for w in self.dataset:
print(w)
distances = []
counter = 0
for centr in self.centroids:
distances.append(math.sqrt(abs((centr[0] - w[0] * centr[0] - w[0]) + (centr[1] - w[1] * centr[1] - w[1]))))
counter += 1
if counter > 0:
try:
if distances[0] > distances[1]:
distances.pop(0)
if distances[1] > distances[0]:
distances.pop(1)
counter -= 1
except IndexError:
pass
self.sorting.append([w, counter, distances[0]])
return self.sorting
def reassignCentroids(self):
counter3 = 1
for r in range(len(self.centroids)):
positionsX = []
positionsY = []
for t in self.sorting:
if t[1] == counter3:
positionsX.append(t[0][0])
positionsY.append(t[0][1])
population = len(positionsY)
if population == 0:
population = 1
self.centroids.append([sum(positionsX) / population, sum(positionsY) / population])
counter3 += 1
self.centroids.pop(0)
return
k = 4
dataSetSize = input("Enter the amount of tuples you want generated: ")
data_set = []
for o in range(int(dataSetSize)):
data_set.append((random.randint(0, 1000), random.randint(0, 1000)))
attempt = Kmeans(k, data_set, 0, 0)
attempt.initializeCentroids()
xvals = []
yvals = []
sortCompare = []
# plots
for p in data_set:
xvals.append(p[0])
yvals.append(p[1])
running = True
while running:
if len(sortCompare) > 1:
centroidChoice0 = []
centroidChoice1 = []
for p in sortCompare[0]:
centroidChoice0.append(p[1])
for d in sortCompare[1]:
centroidChoice1.append(d[1])
print(centroidChoice1)
print(attempt.centroids)
if centroidChoice1 == centroidChoice0:
running = False
for m in attempt.centroids:
plt.scatter((attempt.centroids[0][0], attempt.centroids[1][0]), (attempt.centroids[0][1], attempt.centroids[1][1]))
running = False
sortCompare.pop(0)
attempt.calcDistance()
sortCompare.append(attempt.sorting)
attempt.reassignCentroids()
As the title states, I've implemented the N-Queens problem for all soulutions but there is one problem, it prints an empty board. I saw a solution only where we put the printboard in an if statement but without a return in printboard i fail to see how it works`
#N Queens through Backtracking with all solutions
def initialize(n):
for key in ['queen','row','col','NWtoSE','SWtoNE']:
board[key] = {}
for i in range(n):
board['queen'][i] = -1
board['row'][i] = 0
board['col'][i] = 0
for i in range (2*n-1):
#Sum of NW to SE diagonal add to constant i.e (i+j) = const
board['SWtoNE'][i] = 0
for i in range (-(n-1), n):
#Difference of SW to NE diagonal is constant i.e (j-i) = const
board['NWtoSE'][i] = 0
def isAvailable(i, j):
return (board['row'][i] == 0 and board['col'][j] == 0 and
board['NWtoSE'][j-i] == 0 and board['SWtoNE'][j+i] == 0)
def addQueen(i, j):
board['queen'][i] = j
board['row'][i] = 1
board['col'][j] = 1
board['NWtoSE'][j-i] = 1
board['SWtoNE'][j+i] = 1
def undo(i, j):
board['queen'][i] = -1
board['row'][i] = 0
board['col'][j] = 0
board['NWtoSE'][j-i] = 0
board['SWtoNE'][j+i] = 0
def printboard():
for i in board['queen'].keys():
print((i, board['queen'][i]), end = " ")
print()
def placequeen(i):
n = len(board['queen'].keys())
for j in range(n):
if(isAvailable(i, j)):
addQueen(i, j)
if i == n-1:
printboard()
else:
placequeen(i+1)
undo(i,j)
board = {}
n = int(input("Enter number of queens : "))
initialize(n)
printboard()
The following is the solution which I don't understand
if placequeen(0): printboard()
We are trying to make a program that solves any maze by recognising all junctions and eliminating the ones that do not lead to the entrance. We managed to create such a program but we are struggling to get the dots to connect to create a proper path. Does anybody have an idea how to do this because we are out of clues...Picture of the result, but the dots aren't connect by a line
The maze is basically a (n)x(n) grid in a numpy array with walls (true) and paths (false) see:picture of maze as seen from the variable explorer
import numpy as np
import maze_utils as mu
import matplotlib.pyplot as plt
size = 101
maze, start = mu.make_maze(size)
start = [start[1],start[0]]
#------------------------------------------------------------------------------
def junctions_finder(maze, size, start):
junctions = [start]
end = []
for y, row in enumerate(maze):
for x, column in enumerate(row):
if maze[x,y] == False:
if x == 0 or x == (size-1) or y == 0 or y == (size-1):
junctions.append([y,x])
end.append([y,x])
while True:
if x+1 < size and y+1 < size and\
maze[x+1,y] == False and maze[x,y+1] == False\
or x+1 < size and y-1 > 0 and\
maze[x+1,y] == False and maze[x,y-1] == False\
or x-1 > 0 and y-1 > 0 and\
maze[(x-1),y] == False and maze[x,(y-1)] == False\
or x-1 > 0 and y+1 < size and\
maze[(x-1),y] == False and maze[x,(y+1)] == False:
junctions.append([y,x])
break
else:
break
return junctions, end
#------------------------------------------------------------------------------
def eliminate_coor(junctions, end, start):
eliminated = []
for row in junctions:
a = row[1]
b = row[0]
connections = 0
U = False
D = False
L = False
R = False
UW = False
DW = False
LW = False
RW = False
SE = False
if row == start or row == end[0]:
connections = 2
SE = True
for i in range(1,size):
if SE == False:
if a+i <= size-1 and DW == False and D == False:
if maze[a+i, b] == True:
DW = True
else:
for coor in junctions:
if [coor[1],coor[0]] == [a+i,b]:
connections = connections + 1
D = True
if a-i >= 0 and UW == False and U == False:
if maze[a-i, b] == True:
UW = True
else:
for coor in junctions:
if [coor[1],coor[0]] == [a-i,b]:
connections = connections + 1
U = True
if b+i <= size-1 and RW == False and R == False:
if maze[a, b+i] == True:
RW = True
else:
for coor in junctions:
if [coor[1],coor[0]] == [a,b+i]:
connections = connections + 1
R = True
if b-i >= 0 and LW == False and L == False:
if maze[a, b-i] == True:
LW = True
else:
for coor in junctions:
if [coor[1],coor[0]] == [a,b-i]:
connections = connections + 1
L = True
if connections < 2:
eliminated.append([b,a])
return eliminated
#------------------------------------------------------------------------------
def junction_remover(junctions, eliminated):
counter = 0
for index, row in enumerate(junctions):
for erow in (eliminated):
if erow == row:
junctions[index] = -1
counter = counter + 1
for times in range(counter):
junctions.remove(-1)
return junctions, counter
#------------------------------------------------------------------------------
junctions, end = junctions_finder(maze, size, start)
counter = 1
while counter > 0:
eliminated = eliminate_coor(junctions, end, start)
junctions, counter = junction_remover(junctions, eliminated)
start = [start[1],start[0]]
junctions.pop(0)
pyjunc = np.array(junctions)
mu.plot_maze(maze, start=start)
plt.plot(pyjunc[:,0], pyjunc[:,1], 'o')
plt.plot(pyjunc[:,0], pyjunc[:,1]) would connect the dots... Or did you mean you have a bug you can't trace? In your picture it seems there's a beginning, but no end, so it retraces back to the beginning?
plt.plot(pyjunc[:,0], pyjunc[:,1], 'o')
plots the data points in the list with the circle marker 'o'. But you haven't defined a linestyle.
The quickest way to do this is to add it the format shorthand:
plt.plot(pyjunc[:,0], pyjunc[:,1], 'o-')
Which says to use a circle marker and a solid line '-'.
Expanding that out to how matplotlib interprets it, you could write:
plt.plot(pyjunc[:,0], pyjunc[:,1], marker='o', linestyle='-')
You can see the full documentation for plt.plot more ways to customise your plot