コード例 #1
0
    def equivalent(self, css):
        """
        :param css:
            A simple CSS object
        :returns:
            True iff the object represents the same CSS file as css.
            That is, contains the same edges and respects the order.
        """
        edgeSet = { Sim.simpleRule(s, p)
                    for (ss, pp) in self.cliques
                    for (s, p) in product(ss, pp) }

        if edgeSet != css.edgeSet:
            if __DEBUG__:
                print 'There are ' + str(len(edgeSet)) +' edges in edgeSet'
                print 'There are ' + str(len(css.edgeSet)) +\
                        ' edges in css.edgeSet'
                print 'There are ' + str(len(edgeSet - css.edgeSet)) +\
                        ' edges in edgeSet - css.edgeSet'
                print 'There are ' + str(len(css.edgeSet - edgeSet)) +\
                        ' edges in css.edgeSet - edgeSet'
                print 'Edges missing from clique: ' +\
                        str(css.edgeSet - edgeSet)
                print 'Edges missing from simple css: ' +\
                        str(edgeSet - css.edgeSet)
            return False

        last_occurence = dict()
        i = 0
        lo_to_bucket = dict()
        j = 0
        for (ss, pp) in self.cliques:
            for p in pp:
                for s in ss:
                    e = Sim.simpleRule(s, p)
                    last_occurence[e] = i
                    lo_to_bucket[i] = j
                    i += 1
            j += 1

        for (e1, e2) in css.edgeOrder:
            # TODO: fix so edges can be in same bucket as long as they can be
            # ordered
            if not last_occurence[e1] < last_occurence[e2]:
                print "Edge ", e1, " last appears at property position", last_occurence[e1]
                print "Edge ", e1, " last appears at bucket", \
                lo_to_bucket[last_occurence[e1]]
                print self.cliques[lo_to_bucket[last_occurence[e1]]]
                print "Edge ", e2, " last appears at property position", last_occurence[e2]
                print "Edge ", e2, " last appears at bucket", \
                lo_to_bucket[last_occurence[e2]]
                print self.cliques[lo_to_bucket[last_occurence[e2]]]
                print "But the first should appear before the second!"
                return False

        return True
コード例 #2
0
def trim_file(clique):
    """Removes nodes (selectors or properties) from cliques if all incident
    edges are not the final instance of that edge in the file.

    :param clique:
        A cliqueCSS that will be trimmed in place
    :returns:
        Number of nodes removed
    """
    last_index = clique.build_last_index_map()
    removed = 0

    # remove nodes
    for (i, (ss, pp)) in enumerate(clique):
        s_to_del = []
        for s in ss:
            removable = True
            for p in pp:
                if last_index[simpleRule(s, p)] == i:
                    removable = False
                    break
            if removable:
                s_to_del.append(s)

        p_to_del = []
        for p in pp:
            removable = True
            for s in ss:
                if last_index[simpleRule(s, p)] == i:
                    removable = False
                    break
            if removable:
                p_to_del.append(p)

        for s in s_to_del:
            ss.remove(s)
        for p in p_to_del:
            pp.remove(p)

        removed += len(s_to_del) + len(p_to_del)

    # remove empty buckets
    to_del = []
    for (i, (ss, pp)) in enumerate(clique):
        if len(ss) == 0 or len(pp) == 0:
            bisect.insort(to_del, i)
    for i in reversed(to_del):
        clique.remove_rule(i)

    return removed
コード例 #3
0
    def __add_clique_count_size(self, i, optimizer):
        """Adds soft constraint counting the size of each clique i after the
        refactoring.  Not quite accurate since we don't detect savings from
        emptied bicliques.

        :param i:
            An index in range(num rules in clique)
        :param optimizer:
            A Z3 Optimize to add soft_constraints to
        :returns:
            A Z3 handle to the soft_constraints, else None if none created
        """
        h = None
        (ss, pp) = self.clique.cliques[i]

        # now subtract any nodes we can remove
        for s in ss:
            # can remove if all incident edges appearing here last appear later
            # or in new bucket (if new bucket appears later)
            can_remove = [
                self.__has_edge(s, p, optimizer) for p in pp
                if self.last_index[simpleRule(s, p)] == i
            ]
            can_remove.append(i < self.idx)

            can_remove_v = _z3.Bool("can_remove_s_" + str(s) +
                                    "_from_bucket_" + str(i))

            cnf_v_iff_conj(can_remove_v, can_remove, optimizer, _z3)

            # if edge appears after bucket, or can't remove, cost is len(s) + 1
            # for trailing ,
            h = optimizer.add_soft(can_remove_v, len(s) + 1)

        for p in pp:
            can_remove = [
                self.__has_edge(s, p, optimizer) for s in ss
                if self.last_index[simpleRule(s, p)] == i
            ]
            can_remove.append(i < self.idx)

            can_remove_v = _z3.Bool("can_remove_p_" + str(p) +
                                    "_from_bucket_" + str(i))

            cnf_v_iff_conj(can_remove_v, can_remove, optimizer, _z3)

            h = optimizer.add_soft(can_remove_v, len(p) + 1)

        return h
