Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update base layout type class to current design #20

Open
cartazio opened this issue Jun 16, 2023 · 1 comment
Open

update base layout type class to current design #20

cartazio opened this issue Jun 16, 2023 · 1 comment

Comments

@cartazio
Copy link
Member

cartazio commented Jun 16, 2023

heres a summary i wrote earlier today [edited to add freshenLayout and its associated type synonym]

--- Index is a size indexed list of integers
class Layout format where 
     type AddressRep format -- the representation of memory addresses
     type FreshLayout lay 
      -- the sibling layout that has the same ordering, but corresponds with 
      -- a freshly allocated contiguous memory buffer
     type Rank format
     freshenLayout :: layout -> FreshLayout layout 
     --- this operation is what you'd use to generate the layout descriptor if you're doing a 
     --- deep copy of a heavily sliced input array
     compareIx :: format -> Index (Rank) -> Index (Rank) -> ORD
     --- every address layout *must* have an ordering of the indices
     ---  that respects the associated address of values layout ordering, 
     ----this lets you write good locality code without knowing the memory layout!
     --- ie if ix1 and ix2 are in bounds, they must be totally ordererable, 
     ---- even if the coordinates are invalid and do not map to concrete addresses
     compareAddr :: (addr ~ AddressRep format) => format -> addr -> addr -> ORD
     --- compareIx and compareAddr should agree on point that are valid in both index and address space
     addressRange ::(addr ~ AddressRep format) => format -> Maybe (addr,addr)
     --- returns the first and last valid addresses for a given format datum. should be O(rank) or ideally O(1)
     address2Index :: (addr ~ AddressRep format) => format -> addr -> Index (Rank format)
     -- address2index should always succeed for valid addreses, 
     -- and should have complexity O(rank format). eg O(2) for matrices :). 
     --- Constant time for fixed choice in layout format 
     addressPopCount :: (addr ~ AddressRep format) =>form -> (addr,addr) -> Word64
     --- addressPopCount form (addr1,addr2) counts the number of valid addresses 
     --- inclusive of the min and max points as determined by the tuple (addr1,addr2)
     nextAddress :: (addr ~ AddressRep format) => format -> addr -> Maybe addr
     -- nextaddress should also have complexity O(rank format), 
     --this can be accomplished by having the associated address datatype carry a little bit of extra information 
     --- for pretty much every format i've come across
     affineShift ::  (addr ~ AddressRep format) => format -> addr -> Int64 -> Maybe addr
     --- `affineShift format address shift`should strive to have 
     ---complexity O(log min(|shift|, pop count of format range )) or better
     --- achieving this complexity bound may require extra 
     --- precomputed metadata in the datatype definition of the Format `form`
     index2address :: (addr ~ AddressRep format) => format -> Index (Rank format) -> Maybe addr 
     index2address form ix =  case findIndex form ix of Nothing -> Nothing ;
                                               Just (ix2,addr) -> if ix2==ix then Just addr else Nothing 
     findIndex :: (addr ~ AddressRep format) => format -> Index (Rank format) -> Maybe (Index (Rank format), addr)
     -- findindex form ix, finds the first address in the layout format that corresponds with an index equal to or greater  than ix
     --- if `ix` is a valid coordinate, findindex form ix will return Just (ix,addr_of_ix)
     --- as determined by the ordering relation `compareIx` (equivalently the  ordering of increasing addresses )
     --- a further optimized version would take an extra `Maybe addr` argument as a hint 
     ---for where to start the search for the right index,address pair result tuple.
@cartazio
Copy link
Member Author

need to also add to this my updated thinking about the interfaces for Sparse and Dense and structured and tiled Rectilinear layouts (which are the majority of formats used in practice).
It'll still roughly follow whats in the code here

