'''
Created on Mar 11, 2016

@author: cesar
'''

from scipy.special import comb
import operator

#===============================================================================
# Simple Stats
#===============================================================================

def nodesInTuples(setOfTuples):
    """
    Show which nodes appear
    """
    nodesList = []
    for tupl in setOfTuples:
        nodesList.extend(tupl)
    return list(set(nodesList))
#===============================================================================
#  NODES WHICH COOCCUR WITH NODE STATS
#===============================================================================

def cooccuranceBlock(ntupleSet,nodeList):
    """
    Obtains how many different nodes coocuurs as well who coocuur
    this is the main object required for the learning
    """
    nodesPerNode = dict(zip(nodeList,[[] for n in range(len(nodeList))]))
    for ntuple in ntupleSet:
        for nodeInTuple in ntuple:
            nodesPerNode[nodeInTuple].extend(ntuple)
    
    for a,v in nodesPerNode.iteritems():
        differentNodes = set(v).difference(set([a]))
        NumberdifferentNodes = len(differentNodes) 
        nodesPerNode[a] = (NumberdifferentNodes,differentNodes)
    
    return sorted(nodesPerNode.iteritems(),key=operator.itemgetter(1))

def differentNodesForNode(ntupleSet,nodeList,verbose=False):
    """
    For each node obtain the different tuples in which he participates
    
    Parameter:
    ----------
    
    Return:
    -------
    nodesPerNodes dict with the sets of nodes with which the node occurs
    """
    nodesPerNode = dict(zip(nodeList,[[] for n in range(len(nodeList))]))
    for ntuple in ntupleSet:
        for nodeInTuple in ntuple:
            nodesPerNode[nodeInTuple].extend(ntuple)
    
    for a,v in nodesPerNode.iteritems():
        nodesPerNode[a] = set(v)
    
    return nodesPerNode

def numberDifferentNodesForNode(ntupleSet,nodeList,differentNodesPN=None,verbose=False):
    """
    For each node obtain the number of different tuples in which he participates
    
    Parameter:
    ----------
    Return:
    -------
    nNodesPerNode: dict with the number of nodes with which the node co-occurs
    """
    if(differentNodesPN == None):
        differentNodesPN = differentNodesForNode(ntupleSet,nodeList)
    
    numberOfNodesPerNode = {}
    for node, nTupleSet in differentNodesPN.iteritems():
        numberOfNodesPerNode[node] = len(nTupleSet)
        if verbose:
            print "Node {0} has {1} n nodes".format(node,len(nTupleSet)) 
    
    return numberOfNodesPerNode


#===============================================================================
#  TUPLES STATS
#===============================================================================

def differentNTuplesForNode(ntupleSet,nodeList,verbose=False):
    """
    For each node obtain the different tuples in which he participates
    
    Parameter:
    ----------
    
    Return:
    -------
    ntuplesPerNode: dict with the sets of ntuples in which each node occurs
    """
    ntuplesPerNode = dict(zip(nodeList,[[] for n in range(len(nodeList))]))
    for ntuple in ntupleSet:
        ntuple.sort()
        joinedTuple = "".join(ntuple)
        for nodeInTuple in ntuple:
            ntuplesPerNode[nodeInTuple].append(joinedTuple)
    
    for a,v in ntuplesPerNode.iteritems():
        ntuplesPerNode[a] = set(v)
    
    return ntuplesPerNode

def numberDifferentNTuplesForNode(ntupleSet,nodeList,ntuplesPerNode=None,verbose=False):
    """
    
    Parameters:
    ----------
    nTupleSet: list of tuples
    nodeList: list of nodes names
    ntuplesPerNode: dict with the sets of ntuples in which each node occurs
    
    Returns:
    --------
    numberOfnTuplesPerNode: dict of number of different tuples per node
    """
    if(ntuplesPerNode == None):
        ntuplesPerNode = differentNTuplesForNode(ntupleSet,nodeList)
    
    numberOfnTuplesPerNode = {}
    for node, nTupleSet in ntuplesPerNode.iteritems():
        numberOfnTuplesPerNode[node] = len(nTupleSet)
        if verbose:
            print "Node {0} has {1} nTuples".format(node,len(nTupleSet)) 
    
    return numberOfnTuplesPerNode

    
def possibleTuples(nDifferentNodes):
    """
    Calculates the possible number of tuples for a given set of
    
    Parameters:
    ----------
    nDifferentNodes: dictionary with the number of different nodes observed along this node
    
    Returns:
    -------
    numberOfPossibleTuples: dict 
    """
    numberOfPossibleTuples = {}
    for nodeName, numberOfDifferent in nDifferentNodes.iteritems():
        numberOfPossibleTuples[nodeName] = sum([comb(numberOfDifferent,i,exact=True)for i in range(0,4)])
    return numberOfPossibleTuples



def nodesToTuplesRatio(tuples,nodesList):
    """
    """
    nDifferentNTuples =   numberDifferentNTuplesForNode(tuples,nodesList)
    nDifferentNodes = numberDifferentNodesForNode(tuples,nodesList)
    return None
