def build_linear_extent_selector(interpreter, speaker, location_d): """ builds a MemoryFilter that selects by a linear_extent dict chooses memory location nearest to the linear_extent dict interpreted as a location """ # FIXME this is being done at construction time, rather than execution mems = interpreter.subinterpret["reference_locations"](interpreter, speaker, location_d) steps, reldir = interpret_relative_direction(interpreter, location_d) pos, _ = interpreter.subinterpret["specify_locations"](interpreter, speaker, mems, steps, reldir) class dummy_loc_mem: def get_pos(self): return pos selector_attribute = LinearExtentAttribute(interpreter.agent, {"relative_direction": "AWAY"}, mem=dummy_loc_mem()) polarity = "argmin" sa = ApplyAttribute(interpreter.agent.memory, selector_attribute) selector = ExtremeValueMemorySelector(interpreter.agent.memory, polarity=polarity, ordinal=1) selector.append(sa) mems_filter = MemidList(interpreter.agent.memory, [mems[0].memid]) not_mems_filter = NotFilter(interpreter.agent.memory, [mems_filter]) selector.append(not_mems_filter) # selector.append(build_radius_comparator(interpreter, speaker, location_d)) return selector
def handle_move(self, speaker, d) -> Tuple[Optional[str], Any]: Move = self.task_objects["move"] Control = self.task_objects["control"] def new_tasks(): # TODO if we do this better will be able to handle "stay between the x" default_loc = getattr(self, "default_loc", SPEAKERLOOK) location_d = d.get("location", default_loc) # FIXME! this loop_data trick can now be done more properly with # a fixed mem filter if self.loop_data and hasattr(self.loop_data, "get_pos"): mems = [self.loop_data] else: mems = self.subinterpret["reference_locations"](self, speaker, location_d) # FIXME this should go in the ref_location subinterpret: steps, reldir = interpret_relative_direction(self, location_d) pos, _ = self.subinterpret["specify_locations"](self, speaker, mems, steps, reldir) # TODO: can this actually happen? if pos is None: raise ErrorWithResponse( "I don't understand where you want me to move.") pos = self.post_process_loc(pos, self) task_data = {"target": pos, "action_dict": d} task = Move(self.agent, task_data) return task if "stop_condition" in d: condition = self.subinterpret["condition"](self, speaker, d["stop_condition"]) location_d = d.get("location", SPEAKERLOOK) mems = self.subinterpret["reference_locations"](self, speaker, location_d) if mems: self.loop_data = mems[0] steps, reldir = interpret_relative_direction(self, location_d) # FIXME grammar to handle "remove" vs "stop" loop_task_data = { "new_tasks": new_tasks, "remove_condition": condition, #!!! semantic parser + GT need updating "action_dict": d, } return Control(self.agent, loop_task_data), None, None else: return new_tasks(), None, None
def new_tasks(): # TODO if we do this better will be able to handle "stay between the x" default_loc = getattr(self, "default_loc", SPEAKERLOOK) location_d = d.get("location", default_loc) if self.loop_data and hasattr(self.loop_data, "get_pos"): mems = [self.loop_data] else: mems = self.subinterpret["reference_locations"](self, speaker, location_d) # FIXME this should go in the ref_location subinterpret: steps, reldir = interpret_relative_direction(self, location_d) pos, _ = self.subinterpret["specify_locations"](self, speaker, mems, steps, reldir) # TODO: can this actually happen? if pos is None: raise ErrorWithResponse("I don't understand where you want me to move.") pos = self.post_process_loc(pos, self) task_data = {"target": pos, "action_dict": d} task = Move(self.agent, task_data) return [task]
def handle_move(self, speaker, d) -> Tuple[Optional[str], Any]: Move = self.task_objects["move"] Loop = self.task_objects["loop"] def new_tasks(): # TODO if we do this better will be able to handle "stay between the x" default_loc = getattr(self, "default_loc", SPEAKERLOOK) location_d = d.get("location", default_loc) if self.loop_data and hasattr(self.loop_data, "get_pos"): mems = [self.loop_data] else: mems = self.subinterpret["reference_locations"](self, speaker, location_d) # FIXME this should go in the ref_location subinterpret: steps, reldir = interpret_relative_direction(self, location_d) pos, _ = self.subinterpret["specify_locations"](self, speaker, mems, steps, reldir) # TODO: can this actually happen? if pos is None: raise ErrorWithResponse("I don't understand where you want me to move.") pos = self.post_process_loc(pos, self) task_data = {"target": pos, "action_dict": d} task = Move(self.agent, task_data) return [task] if "stop_condition" in d: condition = self.subinterpret["condition"](self, speaker, d["stop_condition"]) location_d = d.get("location", SPEAKERLOOK) mems = self.subinterpret["reference_locations"](self, speaker, location_d) if mems: self.loop_data = mems[0] steps, reldir = interpret_relative_direction(self, location_d) loop_task_data = { "new_tasks_fn": new_tasks, "stop_condition": condition, "action_dict": d, } self.append_new_task(Loop, loop_task_data) else: for t in new_tasks(): self.append_new_task(t) self.finished = True return None, None
def filter_by_sublocation( interpreter, speaker, candidates: List[Tuple[XYZ, T]], d: Dict, limit=1, all_proximity=10, loose=False, ) -> List[Tuple[XYZ, T]]: """Select from a list of candidate (xyz, object) tuples given a sublocation If limit == 'ALL', return all matching candidates Returns a list of (xyz, mem) tuples """ F = d.get("filters") assert F is not None, "no filters: {}".format(d) default_loc = getattr(interpreter, "default_loc", SPEAKERLOOK) location = F.get("location", default_loc) # if limit == 1: # limit = get_repeat_num(d) reldir = location.get("relative_direction") if reldir: if reldir == "INSIDE": # FIXME formalize this better, make extensible if location.get("reference_object"): # should probably return from interpret_reference_location... ref_mems = interpret_reference_object( interpreter, speaker, location["reference_object"]) for l, candidate_mem in candidates: I = interpreter.agent.on_demand_perception.get[ "check_inside"] if I: if I([candidate_mem, ref_mems[0]]): return [(l, candidate_mem)] else: raise ErrorWithResponse( "I don't know how to check inside") raise ErrorWithResponse("I can't find something inside that") elif reldir == "AWAY": raise ErrorWithResponse("I don't know which object you mean") elif reldir == "NEAR": pass # fall back to no reference direction elif reldir == "BETWEEN": mems = interpreter.subinterpret["reference_locations"](interpreter, speaker, location) steps, reldir = interpret_relative_direction(interpreter, d) ref_loc, _ = interpreter.subinterpret["specify_locations"]( interpreter, speaker, mems, steps, reldir) candidates.sort(key=lambda c: euclid_dist(c[0], ref_loc)) return candidates[:limit] else: # FIXME need some tests here # reference object location, i.e. the "X" in "left of X" mems = interpreter.subinterpret["reference_locations"](interpreter, speaker, location) # FIXME!!! handle frame better, might want agent's frame instead eid = interpreter.agent.memory.get_player_by_name(speaker).eid self_mem = interpreter.agent.memory.get_mem_by_id( interpreter.agent.memory.self_memid) L = LinearExtentAttribute(interpreter.agent, { "frame": eid, "relative_direction": reldir }, mem=self_mem) proj = L([c[1] for c in candidates]) # filter by relative dir, e.g. "left of Y" proj_cands = [(p, c) for (p, c) in zip(proj, candidates) if p > 0] # "the X left of Y" = the right-most X that is left of Y if limit == "ALL": limit = len(proj_cands) return [c for (_, c) in sorted(proj_cands, key=lambda p: p[0]) ][:limit] else: # no reference direction: choose the closest mems = interpreter.subinterpret["reference_locations"](interpreter, speaker, location) steps, reldir = interpret_relative_direction(interpreter, d) ref_loc, _ = interpreter.subinterpret["specify_locations"](interpreter, speaker, mems, steps, reldir) if limit == "ALL": return list( filter(lambda c: euclid_dist(c[0], ref_loc) <= all_proximity, candidates)) else: candidates.sort(key=lambda c: euclid_dist(c[0], ref_loc)) return candidates[:limit] return [] # this fixes flake but seems awful?