-- |
-- Module      :  Data.POSet
-- Copyright   :  (c) Sebastian Graf 2017
-- License     :  MIT
-- Maintainer  :  sgraf1337@gmail.com
-- Portability :  portable
--
-- A reasonably efficient implementation of partially ordered sets.
--
-- These modules are intended to be imported qualified, to avoid name
-- clashes with Prelude functions, e.g.
--
-- > import qualified Data.POSet as POSet
--
-- The implementation of 'POSet' is based on a decomposition of
-- chains (totally ordered submaps), inspired by
-- [\"Sorting and Selection in Posets\"](https://arxiv.org/abs/0707.1532).
--
-- Operation comments contain the operation time complexity in
-- [Big-O notation](http://en.wikipedia.org/wiki/Big_O_notation) and
-- commonly refer to two characteristics of the poset from which keys are drawn:
-- The number of elements in the set \(n\) and the /width/ \(w\) of the poset,
-- referring to the size of the biggest anti-chain (set of incomparable elements).
--
-- Generally speaking, lookup and mutation operations incur an additional
-- factor of \(\mathcal{O}(w)\) compared to their counter-parts in "Data.Set".
--
-- Note that for practical applications, the width of the poset should be
-- in the order of \(w\in \mathcal{O}(\frac{n}{\log n})\), otherwise a simple lookup list
-- is asymptotically superior.
-- Even if that holds, the constants might be too big to be useful for any \(n\) that can
-- can happen in practice.
--
-- The following examples assume the following definitions for a set on the divisibility
-- relation on `Int`egers:
--
-- @
-- {-\# LANGUAGE GeneralizedNewtypeDeriving \#-}
--
-- import           Algebra.PartialOrd
-- import           Data.POSet (POSet)
-- import qualified Data.POSet as POSet
--
-- newtype Divisibility
--   = Div Int
--   deriving (Eq, Read, Show, Num)
--
-- default (Divisibility)
--
-- instance 'PartialOrd' Divisibility where
--   Div a \`leq\` Div b = b \`mod\` a == 0
--
-- type DivSet = POSet Divisibility
--
-- -- We want integer literals to be interpreted as 'Divisibility's
-- -- and default 'empty's to DivSet.
-- default (Divisibility, DivSet)
-- @
--
-- 'Divisility' is actually an example for a 'PartialOrd' that should not be used as keys of 'POSet'.
-- Its width is \(w=\frac{n}{2}\in\Omega(n)\)!

module Data.POSet
  (
  -- * Set type
    Impl.POSet
  -- * Query
  , Foldable.null
  , Impl.size
  , Impl.member
  , Impl.notMember
  , Impl.lookupLT
  , Impl.lookupGT
  , Impl.lookupLE
  , Impl.lookupGE
  , Impl.isSubsetOf
  , Impl.isProperSubsetOf

  -- * Construction
  , Impl.empty
  , Impl.singleton
  , Impl.insert
  , Impl.delete

  -- * Combine
  , Impl.union
  , Impl.unions
  , Impl.difference
  , Impl.intersection

  -- * Filter
  , Impl.filter
  , Impl.partition

  -- * Map
  , Impl.map
  , Impl.mapMonotonic

  -- * Folds
  , Foldable.foldr
  , Foldable.foldl
  -- ** Strict folds
  , Impl.foldr'
  , Impl.foldl'

  -- * Min\/Max
  , Impl.lookupMin
  , Impl.lookupMax

  -- * Conversion
  , Impl.elems
  , Impl.toList
  , Impl.fromList
  ) where

import qualified Data.Foldable       as Foldable
import qualified Data.POSet.Internal as Impl