По существу последовательные преобразования массива в репе

StackOverflow https://stackoverflow.com/questions/6320775

  •  27-10-2019
  •  | 
  •  

Вопрос

Интересно, есть ли в 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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top