Esempio n. 1
0
def dijkstra_PQ(G, start, target):
    P = {start}  # Visited Nodes
    S = PriorityQueue()  # Nodes to visit
    D = {}  # Current SP to each node
    p = {}  # Current best parent for each node

    # Initialise D, p and S
    for n in G.nodes():
        if n == start:
            D[n] = 0
        else:
            if G.has_edge(start, n):
                D[n] = G[start][n]["weight"]
            else:
                D[n] = math.inf

            p[n] = start
            # S is updated with each node and the current SP to each node. The SP value is also
            # called the priority of that node
            S.add_task(n, D[n])

    # Begin Dijkstra search - The algorithm continues visiting nodes until the target node is
    # visited and processed
    alg_continue = True
    while alg_continue != False:
        # pop_task() removes and returns the lowest priority task
        u, Du = S.pop_task()
        if u in P: continue

        # Node is added to the list of seen nodes P
        P.add(u)

        # All neighbours of u, not already visited are now processed
        for v, Dv in S:
            if v in P: continue
            if G.has_edge(u, v):
                if D[v] > D[u] + G[u][v]["weight"]:
                    D[v] = D[u] + G[u][v]["weight"]
                    p[v] = u
                    S.add_task(v, D[v])

        # Stopping Criteria - If the target node has been added to P (i.e. processed)
        # then the algorithm stopping criteria is updated and the while loop terminates
        if target in P:
            alg_continue = False
        else:
            continue

    # Create Shortest Path
    next = target
    SP = deque([target])
    while next != start:
        for i, k in p.items():
            if i == next:
                SP.appendleft(k)
                next = k

    return list(SP)
Esempio n. 2
0
def a_star_tree_search(problem, heuristic_function):

    # Initiate return variables
    num_nodes_expanded = 0
    current_ply_depth = 0
    action_tree_edges = {}
    state_incrementer = 0

    # Initiate loop variables
    estimated_total_cost = 0  # Value is irrelevant for root node since always popped first
    cost_to_current_ply = 0
    parent_action = None
    queue = PriorityQueue()
    queue.add_task((problem.initial_state, state_incrementer, current_ply_depth, cost_to_current_ply, parent_action), estimated_total_cost)

    while not queue.is_empty():

        # Track the number of nodes expanded
        if num_nodes_expanded % 10000 == 0:
            print('Number of nodes expanded: ', num_nodes_expanded)
        num_nodes_expanded += 1

        # Get the next node to explore
        state, state_id, current_ply_depth, cost_to_current_ply, parent_action = queue.pop_task()

        # Test for the goal state, with admissible heuristic this is guaranteed to be the optimal solution
        if problem.goal_test_function(state):
            action_sequence = extract_action_sequence(action_edges=action_tree_edges, terminating_action=parent_action)

            return state, num_nodes_expanded, current_ply_depth, action_sequence

        else:

            # Expand the current nodes and add children to the queue
            for child_action in problem.get_applicable_actions(state):

                state_incrementer +=1
                child_state_id = state_incrementer

                # Store the action edge
                action_tree_edges[child_action] = parent_action

                # Generate the child state
                result = child_action.execute(state)
                child_state = result.state

                # Calculate the cost to this point
                cost_to_child_ply = cost_to_current_ply + result.cost
                estimated_total_cost = cost_to_child_ply + heuristic_function(child_state)

                # Insert next node into the queue
                child_ply_depth = current_ply_depth + 1
                queue.add_task((child_state, child_state_id, child_ply_depth, cost_to_child_ply, child_action), estimated_total_cost)

    # If no solution is found return None
    return None, num_nodes_expanded
Esempio n. 3
0
def find_ldag(G, v, theta, Ew) -> nx.DiGraph:
    '''
    有向非巡回グラフとなるような部分グラフを作る
    INPUT:
        G -- networkの 有向グラフ
        v -- 有向グラフのノード 
        theta -- 閾値θ
        Ew -- グラフG内のエッジ間の重要度
    OUTPUT:
        D -- 有向グラフとなるような部分グラフ(network DiGraph)
    '''

    Inf = PQ()
    Inf.add_task(v, -1)
    x, priority = Inf.pop_item()
    M = -priority
    X = [x]

    D = nx.DiGraph()
    while M >= theta:  # あるノードの影響度が閾値θを超えるまで繰り返す
        out_edges = G.out_edges(
            [x],
            data=True)  # 終点がノードxとなるエッジを求める[(hoge, x),(fuga, x), …()]のように求められる
        for (v1, v2, edata) in out_edges:
            if v2 in X:
                D.add_edge(
                    v1, v2, weight=edata['weight']
                )  # ノードxが有向非巡回グラフの中に含まれていないが,最も影響度が大きい場合は有向非巡回グラフに追加
        in_edges = G.in_edges(
            [x])  # 始点がノードxとなるエッジを求める[(x, hoge), (x, fuga), …]のように求められる.
        for (u, _) in in_edges:
            if u not in X:
                try:
                    [pr, _, _] = Inf.entry_finder[u]
                except KeyError:
                    pr = 0
                # ノードu,v間に複数のエッジがあることを想定し,エッジの数×重み = Inf(u,v) = Σ w(u,x)* Inf(x,v)としている.
                Inf.add_task(u, pr - G[u][x]['weight'] * Ew[(u, x)] * M)
        try:
            x, priority = Inf.pop_item()
        except KeyError:
            return D
        M = -priority
        X.append(x)  # ノードxを有向非巡回グラフのインフルエンサーとして追加

    return D
