{-# LANGUAGE MagicHash #-}-- This is specialised for stencils up to 7x7.-- Due to limitations in the GHC optimiser, using larger stencils doesn't-- work, and will yield `error` at runtime. We can probably increase the-- limit if required -- just ask.---- The focus of the stencil is in the center of the 7x7 tile, which has-- coordinates (0, 0). All coefficients in the stencil must fit in the tile,-- so they can be given X,Y coordinates up to +/- 3 positions.-- The stencil can be any shape, and need not be symmetric -- provided it-- fits in the 7x7 tile.--moduleData.Array.Repa.Stencil.Dim2(-- * Stencil creationmakeStencil2,stencil2-- * Stencil operators,PC5,mapStencil2,forStencil2)whereimportData.Array.RepaimportData.Array.Repa.Repr.CursoredimportData.Array.Repa.Repr.PartitionedimportData.Array.Repa.Repr.HintimportData.Array.Repa.Repr.UndefinedimportData.Array.Repa.Stencil.BaseimportData.Array.Repa.Stencil.TemplateimportData.Array.Repa.Stencil.PartitionimportGHC.Exts-- | A index into the flat array.-- Should be abstract outside the stencil modules.dataCursor=CursorInttypePC5=PC(P(SD)(P(SD)(P(SD)(P(SD)X))))-- Wrappers --------------------------------------------------------------------- | Like `mapStencil2` but with the parameters flipped.forStencil2::Reprra=>Boundarya->ArrayrDIM2a->StencilDIM2a->ArrayPC5DIM2a{-# INLINE forStencil2 #-}forStencil2boundaryarrstencil=mapStencil2boundarystencilarr--------------------------------------------------------------------------------- | Apply a stencil to every element of a 2D array.mapStencil2::Reprra=>Boundarya-- ^ How to handle the boundary of the array.->StencilDIM2a-- ^ Stencil to apply.->ArrayrDIM2a-- ^ Array to apply stencil to.->ArrayPC5DIM2a{-# INLINE mapStencil2 #-}mapStencil2boundarystencil@(StencilStaticsExtent_zero_load)arr=letsh=extentarr(_:.aHeight:.aWidth)=sh(_:.sHeight:.sWidth)=sExtentsHeight2=sHeight`div`2sWidth2=sWidth`div`2-- Partition the array into the internal and border regions.![RegioninXinYinWinH,RegionwestXwestYwestWwestH,RegioneastXeastYeastWeastH,RegionnorthXnorthYnorthWnorthH,RegionsouthXsouthYsouthWsouthH]=partitionForStencil(SizeaWidthaHeight)(SizesWidthsHeight)(OffsetsWidth2sHeight2){-# INLINE inInternal #-}inInternal(Z:.y:.x)=x>=inX&&x<(inX+inW)&&y>=inY&&y<(inY+inH){-# INLINE inBorder #-}inBorder=not.inInternal-- Cursor functions ----------------{-# INLINE makec #-}makec(Z:.y:.x)=Cursor(x+y*aWidth){-# INLINE shiftc #-}shiftcix(Cursoroff)=Cursor$caseixofZ:.y:.x->off+y*aWidth+x{-# INLINE arrInternal #-}arrInternal=makeCursored(extentarr)makecshiftcgetInner'{-# INLINE getInner' #-}getInner'cur=unsafeAppStencilCursor2shiftcstencilarrcur{-# INLINE arrBorder #-}arrBorder=ASmall(fromFunction(extentarr)getBorder'){-# INLINE getBorder' #-}getBorder'ix=caseboundaryofBoundConstc->cBoundClamp->unsafeAppStencilCursor2_clampaddDimstencilarrixin-- internal regionAPartsh(Range(Z:.inY:.inX)(Z:.inH:.inW)inInternal)arrInternal-- border regions$APartsh(Range(Z:.westY:.westX)(Z:.westH:.westW)inBorder)arrBorder$APartsh(Range(Z:.eastY:.eastX)(Z:.eastH:.eastW)inBorder)arrBorder$APartsh(Range(Z:.northY:.northX)(Z:.northH:.northW)inBorder)arrBorder$APartsh(Range(Z:.southY:.southX)(Z:.southH:.southW)inBorder)arrBorder$AUndefinedshunsafeAppStencilCursor2::Reprra=>(DIM2->Cursor->Cursor)->StencilDIM2a->ArrayrDIM2a->Cursor->a{-# INLINE unsafeAppStencilCursor2 #-}unsafeAppStencilCursor2shift(StencilStaticsExtentzeroloads)arrcur0|_:.sHeight:.sWidth<-sExtent,sHeight<=7,sWidth<=7=let-- Get data from the manifest array.{-# INLINE getData #-}getData(Cursorcur)=arr`unsafeLinearIndex`cur-- Build a function to pass data from the array to our stencil.{-# INLINE oload #-}oloadoyox=let!cur'=shift(Z:.oy:.ox)cur0inloads(Z:.oy:.ox)(getDatacur')intemplate7x7oloadzero|otherwise=error$unlines["mapStencil2: Your stencil is too big for this method."," It must fit within a 7x7 tile to be compiled statically."]-- | Like above, but clamp out of bounds array values to the closest real value.unsafeAppStencilCursor2_clamp::forallra.Reprra=>(DIM2->DIM2->DIM2)->StencilDIM2a->ArrayrDIM2a->DIM2->a{-# INLINE unsafeAppStencilCursor2_clamp #-}unsafeAppStencilCursor2_clampshift(StencilStaticsExtentzeroloads)arrcur|_:.sHeight:.sWidth<-sExtent,_:.(I#aHeight):.(I#aWidth)<-extentarr,sHeight<=7,sWidth<=7=let-- Get data from the manifest array.{-# INLINE getData #-}getData::DIM2->agetData(Z:.(I#y):.(I#x))=wrapLoadXxy{-# NOINLINE wrapLoadX #-}wrapLoadX::Int#->Int#->awrapLoadX!x!y|x<#0#=wrapLoadY0#y|x>=#aWidth=wrapLoadY(aWidth-#1#)y|otherwise=wrapLoadYxy{-# NOINLINE wrapLoadY #-}wrapLoadY::Int#->Int#->awrapLoadY!x!y|y<#0#=loadXYx0#|y>=#aHeight=loadXYx(aHeight-#1#)|otherwise=loadXYxy{-# INLINE loadXY #-}loadXY::Int#->Int#->aloadXY!x!y=arr`unsafeIndex`(Z:.(I#y):.(I#x))-- Build a function to pass data from the array to our stencil.{-# INLINE oload #-}oloadoyox=let!cur'=shift(Z:.oy:.ox)curinloads(Z:.oy:.ox)(getDatacur')intemplate7x7oloadzero|otherwise=error$unlines["mapStencil2: Your stencil is too big for this method."," It must fit within a 7x7 tile to be compiled statically."]-- | Data template for stencils up to 7x7.template7x7::(Int->Int->a->a)->a->a{-# INLINE template7x7 #-}template7x7fzero=f(-3)(-3)$f(-3)(-2)$f(-3)(-1)$f(-3)0$f(-3)1$f(-3)2$f(-3)3$f(-2)(-3)$f(-2)(-2)$f(-2)(-1)$f(-2)0$f(-2)1$f(-2)2$f(-2)3$f(-1)(-3)$f(-1)(-2)$f(-1)(-1)$f(-1)0$f(-1)1$f(-1)2$f(-1)3$f0(-3)$f0(-2)$f0(-1)$f00$f01$f02$f03$f1(-3)$f1(-2)$f1(-1)$f10$f11$f12$f13$f2(-3)$f2(-2)$f2(-1)$f20$f21$f22$f23$f3(-3)$f3(-2)$f3(-1)$f30$f31$f32$f33$zero