Exemple #1
0
 def __init__(self, nodes):
     self.cid = 0
     self.judge = Judge(nodes)
     edges = self.judge.get_conflicts()
     self.dotgraph = nx.DiGraph()
     self.graph_container = Gexf("Nico Rotstein", 
         "Arguiew (reviews as argumentation) graph")
     self.dotnodes = {}
     self.has_compressed = {}
     self.warranted = set([])
     self.redundant = {}
     for n in nodes:
         if n.attributes != []:
             self.dotgraph.add_node(n.id, shape="record", 
                 label=n.get_label())
             self.dotnodes[n.id] = n
     for (n1, n2) in edges:
         if self.judge.equivalent(n1, n2):
             self.dotgraph.add_edge(n1.id, n2.id, color="red", dir="both", 
                 label=n1.get_conf_label(n2))
             self.dotgraph.add_edge(n2.id, n1.id, color="transparent")
         else:
             (better, worse) = self.judge.get_better_review(n1, n2)
             self.dotgraph.add_edge(better.id, worse.id, 
                 label=better.get_conf_label(worse))
     self.prettyGraph()
Exemple #2
0
class Grapher:
    """
    handles all things related to graph handling
    it keeps the graph and 
    a dictionary of nodes whose key is the node id 
    and the value is the node itself
    """

    def __init__(self, nodes):
        self.cid = 0
        self.judge = Judge(nodes)
        edges = self.judge.get_conflicts()
        self.dotgraph = nx.DiGraph()
        self.graph_container = Gexf("Nico Rotstein", "Arguiew (reviews as argumentation) graph")
        self.dotnodes = {}
        self.has_compressed = {}
        self.warranted = set([])
        for n in nodes:
            if n.attributes != []:
                self.dotgraph.add_node(n.id, shape="record", label=n.get_label())
                self.dotnodes[n.id] = n
        for (n1, n2) in edges:
            if self.judge.equivalent(n1, n2):
                self.dotgraph.add_edge(n1.id, n2.id, color="red", dir="both", label=n1.get_conf_label(n2))
                self.dotgraph.add_edge(n2.id, n1.id, color="transparent")
            else:
                (better, worse) = self.judge.get_better_review(n1, n2)
                self.dotgraph.add_edge(better.id, worse.id, label=better.get_conf_label(worse))
        self.prettyGraph()

    def get_container(self):
        graph = self.graph_container.addGraph("directed", "static", "Arguiew graph")
        attWarrant = graph.addNodeAttribute("warranted", "false", "boolean")
        attPosText = graph.addNodeAttribute("positive_text", "", "string")
        attNegText = graph.addNodeAttribute("negative_text", "", "string")
        attHasCompressed = graph.addNodeAttribute("has_compressed", "[]", "liststring")
        nodes = []
        for n in self.dotgraph.nodes():
            nodes.append(self.dotnodes[n])
        self.judge = Judge(nodes)
        edges = self.judge.get_conflicts()
        node_handlers = {}
        for n in nodes:
            i = graph.addNode(n.id, n.get_formatted_atts())
            node_handlers[n.id] = i
            i.addAttribute(attPosText, str(n.positive_text))
            i.addAttribute(attNegText, str(n.negative_text))
            if self.has_compressed != {}:
                i.addAttribute(attHasCompressed, str(list(self.has_compressed[n.id])))
        for (n1, n2) in edges:
            graph.addEdge(n1.id + "-" + n2.id, n1.id, n2.id, label=n1.get_conf_label(n2))
        for w in self.warranted:
            node_handlers[w].addAttribute(attWarrant, "true")
            node_handlers[w].setColor("20", "200", "20")
        return self.graph_container

    def get_dotgraph(self):
        return self.dotgraph

    def resolve_cycles(self):
        # capture all cycles
        cycles = nx.simple_cycles(self.dotgraph)
        # the kind of cycles we are interested in are either binary (eg, [1,2,1]) or
        # even-lengthed (eg, [0,1,2,0]) - here we capture the latter and flag them
        # as "blocked"- don't be fooled by the length of the list
        blocked = []
        for cycle in cycles:
            # if (len(cycle) % 2 == 0):
            blocked += cycle
        affected_by_cycles = []
        preds = {}
        succs = {}
        for cycle in cycles:
            # we store all predecessors of all cycles and compute all successors
            cycle_set = list(set(cycle))
            cycle_predecessors = tools.all_predecessors(self.dotgraph, cycle_set, [])
            cycle_predecessors = list(set(cycle_predecessors) - set(blocked))
            cycle_successors = tools.all_successors(self.dotgraph, cycle_set, [])
            preds[str(cycle)] = cycle_predecessors
            # whenever a cycle has no predecessors, it introduces undecidedness
            # hence we store all successors in a global list of nodes that are
            # "affected by cycles"
            if cycle_predecessors == []:
                affected_by_cycles += cycle_successors
        # those cycles that have no predecessors or that their predecessors
        # are affected by cycles that have no predecessors or... and so on and so forth
        out = []
        for cycle in cycles:
            if (preds[str(cycle)] == []) or (set(preds[str(cycle)]) & set(affected_by_cycles) == []):
                out += cycle
        if out != []:
            # print "out due to unforgiving cycles: ", out
            print len(out), "reviews were involved in improper cycling"
        for o in set(out):
            self.dotgraph.remove_node(o)

    def prettyGraph(self):
        self.remove_dupes()
        print "resolving cycles..."
        self.resolve_cycles()
        print "computing accepted reviews..."
        self.set_warranted()

    def compress(self):
        print "compressing graph..."
        self.compress()
        print "removing redundant reviews in compressed graph"
        self.remove_dupes()

    def remove_dupes(self):
        removals = []
        remaining_nodes = set(self.dotgraph.nodes())
        while remaining_nodes != set([]):
            n = remaining_nodes.pop()
            for n2 in remaining_nodes:
                if set(self.dotnodes[n2].attributes).issubset(set(self.dotnodes[n].attributes)):
                    removals.append(n2)
        if removals != []:
            if len(set(removals)) == 1:
                print "1 review was redundant"
            else:
                print len(set(removals)), "reviews were redundant"
        for r in set(removals):
            print "review " + r + " was redundant - should be attached to the review that stayed in!!!"
            self.dotgraph.remove_node(r)

    def set_warranted(self):
        undefeated = set([node for (node, x) in self.dotgraph.edges()]) - set(
            [node for (x, node) in self.dotgraph.edges()]
        )
        undefeated |= set([node for node in self.dotgraph.nodes() if nx.is_isolate(self.dotgraph, node)])
        warranted = undefeated | self.judge.grounded(undefeated, self.dotgraph, set([]), set([]))
        for w in warranted:
            self.dotgraph.add_node(w, style="filled", fillcolor="green")
        self.warranted = warranted
        print len(warranted), "reviews were accepted"

    def compress(self):
        first_stage = set([node for (node, x) in self.dotgraph.edges()]) - set(
            [node for (x, node) in self.dotgraph.edges()]
        )
        first_stage |= set([node for node in self.dotgraph.nodes() if nx.is_isolate(self.dotgraph, node)])
        defeat_stages = [first_stage] + self.stages(first_stage, first_stage)
        cs = []
        for stage in defeat_stages:
            cs += self.consistent_subsets(stage, self.warranted)
        compressed_dotnodes = {}
        has_compressed = {}
        compressed_warranted = set([])
        compressed_dotgraph = nx.DiGraph()
        for subset in cs:
            positive_feats = set([])
            negative_feats = set([])
            for i in subset:
                positive_feats |= set(self.dotnodes[i].get_positive_feats())
                negative_feats |= set(self.dotnodes[i].get_negative_feats())
                r = Review(
                    "c" + str(self.cid),
                    {"feats": list(positive_feats), "text": ""},
                    {"feats": list(negative_feats), "text": ""},
                )
            compressed_dotnodes[r.id] = r
            has_compressed[r.id] = subset
            self.cid += 1
            if subset.issubset(self.warranted):
                compressed_warranted.add(r.id)
                compressed_dotgraph.add_node(
                    r.id, style="filled", fillcolor="green", shape="record", label=str(r.subset_label(subset))
                )
            else:
                compressed_dotgraph.add_node(r.id, shape="record", label=str(r.subset_label(subset)))
        for id1, n1 in has_compressed.items():
            for id2, n2 in has_compressed.items():
                for i in n1:
                    for j in n2:
                        ri = self.dotnodes[i]
                        rj = self.dotnodes[j]
                        if (
                            ri.in_conflict(rj)
                            and not (id1, id2) in compressed_dotgraph.edges()
                            and not (id2, id1) in compressed_dotgraph.edges()
                        ):
                            compressed_dotgraph.add_edge(id1, id2, dir="none")
        self.warranted = compressed_warranted
        self.dotgraph = compressed_dotgraph
        self.dotnodes = compressed_dotnodes
        self.has_compressed = has_compressed

    def stages(self, fringe, so_far):
        next = set()
        for r in fringe:
            next = next | set(self.dotgraph.successors(r))
        next = next - so_far - fringe
        if next == set([]):
            return []
        else:
            return [next] + self.stages(next, so_far | fringe)

    def consistent_subsets(self, stage, warranted):
        elem = stage.pop()
        (incons, consis) = self.consistent_in_rest([elem], stage, warranted)
        if incons == set([]):
            return [consis]
        else:
            return [consis] + self.consistent_subsets(incons, warranted)

    def consistent_in_rest(self, elems, rest, warranted):
        if rest == set([]):
            return (set([]), set(elems))
        else:
            ss = set()
            ps = set()
            for elem in elems:
                ss |= set(self.dotgraph.successors(elem))
                ps |= set(self.dotgraph.predecessors(elem))
            next = rest.pop()
            if next in ss or next in ps or set(elems).issubset(warranted) and next not in warranted:
                (i, c) = self.consistent_in_rest(elems, rest, warranted)
                return (i | set([next]), c | set(elems))
            else:
                (i, c) = self.consistent_in_rest(elems + [next], rest, warranted)
                return (i, set(elems + [next]) | c)