def rand_point(self, size): """ Generate a random vector within the allowable region. :param size: norm of the vector to be generated :return: a random vector within the allowable regions (class P) """ if self.full: # if all motion is allowed, generate a completely random vector return P(misc.rand() - 0.5, misc.rand() - 0.5).resize(size) # else, generate a vector within the allowable regions # Draw a random angle within the accumulated allowed # regions total angle t = misc.rand() * self.width() total = 0 # Find in which region this randomly generated angle falls for r in self.regions: total += r.angle() if total >= t: res = r.rand_point( size) # Generate a random vector of norm=size within the # randomly chosen region return res print("Apparently stuck", self.width()) exit(1)
def rand_point_normal(self, direction, sigma): """ Choose a random angle from a normal distribution with mean direction and standard deviation sigma. Rotate input direction by this angle, unless it is too large (above 100). if so, draw a completely random direction. Note that since the normal distribution is not defined on an angular variable, the actual pdf we use is not truly normally distributed around the 0-direction (but it is close enough for our purposes). """ def cdf( x_var ): # shorthand function for cumulative distribution function with SD=sigma return sct.norm.cdf(x_var, scale=sigma) def ppf( x_var ): # shorthand function for inverse of the cumulative distribution function # with SD=sigma return sct.norm.ppf(x_var, scale=sigma) intervals = [] if self.full: # Truncating normal distribution cdf to fit angular variable intervals += [(cdf(-math.pi), cdf(math.pi))] else: for r in self.regions: # Rotating region sides to be centered around direction a1 = r.p1.rotate(-(direction.angle())).angle() a2 = r.p2.rotate(-(direction.angle())).angle() # Make sure interval boundaries are set up correctly if r.contains(-direction): intervals += [(cdf(a1), cdf(math.pi))] intervals += [(cdf(-math.pi), cdf(a2))] else: intervals += [(cdf(a1), cdf(a2))] # Accumulate allowed cdf(angle) in all intervals to randomly draw from total = 0 for x, y in intervals: total += y - x t = misc.rand() * total # Go over all intervals and translate random number t into the actual corresponding angle # in the accumulated cdf intervals for x, y in intervals: if t <= y - x: angle = ppf(x + t) # translate from x+t=cdf(angle) back to angle # if angle change is too large, choose random direction, else, rotate by this # angle. if angle > 100: return self.rand_point(direction.norm()) return direction.rotate(angle) t -= y - x exit(1)
def random_step(self, stones: PolygonSet, step_size: float, bias: P): last = self.last() directions = stones.open_directions_for_point(last, step_size) if not directions: print("walk stuck") exit(1) if misc.rand() < 0.5: random_directions = [ directions.rand_point(step_size) for i in range(2) ] direction = bias.resize(step_size).closest_point(random_directions) else: direction = directions.rand_point(step_size) self.points.append(last + direction)
def step(self): """ Perform one time step of the simulation. :return: cheerio - next load location (point P), False - signifying the simulation is not finished. """ cfg = self.cfg cheerio = self.cheerio # Where can we currently go allowable = cfg.stones.open_direction_for_circle(cheerio, cfg.cheerio_radius, self.speed) if not allowable: raise SimulationError # Update speed nest_direction = (cfg.nest - cheerio).resize(self.speed) # speed vector in the direction # of the nest (determined by the last data point of the load in that maze) # Compute two possible velocity directions: # 1)Align current velocity direction with some nest_direction bias (if needed) v1 = self.align((self.v + (nest_direction * 0.1)).resize(self.speed), allowable) # 2)Align nest_direction (if needed) v2 = self.align(nest_direction, allowable) if v1 and v2: # Align can return None if original velocity and aligned velocity have # an angle >90 between them expected_steps = cfg.cheerio_radius * 4 / self.speed # Average number of steps going # in the direction of the velocity (with rolling and a small bias) - persistent # behavior if misc.rand() < 1 / expected_steps: self.v = v2 else: self.v = v1 elif v1: self.v = v1 elif v2: self.v = v2 else: # Both are None, move in a random (allowed) direction. self.v = allowable.rand_point(self.speed) # self.v = allowable.rand_point_normal(nest_direction, 1) # Move cheerio self.cheerio = cheerio + self.v return cheerio, False
def random_squares(self, num, size): while len(self.polys) < num: self.add( Polygon.square(P(misc.rand(), misc.rand()), size, misc.rand() * np.pi / 2))
def random(cls): """class method/static method creating a random point.""" return cls(misc.rand(), misc.rand())