在过去,我经常使用以下类型的循环(Haskell示例):
upperBoundToTuples :: Int -> [(Int, Int)]
upperBoundToTuples n = [(x,y) | x <- [0..n], y <- [x+1..n]]
上面的代码产生范围(0,1)..(n,n)的元组,其中对于所有x&lt;收率
我想知道是否有一种有效的方法可以获得给定单个索引的那些(x,y)索引?可能的应用包括GPU上的优化问题,其中不允许循环并且每个线程仅获得索引。
此外,如果2D情况可能,这样的算法可以推广到多维吗?
答案 0 :(得分:4)
你要求从[0,N(N + 1)/ 2)到对(x,y)的双射,其中0 <= x&lt; y&lt; = N。
这是一种定义它的简单方法(在伪代码中,但转换为Haskell应该很简单):
x0, y0 = i / (N + 1), i % (N + 1)
if x0 < y0 then result = (x0, y0)
else result = (N - 1 - x0, N - y0)
这是N = 6函数的可视化。地图布局在一个长度为N + 1 = 7的行的表中,第一行代表i = 0到6的函数值,下一个i = 7到13,依此类推。如果仔细观察,可以看到前方对角线上方的东西映射到表中的位置,对角线上方或下方的东西可以旋转到后面的条目。
5,6 0,1 0,2 0,3 0,4 0,5 0,6
4,6 4,5 1,2 1,3 1,4 1,5 1,6
3,6 3,5 3,4 2,3 2,4 2,5 2,6
这与此可视化相反:表T
的大小(N + 1)乘以(N + 1),T[x, y] = i
其中i
映射到(x,y) )通过上述功能。
- 1 2 3 4 5 6
- - 9 10 11 12 13
- - - 17 18 19 20
- - - - 16 15 14
- - - - - 8 7
- - - - - - 0
- - - - - - -
这种方法可能会在更高的维度上工作,但我不会立即看到。作为替代方案,这是一个简单但效率低下的方法,可以在任意维度上工作。
首先,请注意从choose(N + 1, k)
到k
的数字0
的{{1}}长度增加序列N
choose(N, k)
是binomial coefficient )。其中choose(N, k - 1)
以N
结尾。这给出了这个递归函数,它以降序的colexicographical顺序生成序列(再次以伪代码形式):
sequence(N, k, index)
= [] if k == 0
= sequence(N - 1, k - 1, index) + [N] if index < choose(N, k - 1)
= sequence(N - 1, k, index - choose(N, k - 1)) otherwise
此处为sequence(5, 3, index)
index
介于0和19之间:
0 -> [3, 4, 5]
1 -> [2, 4, 5]
2 -> [1, 4, 5]
3 -> [0, 4, 5]
4 -> [2, 3, 5]
5 -> [1, 3, 5]
6 -> [0, 3, 5]
7 -> [1, 2, 5]
8 -> [0, 2, 5]
9 -> [0, 1, 5]
10 -> [2, 3, 4]
11 -> [1, 3, 4]
12 -> [0, 3, 4]
13 -> [1, 2, 4]
14 -> [0, 2, 4]
15 -> [0, 1, 4]
16 -> [1, 2, 3]
17 -> [0, 2, 3]
18 -> [0, 1, 3]
19 -> [0, 1, 2]
答案 1 :(得分:2)
我们可以等同地考虑[(x,y) | x<-[0..n], y<-[0..x-1]]
。这个清单有长度
ℓ n = x = 0 Σ n x = n·(n+1)/2
因此,我们可以得到一个给定的ℓ,最近的 n 到
2·ℓ n = n ·( n +1) = n 2 + n
n 〜 =-½±√(¼+ 2·ℓ n )
特别是,对于给定的索引 i ,
n i - =⌊-½±√(¼+ 2· i )⌋
是最后一个完整三角形的x长度。因此,索引 i 位于行 n i - +1中。该三角形的面积为
ℓ n i - = n <子> I - 子>·(名词 <子> I - 子> 1)< / SUP> / <子> 2 子>
因此我们需要从 i 中减去以得到余数索引(在y方向上)。这就产生了定义
lowerTriangularTuple :: Int -> (Int,Int)
lowerTriangularTuple i = (nmin+1, i - (nmin*(nmin+1))`div`2)
where nmin = floor $ -1/2 + sqrt(1/4 + 2 * fromIntegral i)
示例:
GHCi> lowerTriangularTuple <$> [0..30]
[(1,0),(2,0),(2,1),(3,0),(3,1),(3,2),(4,0),(4,1),(4,2),(4,3),(5,0),(5,1),(5,2),(5,3),(5,4),(6,0),(6,1),(6,2),(6,3),(6,4),(6,5),(7,0),(7,1),(7,2),(7,3),(7,4),(7,5),(7,6),(8,0),(8,1),(8,2)]