NumPy:n个向量的稀疏外积(双曲线交叉)

时间:2015-06-17 09:31:08

标签: python algorithm performance numpy

我试图计算n向量的完整外积的某个子集。完整外部产品的计算在this question中描述。

正式:让v1v2,...,vk为某个长度为n的向量,K为正常数。我想要一个包含v1[i1]v2[i2]...vk[ik](索引从一开始)的所有产品i1*i2*...*ik <= K的列表。注意:例如,如果K = n ** k,则列表将包含每个组合。

我目前的做法是创建一个满足上述条件的索引的分层列表,然后递归计算产品,这有利于重用某些因素。

此实现比使用NumPy计算完整外部产品要快得多(对于相同的nk)。我希望获得比完整产品的计算更好的性能。我对k较大的值和 small K感兴趣(这个问题来自使用稀疏基数的函数逼近,即双曲线十字)。

有没有人知道更高效的方式来获取此列表?也许通过使用更多的NumPy或其他算法?我接下来会尝试C实现。

这是我目前的实施:

import numpy as np

def get_cross_indices(n, k, K):
    """
    Assume k > 0.
    Returns a hierarchical list containg elements of type
      (i1, list) with
        - i1 being a index (zero based!)
        - list being again a list (possibly empty) with all indices i2, such
          that (i1+1) * (i2+1) * ... * (ik+1) <= K  (going down the hierarchy)
    """
    if k == 1:
        num = min(n, K)
        return (num, [(x, []) for x in range(num)])
    else:
        indices = []
        nums = 0
        for i in xrange(min(n, K)):
            (num, tail) = get_cross_indices(n,
                k - 1, K // (i + 1))
            indices.append((i,  tail))
            nums += num
        return (nums, indices)

def calc_cross_outer_product(vectors, result, factor, indices, pos):
    """
    Fills the result list recursively with all products
        vectors[0][i1] * ... * vectors[k-1][ik]

    such that i1,...,ik is a feasible index sequence
    from `indices` (they are in there hierarchically,
    also see `get_cross_indices`).
    """
    for (x, list) in indices:
        if not list:
            result[pos] = factor * vectors[0][x]
            pos += 1
        else:
            pos = calc_cross_outer_product(vectors[1:], result,
                factor * vectors[0][x], list, pos)
    return pos

k = 3 # number of vectors
n = 4 # vector length
K = 3
# using random values here just for demonstration purposes
vectors = np.random.rand(k, n)

# get all indices which meet the condition
(count, indices) = get_cross_indices(n, k, K)

result = np.ones(count)
calc_cross_outer_product(vectors, result, 1, indices, 0)


## Equivalent version ##
alt_result = np.ones(count)
# create full outer products
outer_product = reduce(np.multiply, np.ix_(*vectors))
pos = 0
for inds in np.ndindex((n,)*k):
    # current index set is feasible?
    if np.product(np.array(inds) + 1) <= K:
        # compute [ vectors[0][inds[0]],...,vectors[k-1][inds[k-1]] ]
        values = map(lambda x: vectors[x[0]][x[1]],
            np.dstack((np.arange(k), inds))[0])
        alt_result[pos] = np.product(values)
        pos += 1

要了解我感兴趣的指数的视觉概念,以下是k=3的图片,K=n

Hyperbolic Cross

(摘自this website

0 个答案:

没有答案