a3fa924449ad2c6ae66eadae47355900c7910465
'''
Created on Mar 11, 2016

@author: cesar
'''

from scipy.special import comb
import operator

#===============================================================================
# Simple Stats
#===============================================================================

def nodesInTuples(setOfTuples):
    """
    Show which nodes appear
    """
    nodesList = []
    for tupl in setOfTuples:
        nodesList.extend(tupl)
    return list(set(nodesList))
#===============================================================================
#  NODES WHICH COOCCUR WITH NODE STATS
#===============================================================================

def cooccuranceBlock(ntupleSet,nodeList):
    """
    Obtains how many different nodes coocuurs as well who coocuur
    this is the main object required for the learning
    """
    nodesPerNode = dict(zip(nodeList,[[] for n in range(len(nodeList))]))
    for ntuple in ntupleSet:
        for nodeInTuple in ntuple:
            nodesPerNode[nodeInTuple].extend(ntuple)
    
    for a,v in nodesPerNode.iteritems():
        differentNodes = set(v).difference(set([a]))
        NumberdifferentNodes = len(differentNodes) 
        nodesPerNode[a] = (NumberdifferentNodes,differentNodes)
    
    return sorted(nodesPerNode.iteritems(),key=operator.itemgetter(1))

def differentNodesForNode(ntupleSet,nodeList,verbose=False):
    """
    For each node obtain the different tuples in which he participates
    
    Parameter:
    ----------
    
    Return:
    -------
    nodesPerNodes dict with the sets of nodes with which the node occurs
    """
    nodesPerNode = dict(zip(nodeList,[[] for n in range(len(nodeList))]))
    for ntuple in ntupleSet:
        for nodeInTuple in ntuple:
            nodesPerNode[nodeInTuple].extend(ntuple)
    
    for a,v in nodesPerNode.iteritems():
        nodesPerNode[a] = set(v)
    
    return nodesPerNode

def numberDifferentNodesForNode(ntupleSet,nodeList,differentNodesPN=None,verbose=False):
    """
    For each node obtain the number of different tuples in which he participates
    
    Parameter:
    ----------
    Return:
    -------
    nNodesPerNode: dict with the number of nodes with which the node co-occurs
    """
    if(differentNodesPN == None):
        differentNodesPN = differentNodesForNode(ntupleSet,nodeList)
    
    numberOfNodesPerNode = {}
    for node, nTupleSet in differentNodesPN.iteritems():
        numberOfNodesPerNode[node] = len(nTupleSet)
        if verbose:
            print "Node {0} has {1} n nodes".format(node,len(nTupleSet)) 
    
    return numberOfNodesPerNode


#===============================================================================
#  TUPLES STATS
#===============================================================================

def differentNTuplesForNode(ntupleSet,nodeList,verbose=False):
    """
    For each node obtain the different tuples in which he participates
    
    Parameter:
    ----------
    
    Return:
    -------
    ntuplesPerNode: dict with the sets of ntuples in which each node occurs
    """
    ntuplesPerNode = dict(zip(nodeList,[[] for n in range(len(nodeList))]))
    for ntuple in ntupleSet:
        ntuple.sort()
        joinedTuple = "".join(ntuple)
        for nodeInTuple in ntuple:
            ntuplesPerNode[nodeInTuple].append(joinedTuple)
    
    for a,v in ntuplesPerNode.iteritems():
        ntuplesPerNode[a] = set(v)
    
    return ntuplesPerNode

def numberDifferentNTuplesForNode(ntupleSet,nodeList,ntuplesPerNode=None,verbose=False):
    """
    
    Parameters:
    ----------
    nTupleSet: list of tuples
    nodeList: list of nodes names
    ntuplesPerNode: dict with the sets of ntuples in which each node occurs
    
    Returns:
    --------
    numberOfnTuplesPerNode: dict of number of different tuples per node
    """
    if(ntuplesPerNode == None):
        ntuplesPerNode = differentNTuplesForNode(ntupleSet,nodeList)
    
    numberOfnTuplesPerNode = {}
    for node, nTupleSet in ntuplesPerNode.iteritems():
        numberOfnTuplesPerNode[node] = len(nTupleSet)
        if verbose:
            print "Node {0} has {1} nTuples".format(node,len(nTupleSet)) 
    
    return numberOfnTuplesPerNode

    
def possibleTuples(nDifferentNodes):
    """
    Calculates the possible number of tuples for a given set of
    
    Parameters:
    ----------
    nDifferentNodes: dictionary with the number of different nodes observed along this node
    
    Returns:
    -------
    numberOfPossibleTuples: dict 
    """
    numberOfPossibleTuples = {}
    for nodeName, numberOfDifferent in nDifferentNodes.iteritems():
        numberOfPossibleTuples[nodeName] = sum([comb(numberOfDifferent,i,exact=True)for i in range(0,4)])
    return numberOfPossibleTuples



def nodesToTuplesRatio(tuples,nodesList):
    """
    """
    nDifferentNTuples =   numberDifferentNTuplesForNode(tuples,nodesList)
    nDifferentNodes = numberDifferentNodesForNode(tuples,nodesList)
    return None