data MajorOrientation = Rowed | Columned | BlockedColumn | BlockedRow
deriving(Data,Typeable)
data SMajorOrientation (o :: MajorOrientation) where
SRowed :: SMajorOrientation 'Rowed
SColumned :: SMajorOrientation 'Columned
SBlockedRow :: SMajorOrientation 'BlockedRow
SBlockedColumn :: SMajorOrientation 'BlockedColumn
-- | Every instance of 'RectilinearLayout' needs to have a corresponding
-- 'RectOrientationForm', 'RectDownRankForm', and 'InnerContigForm'
type family RectOrientationForm form :: MajorOrientation
type family RectDownRankForm form :: Type
type family InnerContigForm form :: Type
{- | 'RectilinearLayout' is the type class that supports the modle widely
usable class of slicing operations in Numerical.
for every instance @'RectilinearLayout' format rank orientation@, a corresponding
@'RectOrientationForm' form @, @'RectDownRankForm' form@
and @'InnerContigForm' form@ type family instance should be defined
The purpose of 'RectilinearLayout' class is to provide
-}
class Layout form rank =>
RectilinearLayout form (rank :: Nat) (oriented :: MajorOrientation) | form -> rank oriented where
-- | 'formRectOrientation' provides a runtime mechanism for reflecting
-- the orientation of the format
formRectOrientation :: p form -> SMajorOrientation oriented
{-
is array layout always static?
for now lets say yes, cause you can always just existential up the class
-}
-- | For @'rectlinearShape' form==shp@, we always have that
-- @'basicLogicalShape' form `weaklyDominates` shp@.
-- when 'strictlyDominates' holds, that implies that the underlying array format
-- is a rectilinear layout whose "elements" are tiles of a fixed size array format.
-- For this initial release and initial set of applicable rectilinear array formats,
-- the following is always true @'basicLogicalShape' form == basicLogicalShape' form @
-- Should be @O(1)@ always. Or more precisely @O(rank)@
rectlinearShape :: form -> Index rank
unconsOuter:: ('S down ~ rank)=> p form -> Shape rank a -> (a, Shape down a)
consOuter :: ('S down ~ rank)=> p form -> a -> Shape down a -> Shape rank a
-- | @'majorAxisSlice' fm (x,y)@ requires that y-x>=1, ie that more than
-- one sub range wrt the major axis be selected, so that the logical
-- rank of the selected array stays the same. This operation also preserves
-- memory locality as applicable.
-- @O(1)@ / @O(rank)@
majorAxisSlice :: form -> (Int,Int)-> form
-- should this be -> Maybe form?
-- | @'majorAxixProject' form x@ picks a "row" with respect to the outer most
-- dimension of the array format. This will
-- @O(1)@ or @O(rank)@
majorAxisProject :: (RectilinearLayout downForm subRank oriented,
rank ~ ('S subRank) , downForm~ RectDownRankForm form) => form -> Int -> downForm
-- | this is the nonstrided subset of general array slice notation.
-- Invoke as @'rectilinearSlice' form leastCorner greatestCorner@,
-- where the least and greatest corners of the sub array are determined
-- by the 'strictlyDominates' partial order on the bounds of the sub array.
-- For Dense array formats, this should be @O(1)@ or more precisely @O(rank)@
-- For the basic Sparse array formats thus far the complexity should be
-- @O(size of outermost dimension)@, which could be computed by
-- @fst . unconsOuter [form] . rectilinearShape $ form@
rectlinearSlice :: (RectilinearLayout icForm rank oriented,icForm~InnerContigForm form )=>form -> Index rank -> Index rank -> icForm -- FIXME, need the range infos????? (icfFOrm, adddress,address)
{- | 'DenseLayout' only has instances for Dense array formats.
this class will need some sprucing up for the beta,
but its ok for now. NB that 'DenseLayout' is really strictly meant to be used
for optimization purposes, and not meant as a default api
-}
class Layout form rank => DenseLayout form (rank :: Nat) | form -> rank where
basicToDenseAddress :: form -> Index rank -> Address
basicToDenseIndex :: form -> Address -> Index rank
basicNextDenseAddress :: form -> Address -> Address
basicNextDenseAddress = \form shp -> snd
(basicNextDenseIndex form $ basicToDenseIndex form shp )
{-# INLINE basicNextDenseAddress #-}
basicNextDenseIndex :: form -> Index rank ->(Index rank ,Address)
basicNextDenseIndex = \form shp -> (\ addr ->( basicToDenseIndex form addr, addr) ) $!
basicNextDenseAddress form $ basicToDenseAddress form shp
{-# INLINE basicNextDenseIndex #-}
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 707
{-# MINIMAL basicToDenseIndex, basicToDenseAddress,
(basicNextDenseIndex | basicNextDenseAddress) #-}
#endif
{-

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant