def FocusOn(self, focusable, controller): fringe = focusable.GetFringe() # TODO(amahabal) This way, anything that was ever a fringe element of an item stays that way. # But this way is much cheaper than updating everything, and not super wrong... # When we choose an object based on fringe overlap, we can recalculate, # if we wish... for fe, wt in fringe.items(): self.fringe_element_to_item_to_wt[fe][focusable] = wt timestamp = controller.steps_taken self.last_focus_time[focusable] = timestamp controller.ltm.GetNode(content=focusable).IncreaseActivation( 5, current_time=controller.steps_taken) actions = focusable.GetActions(controller) prior_overlapping_foci = self.PriorFociWithSimilarFringe( current_focus=focusable, timestamp=timestamp) if prior_overlapping_foci: actions.extend(focusable.GetRemindingBasedActions( prior_overlapping_foci)) History.Note("In FocusOn: Prior overlapping foci seen") if actions: selected_actions = ChooseAboutN(2, [(x, x.urgency) for x in actions]) History.Note("In FocusOn: Total of suggested actions", times=len(actions)) History.Note( "In FocusOn: Total of selected actions", times=len(selected_actions)) for action in selected_actions: controller.coderack.AddCodelet( action, msg="While focusing on %s" % focusable.BriefLabel(), parents=(focusable, ))
def ForceNextCodelet(self, codelet, *, forcer=None): """Force codelet to be the next one retrieved by GetCodelet. Args: codelet: The codelet to force as the return value of the next GetCodelet. Raises: FargError: codelet is not in fact present in the coderack. .. Note:: This mechanism should only be used during testing. It is unsafe in that if the codelet is expunged (because of new codelets being added), the program can crash. This will never happen if the next codelet is marked and GetCodelet called soon thereafter. """ if codelet not in self._codelets: raise FargError( "Cannot mark a non-existant codelet as the next to retrieve.") self._forced_next_codelet = codelet if forcer: History.AddEvent(EventType.CODELET_FORCED, "Codelet forced to be next", [[codelet, ""], [forcer, "forcer"]]) else: History.AddEvent(EventType.CODELET_FORCED, "Codelet forced to be next", [[codelet, ""]])
def Run(cls, controller, *, me): workspace = controller.workspace supergroups_map = workspace.CalculateSupergroupMap() History.Note("CF_RemoveSpuriousRelations: called") for element in workspace.elements: supergps = supergroups_map[element] if not supergps: continue relations_to_remove = [] for relation in element.relations: if relation.first == element: other_end = relation.second else: other_end = relation.first other_supergps = supergroups_map[other_end] if not other_supergps: continue if supergps.intersection(other_supergps): continue other_end.relations.discard(relation) relations_to_remove.append(relation) History.Note("CF_RemoveSpuriousRelations: removed", times=len(relations_to_remove)) for relation in relations_to_remove: element.relations.discard(relation)
def __init__(self, *, first, second, parents=[]): self.first = first self.second = second Categorizable.__init__(self) if History._is_history_on: roles = {first._hid: "first end", second._hid: "second end"} History.AddArtefact(self, ObjectType.WS_RELN, "", parents, roles) History.Note("Created relation")
def InsertElement(self, element): """Insert an element beyond the last element.""" assert isinstance(element, SElement) anchored = SAnchored(sobj=element, items=[], start_pos=self.num_elements, end_pos=self.num_elements, is_sequence_element=True) self.num_elements += 1 History.AddArtefact(anchored, ObjectType.WS_GROUP, "Initial creation") History.Note("Element Inserted") self.elements.append(anchored)
def _PlonkIntoPlace(self, group, *, parents=None): """Anchors the group into the workspace. Assumes that conflicts have already been checked for. """ groups_at_this_location = list(self.GetGroupsWithSpan(Exactly(group.start_pos), Exactly(group.end_pos))) if groups_at_this_location: # Merge current group into the group at this location, as it were. This merging only # adds the underlying mapping. However, if we extend groups to make multiple # underlying mappings possible, this needs to be updated too. group_at_this_location = groups_at_this_location[ 0] # There can be only 1 if (group.object.underlying_mapping_set and not group_at_this_location.object.underlying_mapping_set): group_at_this_location.object.underlying_mapping_set = set( group.object.underlying_mapping_set) # We should also merge all pieces of the group into the # corresponding existing pieces. for x in group.items: self._PlonkIntoPlace(x) # Ignore output, we don't need it. group_at_this_location.object.AddCategoriesFrom(group.object) return group_at_this_location # Group does not exist, create one. pieces = [self._PlonkIntoPlace(x) for x in group.items] new_object = SAnchored.Create(pieces, underlying_mapping_set=set( group.object.underlying_mapping_set)) new_object.object.AddCategoriesFrom(group.object) self.groups.add(new_object) History.AddArtefact(new_object, ObjectType.WS_GROUP, "Initial creation: [%d, %d]" % (new_object.start_pos, new_object.end_pos), parents=parents) return new_object
def __init__(self): #: Variables are a superset of Attributes: they additionally contain internal, attribute-like #: things, that don't need to be made public. There are no constraints on the values for #: non-attribute variables. self._Variables = set() # We will add to these. self._Variables.update(self._Attributes) #: Compiled rules are obtained from the string versions by parsing and seeking out variables. self._CompiledRules = [] for rule in self._Rules: target, rest = rule.split(sep=':', maxsplit=1) rule_obj = Rule(target=target.strip(), expression=rest.lstrip(), ctx=self._Context) self._Variables.add(target.strip()) self._Variables.update(x for x in rule_obj.GetVars()) self._CompiledRules.append(rule_obj) #: Compiled checks. These are expressed as rules, but there is no target. self._CompiledChecks = [] for rule in self._Checks: rule_obj = Rule(target=None, expression=rule.strip(), ctx=self._Context) self._Variables.update(x for x in rule_obj.GetVars()) self._CompiledChecks.append(rule_obj) self.SanityCheck() History.AddArtefact(self, artefact_type=ObjectType.CATEGORY)
def InsertGroup(self, group, *, parent=None): """Inserts a group into the workspace. It must not conflict with an existing group, else a ConflictingGroupException is raised. Returns a new group formed from things added to the workspace. """ conflicting_groups = tuple(self.GetConflictingGroups(group)) if conflicting_groups: logger.info('Conflicts while adding %s: %s', group, '; '.join(str(x) for x in conflicting_groups)) History.Note("Group insert: conflict") raise ConflictingGroupException( conflicting_groups=conflicting_groups) else: History.Note("Group insert: no conflict") return self._PlonkIntoPlace(group)
def __init__(self, *, ui=None, controller_depth=0, parent_controller=None, workspace_arguments=None, stopping_condition=None): History.AddArtefact(self, ObjectType.CONTROLLER, "Created controller") #: How deeply in the stack this controller is. The top-level controller has a depth #: of 0, Subspaces it spawns 1, and so forth. self.controller_depth = controller_depth #: If this is a controller of a subspace, this points to parent_controller. self.parent_controller = parent_controller #: The coderack. self.coderack = self.coderack_class() #: The stream. self.stream = self.stream_class(self) if self.workspace_class: if workspace_arguments is None: workspace_arguments = dict() #: Workspace, constructed if workspace_class is defined. The workspace is constructed #: using workspace_arguments. self.workspace = self.workspace_class( **workspace_arguments) # pylint: disable=E1102 if self.ltm_name: #: LTM, if any self.ltm = LTMManager.GetLTM(self.ltm_name) else: self.ltm = None #: Number of steps taken self.steps_taken = 0 #: The UI running this controller. May be a GUI or a Guided UI (which knows how to #: answer questions that'd normally be answered by a user in a GUI). Any subspace #: spawned by this space shall inherit the ui. self.ui = ui #: Stopping condition (for SxS and batch modes). self.stopping_condition = stopping_condition # Add any routine codelets... self._AddRoutineCodelets(force=True)
def __init__(self, *, log_msg='', parents=[]): PSFocusable.__init__(self) self.relations = dict() self._span = None History.AddArtefact(item=self, artefact_type=ObjectType.WS_GROUP, log_msg=log_msg, parents=parents)
def _ExpungeSomeCodelet(self): """Removes a codelet, chosen uniformly randomly.""" codelet = random.choice(list(self._codelets)) kLogger.info("Coderack over capacity: expunged codelet of family %s." % codelet.family.__name__) self._RemoveCodelet(codelet) History.AddEvent(EventType.CODELET_FORCED, "Codelet expunged", [[codelet, ""]])
def FindCategories(self, *, end_category): new_cats = [] for reln_cat in end_category._RelationCategories: if self.IsKnownAsInstanceOf(reln_cat): continue if (self.DescribeAs(reln_cat)): History.Note("Category added to reln") new_cats.append(reln_cat) return new_cats
def GetFringe(self): fringe = self.CalculateFringe() for cat, instance_logic in self.categories.items(): fringe[cat] = 1 for att, val in instance_logic._attributes.items(): fringe[(cat, att, val.Structure())] = 0.5 self.stored_fringe = fringe History.Note("GetFringe called") return fringe
def Append(self, *, magnitudes): """Adds elements with these magnitudes at the end.""" to_add = [PSElement(magnitude=x) for x in magnitudes] for idx, el in enumerate(to_add, self._next_index): el._span = (idx, idx) self._objects_with_span[(idx, idx)][el.Structure()] = el self.element.extend(to_add) self._next_index += len(magnitudes) History.Note("Arena: elements added", times=len(magnitudes))
def AddCodelet(self, codelet, *, msg="", parents=[]): """Adds codelet to coderack. Removes some existing codelet if needed.""" kLogger.debug('Codelet added: %s', str(codelet.family)) if self._codelet_count == self._max_capacity: self._ExpungeSomeCodelet() self._codelets.add(codelet) self._codelet_count += 1 self._urgency_sum += codelet.urgency History.AddArtefact(codelet, ObjectType.CODELET, "Codelet %s %s" % (codelet.family.__name__, msg), parents)
def __init__(self, first, second, *, mapping_set): #: Typically, the object on the left. self.first = first #: Typically, the object on the right. self.second = second #: The set of mappings any of which transform the left object to the right object. self.mapping_set = mapping_set History.AddArtefact(self, ObjectType.WS_RELN, "", parents=(self.first, self.second))
def FocusOn(self, focusable, *, parents=None): """Focus on focusable, and act on a fringe-hit.""" History.AddEvent(EventType.OBJECT_FOCUS, "", [(focusable, "")]) assert (isinstance(focusable, FocusableMixin)) focusable.OnFocus(self.controller) self._PrepareForFocusing(focusable) hit_map = self.StoreFringeAndCalculateOverlap(focusable) # Possibly add codelets based on the fringe hit. potential_codelets = [] for prior_focusable, overlap_amount in hit_map.items(): if overlap_amount < Stream.kMinOverlapToTriggerSimilarity: continue potential_codelets.extend( prior_focusable.GetSimilarityAffordances( focusable, other_fringe=self.stored_fringes[focusable], my_fringe=self.stored_fringes[prior_focusable], controller=self.controller)) potential_codelets.extend( focusable.GetAffordances(controller=self.controller)) if potential_codelets: selected_codelets = ChooseAboutN(2, [(x, x.urgency) for x in potential_codelets]) History.Note("Chose to keep codelet during FocusOn", times=len(selected_codelets)) History.Note("Chose not to keep codelet during FocusOn", times=len(potential_codelets) - len(selected_codelets)) effective_parents = [focusable] if parents: effective_parents.extend(parents) for codelet in selected_codelets: self.controller.coderack.AddCodelet( codelet, msg="While focusing on %s" % focusable.BriefLabel(), parents=effective_parents)
def MergeObject(self, obj): merge_map = dict() merged = self._MergeObject(obj, merge_map) for old, new in merge_map.items(): for tgt, rel in old.relations.items(): effective_tgt = tgt if tgt in merge_map: effective_tgt = merge_map[tgt] rel_in_arena = new.GetRelationTo(effective_tgt) rel_in_arena.MergeCategoriesFrom(rel) History.AddEvent(event_type=EventType.OBJ_MERGED, log_msg="Merged", item_msg_list=dict(obj="outside arena", merged="Inside arena")) return merged
def Step(self): """Executes the next (stochastically chosen) step in the model.""" self.steps_taken += 1 if self.ltm: self.ltm._timesteps = self.steps_taken self._AddRoutineCodelets() if not self.coderack.IsEmpty(): codelet = self.coderack.GetCodelet() History.AddEvent(EventType.CODELET_RUN_START, "Codelet run started", [[codelet, ""]]) codelet.Run() if self.stopping_condition: if self.steps_taken % farg_flags.FargFlags.stopping_condition_granularity == 0: if self.stopping_condition(self): raise StoppingConditionMet(codelet_count=self.steps_taken)
def AddCodelet(self, codelet, *, msg="", parents=[]): """Adds codelet to coderack. Removes some existing codelet if needed.""" kLogger.debug("Codelet added: %s", str(codelet.family)) if self._codelet_count == self._max_capacity: self._ExpungeSomeCodelet() self._codelets.add(codelet) self._codelet_count += 1 self._urgency_sum += codelet.urgency roles = {} for k, v in codelet.args.items(): if hasattr(v, "_hid"): roles[v._hid] = "Argument %s" % k History.AddArtefact(codelet, ObjectType.CODELET, msg, parents, roles=roles)
def Step(self): """Executes the next (stochastically chosen) step in the model.""" self.steps_taken += 1 if self.ltm: self.ltm._timesteps = self.steps_taken self._AddRoutineCodelets() if not self.coderack.IsEmpty(): codelet = self.coderack.GetCodelet() roles = [[codelet, "codelet"]] for k, v in codelet.args.items(): if hasattr(v, "_hid"): roles.append([v, "Argument %s" % k]) History.AddEvent(EventType.CODELET_RUN_START, "", roles) codelet.Run() if self.stopping_condition: if self.steps_taken % farg_flags.FargFlags.stopping_condition_granularity == 0: if self.stopping_condition(self): raise StoppingConditionMet(codelet_count=self.steps_taken)
def __init__(self, parent_controller, *, nsteps=5, workspace_arguments=None, parents=None, msg=""): """Initializes the subspace by just storing the arguments.""" self.parent_controller = parent_controller self.nsteps = nsteps self.workspace_arguments = workspace_arguments effective_parents = [parent_controller] if parents: effective_parents.extend(parents) History.AddArtefact(self, ObjectType.SUBSPACE, msg, parents=effective_parents)
def Run(cls, controller, left, right, *, me): if left not in controller.workspace.groups or right not in controller.workspace.groups: # Groups gone, fizzle. History.Note("CF_ActOnOverlappingGroups: left group now dead") return if set(left.items).intersection(set(right.items)): # So overlap, and share elements. left_underlying_set = left.object.underlying_mapping_set right_underlying_set = right.object.underlying_mapping_set # TODO(# --- Jan 28, 2012): Even if the following fails, there is reason to try and # see how the two may be made to agree. if left_underlying_set and left_underlying_set.intersection( right_underlying_set): # This calls out for merging! new_group_items = sorted(set(left.items).union(set( right.items)), key=lambda x: x.start_pos) logging.debug("New group items: %s", '; '.join(str(x) for x in new_group_items)) new_group = SAnchored.Create( new_group_items, underlying_mapping_set=left_underlying_set.intersection( right_underlying_set)) try: controller.workspace.Replace((left, right), new_group) except ConflictingGroupException as e: SubspaceDealWithConflictingGroups( controller, workspace_arguments=dict( new_group=new_group, incumbents=e.conflicting_groups), parents=[me, left, right], msg="Conflict when merging overlapping groups").Run() except CannotReplaceSubgroupException as e: SubspaceDealWithConflictingGroups( controller, workspace_arguments=dict(new_group=new_group, incumbents=e.supergroups), parents=[me, left, right], msg= "Cannot replace subgp when merging overlapping groups" ).Run()
def ProcessFlags(self): """Sanity checks and does some flag-related and flag-triggered house-keeping. This includes creating directories, starting logging, and so forth. """ if self.flags.history: History.TurnOn() if self.flags.debug_config: logging.config.fileConfig(self.flags.debug_config) if self.flags.debug: numeric_level = getattr(logging, self.flags.debug.upper(), None) if not isinstance(numeric_level, int): print('Invalid log level: %s' % self.flags.debug) sys.exit(1) logging.basicConfig(level=numeric_level, format='%(levelname)s:%(message)s') logging.getLogger().setLevel( numeric_level) # To override based on --debug flag logging.debug("Debugging turned on") self.ProcessCustomFlags() if self.flags.input_spec_file: # Check that this is a file and it exists. if not os.path.exists(self.flags.input_spec_file): print( "Input specification file '%s' does not exist. Bailing out." % self.flags.input_spec_file) sys.exit(1) if not os.path.isfile(self.flags.input_spec_file): print("Input specification '%s' is not a file. Bailing out." % self.flags.input_spec_file) sys.exit(1) self._VerifyStoppingConditionSanity() self._VerifyPersistentDirectoryPath() self._VerifyLTMPath() self._VerifyStatsPath() self.run_mode = self._CreateRunModeInstance()
def Run(cls, controller, relation, *, me): # If there is a group spanning the proposed group, perish the thought. left, right = relation.first.start_pos, relation.second.end_pos from farg.apps.seqsee.util import GreaterThanEq, LessThanEq if tuple( controller.workspace.GetGroupsWithSpan(LessThanEq(left), GreaterThanEq(right))): History.Note("CF_GroupFromRelation: a spanning group exists") return anchored = SAnchored.Create( (relation.first, relation.second), underlying_mapping_set=relation.mapping_set) try: controller.workspace.InsertGroup(anchored, parent=[me]) except ConflictingGroupException as e: SubspaceDealWithConflictingGroups( controller, workspace_arguments=dict(new_group=anchored, incumbents=e.conflicting_groups), parents=[me, relation], msg="Conflict while inserting %s" % anchored.BriefLabel()).Run()
def Run(self): """Runs the subspace by first trying to quickly estimate need for deeper exploration. If deeper exploration is called for, sets up the controller, workspace, and so forth, and runs the controller for upto the specified number of steps. """ History.AddEvent(EventType.SUBSPACE_ENTER, "", [(self, '')]) quick_reconn_result = self.QuickReconn() if quick_reconn_result.state == QuickReconnResults.kAnswerFound: History.AddEvent(EventType.SUBSPACE_EXIT, "Answer found", [(self, '')]) return quick_reconn_result.answer elif quick_reconn_result.state == QuickReconnResults.kAnswerCannotBeFound: History.AddEvent(EventType.SUBSPACE_EXIT, "Answer cannot be found", [(self, '')]) return None History.AddEvent(EventType.SUBSPACE_DEEPER_EX, "", [(self, '')]) # So we need deeper exploration. parent_controller = self.parent_controller self.controller = self.controller_class( ui=parent_controller.ui, controller_depth=(parent_controller.controller_depth + 1), workspace_arguments=self.workspace_arguments, parent_controller=parent_controller) self.InitializeCoderack() try: self.controller.RunUptoNSteps(self.nsteps) except AnswerFoundException as e: History.AddEvent(EventType.SUBSPACE_EXIT, "Found answer", [(self, '')]) return e.answer except NoAnswerException: History.AddEvent(EventType.SUBSPACE_EXIT, "No answer", [(self, '')]) return None History.AddEvent(EventType.SUBSPACE_EXIT, "No answer", [(self, '')]) return None
def __init__(self, *, first, second): self.first = first self.second = second Categorizable.__init__(self) History.Note("Created relation")
def __init__(self): self.stored_fringe = None History.Note("Focusable created") Categorizable.__init__(self)
def Run(cls, controller, item, *, me): if item not in controller.workspace.groups: History.Note("CF_ExtendGroup: item not in workspace") # item deleted? return # QUALITY TODO(Feb 14, 2012): Direction to extend choice can be # improved. extend_right = True if (item.start_pos > 0 and Toss(0.5)): extend_right = False parts = item.items underlying_mapping_set = item.object.underlying_mapping_set if not underlying_mapping_set: History.Note("CF_ExtendGroup: no underlying relations") return mapping = SelectWeightedByActivation( controller.ltm, underlying_mapping_set) if extend_right: next_part = mapping.Apply(parts[-1].object) if not next_part: History.Note( "CF_ExtendGroup: could not apply mapping to last part") return magnitudes = next_part.FlattenedMagnitudes() number_of_known_elements = len( controller.workspace.elements) - item.end_pos - 1 if len(magnitudes) > number_of_known_elements: # TODO(# --- Feb 14, 2012): This is where we may go beyond known elements. # To the extent that the next few elements are known, ensure that they agree with # what's known. if not controller.workspace.CheckForPresence(item.end_pos + 1, magnitudes[:number_of_known_elements]): return # The following either returns false soon if the user will not be asked, or asks # the user and returns the response. If the response is yes, the elements are also # added. should_continue = SubspaceGoBeyondKnown( controller, workspace_arguments=dict(basis_of_extension=item, suggested_terms=magnitudes), parents=[me, item]).Run() if not should_continue: return else: if not controller.workspace.CheckForPresence(item.end_pos + 1, magnitudes): return next_part_anchored = SAnchored.CreateAt( item.end_pos + 1, next_part) new_parts = list(parts[:]) new_parts.append(next_part_anchored) else: flipped = mapping.FlippedVersion() if not flipped: return previous_part = flipped.Apply(parts[0].object) if not previous_part: return magnitudes = previous_part.FlattenedMagnitudes() if len(magnitudes) > item.start_pos: return if not controller.workspace.CheckForPresence(item.start_pos - len(magnitudes), magnitudes): return prev_part_anchored = SAnchored.CreateAt(item.start_pos - len(magnitudes), previous_part) new_parts = [prev_part_anchored] new_parts.extend(parts) new_group = SAnchored.Create(new_parts, underlying_mapping_set={mapping}) from farg.apps.seqsee.exceptions import ConflictingGroupException from farg.apps.seqsee.exceptions import CannotReplaceSubgroupException from farg.apps.seqsee.subspaces.deal_with_conflicting_groups import SubspaceDealWithConflictingGroups try: controller.workspace.Replace(item, new_group) except ConflictingGroupException as e: SubspaceDealWithConflictingGroups( controller, workspace_arguments=dict(new_group=new_group, incumbents=e.conflicting_groups), parents=[me, item], msg="Conflict when replacing item with enlarged group").Run() except CannotReplaceSubgroupException as e: SubspaceDealWithConflictingGroups( controller, workspace_arguments=dict(new_group=new_group, incumbents=e.supergroups), parents=[me, item], msg="Cannot replace subgp when extending item").Run()
def __init__(self, *, msg='', parents=[]): PSFocusable.__init__(self) self.relations = dict() self._span = None History.AddArtefact(self, ObjectType.WS_GROUP, "EltOrGp %s" % msg, parents)