def node_value_map_inv_sq(graph, rep):
    ''' Given a
        graph - reconciliation graph
        rep  - a reconciliation in event-set form
    returns a map from event nodes in the graph to their frequency over the
    inverse square of the distance of the reconciliations from the
    representative/template '''
    def weight(distance):
        # return 1 # Constant weight
        # return 0 if distance == 0 else 1 # Constant, but weights the perfect match as 0
        return 1 if distance == 0 else float(distance) ** -2.0 # Inverse Square
    counts = sparse_counts_n(graph, [rep])
    K = 0.0
    for n in graph.roots:
        for pt in counts[n].map:
            assert len(pt) == 1
            distance = pt[0]
            number_at_distance = counts[n].map[pt]
            K += weight(distance) * number_at_distance
    value_map = defaultdict(float)

    for n in graph.postorder():
        for pt in counts[n].map:
            assert len(pt) == 1
            distance = pt[0]
            number_at_distance = counts[n].map[pt]
            value_map[n] += number_at_distance * weight(distance)

    for n in value_map:
        value_map[n] = 2 * value_map[n] - K

    return value_map
def node_value_map_inv_sq(graph, rep):
    ''' Given a
        graph - reconciliation graph
        rep  - a reconciliation in event-set form
    returns a map from event nodes in the graph to their frequency over the
    inverse square of the distance of the reconciliations from the
    representative/template '''
    def weight(distance):
        # return 1 # Constant weight
        # return 0 if distance == 0 else 1 # Constant, but weights the perfect match as 0
        return 1 if distance == 0 else float(distance)**-2.0  # Inverse Square

    counts = sparse_counts_n(graph, [rep])
    K = 0.0
    for n in graph.roots:
        for pt in counts[n].map:
            assert len(pt) == 1
            distance = pt[0]
            number_at_distance = counts[n].map[pt]
            K += weight(distance) * number_at_distance
    value_map = defaultdict(float)

    for n in graph.postorder():
        for pt in counts[n].map:
            assert len(pt) == 1
            distance = pt[0]
            number_at_distance = counts[n].map[pt]
            value_map[n] += number_at_distance * weight(distance)

    for n in value_map:
        value_map[n] = 2 * value_map[n] - K

    return value_map
def reconciliations_at_each_distance_from_representatives(graph, reps):
    ''' Given a set of cluster representatives, computes a map for each
    representative, which sends distances to the number of reonciliations
    at that distance which are in the cluster of that representative'''
    counts = sparse_counts_n(graph, reps)
    distances = [defaultdict(float) for rep in reps]
    for n in graph.roots:
        for pt in counts[n].map:
            minDist = min(pt)
            number = counts[n].map[pt]
            closest_rep_i_s = [i for (i, d) in enumerate(pt) if d == minDist]
            for i in closest_rep_i_s:
                distances[i][minDist] += float(number) / len(closest_rep_i_s)
    return distances
def reconciliations_at_each_distance_from_representatives(graph, reps):
    ''' Given a set of cluster representatives, computes a map for each
    representative, which sends distances to the number of reonciliations
    at that distance which are in the cluster of that representative'''
    counts = sparse_counts_n(graph, reps)
    distances = [defaultdict(float) for rep in reps]
    for n in graph.roots:
        for pt in counts[n].map:
            minDist = min(pt)
            number = counts[n].map[pt]
            closest_rep_i_s = [i for (i, d) in enumerate(pt) if d == minDist]
            for i in closest_rep_i_s:
                distances[i][minDist] += float(number) / len(closest_rep_i_s)
    return distances
def node_value_maps_symmetric(graph, reps):
    ''' Given a
        graph - reconcilliation graph
        reps  - a list of reconciliations in event-set form
    returns a list of value maps (in the same order as the reps)

    where a value map is a mapping from a node in the reconciliation graph
      to a number (See the 'Computing Weighted Means' section of the paper)

    Sometimes reconciliations in the graph are equally close to multiple
    representatives. This function gives the reconciliation to the closest
    representative which occurs first in the `reps` list.
    '''
    counts = sparse_counts_n(graph, reps)
    Ks = [0 for rep in reps]
    for n in graph.roots:
        # Perhaps pt is (1, 4, 1, 9)
        for pt in counts[n].map:
            minDist = min(pt)
            number = counts[n].map[pt]
            # so closest_rep_i_s is [0, 2]
            closest_rep_i_s = [i for (i, d) in enumerate(pt) if d == minDist]
            # Given the reconciliation to the lowest-indexed closest rep.
            i = min(closest_rep_i_s)
            Ks[i] += float(number)

    value_maps = [defaultdict(float) for rep in reps]
    for n in (n for n in graph.postorder() if n.isEvent()):
        for pt in counts[n].map:
            minDist = min(pt)
            number = counts[n].map[pt]
            closest_rep_i_s = [i for (i, d) in enumerate(pt) if d == minDist]
            # Given the reconciliation to the lowest-indexed closest rep.
            i = min(closest_rep_i_s)
            value_maps[i][n] += float(number)
    for n in (n for n in graph.postorder() if n.isEvent()):
        for (value_map, K) in zip(value_maps, Ks):
            value_map[n] = 2 * value_map[n] - K

    if not abs(sum(Ks) - sum(counts[graph.roots[0]].map.values())) < 1:
        print >> sys.stderr, 'Reconciliation count by constant: %d' % abs(
            sum(Ks))
        print >> sys.stderr, 'Reconciliation count by roots   : %d' % sum(
            counts[graph.roots[0]].map.values())
        print >> sys.stderr, 'Should be equal'
        assert False
    return value_maps
def node_value_maps_symmetric(graph, reps):

    ''' Given a
        graph - reconcilliation graph
        reps  - a list of reconciliations in event-set form
    returns a list of value maps (in the same order as the reps)

    where a value map is a mapping from a node in the reconciliation graph
      to a number (See the 'Computing Weighted Means' section of the paper)

    Sometimes reconciliations in the graph are equally close to multiple
    representatives. This function gives the reconciliation to the closest
    representative which occurs first in the `reps` list.
    '''
    counts = sparse_counts_n(graph, reps)
    Ks = [0 for rep in reps]
    for n in graph.roots:
        # Perhaps pt is (1, 4, 1, 9)
        for pt in counts[n].map:
            minDist = min(pt)
            number = counts[n].map[pt]
            # so closest_rep_i_s is [0, 2]
            closest_rep_i_s = [i for (i, d) in enumerate(pt) if d == minDist]
            # Given the reconciliation to the lowest-indexed closest rep.
            i = min(closest_rep_i_s)
            Ks[i] += float(number)

    value_maps = [defaultdict(float) for rep in reps]
    for n in (n for n in graph.postorder() if n.isEvent()):
        for pt in counts[n].map:
            minDist = min(pt)
            number = counts[n].map[pt]
            closest_rep_i_s = [i for (i, d) in enumerate(pt) if d == minDist]
            # Given the reconciliation to the lowest-indexed closest rep.
            i = min(closest_rep_i_s)
            value_maps[i][n] += float(number)
    for n in (n for n in graph.postorder() if n.isEvent()):
        for (value_map,K) in zip(value_maps, Ks):
            value_map[n] = 2 * value_map[n] - K

    if not abs(sum(Ks) - sum(counts[graph.roots[0]].map.values())) < 1:
        print >> sys.stderr, 'Reconciliation count by constant: %d' % abs(sum(Ks))
        print >> sys.stderr, 'Reconciliation count by roots   : %d' % sum(counts[graph.roots[0]].map.values())
        print >> sys.stderr, 'Should be equal'
        assert False
    return value_maps