def k_means(X, k, n, init=None): # INITIALIZATION # return two vectors for the minimum and maximum point values for each dimension in the data # initialize the means by selecting random points from the dirts if init is None or len(init) != k: if k <= len(X): means = random.sample(X, k) else: means = X + random.choices(X, k=k - len(X)) else: if len(init) != k: print('init is the incorrect size') means = init for i in range(n): dists = [[distance2(u, x) for u in means] for x in X] # using distance squared because square roots # are expensive and argmin(x) == argmin(x^2) clusters = [[x for (x, ds) in zip(X, dists) if ds.index(min(ds)) == i] for i in range(k)] means = [ vector_average(xs) if xs else u for (xs, u) in zip(clusters, means) ] return (clusters, means)
def __init__(self, point_item): self.vertices = set() if not point_item.is_bounded(): return # Compute segments edges for other in point_item.others: v1, v2 = other.vertices() for v in [v1, v2]: EPSILON = 1e-4 distances = list(utils.distance2(v, i) for i in self.vertices) if len(distances) == 0 or min(distances) > EPSILON: self.vertices |= {v} # Sort vertices to make the shape convex self.vertices = list(self.vertices) OA = utils.vector(point_item.point, self.vertices[0]) len_OA = utils.length(OA) t = {(self.vertices[0], 0)} for vertex in self.vertices[1:]: OB = utils.vector(point_item.point, vertex) len_OB = utils.length(OB) cos_angle = utils.dot(OA, OB) / (len_OA * len_OB) if cos_angle < -1: cos_angle = -1 elif cos_angle > 1: cos_angle = 1 angle = math.acos(cos_angle) if utils.cross(OA, OB) < 0: # sign of sin angle = 2 * math.pi - angle t |= {(vertex, angle)} self.vertices = list(vertex for vertex, _ in sorted(t, key=lambda x: x[1]))
def delete_points(self, points_to_delete): EPSILON = 1e-4 others_to_delete = set() for p in points_to_delete: for other in self.others: if utils.distance2(other.item.point, p) < EPSILON: others_to_delete |= {other} self.others -= others_to_delete
def get_mask(self, width, height): # TODO caching static lights would optimize somewhat, but invalidation # needs to be taken into account mask = BitMask.zeros(width, height) if not self.lit: return mask # TODO this could be optimized to a square of 2 * range for y, row in enumerate(mask): for x, c in enumerate(row): if distance2(self._owner.pos, (x, y)) <= (self._range * self._range): mask[y][x] = 1 return mask
def delete_points(self, points_to_delete): EPSILON = 1e-4 items_to_delete = set() for i in self.point_items: to_delete = False for p in points_to_delete: if utils.distance2(i.point, p) < EPSILON: items_to_delete |= {i} to_delete = True break if not to_delete: i.delete_points(points_to_delete) self.point_items -= items_to_delete
def distance2(self, other): return distance2(self.pos, other.pos)
def build_network(self): self.network = nx.Graph() for u in self.env.agents: for v in [a for a in self.env.agents if distance2(u.location,a.location) <= self.range**2]: if not u is v: self.network.add_edge(u,v)
def find_nearest(agent_location, dirts): dists = [distance2(agent_location, d) for d in dirts] return dirts[dists.index(min(dists))]
def p_greedy_drone(percepts): agent_location = percepts['GPS'] agent_heading = percepts['Compass'] # collect communication data dirts = [o[1] for o in percepts['Objects'] if o[0] == 'Dirt'] drones = [ d[1] for d in percepts['Objects'] if d[0] == 'Drone' and d[1] != agent_location ] if dirts: close_dirts = [ d for d in dirts if distance2(d, agent_location) < (sensor_radius * .75)**2 ] if close_dirts: # if there are dirts close to you, move towards the center (of mass) of them target = vector_average(close_dirts) else: # if there are no dirts close to you, move towards the closest dirt target = find_nearest(agent_location, dirts) if drones: # if there are drones around, move away from them by half your sensor radius targets = [target] for d in [ d for d in drones if distance2(d, agent_location) < (sensor_radius)**2 ]: targets.append( vector_add( scalar_vector_product( sensor_radius * .5, vector_add(agent_location, scalar_vector_product(-1, d))), agent_location)) target = vector_average(targets) command = go_to(agent_location, agent_heading, target, bump=False) return command elif drones: # if no dirts, but there are drones around targets = [] for d in [ d for d in drones if distance2(d, agent_location) < (sensor_radius)**2 ]: targets.append( vector_add( scalar_vector_product( sensor_radius * .5, vector_add(agent_location, scalar_vector_product(-1, d))), agent_location)) if targets: target = vector_average(targets) return go_to(agent_location, agent_heading, target, bump=False) else: return random.choice([ 'TurnRight', 'TurnLeft', 'MoveForward', 'MoveForward', 'MoveForward', 'MoveForward' ]) else: # if no dirts and no drones, make a random action return random.choice([ 'TurnRight', 'TurnLeft', 'MoveForward', 'MoveForward', 'MoveForward', 'MoveForward' ])