import numpy as np import threading INPUT_FILE = "data/medium.in" POPULATION = 1000 MUTATION_AMOUNT = 250 ITERATIONS = 30 data = [line for line in open(INPUT_FILE)] params = list(map(int, data[0].split(" "))) data = [[0 if x=="T" else 1 for x in line] for line in data[1:]] data = np.array(data)[:, :-1] clusters = np.arange(params[0]*params[1]).reshape((1, params[0], params[1])) clusters = np.repeat(clusters, POPULATION, axis=0)+1 print(params) print(data) print(clusters[0]) values = {} first = True class myThread (threading.Thread): def __init__(self, cluster, clean, id): threading.Thread.__init__(self) self.cluster = cluster self.clean = clean self.id = id self.result = None self.first = False self.values = {} self.vfunc = np.vectorize(self.myfunc) def run(self): # calc fitness self.values = {} self.first = True self.vfunc(self.cluster, data) self.result = get_fitness(self.values, clean=self.clean) print("Exit thread", self.id) def myfunc(self, a, b): if self.first: self.first = False return if a not in values: self.values[a] = [0, 0] self.values[a][b] += 1 def get_fitnesses(clusts, clean=False): threads = [] for i, cluster in enumerate(clusters): if i % 20 == 0: print("fitness", i, iteration) # Create new threads thread = myThread(cluster, clean, i) # Start new Threads thread.start() # Add threads to thread list threads.append(thread) # Wait for all threads to complete for t in threads: t.join() print("Exiting Main Thread") return np.array([thread.result for thread in threads]) def get_fitness(vals, clean=False): fit = 0 for key, val in vals.items(): if key == 0: continue size = sum(val) if size <= params[3] and min(val) >= params[2]: fit += size if clean: continue size_diff = params[3]-size if size_diff < 0: fit += 1-size_diff**2 elif size_diff > 0: fit += np.exp(-abs(size-params[3])) return fit def get_left_bound(clust, y, x): val = clust[y, x] while x > 0 and val == clust[y, x-1]: x -= 1 return (y, x) def get_right_bound(clust, y, x): val = clust[y, x] while x+1 < clust.shape[1] and val == clust[y, x+1]: x += 1 return (y, x) def get_top_bound(clust, y, x): val = clust[y, x] while y > 0 and val == clust[y-1, x]: y -= 1 return (y, x) def get_bottom_bound(clust, y, x): val = clust[y, x] while y+1 < clust.shape[0] and val == clust[y+1, x]: y += 1 return (y, x) def set_area(clust, y1, x1, y2, x2, value): for y in range(y1, y2+1): for x in range(x1, x2+1): clust[y, x] = value return clust def mutation(clust): for _ in range(np.random.random_integers(MUTATION_AMOUNT)): y = np.random.random_integers(params[0])-1 x = np.random.random_integers(params[1])-1 z = np.random.random() if z < 0.2: if y > 0: # expand to top yn = y-1 _, inner_left = get_left_bound(clust, y, x) _, outer_left = get_left_bound(clust, yn, inner_left) _, inner_right = get_right_bound(clust, y, x) _, outer_right = get_right_bound(clust, yn, inner_right) clust = set_area(clust, yn, outer_left, yn, outer_right, 0) clust = set_area(clust, yn, inner_left, yn, inner_right, clust[y, x]) elif z < 0.4: if x > 0: # expand to left xn = x-1 inner_top, _ = get_top_bound(clust, y, x) outer_top, _ = get_top_bound(clust, inner_top, xn) inner_bot, _ = get_bottom_bound(clust, y, x) outer_bot, _ = get_bottom_bound(clust, inner_bot, xn) clust = set_area(clust, outer_top, xn, outer_bot, xn, 0) clust = set_area(clust, inner_top, xn, inner_bot, xn, clust[y, x]) elif z < 0.6: if y < params[0]-1: # expand to bottom yn = y+1 _, inner_left = get_left_bound(clust, y, x) _, outer_left = get_left_bound(clust, yn, inner_left) _, inner_right = get_right_bound(clust, y, x) _, outer_right = get_right_bound(clust, yn, inner_right) clust = set_area(clust, yn, outer_left, yn, outer_right, 0) clust = set_area(clust, yn, inner_left, yn, inner_right, clust[y, x]) elif z < 0.8: if x < params[1]-1: # expand to right xn = x+1 inner_top, _ = get_top_bound(clust, y, x) outer_top, _ = get_top_bound(clust, inner_top, xn) inner_bot, _ = get_bottom_bound(clust, y, x) outer_bot, _ = get_bottom_bound(clust, inner_bot, xn) clust = set_area(clust, outer_top, xn, outer_bot, xn, 0) clust = set_area(clust, inner_top, xn, inner_bot, xn, clust[y, x]) else: pass#clust[y, x] = np.amax(clust)+1 return clust def myfunc(a, b): global first, values if first: first = False return if a not in values: values[a] = [0, 0] values[a][b] += 1 vfunc = np.vectorize(myfunc) # mutation xx = MUTATION_AMOUNT for i in range(POPULATION): if i % 20 == 0: print("mutation", i) MUTATION_AMOUNT = 500 clusters[i] = mutation(clusters[i]) MUTATION_AMOUNT = xx for iteration in range(ITERATIONS): fitnesses = get_fitnesses(clusters, clean=False) # calc fitness fitnesses = np.zeros((POPULATION, )) for i, cluster in enumerate(clusters): if i % 20 == 0: print("fitness", i, iteration) values = {} first = True vfunc(cluster, data) fitnesses[i] = get_fitness(values) # select z_exp = [np.exp(i) for i in fitnesses] sum_z_exp = sum(z_exp) softmax = [i / sum_z_exp for i in z_exp] idx = np.random.choice(POPULATION, POPULATION, p=softmax) clusters = clusters[idx, :, :] # print best max_idx = np.argmax(fitnesses) print(clusters[max_idx]) print(iteration, max(fitnesses)) # mutation for i in range(POPULATION): clusters[i] = mutation(clusters[i]) fitnesses = np.zeros((POPULATION, )) for i, cluster in enumerate(clusters): values = {} first = True vfunc(cluster, data) fitnesses[i] = get_fitness(values, clean=True) max_idx = np.argmax(fitnesses) print(clusters[max_idx]) print(max(fitnesses))