По существу последовательные преобразования массива в репе
Вопрос
Интересно, есть ли в REPA аналог (//)?
Это необходимо для преобразований массива, которые не могут быть параллелизированы. Например, если функция требует, чтобы весь массив изменил одну запись массива, а затем применяется к новому массиву и т. Д. (И его следует запускать последовательно).
Решение
(//)
может быть реализован с точки зрения data.array.repa.fromfunction:
import Data.Array.Repa
(//) :: Shape sh => Array sh a -> [(sh,a)] -> Array sh a
(//) arr us = fromFunction (extent arr) (\sh -> case lookup sh us of
Just a -> a
Nothing -> index arr sh)
fromFunction
может быть передано функцией типа Shape sh => s -> a
который сам по себе может использовать весь массив.
Приведенная выше реализация выполняет все обновления за один проход.
Другие советы
Одна потенциальная проблема с (//) заключается в том, что она требует поиска в списке, чтобы найти значение для каждого элемента. Если массив или список большие, это может стать дорого.
Другой вариант - использовать удобную функцию из Data.Vector:
modify :: Vector v a => (forall s. Mutable v s a -> ST s ()) -> v a -> v a
Это имеет возможность сделать обновление на месте, если оно безопасно. Так что -то вроде
import Data.Vector.Unboxed as V
import Data.Vector.Mutable.Unboxed as M
import Data.Array.Repa as R
(///) :: Shape sh => Array sh a -> [(sh,a)] -> Array sh a
(///) arr us = R.fromVector sh . modify f $ R.toVector arr
where
sh = extent arr
f mv = forM_ us $ \(k,x) -> do
M.write mv (R.toIndex sh k) x
На моем ноутбуке я проверил это на массив DIM1 на 1 миллион, обновив 100 записей и получил эти времена: (//): 3,598973 (///): 2.08599999999997e-3