Python NumPy矢量化

Python NumPy矢量化,python,algorithm,numpy,graph,vectorization,Python,Algorithm,Numpy,Graph,Vectorization,我正试图为未加权顶点覆盖问题编写所谓的列表右启发式代码。背景如下: 顶点覆盖问题:在顶点覆盖问题中,我们给出了一个无向图G=(V,E),其中V是顶点集,E是边集。我们需要找到一个最小的集合V',它是V的子集,使得V'覆盖G。如果图中的所有边在V'中至少有一个顶点,则称集合V'覆盖图G 列表右启发式:算法非常简单。给定一个顶点列表V=[v1,v2,…vn],其中n是G中的顶点数,如果i>j且vi和vj由图G中的边连接,则称vi为vj的右邻居。我们启动一个覆盖C={}(空集)并从右向左扫描V。在任何

我正试图为未加权顶点覆盖问题编写所谓的列表右启发式代码。背景如下:

顶点覆盖问题:在顶点覆盖问题中,我们给出了一个无向图G=(V,E),其中V是顶点集,E是边集。我们需要找到一个最小的集合V',它是V的子集,使得V'覆盖G。如果图中的所有边在V'中至少有一个顶点,则称集合V'覆盖图G

列表右启发式:算法非常简单。给定一个顶点列表V=[v1,v2,…vn],其中n是G中的顶点数,如果i>j且vi和vj由图G中的边连接,则称vi为vj的右邻居。我们启动一个覆盖C={}(空集)并从右向左扫描V。在任何一点上,假设当前扫描的顶点是u。如果u至少有一个右邻居不在C中,那么u被添加到C中。整个V只扫描一次

我一次解决多个图(具有相同顶点但不同边)的问题

我用python编写了这个列表。我能够一次对它进行矢量化以解决多个图形,但我无法对原始for循环进行矢量化。我用邻接矩阵来表示这个图。我想知道它是否可以进一步矢量化。这是我的密码:

def list_right_heuristic(population: np.ndarray, adj_matrix: np.ndarray):
    adj_matrices = np.matlib.repmat(adj_matrix,population.shape[0], 1).reshape((population.shape[0], *adj_matrix.shape))

    for i in range(population.shape[0]):
        # Remove covered vertices from the graph. Delete corresponding edges
        adj_matrices[i, np.outer(population[i], population[i]).astype(bool)] = 0

    vertex_covers = np.zeros(shape=population.shape, dtype=population.dtype)
    for index in range(population.shape[-1] - 1, -1, -1):
        # Get num of intersecting elements (for each row) in right neighbors and vertex_covers
        inclusion_rows = np.sum(((1 - vertex_covers) * adj_matrices[..., index])[..., index + 1:], axis=-1).astype(bool)
        # Only add vertices to cover for rows which have at least one right neighbor not in vertex cover
        vertex_covers[inclusion_rows, index] = 1

    return vertex_covers
我有p个图,我正试图同时求解,其中p=population.shape[0]。每个图都有相同的顶点,但有不同的边。填充数组是一个2D数组,其中每一行表示图G中已经在覆盖层中的顶点。我只是想找到不在封面上的顶点。因此,将cover中顶点的所有行和列设置为0,即删除相应的边。理论上,启发式应该只返回不在覆盖层中的顶点。 所以在第一个for循环中,我只是将邻接矩阵中相应的行和列设置为0(行和列中的所有元素都将为零)。接下来,我将从右到左遍历2D顶点数组,并查找每行中不在顶点覆盖范围内的右邻域数。为此,我首先找到不在覆盖范围内的顶点(1-顶点覆盖),然后将其与adj_矩阵中相应的列(或行,因为adj矩阵是对称的)相乘,得到我们正在扫描的顶点的邻居。然后我把所有元素加在右边。如果该值大于0,则至少有一个右邻居不在顶点覆盖中。 我这样做对吗?
还有什么方法可以矢量化第二个for循环(或者第一个for循环)或者总体上加快代码的速度?对于大型图(具有1000多个顶点),在其他一些代码中数千次调用此函数。任何帮助都将不胜感激

您可以使用
np.einsum
在索引之间执行许多复杂的操作。在您的情况下,第一个循环可以这样执行:

adj_matrices[np.einsum('ij, ik->ijk', population, population).astype(bool)] = 0
我花了一些时间来理解
einsum
是如何工作的。我觉得很有帮助

顺便说一句,您的代码给了我以下语法错误:

SyntaxError: can use starred expression only as assignment target
我不得不将函数的第一行重写为:

adj_matrices = np.matlib.repmat(adj_matrix,population.shape[0], 
        1).reshape((population.shape[0],) + adj_matrix.shape)

总体
调整矩阵
的形状是相同的,对吗?而且,它们都是方形阵列?adj矩阵是方形矩阵。人口不一定会增加。例如,考虑用[0,0,1,0],[0,0,0,1],[1,0,0,1],[0,1,1,0]的邻接矩阵为图编码的两个不同的顶点覆盖。假设覆盖1中有第二个和第四个顶点,覆盖2有第二个和第三个顶点。那么人口将是[[0,1,0,1],[0,1,1,0]]。虽然只需添加更多随机覆盖的行,就可以很容易地使总体成为方形矩阵。