11

더 구체적으로, 나는 다음과 같은 무해한 보이는 작은 바디 수리 3 프로그램이 있습니다Repa 2와 3 API의 주요 차이점은 무엇입니까?

real 2m32.572s 
user 4m57.324s 
sys  0m1.870s 
: 내 2GHz의 코어 2 듀오 노트북에 640x420 이미지를 처리하기 위해이 정도의 시간이 소요

{-# LANGUAGE QuasiQuotes #-} 

import Prelude hiding (map, zipWith) 
import System.Environment (getArgs) 
import Data.Word (Word8) 
import Data.Array.Repa 
import Data.Array.Repa.IO.DevIL 
import Data.Array.Repa.Stencil 
import Data.Array.Repa.Stencil.Dim2 

main = do 
    [s] <- getArgs 
    img <- runIL $ readImage s 

    let out = output x where RGB x = img 
    runIL . writeImage "out.bmp" . Grey =<< computeP out 

output img = map cast . blur . blur $ blur grey 
    where 
    grey    = traverse img to2D luminance 
    cast n   = floor n :: Word8 
    to2D (Z:.i:.j:._) = Z:.i:.j 

--------------------------------------------------------------- 

luminance f (Z:.i:.j) = 0.21*r + 0.71*g + 0.07*b :: Float 
    where 
    (r,g,b) = rgb (fromIntegral . f) i j 

blur = map (/ 9) . convolve kernel 
    where 
    kernel = [stencil2| 1 1 1 
         1 1 1 
         1 1 1 |] 

convolve = mapStencil2 BoundClamp 

rgb f i j = (r,g,b) 
    where 
    r = f $ Z:.i:.j:.0 
    g = f $ Z:.i:.j:.1 
    b = f $ Z:.i:.j:.2 

RepA 2를 사용하는 훨씬 더 복잡한 알고리즘에 대해 훨씬 더 나은 성능을 얻었 기 때문에 무언가가 틀림 없음을 알고 있습니다.이 API에서 발견 된 큰 개선점은 모든 배열 변환 전에 '강제'호출을 추가 한 것입니다. map, convolve, traverse 등의 모든 호출을 의미하는 것으로 이해). 필자는 Repa 3에서 할 수있는 비슷한 것을 만들 수 없다. 사실, 새로운 구현 형 매개 변수가 배열을 강제해야 할 때에 대한 모호성이 없도록 보장한다고 생각 했는가? 그리고 새로운 모나드 인터페이스는이 계획에 어떻게 들어 맞습니까? 나는 Don S가 작성한 훌륭한 튜토리얼을 읽었지만, 온라인 AFAIK에 대해서는 거의 언급되지 않은 Repa 2와 3 API 사이에 몇 가지 중요한 차이가있다.

더 간단히 말하면, 위의 프로그램의 효율성을 수정하는 데 최소한의 영향을 미치는 방법이 있습니까?

답변

10

새로운 표현 형식 매개 변수는 자동적으로 (아마 그 잘 할 수있는 어려운 문제입니다) 강요하지 않는다 - 당신이 수동으로 강제해야한다. 이 모나드 왜 당신은 단지뿐만 아니라 모나드 신원을 사용할 수 있기 때문에

computeP 
    :: (Monad m, Repr r2 e, Fill r1 r2 sh e) 
    => Array r1 sh e -> m (Array r2 sh e) 

나는 개인적으로 정말 이해가 안 : 바디 수리 3 년이는 computeP 기능을 수행 그래서

import Control.Monad.Identity (runIdentity) 
force 
    :: (Repr r2 e, Fill r1 r2 sh e) 
    => Array r1 sh e -> Array r2 sh e 
force = runIdentity . computeP 

을 지금, 당신의 output 기능은 적절한가 강제로 다시 작성할 수 있습니다 : 약어 f

output img = map cast . f . blur . f . blur . f . blur . f $ grey 
    where ... 

돕기 위해 도우미 함수 u를 사용하여 타입 추론 이러한 변화

u :: Array U sh e -> Array U sh e 
u = id 
f = u . force 

는 고속화 매우 극적이다 - 각 출력 화소가 필요한 것보다 훨씬 더 평가 끝 강제 중간체없이 같이 예상 할 수있는 (중간 값이 공유되지 않은) .

원래 코드 :

real 0m25.339s 
user 1m35.354s 
sys  0m1.760s 

강제로하십시오 600x400 PNG로 테스트

real 0m0.130s 
user 0m0.320s 
sys  0m0.028s 

는, 출력 파일은 동일했다.

+0

이것은 훌륭한 대답입니다! 나는 computeP가 '힘'의 대체물이지만, 신원 모나드와 함께 사용하지 않을 것이라고 이해했다. 도와 주셔서 감사합니다. – sacheie

+1

나는 모나드 리턴 타입을 사용하는 이유는 무언가를 강요한다는 생각이 순차적으로 일어나는 힘과 밀접하게 연결되어 있기 때문이라고 생각한다. http://www.cse.unsw.edu.au/~chak/papers/LCKP12.html에 더 좋은 설명이 있습니다. – Axman6

7

computeP은 새로운 force입니다. 당신이 무슨 일을하는지 유사하다 바디 수리 2.

에 바디 수리-예에서 Laplace 예를 force을 사용했을 사방

는 바디 수리 3에서는 computeP를 사용해야합니다. blur 함수에는 을 일반 map 대신에 사용해야합니다. 다음 주 초에 내 홈페이지에 이유를 설명하는 종이가있을 것입니다. 필요할 때

+0

하스켈 커뮤니티에 대한 좋은 점 - 도서관 개발자들의 의견 : 저는 열심히 여러분의 논문을 기다리고 있습니다. – sacheie

관련 문제