def test_replacement(self): new_group = SAnchored.Create((SAnchored(SElement(7), (), 7, 7), SAnchored(SElement(8), (), 8, 8), SAnchored(SElement(9), (), 9, 9))) ws = Workspace() ws.InsertElements(range(0, 10)) helper_create_and_insert_groups(ws, ((1, 2, 3), (4, 5, 6), (7, 8))) existing_group = list(ws.GetGroupsWithSpan(Exactly(7), Exactly(8)))[0] # Cannot replace a group which is not the topmost. self.assertRaises(CannotReplaceSubgroupException, ws.Replace, existing_group, new_group) ws = Workspace() ws.InsertElements(range(0, 10)) helper_create_and_insert_groups(ws, (7, 8)) existing_group = list(ws.GetGroupsWithSpan(Exactly(7), Exactly(8)))[0] ws.Replace(existing_group, new_group) self.assertTrue(existing_group not in ws.groups) self.assertEqual(1, len(list(ws.GetGroupsWithSpan(Exactly(7), Exactly(9))))) # So now (7, 8, 9) is a group. Let's add a group (5, 6) and try and extend it to 5:8 helper_create_and_insert_groups(ws, (5, 6)) existing_group = list(ws.GetGroupsWithSpan(Exactly(5), Exactly(6)))[0] new_group = SAnchored.Create((SAnchored(SElement(5), (), 5, 5), SAnchored(SElement(6), (), 6, 6), SAnchored(SElement(7), (), 7, 7), SAnchored(SElement(8), (), 8, 8))) self.assertRaises(ConflictingGroupException, ws.Replace, existing_group, new_group) # The original group still exists self.assertTrue(existing_group in ws.groups)
def test_anchored_creation(self): o1 = SObject.Create([3]) o1_anc = SAnchored(o1, [], 3, 3) o2 = SObject.Create([40]) o2_anc = SAnchored(o2, [], 4, 4) o3 = SObject.Create([30]) o3_anc = SAnchored(o3, [], 5, 5) # Create expects anchored objects... self.assertRaises(FargError, SAnchored.Create, (o1, )) # With a single arg, the object is returned unchanged. self.assertEqual(o1_anc, SAnchored.Create((o1_anc, ))) # With multiple args, we expect the positions of these to be adjacent. self.assertRaises(NonAdjacentGroupElementsException, SAnchored.Create, (o1_anc, o3_anc)) # This also implies that elements may not be repeated: self.assertRaises(NonAdjacentGroupElementsException, SAnchored.Create, (o1_anc, o1_anc)) # If ranges are fine, the group is constructed fine: o123_anc = SAnchored.Create((o1_anc, o2_anc, o3_anc)) self.assertEqual((3, 5), o123_anc.Span()) self.assertEqual((3, 40, 30), o123_anc.Structure())
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 test_plonk_into_place(self): ws = Workspace() ws.InsertElements((7, 8, 7, 8, 9)) # Plonk an element... returns existing element. elt = SAnchored(SElement(8), (), 3, 3) self.assertEqual(ws.elements[3], ws._PlonkIntoPlace(elt)) # Plonk a group, one item of which is an existing element, one novel. The plonked group # has the existing element as a subgroup. elt0 = SAnchored(SElement(7), (), 0, 0) elt1 = SAnchored(SElement(8), (), 1, 1) elt2 = SAnchored(SElement(7), (), 2, 2) elt3 = SAnchored(SElement(8), (), 3, 3) elt4 = SAnchored(SElement(9), (), 4, 4) numeric_successor = NumericMapping(name="succ", category=Number()) numeric_sameness = NumericMapping(name="same", category=Number()) successor_mapping_based_cat = MappingBasedCategory( mapping=numeric_successor) next_ascending = StructuralMapping( category=MappingBasedCategory(mapping=numeric_successor), bindings_mapping=frozenset((('length', numeric_successor), ('start', numeric_sameness)))) gp1 = SAnchored.Create( (elt0, elt1), underlying_mapping_set={numeric_successor}) gp2 = SAnchored.Create( (elt2, elt3, elt4), underlying_mapping_set={numeric_successor}) gp3 = SAnchored.Create( (gp1, gp2), underlying_mapping_set={next_ascending}) self.assertTrue(gp1.object.IsKnownAsInstanceOf( successor_mapping_based_cat)) plonked = ws._PlonkIntoPlace(gp3) self.assertEqual(((7, 8), (7, 8, 9)), plonked.Structure()) existing_groups = list(ws.GetGroupsWithSpan(Exactly(0), Exactly(1))) self.assertEqual(existing_groups[0], plonked.items[0]) self.assertTrue(plonked.items[0].object.IsKnownAsInstanceOf( successor_mapping_based_cat)) self.assertTrue(numeric_successor in plonked.items[ 0].object.underlying_mapping_set) self.assertTrue( next_ascending in plonked.object.underlying_mapping_set)
def test_insert_group(self): ws = Workspace() ws.InsertElements((5, 6)) gp = SAnchored.Create(ws.elements[:]) self.assertEqual((0, 1), gp.Span()) self.assertEqual((5, 6), gp.Structure()) ws.InsertGroup(gp) self.assertEqual(1, len(ws.groups))
def helper_create_group_given_spans_of_items(ws, *spans): anchored_items = [] for span in spans: if isinstance(span, int): anchored_items.append(ws.elements[span]) else: matching_groups = ws.GetGroupsWithSpan(Exactly(span[0]), Exactly(span[1])) anchored_items.append(next(matching_groups)) return SAnchored.Create(anchored_items)
def test_ltm_storability(self): gp = list(self.ws.groups)[0] self.assertIsInstance(gp, LTMStorableMixin) storable = gp.GetLTMStorableContent() self.assertIsInstance(storable, LTMStorableSObject) self.assertEqual((5, 6), storable.structure) self.assertEqual(gp.GetLTMStorableContent(), storable, "Repeated call gives same value.") # A different group with the same structure will also give the same storable. self.assertEqual( SAnchored.Create((self.ws.elements[0], self.ws.elements[1])).GetLTMStorableContent(), storable)
def test_group_overlap(self): # We can create a second group at same location ws = self.ws gp = list(ws.groups)[0] gp_cp = SAnchored.Create((ws.elements[0], ws.elements[1])) self.assertNotIn(gp_cp, ws.groups, "gp_cp not yet part of workspace") self.assertNotEqual(gp, gp_cp, "The two groups differ") gp2 = SAnchored.Create(ws.elements[:]) self.assertIn(gp, ws.GetConflictingGroups(gp2)) gp3 = SAnchored.Create((ws.elements[1], ws.elements[2])) # Overlap does not constitute conflict. self.assertNotIn(gp, ws.GetConflictingGroups(gp3)) # Also, groups do not conflict with others at exactly the same location if their structures are # identical. self.assertNotIn(gp, ws.GetConflictingGroups(gp_cp)) # However, [[X, Y], Z] SHOULD conflict [X, [Y, Z]] gp_XY_Z = ws.InsertGroup(SAnchored.Create((gp, ws.elements[2]))) gp_X_YZ = SAnchored.Create((ws.elements[0], gp3)) self.assertIn(gp_XY_Z, ws.GetConflictingGroups(gp_X_YZ))
def test_relations(self): # I will insert a relation between two groups, test its existence, and then delete one group. # The relation should disappear. gp = list(self.ws.groups)[0] gp2 = self.ws.InsertGroup(SAnchored.Create(self.ws.elements[2:4])) rel = Relation(gp, gp2, mapping_set=set()) rel.InsertSelf() self.assertIn(rel, gp.relations, "Ends contain relation") self.assertIn(rel, gp2.relations, "Ends contain relation") # Now let's delete gp2: gp should have no relations left. self.assertEqual(2, len(self.ws.groups)) self.ws.DeleteGroup(gp2) self.assertEqual(1, len(self.ws.groups)) self.assertNotIn(rel, gp.relations, "End no longer contains relation")
def helper_create_and_insert_group(ws, specification): """Utility for quickly creating groups. Each element in the specification is a tuple consisting of integers or of other similarly structured tuples. Each generates a group, where the integers correspond to position in the workspace. A degenerate case is when the specification is an integer, in which case the WS element is returned. """ if isinstance(specification, int): return ws.elements[specification] else: anchored_items = list(helper_create_and_insert_group(ws, x) for x in specification) new_group = SAnchored.Create(anchored_items) ws.InsertGroup(new_group) return new_group
def HelperCreateAndInsertGroup(workspace, specification, underlying_mapping_set=None): """Utility for quickly creating groups. Each element in the specification is a tuple consisting of integers or of other similarly structured tuples. Each generates a group, where the integers correspond to position in the workspace. A degenerate case is when the specification is an integer, in which case the WS element is returned. """ if isinstance(specification, int): return workspace.elements[specification] else: anchored_items = list(FringeOverlapTest.HelperCreateAndInsertGroup(workspace, x) for x in specification) new_group = SAnchored.Create(anchored_items, underlying_mapping_set=underlying_mapping_set) return workspace.InsertGroup(new_group)
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 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(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 setUp(self): self.ws = ws = Workspace() ws.InsertElements((5, 6, 7, 8)) ws.InsertGroup(SAnchored.Create((ws.elements[0], ws.elements[1])))