Esempio n. 4
0
def degreeDiscount(G, k):
    ''' 
    Finds initial set of nodes to propagate in Independent Cascade model (with priority queue)
    Input: G -- networkx graph object
    k -- number of nodes needed
    Output:
    S -- chosen k nodes
    '''
    S = []
    dd = PQ()  # degree discount
    t = dict()  # number of adjacent vertices that are in S
    d = dict()  # degree of each vertex
    p = dict()  # propagation probability in each user

    for u in G:
        p[u] = np.random.random()

    # initialize degree discount
    for u in G.nodes():
        d[u] = sum([G[u][v]['weight']
                    for v in G[u]])  # each edge adds degree 1
        # d[u] = len(G[u]) # each neighbor adds degree 1
        dd.add_task(u, -d[u])  # add degree of each node
        t[u] = 0

    # add vertices to S greedily
    for i in range(k):
        u, priority = dd.pop_item(
        )  # extract node with maximal degree discount
        S.append(u)
        for v in G[u]:
            if v not in S:
                t[v] += G[u][v][
                    'weight']  # increase number of selected neighbors
                priority = d[v] - 2 * t[v] - (
                    d[v] - t[v]) * t[v] * p[v]  # discount of degree
                dd.add_task(v, -priority)
    return S
def degreeDiscount(G, k, probability_fixed=True):
    """
    Input: 
    G: 無向 or 有向グラフ
    k: 求めたいインフルエンサーの数
    probability_fixed: 自分の友人に影響を与えることに成功する確率pを全ユーザー共通にするかどうか(True: 共通にする.False:しない)
    
    Output
    S: インフルエンサーの集合 |S| = k
    """
    S = []
    dd = PQ() # degree discount
    t = dict() # number of adjacent vertices that are in S
    d = dict() # degree of each vertex
    
    # initialize degree discount
    for u in G.nodes():
        d[u] = np.sum([G[u][v]['weight'] for v in G[u]]) # each edge adds degree 1
        dd.add_task(u, -d[u]) # add degree of each node
        t[u] = 0
    
    if probability_fixed:
        p = 0.01
        # add vertices to S greedily
        for i in range(k):
            u, priority = dd.pop_item() # extract node with maximal degree discount
            S.append(u)
            for v in G[u]:
                if v not in S:
                    t[v] += G[u][v]['weight'] # increase number of selected neighbors (t_v = t_v + 1)
                    priority = d[v] - 2*t[v] - (d[v] - t[v])*t[v]*p # discount of degree
                    dd.add_task(v, -priority)
        return S
    
    else:
        p = dict() # propagation probability in each user
        for u in G:
            p[u] = np.random.uniform(0, 1)

        # add vertices to S greedily
        for i in range(k):
            u, priority = dd.pop_item() # extract node with maximal degree discount
            S.append(u)
            for v in G[u]:
                if v not in S:
                    t[v] += G[u][v]['weight'] # increase number of selected neighbors
                    priority = d[v] - 2*t[v] - (d[v] - t[v])*t[v]*p[v]  # discount of degree
                    dd.add_task(v, -priority)
        return S
def bi_dijkstra_PQ(G, start, target):
    # All the same data structures are used, except now there are structures for both the
    # forward and backward directions
    P_f = {start}
    P_b = {target}
    S_f = PriorityQueue()
    S_b = PriorityQueue()
    D_f = {}
    D_b = {}
    p_f = {}
    p_b = {}

    # Forward Initialisation
    for n in G.nodes():
        if n == start:
            D_f[n] = 0
        else:
            if G.has_edge(start, n):
                D_f[n] = G[start][n]["weight"]
            else:
                D_f[n] = math.inf

            p_f[n] = start
            S_f.add_task(n, D_f[n])

    # Backward Initialisation
    for n in G.nodes():
        if n == target:
            D_b[n] = 0
        else:
            if G.has_edge(target, n):
                D_b[n] = G[target][n]["weight"]
            else:
                D_b[n] = math.inf

            p_b[n] = target
            S_b.add_task(n, D_b[n])

    alg_continue = True
    while alg_continue != False:
        # Forward
        # pop_task() removes and returns the lowest priority task
        u, Du = S_f.pop_task()
        if u in P_f: continue

        P_f.add(u)

        for v, Dv in S_f:
            if v in P_f: continue
            if G.has_edge(u, v):
                if D_f[v] > D_f[u] + G[u][v]["weight"]:
                    D_f[v] = D_f[u] + G[u][v]["weight"]
                    p_f[v] = u
                    S_f.add_task(v, D_f[v])

        if u in P_b:
            alg_continue = False
            w = u
            continue
        else:
            pass

        # Backward
        # pop_task() removes and returns the lowest priority task
        u, Du = S_b.pop_task()
        if u in P_b: continue

        P_b.add(u)

        for v, Dv in S_b:
            if v in P_b: continue
            if G.has_edge(u, v):
                if D_b[v] > D_b[u] + G[u][v]["weight"]:
                    D_b[v] = D_b[u] + G[u][v]["weight"]
                    p_b[v] = u
                    S_b.add_task(v, D_b[v])

        if u in P_f:
            alg_continue = False
            w = u
            continue
        else:
            pass

    # The SP at the visited node is calculated
    min_dist = D_f[w] + D_b[w]

    # All nodes are now visited in both the forward and backward direction
    # The distance to these numbers in both directions are added and compared with the minimum
    # distance to the stopping node. If the new distance is smaller, the node is on the SP
    SP_node = w
    for i in G.nodes():
        if D_f[i] + D_b[i] < min_dist:
            min_dist = D_f[i] + D_b[i]
            SP_node = i
            SP = deque()
        else:
            SP = deque([SP_node])

    # The shortest path is created by going through all parent nodes from the min distance connection
    # node in both the forward and backward direction
    next = SP_node
    while next != start:
        for i, k in p_f.items():
            if i == next:
                SP.appendleft(k)
                next = k

    next = SP_node
    while next != target:
        for i, k in p_b.items():
            if i == next:
                SP.append(k)
                next = k

    return list(SP)
Esempio n. 7
0
def LDAG_heuristic(G, Ew, k, theta):
    ''' 
    LDAG algorithm for seed selection.
    Input:
    G -- directed graph (nx.DiGraph)
    Ew -- inlfuence weights of edges (eg. uniform, random) (dict)
    k -- size of seed set (int)
    t -- parameter theta for finding LDAG (0 <= t <= 1; typical value: 1/320) (int)
    Output:
    S -- seed set (list)
    '''
    # define variables
    S = []
    IncInf = PQ()
    for node in G:
        IncInf.add_task(node, 0)

    LDAGs = dict()
    InfSet = dict()
    ap = dict()
    A = dict()

    for v in G:
        LDAGs[v] = find_ldag(G, v, theta, Ew)
        # update influence set for each node in LDAGs[v] with its root
        for u in LDAGs[v]:
            InfSet.setdefault(u, []).append(v)
        alpha = computeAlpha(LDAGs[v], Ew, S, v)
        A.update(alpha)  # add new linear coefficients to A
        # update incremental influence of all nodes in LDAGs[v] with alphas
        for u in LDAGs[v]:
            ap[(
                v, u
            )] = 0  # additionally set initial activation probability (line 7)
            priority, _, _ = IncInf.entry_finder[
                u]  # find previous value of IncInf
            IncInf.add_task(u, priority - A[(v, u)])  # and add alpha

    for it in range(k):
        s, priority = IncInf.pop_item(
        )  # 活性化させたノード数の多かったインフルエンサーs(α_v(u)の総和が最も多くなるようなノードv)を求める
        for v in InfSet[s]:  # インフルエンサーsによって活性化したノードv
            if v not in S:  # ノードvがインフルエンサーの集合Sに存在しなければ
                # ノードvを前処理で求めたグラフの中に入れて,係数を更新
                D = LDAGs[v]
                alpha_v_s = A[(v, s)]
                dA = computeAlpha(D, Ew, S, s, val=-alpha_v_s)
                for (s, u) in dA:
                    if u not in S + [
                            s
                    ]:  # don't update IncInf if it's already in S
                        A[(v, u)] += dA[(s, u)]
                        priority, _, _ = IncInf.entry_finder[
                            u]  # find previous value of incremental influence of u
                        IncInf.add_task(
                            u, priority - dA[(s, u)] *
                            (1 - ap[(v, u)]))  # and update it accordingly
                # update ap_v_u for all u reachable from s in D
                dap = computeActProb(D, Ew, S + [s], s, val=1 - ap[(v, s)])
                for (s, u) in dap:  # ノードのsがノードuに影響を及ぼす確率dapに対して
                    if u not in S + [s]:  # ノードuがインフルエンサーでなければ
                        ap[(v, u)] += dap[(s, u)]
                        priority, _, _ = IncInf.entry_finder[
                            u]  # find previous value of incremental influence of u
                        IncInf.add_task(
                            u, priority + A[(v, u)] *
                            dap[(s, u)])  # and update it accordingly
        S.append(s)
    return S