コード例 #4
0
    def __add_biclique_position_range(self, optimizer):
        """Adds to optimizer a formula asserting that biclique i cannot appear
        before any of its edges have appeared, or more than one bucket after the
        last of its edges appears in the current CSS.

        Also asserts that the ith insertion appears after the (i-1)th

        :param optimizer:
            A Z3 Optimize instance to add to
        """
        first_index = self.clique.build_first_index_map()

        for (ss, pp) in self.bicliques:
            # have to be able to remove from at least two rules to make a
            # difference
            min_idx = self.second_index[(ss, pp)]
            max_idx = 1 + max(self.last_index[simpleRule(s, p)]
                              for (s, p) in product(ss, pp))

            # is biclique => idx > min && idx < max
            optimizer.add(
                _z3.Or(_z3.Not(self.__is_biclique((ss, pp))),
                       self.idx > min_idx))
            optimizer.add(
                _z3.Or(_z3.Not(self.__is_biclique((ss, pp))),
                       self.idx <= max_idx))
コード例 #5
0
    def __edge_order_respected(self, edgeOrder):
        """
        :param edgeOrder:
            A list of pairs of simpleRules (e1, e2) giving order e1 < e2
        :returns:
            True iff the cliqueCSS object respects the edgeOrder
        """
        last_occurence = dict()
        i = 0
        for (ss, pp) in self.cliques:
            for p in pp:
                for s in ss:
                    e = Sim.simpleRule(s, p)
                    last_occurence[e] = i
                    i += 1

        for (e1, e2) in edgeOrder:
            if (e1 in last_occurence and
                e2 in last_occurence and
                not last_occurence[e1] < last_occurence[e2]):
                print "Edge ", e1, " last appears at property position", last_occurence[e1]
                print "Edge ", e2, " last appears at property position", last_occurence[e2]
                print "But the first should appear before the second!"
                return False

        return True
コード例 #6
0
    def build_last_index_map(self):
        """Note: constructs map anew each call.

        :returns:
            A map where last_index[simpleRule(s, p)] returns the index of the last
            bucket containing that edge
        """
        last_index = dict()
        for (i, (ss, pp)) in enumerate(self):
            for (s, p) in product(ss, pp):
                simple = Sim.simpleRule(s,p)
                last_index[simple] = i
        return last_index
コード例 #7
0
    def get_edge_set(self, min_pos = 0, max_pos = -1):
        """Note: computes each time

        :param min_pos:
            For getting rules from a portion of the file, begin at min_pos.
            Must be in range(num_rules())
        :param max_pos:
            The last position to get edges from.
            Can be -1 to denote end of file
        :returns:
            a set of all simpleRules covered by the cliqueCSS
        """
        if max_pos < 0:
            max_pos = self.num_rules()

        return { Sim.simpleRule(s, p)
                 for i in xrange(min_pos, max_pos)
                 for (s, p) in product(self.cliques[i][0],
                                       self.cliques[i][1]) }
コード例 #8
0
    def __build_second_index_map(self, bicliques):
        """
        :param bicliques:
            Set of bicliques (ss, pp) to build map for
        :returns:
            A map from max bicliques of simple to the second bucket in
            clique that contains an edge of the max biclique.
            Only defined for max bicliques satisfying such a property
        """
        second_index_map = dict()

        first_index = self.clique.build_first_index_map()

        for (ss, pp) in bicliques:
            min_idxs = set(first_index[simpleRule(s, p)]
                           for (s, p) in product(ss, pp))
            if len(min_idxs) > 1:
                min_idxs.remove(min(min_idxs))
                second_index_map[(ss, pp)] = min(min_idxs)

        return second_index_map
コード例 #9
0
 def __add_edges_exist(self, optimizer):
     """Adds a formula asserting that edges in the refactoring actually exist"""
     for (s, p) in product(self.sels, self.props):
         e = simpleRule(s, p)
         if e not in self.last_index:
             optimizer.add(_z3.Not(self.__has_edge_e(e)))
