def generate_vhash_graph(nodes):
    locs = {}
    revlocs = {}
    overlay = networkx.DiGraph()
    overlay.add_nodes_from(nodes)
    for n in nodes:
        locs[n] = vhash.randPoint()
        revlocs[locs[n]] = n
    close_peers = {}
    far_peers = {}
    for n in nodes:
        others = nodes[:]
        others.remove(n)
        close_peers[n] = []
        for ploc in vhash.getShell(locs[n],map(lambda x: locs[x],others)):
            close_peers[n].append(revlocs[ploc])
    for n in nodes:
        far_peers[n] = []
    for n in nodes:
        for p in close_peers[n]:
            for p2 in close_peers[n]:
                if p2 not in far_peers[p] and p2 != p:
                    far_peers[p].append(p2)
    for n in nodes:
        for p in close_peers[n]:
            overlay.add_edge(n,p)
        for p in far_peers[n]:
            overlay.add_edge(n,p)
    return overlay
def generate_optimized_vhash_graph(nodes,real,gens):
    locs = {}
    revlocs = {}
    overlay = networkx.DiGraph()
    overlay.add_nodes_from(nodes)
    for n in nodes:
        locs[n] = vhash.randPoint()
        revlocs[locs[n]] = n
    close_peers = {}
    far_peers = {}
    for i in range(0,gens):
        close_peers = {}
        far_peers = {}
        for n in nodes:
            others = nodes[:]
            others.remove(n)
            close_peers[n] = []
            for ploc in vhash.getShell(locs[n],map(lambda x: locs[x],others)):
                close_peers[n].append(revlocs[ploc])
        for n in nodes:
            far_peers[n] = []
        for n in nodes:
            for p in close_peers[n]:
                for p2 in close_peers[n]:
                    if p2 not in far_peers[p] and p2 != p:
                        far_peers[p].append(p2)
        for n in nodes:
            weighted_vectors = []
            weight_sum = 0.0
            for p in close_peers[n]:
                latency = float(underlay.hops(real,n,p))
                delta_vec = map(lambda x,y: min([y-x,vhash.space_size-(y-x)])/latency, locs[p], locs[n])
                weight_sum+=latency**-1.0
                weighted_vectors.append(delta_vec)
            delta_vec = map(lambda x: x/weight_sum, reduce(vhash.vec_sum, weighted_vectors))
            del revlocs[locs[n]]
            locs[n] = tuple(vhash.vec_sum(locs[n],delta_vec))
            revlocs[locs[n]] = n
    for n in nodes:
        for p in close_peers[n]:
            overlay.add_edge(n,p)
        for p in far_peers[n]:
            overlay.add_edge(n,p)
    return overlay
                theta = math.acos(cos_theta)
                dist = ((0.5*magnitude(AB))**2.0 + (0.5*magnitude(AB)*math.tan(theta))**2.0)**0.5
                distances.append(dist)
        return min(distances)


def approx_volume(center, points):
        radii = []
        for i in range(0,1000):
                unit = randSample([0.0]*d)
                radii.append(calc_radius(center, points, unit))
        return sum(radii)/float(len(radii))

def get_delunay_peers(center, points):
        points = sorted(points,key=lambda x: dist(center,x))
        peers = [points.pop(0)]
        vol = approx_volume(center, peers)
        for p in points:
                tmp_vol = approx_volume(center, peers+[p])
                if tmp_vol < vol:
                        vol = tmp_vol
                        peers.append(p)
        return peers
if __name__ == '__main__':
    points = []
    center = [0.0]*d
    for i in range(0,20):
        points.append(randPoint())
        #print points
        print i,len(get_delunay_peers(center,points)),len(vhash_greedy.getShell(center,points))
def generate_optimized_vhash_graph(nodes,real,gens,d):
    min_short_peers = 3*d+1
    max_long_peers = min_short_peers*min_short_peers

    locs = {}
    revlocs = {}
    overlay = networkx.DiGraph()
    overlay.add_nodes_from(nodes)
    for n in nodes:
        locs[n] = vhash.randPoint()
        revlocs[locs[n]] = n
    close_peers = {}
    far_peers = {}
    for i in range(0,gens):
        close_peers = {}
        far_peers = {}
        for n in nodes:
            others = nodes[:]
            others.remove(n)
            close_peers[n] = []
            for ploc in vhash.getShell(locs[n],map(lambda x: locs[x],others)):
                close_peers[n].append(revlocs[ploc])

            if len(close_peers[n]) < min_short_peers:
                for p in sorted(others,key = lambda x: vhash.dist(locs[n],locs[x])):
                    if p in close_peers[n]:
                        continue
                    close_peers[n].append(p)
                    if len(close_peers[n]) >= min_short_peers:
                        break

        for n in nodes:
            far_peers[n] = []
        for n in nodes:
            for p in close_peers[n]:
                for p2 in close_peers[p]:
                    if p2 not in far_peers[n] and p2 != n:
                        far_peers[n].append(p2)
            if len(far_peers[n]) > max_long_peers:
                far_peers[n] = random.sample(far_peers[n],max_long_peers)

        for n in nodes:
            unit_distance_per_hop = sum([vhash.dist(locs[n], locs[x]) for x in close_peers[n]])
            unit_distance_per_hop /=sum([ float(underlay.hops(real,n,x)) for x in close_peers[n]])
            zero = [0.0]*len(locs[n])
            error_vector = zero[:]
            for p in close_peers[n]:
                latency = float(underlay.hops(real,n,p))
                ideal_length = latency*unit_distance_per_hop
                delta_vec = map(lambda x,y: min([y-x,vhash.space_size-(y-x)]), locs[p], locs[n])
                delta_dist = vhash.dist(zero,delta_vec)
                error_dist = 1.0+ideal_length-delta_dist
                error_delta = map(lambda x: error_dist*x/delta_dist,delta_vec)
                error_vector = vhash.vec_sum(error_vector, error_delta)
            del revlocs[locs[n]]
            locs[n] = tuple(vhash.vec_sum(locs[n],error_vector))
            revlocs[locs[n]] = n

    for n in nodes:
        for p in close_peers[n]:
            overlay.add_edge(n,p)
        for p in far_peers[n]:
            overlay.add_edge(n,p)

    if render_overlay_plot:
        xs = [locs[x][0] for x in nodes]
        ys = [locs[x][1] for x in nodes]
        plt.scatter(xs,ys)
        plt.show()


    return overlay