{-# OPTIONS_GHC -fno-warn-duplicate-exports #-}

-- |
-- Module      : Data.Massiv.Array
-- Copyright   : (c) Alexey Kuleshevich 2018-2022
-- License     : BSD3
-- Maintainer  : Alexey Kuleshevich <lehins@yandex.ru>
-- Stability   : experimental
-- Portability : non-portable
--
--
-- Massiv is a library, that allows creation and manipulation of arrays in parallel and
-- sequentially. Depending on the representation (@__r__@), an @__`Array` r ix e__@ will have
-- certain properties that are unique to that particular representation, but all of them will share
-- the same trait, that an array is simply a mapping from an index (@__ix__@) of an arbitrary
-- dimension to an element (@__e__@) of some value. Which means that some representations describe
-- classic arrays and are backed by a contiguous chunk of memory reserved for the elements (or
-- pointers to elements), namely arrays with `Manifest` representations:
--
-- * `B` - The most basic type of array that can hold any type of element in a boxed form, i.e. each
--         element is a pointer to the actual value, therefore it is also the slowest
--         representation. Elements are kept in a Weak Head Normal Form (WHNF).
--
-- * `BN` - Similar to `B`, it is also a boxed type, except its elements are always kept in a Normal
--         Form (NF). This property is very useful for parallel processing, i.e. when calling
--         `compute` you do want all of your elements to be fully evaluated.
--
-- * `BL` - Similar to `B`, it is also a boxed type, but lazy. Its elements are not evaluated when
--         array is computed.
--
-- * `S` - Is a type of array that is backed by pinned memory, therefore pointers to those arrays
--         can be passed to FFI calls, because Garbage Collector (GC) is guaranteed not to move
--         it. Elements must be an instance of `Storable` class. It is just as efficient as `P` and
--         `U` arrays, except it is subject to fragmentation.
--
-- * `U` - Unboxed representation. Elements must be an instance of `Unbox` class.
--
-- * `P` - Array that can hold Haskell primitives, such as `Int`, `Word`, `Double`, etc. Any element
--        must be an instance of `Prim` class.
--
-- There are also array representations that only describe how values for its elements can be
-- computed or loaded into memory, as such, they are represented by functions and do not impose the
-- memory overhead, that is normally associated with arrays. They are needed for proper fusion and
-- parallelization of computation.
--
-- * `D` - delayed array that is a mere function from an index to an element. Also known as /Pull/
--         array. Crucial representation for fusing computation. Use `computeAs` in order to load
--         array into `Manifest` representation.
--
-- * `DL` - delayed load array representation that describes how an array can be loaded. Also known
--         as /Push/ array. Useful for fusing various array combining functions. Use `computeAs` in
--         order to load array into `Manifest` representation.
--
-- * `DS` - delayed stream vector representation that describes how to handle a vector with
--         possibility of unknown length. Useful for filtering and unfolding. Use `computeAs`
--         in order to load such vector into `Manifest` representation.
--
-- * `DI` - delayed interleaved array. Same as `D`, but performs better with unbalanced
--         computation, when evaluation of one element takes much longer than of its neighbor.
--
-- * `DW` - delayed windowed array. This peculiar representation allows for very fast `Stencil`
--        computation.
--
-- Other Array types:
--
-- * `L` - this type isn't particularly useful on its own, but because it has unique ability to be
--       converted to and from nested lists in constant time, it provides a perfect intermediary for
--       conversion of nested lists into manifest arrays.
--
-- Most of the `Manifest` arrays are capable of in-place mutation. Check out
-- "Data.Massiv.Array.Mutable" module for available functionality.
--
-- Many of the function names exported by this package will clash with the ones from "Prelude",
-- hence it can be more convenient to import like this:
--
-- @
-- import Prelude as P
-- import Data.Massiv.Array as A
-- @
module Data.Massiv.Array (
  -- * Construct
  module Data.Massiv.Array.Ops.Construct,

  -- * Compute
  getComp,
  setComp,
  appComp,
  compute,
  computeS,
  computeP,
  computeIO,
  computePrimM,
  computeAs,
  computeProxy,
  computeSource,
  computeWithStride,
  computeWithStrideAs,
  clone,
  convert,
  convertAs,
  convertProxy,
  fromRaggedArrayM,
  fromRaggedArray',

  -- * Vector
  module Data.Massiv.Vector,

  -- * Size
  size,
  elemsCount,
  isEmpty,
  isNotEmpty,
  isNull,
  isNotNull,

  -- * Indexing
  (!?),
  (!),
  (??),
  indexM,
  index,
  index',
  defaultIndex,
  borderIndex,
  evaluateM,
  evaluate',

  -- * Mapping
  module Data.Massiv.Array.Ops.Map,

  -- * Folding
  -- $folding
  module Data.Massiv.Array.Ops.Fold,

  -- * Transforming
  module Data.Massiv.Array.Ops.Transform,

  -- * Slicing
  module Data.Massiv.Array.Ops.Slice,

  -- * Algorithms

  -- ** Sorting
  quicksort,
  quicksortBy,
  quicksortByM,
  tally,

  -- ** Iterations
  iterateUntil,

  -- * Conversion
  module Data.Massiv.Array.Manifest.List,

  -- * Mutable
  module Data.Massiv.Array.Mutable,

  -- * Core
  module Data.Massiv.Core,

  -- * Representations
  module Data.Massiv.Array.Delayed,
  module Data.Massiv.Array.Manifest,

  -- * Stencil
  module Data.Massiv.Array.Stencil,

  -- * Numeric Operations
  module Data.Massiv.Array.Numeric,
) where

import Data.Massiv.Array.Delayed
import Data.Massiv.Array.Manifest
import Data.Massiv.Array.Manifest.Internal
import Data.Massiv.Array.Manifest.List
import Data.Massiv.Array.Mutable
import Data.Massiv.Array.Numeric
import Data.Massiv.Array.Ops.Construct
import Data.Massiv.Array.Ops.Fold
import Data.Massiv.Array.Ops.Map
import Data.Massiv.Array.Ops.Slice
import Data.Massiv.Array.Ops.Sort
import Data.Massiv.Array.Ops.Transform
import Data.Massiv.Array.Stencil
import Data.Massiv.Core
import Data.Massiv.Core.Common
import Data.Massiv.Vector
import Prelude as P hiding (
  all,
  and,
  any,
  enumFromTo,
  foldl,
  foldr,
  mapM,
  mapM_,
  maximum,
  minimum,
  or,
  product,
  replicate,
  splitAt,
  sum,
  zip,
 )

-- $folding
--
-- All folding is done in a row-major order.