Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 以优先可行顺序获得有向无环图的预处理器和后继器_Python_Search_Directed Acyclic Graphs - Fatal编程技术网

Python 以优先可行顺序获得有向无环图的预处理器和后继器

Python 以优先可行顺序获得有向无环图的预处理器和后继器,python,search,directed-acyclic-graphs,Python,Search,Directed Acyclic Graphs,对于一个给定的有向无环图G,只有已知的后继者,我试图找到任何可能的给定节点N的所有直接和间接的前继者和后继者。解的顺序应该是优先可行的,并且解本身应该包含N。一个节省资源的解决方案会很好,因为G的大小可能会急剧增加 例如: 对于N=8 [0, 3, 1, 4, 6, 7, 8, 11] 或 可能是可行的解决方案,但不是 [0, 3, 1, 6, 4, 7, 8, 11] 因为6是4的继承者 如上所示,可能存在几种解决方案。一个就足够了,但如果对于给定的N(如果存在多个解决方案),它并不总是

对于一个给定的有向无环图G,只有已知的后继者,我试图找到任何可能的给定节点N的所有直接和间接的前继者和后继者。解的顺序应该是优先可行的,并且解本身应该包含N。一个节省资源的解决方案会很好,因为G的大小可能会急剧增加

例如:

对于N=8

[0, 3, 1, 4, 6, 7, 8, 11]

可能是可行的解决方案,但不是

[0, 3, 1, 6, 4, 7, 8, 11]
因为6是4的继承者


如上所示,可能存在几种解决方案。一个就足够了,但如果对于给定的N(如果存在多个解决方案),它并不总是相同的,那就更好了。

以下是解决方案的摘要:

  • 对于给定的起点终点,以及特定值N,列出通过N的所有可能路径
  • 计算所有路径组合(直接和间接)的长度,并创建一个字典,其中长度,n和,是路径的索引
  • 合并给定N的路径,同时保持可行解的优先级

  • 细节 第一步 为了列出图形的所有路径,我使用了此解决方案,并进行了一些修改:

     G = {
        0: [1,2,3], 
        1: [4,5], 
        2: [9,10],
        3: [8],
        4: [6,7],
        5: [9,10],
        6: [8,9],
        7: [8],
        8: [11],
        9: [11],
        10: [11],
        11: [],
        }
    
    G2 = {k:set(v) for k,v in G.items()}
    
    def dfs_paths(graph, start, goal):
        stack = [(start, [start])]
        while stack:
            (vertex, path) = stack.pop()
            for next in graph[vertex] - set(path):
                if next == goal:
                    yield path + [next]
                else:
                    stack.append((next, path + [next]))
    
    def run_paths(graph, start, end, N = None):
        all_paths = dfs_paths(graph, start, end)
        if N == None : 
            return([x for x in all_paths])
        else:
            return([x for x in all_paths if (N in x)])
    
    请注意,在
    运行路径(…)
    中,如果指定了
    N
    ,函数将返回仅包含N的路径

    print(run_paths(G2, 0,11))
    [[0, 3, 8, 11], [0, 2, 10, 11], [0, 2, 9, 11], [0, 1, 5, 10, 11], [0, 1, 5, 9, 11], [0, 1, 4, 7, 8, 11], 
    
    print(run_paths(G2, 0,11, 8))
    [[0, 3, 8, 11], [0, 1, 4, 7, 8, 11], [0, 1, 4, 6, 8, 11]]
    
    步骤2 使用中描述的成对函数,我们可以生成所有路径组合索引并计算它们的路径。当计算直接和间接路径时,
    set()
    函数将消除重复。最后,创建一个字典,其中键是数组的长度,值是相关路径索引的列表

    from itertools import *
    def get_size_dict( list_of_sols ):
        def powerset(iterable):
            s = list(iterable)
            return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
    
        comb_of_indexs = powerset(range(len(list_of_sols))) # return a comb of indicies
        d = {}
        for indexs in comb_of_indexs:
    
            myset = set([x for index in indexs for x in list_of_sols[index]])
            set_length = len(myset)
            if set_length not in d.keys():
                d[set_length] = []
    
            d[set_length].append(indexs)
    
        return(d)
    
    对于我们的示例,给定步骤1的输出,函数将返回以下字典

    {0: [()], 4: [(0,)], 6: [(1,), (2,)], 7: [(0, 1), (0, 2), (1, 2)], 8: [(0, 1, 2)]}
    
    如果我们需要N=8,我们需要使用路径索引0,即
    [0,3,8,11]
    ,索引1和索引2

    步骤3 合并路径。这里使用的技术是确定两条路径之间的公共节点的位置。然后在每对公共节点上循环,在第一条路径中找到它们之间的节点,并将其附加到列表中,然后对第二条路径执行相同的操作。然后,我们可以使用
    reduce
    函数将此技术应用于合并多个路径

    from functools import *
    
    def merge_paths(a, b):
        def pairwise(iterable):
            "s -> (s0,s1), (s1,s2), (s2, s3), ..."
            a, b = tee(iterable)
            next(b, None)
            return zip(a, b)
    
        def find_elements(x, text1, text2):
            return(x[x.index(text1)+1:x.index(text2)])
    
        my_list = []
        interesect_points = [x for x in a if x in b]
        for (x,y) in pairwise(interesect_points):
            ''' 
            get elements from a that within x,y --> e1
            get elements from b that within x,y --> e2
            if my_list is empty:
                add x,e1, e2, y to my_list
            else add e1, e2, y
            '''
            e1 = find_elements(a, x, y)
    
            e2 = find_elements(b, x, y)
    
            if len(my_list ) == 0:
                my_list.extend([x] + e1 + e2 + [y])
            else:
                my_list.extend(e1 + e2 + [y])
    
        return(my_list)
    
    完成解决方案 最后一部分是函数
    process\u图
    ,它封装了前面讨论的所有功能

    在计算字典d中的长度后,如果值N不是字典键的一部分,则函数终止并返回
    None

    def set_for_size_N(paths, indexes ):
    
        for index in indexes:
            yield [paths[i] for i in index]
    
    def process_graph(G, start, end, N):
        paths = run_paths(G2, start, end, N)
    
        d = get_size_dict(paths)
        if N not in d.keys():
            return(None)
    
        list_of_paths_of_size_N = set_for_size_N(paths,d[N])
        for paths_of_size_N in list_of_paths_of_size_N:
            yield(reduce(merge_paths, paths_of_size_N))
    
    N=8的输出:

    for i in process_graph(G2, 0, 11, 8):
        print(i)
    [0, 3, 1, 4, 7, 6, 8, 11]
    
    下面是
    N=6
    的另一个例子:

    for i in process_graph(G2, 0, 11, 6):
        print(i)
    [0, 1, 4, 6, 9, 11]
    [0, 1, 4, 6, 8, 11]
    

    这可能不是最有效或最微妙的解决方案,还有改进的余地。

    @qualitaetsmuell,如果它能解决您的问题,请接受答案。
    for i in process_graph(G2, 0, 11, 8):
        print(i)
    [0, 3, 1, 4, 7, 6, 8, 11]
    
    for i in process_graph(G2, 0, 11, 6):
        print(i)
    [0, 1, 4, 6, 9, 11]
    [0, 1, 4, 6, 8, 11]