<commit_before>"""
Graph for reasons of pgraph solution 
"""

__author__ = "<NAME>"
__date__ = "2013-06-28"

import sys
import Queue
from mybuild.pgraph import *

class NodeContainer(object):
    def __init__(self, literals):
        self.literals = literals 
        self.containers = set() #NodeContainrs set that contains nodes with current node as member 
        self.members = set() #Node set of nodes with one literal from node.literals
        self.consequences = {} #key = node, value = reason
        self.reasons = {} #key = node, value = reason
        self.length = float("+inf")
        self.parent = None
        
    def __lt__(self, other):
        return self.length < other.length
    
    def compare_literals(self, literals):
        return (set(literals) == self.literals)

class Rgraph(object): 
    """
    Rgraph or Reason graph
    """  
    def __init__(self, literals, reasons):
        self.initial = NodeContainer(set())  
        self.nodes = set()   
        self.nodes.add(self.initial)
        
        for literal in literals:
            self.nodes.add(NodeContainer(self.literal_to_set(literal)))
                
        for reason in reasons:
            self.fill_data(reason)
            
    def literal_to_set(self, literal):
        s = set()
        s.add(literal)
        return s
                
    def update_containers(self, node):
        for literal in node.literals:
            member = self.get_node_by_literals(self.literal_to_set(literal))
            node.members.add(member)
            member.containers.add(node)
        
    def get_node_by_literals(self, literals): 
        for n in self.nodes:
            if n.compare_literals(literals):
                return n                      
            
    def fill_data(self, reason): 
        if len(reason.cause_literals) > 1:
            s = set(reason.cause_literals)
            self.nodes.add(NodeContainer(s))
            self.update_containers(self.get_node_by_literals(s))
                      
        cause_node = self.get_node_by_literals(reason.cause_literals)
        literal_node = self.get_node_by_literals(self.literal_to_set(reason.literal))
        
        cause_node.consequences[literal_node] = reason
        literal_node.reasons[cause_node] = reason
    
    def print_graph(self):
        """
        Simple way to print reason graph. Nodes of more one reason are printed in new line without offset.
        """
        queue = Queue.LifoQueue()
        used = set()
        
        #queue contains touples (node, reason)
        for node in self.initial.consequences:
            queue.put((node, self.initial.consequences[node]))
        
        while not queue.empty():
            node = queue.get()        
            self.dfs(node[0], node[1], used, queue, 0)
                
    def dfs(self, node, reason, used, queue, depth):
        if node in used:
            self.print_reason(reason,depth)
            return
        
        used.add(node)
        self.print_reason(reason,depth)
        for cons in node.consequences:
            self.dfs(cons, node.consequences[cons], used, queue, depth + 1)
            for container in cons.containers:
                if container not in used:
                    used.add(container)
                    for ccons in container.consequences:
                        if cons not in queue.queue:
                            queue.put((ccons, container.consequences[ccons]))
                            
    def print_reason(self, reason, depth):
        print self.get_offset(depth), reason.why(reason, reason.literal, reason.cause_literals)
    
    def get_offset(self, depth):
        st = ''  
        for i in range(0, depth) :
            st = st + '  '  
        return st
               
    def find_shortest_ways(self):
        """
        This algorithm a common Dijkstra's algorithm with small modification,
        length of node of more one reason is computed as sum of it's reasons.
        After function applying each node contains field length, the length of 
        the shortest way to the initial nodes. Parent is the previous node in 
        the shortest way.
        """ <commit_msg>some refactoring, nodes is dictionary now<commit_after>"""
Graph for reasons of pgraph solution 
"""

__author__ = "<NAME>"
__date__ = "2013-06-28"

import sys
import Queue
from mybuild.pgraph import *

class NodeContainer(object):
    def __init__(self, literals):
        self.literals = frozenset(literals) 
        self.containers = set() #NodeContainrs set that contains nodes with current node as member 
        self.members = set() #Node set of nodes with one literal from node.literals
        self.consequences = {} #key = node, value = reason
        self.reasons = {} #key = node, value = reason
        self.length = float("+inf")
        self.parent = None
        
    def __lt__(self, other):
        return self.length < other.length
    
    def compare_literals(self, literals):
        return (set(literals) == self.literals)

class Rgraph(object): 
    """
    Rgraph or Reason graph
    """  
    def __init__(self, literals, reasons):
        self.initial = NodeContainer(set())  
        self.nodes = {}    
        self.nodes[frozenset(set())] = self.initial
        
        for literal in literals:
            self.nodes[frozenset([literal])] = NodeContainer(frozenset([literal]))
                
        for reason in reasons:
            self.fill_data(reason)              
            
    def fill_data(self, reason): 
        if len(reason.cause_literals) > 1:
            s = frozenset(reason.cause_literals)
            self.nodes[s] = NodeContainer(s)
            self.update_containers(self.nodes[s])
                     
        cause_node = self.nodes[frozenset(reason.cause_literals)]
        literal_node = self.nodes[frozenset([reason.literal])]
        
        cause_node.consequences[literal_node] = reason
        literal_node.reasons[cause_node] = reason
        
    def update_containers(self, node):
        for literal in node.literals:
            member = self.nodes[frozenset([literal])]
            node.members.add(member)
            member.containers.add(node)  
    
    def print_graph(self):
        """
        Simple way to print reason graph. Nodes of more one reason are printed in new line without offset.
        """
        queue = Queue.LifoQueue()
        used = set()
        
        #queue contains touples (node, reason)
        for node in self.initial.consequences:
            queue.put((node, self.initial.consequences[node]))
        
        while not queue.empty():
            node, reason = queue.get()        
            self.dfs(node, reason, used, queue, 0)
                
    def dfs(self, node, reason, used, queue, depth):
        if node in used:
            self.print_reason(reason,depth)
            return
        
        used.add(node)
        self.print_reason(reason,depth)
        for cons in node.consequences:
            self.dfs(cons, node.consequences[cons], used, queue, depth + 1)
            for container in cons.containers:
                if container not in used:
                    used.add(container)
                    for ccons in container.consequences:
                        if cons not in queue.queue:
                            queue.put((ccons, container.consequences[ccons]))
                            
    def print_reason(self, reason, depth):
        print '  ' * depth, reason.why(reason, reason.literal, reason.cause_literals)
               
    def find_shortest_ways(self):
        """
        This algorithm a common Dijkstra's algorithm with small modification,
        length of node of more one reason is computed as sum of it's reasons.
        After function applying each node contains field length, the length of 
        the shortest way to the initial nodes. Parent is the previous node in 
        the shortest way.
        """ 
{'fraction_non_alphanumeric': 0.08920070157855174, 'fraction_numerical': 0.003132047105988474, 'mean_word_length': 1.8819494584837546, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3901630', 'n_tokens_mistral': 2239, 'n_tokens_neox': 2153, 'n_words': 600}