Python NumPy 向量化

标签 python algorithm numpy graph vectorization

我正在尝试为未加权的顶点覆盖问题编写所谓的 List Right Heuristic 代码。背景如下:

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

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

我正在同时为多个图(具有相同的顶点但不同的边)解决这个问题。

我用 Python 编写了 List Right Heuristic。我能够对其进行矢量化以一次解决多个图形,但我无法对原始 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]。每个图都有相同的顶点但不同的边。 population 数组是一个二维数组,其中每一行表示图 G 中已经在封面中的顶点。我只是想找到不在封面中的顶点。因此,出于这个原因,将 cover 中所有顶点的行和列设置为 0,即,我正在删除相应的边。启发式算法理论上应该现在只返回不在封面中的顶点。 所以在第一个 for 循环中,我只是将邻接矩阵中相应的行和列设置为 0(行和列中的所有元素都将为零)。接下来,我将从右到左遍历二维顶点数组,并在不在 vertex_covers 中的每一行中找到右邻居的数量。为此,我首先找到不在 cover (1 - vertex_covers) 中的顶点,然后将其与 adj_matrices 中的相应列相乘(或行,因为 adj 矩阵是对称的)以获得我们正在扫描的那个顶点的邻居。然后我将所有元素加到这个右边。如果该值大于 0,则至少有一个右邻不在 vertex_covers 中。 我这样做正确吗? 有什么方法可以向量化第二个 for 循环(或第一个 for 循环)或总体上加速代码?在一些其他代码中为大型图(具有 1000 多个顶点)调用此函数数千次。任何帮助,将不胜感激。

最佳答案

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

adj_matrices[np.einsum('ij, ik->ijk', population, population).astype(bool)] = 0

我花了一些时间才明白 einsum 是如何工作的。我找到了 this SO question很有帮助。

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

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)

关于Python NumPy 向量化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34656689/

相关文章:

python - "[:,]"list slicing python,什么意思?

python - matplotlib从左到右到下显示图像(matlab蒙太奇)

python - 就地释放 Numpy 内存

python - 如何获取 Tornado 请求的客户端 IP?

python - 无法到达 Sentry 日志服务器错误 400

python - 以 Django 形式保存用户密码的散列版本不起作用

algorithm - 算力集算法分析

java - 当用户在Java中输入数组大小时,如何生成从0到100的随机数而不重复?

python - 如何将大量参数传递给 Django 中的 View ?

algorithm - 在有向图中查找可达顶点