Data.Vector
API提供了一个高效的backpermute
函数,该函数基本上将索引映射σ
- 向量应用于向量v
,即v'[j] = v[σ[j]]
。
或者以list-syntax表示(为简单起见):
backpermute :: [Int] -> [a] -> [a]
backpermute σ v = map (v !!) σ
如果!!
具有 O(1)复杂度(我假设为Data.Vector
),那么 O(n)复杂度可能会有所不同。现在我想要反向“前向”permute
操作(或者反转σ
- 向量本身的函数),即类似(再次在列表语法中):
permute :: [Int] -> [a] -> [a]
permute σ = map snd . sortBy (comparing fst) . zip σ
invperm :: [Int] -> [Int]
invperm σ = permute σ [0..]
唉,由于sortBy
,上面的代码不是 O(n)。但由于σ
被假定为[0..]
permute
前缀的排列,因此应将其表示为{em> O(n)算法{{1} API。
那么,我怎样才能实现高效的 O(n) Data.Vector
(或者 O(n) permute
) invperm
API?
答案 0 :(得分:6)
因此permute
应该采用索引向量和值向量并创建一个新向量,以便每个值都存储在相应的索引中,即v'[σ[j]] = v[j]
,{backpermute
的倒数1}}。
据我所知,Data.Vector
中没有用于构建索引值对的新Vector
的函数,但是有一个更新现有向量的函数,即
update :: Vector a -> Vector (Int, a) -> Vector a
。它的运行时是 O(m + n),其中 m 是向量的大小, n 是更新的数量。
还有变体update_ :: Vector a -> Vector Int -> Vector a -> Vector a
,它采用两个向量而不是对向量。完善。现在我们只需要一个初始向量来“覆盖”这些值。假设σ
是有效的排列,所有项目都将更新,因此任何类型和长度与v
相同的向量都可以,因此我们可以重用v
。
permute :: Vector Int -> Vector a -> Vector a
permute σ v = update_ v σ v
由于σ
的长度与v
相同,因此运行时为 O(n)。
更安全的选择是使用最低值向量。这样,如果您尝试读取σ
中没有索引的项目而不是默默地得到错误的结果,您将收到错误。
permute σ v = update_ (replicate (length v) undefined) σ v
答案 1 :(得分:6)
Monadic初始化,也许?
invSigma :: Vector Int -> Vector Int
invSigma s = create $
do v <- new n
zipWithM_ (write v) s (enumFromN 0 n)
return v
where n = V.length s