示例#1
0
    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
示例#2
0
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)
示例#3
0
    def GetConflictingGroups(self, gp):
        """Get a list of groups conflicting with given group.

           Only maximal groups are returned, where the relative order is based on being a
           subgroup (i.e., if A is a part of B, and both conflict, B is returned; note that if A
           conflicts with the group under consideration, so does B).
           .. Note:: This can be sped up if I am keeping track of supergroups.
        """
        if gp.is_sequence_element:
            return  # Elements can never conflict.
        if gp in self.groups:
            return       # Group already present, no conflict possible.

        groups_at_this_location = list(self.GetGroupsWithSpan(Exactly(gp.start_pos),
                                                              Exactly(gp.end_pos)))
        if groups_at_this_location:
            # If something lies at exactly this location, it had better have
            # the same structure.
            # Can only be one.
            group_at_this_location = groups_at_this_location[0]
            if group_at_this_location.Structure() == gp.Structure():
                return
            else:
                yield self.SomeMaximalSuperGroup(group_at_this_location)
                return

        # If we get here, no group at this exact location. See if any subgroup
        # conflicts.
        gp_items = set(gp.items)
        for subgroup in gp_items:
            conflicts = list(self.GetConflictingGroups(subgroup))
            if conflicts:
                for conflict in conflicts:
                    yield conflict
                return

        # Since we got here, any subgroup is fine individually. The only thing that may go wrong
        # is that there is overlap of more than one subgroup with an existing group (i.e., there
        # exists a (1, 2, 3, 4) and we are adding (3, 4, 5, 6)).

        existsing_group_items = set()
        for item in gp_items:
            # If a group exists with these ends, keep it in existing groups.
            for existing_group in self.GetGroupsWithSpan(Exactly(item.start_pos),
                                                         Exactly(item.end_pos)):
                # There can be at most one
                existsing_group_items.add(existing_group)

        for other_group in self.groups:
            other_gp_items = set(other_group.items)
            overlap = existsing_group_items.intersection(other_gp_items)
            if len(overlap) >= 2:
                yield self.SomeMaximalSuperGroup(other_group)
示例#4
0
  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)
示例#5
0
    def test_utility_functions(self):
        self.assertTrue(
            LessThan(3)(2), "2 is acceptable for the function LessThan(3)")
        self.assertTrue(
            LessThanEq(3)(2), "2 is acceptable for the function LessThanEq(3)")
        self.assertTrue(LessThanEq(3)(3))
        self.assertFalse(LessThan(3)(3))

        self.assertTrue(GreaterThan(3)(4))
        self.assertTrue(GreaterThanEq(3)(4))
        self.assertFalse(GreaterThan(3)(2))

        self.assertTrue(Exactly(3)(3))
        self.assertFalse(Exactly(3)(4))
示例#6
0
    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)
示例#7
0
 def GetGroupDistanceMagnitude(self, left, right):
     """Helper for the function above."""
     if right == left + 1:
         return 0
     rightward_groups = list(self.GetGroupsWithSpan(
         Exactly(left + 1), LessThan(right)))
     if not rightward_groups:
         return 1 + self.GetGroupsWithSpan(left + 1, right)
     else:
         new_left = max(x.end_pos for x in rightward_groups)
         return 1 + self.GetGroupDistanceMagnitude(new_left, right)