コード例 #10
0
def main():
    r1 = Sim.simpleRule('A','1')
    r2 = Sim.simpleRule('A','4')
    r3 = Sim.simpleRule('A','7')
    r4 = Sim.simpleRule('B','1')
    r5 = Sim.simpleRule('B','4')
    r6 = Sim.simpleRule('C','4')
    r7 = Sim.simpleRule('C','5')
    r8 = Sim.simpleRule('C','7')
    r9 = Sim.simpleRule('D','3')
    r10 = Sim.simpleRule('D','5')
    r11 = Sim.simpleRule('D','6')
    r12 = Sim.simpleRule('E','2')
    r13 = Sim.simpleRule('E','3')
    r14 = Sim.simpleRule('E','6')
    r15 = Sim.simpleRule('E','7')
    r16 = Sim.simpleRule('F','2')
    r17 = Sim.simpleRule('F','7')
    CSS = Sim.simpleCSS([ eval('r'+str(i)) for i in range(1,18)],[(r1,r2),(r2,r3)])
    clique = cliqueCSS()
    clique.add_rule({r1.getSelector()},[r1.getProperty()])
    clique.add_rule({r3.getSelector()},[r3.getProperty()])
    clique.add_rule({r2.getSelector()},[r2.getProperty()])
    assert clique.is_sub_css(CSS), 'something wrong'
コード例 #11
0
    def equivalent_masked(self, css):
        """
        :param css:
            A simple CSS object
        :returns:
            True iff the object represents the same CSS file as css if property masking is taken into account.
            E.g. s {p: 1; p: 2} has p: 1 masked so not counted.
            Requires prop_names to have been given.
        """

        edgeSet = set()
        pnEdgeSet = set()

        for (ss, pp) in reversed(self.cliques):
            for s in ss:
                for p in reversed(pp):
                    pn = self.prop_names[p]
                    if (s, pn) not in pnEdgeSet:
                        pnEdgeSet.add((s, pn))
                        edgeSet.add(Sim.simpleRule(s, p))

        simple_trcl = css.getTrClEdgeOrder()
        simple_masked = { r1
                          for (r1, r2) in css.getTrClEdgeOrder()
                          if ((r1.getSelector() == r2.getSelector())
                              and
                              (self.prop_names[r1.getProperty()] ==
                               self.prop_names[r2.getProperty()])) }

        cssEdgeSet = css.edgeSet - simple_masked

        if edgeSet != cssEdgeSet:
            if __DEBUG__:
                print 'There are ' + str(len(edgeSet)) +' edges in edgeSet'
                print 'There are ' + str(len(cssEdgeSet)) +\
                        ' edges in cssEdgeSet'
                print 'There are ' + str(len(edgeSet - cssEdgeSet)) +\
                        ' edges in edgeSet - cssEdgeSet'
                print 'There are ' + str(len(cssEdgeSet - edgeSet)) +\
                        ' edges in cssEdgeSet - edgeSet'
                print 'Edges missing from clique: ' +\
                        str(cssEdgeSet - edgeSet)
                print 'Edges missing from simple css: ' +\
                        str(edgeSet - cssEdgeSet)
            return False

        last_occurence = dict()
        i = 0
        lo_to_bucket = dict()
        j = 0
        for (ss, pp) in self.cliques:
            for p in pp:
                for s in ss:
                    e = Sim.simpleRule(s, p)
                    last_occurence[e] = i
                    lo_to_bucket[i] = j
                    i += 1
            j += 1

        for (e1, e2) in css.edgeOrder:
            if e1 in cssEdgeSet and e2 in cssEdgeSet:
                # TODO: fix so edges can be in same bucket as long as they can be
                # ordered
                if not last_occurence[e1] < last_occurence[e2]:
                    print "Edge ", e1, " last appears at property position", last_occurence[e1]
                    print "Edge ", e1, " last appears at bucket", \
                    lo_to_bucket[last_occurence[e1]]
                    print self.cliques[lo_to_bucket[last_occurence[e1]]]
                    print "Edge ", e2, " last appears at property position", last_occurence[e2]
                    print "Edge ", e2, " last appears at bucket", \
                    lo_to_bucket[last_occurence[e2]]
                    print self.cliques[lo_to_bucket[last_occurence[e2]]]
                    print "But the first should appear before the second!"
                    return False

        return True