packages feed

hgeometry-combinatorial (empty) → 0.9.0.0

raw patch · 47 files changed

+5528/−0 lines, 47 filesdep +MonadRandomdep +QuickCheckdep +aesonsetup-changedbinary-added

Dependencies added: MonadRandom, QuickCheck, aeson, approximate-equality, base, bifunctors, bytestring, containers, contravariant, data-clist, deepseq, directory, dlist, doctest, filepath, fingertree, hgeometry-combinatorial, hspec, lens, linear, mtl, quickcheck-instances, random, reflection, semigroupoids, semigroups, singletons, template-haskell, text, vector, vector-builder, vinyl, yaml

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, Frank Staals++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Frank Staals nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,4 @@+HGeometry-combinatorial+=======================++The combinatorial types for the [HGeometry](https://hackage.haskell.org/package/hgeometry) package.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ changelog.org view
+ docs/Data/PlanarGraph/testG.png view

binary file changed (absent → 38819 bytes)

+ docs/Data/PlaneGraph/planegraph.png view

binary file changed (absent → 108198 bytes)

+ doctests.hs view
@@ -0,0 +1,66 @@+import Test.DocTest+++main :: IO ()+main = doctest $ ["-isrc" ] ++ ghcExts ++ files+++ghcExts :: [String]+ghcExts = map ("-X" ++)+          [ "TypeFamilies"+          , "GADTs"+          , "KindSignatures"+          , "DataKinds"+          , "TypeOperators"+          , "ConstraintKinds"+          , "PolyKinds"+          , "RankNTypes"+          , "TypeApplications"+          , "ScopedTypeVariables"++          , "PatternSynonyms"+          , "ViewPatterns"+          , "TupleSections"+          , "MultiParamTypeClasses"+          , "LambdaCase"+          , "TupleSections"+++          , "StandaloneDeriving"+          , "GeneralizedNewtypeDeriving"+          , "DeriveFunctor"+          , "DeriveFoldable"+          , "DeriveTraversable"+          , "AutoDeriveTypeable"+          , "DeriveGeneric"+          , "FlexibleInstances"+          , "FlexibleContexts"+          ]++files :: [String]+files = map toFile modules+++toFile :: String -> String+toFile = (\s -> "src/" <> s <> ".hs") . replace '.' '/'++replace     :: Eq a => a -> a -> [a] -> [a]+replace a b = go+  where+    go []                 = []+    go (c:cs) | c == a    = b:go cs+              | otherwise = c:go cs++modules :: [String]+modules =+  [ "Data.Range"+  , "Data.CircularList.Util"+  , "Data.Permutation"+  , "Data.CircularSeq"+  , "Data.LSeq"+  , "Data.PlanarGraph"+  , "Data.PlanarGraph.Dart"+  , "Data.PlanarGraph.Core"+  , "Data.Tree.Util"+  , "Data.Set.Util"+  ]
+ hgeometry-combinatorial.cabal view
@@ -0,0 +1,235 @@+-- Initial hgeometry.cabal generated by cabal init.  For further+-- documentation, see http://haskell.org/cabal/users-guide/++name:                hgeometry-combinatorial+version:             0.9.0.0+synopsis:            Data structures, and Data types.+description:+    The Non-geometric data types and algorithms used in HGeometry.+homepage:            https://fstaals.net/software/hgeometry+license:             BSD3+license-file:        LICENSE+author:              Frank Staals+maintainer:          frank@fstaals.net+-- copyright:++tested-with:         GHC >= 8.4++category:            Geometry+build-type:          Simple++data-files:          test/Data/PlanarGraph/myGraph.yaml+                     -- in the future (cabal >=2.4) we can use+                     -- examples/**/*.in+                     -- examples/**/*.out++extra-source-files:  README.md+                     changelog.org++Extra-doc-files:     docs/Data/PlanarGraph/testG.png+                     docs/Data/PlaneGraph/planegraph.png+                     -- docs/**/*.png++cabal-version:       2.0+source-repository head+  type:     git+  location: https://github.com/noinia/hgeometry+++library+  ghc-options: -O2 -Wall -fno-warn-unticked-promoted-constructors -fno-warn-type-defaults++  exposed-modules:+                    -- * Graph Algorithms+                    Algorithms.Graph.DFS+                    Algorithms.Graph.MST+++                    Algorithms.StringSearch.KMP++                    -- * General Data Types+                    Data.UnBounded+                    Data.Intersection+                    Data.Range+                    Data.Ext+                    Data.LSeq+                    Data.CircularSeq+                    Data.Sequence.Util+                    Data.BinaryTree+                    Data.BinaryTree.Zipper++                    Data.CircularList.Util+                    Data.BalBST+                    Data.OrdSeq+                    Data.SlowSeq+                    Data.Tree.Util+                    Data.Util++                    Data.DynamicOrd+                    Data.Set.Util++                    -- * Planar Graphs+                    Data.Permutation+                    Data.PlanarGraph+                    Data.PlanarGraph.AdjRep+                    Data.PlanarGraph.IO+                    Data.PlanarGraph.Dart+                    Data.PlanarGraph.Core+                    Data.PlanarGraph.Dual+                    Data.PlanarGraph.EdgeOracle++                    -- * Other+                    System.Random.Shuffle+                    Control.Monad.State.Persistent+                    Data.Yaml.Util++  other-modules:++  -- other-extensions:+  build-depends:+                base                    >= 4.11      &&     < 5+              , bifunctors              >= 4.1+              , bytestring              >= 0.10+              , containers              >= 0.5.9+              , dlist                   >= 0.7+              , lens                    >= 4.2+              , contravariant           >= 1.5+              , semigroupoids           >= 5+              , semigroups              >= 0.18+              , singletons              >= 2.0+              , vinyl                   >= 0.10+              , deepseq                 >= 1.1+              , fingertree              >= 0.1+              , MonadRandom             >= 0.5+              , QuickCheck              >= 2.5+              , quickcheck-instances    >= 0.3+              , reflection              >= 2.1++              , vector                  >= 0.11+              , data-clist              >= 0.1.2.3+              , vector-builder          >= 0.3.7++              , aeson                   >= 1.0+              , yaml                    >= 0.8+              , text                    >= 1.1.1.0++              , mtl+              , template-haskell+++++  hs-source-dirs: src+                  -- examples/demo++  default-language:    Haskell2010++  default-extensions: TypeFamilies+                    , GADTs+                    , KindSignatures+                    , DataKinds+                    , TypeOperators+                    , ConstraintKinds+                    , PolyKinds+                    , RankNTypes+                    , TypeApplications+                    , ScopedTypeVariables++                    , PatternSynonyms+                    , TupleSections+                    , LambdaCase+                    , ViewPatterns++                    , StandaloneDeriving+                    , GeneralizedNewtypeDeriving+                    , DeriveFunctor+                    , DeriveFoldable+                    , DeriveTraversable+                    , DeriveGeneric+                    , AutoDeriveTypeable+++                    , FlexibleInstances+                    , FlexibleContexts+                    , MultiParamTypeClasses++test-suite doctests+  type:          exitcode-stdio-1.0+  ghc-options:   -threaded+  main-is:       doctests.hs+  build-depends: base+               , doctest             >= 0.8+--               , doctest-discover++  default-language:    Haskell2010++test-suite hspec+  type:                 exitcode-stdio-1.0+  default-language:     Haskell2010+  hs-source-dirs:       test+  main-is:              Spec.hs+  ghc-options:   -fno-warn-unticked-promoted-constructors+                 -fno-warn-partial-type-signatures+                 -fno-warn-missing-signatures++  build-tool-depends: hspec-discover:hspec-discover++  other-modules: Algorithms.StringSearch.KMPSpec+                 Data.RangeSpec+                 Data.EdgeOracleSpec+                 Data.PlanarGraphSpec+                 Data.OrdSeqSpec+                 Data.CircularSeqSpec+++  build-depends:        base+                      , hspec                   >= 2.1+                      , QuickCheck              >= 2.5+                      , quickcheck-instances    >= 0.3+                      , approximate-equality    >= 1.1.0.2+                      , hgeometry-combinatorial+                      , lens+                      , data-clist+                      , linear+                      , bytestring+                      , vinyl+                      , semigroups+                      , vector+                      , containers+                      , random+                      , singletons+                      , filepath+                      , directory+                      , yaml+                      , MonadRandom++  default-extensions: TypeFamilies+                    , GADTs+                    , KindSignatures+                    , DataKinds+                    , TypeOperators+                    , ConstraintKinds+                    , PolyKinds+                    , RankNTypes+                    , TypeApplications+                    , ScopedTypeVariables+++                    , PatternSynonyms+                    , ViewPatterns+                    , LambdaCase+                    , TupleSections+++                    , StandaloneDeriving+                    , GeneralizedNewtypeDeriving+                    , DeriveFunctor+                    , DeriveFoldable+                    , DeriveTraversable++                    , AutoDeriveTypeable++                    , FlexibleInstances+                    , FlexibleContexts+                    , MultiParamTypeClasses+                    , OverloadedStrings
+ src/Algorithms/Graph/DFS.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE ScopedTypeVariables #-}+module Algorithms.Graph.DFS where++import           Control.Monad.ST (ST,runST)+import           Data.Maybe+import           Data.PlanarGraph+import           Data.Tree+import qualified Data.Vector as V+import qualified Data.Vector.Generic as GV+import qualified Data.Vector.Unboxed.Mutable as UMV+++-- | DFS on a planar graph.+--+-- Running time: \(O(n)\)+--+-- Note that since our planar graphs are always connected there is no need need+-- for dfs to take a list of start vertices.+dfs  :: forall s w v e f.+      PlanarGraph s w v e f -> VertexId s w -> Tree (VertexId s w)+dfs g = dfs' (adjacencyLists g)++-- | Adjacency list representation of a graph: for each vertex we simply list+-- all connected neighbours.+type AdjacencyLists s w = V.Vector [VertexId s w]++-- | Transform into adjacencylist representation+adjacencyLists   :: PlanarGraph s w v e f -> AdjacencyLists s w+adjacencyLists g = V.toList . flip neighboursOf g <$> vertices' g++-- | DFS, from a given vertex, on a graph in AdjacencyLists representation.+--+-- Running time: \(O(n)\)+dfs'          :: forall s w. AdjacencyLists s w -> VertexId s w -> Tree (VertexId s w)+dfs' g start = runST $ do+                 bv     <- UMV.replicate n False -- bit vector of marks+                 -- start will be unvisited, thus the fromJust is safe+                 fromJust <$> dfs'' bv start+  where+    n = GV.length g++    neighs              :: VertexId s w -> [VertexId s w]+    neighs (VertexId u) = g GV.! u++    visit   bv (VertexId i) = UMV.write bv i True+    visited bv (VertexId i) = UMV.read  bv i+    dfs''      :: UMV.MVector s' Bool -> VertexId s w+               -> ST s' (Maybe (Tree (VertexId s w)))+    dfs'' bv u = visited bv u >>= \case+                   True  -> pure Nothing+                   False -> do+                              visit bv u+                              Just . Node u . catMaybes <$> mapM (dfs'' bv) (neighs u)
+ src/Algorithms/Graph/MST.hs view
@@ -0,0 +1,152 @@+{-# LANGUAGE ScopedTypeVariables #-}+module Algorithms.Graph.MST( mst+                           , mstEdges+                           , makeTree+                           ) where++import           Algorithms.Graph.DFS (AdjacencyLists, dfs')+import           Control.Monad (forM_, when, filterM)+import           Control.Monad.ST (ST,runST)+import qualified Data.List as L+import           Data.PlanarGraph+import           Data.Tree+import qualified Data.Vector as V+import qualified Data.Vector.Mutable as MV+import qualified Data.Vector.Unboxed.Mutable as UMV++--------------------------------------------------------------------------------+++-- | Minimum spanning tree of the edges. The result is a rooted tree, in which+-- the nodes are the vertices in the planar graph together with the edge weight+-- of the edge to their parent. The root's weight is zero.+--+-- The algorithm used is Kruskal's.+--+-- running time: \(O(n \log n)\)+mst   :: Ord e => PlanarGraph s w v e f -> Tree (VertexId s w)+mst g = makeTree g $ mstEdges g+  -- TODO: Add edges/darts to the output somehow.++-- | Computes the set of edges in the Minimum spanning tree+--+-- running time: \(O(n \log n)\)+mstEdges   :: Ord e => PlanarGraph s w v e f -> [Dart s]+mstEdges g = runST $ do+          uf <- new (numVertices g)+          filterM (\e -> union uf (headOf e g) (tailOf e g)) edges''+  where+    edges'' = map fst . L.sortOn snd . V.toList $ edges g+++-- | Given an underlying planar graph, and a set of edges that form a tree,+-- create the actual tree.+--+-- pre: the planar graph has at least one vertex.+makeTree   :: forall s w v e f.+              PlanarGraph s w v e f -> [Dart s] -> Tree (VertexId s w)+makeTree g = flip dfs' start . mkAdjacencyLists+  where+    n = numVertices g+    start = V.head $ vertices' g++    append                  :: MV.MVector s' [a] -> VertexId s w -> a -> ST s' ()+    append v (VertexId i) x = MV.read v i >>= MV.write v i . (x:)++    mkAdjacencyLists         :: [Dart s] -> AdjacencyLists s w+    mkAdjacencyLists edges'' = V.create $ do+                                 vs <- MV.replicate n []+                                 forM_ edges'' $ \e -> do+                                   let u = headOf e g+                                       v = tailOf e g+                                   append vs u v+                                   append vs v u+                                 pure vs+--------------------------------------------------------------------------------++-- | Union find DS+newtype UF s a = UF { _unUF :: UMV.MVector s (Int,Int) }++new   :: Int -> ST s (UF s a)+new n = do+          v <- UMV.new n+          forM_ [0..n-1] $ \i ->+            UMV.write v i (i,0)+          pure $ UF v++-- | Union the components containing x and y. Returns weather or not the two+-- components were already in the same component or not.+union               :: (Enum a, Eq a) => UF s a -> a -> a -> ST s Bool+union uf@(UF v) x y = do+                        (rx,rrx) <- find' uf x+                        (ry,rry) <- find' uf y+                        let b = rx /= ry+                            rx' = fromEnum rx+                            ry' = fromEnum ry+                        when b $ case rrx `compare` rry of+                            LT -> UMV.write v rx'  (ry',rrx)+                            GT -> UMV.write v ry' (rx',rry)+                            EQ -> do UMV.write v ry' (rx',rry)+                                     UMV.write v rx' (rx',rrx+1)+                        pure b+++-- | Get the representative of the component containing x+-- find    :: (Enum a, Eq a) => UF s a -> a -> ST s a+-- find uf = fmap fst . find' uf++-- | get the representative (and its rank) of the component containing x+find'             :: (Enum a, Eq a) => UF s a -> a -> ST s (a,Int)+find' uf@(UF v) x = do+                      (p,r) <- UMV.read v (fromEnum x) -- get my parent+                      if toEnum p == x then+                        pure (x,r) -- I am a root+                      else do+                        rt@(j,_) <- find' uf (toEnum p)  -- get the root of my parent+                        UMV.write v (fromEnum x) (fromEnum j,r)   -- path compression+                        pure rt+++--------------------------------------------------------------------------------++-- partial implementation of Prims+-- mst g = undefined++-- -- | runs MST with a given root+-- mstFrom     :: (Ord e, Monoid e)+--             => VertexId s w -> PlanarGraph s w v e f -> Tree (VertexId s w, e)+-- mstFrom r g = prims initialQ (Node (r,mempty) [])+--   where+--     update' k p q = Q.adjust (const p) k q++--     -- initial Q has the value of the root set to the zero element, and has no+--     -- parent. The others are all set to Top (and have no parent yet)+--     initialQ = update' r (ValT (mempty,Nothing))+--              . GV.foldr (\v q -> Q.insert v (Top,Nothing) q) Q.empty $ vertices g++--     prims qq t = case Q.minView qq of+--       Nothing -> t+--       Just (v Q.:-> (w,p), q) -> prims $++--------------------------------------------------------------------------------+-- Testing Stuff++-- testG = planarGraph' [ [ (Dart aA Negative, "a-")+--                        , (Dart aC Positive, "c+")+--                        , (Dart aB Positive, "b+")+--                        , (Dart aA Positive, "a+")+--                        ]+--                      , [ (Dart aE Negative, "e-")+--                        , (Dart aB Negative, "b-")+--                        , (Dart aD Negative, "d-")+--                        , (Dart aG Positive, "g+")+--                        ]+--                      , [ (Dart aE Positive, "e+")+--                        , (Dart aD Positive, "d+")+--                        , (Dart aC Negative, "c-")+--                        ]+--                      , [ (Dart aG Negative, "g-")+--                        ]+--                      ]+--   where+--     (aA:aB:aC:aD:aE:aG:_) = take 6 [Arc 0..]
+ src/Algorithms/StringSearch/KMP.hs view
@@ -0,0 +1,67 @@+--------------------------------------------------------------------------------+-- |+-- Module      :  Algorithms.StringSearch.KMP+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Implementation of Knuth-Morris-Pratt String-searching+-- algorithm. The exposition is based on that of Goodrich and+-- Tamassia in "Data Structures and Algorithms in Java 2nd Edition".+--+--------------------------------------------------------------------------------+module Algorithms.StringSearch.KMP( isSubStringOf+                                  , kmpMatch+                                  , buildFailureFunction+                                  ) where++import           Control.Monad.ST+import qualified Data.Vector as V+import           Data.Vector.Generic ((!))+import qualified Data.Vector.Unboxed as UV+import qualified Data.Vector.Unboxed.Mutable as UMV+import qualified VectorBuilder.Builder as Builder+import qualified VectorBuilder.Vector as Builder+++--------------------------------------------------------------------------------++-- | Constructs the failure function.+--+-- running time: \(O(m)\).+buildFailureFunction   :: forall a. Eq a => V.Vector a -> UV.Vector Int+buildFailureFunction p = UV.create $ do+                           f <- UMV.new m+                           go f 1 0+   where+     m = V.length p+     go                        :: UMV.MVector s Int -> Int -> Int -> ST s (UMV.MVector s Int)+     go f i j | i == m         = pure f+              | p ! j == p ! i = UMV.write f i (j+1) >>  go f (i+1) (j+1)+              | j > 0          = UMV.read  f (j-1)   >>= go f i+              | otherwise      = UMV.write f i 0     >>  go f (i+1) 0++-- | Test if the first argument, the pattern p, occurs as a consecutive subsequence in t.+--+-- running time: \(O(n+m)\), where p has length \(m\) and t has length \(n\).+isSubStringOf       :: (Eq a, Foldable p, Foldable t) => p a -> t a -> Maybe Int+p `isSubStringOf` t = kmpMatch (Builder.build . Builder.foldable $ p)+                               (Builder.build . Builder.foldable $ t)+++-- | Test if the first argument, the pattern p, occurs as a consecutive subsequence in t.+--+-- running time: \(O(n+m)\), where p has length \(m\) and t has length \(n\).+kmpMatch                 :: Eq a => V.Vector a -> V.Vector a -> Maybe Int+kmpMatch p t | m == 0    = Just 0+             | otherwise = kmp 0 0+  where+    m = V.length p+    n = V.length t+    f = buildFailureFunction p++    kmp i j | i == n         = Nothing+            | p ! j == t ! i = if j == m - 1 then Just (i - m + 1)+                                             else kmp (i+1) (j+1)+            | j > 0          = kmp i     (f ! (j - 1))+            | otherwise      = kmp (i+1) 0           -- j == 0
+ src/Control/Monad/State/Persistent.hs view
@@ -0,0 +1,48 @@+module Control.Monad.State.Persistent( PersistentStateT+                                     , PersistentState+                                     , store+                                     , runPersistentStateT+                                     , runPersistentState+                                     ) where++import Control.Monad.State+import Control.Monad.Identity(Identity(..))+import Data.List.NonEmpty(NonEmpty(..),(<|),toList)++--------------------------------------------------------------------------------++-- | A State monad that can store earlier versions of the state.+newtype PersistentStateT s m a =+  PersistentStateT (StateT (NonEmpty s) m a)+  deriving (Functor,Applicative,Monad)+           -- We store all the versions in reverse order++-- | Create a snapshot of the current state and add it to the list of states+-- that we store.+store :: Monad m => PersistentStateT s m ()+store = PersistentStateT $ do+  ss@(s :| _) <- get+  put (s <| ss)+++instance Monad m => MonadState s (PersistentStateT s m) where+  state f = PersistentStateT $ do+              (s :| os) <- get+              let (x,s') = f s+              put (s' :| os)+              return x++-- | run a persistentStateT, returns a triplet with the value, the last state+-- and a list of all states (including the last one) in chronological order+runPersistentStateT :: Functor m => PersistentStateT s m a -> s -> m (a,s,[s])+runPersistentStateT (PersistentStateT act) initS = f <$> runStateT act (initS :| [])+  where+    f (x,ss@(s :| _)) = (x, s, reverse $ toList ss)+++--------------------------------------------------------------------------------++type PersistentState s = PersistentStateT s Identity++runPersistentState     :: PersistentState s a -> s -> (a,s,[s])+runPersistentState act = runIdentity . runPersistentStateT act
+ src/Data/BalBST.hs view
@@ -0,0 +1,378 @@+{-# LANGUAGE RecordWildCards #-}+module Data.BalBST where++import           Control.Applicative((<|>))+import           Data.Bifunctor+import           Data.Function (on)+import           Data.Functor.Contravariant+import qualified Data.List as L+import           Data.Maybe+import qualified Data.Tree as T+import           Prelude hiding (lookup,null)++--------------------------------------------------------------------------------++-- | Describes how to search in a tree+data TreeNavigator k a = Nav { goLeft     :: a -> k -> Bool+                             , extractKey :: a -> a -> k+                             }++instance Contravariant (TreeNavigator k) where+  contramap f (Nav gL eK) = Nav (\a k -> gL (f a) k) (\x y -> eK (f x) (f y))+++ordNav :: Ord a => TreeNavigator a a+ordNav = Nav (<=) min+++ordNavBy   :: Ord b => (a -> b) ->  TreeNavigator b a+ordNavBy f = Nav (\x k -> f x <= k) (min `on` f)+++-- instance Functor (TreeNavigator k) where+--   fmap f Nav{..} = Nav (\b k -> )++++-- | A balanced binary search tree+data BalBST k a = BalBST { nav    :: !(TreeNavigator k a)+                         , toTree :: !(Tree k a)+                         }++instance (Show k, Show a) => Show (BalBST k a) where+  show (BalBST _ t) = "BalBST (" ++ show t ++ ")"+++data Color = Red | Black deriving (Show,Read,Eq,Ord)++type Height = Int++-- Red-Black tree with values in the leaves+data Tree k a = Empty+              | Leaf !a+              | Node !Color !Height (Tree k a) !k (Tree k a) deriving (Show,Eq)++--------------------------------------------------------------------------------++-- | Creates an empty BST+empty   :: TreeNavigator k a -> BalBST k a+empty n = BalBST n Empty+++-- | \(O(n\log n)\)+fromList :: TreeNavigator k a -> [a] -> BalBST k a+fromList n = foldr insert (empty n)++fromList' :: Ord a => [a] -> BalBST a a+fromList' = fromList ordNav+++-- -- | \(O(n)\)+-- fromAscList :: TreeNavigator k a -> [a] -> BalBST k a+-- fromAscList = undefined+++--------------------------------------------------------------------------------++-- | Check if the tree is empty+null                  :: BalBST k a -> Bool+null (BalBST _ Empty) = True+null _                = False++-- | Test if an element occurs in the BST.+-- \(O(\log n)\)+lookup :: Eq a => a -> BalBST k a -> Maybe a+lookup x (BalBST Nav{..} t) = lookup' t+  where+    lookup' Empty            = Nothing+    lookup' (Leaf y)         = if x == y then Just y else Nothing+    lookup' (Node _ _ l k r)+      | goLeft x k           = lookup' l+      | otherwise            = lookup' r++-- | \(O(\log n)\)+member   :: Eq a => a -> BalBST k a -> Bool+member x = isJust . lookup x++-- | Search for the Predecessor+-- \(O(\log n)\)+lookupLE :: Ord k => k -> BalBST k a -> Maybe a+lookupLE kx (BalBST n@Nav{..} t) = lookup' t+  where+    lookup' Empty            = Nothing+    lookup' (Leaf y)         = if goLeft y kx then Just y else Nothing+    lookup' (Node _ _ l k r)+      | kx <= k              = lookup' l+      | otherwise            = lookup' r <|> lookupMax (BalBST n l)+++-- | Insert an element in the BST.+--+-- \(O(\log n)\)+insert :: a -> BalBST k a -> BalBST k a+insert x (BalBST n@Nav{..} t) = BalBST n (blacken $ insert' t)+  where+    insert' Empty    = Leaf x+    insert' (Leaf y) = let k     = extractKey x y+                           (l,r) = if goLeft x k then (x,y) else (y,x)+                       in red 2 (Leaf l) k (Leaf r)+    insert' (Node c h l k r)+      | goLeft  x k  = balance c h (insert' l) k r+      | otherwise    = balance c h l           k (insert' r)++++-- delete = undefined++-- | Delete (one occurance of) an element.+-- \(O(\log n)\)+delete                        :: Eq a => a -> BalBST k a -> BalBST k a+delete x t = let Split l _ r = split x t+                 n           = nav t+             in BalBST n $ joinWith n l r+++-- (BalBST n@Nav{..} t) = delete' t+--   where+--     delete' Empty      = Empty+--     delete' l@(Leaf y) = if x == y then Empty else l+--     delete' (Node c h l k r)+--       | goLeft x k     =+++--------------------------------------------------------------------------------+++-- | Extract the minimum from the tree+-- \(O(\log n)\)+minView              :: BalBST k a -> Maybe (a, Tree k a)+minView (BalBST n t) = minView' t+  where+    minView' Empty            = Nothing+    minView' (Leaf x)         = Just (x,Empty)+    minView' (Node _ _ l _ r) = fmap (flip (joinWith n) r) <$> minView' l++lookupMin :: BalBST k b -> Maybe b+lookupMin = fmap fst . maxView++-- | Extract the maximum from the tree+-- \(O(\log n)\)+maxView              :: BalBST k a -> Maybe (a, Tree k a)+maxView (BalBST n t) = maxView' t+  where+    maxView' Empty            = Nothing+    maxView' (Leaf x)         = Just (x,Empty)+    maxView' (Node _ _ l _ r) = fmap (joinWith n l) <$> maxView' r++lookupMax :: BalBST k b -> Maybe b+lookupMax = fmap fst . maxView+++-- | Joins two BSTs. Assumes that the ranges are disjoint. It takes the left Tree nav+--+-- \(O(\log n)\)+join                           :: BalBST k a -> BalBST k a -> BalBST k a+join (BalBST n l) (BalBST _ r) = BalBST n $ joinWith n l r++-- | Joins two BSTs' with a specific Tree Navigator+--+-- \(O(\log n)\)+joinWith               :: TreeNavigator k a -> Tree k a -> Tree k a -> Tree k a+joinWith Nav{..} tl tr+    | lh >= rh         = blacken $ joinL tl tr+    | otherwise        = blacken $ joinR tl tr+  where+    rh = height tr+    lh = height tl++    joinL Empty      _           = Empty+    joinL l          Empty       = l+    joinL l@(Leaf x) r@(Leaf y)  = red 2 l (extractKey x y) r+    joinL l@(Node c h ll k lr) r+      | h == rh                  = let lm = unsafeMax lr+                                       rm = unsafeMin r+                                   in balance Red (h+1) l (extractKey lm rm) r+      | otherwise                = balance c h ll k (joinL lr r)+        -- lh >= rh+    joinL _ _ = error "joinL. absurd"+++    joinR _          Empty       = Empty+    joinR Empty      r           = r++    joinR l@(Leaf x) r@(Leaf y)  = red 2 l (extractKey x y) r+    joinR l r@(Node c h rl k rr)+      | h == lh                  = let lm = unsafeMax l+                                       rm = unsafeMin rl+                                   in balance Red (h+1) l (extractKey lm rm) r+      | otherwise                = balance c h (joinR l rl) k rr+        -- lh >= rh+    joinR _ _ = error "joinR absurd"+++--------------------------------------------------------------------------------+-- | Splitting and extracting++-- | A pair that is strict in its first argument and lazy in the second.+data Pair a b = Pair { fst' :: !a+                     , snd' :: b+                     } deriving (Show,Eq,Functor,Foldable,Traversable)+++collect        :: b -> [Pair a b] -> Pair [a] b+collect def [] = Pair [] def+collect _   xs = Pair (map fst' xs) (snd' $ last xs)+++-- | Extract a prefix from the tree, i.e. a repeated 'minView'+--+-- \(O(\log n +k)\), where \(k\) is the size of the extracted part+extractPrefix                      :: BalBST k a -> [Pair a (Tree k a)]+extractPrefix (BalBST n@Nav{..} t) = extractPrefix' t+  where+    extractPrefix' Empty            = []+    extractPrefix' (Leaf x)         = [Pair x Empty]+    extractPrefix' (Node _ _ l _ r) = ls ++ extractPrefix' r+      where+        ls = map (fmap $ flip (joinWith n) r) $ extractPrefix' l++-- | Extract a suffix from the tree, i.e. a repeated 'minView'+--+-- \(O(\log n +k)\), where \(k\) is the size of the extracted part+extractSuffix                      :: BalBST k a -> [Pair a (Tree k a)]+extractSuffix (BalBST n@Nav{..} t) = extract t+  where+    extract Empty            = []+    extract (Leaf x)         = [Pair x Empty]+    extract (Node _ _ l _ r) = rs ++ extract l+      where+        rs = map (fmap $ joinWith n l) $ extract r++-- | Result of splititng a tree+data Split a b = Split a !b a deriving (Show,Eq)++-- | Splits the tree at x. Note that if x occurs more often, no guarantees are+-- given which one is found.+--+-- \(O(\log n)\)+split                        :: Eq a => a -> BalBST k a -> Split (Tree k a) (Maybe a)+split x (BalBST n@Nav{..} t) = split' t+  where+    split' Empty                  = Split Empty Nothing Empty+    split' l@(Leaf y)+      | x == y                    = Split Empty (Just y) Empty+      | goLeft x (extractKey x y) = Split l     Nothing  Empty+      | otherwise                 = Split Empty Nothing  l+    split' (Node _ _ l k r)+      | goLeft x k                = let Split l' mx r' = split' l+                                    in Split l' mx (joinWith n r' r)+      | otherwise                 = let Split l' mx r' = split' r+                                    in Split (joinWith n l l') mx r'++-- | split based on a monotonic predicate+--+-- \(O(\log n)\)+splitMonotone                        :: (a -> Bool) -> BalBST k a+                                     -> (BalBST k a, BalBST k a)+splitMonotone p (BalBST n@Nav{..} t) = bimap (BalBST n) (BalBST n) $ split' t+  where+    split' Empty        = (Empty,Empty)+    split' l@(Leaf y)+      | p y             = (Empty,l)+      | otherwise       = (l,Empty)+    split' (Node _ _ l _ r)+      | p (unsafeMin r) = let (l',m) = split' l in (l',joinWith n m r)+      | otherwise       = let (m,r') = split' r in (joinWith n l m, r')+++-- | Splits at a given monotone predicate p, and then selects everything that+-- satisfies the predicate sel.+splitExtract           :: (a -> Bool) -> (a -> Bool) -> BalBST k a+                       -> Split (BalBST k a) ([a],[a])+splitExtract p sel bst = Split (BalBST n before) (reverse mid1,mid2) (BalBST n after)+  where+    n                = nav bst+    (before',after') = splitMonotone p bst++    extract def = collect def . L.takeWhile (sel . fst')++    Pair mid1 before = extract (toTree before') $ extractSuffix before'+    Pair mid2 after  = extract (toTree after')  $ extractPrefix after'+++--------------------------------------------------------------------------------+++data T k a = Internal !Color !Height !k | Val !a deriving (Show,Eq,Ord)++toRoseTree :: Tree k a -> Maybe (T.Tree (T k a))+toRoseTree Empty            = Nothing+toRoseTree (Leaf x)         = Just $ T.Node (Val x) []+toRoseTree (Node c h l k r) = Just $ T.Node (Internal c h k) (mapMaybe toRoseTree [l,r])+++showTree :: (Show k, Show a) => BalBST k a -> String+showTree = maybe "Empty" T.drawTree . fmap (fmap show) . toRoseTree . toTree++-- | Get the minimum in the tree. Errors when the tree is empty+--+-- \(O(\log n)\)+unsafeMin                  :: Tree k a -> a+unsafeMin (Leaf x)         = x+unsafeMin (Node _ _ l _ _) = unsafeMin l+unsafeMin _                = error "unsafeMin: Empty"++-- | Get the maximum in the tree. Errors when the tree is empty+--+-- \(O(\log n)\)+unsafeMax                  :: Tree k a -> a+unsafeMax (Leaf x)         = x+unsafeMax (Node _ _ _ _ r) = unsafeMax r+unsafeMax _                = error "unsafeMax: Empty"++-- | Extract all elements in the tree+--+-- \(O(n)\)+toList :: BalBST k a -> [a]+toList = toList' . toTree++-- | Extract all elements in the tree+--+-- \(O(n)\)+toList'                  :: Tree k a -> [a]+toList' Empty            = []+toList' (Leaf x)         = [x]+toList' (Node _ _ l _ r) = toList' l ++ toList' r+++--------------------------------------------------------------------------------+-- * Helper stuff++black :: Height -> Tree k a -> k -> Tree k a -> Tree k a+black = Node Black++red :: Height -> Tree k a -> k -> Tree k a -> Tree k a+red = Node Red+++blacken                    :: Tree k a -> Tree k a+blacken (Node Red h l k r) = Node Black h l k r+blacken t                  = t++-- | rebalance the tree+balance  :: Color -> Height -> Tree k a -> k -> Tree k a -> Tree k a+balance Black h (Node Red _ (Node Red _ a x b) y c) z d = mkNode h a x b y c z d+balance Black h (Node Red _ a x (Node Red _ b y c)) z d = mkNode h a x b y c z d+balance Black h a x (Node Red _ (Node Red _ b y c) z d) = mkNode h a x b y c z d+balance Black h a x (Node Red _ b y (Node Red _ c z d)) = mkNode h a x b y c z d+balance co h a x b                                      = Node co h a x b++mkNode                 :: Height+                       -> Tree k a -> k -> Tree k a -> k -> Tree k a  -> k -> Tree k a+                       -> Tree k a+mkNode h a x b y c z d = red h (black h a x b) y (black h c z d)++height                  :: Tree k a -> Height+height Empty            = 0+height (Leaf _)         = 1+height (Node _ h _ _ _) = h
+ src/Data/BinaryTree.hs view
@@ -0,0 +1,222 @@+{-# Language DeriveFunctor#-}+{-# Language FunctionalDependencies #-}+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.BinaryTree+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Several types of Binary trees.+--+--------------------------------------------------------------------------------+module Data.BinaryTree where++import           Control.DeepSeq+import           Data.Bifunctor.Apply+import           Data.List.NonEmpty (NonEmpty(..),(<|))+import qualified Data.List.NonEmpty as NonEmpty+import           Data.Maybe (mapMaybe)+import           Data.Semigroup.Foldable+import qualified Data.Tree as Tree+import qualified Data.Vector as V+import           GHC.Generics (Generic)+import           Test.QuickCheck++--------------------------------------------------------------------------------++-- | Binary tree that stores its values (of type a) in the leaves. Internal+-- nodes store something of type v.+data BinLeafTree v a = Leaf !a+                     | Node (BinLeafTree v a) !v (BinLeafTree v a)+                     deriving (Show,Read,Eq,Ord,Functor,Generic)++instance (NFData v, NFData a) => NFData (BinLeafTree v a)++class Semigroup v => Measured v a | a -> v where+  measure :: a -> v++-- | smart constructor+node     :: Measured v a => BinLeafTree v a -> BinLeafTree v a -> BinLeafTree v a+node l r = Node l (measure l <> measure r) r+++instance Bifunctor BinLeafTree where+  bimap f g = \case+    Leaf x     -> Leaf $ g x+    Node l k r -> Node (bimap f g l) (f k) (bimap f g r)++instance Measured v a => Measured v (BinLeafTree v a) where+  measure (Leaf x)     = measure x+  measure (Node _ v _) = v+++instance Foldable (BinLeafTree v) where+  foldMap f (Leaf a)     = f a+  foldMap f (Node l _ r) = foldMap f l `mappend` foldMap f r++instance Foldable1 (BinLeafTree v)++instance Traversable (BinLeafTree v) where+  traverse f (Leaf a)     = Leaf <$> f a+  traverse f (Node l v r) = Node <$> traverse f l <*> pure v <*> traverse f r++instance Measured v a => Semigroup (BinLeafTree v a) where+  l <> r = node l r++instance (Arbitrary a, Arbitrary v) => Arbitrary (BinLeafTree v a) where+  arbitrary = sized f+    where f n | n <= 0    = Leaf <$> arbitrary+              | otherwise = do+                              l <- choose (0,n-1)+                              Node <$> f l <*> arbitrary <*> f (n-l-1)++-- | Create a balanced tree, i.e. a tree of height \(O(\log n)\) with the+-- elements in the leaves.+--+-- \(O(n)\) time.+asBalancedBinLeafTree :: NonEmpty a -> BinLeafTree Size (Elem a)+asBalancedBinLeafTree = repeatedly merge . fmap (Leaf . Elem)+  where+    repeatedly _ (t :| []) = t+    repeatedly f ts        = repeatedly f $ f ts++    merge ts@(_ :| [])  = ts+    merge (l :| r : []) = node l r :| []+    merge (l :| r : ts) = node l r <| (merge $ NonEmpty.fromList ts)+-- -- the implementation below produces slightly less high trees, but runs in+-- -- \(O(n \log n)\) time, as on every level it traverses the list passed down.+-- asBalancedBinLeafTree ys = asBLT (length ys') ys' where ys' = toList ys++--     asBLT _ [x] = Leaf (Elem x)+--     asBLT n xs  = let h       = n `div` 2+--                       (ls,rs) = splitAt h xs+--                   in node (asBLT h ls) (asBLT (n-h) rs)++-- | Given a function to combine internal nodes into b's and leafs into b's,+-- traverse the tree bottom up, and combine everything into one b.+foldUp                  :: (b -> v -> b -> b) -> (a -> b) -> BinLeafTree v a -> b+foldUp _ g (Leaf x)     = g x+foldUp f g (Node l x r) = f (foldUp f g l) x (foldUp f g r)+++-- | Traverses the tree bottom up, recomputing the assocated values.+foldUpData     :: (w -> v -> w -> w) -> (a -> w) -> BinLeafTree v a -> BinLeafTree w a+foldUpData f g = foldUp f' Leaf+  where+    f' l v r = Node l (f (access' l) v (access' r)) r++    access' (Leaf x)     = g x+    access' (Node _ v _) = v++-- | Takes two trees, that have the same structure, and uses the provided+-- functions to "zip" them together+zipExactWith                                  :: (u -> v -> w)+                                              -> (a -> b -> c)+                                              -> BinLeafTree u a+                                              -> BinLeafTree v b+                                              -> BinLeafTree w c+zipExactWith _ g (Leaf x)     (Leaf y)        = Leaf (x `g` y)+zipExactWith f g (Node l m r) (Node l' m' r') = Node (zipExactWith f g l l')+                                                     (m `f` m')+                                                     (zipExactWith f g r r')+zipExactWith _ _ _            _               =+    error "zipExactWith: tree structures not the same "++newtype Size = Size Int deriving (Show,Read,Eq,Num,Integral,Enum,Real,Ord,Generic,NFData)++instance Semigroup Size where+  x <> y = x + y++instance Monoid Size where+  mempty = Size 0+  mappend = (<>)++newtype Elem a = Elem { _unElem :: a }+               deriving (Show,Read,Eq,Ord,Functor,Foldable,Traversable)++instance Measured Size (Elem a) where+  measure _ = 1+++data Sized a = Sized !Size a+             deriving (Show,Eq,Ord,Functor,Foldable,Traversable,Generic)+instance NFData a => NFData (Sized a)++instance Semigroup a => Semigroup (Sized a) where+  (Sized i a) <> (Sized j b) = Sized (i <> j) (a <> b)++instance Monoid a => Monoid (Sized a) where+  mempty = Sized mempty mempty+  (Sized i a) `mappend` (Sized j b) = Sized (i <> j) (a `mappend` b)++-- instance Semigroup a => Measured Size (Sized a) where+--   measure (Sized i _) = i+++--------------------------------------------------------------------------------+-- * Converting into a Data.Tree++data RoseElem v a = InternalNode v | LeafNode a deriving (Show,Eq,Functor)++toRoseTree              :: BinLeafTree v a -> Tree.Tree (RoseElem v a)+toRoseTree (Leaf x)     = Tree.Node (LeafNode x) []+toRoseTree (Node l v r) = Tree.Node (InternalNode v) (map toRoseTree [l,r])+++drawTree :: (Show v, Show a) => BinLeafTree v a -> String+drawTree = Tree.drawTree . fmap show . toRoseTree+++--------------------------------------------------------------------------------+-- * Internal Node Tree++-- | Binary tree in which we store the values of type a in internal nodes.+data BinaryTree a = Nil+                  | Internal (BinaryTree a) !a (BinaryTree a)+                  deriving (Show,Read,Eq,Ord,Functor,Foldable,Traversable,Generic)+instance NFData a => NFData (BinaryTree a)++instance Arbitrary a => Arbitrary (BinaryTree a) where+  arbitrary = sized f+    where f n | n <= 0    = pure Nil+              | otherwise = do+                              l <- choose (0,n-1)+                              Internal <$> f l <*> arbitrary <*> f (n-l-1)++-- | Get the element stored at the root, if it exists+access                  :: BinaryTree a -> Maybe a+access Nil              = Nothing+access (Internal _ x _) = Just x++-- | Create a balanced binary tree.+--+-- running time: \(O(n)\)+asBalancedBinTree :: [a] -> BinaryTree a+asBalancedBinTree = mkTree . V.fromList+  where+    mkTree v = let n = V.length v+                   h = n `div` 2+                   x = v V.! h+               in if n == 0 then Nil+                            else Internal (mkTree $ V.slice 0 h v) x+                                          (mkTree $ V.slice (h+1) (n - h -1) v)++-- | Fold function for folding over a binary tree.+foldBinaryUp                      :: b -> (a -> b -> b -> b)+                                  -> BinaryTree a -> BinaryTree (a,b)+foldBinaryUp _ _ Nil              = Nil+foldBinaryUp e f (Internal l x r) = let l' = foldBinaryUp e f l+                                        r' = foldBinaryUp e f r+                                        g  = maybe e snd . access+                                        b  = f x (g l') (g r')+                                    in Internal l' (x,b) r'++-- | Convert a @BinaryTree@ into a RoseTree+toRoseTree'                  :: BinaryTree a -> Maybe (Tree.Tree a)+toRoseTree' Nil              = Nothing+toRoseTree' (Internal l v r) = Just $ Tree.Node v $ mapMaybe toRoseTree' [l,r]++-- | Draw a binary tree.+drawTree' :: Show a => BinaryTree a -> String+drawTree' = maybe "Nil" (Tree.drawTree . fmap show) . toRoseTree'
+ src/Data/BinaryTree/Zipper.hs view
@@ -0,0 +1,64 @@+module Data.BinaryTree.Zipper where++import Data.BinaryTree++--------------------------------------------------------------------------------++data Ctx a = Top | L (Ctx a) a (BinaryTree a) | R (BinaryTree a) a (Ctx a)+           deriving (Show,Read,Eq,Ord,Functor,Foldable,Traversable)++data BinaryTreeZipper a = Loc (BinaryTree a) (Ctx a)+           deriving (Show,Read,Eq,Ord,Functor,Foldable,Traversable)++-- | Focus on the root+top   :: BinaryTree a -> BinaryTreeZipper a+top t = Loc t Top++-- | Go to the left child+left                            :: BinaryTreeZipper a -> Maybe (BinaryTreeZipper a)+left (Loc (Internal l x r) ctx) = Just $ Loc l (L ctx x r)+left (Loc Nil _)                = Nothing++-- | Go to the right child+right                            :: BinaryTreeZipper a -> Maybe (BinaryTreeZipper a)+right (Loc (Internal l x r) ctx) = Just $ Loc r (R l x ctx)+right (Loc Nil _)                = Nothing++-- | Move to the parent+up                     :: BinaryTreeZipper a -> Maybe (BinaryTreeZipper a)+up (Loc _ Top)         = Nothing+up (Loc l (L ctx x r)) = Just $ Loc (Internal l x r) ctx+up (Loc r (R l x ctx)) = Just $ Loc (Internal l x r) ctx++-- | Navigate to the root+toRoot   :: BinaryTreeZipper a -> BinaryTreeZipper a+toRoot z = toRoot' z (Just z)+  where+    toRoot' z' Nothing   = z'+    toRoot' _  (Just z') = toRoot' z' (up z')+++-- | Returns a list of zippers; one focussed on each node in the tree+visitAll   :: BinaryTree a -> [BinaryTreeZipper a]+visitAll t = visitAll' (top t)+  where+    f           = maybe [] visitAll'+    visitAll' z = z : f (left z) <> f (right z)++-- | Get the value stored at the current node+accessZ           :: BinaryTreeZipper a -> Maybe a+accessZ (Loc t _) = access t+++-- | Returns all subtrees; i.e. every node with all its decendents+subTrees :: BinaryTree a -> [BinaryTree a]+subTrees t = Nil : subTrees' t+  where+    subTrees' Nil                 = []+    subTrees' tt@(Internal l _ r) = tt : subTrees' l <> subTrees' r+++-- | Splits the tree here, returns a pair (innerTree,outerTree)+splitTree             :: BinaryTreeZipper a -> (BinaryTree a, BinaryTree a)+splitTree (Loc t ctx) = let (Loc r _) = toRoot $ Loc Nil ctx+                        in (t, r)
+ src/Data/CircularList/Util.hs view
@@ -0,0 +1,67 @@+module Data.CircularList.Util where++import           Control.Lens+import           Data.Tuple+import qualified Data.CircularList as C+import qualified Data.List as L+++--------------------------------------------------------------------------------++-- $setup+-- >>> let ordList = C.fromList [5,6,10,20,30,1,2,3]++++-- | Given a circular list, whose elements are in increasing order, insert the+-- new element into the Circular list in its sorted order.+--+-- >>> insertOrd 1 C.empty+-- fromList [1]+-- >>> insertOrd 1 $ C.fromList [2]+-- fromList [2,1]+-- >>> insertOrd 2 $ C.fromList [1,3]+-- fromList [1,2,3]+-- >>> insertOrd 31 ordList+-- fromList [5,6,10,20,30,31,1,2,3]+-- >>> insertOrd 1 ordList+-- fromList [5,6,10,20,30,1,1,2,3]+-- >>> insertOrd 4 ordList+-- fromList [5,6,10,20,30,1,2,3,4]+-- >>> insertOrd 11 ordList+-- fromList [5,6,10,11,20,30,1,2,3]+insertOrd :: Ord a => a -> C.CList a -> C.CList a+insertOrd = insertOrdBy compare++-- | Insert an element into an increasingly ordered circular list, with+-- specified compare operator.+insertOrdBy       :: (a -> a -> Ordering) -> a -> C.CList a -> C.CList a+insertOrdBy cmp x = C.fromList . insertOrdBy' cmp x . C.rightElements++-- | List version of insertOrdBy; i.e. the list contains the elements in+-- cirulcar order. Again produces a list that has the items in circular order.+insertOrdBy'         :: (a -> a -> Ordering) -> a -> [a] -> [a]+insertOrdBy' cmp x xs = case (rest, x `cmp` head rest) of+    ([],  _)   -> L.insertBy cmp x pref+    (z:zs, GT) -> (z : L.insertBy cmp x zs) ++ pref+    (_:_,  EQ) -> (x : xs) -- == x : rest ++ pref+    (_:_,  LT) -> rest ++ L.insertBy cmp x pref+  where+    -- split the list at its maximum.+    (pref,rest) = splitIncr cmp xs++-- given a list of elements that is supposedly a a cyclic-shift of a list of+-- increasing items, find the splitting point. I.e. returns a pair of lists+-- (ys,zs) such that xs = zs ++ ys, and ys ++ zs is (supposedly) in sorted+-- order.+splitIncr              :: (a -> a -> Ordering) -> [a] -> ([a],[a])+splitIncr _   []       = ([],[])+splitIncr cmp xs@(x:_) = swap . bimap (map snd) (map snd)+                      . L.break (\(a,b) -> (a `cmp` b) == GT) $ zip (x:xs) xs++-- | Test if the circular list is a cyclic shift of the second list.+-- Running time: O(n), where n is the size of the smallest list+isShiftOf         :: Eq a => C.CList a -> C.CList a -> Bool+xs `isShiftOf` ys = let rest = tail . C.leftElements+                    in maybe False (\xs' -> rest xs' == rest ys) $+                         C.focus ys >>= flip C.rotateTo xs
+ src/Data/CircularSeq.hs view
@@ -0,0 +1,384 @@+module Data.CircularSeq( CSeq+                       , cseq+                       , singleton+                       , fromNonEmpty+                       , fromList++                       , focus+                       , index, adjust+                       , item++                       , rotateL+                       , rotateR+                       , rotateNL, rotateNR++                       , rightElements+                       , leftElements+                       , asSeq++                       , reverseDirection+                       , allRotations++                       , findRotateTo+                       , rotateTo++                       , zipLWith, zipL+                       , zip3LWith+++                       , insertOrd, insertOrdBy+                       , isShiftOf+                       ) where++import           Algorithms.StringSearch.KMP (isSubStringOf)+import           Control.DeepSeq+import           Control.Lens (lens, Lens', bimap)+import qualified Data.Foldable as F+import qualified Data.List as L+import qualified Data.List.NonEmpty as NonEmpty+import           Data.Maybe (listToMaybe, isJust)+import           Data.Semigroup.Foldable+import           Data.Sequence ((|>),(<|),ViewL(..),ViewR(..),Seq)+import qualified Data.Sequence as S+import qualified Data.Traversable as T+import           Data.Tuple (swap)+import           GHC.Generics (Generic)+import           Test.QuickCheck(Arbitrary(..))+import           Test.QuickCheck.Instances ()++--------------------------------------------------------------------------------++-- $setup+-- >>> let ordList = fromList [5,6,10,20,30,1,2,3]+++-- | Nonempty circular sequence+data CSeq a = CSeq !(Seq a) !a !(Seq a)+  deriving (Generic)+                     -- we keep the seq balanced, i.e. size left >= size right++instance NFData a => NFData (CSeq a)++instance Eq a => Eq (CSeq a) where+  a == b = asSeq a == asSeq b++instance Show a => Show (CSeq a) where+  showsPrec d s = showParen (d > app_prec) $+                    showString (("CSeq " <>) . show . F.toList . rightElements $ s)+    where app_prec = 10++-- traverses starting at the focus, going to the right.+instance T.Traversable CSeq where+  traverse f (CSeq l x r) = (\x' r' l' -> CSeq l' x' r')+                         <$> f x <*> traverse f r <*> traverse f l+-- instance Traversable1 CSeq where+--   traverse1 f (CSeq l x r) = liftF3 (\x' r' l' -> CSeq l' x' r')+--                                     (f x) (traverse f r) (traverse f l)++instance Foldable1 CSeq++instance F.Foldable CSeq where+  foldMap = T.foldMapDefault+  length (CSeq l _ r) = 1 + S.length l + S.length r++instance Functor CSeq where+  fmap = T.fmapDefault++instance Arbitrary a => Arbitrary (CSeq a) where+  arbitrary = CSeq <$> arbitrary <*> arbitrary <*> arbitrary++singleton   :: a -> CSeq a+singleton x = CSeq S.empty x S.empty++-- | Gets the focus of the CSeq+-- running time: O(1)+focus              :: CSeq a -> a+focus (CSeq _ x _) = x++-- | Access the i^th item  (w.r.t the focus) in the CSeq (indices modulo n).+--+-- running time: \(O(\log (i \mod n))\)+--+-- >>> index (fromList [0..5]) 1+-- 1+-- >>> index (fromList [0..5]) 2+-- 2+-- >>> index (fromList [0..5]) 5+-- 5+-- >>> index (fromList [0..5]) 10+-- 4+-- >>> index (fromList [0..5]) 6+-- 0+-- >>> index (fromList [0..5]) (-1)+-- 5+-- >>> index (fromList [0..5]) (-6)+-- 0+index                   :: CSeq a -> Int -> a+index s@(CSeq l x r) i' = let i  = i' `mod` length s+                              rn = length r+                          in if i == 0 then x+                               else if i - 1 < rn then S.index r (i - 1)+                                                  else S.index l (i - rn - 1)++-- | Adjusts the i^th element w.r.t the focus in the CSeq+--+-- running time: \(O(\log (i \mod n))\)+--+-- >>> adjust (const 1000) 2 (fromList [0..5])+-- CSeq [0,1,1000,3,4,5]+adjust                     :: (a -> a) -> Int -> CSeq a -> CSeq a+adjust f i' s@(CSeq l x r) = let i  = i' `mod` length s+                                 rn = length r+                             in if i == 0 then CSeq l (f x) r+                                else if i - 1 < rn+                                     then CSeq l                           x (S.adjust f (i - 1) r)+                                     else CSeq (S.adjust f (i - rn - 1) l) x r+++-- | Access te ith item in the CSeq (w.r.t the focus) as a lens+item   :: Int -> Lens' (CSeq a) a+item i = lens (flip index i) (\s x -> adjust (const x) i s)+++resplit   :: Seq a -> (Seq a, Seq a)+resplit s = swap $ S.splitAt (length s `div` 2) s+++-- | smart constructor that automatically balances the seq+cseq                   :: Seq a -> a -> Seq a -> CSeq a+cseq l x r+    | ln > 1 + 2*rn    = withFocus x (r <> l)+    | ln < rn `div`  2 = withFocus x (r <> l)+    | otherwise        = CSeq l x r+  where+    rn = length r+    ln = length l++-- smart constructor that automatically balances the sequence.+-- pre: at least one of the two seq's is NonEmpty+--+cseq'     :: Seq a -> Seq a -> CSeq a+cseq' l r = case S.viewl r of+              (x :< r') -> cseq l x r'+              EmptyL    -> let (x :< l') = S.viewl l in cseq l' x r++-- | Builds a balanced seq with the element as the focus.+withFocus     :: a -> Seq a -> CSeq a+withFocus x s = let (l,r) = resplit s in CSeq l x r++-- | rotates one to the right+--+-- running time: O(1) (amortized)+--+-- >>> rotateR $ fromList [3,4,5,1,2]+-- CSeq [4,5,1,2,3]+rotateR                :: CSeq a -> CSeq a+rotateR s@(CSeq l x r) = case S.viewl r of+                           EmptyL    -> case S.viewl l of+                             EmptyL    -> s+                             (y :< l') -> cseq (S.singleton x) y l'+                           (y :< r') -> cseq (l |> x) y r'++-- | rotates the focus to the left+--+-- running time: O(1) (amortized)+--+-- >>> rotateL $ fromList [3,4,5,1,2]+-- CSeq [2,3,4,5,1]+-- >>> mapM_ print . take 5 $ iterate rotateL $ fromList [1..5]+-- CSeq [1,2,3,4,5]+-- CSeq [5,1,2,3,4]+-- CSeq [4,5,1,2,3]+-- CSeq [3,4,5,1,2]+-- CSeq [2,3,4,5,1]+rotateL                :: CSeq a -> CSeq a+rotateL s@(CSeq l x r) = case S.viewr l of+                           EmptyR    -> case S.viewr r of+                             EmptyR     -> s+                             (r' :> y)  -> cseq r' y (S.singleton x)+                           (l' :> y) -> cseq l' y (x <| r)+++-- | Convert to a single Seq, starting with the focus.+asSeq :: CSeq a -> Seq a+asSeq = rightElements+++-- | All elements, starting with the focus, going to the right++-- >>> rightElements $ fromList [3,4,5,1,2]+-- fromList [3,4,5,1,2]+rightElements              :: CSeq a -> Seq a+rightElements (CSeq l x r) = x <| r <> l+++-- | All elements, starting with the focus, going to the left+--+-- >>> leftElements $ fromList [3,4,5,1,2]+-- fromList [3,2,1,5,4]+leftElements              :: CSeq a -> Seq a+leftElements (CSeq l x r) = x <| S.reverse l <> S.reverse r++-- | builds a CSeq+fromNonEmpty                    :: NonEmpty.NonEmpty a -> CSeq a+fromNonEmpty (x NonEmpty.:| xs) = withFocus x $ S.fromList xs++fromList        :: [a] -> CSeq a+fromList (x:xs) = withFocus x $ S.fromList xs+fromList []     = error "fromList: Empty list"++-- | Rotates i elements to the right.+--+-- pre: 0 <= i < n+--+-- running time: \(O(\log i)\) amortized+--+-- >>> rotateNR 0 $ fromList [1..5]+-- CSeq [1,2,3,4,5]+-- >>> rotateNR 1 $ fromList [1..5]+-- CSeq [2,3,4,5,1]+-- >>> rotateNR 4 $ fromList [1..5]+-- CSeq [5,1,2,3,4]+rotateNR   :: Int -> CSeq a -> CSeq a+rotateNR i = uncurry cseq' . S.splitAt i . rightElements++-- | Rotates i elements to the left.+--+-- pre: 0 <= i < n+--+-- running time: \(O(\log i)\) amoritzed+--+-- >>> rotateNL 0 $ fromList [1..5]+-- CSeq [1,2,3,4,5]+-- >>> rotateNL 1 $ fromList [1..5]+-- CSeq [5,1,2,3,4]+-- >>> rotateNL 2 $ fromList [1..5]+-- CSeq [4,5,1,2,3]+-- >>> rotateNL 3 $ fromList [1..5]+-- CSeq [3,4,5,1,2]+-- >>> rotateNL 4 $ fromList [1..5]+-- CSeq [2,3,4,5,1]+rotateNL     :: Int -> CSeq a -> CSeq a+rotateNL i s = let (x :< xs) = S.viewl $ rightElements s+                   (l',r)    = S.splitAt (length s - i) $ xs |> x+               in case S.viewr l' of+                    l :> y   -> cseq l y r+                    S.EmptyR -> let (y :< r') = S.viewl r in cseq l' y r'+++-- | Reversres the direction of the CSeq+--+-- running time: \(O(n)\)+--+-- >>> reverseDirection $ fromList [1..5]+-- CSeq [1,5,4,3,2]+reverseDirection              :: CSeq a -> CSeq a+reverseDirection (CSeq l x r) = CSeq (S.reverse r) x (S.reverse l)+++-- | Finds an element in the CSeq+--+-- >>> findRotateTo (== 3) $ fromList [1..5]+-- Just (CSeq [3,4,5,1,2])+-- >>> findRotateTo (== 7) $ fromList [1..5]+-- Nothing+findRotateTo   :: (a -> Bool) -> CSeq a -> Maybe (CSeq a)+findRotateTo p = listToMaybe . filter (p . focus) . allRotations'+++rotateTo   :: Eq a => a -> CSeq a -> Maybe (CSeq a)+rotateTo x = findRotateTo (== x)+++-- | All rotations, the input CSeq is the focus.+--+-- >>> mapM_ print . allRotations $ fromList [1..5]+-- CSeq [1,2,3,4,5]+-- CSeq [2,3,4,5,1]+-- CSeq [3,4,5,1,2]+-- CSeq [4,5,1,2,3]+-- CSeq [5,1,2,3,4]+allRotations :: CSeq a -> CSeq (CSeq a)+allRotations = fromList . allRotations'++allRotations'   :: CSeq a -> [CSeq a]+allRotations' s = take (length s) . iterate rotateR $ s++-- | "Left zip": zip the two CLists, pairing up every element in the *left*+-- list with its corresponding element in the right list. If there are more+-- items in the right clist they are discarded.+zipLWith         :: (a -> b -> c) -> CSeq a -> CSeq b -> CSeq c+zipLWith f as bs = fromList $ zipWith f (F.toList as) (F.toList bs)++-- | see 'zipLWith+zipL :: CSeq a -> CSeq b -> CSeq (a, b)+zipL = zipLWith (,)+++-- | same as zipLWith but with three items+zip3LWith            :: (a -> b -> c -> d) -> CSeq a -> CSeq b -> CSeq c -> CSeq d+zip3LWith f as bs cs = fromList $ zipWith3 f (F.toList as) (F.toList bs) (F.toList cs)+++++-- | Given a circular seq, whose elements are in increasing order, insert the+-- new element into the Circular seq in its sorted order.+--+-- >>> insertOrd 1 $ fromList [2]+-- CSeq [2,1]+-- >>> insertOrd 2 $ fromList [1,3]+-- CSeq [1,2,3]+-- >>> insertOrd 31 ordList+-- CSeq [5,6,10,20,30,31,1,2,3]+-- >>> insertOrd 1 ordList+-- CSeq [5,6,10,20,30,1,1,2,3]+-- >>> insertOrd 4 ordList+-- CSeq [5,6,10,20,30,1,2,3,4]+-- >>> insertOrd 11 ordList+-- CSeq [5,6,10,11,20,30,1,2,3]+--+-- running time: \(O(n)\)+insertOrd :: Ord a => a -> CSeq a -> CSeq a+insertOrd = insertOrdBy compare++-- | Insert an element into an increasingly ordered circular list, with+-- specified compare operator.+--+-- running time: \(O(n)\)+insertOrdBy       :: (a -> a -> Ordering) -> a -> CSeq a -> CSeq a+insertOrdBy cmp x = fromList . insertOrdBy' cmp x . F.toList . rightElements++-- | List version of insertOrdBy; i.e. the list contains the elements in+-- cirulcar order. Again produces a list that has the items in circular order.+insertOrdBy'         :: (a -> a -> Ordering) -> a -> [a] -> [a]+insertOrdBy' cmp x xs = case (rest, x `cmp` head rest) of+    ([],  _)   -> L.insertBy cmp x pref+    (z:zs, GT) -> (z : L.insertBy cmp x zs) ++ pref+    (_:_,  EQ) -> (x : xs) -- == x : rest ++ pref+    (_:_,  LT) -> rest ++ L.insertBy cmp x pref+  where+    -- split the list at its maximum.+    (pref,rest) = splitIncr cmp xs++-- given a list of elements that is supposedly a a cyclic-shift of a list of+-- increasing items, find the splitting point. I.e. returns a pair of lists+-- (ys,zs) such that xs = zs ++ ys, and ys ++ zs is (supposedly) in sorted+-- order.+splitIncr              :: (a -> a -> Ordering) -> [a] -> ([a],[a])+splitIncr _   []       = ([],[])+splitIncr cmp xs@(x:_) = swap . bimap (map snd) (map snd)+                      . L.break (\(a,b) -> (a `cmp` b) == GT) $ zip (x:xs) xs++-- | Test if the circular list is a cyclic shift of the second+-- list. We have that+--+-- prop> (xs `isShiftOf` ys) == (xs `elem` allRotations (ys :: CSeq Int))+--+-- Running time: \(O(n+m)\), where \(n\) and \(m\) are the sizes of+-- the lists.+isShiftOf         :: Eq a => CSeq a -> CSeq a -> Bool+xs `isShiftOf` ys = let twice zs    = let zs' = leftElements zs in zs' <> zs'+                        once        = leftElements+                        check as bs = isJust $ once as `isSubStringOf` twice bs+                    in length xs == length ys && check xs ys
+ src/Data/DynamicOrd.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE UndecidableInstances #-}+module Data.DynamicOrd where++import Data.Proxy+import Data.Reflection+import Unsafe.Coerce++--------------------------------------------------------------------------------++-- Implementation from+-- https://www.schoolofhaskell.com/user/thoughtpolice/using-reflection++-- | Values of type 'a' in our dynamically constructed 'Ord' instance+newtype O (s :: *) (a :: *) = O { runO :: a } deriving (Show)++-- | An Ord Dictionary+newtype OrdDict a = OrdDict { compare_ :: a -> a -> Ordering }++instance Reifies s (OrdDict a) => Eq (O s a) where+  (O l) == (O r) = let cmp = compare_ $ reflect (Proxy :: Proxy s)+                           in case l `cmp` r of+                                EQ -> True+                                _  -> False++instance (Eq (O s a), Reifies s (OrdDict a)) => Ord (O s a) where+  (O l) `compare` (O r) = let cmp = compare_ $ reflect (Proxy :: Proxy s)+                                  in l `cmp` r++-- | Run a computation with a given ordering+withOrd       :: (a -> a -> Ordering) -> (forall s. Reifies s (OrdDict a) => O s b) -> b+withOrd cmp v = reify (OrdDict cmp) (runO . asProxyOf v)+  where+    asProxyOf      :: f s a -> Proxy s -> f s a+    asProxyOf v' _ = v'++--------------------------------------------------------------------------------+-- * Introducing and removing the dynamic order type+-- Note that all of these may be unsafe if used incorrectly++-- | Lifts a container f whose values (of type a) depend on 's' into a+-- more general computation in that produces a 'f a' (depending on s).+--+-- running time: \(O(1)\)+extractOrd1 :: f (O s a) -> O s (f a)+extractOrd1 = unsafeCoerce+++-- | Introduce dynamic order in a container 'f'.+--+-- running time: \(O(1)\)+introOrd1 :: f a -> f (O s a)+introOrd1 = unsafeCoerce++-- | Lifts a function that works on a container 'f' of+-- orderable-things into one that works on dynamically ordered ones.+liftOrd1   :: (f (O s a) -> f (O s a))+           -> f a -> O s (f a)+liftOrd1 f = extractOrd1 . f . introOrd1+++-- | Lifts a container f whose keys (of type k) depend on 's' into a+-- more general computation in that produces a 'f k v' (depending on s).+--+-- running time: \(O(1)\)+extractOrd2 :: f (O s k) v -> O s (f k v)+extractOrd2 = unsafeCoerce++-- | Introduce dynamic order in a container 'f' that has keys of type+-- k.+--+-- running time: \(O(1)\)+introOrd2 :: f k v -> f (O s k) v+introOrd2 = unsafeCoerce
+ src/Data/Ext.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE DeriveAnyClass  #-}+{-# LANGUAGE OverloadedStrings  #-}+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.Ext+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- A pair-like data type to represent a 'core' type that has extra information+-- as well.+--+--------------------------------------------------------------------------------+module Data.Ext where++import Control.DeepSeq+import Control.Lens hiding ((.=))+import Data.Aeson+import Data.Aeson.Types (typeMismatch)+import Data.Biapplicative+import Data.Bifoldable+import Data.Bifunctor.Apply+import Data.Bitraversable+import Data.Functor.Apply (liftF2)+import Data.Semigroup.Bifoldable+import Data.Semigroup.Bitraversable+import GHC.Generics (Generic)+import Test.QuickCheck++--------------------------------------------------------------------------------++-- | Our Ext type that represents the core datatype core extended with extra+-- information of type 'extra'.+data core :+ extra = core :+ extra deriving (Show,Read,Eq,Ord,Bounded,Generic,NFData)+infixr 1 :++++instance Bifunctor (:+) where+  bimap f g (c :+ e) = f c :+ g e++instance Biapply (:+) where+  (f :+ g) <<.>> (c :+ e) = f c :+ g e++instance Biapplicative (:+) where+  bipure = (:+)+  (f :+ g) <<*>> (c :+ e) = f c :+ g e++instance Bifoldable (:+) where+  bifoldMap f g (c :+ e) = f c `mappend` g e++instance Bitraversable (:+) where+  bitraverse f g (c :+ e) = (:+) <$> f c <*> g e++instance Bifoldable1 (:+)++instance Bitraversable1 (:+) where+  bitraverse1 f g (c :+ e) = liftF2 (:+) (f c) (g e)++instance (Semigroup core, Semigroup extra) => Semigroup (core :+ extra) where+  (c :+ e) <> (c' :+ e') = c <> c' :+ e <> e'+++instance (ToJSON core, ToJSON extra) => ToJSON (core :+ extra) where+  -- toJSON     (c :+ e) = toJSON     (c,e)+  -- toEncoding (c :+ e) = toEncoding (c,e)+  toJSON     (c :+ e) = object ["core" .= c, "extra" .= e]+  toEncoding (c :+ e) = pairs  ("core" .= c <> "extra" .= e)++instance (FromJSON core, FromJSON extra) => FromJSON (core :+ extra) where+  -- parseJSON = fmap (\(c,e) -> c :+ e) . parseJSON+  parseJSON (Object v) = (:+) <$> v .: "core" <*> v .: "extra"+  parseJSON invalid    = typeMismatch "Ext (:+)" invalid++instance (Arbitrary c, Arbitrary e) => Arbitrary (c :+ e) where+  arbitrary = (:+) <$> arbitrary <*> arbitrary++_core :: (core :+ extra) -> core+_core (c :+ _) = c++_extra :: (core :+ extra) -> extra+_extra (_ :+ e) = e++core :: Lens (core :+ extra) (core' :+ extra) core core'+core = lens _core (\(_ :+ e) c -> (c :+ e))++extra :: Lens (core :+ extra) (core :+ extra') extra extra'+extra = lens _extra (\(c :+ _) e -> (c :+ e))++ext   :: a -> a :+ ()+ext x = x :+ ()
+ src/Data/Intersection.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE UnicodeSyntax #-}+{-# LANGUAGE DefaultSignatures #-}+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.Intersection+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Defines a data type for representing intersections. Mostly useful+-- for the more geometric types.+--+--------------------------------------------------------------------------------+module Data.Intersection where++import Data.Maybe (isNothing)+import Data.Vinyl.CoRec+import Data.Vinyl.Core+import Data.Vinyl.Functor+import Data.Vinyl.Lens++-------------------------------------------------------------------------------++-- | A simple data type expressing that there are no intersections+data NoIntersection = NoIntersection deriving (Show,Read,Eq,Ord)++-- | The result of interesecting two geometries is a CoRec,+type Intersection g h = CoRec Identity (IntersectionOf g h)++-- | The type family specifying the list of possible result types of an+-- intersection.+type family IntersectionOf g h :: [*]++-- | Helper to produce a corec+coRec :: (a ∈ as) => a -> CoRec Identity as+coRec = CoRec . Identity++class IsIntersectableWith g h where+  intersect :: g -> h -> Intersection g h++  -- | g `intersects` h  <=> The intersection of g and h is non-empty.+  --+  -- The default implementation computes the intersection of g and h,+  -- and uses nonEmptyIntersection to determine if the intersection is+  -- non-empty.+  intersects :: g -> h -> Bool+  g `intersects` h = nonEmptyIntersection (Identity g) (Identity h) $ g `intersect` h++  -- | Helper to implement `intersects`.+  nonEmptyIntersection :: proxy g -> proxy h -> Intersection g h -> Bool+  {-# MINIMAL intersect, nonEmptyIntersection #-}++  default nonEmptyIntersection :: ( NoIntersection ∈ IntersectionOf g h+                                  , RecApplicative (IntersectionOf g h)+                                  )+                                  => proxy g -> proxy h -> Intersection g h -> Bool+  nonEmptyIntersection = defaultNonEmptyIntersection+++-- | When using IntersectionOf we may need some constraints that are always+-- true anyway.+type AlwaysTrueIntersection g h = RecApplicative (IntersectionOf g h)+++-- | Returns True iff the result is *not* a NoIntersection+defaultNonEmptyIntersection :: forall g h proxy.+                            ( NoIntersection ∈ IntersectionOf g h+                            , RecApplicative (IntersectionOf g h)+                            )+                            => proxy g -> proxy h -> Intersection g h -> Bool+defaultNonEmptyIntersection _ _ = isNothing . asA @NoIntersection
+ src/Data/LSeq.hs view
@@ -0,0 +1,314 @@+{-# LANGUAGE ScopedTypeVariables #-}+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.LSeq+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+-- Description :  Wrapper around Data.Sequence with type level length annotation.+--+--------------------------------------------------------------------------------+module Data.LSeq( LSeq+                , toSeq+                , empty+                , fromList+                , fromNonEmpty+                , fromSeq++                , (<|), (|>)+                , (><)+                , eval++                , index+                , adjust+                , partition+                , mapWithIndex+                , take+                , drop+                , unstableSort, unstableSortBy+                , head, last+                , append++                , ViewL(..)+                , viewl+                , pattern (:<|)++                , pattern (:<<)+                , pattern EmptyL++                , ViewR(..)+                , viewr+                , pattern (:|>)+++                , promise+                , forceLSeq+                ) where++import           Control.DeepSeq+import           Control.Lens ((%~), (&), (<&>), (^?), bimap)+import           Control.Lens.At (Ixed(..), Index, IxValue)+import qualified Data.Foldable as F+import qualified Data.List.NonEmpty as NonEmpty+import           Data.Maybe (fromJust)+import           Data.Proxy+import           Data.Semigroup.Foldable+import qualified Data.Sequence as S+import qualified Data.Traversable as Tr+import           GHC.Generics (Generic)+import           GHC.TypeLits+import           Prelude hiding (drop,take,head,last)+import           Test.QuickCheck(Arbitrary(..),vector)++--------------------------------------------------------------------------------++-- $setup+-- >>> :{+-- import Data.Proxy+-- :}++++-- | LSeq n a certifies that the sequence has *at least* n items+newtype LSeq (n :: Nat) a = LSeq (S.Seq a)+                          deriving (Show,Read,Eq,Ord,Foldable,Functor,Traversable+                                   ,Generic,NFData)++toSeq          :: LSeq n a -> S.Seq a+toSeq (LSeq s) = s++instance Semigroup (LSeq n a) where+  (LSeq s) <> (LSeq s') = LSeq (s <> s')++instance Monoid (LSeq 0 a) where+  mempty = empty+  mappend = (<>)++instance (KnownNat n, Arbitrary a) => Arbitrary (LSeq n a) where+  arbitrary = (\s s' -> promise . fromList $ s <> s')+            <$> vector (fromInteger . natVal $ (Proxy :: Proxy n))+            <*> arbitrary+++type instance Index   (LSeq n a) = Int+type instance IxValue (LSeq n a) = a+instance Ixed (LSeq n a) where+  ix i f s@(LSeq xs)+    | 0 <= i && i < S.length xs = f (S.index xs i) <&> \x -> LSeq $ S.update i x xs+    | otherwise                 = pure s++instance (1 <= n) => Foldable1 (LSeq n)++empty :: LSeq 0 a+empty = LSeq S.empty++(<|) :: a -> LSeq n a -> LSeq (1 + n) a+x <| xs = LSeq (x S.<| toSeq xs)++(|>)    :: LSeq n a -> a -> LSeq (1 + n) a+xs |> x = LSeq (toSeq xs S.|> x)++infixr 5 <|+infixl 5 |>++(><) :: LSeq n a -> LSeq m a -> LSeq (n + m) a+xs >< ys = LSeq (toSeq xs <> toSeq ys)++infix 5 ><+++eval :: forall proxy n m a. KnownNat n => proxy n -> LSeq m a -> Maybe (LSeq n a)+eval n (LSeq xs)+  | toInteger (S.length xs) >= natVal n = Just $ LSeq xs+  | otherwise                           = Nothing++++++-- | Promises that the length of this LSeq is actually n. This is not+-- checked.+--+-- This function should be a noop+promise :: LSeq m a -> LSeq n a+promise = LSeq . toSeq+++-- | Forces the first n elements of the LSeq+forceLSeq   :: KnownNat n => proxy n -> LSeq m a -> LSeq n a+forceLSeq n = promise . go (fromInteger $ natVal n)+  where+    -- forces the Lseq for n' positions+    go      :: Int -> LSeq m a -> LSeq m a+    go n' s | n' <= l    = s+            | otherwise  = error msg+      where+        l   = S.length . S.take n' . toSeq $ s+        msg = "forceLSeq: too few elements. expected " <> show n' <> " but found " <> show l+++-- | appends two sequences.+--+append         :: LSeq n a -> LSeq m a -> LSeq (n + m) a+sa `append` sb = LSeq $ (toSeq sa) <> toSeq sb++--------------------------------------------------------------------------------++-- | get the element with index i, counting from the left and starting at 0.+-- O(log(min(i,n-i)))+index     :: LSeq n a -> Int -> a+index s i = fromJust $ s^?ix i++adjust       :: (a -> a) -> Int -> LSeq n a -> LSeq n a+adjust f i s = s&ix i %~ f+++partition   :: (a -> Bool) -> LSeq n a -> (LSeq 0 a, LSeq 0 a)+partition p = bimap LSeq LSeq . S.partition p . toSeq++mapWithIndex   :: (Int -> a -> b) -> LSeq n a -> LSeq n b+mapWithIndex f = wrapUnsafe (S.mapWithIndex f)++take   :: Int -> LSeq n a -> LSeq 0 a+take i = wrapUnsafe (S.take i)++drop   :: Int -> LSeq n a -> LSeq 0 a+drop i = wrapUnsafe (S.drop i)+++unstableSortBy   :: (a -> a -> Ordering) -> LSeq n a -> LSeq n a+unstableSortBy f = wrapUnsafe (S.unstableSortBy f)++unstableSort :: Ord a => LSeq n a -> LSeq n a+unstableSort = wrapUnsafe (S.unstableSort)+++wrapUnsafe :: (S.Seq a -> S.Seq b) -> LSeq n a -> LSeq m b+wrapUnsafe f = LSeq . f . toSeq++--------------------------------------------------------------------------------++fromSeq :: S.Seq a -> LSeq 0 a+fromSeq = LSeq++fromList :: Foldable f => f a -> LSeq 0 a+fromList = LSeq . S.fromList . F.toList++fromNonEmpty :: NonEmpty.NonEmpty a -> LSeq 1 a+fromNonEmpty = LSeq . S.fromList . F.toList+++--------------------------------------------------------------------------------++data ViewL n a where+  (:<) :: a -> LSeq n a -> ViewL (1 + n) a++infixr 5 :<++instance Semigroup (ViewL n a) where+  (x :< xs) <> (y :< ys) = x :< LSeq (toSeq xs <> (y S.<| toSeq ys))++deriving instance Show a => Show (ViewL n a)+instance Functor (ViewL n) where+  fmap = Tr.fmapDefault+instance Foldable (ViewL n) where+  foldMap = Tr.foldMapDefault+instance Traversable (ViewL n) where+  traverse f (x :< xs) = (:<) <$> f x <*> traverse f xs+instance Eq a => Eq (ViewL n a) where+  s == s' = F.toList s == F.toList s'+instance Ord a => Ord (ViewL n a) where+  s `compare` s' = F.toList s `compare` F.toList s'+++viewl :: LSeq (1 + n) a -> ViewL (1 + n) a+viewl xs = let ~(x S.:< ys) = S.viewl $ toSeq xs in x :< LSeq ys++viewl'    :: LSeq (1 + n) a -> (a, LSeq n a)+viewl' xs = let ~(x S.:< ys) = S.viewl $ toSeq xs in (x,LSeq ys)++infixr 5 :<|++pattern (:<|)    :: a -> LSeq n a -> LSeq (1 + n) a+pattern x :<| xs <- (viewl' -> (x,xs)) -- we need the coerce unfortunately+  where+    x :<| xs = x <| xs+{-# COMPLETE (:<|) #-}++++infixr 5 :<<++pattern (:<<)    :: a -> LSeq 0 a -> LSeq n a+pattern x :<< xs <- (viewLSeq -> Just (x,xs))++pattern EmptyL   :: LSeq n a+pattern EmptyL   <- (viewLSeq -> Nothing)++viewLSeq          :: LSeq n a -> Maybe (a,LSeq 0 a)+viewLSeq (LSeq s) = case S.viewl s of+                      S.EmptyL    -> Nothing+                      (x S.:< xs) -> Just (x,LSeq xs)+++--------------------------------------------------------------------------------++data ViewR n a where+  (:>) :: LSeq n a -> a -> ViewR (1 + n) a++infixl 5 :>++instance Semigroup (ViewR n a) where+  (xs :> x) <> (ys :> y) = LSeq ((toSeq xs S.|> x) <> toSeq ys) :> y++deriving instance Show a => Show (ViewR n a)+instance Functor (ViewR n) where+  fmap = Tr.fmapDefault+instance Foldable (ViewR n) where+  foldMap = Tr.foldMapDefault+instance Traversable (ViewR n) where+  traverse f (xs :> x) = (:>) <$> traverse f xs <*> f x+instance Eq a => Eq (ViewR n a) where+  s == s' = F.toList s == F.toList s'+instance Ord a => Ord (ViewR n a) where+  s `compare` s' = F.toList s `compare` F.toList s'++viewr    :: LSeq (1 + n) a -> ViewR (1 + n) a+viewr xs = let ~(ys S.:> x) = S.viewr $ toSeq xs in LSeq ys :> x++viewr'    :: LSeq (1 + n) a -> (LSeq n a, a)+viewr' xs = let ~(ys S.:> x) = S.viewr $ toSeq xs in (LSeq ys, x)++infixl 5 :|>++pattern (:|>)    :: forall n a. LSeq n a -> a -> LSeq (1 + n) a+pattern xs :|> x <- (viewr' -> (xs,x))+  where+    xs :|> x = xs |> x+{-# COMPLETE (:|>) #-}++--------------------------------------------------------------------------------++-- | Gets the first element of the LSeq+--+-- >>> head $ forceLSeq (Proxy :: Proxy 3) $ fromList [1,2,3]+-- 1+head           :: LSeq (1 + n) a -> a+head (x :<| _) = x++-- s = let (x :< _) = viewl s in x++-- | Get the last element of the LSeq+--+-- >>> last $ forceLSeq (Proxy :: Proxy 3) $ fromList [1,2,3]+-- 3+last           :: LSeq (1 + n) a -> a+last (_ :|> x) = x++-- testL = (eval (Proxy :: Proxy 2) $ fromList [1..5])++-- testL' :: LSeq 2 Integer+-- testL' = fromJust testL++-- test            :: Show a => LSeq (1 + n) a -> String+-- test (x :<| xs) = show x ++ show xs
+ src/Data/OrdSeq.hs view
@@ -0,0 +1,193 @@+module Data.OrdSeq where+++import           Control.Lens (bimap)+import qualified Data.FingerTree as FT+import           Data.FingerTree hiding (null, viewl, viewr)+import qualified Data.Foldable as F+import           Data.Maybe+import           Test.QuickCheck++--------------------------------------------------------------------------------++data Key a = NoKey | Key { getKey :: !a } deriving (Show,Eq,Ord)++instance Semigroup (Key a) where+  k <> NoKey = k+  _ <> k     = k++instance Monoid (Key a) where+  mempty = NoKey+  k `mappend` k' = k <> k'++liftCmp                     :: (a -> a -> Ordering) -> Key a -> Key a -> Ordering+liftCmp _   NoKey   NoKey   = EQ+liftCmp _   NoKey   (Key _) = LT+liftCmp _   (Key _) NoKey   = GT+liftCmp cmp (Key x) (Key y) = x `cmp` y++++newtype Elem a = Elem { getElem :: a } deriving (Eq,Ord,Traversable,Foldable,Functor)++instance Show a => Show (Elem a) where+  show (Elem x) = "Elem " <> show x+++newtype OrdSeq a = OrdSeq { _asFingerTree :: FingerTree (Key a) (Elem a) }+                   deriving (Show,Eq)++instance Semigroup (OrdSeq a) where+  (OrdSeq s) <> (OrdSeq t) = OrdSeq $ s `mappend` t++instance Monoid (OrdSeq a) where+  mempty = OrdSeq mempty+  mappend = (<>)++instance Foldable OrdSeq where+  foldMap f = foldMap (foldMap f) . _asFingerTree+  null      = null . _asFingerTree+  length    = length . _asFingerTree+  minimum   = fromJust . lookupMin+  maximum   = fromJust . lookupMax++instance (Arbitrary a, Ord a) => Arbitrary (OrdSeq a) where+  arbitrary = fromListByOrd <$> arbitrary++instance Measured (Key a) (Elem a) where+  measure (Elem x) = Key x+++type Compare a = a -> a -> Ordering++-- | Insert into a monotone OrdSeq.+--+-- pre: the comparator maintains monotonicity+--+-- \(O(\log n)\)+insertBy                  :: Compare a -> a -> OrdSeq a -> OrdSeq a+insertBy cmp x (OrdSeq s) = OrdSeq $ l `mappend` (Elem x <| r)+  where+    (l,r) = split (\v -> liftCmp cmp v (Key x) `elem` [EQ, GT]) s++-- | Insert into a sorted OrdSeq+--+-- \(O(\log n)\)+insert :: Ord a => a -> OrdSeq a -> OrdSeq a+insert = insertBy compare++deleteAllBy         :: Compare a -> a -> OrdSeq a -> OrdSeq a+deleteAllBy cmp x s = l <> r+  where+    (l,_,r) = splitBy cmp x s++    -- (l,m) = split (\v -> liftCmp cmp v (Key x) `elem` [EQ,GT]) s+    -- (_,r) = split (\v -> liftCmp cmp v (Key x) == GT) m+++-- | \(O(\log n)\)+splitBy                  :: Compare a -> a -> OrdSeq a -> (OrdSeq a, OrdSeq a, OrdSeq a)+splitBy cmp x (OrdSeq s) = (OrdSeq l, OrdSeq m', OrdSeq r)+  where+    (l, m) = split (\v -> liftCmp cmp v (Key x) `elem` [EQ,GT]) s+    (m',r) = split (\v -> liftCmp cmp v (Key x) == GT) m+++-- | Given a monotonic function f that maps a to b, split the sequence s+-- depending on the b values. I.e. the result (l,m,r) is such that+-- * all (< x) . fmap f $ l+-- * all (== x) . fmap f $ m+-- * all (> x) . fmap f $ r+--+-- >>> splitOn id 3 $ fromAscList' [1..5]+-- (OrdSeq {_asFingerTree = fromList [Elem 1,Elem 2]},OrdSeq {_asFingerTree = fromList [Elem 3]},OrdSeq {_asFingerTree = fromList [Elem 4,Elem 5]})+-- >>> splitOn fst 2 $ fromAscList' [(0,"-"),(1,"A"),(2,"B"),(2,"C"),(3,"D"),(4,"E")]+-- (OrdSeq {_asFingerTree = fromList [Elem (0,"-"),Elem (1,"A")]},OrdSeq {_asFingerTree = fromList [Elem (2,"B"),Elem (2,"C")]},OrdSeq {_asFingerTree = fromList [Elem (3,"D"),Elem (4,"E")]})+--+-- \(O(\log n)\)+splitOn :: Ord b => (a -> b) -> b -> OrdSeq a -> (OrdSeq a, OrdSeq a, OrdSeq a)+splitOn f x (OrdSeq s) = (OrdSeq l, OrdSeq m', OrdSeq r)+  where+    (l, m) = split (\(Key v) -> compare (f v) x `elem` [EQ,GT]) s+    (m',r) = split (\(Key v) -> compare (f v) x ==     GT)      m++-- | Given a monotonic predicate p, splits the sequence s into two sequences+--  (as,bs) such that all (not p) as and all p bs+--+-- \(O(\log n)\)+splitMonotonic  :: (a -> Bool) -> OrdSeq a -> (OrdSeq a, OrdSeq a)+splitMonotonic p = bimap OrdSeq OrdSeq . split (p . getKey) . _asFingerTree+++-- Deletes all elements from the OrdDeq+--+-- \(O(n\log n)\)+deleteAll :: Ord a => a -> OrdSeq a -> OrdSeq a+deleteAll = deleteAllBy compare+++-- | inserts all eleements in order+-- \(O(n\log n)\)+fromListBy     :: Compare a -> [a] -> OrdSeq a+fromListBy cmp = foldr (insertBy cmp) mempty++-- | inserts all eleements in order+-- \(O(n\log n)\)+fromListByOrd :: Ord a => [a] -> OrdSeq a+fromListByOrd = fromListBy compare++-- | O(n)+fromAscList' :: [a] -> OrdSeq a+fromAscList' = OrdSeq . fromList . fmap Elem+++-- | \(O(\log n)\)+lookupBy         :: Compare a -> a -> OrdSeq a -> Maybe a+lookupBy cmp x s = let (_,m,_) = splitBy cmp x s in listToMaybe . F.toList $ m++memberBy        :: Compare a -> a -> OrdSeq a -> Bool+memberBy cmp x = isJust . lookupBy cmp x+++-- | Fmap, assumes the order does not change+-- O(n)+mapMonotonic   :: (a -> b) -> OrdSeq a -> OrdSeq b+mapMonotonic f = fromAscList' . map f . F.toList+++-- | Gets the first element from the sequence+-- \(O(1)\)+viewl :: OrdSeq a -> ViewL OrdSeq a+viewl = f . FT.viewl . _asFingerTree+  where+    f EmptyL         = EmptyL+    f (Elem x :< s)  = x :< OrdSeq s++-- Last element+-- \(O(1)\)+viewr :: OrdSeq a -> ViewR OrdSeq a+viewr = f . FT.viewr . _asFingerTree+  where+    f EmptyR         = EmptyR+    f (s :> Elem x)  = OrdSeq s :> x+++-- \(O(1)\)+minView   :: OrdSeq a -> Maybe (a, OrdSeq a)+minView s = case viewl s of+              EmptyL   -> Nothing+              (x :< t) -> Just (x,t)++-- \(O(1)\)+lookupMin :: OrdSeq a -> Maybe a+lookupMin = fmap fst . minView++-- \(O(1)\)+maxView   :: OrdSeq a -> Maybe (a, OrdSeq a)+maxView s = case viewr s of+              EmptyR   -> Nothing+              (t :> x) -> Just (x,t)++-- \(O(1)\)+lookupMax :: OrdSeq a -> Maybe a+lookupMax = fmap fst . maxView
+ src/Data/Permutation.hs view
@@ -0,0 +1,124 @@+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.Permutation+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Data type for representing a Permutation+--+--------------------------------------------------------------------------------+module Data.Permutation where++import           Control.DeepSeq+import           Control.Lens+import           Control.Monad (forM)+import           Control.Monad.ST (runST)+import qualified Data.Foldable as F+import           Data.Maybe (catMaybes)+import qualified Data.Traversable as T+import qualified Data.Vector as V+import qualified Data.Vector.Generic as GV+import qualified Data.Vector.Unboxed as UV+import qualified Data.Vector.Unboxed.Mutable as UMV+import           GHC.Generics (Generic)++--------------------------------------------------------------------------------++-- | Orbits (Cycles) are represented by vectors+type Orbit a = V.Vector a++-- | Cyclic representation of a permutation.+data Permutation a = Permutation { _orbits  :: V.Vector (Orbit a)+                                 , _indexes :: UV.Vector (Int,Int)+                                               -- ^ idxes (fromEnum a) = (i,j)+                                               -- implies that a is the j^th+                                               -- item in the i^th orbit+                                 }+                   deriving (Show,Eq,Generic)+makeLenses ''Permutation++instance NFData a => NFData (Permutation a)++instance Functor Permutation where+  fmap = T.fmapDefault++instance F.Foldable Permutation where+  foldMap = T.foldMapDefault++instance T.Traversable Permutation where+  traverse f (Permutation os is) = flip Permutation is <$> T.traverse (T.traverse f) os+++elems :: Permutation a -> V.Vector a+elems = GV.concat . GV.toList . _orbits++size      :: Permutation a -> Int+size perm = GV.length (perm^.indexes)++-- | The cycle containing a given item+cycleOf        :: Enum a => Permutation a -> a -> Orbit a+cycleOf perm x = perm^?!orbits.ix (perm^?!indexes.ix (fromEnum x)._1)+++-- | Next item in a cyclic permutation+next     :: GV.Vector v a => v a -> Int -> a+next v i = let n = GV.length v in v GV.! ((i+1) `mod` n)++-- | Previous item in a cyclic permutation+previous     :: GV.Vector v a => v a -> Int -> a+previous v i = let n = GV.length v in v GV.! ((i-1) `mod` n)++-- | Lookup the indices of an element, i.e. in which orbit the item is, and the+-- index within the orbit.+--+-- runnign time: \(O(1)\)+lookupIdx        :: Enum a => Permutation a -> a -> (Int,Int)+lookupIdx perm x = perm^?!indexes.ix (fromEnum x)++-- | Apply the permutation, i.e. consider the permutation as a function.+apply        :: Enum a => Permutation a -> a -> a+apply perm x = let (c,i) = lookupIdx perm x+               in next (perm^?!orbits.ix c) i+++-- | Find the cycle in the permutation starting at element s+orbitFrom     :: Eq a => a -> (a -> a) -> [a]+orbitFrom s p = s : (takeWhile (/= s) . tail $ iterate p s)++-- | Given a vector with items in the permutation, and a permutation (by its+-- functional representation) construct the cyclic representation of the+-- permutation.+cycleRep        :: (GV.Vector v a, Enum a, Eq a) => v a -> (a -> a) -> Permutation a+cycleRep v perm = toCycleRep n $ runST $ do+    bv    <- UMV.replicate n False -- bit vector of marks+    morbs <- forM [0..(n - 1)] $ \i -> do+               m <- UMV.read bv (fromEnum $ v GV.! i)+               if m then pure Nothing -- already visited+                    else do+                      let xs = orbitFrom (v GV.! i) perm+                      markAll bv $ map fromEnum xs+                      pure . Just $ xs+    pure . catMaybes $ morbs+  where+    n  = GV.length v++    mark    bv i = UMV.write bv i True+    markAll bv   = mapM_ (mark bv)+++-- | Given the size n, and a list of Cycles, turns the cycles into a+-- cyclic representation of the Permutation.+toCycleRep      :: Enum a => Int -> [[a]] -> Permutation a+toCycleRep n os = Permutation (V.fromList . map V.fromList $ os) (genIndexes n os)+++genIndexes      :: Enum a => Int -> [[a]] -> UV.Vector (Int,Int)+genIndexes n os = UV.create $ do+                                v <- UMV.new n+                                mapM_ (uncurry $ UMV.write v) ixes'+                                pure v+  where+    f i c = zipWith (\x j -> (fromEnum x,(i,j))) c [0..]+    ixes' = concat $ zipWith f [0..] os
+ src/Data/PlanarGraph.hs view
@@ -0,0 +1,157 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings #-}+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.PlanarGraph+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Data type for representing connected planar graphs+--------------------------------------------------------------------------------+module Data.PlanarGraph( -- $setup+                         -- * The Planar Graph type+                         PlanarGraph+                       , embedding, vertexData, dartData, faceData, rawDartData+                       , edgeData++                       , World(..)+                       , DualOf++                       -- * Representing edges: Arcs and Darts+                       , Arc(..)+                       , Direction(..), rev++                       , Dart(..), arc, direction+                       , twin, isPositive++                       -- * Vertices++                       , VertexId(..), VertexId'++                       -- * Building a planar graph++                       , planarGraph, planarGraph', fromAdjacencyLists+                       , toAdjacencyLists+                       , fromAdjRep, toAdjRep++                       -- , buildFromJSON++                       -- * Quering a planar graph++                       , numVertices, numDarts, numEdges, numFaces+                       , darts', darts, edges', edges, vertices', vertices, faces', faces+                       , traverseVertices, traverseDarts, traverseFaces++                       , tailOf, headOf, endPoints+                       , incidentEdges, incomingEdges, outgoingEdges, neighboursOf+                       , nextIncidentEdge, prevIncidentEdge++                       -- * Associated Data++                       , HasDataOf(..), endPointDataOf, endPointData++                       , dual++                       -- * Faces++                       , FaceId(..), FaceId'+                       , leftFace, rightFace+                       , boundaryDart, boundary, boundary', boundaryVertices+                       , nextEdge, prevEdge++                       ) where+++import           Data.PlanarGraph.Core+import           Data.PlanarGraph.Dart+import           Data.PlanarGraph.Dual+import           Data.PlanarGraph.IO++--------------------------------------------------------------------------------+-- $setup+-- >>> :{+-- let dart i s = Dart (Arc i) (read s)+--     (aA:aB:aC:aD:aE:aG:_) = take 6 [Arc 0..]+--     myGraph :: PlanarGraph () Primal () String ()+--     myGraph = planarGraph [ [ (Dart aA Negative, "a-")+--                             , (Dart aC Positive, "c+")+--                             , (Dart aB Positive, "b+")+--                             , (Dart aA Positive, "a+")+--                             ]+--                           , [ (Dart aE Negative, "e-")+--                             , (Dart aB Negative, "b-")+--                             , (Dart aD Negative, "d-")+--                             , (Dart aG Positive, "g+")+--                             ]+--                           , [ (Dart aE Positive, "e+")+--                             , (Dart aD Positive, "d+")+--                             , (Dart aC Negative, "c-")+--                             ]+--                           , [ (Dart aG Negative, "g-")+--                             ]+--                           ]+-- :}+--+--+-- This represents the following graph. Note that the graph is undirected, the+-- arrows are just to indicate what the Positive direction of the darts is.+--+-- ![myGraph](docs/Data/PlanarGraph/testG.png)+++++--------------------------------------------------------------------------------+-- Testing stuff++-- testPerm :: Permutation (Dart s)+-- testPerm = let (a:b:c:d:e:g:_) = take 6 [Arc 0..]+--            in toCycleRep 12 [ [ Dart a Negative+--                               , Dart c Positive+--                               , Dart b Positive+--                               , Dart a Positive+--                               ]+--                             , [ Dart e Negative+--                               , Dart b Negative+--                               , Dart d Negative+--                               , Dart g Positive+--                               ]+--                             , [ Dart e Positive+--                               , Dart d Positive+--                               , Dart c Negative+--                               ]+--                             , [ Dart g Negative+--                               ]+--                             ]++-- data Test++-- testG :: PlanarGraph Test Primal () String ()+-- testG = planarGraph [ [ (Dart aA Negative, "a-")+--                       , (Dart aC Positive, "c+")+--                       , (Dart aB Positive, "b+")+--                       , (Dart aA Positive, "a+")+--                       ]+--                     , [ (Dart aE Negative, "e-")+--                       , (Dart aB Negative, "b-")+--                       , (Dart aD Negative, "d-")+--                       , (Dart aG Positive, "g+")+--                       ]+--                     , [ (Dart aE Positive, "e+")+--                       , (Dart aD Positive, "d+")+--                       , (Dart aC Negative, "c-")+--                       ]+--                     , [ (Dart aG Negative, "g-")+--                       ]+--                     ]+--   where+--     (aA:aB:aC:aD:aE:aG:_) = take 6 [Arc 0..]+++++++--------------------------------------------------------------------------------
+ src/Data/PlanarGraph/AdjRep.hs view
@@ -0,0 +1,63 @@+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.PlanarGraph.AdjRep+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Data types that to represent a planar graph as Adjacency Lists. The main+-- purpose is to help encode/decode a PlanarGraph as a JSON/YAML file.+--+--------------------------------------------------------------------------------+module Data.PlanarGraph.AdjRep where++import Data.Aeson+import GHC.Generics (Generic)+import Control.Lens(Bifunctor(..))++--------------------------------------------------------------------------------++-- | Data type representing the graph in its JSON/Yaml format+data Gr v f = Gr { ajacencies :: [v]+                 , faces      :: [f]+                 } deriving (Generic)++instance Bifunctor Gr where+  bimap f g (Gr vs fs) = Gr (map f vs) (map g fs)++instance (ToJSON v, ToJSON f)     => ToJSON   (Gr v f) where+  toEncoding = genericToEncoding defaultOptions+instance (FromJSON v, FromJSON f) => FromJSON (Gr v f)++----------------------------------------++-- | A vertex, represented by an id, its adjacencies, and its data.+data Vtx v e = Vtx { id    :: Int+                   , adj   :: [(Int,e)] -- ^ adjacent vertices + data on the+                                        -- edge. Adjacencies are given in+                                        -- arbitrary order+                   , vData :: v+                   } deriving (Generic)++instance Bifunctor Vtx where+  bimap f g (Vtx i as x) = Vtx i (map (\(j,y) -> (j,g y)) as) (f x)++instance (ToJSON v, ToJSON e)     => ToJSON   (Vtx v e) where+  toEncoding = genericToEncoding defaultOptions+instance (FromJSON v, FromJSON e) => FromJSON (Vtx v e)++----------------------------------------++-- | Faces+data Face f = Face { incidentEdge :: (Int,Int) -- ^ an edge (u,v) s.t. the face+                                               -- is right from (u,v)+                   , fData        :: f+                   } deriving (Generic,Functor)++instance ToJSON f   => ToJSON   (Face f) where+  toEncoding = genericToEncoding defaultOptions++instance FromJSON f => FromJSON (Face f)+++--------------------------------------------------------------------------------
+ src/Data/PlanarGraph/Core.hs view
@@ -0,0 +1,540 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE ScopedTypeVariables #-}+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.PlanarGraph.Core+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Data type for representing connected planar graphs+--------------------------------------------------------------------------------+module Data.PlanarGraph.Core where+++import           Control.DeepSeq+import           Control.Lens hiding ((.=))+import           Control.Monad.State.Strict+import           Data.Aeson+import qualified Data.Foldable as F+import           Data.Permutation+import           Data.PlanarGraph.Dart+import           Data.Type.Equality (gcastWith, (:~:)(..))+import qualified Data.Vector as V+import qualified Data.Vector.Mutable as MV+import           GHC.Generics (Generic)+import           Unsafe.Coerce (unsafeCoerce)++--------------------------------------------------------------------------------++--------------------------------------------------------------------------------+-- $setup+-- >>> :{+-- let dart i s = Dart (Arc i) (read s)+--     (aA:aB:aC:aD:aE:aG:_) = take 6 [Arc 0..]+--     myGraph :: PlanarGraph () Primal () String ()+--     myGraph = planarGraph [ [ (Dart aA Negative, "a-")+--                             , (Dart aC Positive, "c+")+--                             , (Dart aB Positive, "b+")+--                             , (Dart aA Positive, "a+")+--                             ]+--                           , [ (Dart aE Negative, "e-")+--                             , (Dart aB Negative, "b-")+--                             , (Dart aD Negative, "d-")+--                             , (Dart aG Positive, "g+")+--                             ]+--                           , [ (Dart aE Positive, "e+")+--                             , (Dart aD Positive, "d+")+--                             , (Dart aC Negative, "c-")+--                             ]+--                           , [ (Dart aG Negative, "g-")+--                             ]+--                           ]+-- :}+--+--+-- This represents the following graph. Note that the graph is undirected, the+-- arrows are just to indicate what the Positive direction of the darts is.+--+-- ![myGraph](docs/Data/PlanarGraph/testG.png)++--------------------------------------------------------------------------------+-- * Representing The World++-- | The world in which the graph lives+data World = Primal | Dual deriving (Show,Eq)++-- | We can take the dual of a world. For the Primal this gives us the Dual,+-- for the Dual this gives us the Primal.+type family DualOf (sp :: World) where+  DualOf Primal = Dual+  DualOf Dual   = Primal++-- | The Dual of the Dual is the Primal.+dualDualIdentity :: forall w. DualOf (DualOf w) :~: w+dualDualIdentity = unsafeCoerce Refl+          -- manual proof:+          --    DualOf (DualOf Primal) = Primal+          --    DualOf (DualOf Dual)   = Dual+++--------------------------------------------------------------------------------+-- * VertexId's++-- | A vertex in a planar graph. A vertex is tied to a particular planar graph+-- by the phantom type s, and to a particular world w.+newtype VertexId s (w :: World) = VertexId { _unVertexId :: Int }+                                deriving (Eq,Ord,Enum,ToJSON,FromJSON,Generic,NFData)+-- VertexId's are in the range 0...|orbits|-1++-- | Shorthand for vertices in the primal.+type VertexId' s = VertexId s Primal++unVertexId :: Getter (VertexId s w) Int+unVertexId = to _unVertexId++instance Show (VertexId s w) where+  show (VertexId i) = "VertexId " ++ show i++--------------------------------------------------------------------------------+-- * FaceId's++-- | The type to reprsent FaceId's+newtype FaceId s w = FaceId { _unFaceId :: VertexId s (DualOf w) }+                   deriving (Eq,Ord,Enum,ToJSON,FromJSON)++-- | Shorthand for FaceId's in the primal.+type FaceId' s = FaceId s Primal++instance Show (FaceId s w) where+  show (FaceId (VertexId i)) = "FaceId " ++ show i+++--------------------------------------------------------------------------------+-- * The graph type itself++-- | A *connected* Planar graph with bidirected edges. I.e. the edges (darts) are+-- directed, however, for every directed edge, the edge in the oposite+-- direction is also in the graph.+--+-- The types v, e, and f are the are the types of the data associated with the+-- vertices, edges, and faces, respectively.+--+-- The orbits in the embedding are assumed to be in counterclockwise+-- order. Therefore, every dart directly bounds the face to its right.+data PlanarGraph s (w :: World) v e f = PlanarGraph { _embedding   :: Permutation (Dart s)+                                                    , _vertexData  :: V.Vector v+                                                    , _rawDartData :: V.Vector e+                                                    , _faceData    :: V.Vector f+                                                    , _dual        :: PlanarGraph s (DualOf w) f e v+                                                    } deriving (Generic)++instance (Show v, Show e, Show f) => Show (PlanarGraph s w v e f) where+  show (PlanarGraph e v r f _) = unwords [ "PlanarGraph"+                                         , "embedding =", show e+                                         , ", vertexData =", show v+                                         , ", rawDartData =", show r+                                         , ", faceData =", show f+                                         ]++instance (Eq v, Eq e, Eq f) => Eq (PlanarGraph s w v e f) where+  (PlanarGraph e v r f _) == (PlanarGraph e' v' r' f' _) =  e == e' && v == v'+                                                         && r == r' && f == f'++++-- ** lenses and getters++-- | Get the embedding, reprsented as a permutation of the darts, of this+-- graph.+embedding :: Getter (PlanarGraph s w v e f) (Permutation (Dart s))+embedding = to _embedding++vertexData :: Lens (PlanarGraph s w v e f) (PlanarGraph s w v' e f)+                   (V.Vector v) (V.Vector v')+vertexData = lens _vertexData (\g vD -> updateData (const vD) id id g)++rawDartData :: Lens (PlanarGraph s w v e f) (PlanarGraph s w v e' f)+                    (V.Vector e) (V.Vector e')+rawDartData = lens _rawDartData (\g dD -> updateData id (const dD) id g)++faceData :: Lens (PlanarGraph s w v e f) (PlanarGraph s w v e f')+                 (V.Vector f) (V.Vector f')+faceData = lens _faceData (\g fD -> updateData id id (const fD) g)++-- | Get the dual graph of this graph.+dual :: Getter (PlanarGraph s w v e f) (PlanarGraph s (DualOf w) f e v)+dual = to _dual+++-- FIXME: So I guess the two darts associated with an edge can store different+-- data. This is useful. Make sure that works as expected.++-- | lens to access the Dart Data+--+--+dartData :: Lens (PlanarGraph s w v e f) (PlanarGraph s w v e' f)+                 (V.Vector (Dart s, e))  (V.Vector (Dart s, e'))+dartData = lens darts (\g dD -> updateData id (const $ reorderEdgeData dD) id g)++-- | edgeData is just an alias for 'dartData'+edgeData :: Lens (PlanarGraph s w v e f) (PlanarGraph s w v e' f)+                 (V.Vector (Dart s, e)) (V.Vector (Dart s, e'))+edgeData = dartData++-- | Helper function to update the data in a planar graph. Takes care to update+-- both the data in the original graph as well as in the dual.+updateData :: forall s w v e f v' e' f'+           .  (V.Vector v -> V.Vector v')+           -> (V.Vector e -> V.Vector e')+           -> (V.Vector f -> V.Vector f')+           -> PlanarGraph s w v  e  f+           -> PlanarGraph s w v' e' f'+updateData = gcastWith proof updateData'+  where+    proof :: DualOf (DualOf w) :~: w+    proof = dualDualIdentity++-- | The function that does the actual work for 'updateData'+updateData'  :: (DualOf (DualOf w) ~ w)+             => (V.Vector v -> V.Vector v')+             -> (V.Vector e -> V.Vector e')+             -> (V.Vector f -> V.Vector f')+             -> PlanarGraph s w v  e  f+             -> PlanarGraph s w v' e' f'+updateData' fv fe ff (PlanarGraph em vtxData dData fData dg) = g'+  where+    vtxData' = fv vtxData+    dData'   = fe dData+    fData'   = ff fData++    g'       = PlanarGraph em              vtxData' dData' fData'   dg'+    dg'      = PlanarGraph (dg^.embedding) fData'   dData' vtxData' g'+++-- | Reorders the edge data to be in the right order to set edgeData+reorderEdgeData    :: Foldable f => f (Dart s, e) -> V.Vector e+reorderEdgeData ds = V.create $ do+                                  v <- MV.new (F.length ds)+                                  forM_ (F.toList ds) $ \(d,x) ->+                                    MV.write v (fromEnum d) x+                                  pure v++-- | Traverse the vertices+--+-- (^.vertexData) <$> traverseVertices (\i x -> Just (i,x)) myGraph+-- Just [(VertexId 0,()),(VertexId 1,()),(VertexId 2,()),(VertexId 3,())]+-- >>> traverseVertices (\i x -> print (i,x)) myGraph >> pure ()+-- (VertexId 0,())+-- (VertexId 1,())+-- (VertexId 2,())+-- (VertexId 3,())+traverseVertices   :: Applicative m+                   => (VertexId s w -> v -> m v')+                   -> PlanarGraph s w v e f+                   -> m (PlanarGraph s w v' e f)+traverseVertices f = itraverseOf (vertexData.itraversed) (\i -> f (VertexId i))++-- | Traverses the darts+--+-- >>> traverseDarts (\d x -> print (d,x)) myGraph >> pure ()+-- (Dart (Arc 0) +1,"a+")+-- (Dart (Arc 0) -1,"a-")+-- (Dart (Arc 1) +1,"b+")+-- (Dart (Arc 1) -1,"b-")+-- (Dart (Arc 2) +1,"c+")+-- (Dart (Arc 2) -1,"c-")+-- (Dart (Arc 3) +1,"d+")+-- (Dart (Arc 3) -1,"d-")+-- (Dart (Arc 4) +1,"e+")+-- (Dart (Arc 4) -1,"e-")+-- (Dart (Arc 5) +1,"g+")+-- (Dart (Arc 5) -1,"g-")+traverseDarts   :: Applicative m+                => (Dart s -> e -> m e')+                -> PlanarGraph s w v e f+                -> m (PlanarGraph s w v e' f)+traverseDarts f = itraverseOf (rawDartData.itraversed) (\i -> f (toEnum i))++-- | Traverses the faces+--+-- >>> traverseFaces (\i x -> print (i,x)) myGraph >> pure ()+-- (FaceId 0,())+-- (FaceId 1,())+-- (FaceId 2,())+-- (FaceId 3,())+traverseFaces   :: Applicative m+                => (FaceId s w -> f -> m f')+                -> PlanarGraph s w v e f+                -> m (PlanarGraph s w v e f')+traverseFaces f = itraverseOf (faceData.itraversed) (\i -> f (FaceId $ VertexId i))++--------------------------------------------------------------------------------+-- ** Constructing a Planar graph++-- | Construct a planar graph+--+-- running time: \(O(n)\).+planarGraph'      :: Permutation (Dart s) -> PlanarGraph s w () () ()+planarGraph' perm = pg+  where+    pg = PlanarGraph perm vData eData fData (computeDual pg)+        -- note the lazy calculation of computeDual that refers to pg itself+    d  = size perm+    e  = d `div` 2+    v  = V.length (perm^.orbits)+    f  = e - v + 2++    vData  = V.replicate v ()+    eData  = V.replicate d ()+    fData  = V.replicate f ()++-- | Construct a planar graph, given the darts in cyclic order around each+-- vertex.+--+-- running time: \(O(n)\).+planarGraph    :: [[(Dart s,e)]] -> PlanarGraph s Primal () e ()+planarGraph ds = (planarGraph' perm)&dartData .~ (V.fromList . concat $ ds)+  where+    n     = sum . map length $ ds+    perm  = toCycleRep n $ map (map fst) ds+++++-- | Produces the adjacencylists for all vertices in the graph. For every vertex, the+-- adjacent vertices are given in counter clockwise order.+--+-- Note that in case a vertex u as a self loop, we have that this vertexId occurs+-- twice in the list of neighbours, i.e.: u : [...,u,..,u,...]. Similarly, if there are+-- multiple darts between a pair of edges they occur multiple times.+--+-- running time: \(O(n)\)+toAdjacencyLists    :: PlanarGraph s w v e f -> [(VertexId s w, V.Vector (VertexId s w))]+toAdjacencyLists pg = map (\u -> (u,neighboursOf u pg)) . V.toList . vertices' $ pg+-- TODO: something weird happens when we have self-loops here.+++--------------------------------------------------------------------------------+-- ** Convenience functions++-- | Get the number of vertices+--+-- >>> numVertices myGraph+-- 4+numVertices :: PlanarGraph s w v e f -> Int+numVertices g = V.length (g^.embedding.orbits)++-- | Get the number of Darts+--+-- >>> numDarts myGraph+-- 12+numDarts :: PlanarGraph s w v e f -> Int+numDarts g = size (g^.embedding)++-- | Get the number of Edges+--+-- >>> numEdges myGraph+-- 6+numEdges :: PlanarGraph s w v e f -> Int+numEdges g = numDarts g `div` 2++-- | Get the number of faces+--+-- >>> numFaces myGraph+-- 4+numFaces   :: PlanarGraph s w v e f -> Int+numFaces g = numEdges g - numVertices g + 2+++-- | Enumerate all vertices+--+-- >>> vertices' myGraph+-- [VertexId 0,VertexId 1,VertexId 2,VertexId 3]+vertices'   :: PlanarGraph s w v e f -> V.Vector (VertexId s w)+vertices' g = VertexId <$> V.enumFromN 0 (V.length (g^.embedding.orbits))++-- | Enumerate all vertices, together with their vertex data++-- >>> vertices myGraph+-- [(VertexId 0,()),(VertexId 1,()),(VertexId 2,()),(VertexId 3,())]+vertices   :: PlanarGraph s w v e f -> V.Vector (VertexId s w, v)+vertices g = V.zip (vertices' g) (g^.vertexData)++++-- | Enumerate all darts+darts' :: PlanarGraph s w v e f -> V.Vector (Dart s)+darts' = elems . _embedding++-- | Get all darts together with their data+--+-- >>> mapM_ print $ darts myGraph+-- (Dart (Arc 0) -1,"a-")+-- (Dart (Arc 2) +1,"c+")+-- (Dart (Arc 1) +1,"b+")+-- (Dart (Arc 0) +1,"a+")+-- (Dart (Arc 4) -1,"e-")+-- (Dart (Arc 1) -1,"b-")+-- (Dart (Arc 3) -1,"d-")+-- (Dart (Arc 5) +1,"g+")+-- (Dart (Arc 4) +1,"e+")+-- (Dart (Arc 3) +1,"d+")+-- (Dart (Arc 2) -1,"c-")+-- (Dart (Arc 5) -1,"g-")+darts   :: PlanarGraph s w v e f -> V.Vector (Dart s, e)+darts g = (\d -> (d,g^.dataOf d)) <$> darts' g++-- | Enumerate all edges. We report only the Positive darts+edges' :: PlanarGraph s w v e f -> V.Vector (Dart s)+edges' = V.filter isPositive . darts'++-- | Enumerate all edges with their edge data. We report only the Positive+-- darts.+--+-- >>> mapM_ print $ edges myGraph+-- (Dart (Arc 2) +1,"c+")+-- (Dart (Arc 1) +1,"b+")+-- (Dart (Arc 0) +1,"a+")+-- (Dart (Arc 5) +1,"g+")+-- (Dart (Arc 4) +1,"e+")+-- (Dart (Arc 3) +1,"d+")+edges :: PlanarGraph s w v e f -> V.Vector (Dart s, e)+edges = V.filter (isPositive . fst) . darts+++-- | The tail of a dart, i.e. the vertex this dart is leaving from+--+-- running time: \(O(1)\)+tailOf     :: Dart s -> PlanarGraph s w v e f -> VertexId s w+tailOf d g = VertexId . fst $ lookupIdx (g^.embedding) d++-- | The vertex this dart is heading in to+--+-- running time: \(O(1)\)+headOf   :: Dart s -> PlanarGraph s w v e f -> VertexId s w+headOf d = tailOf (twin d)++-- | endPoints d g = (tailOf d g, headOf d g)+--+-- running time: \(O(1)\)+endPoints :: Dart s -> PlanarGraph s w v e f -> (VertexId s w, VertexId s w)+endPoints d g = (tailOf d g, headOf d g)+++-- | All edges incident to vertex v, in counterclockwise order around v.+--+-- running time: \(O(k)\), where \(k\) is the output size+incidentEdges                :: VertexId s w -> PlanarGraph s w v e f+                             -> V.Vector (Dart s)+incidentEdges (VertexId v) g = g^?!embedding.orbits.ix v+  -- TODO: The Delaunay triang. stuff seems to produce these in clockwise order instead++-- | All incoming edges incident to vertex v, in counterclockwise order around v.+incomingEdges     :: VertexId s w -> PlanarGraph s w v e f -> V.Vector (Dart s)+incomingEdges v g = V.filter (not . isPositive) $ incidentEdges v g++-- | All outgoing edges incident to vertex v, in counterclockwise order around v.+outgoingEdges     :: VertexId s w -> PlanarGraph s w v e f -> V.Vector (Dart s)+outgoingEdges v g = V.filter isPositive $ incidentEdges v g+++-- | Gets the neighbours of a particular vertex, in counterclockwise order+-- around the vertex.+--+-- running time: \(O(k)\), where \(k\) is the output size+neighboursOf     :: VertexId s w -> PlanarGraph s w v e f -> V.Vector (VertexId s w)+neighboursOf v g = otherVtx <$> incidentEdges v g+  where+    otherVtx d = let u = tailOf d g in if u == v then headOf d g else u++-- | Given a dart d that points into some vertex v, report the next dart in the+-- cyclic order around v.+--+-- running time: \(O(1)\)+nextIncidentEdge     :: Dart s -> PlanarGraph s w v e f -> Dart s+nextIncidentEdge d g = let perm  = g^.embedding+                           (i,j) = lookupIdx perm d+                       in next (perm^?!orbits.ix i) j+++-- | Given a dart d that points into some vertex v, report the next dart in the+-- cyclic order around v.+--+-- running time: \(O(1)\)+prevIncidentEdge     :: Dart s -> PlanarGraph s w v e f -> Dart s+prevIncidentEdge d g = let perm  = g^.embedding+                           (i,j) = lookupIdx perm d+                       in previous (perm^?!orbits.ix i) j+++--------------------------------------------------------------------------------+-- * Access data+++class HasDataOf g i where+  type DataOf g i+  -- | get the data associated with the value i.+  --+  -- running time: \(O(1)\) to read the data, \(O(n)\) to write it.+  dataOf :: i -> Lens' g (DataOf g i)++instance HasDataOf (PlanarGraph s w v e f) (VertexId s w) where+  type DataOf (PlanarGraph s w v e f) (VertexId s w) = v+  dataOf (VertexId i) = vertexData.singular (ix i)++instance HasDataOf (PlanarGraph s w v e f) (Dart s) where+  type DataOf (PlanarGraph s w v e f) (Dart s) = e+  dataOf d = rawDartData.singular (ix $ fromEnum d)++instance HasDataOf (PlanarGraph s w v e f) (FaceId s w) where+  type DataOf (PlanarGraph s w v e f) (FaceId s w) = f+  dataOf (FaceId (VertexId i)) = faceData.singular (ix i)+++-- | Data corresponding to the endpoints of the dart+endPointDataOf   :: Dart s -> Getter (PlanarGraph s w v e f) (v,v)+endPointDataOf d = to $ endPointData d+++-- | Data corresponding to the endpoints of the dart+--+-- running time: \(O(1)\)+endPointData     :: Dart s -> PlanarGraph s w v e f -> (v,v)+endPointData d g = let (u,v) = endPoints d g in (g^.dataOf u, g^.dataOf v)+++--------------------------------------------------------------------------------+-- * The Dual graph++-- | The dual of this graph+--+-- >>> :{+--  let fromList = V.fromList+--      answer = fromList [ fromList [dart 0 "-1"]+--                        , fromList [dart 2 "+1",dart 4 "+1",dart 1 "-1",dart 0 "+1"]+--                        , fromList [dart 1 "+1",dart 3 "-1",dart 2 "-1"]+--                        , fromList [dart 4 "-1",dart 3 "+1",dart 5 "+1",dart 5 "-1"]+--                        ]+--  in (computeDual myGraph)^.embedding.orbits == answer+-- :}+-- True+--+-- running time: \(O(n)\).+computeDual :: forall s w v e f. PlanarGraph s w v e f -> PlanarGraph s (DualOf w) f e v+computeDual = gcastWith proof computeDual'+  where+    proof :: DualOf (DualOf w) :~: w+    proof = dualDualIdentity++-- | Does the actual work for dualGraph+computeDual'   :: (DualOf (DualOf w) ~ w)+               => PlanarGraph s w v e f -> PlanarGraph s (DualOf w) f e v+computeDual' g = dualG+  where+    perm  = g^.embedding+    dualG = PlanarGraph (cycleRep (elems perm) (apply perm . twin))+                        (g^.faceData)+                        (g^.rawDartData)+                        (g^.vertexData)+                        g
+ src/Data/PlanarGraph/Dart.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.PlanarGraph.Dart+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Data type for representing Darts (edges) in a planar graph.+--------------------------------------------------------------------------------+module Data.PlanarGraph.Dart where++import Control.DeepSeq+import Control.Lens hiding ((.=))+import GHC.Generics (Generic)+import Test.QuickCheck (Arbitrary(..),suchThat)++-- $setup+-- >>> :{+-- let dart i s = Dart (Arc i) (read s)+-- :}++--------------------------------------------------------------------------------++-- | An Arc is a directed edge in a planar graph. The type s is used to tie+-- this arc to a particular graph.+newtype Arc s = Arc { _unArc :: Int } deriving (Eq,Ord,Enum,Bounded,Generic,NFData)++instance Show (Arc s) where+  show (Arc i) = "Arc " ++ show i++instance Arbitrary (Arc s) where+  arbitrary = Arc <$> (arbitrary `suchThat` (>= 0))+++-- | Darts have a direction which is either Positive or Negative (shown as +1+-- or -1, respectively).+data Direction = Negative | Positive deriving (Eq,Ord,Bounded,Enum,Generic)++instance NFData Direction++instance Show Direction where+  show Positive = "+1"+  show Negative = "-1"++instance Read Direction where+  readsPrec _ "-1" = [(Negative,"")]+  readsPrec _ "+1" = [(Positive,"")]+  readsPrec _ _    = []++instance Arbitrary Direction where+  arbitrary = (\b -> if b then Positive else Negative) <$> arbitrary++-- | Reverse the direcion+rev          :: Direction -> Direction+rev Negative = Positive+rev Positive = Negative++-- | A dart represents a bi-directed edge. I.e. a dart has a direction, however+-- the dart of the oposite direction is always present in the planar graph as+-- well.+data Dart s = Dart { _arc       :: !(Arc s)+                   , _direction :: !Direction+                   } deriving (Eq,Ord,Generic)+makeLenses ''Dart++instance NFData (Dart s)++instance Show (Dart s) where+  show (Dart a d) = "Dart (" ++ show a ++ ") " ++ show d++instance Arbitrary (Dart s) where+  arbitrary = Dart <$> arbitrary <*> arbitrary++-- | Get the twin of this dart (edge)+--+-- >>> twin (dart 0 "+1")+-- Dart (Arc 0) -1+-- >>> twin (dart 0 "-1")+-- Dart (Arc 0) +1+twin            :: Dart s -> Dart s+twin (Dart a d) = Dart a (rev d)++-- | test if a dart is Positive+isPositive   :: Dart s -> Bool+isPositive d = d^.direction == Positive+++instance Enum (Dart s) where+  toEnum x+    | even x    = Dart (Arc $ x `div` 2) Positive+    | otherwise = Dart (Arc $ x `div` 2) Negative+  -- get the back edge by adding one++  fromEnum (Dart (Arc i) d) = case d of+                                Positive -> 2*i+                                Negative -> 2*i + 1+++-- | Enumerates all darts such that+-- allDarts !! i = d   <=> i == fromEnum d+allDarts :: [Dart s]+allDarts = concatMap (\a -> [Dart a Positive, Dart a Negative]) [Arc 0..]
+ src/Data/PlanarGraph/Dual.hs view
@@ -0,0 +1,145 @@+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.PlanarGraph+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Data type for representing connected planar graphs. This module contains+-- everything that has to do with the dual graph (i.e. computing it/ operations+-- on faces etc.)+--------------------------------------------------------------------------------+module Data.PlanarGraph.Dual where++import           Control.Lens hiding ((.=))+import           Data.PlanarGraph.Core+import           Data.PlanarGraph.Dart+import qualified Data.Vector as V+import           Data.Maybe (fromMaybe)++--------------------------------------------------------------------------------++--------------------------------------------------------------------------------+-- $setup+-- >>> :{+-- let dart i s = Dart (Arc i) (read s)+--     (aA:aB:aC:aD:aE:aG:_) = take 6 [Arc 0..]+--     myGraph :: PlanarGraph () Primal () String ()+--     myGraph = planarGraph [ [ (Dart aA Negative, "a-")+--                             , (Dart aC Positive, "c+")+--                             , (Dart aB Positive, "b+")+--                             , (Dart aA Positive, "a+")+--                             ]+--                           , [ (Dart aE Negative, "e-")+--                             , (Dart aB Negative, "b-")+--                             , (Dart aD Negative, "d-")+--                             , (Dart aG Positive, "g+")+--                             ]+--                           , [ (Dart aE Positive, "e+")+--                             , (Dart aD Positive, "d+")+--                             , (Dart aC Negative, "c-")+--                             ]+--                           , [ (Dart aG Negative, "g-")+--                             ]+--                           ]+-- :}+--+--+-- This represents the following graph. Note that the graph is undirected, the+-- arrows are just to indicate what the Positive direction of the darts is.+--+-- ![myGraph](docs/Data/PlanarGraph/testG.png)+++-- | Enumerate all faces in the planar graph+faces' :: PlanarGraph s w v e f -> V.Vector (FaceId s w)+faces' = fmap FaceId . vertices' . _dual++-- | All faces with their face data.+faces   :: PlanarGraph s w v e f -> V.Vector (FaceId s w, f)+faces g = V.zip (faces' g) (g^.faceData)++-- | The face to the left of the dart+--+-- >>> leftFace (dart 1 "+1") myGraph+-- FaceId 1+-- >>> leftFace (dart 1 "-1") myGraph+-- FaceId 2+-- >>> leftFace (dart 2 "+1") myGraph+-- FaceId 2+-- >>> leftFace (dart 0 "+1") myGraph+-- FaceId 0+--+-- running time: \(O(1)\).+leftFace     :: Dart s -> PlanarGraph s w v e f -> FaceId s w+leftFace d g = FaceId . headOf d $ _dual g+++-- | The face to the right of the dart+--+-- >>> rightFace (dart 1 "+1") myGraph+-- FaceId 2+-- >>> rightFace (dart 1 "-1") myGraph+-- FaceId 1+-- >>> rightFace (dart 2 "+1") myGraph+-- FaceId 1+-- >>> rightFace (dart 0 "+1") myGraph+-- FaceId 1+--+-- running time: \(O(1)\).+rightFace     :: Dart s -> PlanarGraph s w v e f -> FaceId s w+rightFace d g = FaceId . tailOf d $ _dual g+++-- | Get the next edge along the face+--+-- running time: \(O(1)\).+nextEdge   :: Dart s -> PlanarGraph s w v e f -> Dart s+nextEdge d = nextIncidentEdge d . _dual++-- | Get the previous edge along the face+--+-- running time: \(O(1)\).+prevEdge :: Dart s -> PlanarGraph s w v e f -> Dart s+prevEdge d = prevIncidentEdge d . _dual+++-- | Gets a dart bounding this face. I.e. a dart d such that the face lies to+-- the right of the dart.+boundaryDart   :: FaceId s w -> PlanarGraph s w v e f -> Dart s+boundaryDart f = V.head . boundary f+-- TODO: make sure that this is indeed to the right.++-- | The darts bounding this face, for internal faces in clockwise order, for+-- the outer face in counter clockwise order.+--+--+-- running time: \(O(k)\), where \(k\) is the output size.+boundary              :: FaceId s w -> PlanarGraph s w v e f -> V.Vector (Dart s)+boundary (FaceId v) g = incidentEdges v $ _dual g+++-- | Generates the darts incident to a face, starting with the given dart.+--+--+-- \(O(k)\), where \(k\) is the number of darts reported+boundary'     :: Dart s -> PlanarGraph s w v e f -> V.Vector (Dart s)+boundary' d g = fromMaybe (error "boundary'")  . rotateTo d $ boundary (rightFace d g) g+  where+    rotateTo     :: Eq a => a -> V.Vector a -> Maybe (V.Vector a)+    rotateTo x v = f <$> V.elemIndex x v+      where+        f i = let (a,b) = V.splitAt i v  in b <> a+++-- | The vertices bounding this face, for internal faces in clockwise order, for+-- the outer face in counter clockwise order.+--+--+-- running time: \(O(k)\), where \(k\) is the output size.+boundaryVertices     :: FaceId s w -> PlanarGraph s w v e f -> V.Vector (VertexId s w)+boundaryVertices f g = fmap (flip tailOf g) $ boundary f g++-- -- | Gets the next dart along the face+-- nextDart     :: Dart s -> PlanarGraph s w v e f -> Dart s+-- nextDart d g = f rightFace e
+ src/Data/PlanarGraph/EdgeOracle.hs view
@@ -0,0 +1,157 @@+{-# LANGUAGE ScopedTypeVariables #-}+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.PlanarGraph.EdgeOracle+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Data structure to represent a planar graph with which we can test in+-- \(O(1)\) time if an edge between a pair of vertices exists.+--------------------------------------------------------------------------------+module Data.PlanarGraph.EdgeOracle where++import           Control.Applicative (Alternative(..))+import           Control.Lens hiding ((.=))+import           Control.Monad.ST (ST)+import           Control.Monad.State.Strict+import           Data.Bitraversable+import           Data.Ext+import qualified Data.Foldable as F+import           Data.Maybe (catMaybes, isJust)+import           Data.PlanarGraph.Core+import           Data.PlanarGraph.Dart+import           Data.Traversable (fmapDefault,foldMapDefault)+import qualified Data.Vector as V+import qualified Data.Vector.Generic as GV+import qualified Data.Vector.Mutable as MV+import qualified Data.Vector.Unboxed as UV+import qualified Data.Vector.Unboxed.Mutable as UMV++--------------------------------------------------------------------------------++-- | Edge Oracle:+--+-- main idea: store adjacency lists in such a way that we store an edge (u,v)+-- either in u's adjacency list or in v's. This can be done s.t. all adjacency+-- lists have length at most 6.+--+-- note: Every edge is stored exactly once (i.e. either at u or at v, but not both)+newtype EdgeOracle s w a =+  EdgeOracle { _unEdgeOracle :: V.Vector (V.Vector (VertexId s w :+ a)) }+                         deriving (Show,Eq)++instance Functor (EdgeOracle s w) where+  fmap = fmapDefault++instance Foldable (EdgeOracle s w) where+  foldMap = foldMapDefault++instance Traversable (EdgeOracle s w) where+  traverse f (EdgeOracle v) = EdgeOracle <$> traverse g v+    where+      -- g   :: V.Vector (VertexId :+ a) -> f (V.Vector (VertexId :+ b))+      g = traverse (bitraverse pure f)+++-- | Given a planar graph, construct an edge oracle. Given a pair of vertices+-- this allows us to efficiently find the dart representing this edge in the+-- graph.+--+-- pre: No self-loops and no multi-edges!!!+--+-- running time: \(O(n)\)+edgeOracle   :: PlanarGraph s w v e f -> EdgeOracle s w (Dart s)+edgeOracle g = buildEdgeOracle [ (v, mkAdjacency v <$> incidentEdges v g)+                               | v <- F.toList $ vertices' g+                               ]+  where+    mkAdjacency v d = otherVtx v d :+ d+    otherVtx v d = let u = tailOf d g in if u == v then headOf d g else u++++-- | Builds an edge oracle that can be used to efficiently test if two vertices+-- are connected by an edge.+--+-- running time: \(O(n)\)+buildEdgeOracle        :: forall f s w e. (Foldable f)+                       => [(VertexId s w, f (VertexId s w :+ e))] -> EdgeOracle s w e+buildEdgeOracle inAdj' = EdgeOracle $ V.create $ do+                          counts <- UV.thaw initCounts+                          marks  <- UMV.replicate (UMV.length counts) False+                          outV   <- MV.new (UMV.length counts)+                          build counts marks outV initQ+                          pure outV+    -- main idea: maintain a vector with counts; i.e. how many unprocessed+    -- vertices are adjacent to u, and a bit vector with marks to keep track if+    -- a vertex has been processed yet. When we process a vertex, we keep only+    -- the adjacencies of unprocessed verticese.+  where+    -- Convert to a vector representation+    inAdj = V.create $ do+              mv <- MV.new (length inAdj')+              forM_ inAdj' $ \(VertexId i,adjI) ->+                MV.write mv i (V.fromList . F.toList $ adjI)+              pure mv++    initCounts = V.convert . fmap GV.length $ inAdj+    -- initial vertices available for processing+    initQ = GV.ifoldr (\i k q -> if k <= 6 then i : q else q) [] initCounts++    -- | Construct the adjacencylist for vertex i. I.e. by retaining only adjacent+    -- vertices that have not been processed yet.+    extractAdj         :: UMV.MVector s' Bool -> Int+                       -> ST s' (V.Vector (VertexId s w :+ e))+    extractAdj marks i = let p = fmap not . UMV.read marks . (^.core.unVertexId)+                         in GV.filterM  p $ inAdj V.! i++    -- | Decreases the number of adjacencies that vertex j has+    -- if it has <= 6 adjacencies left it has become available for processing+    decrease                          :: UMV.MVector s' Int -> (VertexId s w :+ e')+                                      -> ST s' (Maybe Int)+    decrease counts (VertexId j :+ _) = do k <- UMV.read counts j+                                           let k'  = k - 1+                                           UMV.write counts j k'+                                           pure $ if k' <= 6 then Just j else Nothing++    -- The actual algorithm that builds the items+    build :: UMV.MVector s' Int -> UMV.MVector s' Bool+          -> MV.MVector s' (V.Vector (VertexId s w :+ e)) -> [Int] -> ST s' ()+    build _      _     _    []    = pure ()+    build counts marks outV (i:q) = do+             b <- UMV.read marks i+             nq <- if b then pure []+                        else do+                          adjI <- extractAdj marks i+                          MV.write outV i adjI+                          UMV.write marks i True+                          V.toList <$> mapM (decrease counts) adjI+             build counts marks outV (catMaybes nq <> q)++++-- | Test if u and v are connected by an edge.+--+-- running time: \(O(1)\)+hasEdge     :: VertexId s w -> VertexId s w -> EdgeOracle s w a -> Bool+hasEdge u v = isJust . findEdge u v+++-- | Find the edge data corresponding to edge (u,v) if such an edge exists+--+-- running time: \(O(1)\)+findEdge :: VertexId s w -> VertexId s w -> EdgeOracle s w a -> Maybe a+findEdge  (VertexId u) (VertexId v) (EdgeOracle os) = find' u v <|> find' v u+  where+    find' j i = fmap (^.extra) . F.find (\(VertexId k :+ _) -> j == k) $ os V.! i++-- | Given a pair of vertices (u,v) returns the dart, oriented from u to v,+-- corresponding to these vertices.+--+-- running time: \(O(1)\)+findDart :: VertexId s w -> VertexId s w -> EdgeOracle s w (Dart s) -> Maybe (Dart s)+findDart (VertexId u) (VertexId v) (EdgeOracle os) = find' twin u v <|> find' id v u+  where+    -- looks up j in the adjacencylist of i and applies f to the result+    find' f j i = fmap (f . (^.extra)) . F.find (\(VertexId k :+ _) -> j == k) $ os V.! i
+ src/Data/PlanarGraph/IO.hs view
@@ -0,0 +1,156 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE ScopedTypeVariables #-}+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.PlanarGraph.IO+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Converting from/to our JSON/Yaml representation of the plane graph+--+--------------------------------------------------------------------------------+module Data.PlanarGraph.IO where++import           Control.Lens+import           Control.Monad (forM_)+import           Control.Monad.State.Strict+import           Data.Aeson+import           Data.Bifunctor+import           Data.Ext+import qualified Data.Foldable as F+import           Data.Maybe (fromJust)+import           Data.Permutation+import           Data.PlanarGraph.AdjRep (Face(Face), Vtx(Vtx),Gr(Gr))+import           Data.PlanarGraph.Core+import           Data.PlanarGraph.Dart+import           Data.PlanarGraph.Dual+import           Data.PlanarGraph.EdgeOracle+import           Data.Proxy+import qualified Data.Vector as V+import qualified Data.Vector.Mutable as MV++--------------------------------------------------------------------------------++instance (ToJSON v, ToJSON e, ToJSON f) => ToJSON (PlanarGraph s w v e f) where+  toEncoding = toEncoding . toAdjRep+  toJSON     = toJSON     . toAdjRep++instance (FromJSON v, FromJSON e, FromJSON f) => FromJSON (PlanarGraph s Primal v e f) where+  parseJSON v = fromAdjRep (Proxy :: Proxy s) <$> parseJSON v++--------------------------------------------------------------------------------+++-- | Transforms the planar graph into a format taht can be easily converted+-- into JSON format. For every vertex, the adjacent vertices are given in+-- counter clockwise order.+--+-- See 'toAdjacencyLists' for notes on how we handle self-loops.+--+-- running time: \(O(n)\)+toAdjRep   :: PlanarGraph s w v e f -> Gr (Vtx v e) (Face f)+toAdjRep g = Gr vs fs+  where+    vs = [ Vtx ui (map (mkEdge u) $ F.toList us) (g^.dataOf u)+         | (u@(VertexId ui),us) <- toAdjacencyLists g+         ]+    fs = [ Face (outerComponentEdge f) x+         | (f,x) <- F.toList $ faces g+         ]++    outerComponentEdge f = bimap (^.unVertexId) (^.unVertexId)+                         $ endPoints (boundaryDart f g) g++    eo = edgeOracle g++    findData u v = (\d -> g^.dataOf d) <$> findDart u v eo+    mkEdge u v@(VertexId vi) = (vi,fromJust $ findData u v)+++-- | Read a planar graph, given in JSON format into a planar graph. The adjacencylists+-- should be in counter clockwise order.+--+-- running time: \(O(n)\)+fromAdjRep                  :: proxy s -> Gr (Vtx v e) (Face f) -> PlanarGraph s Primal v e f+fromAdjRep px gr@(Gr as fs) = g&vertexData .~ reorder vs' _unVertexId+                               &dartData   .~ ds+                               &faceData   .~ reorder fs' (_unVertexId._unFaceId)+  where+    -- build the actual graph using the adjacencies+    g = buildGraph px gr+    -- build an edge oracle so that we can quickly lookup the dart corresponding to a+    -- pair of vertices.+    oracle = edgeOracle g+    -- function to lookup a given dart+    findEdge' u v = fromJust $ findDart u v oracle+    -- faces are right of oriented darts+    findFace ui vi = let d = findEdge' (VertexId ui) (VertexId vi) in rightFace d g++    vs' = V.fromList [ VertexId vi :+ v     | Vtx vi _ v <- as ]+    fs' = V.fromList [ findFace ui vi :+ f | Face (ui,vi) f <- fs ]++    ds = V.fromList $ concatMap (\(Vtx vi us _) ->+                                   [(findEdge' (VertexId vi) (VertexId ui), x) | (ui,x) <- us]+                                ) as++  -- TODO: Properly handle graphs with self-loops++-- | Builds the graph from the adjacency lists (but ignores all associated data)+buildGraph              :: proxy s -> Gr (Vtx v e) (Face f) -> PlanarGraph s Primal () () ()+buildGraph _ (Gr as' _) = fromAdjacencyLists as+  where+    as = [ (VertexId vi, V.fromList [VertexId ui | (ui,_) <- us])+         | Vtx vi us _ <- as'+         ]++-- make sure we order the data values appropriately+reorder     :: V.Vector (i :+ a) -> (i -> Int) -> V.Vector a+reorder v f = V.create $ do+                           v' <- MV.new (V.length v)+                           forM_ v $ \(i :+ x) ->+                             MV.write v' (f i) x+                           pure v'++--------------------------------------------------------------------------------++-- | Construct a planar graph from a adjacency matrix. For every vertex, all+-- vertices should be given in counter clockwise order.+--+-- pre: No self-loops, and no multi-edges+--+-- running time: \(O(n)\).+fromAdjacencyLists      :: forall s w h. (Foldable h, Functor h)+                        => [(VertexId s w, h (VertexId s w))]+                        -> PlanarGraph s w () () ()+fromAdjacencyLists adjM = planarGraph' . toCycleRep n $ perm+  where+    n    = sum . fmap length $ perm+    perm = map toOrbit  $ adjM'++    adjM' = fmap (second F.toList) adjM++    -- -- | Assign Arcs+    -- adjM' = (^._1) . foldr assignArcs (SP [] 0) $ adjM++    -- Build an edgeOracle, so that we can query the arcId assigned to+    -- an edge in O(1) time.+    oracle :: EdgeOracle s w Int+    oracle = fmap (^.core) . assignArcs . buildEdgeOracle+           . map (second $ map ext)  $ adjM'++    toOrbit (u,adjU) = concatMap (toDart u) adjU++    -- if u = v we have a self-loop, so we add both a positive and a negative dart+    toDart u v = let Just a = findEdge u v oracle+                 in case u `compare` v of+                      LT -> [Dart (Arc a) Positive]+                      EQ -> [Dart (Arc a) Positive, Dart (Arc a) Negative]+                      GT -> [Dart (Arc a) Negative]+++assignArcs   :: EdgeOracle s w e -> EdgeOracle s w (Int :+ e)+assignArcs o = evalState (traverse f o) 0+  where+    f   :: e -> State Int (Int :+ e)+    f e = do i <- get ; put (i+1) ; pure (i :+ e)
+ src/Data/Range.hs view
@@ -0,0 +1,283 @@+{-# LANGUAGE TemplateHaskell   #-}+{-# LANGUAGE DeriveAnyClass  #-}+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.Range+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Data type for representing Generic Ranges (Intervals) and functions that+-- work with them.+--+--------------------------------------------------------------------------------+module Data.Range( EndPoint(..)+                 , isOpen, isClosed+                 , unEndPoint+                 , Range(..)+                 , prettyShow+                 , lower, upper+                 , pattern OpenRange, pattern ClosedRange, pattern Range'+                 , inRange, width, clipLower, clipUpper, midPoint, clampTo+                 , isValid, covers++                 , shiftLeft, shiftRight+                 ) where++import Control.DeepSeq+import Control.Lens+import Data.Intersection+import Data.Vinyl.CoRec+import GHC.Generics (Generic)+import Test.QuickCheck+import Text.Printf (printf)++--------------------------------------------------------------------------------+-- * Representing Endpoints of a Range++-- | Endpoints of a range may either be open or closed.+data EndPoint a = Open   !a+                | Closed !a+                deriving (Show,Read,Eq,Functor,Foldable,Traversable,Generic,NFData)++instance Ord a => Ord (EndPoint a) where+  -- | order on the actual value, and Open before Closed+  a `compare` b = f a `compare` f b+    where+      f (Open x)   = (x,False)+      f (Closed x) = (x,True)++instance Arbitrary r => Arbitrary (EndPoint r) where+  arbitrary = frequency [ (1, Open   <$> arbitrary)+                        , (9, Closed <$> arbitrary)+                        ]++_unEndPoint            :: EndPoint a -> a+_unEndPoint (Open a)   = a+_unEndPoint (Closed a) = a++unEndPoint :: Lens (EndPoint a) (EndPoint b) a b+unEndPoint = lens _unEndPoint f+  where+    f (Open _) a   = Open a+    f (Closed _) a = Closed a+{-# INLINE unEndPoint #-}++isOpen          :: EndPoint a -> Bool+isOpen (Open _) = True+isOpen _        = False++isClosed :: EndPoint a -> Bool+isClosed = not . isOpen+++--------------------------------------------------------------------------------+-- * The Range Data type++-- | Data type for representing ranges.+data Range a = Range { _lower :: !(EndPoint a)+                     , _upper :: !(EndPoint a)+                     }+               deriving (Eq,Functor,Foldable,Traversable,Generic,NFData)+makeLenses ''Range++instance Show a => Show (Range a) where+  show (Range l u) = printf "Range (%s) (%s)" (show l) (show u)+++pattern OpenRange       :: a -> a -> Range a+pattern OpenRange   l u = Range (Open l)   (Open u)++pattern ClosedRange     :: a -> a -> Range a+pattern ClosedRange l u = Range (Closed l) (Closed u)++-- | A range from l to u, ignoring/forgetting the type of the endpoints+pattern Range'     :: a -> a -> Range a+pattern Range' l u <- ((\r -> (r^.lower.unEndPoint,r^.upper.unEndPoint) -> (l,u)))+{-# COMPLETE Range' #-}++instance (Arbitrary r, Ord r) => Arbitrary (Range r) where+  arbitrary = do+                l <- arbitrary+                r <- suchThat arbitrary (p l)+                return $ Range l r+   where+     p (Open l)   r = l <  r^.unEndPoint+     p (Closed l) r = l <= r^.unEndPoint+++-- | Helper function to show a range in mathematical notation.+--+-- >>> prettyShow $ OpenRange 0 2+-- "(0,2)"+-- >>> prettyShow $ ClosedRange 0 2+-- "[0,2]"+-- >>> prettyShow $ Range (Open 0) (Closed 5)+-- "(0,5]"+prettyShow             :: Show a => Range a -> String+prettyShow (Range l u) = concat [ lowerB, show (l^.unEndPoint), ","+                                , show (u^.unEndPoint), upperB+                                ]+  where+    lowerB = if isOpen l then "(" else "["+    upperB = if isOpen u then ")" else "]"++++-- | Test if a value lies in a range.+--+-- >>> 1 `inRange` (OpenRange 0 2)+-- True+-- >>> 1 `inRange` (OpenRange 0 1)+-- False+-- >>> 1 `inRange` (ClosedRange 0 1)+-- True+-- >>> 1 `inRange` (ClosedRange 1 1)+-- True+-- >>> 10 `inRange` (OpenRange 1 10)+-- False+-- >>> 10 `inRange` (ClosedRange 0 1)+-- False+--+-- This one is kind of weird+--+-- >>> 0 `inRange` Range (Closed 0) (Open 0)+-- False+inRange                 :: Ord a => a -> Range a -> Bool+x `inRange` (Range l u) = case ((l^.unEndPoint) `compare` x, x `compare` (u^.unEndPoint)) of+    (_, GT) -> False+    (GT, _) -> False+    (LT,LT) -> True+    (LT,EQ) -> include u -- depends on only u+    (EQ,LT) -> include l -- depends on only l+    (EQ,EQ) -> include l && include u -- depends on l and u+  where+    include = isClosed++type instance IntersectionOf (Range a) (Range a) = [ NoIntersection, Range a]++instance Ord a => (Range a) `IsIntersectableWith` (Range a) where++  nonEmptyIntersection = defaultNonEmptyIntersection++  -- The intersection is empty, if after clipping, the order of the end points is inverted+  -- or if the endpoints are the same, but both are open.+  (Range l u) `intersect` s = let i = clipLower' l . clipUpper' u $ s+                              in if isValid i then coRec i else coRec NoIntersection++-- | Get the width of the interval+--+-- >>> width $ ClosedRange 1 10+-- 9+-- >>> width $ OpenRange 5 10+-- 5+width   :: Num r => Range r -> r+width i = i^.upper.unEndPoint - i^.lower.unEndPoint++midPoint   :: Fractional r => Range r -> r+midPoint r = let w = width r in r^.lower.unEndPoint + (w / 2)++-- | Clamps a value to a range. I.e. if the value lies outside the range we+-- report the closest value "in the range". Note that if an endpoint of the+-- range is open we report that value anyway, so we return a value that is+-- truely inside the range only if that side of the range is closed.+--+-- >>> clampTo (ClosedRange 0 10) 20+-- 10+-- >>> clampTo (ClosedRange 0 10) (-20)+-- 0+-- >>> clampTo (ClosedRange 0 10) 5+-- 5+-- >>> clampTo (OpenRange 0 10) 20+-- 10+-- >>> clampTo (OpenRange 0 10) (-20)+-- 0+-- >>> clampTo (OpenRange 0 10) 5+-- 5+clampTo                :: Ord r => Range r -> r -> r+clampTo (Range' l u) x = (x `max` l) `min` u+++--------------------------------------------------------------------------------+-- * Helper functions++-- | Clip the interval from below. I.e. intersect with the interval {l,infty),+-- where { is either open, (, orr closed, [.+clipLower     :: Ord a => EndPoint a -> Range a -> Maybe (Range a)+clipLower l r = let r' = clipLower' l r in if isValid r' then Just r' else Nothing++-- | Clip the interval from above. I.e. intersect with (-\infty, u}, where } is+-- either open, ), or closed, ],+clipUpper     :: Ord a => EndPoint a -> Range a -> Maybe (Range a)+clipUpper u r = let r' = clipUpper' u r in if isValid r' then Just r' else Nothing++-- | Wether or not the first range completely covers the second one+covers       :: forall a. Ord a => Range a -> Range a -> Bool+x `covers` y = maybe False (== y) . asA @(Range a) $ x `intersect` y+++-- | Check if the range is valid and nonEmpty, i.e. if the lower endpoint is+-- indeed smaller than the right endpoint. Note that we treat empty open-ranges+-- as invalid as well.+isValid             :: Ord a => Range a -> Bool+isValid (Range l u) = case (_unEndPoint l) `compare` (_unEndPoint u) of+                          LT                            -> True+                          EQ | isClosed l || isClosed u -> True+                          _                             -> False++-- operation is unsafe, as it may produce an invalid range (where l > u)+clipLower'                  :: Ord a => EndPoint a -> Range a -> Range a+clipLower' l' r@(Range l u) = case l' `cmpLower` l of+                                GT -> Range l' u+                                _  -> r+-- operation is unsafe, as it may produce an invalid range (where l > u)+clipUpper'                  :: Ord a => EndPoint a -> Range a -> Range a+clipUpper' u' r@(Range l u) = case u' `cmpUpper` u of+                                LT -> Range l u'+                                _  -> r++-- | Compare end points, Closed < Open+cmpLower     :: Ord a => EndPoint a -> EndPoint a -> Ordering+cmpLower a b = case (_unEndPoint a) `compare` (_unEndPoint b) of+                 LT -> LT+                 GT -> GT+                 EQ -> case (a,b) of+                         (Open _,   Open _)   -> EQ  -- if both are same type, report EQ+                         (Closed _, Closed _) -> EQ+                         (Open _,  _)         -> GT  -- otherwise, choose the Closed one+                         (Closed _,_)         -> LT  -- is the *smallest*+++-- | Compare the end points, Open < Closed+cmpUpper     :: Ord a => EndPoint a -> EndPoint a -> Ordering+cmpUpper a b = case (_unEndPoint a) `compare` (_unEndPoint b) of+                 LT -> LT+                 GT -> GT+                 EQ -> case (a,b) of+                         (Open _,   Open _)   -> EQ  -- if both are same type, report EQ+                         (Closed _, Closed _) -> EQ+                         (Open _,  _)         -> LT  -- otherwise, choose the Closed one+                         (Closed _,_)         -> GT  -- is the *largest*+++++--------------------------------------------------------------------------------++-- | Shift a range x units to the left+--+-- >>> prettyShow $ shiftLeft 10 (ClosedRange 10 20)+-- "[0,10]"+-- >>> prettyShow $ shiftLeft 10 (OpenRange 15 25)+-- "(5,15)"+shiftLeft   :: Num r => r -> Range r -> Range r+shiftLeft x = shiftRight (-x)++-- | Shifts the range to the right+--+-- >>> prettyShow $ shiftRight 10 (ClosedRange 10 20)+-- "[20,30]"+-- >>> prettyShow $ shiftRight 10 (OpenRange 15 25)+-- "(25,35)"+shiftRight   :: Num r => r -> Range r -> Range r+shiftRight x = fmap (+x)
+ src/Data/Sequence/Util.hs view
@@ -0,0 +1,76 @@+module Data.Sequence.Util where++import Data.Sequence(Seq, ViewL(..),ViewR(..))+import qualified Data.Sequence as S+import qualified Data.Vector.Generic as V++--------------------------------------------------------------------------------++-- | Given a monotonic predicate, Get the index h such that everything strictly+-- smaller than h has: p i = False, and all i >= h, we have p h = True+--+-- returns Nothing if no element satisfies p+--+-- running time: \(O(\log^2 n + T*\log n)\), where \(T\) is the time to execute the+-- predicate.+binarySearchSeq     :: (a -> Bool) -> Seq a -> Maybe Int+binarySearchSeq p s = case S.viewr s of+                       EmptyR                 -> Nothing+                       (_ :> x)   | p x       -> Just $ case S.viewl s of+                         (y :< _) | p y          -> 0+                         _                       -> binarySearch p' 0 u+                                  | otherwise -> Nothing+  where+    p' = p . S.index s+    u  = S.length s - 1++-- | Given a monotonic predicate, get the index h such that everything strictly+-- smaller than h has: p i = False, and all i >= h, we have p h = True+--+-- returns Nothing if no element satisfies p+--+-- running time: \(O(T*\log n)\), where \(T\) is the time to execute the+-- predicate.+binarySearchVec                             :: V.Vector v a+                                            => (a -> Bool) -> v a -> Maybe Int+binarySearchVec p' v | V.null v   = Nothing+                     | not $ p n' = Nothing+                     | otherwise  = Just $ if p 0 then 0+                                                  else binarySearch p 0 n'+  where+    n' = V.length v - 1+    p = p' . (v V.!)+++-- | Partition the seq s given a monotone predicate p into (xs,ys) such that+--+-- all elements in xs do *not* satisfy the predicate p+-- all elements in ys do       satisfy the predicate p+--+-- all elements in s occur in either xs or ys.+--+-- running time: \(O(\log^2 n + T*\log n)\), where \(T\) is the time to execute the+-- predicate.+splitMonotone     :: (a -> Bool) -> Seq a -> (Seq a, Seq a)+splitMonotone p s = case binarySearchSeq p s of+                      Nothing -> (s,S.empty)+                      Just i  -> S.splitAt i s+++-- | Given a monotonic predicate p, a lower bound l, and an upper bound u, with:+--  p l = False+--  p u = True+--  l < u.+--+-- Get the index h such that everything strictly smaller than h has: p i =+-- False, and all i >= h, we have p h = True+--+-- running time: \(O(\log(u - l))\)+{-# SPECIALIZE binarySearch :: (Int -> Bool) -> Int -> Int -> Int #-}+{-# SPECIALIZE binarySearch :: (Word -> Bool) -> Word -> Word -> Word #-}+binarySearch       :: Integral a => (a -> Bool) -> a -> a -> a+binarySearch p l u = let d = u - l+                         m = l + (d `div` 2)+                     in if d == 1 then u else+                          if p m then binarySearch p l m+                                 else binarySearch p m u
+ src/Data/Set/Util.hs view
@@ -0,0 +1,80 @@+module Data.Set.Util where++import           Data.DynamicOrd+import qualified Data.Set as Set+import           Data.Set (Set)+import qualified Data.Set.Internal as Internal+++-- import Data.Ord(comparing)++-- data S = S String deriving Show+-- cmpS :: S -> S -> Ordering+-- cmpS = comparing (\(S s) -> length s)+++-- $setup+-- >>> import Data.Ord(comparing)+-- >>> data S = S String deriving Show+-- >>> cmpS = comparing (\(S s) -> length s)+--++-- | Given a monotonic function f that maps a to b, split the sequence s+-- depending on the b values. I.e. the result (l,m,r) is such that+-- * all (< x) . fmap f $ l+-- * all (== x) . fmap f $ m+-- * all (> x) . fmap f $ r+--+-- running time: \(O(\log n)\)+splitOn       :: Ord b => (a -> b) -> b -> Set a -> (Set a, Set a, Set a)+splitOn f x s = let (l,s') = Set.spanAntitone (g LT . f) s+                    (m,r)  = Set.spanAntitone (g EQ . f) s'+                    g c y  = y `compare` x == c+                in (l,m,r)++-- | Constructs a Set using the given Order.+--+-- Note that this is dangerous as the resulting set may not abide the+-- ordering expected of such sets.+--+-- running time: \(O(n\log n)\)+fromListBy        :: (a -> a -> Ordering) -> [a] -> Set a+fromListBy cmp xs = withOrd cmp (extractOrd1 . Set.fromList . map O $ xs)++-- | Given two sets l and r, such that all elements of l occur before+-- r, join the two sets into a combined set.+--+-- running time: \(O(\log n)\)+join :: Set a -> Set a -> Set a+join = Internal.merge+++-- | Inserts an element into the set, assuming that the set is ordered+-- by the given order.+--+-- >>> insertBy cmpS (S "ccc") $ fromListBy cmpS [S "a" , S "bb" , S "dddd"]+-- fromList [S "a",S "bb",S "ccc",S "dddd"]+--+-- When trying to insert an element that equals an element already in+-- the set (according to the given comparator), this function replaces+-- the old element by the new one:+--+-- >>> insertBy cmpS (S "cc") $ fromListBy cmpS [S "a" , S "bb" , S "dddd"]+-- fromList [S "a",S "cc",S "dddd"]+--+-- running time: \(O(\log n)\)+insertBy         :: (a -> a -> Ordering) -> a -> Set a -> Set a+insertBy cmp x s = withOrd cmp $ liftOrd1 (Set.insert $ O x) s+++-- | Deletes an element from the set, assuming the set is ordered by+-- the given ordering.+--+-- >>> deleteAllBy cmpS (S "bb") $ fromListBy cmpS [S "a" , S "bb" , S "dddd"]+-- fromList [S "a",S "dddd"]+-- >>> deleteAllBy cmpS (S "bb") $ fromListBy cmpS [S "a" , S "bb" , S "cc", S "dd", S "ee", S "ff", S "dddd"]+-- fromList [S "a",S "dddd"]+--+-- running time: \(O(\log n)\)+deleteAllBy         :: (a -> a -> Ordering) -> a -> Set a -> Set a+deleteAllBy cmp x s = withOrd cmp $ liftOrd1 (Set.delete $ O x) s
+ src/Data/SlowSeq.hs view
@@ -0,0 +1,205 @@+module Data.SlowSeq where+++import           Control.Lens (bimap)+-- import qualified Data.FingerTree as FT+-- import           Data.FingerTree hiding (null, viewl, viewr)+import           Data.FingerTree(ViewL(..),ViewR(..))+import qualified Data.Foldable as F+import           Data.Maybe+import qualified Data.Sequence as S+import qualified Data.Sequence.Util as SU++++--------------------------------------------------------------------------------++data Key a = NoKey | Key { getKey :: a } deriving (Show,Eq,Ord)++instance Semigroup (Key a) where+  k <> NoKey = k+  _ <> k     = k++instance Monoid (Key a) where+  mempty = NoKey+  k `mappend` k' = k <> k'++liftCmp                     :: (a -> a -> Ordering) -> Key a -> Key a -> Ordering+liftCmp _   NoKey   NoKey   = EQ+liftCmp _   NoKey   (Key _) = LT+liftCmp _   (Key _) NoKey   = GT+liftCmp cmp (Key x) (Key y) = x `cmp` y++++-- newtype Elem a = Elem { getElem :: a } deriving (Eq,Ord,Traversable,Foldable,Functor)++-- instance Show a => Show (Elem a) where+--   show (Elem x) = "Elem " <> show x+++newtype OrdSeq a = OrdSeq { _asSeq :: S.Seq a }+                   deriving (Show,Eq)++instance Semigroup (OrdSeq a) where+  (OrdSeq s) <> (OrdSeq t) = OrdSeq $ s `mappend` t++instance Monoid (OrdSeq a) where+  mempty = OrdSeq mempty+  mappend = (<>)++instance Foldable OrdSeq where+  foldMap f = foldMap f . _asSeq+  null      = null . _asSeq+  length    = length . _asSeq+  minimum   = fromJust . lookupMin+  maximum   = fromJust . lookupMax++-- instance Measured (Key a) (Elem a) where+--   measure (Elem x) = Key x+++type Compare a = a -> a -> Ordering++-- | Insert into a monotone OrdSeq.+--+-- pre: the comparator maintains monotonicity+--+-- \(O(\log^2 n)\)+insertBy                  :: Compare a -> a -> OrdSeq a -> OrdSeq a+insertBy cmp x (OrdSeq s) = OrdSeq $ l `mappend` (x S.<| r)+  where+    (l,r) = split (\v -> cmp v x `elem` [EQ, GT]) s+++++++-- | Insert into a sorted OrdSeq+--+-- \(O(\log^2 n)\)+insert :: Ord a => a -> OrdSeq a -> OrdSeq a+insert = insertBy compare++deleteAllBy         :: Compare a -> a -> OrdSeq a -> OrdSeq a+deleteAllBy cmp x s = l <> r+  where+    (l,_,r) = splitBy cmp x s++    -- (l,m) = split (\v -> liftCmp cmp v (Key x) `elem` [EQ,GT]) s+    -- (_,r) = split (\v -> liftCmp cmp v (Key x) == GT) m+++-- | \(O(\log^2 n)\)+splitBy                  :: Compare a -> a -> OrdSeq a -> (OrdSeq a, OrdSeq a, OrdSeq a)+splitBy cmp x (OrdSeq s) = (OrdSeq l, OrdSeq m', OrdSeq r)+  where+    (l, m) = split (\v -> cmp v x `elem` [EQ,GT]) s+    (m',r) = split (\v -> cmp v x == GT) m+++-- | Given a monotonic function f that maps a to b, split the sequence s+-- depending on the b values. I.e. the result (l,m,r) is such that+-- * all (< x) . fmap f $ l+-- * all (== x) . fmap f $ m+-- * all (> x) . fmap f $ r+--+-- >>> splitOn id 3 $ fromAscList' [1..5]+-- (OrdSeq {_asSeq = fromList [Elem 1,Elem 2]},OrdSeq {_asSeq = fromList [Elem 3]},OrdSeq {_asSeq = fromList [Elem 4,Elem 5]})+-- >>> splitOn fst 2 $ fromAscList' [(0,"-"),(1,"A"),(2,"B"),(2,"C"),(3,"D"),(4,"E")]+-- (OrdSeq {_asSeq = fromList [Elem (0,"-"),Elem (1,"A")]},OrdSeq {_asSeq = fromList [Elem (2,"B"),Elem (2,"C")]},OrdSeq {_asSeq = fromList [Elem (3,"D"),Elem (4,"E")]})+--+-- \(O(\log^2 n)\)+splitOn :: Ord b => (a -> b) -> b -> OrdSeq a -> (OrdSeq a, OrdSeq a, OrdSeq a)+splitOn f x (OrdSeq s) = (OrdSeq l, OrdSeq m', OrdSeq r)+  where+    (l, m) = split (\v -> compare (f v) x `elem` [EQ,GT]) s+    (m',r) = split (\v -> compare (f v) x ==     GT)      m++-- | Given a monotonic predicate p, splits the sequence s into two sequences+--  (as,bs) such that all (not p) as and all p bs+--+-- \(O(\log^2 n)\)+splitMonotonic  :: (a -> Bool) -> OrdSeq a -> (OrdSeq a, OrdSeq a)+splitMonotonic p = bimap OrdSeq OrdSeq . split p . _asSeq+++-- monotonic split for Sequences+--+-- \(O(\log^2 n)\)+split :: (a -> Bool) -> S.Seq a -> (S.Seq a, S.Seq a)+split = SU.splitMonotone++-- Deletes all elements from the OrdDeq+--+-- \(O(\log^2 n)\)+deleteAll :: Ord a => a -> OrdSeq a -> OrdSeq a+deleteAll = deleteAllBy compare+++-- | inserts all eleements in order+-- \(O(n\log n)\)+fromListBy     :: Compare a -> [a] -> OrdSeq a+fromListBy cmp = foldr (insertBy cmp) mempty++-- | inserts all eleements in order+-- \(O(n\log n)\)+fromListByOrd :: Ord a => [a] -> OrdSeq a+fromListByOrd = fromListBy compare++-- | O(n)+fromAscList' :: [a] -> OrdSeq a+fromAscList' = OrdSeq . S.fromList+++-- | \(O(\log^2 n)\)+lookupBy                  :: Compare a -> a -> OrdSeq a -> Maybe a+lookupBy cmp x s = let (_,m,_) = splitBy cmp x s in listToMaybe . F.toList $ m++memberBy        :: Compare a -> a -> OrdSeq a -> Bool+memberBy cmp x = isJust . lookupBy cmp x+++-- | Fmap, assumes the order does not change+-- \(O(n)\)+mapMonotonic   :: (a -> b) -> OrdSeq a -> OrdSeq b+mapMonotonic f = fromAscList' . map f . F.toList+++-- | Gets the first element from the sequence+-- \(O(1)\)+viewl :: OrdSeq a -> ViewL OrdSeq a+viewl = f . S.viewl . _asSeq+  where+    f S.EmptyL         = EmptyL+    f (x S.:< s)  = x :< OrdSeq s++-- Last element+-- \(O(1)\)+viewr :: OrdSeq a -> ViewR OrdSeq a+viewr = f . S.viewr . _asSeq+  where+    f S.EmptyR    = EmptyR+    f (s S.:> x)  = OrdSeq s :> x+++-- \(O(1)\)+minView   :: OrdSeq a -> Maybe (a, OrdSeq a)+minView s = case viewl s of+              EmptyL   -> Nothing+              (x :< t) -> Just (x,t)++-- \(O(1)\)+lookupMin :: OrdSeq a -> Maybe a+lookupMin = fmap fst . minView++-- \(O(1)\)+maxView   :: OrdSeq a -> Maybe (a, OrdSeq a)+maxView s = case viewr s of+              EmptyR   -> Nothing+              (t :> x) -> Just (x,t)++-- \(O(1)\)+lookupMax :: OrdSeq a -> Maybe a+lookupMax = fmap fst . maxView
+ src/Data/Tree/Util.hs view
@@ -0,0 +1,154 @@+module Data.Tree.Util where++import Data.Maybe(listToMaybe,maybeToList)+import Control.Lens+import Control.Monad((>=>))+import Data.Tree+import qualified Data.List as List++--------------------------------------------------------------------------------++-- $setup+-- >>> :{+-- let myTree = Node 0 [ Node 1 []+--                     , Node 2 []+--                     , Node 3 [ Node 4 [] ]+--                     ]+-- :}++--------------------------------------------------------------------------------+-- * Zipper on rose trees++-- | Zipper for rose trees+data Zipper a = Zipper { focus      :: Tree a+                       , ancestors  :: [([Tree a], a, [Tree a])] -- left siblings in reverse order+                       }+              deriving (Show,Eq)++-- | Create a new zipper focussiong on the root.+root :: Tree a -> Zipper a+root = flip Zipper []++-- | Move the focus to the parent of this node.+up               :: Zipper a -> Maybe (Zipper a)+up (Zipper t as) = case as of+                     []              -> Nothing+                     ((ls,p,rs):as') -> Just $ Zipper (Node p (reverse ls <> [t] <> rs)) as'++-- | Move the focus to the first child of this node.+--+-- >>> firstChild $ root myTree+-- Just (Zipper {focus = Node {rootLabel = 1, subForest = []}, ancestors = [([],0,[Node {rootLabel = 2, subForest = []},Node {rootLabel = 3, subForest = [Node {rootLabel = 4, subForest = []}]}])]})+firstChild                          :: Zipper a -> Maybe (Zipper a)+firstChild (Zipper (Node x chs) as) = case chs of+                                        []       -> Nothing+                                        (c:chs') -> Just $ Zipper c (([],x,chs'):as)++-- | Move the focus to the next sibling of this node+--+-- >>> (firstChild $ root myTree) >>= nextSibling+-- Just (Zipper {focus = Node {rootLabel = 2, subForest = []}, ancestors = [([Node {rootLabel = 1, subForest = []}],0,[Node {rootLabel = 3, subForest = [Node {rootLabel = 4, subForest = []}]}])]})+nextSibling               :: Zipper a -> Maybe (Zipper a)+nextSibling (Zipper t as) = case as of+                              []                  -> Nothing -- no parent+                              ((_,_,[]):_)        -> Nothing -- no next sibling+                              ((ls,p,(r:rs)):as') -> Just $ Zipper r ((t:ls,p,rs):as')++-- | Move the focus to the next sibling of this node+prevSibling               :: Zipper a -> Maybe (Zipper a)+prevSibling (Zipper t as) = case as of+                              []                  -> Nothing -- no parent+                              (([],_,_):_)        -> Nothing -- no prev sibling+                              (((l:ls),p,rs):as') -> Just $ Zipper l ((ls,p,t:rs):as')++-- | Given a zipper that focussses on some subtree t, construct a list with+-- zippers that focus on each child.+allChildren :: Zipper a -> [Zipper a]+allChildren = List.unfoldr ((\ch -> (ch, nextSibling ch)) <$>) . firstChild++-- | Given a zipper that focussses on some subtree t, construct a list with+-- zippers that focus on each of the nodes in the subtree of t.+allTrees   :: Zipper a -> [Zipper a]+allTrees r = r : concatMap allTrees (allChildren r)++-- | Creates a new tree from the zipper that thas the current node as root. The+-- ancestorTree (if there is any) forms the first child in this new root.+unZipperLocal                          :: Zipper a -> Tree a+unZipperLocal (Zipper (Node x chs) as) = Node x (maybeToList (constructTree as) <> chs)++-- | Constructs a tree from the list of ancestors (if there are any)+constructTree :: [([Tree a],a,[Tree a])] -> Maybe (Tree a)+constructTree = listToMaybe+              . foldr (\(ls,p,rs) tas -> [Node p (tas <> reverse ls <> rs)]) []+++--------------------------------------------------------------------------------++-- | Given a predicate on an element, find a node that matches the predicate, and turn that+-- node into the root of the tree.+--+-- running time: \(O(nT)\) where \(n\) is the size of the tree, and \(T\) is+-- the time to evaluate a predicate.+--+-- >>> findEvert (== 4) myTree+-- Just (Node {rootLabel = 4, subForest = [Node {rootLabel = 3, subForest = [Node {rootLabel = 0, subForest = [Node {rootLabel = 1, subForest = []},Node {rootLabel = 2, subForest = []}]}]}]})+-- >>> findEvert (== 5) myTree+-- Nothing+findEvert   :: (a -> Bool) -> Tree a -> Maybe (Tree a)+findEvert p = findEvert' (p . rootLabel)++-- | Given a predicate matching on a subtree, find a node that matches the predicate, and turn that+-- node into the root of the tree.+--+-- running time: \(O(nT(n))\) where \(n\) is the size of the tree, and \(T(m)\) is+-- the time to evaluate a predicate on a subtree of size \(m\).+findEvert'   :: (Tree a -> Bool) -> Tree a -> Maybe (Tree a)+findEvert' p = fmap unZipperLocal . listToMaybe . filter (p . focus) . allTrees . root++-- | Function to extract a path between a start node and an end node (if such a+--path exists). If there are multiple paths, no guarantees are given about+--which one is returned.+--+-- running time: \(O(n(T_p+T_s)\), where \(n\) is the size of the tree, and+-- \(T_p\) and \(T_s\) are the times it takes to evaluate the 'isStartingNode'+-- and 'isEndingNode' predicates.+--+--+-- >>> findPath (== 1) (==4) myTree+-- Just [1,0,3,4]+-- >>>  findPath (== 1) (==2) myTree+-- Just [1,0,2]+-- >>>  findPath (== 1) (==1) myTree+-- Just [1]+-- >>>  findPath (== 1) (==2) myTree+-- Just [1,0,2]+-- >>>  findPath (== 4) (==2) myTree+-- Just [4,3,0,2]+findPath               :: (a -> Bool) -- ^ is this node a starting node+                          -> (a -> Bool) -- ^ is this node an ending node+                          -> Tree a -> Maybe [a]+findPath isStart isEnd = findEvert isStart >=> findNode isEnd++-- | Given a predicate on a, find (the path to) a node that satisfies the predicate.+--+-- >>> findNode (== 4) myTree+-- Just [0,3,4]+findNode   :: (a -> Bool) -> Tree a -> Maybe [a]+findNode p = listToMaybe . findNodes (p . rootLabel)++-- | Find all paths to nodes that satisfy the predicate+--+-- running time: \(O(nT(n))\) where \(n\) is the size of the tree, and \(T(m)\) is+-- the time to evaluate a predicate on a subtree of size \(m\).+--+-- >>> findNodes ((< 4) . rootLabel) myTree+-- [[0],[0,1],[0,2],[0,3]]+-- >>> findNodes (even . rootLabel) myTree+-- [[0],[0,2],[0,3,4]]+-- >>> let size = length in findNodes ((> 1) . size) myTree+-- [[0],[0,3]]+findNodes   :: (Tree a -> Bool) -> Tree a -> [[a]]+findNodes p = go+  where+    go t = let mh = if p t then [[]] else []+           in map (rootLabel t:) $ mh <> concatMap go (children t)
+ src/Data/UnBounded.hs view
@@ -0,0 +1,127 @@+{-# LANGUAGE TemplateHaskell   #-}+module Data.UnBounded( Top, topToMaybe+                     , pattern ValT, pattern Top++                     , Bottom, bottomToMaybe+                     , pattern Bottom, pattern ValB++                     , UnBounded(..)+                     , unUnBounded+                     , unBoundedToMaybe+                     ) where++import           Control.Lens+import qualified Data.Foldable as F+import qualified Data.Traversable as T+import           Data.Functor.Classes++--------------------------------------------------------------------------------+-- * Top and Bottom++-- | `Top a` represents the type a, together with a 'Top' element, i.e. an element+-- that is greater than any other element. We can think of `Top a` being defined as:+--+-- >>> data Top a = ValT a | Top+newtype Top a = GTop { topToMaybe :: Maybe a }+                deriving (Eq,Functor,F.Foldable,T.Traversable,Applicative,Monad,Eq1)++pattern ValT  :: a -> Top a+pattern ValT x = GTop (Just x)++pattern Top    :: Top a+pattern Top    = GTop Nothing++{-# COMPLETE ValT, Top #-}+++instance Ord1 Top where+  liftCompare _   Top       Top       = EQ+  liftCompare _   _         Top       = LT+  liftCompare _   Top       _         = GT+  liftCompare cmp ~(ValT x) ~(ValT y) = x `cmp` y++instance Ord a => Ord (Top a) where+  compare = compare1++instance Show a => Show (Top a) where+  show Top       = "Top"+  show ~(ValT x) = "ValT " ++ show x++--------------------------------------------------------------------------------++-- | `Bottom a` represents the type a, together with a 'Bottom' element,+-- i.e. an element that is smaller than any other element. We can think of+-- `Bottom a` being defined as:+--+-- >>> data Bottom a = Bottom | ValB a+newtype Bottom a = GBottom { bottomToMaybe :: Maybe a }+                 deriving (Eq,Ord,Functor,F.Foldable,T.Traversable,Applicative,Monad,Eq1,Ord1)++pattern Bottom :: Bottom a+pattern Bottom = GBottom Nothing++pattern ValB   :: a -> Bottom a+pattern ValB x = GBottom (Just x)++{-# COMPLETE Bottom, ValB #-}++instance Show a => Show (Bottom a) where+  show Bottom    = "Bottom"+  show ~(ValB x) = "ValB " ++ show x++--------------------------------------------------------------------------------++-- | `UnBounded a` represents the type a, together with an element+-- `MaxInfinity` larger than any other element, and an element `MinInfinity`,+-- smaller than any other element.+data UnBounded a = MinInfinity | Val { _unUnBounded :: a }  | MaxInfinity+                 deriving (Eq,Ord,Functor,F.Foldable,T.Traversable)++makeLenses ''UnBounded++instance Show a => Show (UnBounded a) where+  show MinInfinity = "MinInfinity"+  show (Val x)     = "Val " ++ show x+  show MaxInfinity = "MaxInfinity"++instance Num a => Num (UnBounded a) where+  MinInfinity + _           = MinInfinity+  _           + MinInfinity = MinInfinity+  (Val x)     + (Val y)     = Val $ x + y+  _           + MaxInfinity = MaxInfinity+  MaxInfinity + _           = MaxInfinity+++  MinInfinity * _           = MinInfinity+  _           * MinInfinity = MinInfinity++  (Val x)     * (Val y)     = Val $ x * y+  _           * MaxInfinity = MaxInfinity+  MaxInfinity * _           = MaxInfinity++  abs MinInfinity = MinInfinity+  abs (Val x)     = Val $ abs x+  abs MaxInfinity = MaxInfinity++  signum MinInfinity = -1+  signum (Val x)     = Val $ signum x+  signum MaxInfinity = 1++  fromInteger = Val . fromInteger++  negate MinInfinity = MaxInfinity+  negate (Val x)     = Val $ negate x+  negate MaxInfinity = MinInfinity++instance Fractional a => Fractional (UnBounded a) where+  MinInfinity / _       = MinInfinity+  (Val x)     / (Val y) = Val $ x / y+  (Val _)     / _       = 0+  MaxInfinity / _       = MaxInfinity++  fromRational = Val . fromRational+++unBoundedToMaybe         :: UnBounded a -> Maybe a+unBoundedToMaybe (Val x) = Just x+unBoundedToMaybe _       = Nothing
+ src/Data/Util.hs view
@@ -0,0 +1,96 @@+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.Util+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Some basic types, mostly strict triples and pairs.+--+--------------------------------------------------------------------------------+module Data.Util where++import Control.DeepSeq+import Control.Lens+import GHC.Generics (Generic)+import qualified Data.List as List++--------------------------------------------------------------------------------+-- * Strict Triples++-- |  strict triple+data STR a b c = STR { fst' :: !a, snd' :: !b , trd' :: !c}+               deriving (Show,Eq,Ord,Functor,Generic)++instance (Semigroup a, Semigroup b, Semigroup c) => Semigroup (STR a b c) where+  (STR a b c) <> (STR d e f) = STR (a <> d) (b <> e) (c <> f)++instance (Semigroup a, Semigroup b, Semigroup c+         , Monoid a, Monoid b, Monoid c) => Monoid (STR a b c) where+  mempty = STR mempty mempty mempty+  mappend = (<>)++instance (NFData a, NFData b, NFData c) => NFData (STR a b c)++instance Field1 (STR a b c) (STR d b c) a d where+  _1 = lens fst' (\(STR _ b c) d -> STR d b c)++instance Field2 (STR a b c) (STR a d c) b d where+  _2 = lens snd' (\(STR a _ c) d -> STR a d c)++instance Field3 (STR a b c) (STR a b d) c d where+  _3 = lens trd' (\(STR a b _) d -> STR a b d)++-- | Generate All unique unordered triplets.+--+uniqueTriplets    :: [a] -> [STR a a a]+uniqueTriplets xs = [ STR x y z | (x:ys) <- nonEmptyTails xs, SP y z <- uniquePairs ys]+++--------------------------------------------------------------------------------+-- * Strict Pairs+++-- | Strict pair+data SP a b = SP !a !b deriving (Show,Eq,Ord,Functor,Generic)++instance (Semigroup a, Semigroup b) => Semigroup (SP a b) where+  (SP a b) <> (SP c d) = SP (a <> c) (b <> d)++instance (Semigroup a, Semigroup b, Monoid a, Monoid b) => Monoid (SP a b) where+  mempty = SP mempty mempty+  mappend = (<>)++instance (NFData a, NFData b) => NFData (SP a b)+++instance Field1 (SP a b) (SP c b) a c where+  _1 = lens (\(SP a _) -> a) (\(SP _ b) c -> SP c b)++instance Field2 (SP a b) (SP a c) b c where+  _2 = lens (\(SP _ b) -> b) (\(SP a _) c -> SP a c)++instance Bifunctor SP where+  bimap f g (SP a b) = SP (f a) (g b)++--------------------------------------------------------------------------------+-- | * Strict pair whose elements are of the same type.++-- | Strict pair with both items the same+type Two a = SP a a++pattern Two :: a -> a -> Two a+pattern Two a b = SP a b+{-# COMPLETE Two #-}++-- | Given a list xs, generate all unique (unordered) pairs.+--+--+uniquePairs    :: [a] -> [Two a]+uniquePairs xs = [ Two x y | (x:ys) <- nonEmptyTails xs, y <- ys ]++--------------------------------------------------------------------------------++-- | A version of List.tails in which we remove the emptylist+nonEmptyTails :: [a] -> [[a]]+nonEmptyTails = List.init . List.tails
+ src/Data/Yaml/Util.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE OverloadedStrings #-}+--------------------------------------------------------------------------------+-- |+-- Module      :  Data.Yaml.Util+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+-- Description :  Helper functions for working with yaml+--+--------------------------------------------------------------------------------+module Data.Yaml.Util( encodeYaml, encodeYamlFile+                     , decodeYaml, decodeYamlFile+                     , printYaml+                     , parseVersioned+                     , Versioned(Versioned), unversioned+                     ) where++import           Control.Applicative+import           Data.Aeson+import           Data.Aeson.Types (typeMismatch)+import           Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as B+import qualified Data.Text as T+import           Data.Version+import           Data.Yaml+import qualified Data.Yaml.Pretty as YamlP+import           GHC.Generics (Generic)+import           Text.ParserCombinators.ReadP (readP_to_S)++--------------------------------------------------------------------------------++-- | Write the output to yaml+encodeYaml :: ToJSON a => a -> ByteString+encodeYaml = YamlP.encodePretty YamlP.defConfig++-- | Prints the yaml+printYaml :: ToJSON a => a -> IO ()+printYaml = B.putStrLn . encodeYaml++-- | alias for decodeEither' from the Yaml Package+decodeYaml :: FromJSON a => ByteString -> Either ParseException a+decodeYaml = decodeEither'++-- | alias for reading a yaml file+decodeYamlFile :: FromJSON a => FilePath -> IO (Either ParseException a)+decodeYamlFile = decodeFileEither++-- | Encode a yaml file+encodeYamlFile    :: ToJSON a => FilePath -> a -> IO ()+encodeYamlFile fp = B.writeFile fp . encodeYaml+++-- | Data type for things that have a version+data Versioned a = Versioned { version :: Version+                             , content :: a+                             } deriving (Show,Read,Generic,Eq,Functor,Foldable,Traversable)++unversioned :: Versioned a -> a+unversioned = content++instance ToJSON a => ToJSON (Versioned a) where+  toJSON     (Versioned v x) = object [ "version" .= showVersion v, "content" .= x]+  toEncoding (Versioned v x) = pairs ("version" .= showVersion v <> "content" .= x)+++-- | Given a list of candidate parsers, select the right one+parseVersioned               :: [(Version -> Bool,Value -> Parser a)]+                             -> Value -> Parser (Versioned a)+parseVersioned ps (Object o) = do V v <- o .: "version"+                                  co  <- o .: "content"+                                  let ps' = map (\(_,p) -> Versioned v <$> p co)+                                          . filter (($ v) . fst) $ ps+                                      err = fail $ "no matching version found for version "+                                                   <> showVersion v+                                  foldr (<|>) err ps'+parseVersioned _ invalid     = typeMismatch "Versioned" invalid++-- instance (FromJSON a) => FromJSON (Versioned a) where+--   parseJSON (Object v) = Versioned <$> (unV <$> v .: "version")+--                                    <*> v .: "content"+--   parseJSON invalid    = typeMismatch "Versioned" invalid++newtype V = V Version++instance FromJSON V where+  parseJSON (String t) = case filter (null . snd) (readP_to_S parseVersion $ T.unpack t) of+     ((v,""):_) -> pure $ V v+     _          -> fail $ "parsing " <> show t <> " into a version failed"+  parseJSON invalid    = typeMismatch "Version" invalid
+ src/System/Random/Shuffle.hs view
@@ -0,0 +1,36 @@+--------------------------------------------------------------------------------+-- |+-- Module      :  System.Random.Shuffle+-- Copyright   :  (C) Frank Staals+-- License     :  see the LICENSE file+-- Maintainer  :  Frank Staals+--+-- Implements Fishyer-Yates shuffle.+--+--------------------------------------------------------------------------------+module System.Random.Shuffle(shuffle) where++import           Control.Monad+import           Control.Monad.Random.Class+import qualified Data.Foldable as F+import           Data.Util+import qualified Data.Vector as V+import qualified Data.Vector.Mutable as MV++--------------------------------------------------------------------------------++-- | Fisher–Yates shuffle, which shuffles a list/foldable uniformly at random.+--+-- running time: \(O(n)\).+shuffle :: (Foldable f, MonadRandom m) => f a -> m (V.Vector a)+shuffle = withLength . V.fromList . F.toList+  where+    withLength v = let n = V.length v in flip withRands v <$> rands (n - 1)+    withRands rs = V.modify $ \v ->+                     forM_ rs $ \(SP i j) -> MV.swap v i j+++-- | Generate a list of indices in decreasing order, coupled with a random+-- value in the range [0,i].+rands   :: MonadRandom m => Int -> m [SP Int Int]+rands n = mapM (\i -> SP i <$> getRandomR (0,i)) [n,(n-1)..1]
+ test/Algorithms/StringSearch/KMPSpec.hs view
@@ -0,0 +1,27 @@+module Algorithms.StringSearch.KMPSpec where++import           Algorithms.StringSearch.KMP+import qualified Data.Foldable as F+import qualified Data.List as List+import qualified Data.Vector as V+import qualified Data.Vector.Unboxed as UV+import           Test.QuickCheck.Instances ()+import           Test.Hspec+import           Test.QuickCheck++--------------------------------------------------------------------------------++patternFound :: String -> String -> Maybe Int -> Bool+patternFound p t = \case+                     Nothing -> True+                     Just i  -> List.isPrefixOf p . List.drop i $ t++spec :: Spec+spec = do+  describe "KMP tests" $ do+    it "failure-function manual example" $+      buildFailureFunction (V.fromList "abacab")+        `shouldBe` (UV.fromList [0,0,1,0,1,2])+    it "manual example" $+      [4,1,2,3] `isSubStringOf` [1,4,5,4,1,2,3,6]+        `shouldBe` (Just 3)
+ test/Data/CircularSeqSpec.hs view
@@ -0,0 +1,53 @@+module Data.CircularSeqSpec where++import Data.CircularSeq+import Test.Hspec+import Test.QuickCheck+import Test.QuickCheck.Instances()+import Data.List.NonEmpty(NonEmpty)++spec :: Spec+spec = do+  describe "CircularCeq tests" $ do+    it "isShiftOf" $ do+      let c1 :: CSeq Int+          c1 = fromList [1, 2, 1, 3]+          c2 = rotateNL 2 c1+      (c1 `isShiftOf` c2) `shouldBe` True+      (c2 `isShiftOf` c1) `shouldBe` True+    it "is not a shift of " $ do+      let c1 :: CSeq Int+          c1 = fromList [1, 2, 3, 4]+          c2 = fromList [3, 2]+      (c1 `isShiftOf` c2) `shouldBe` False+      (c2 `isShiftOf` c1) `shouldBe` False+    it "multiple copies is not a shift" $ do+      let c1 = fromList [1]+          c2 = fromList [1,1]+          c3 = fromList [1,1,1]+      (c1 `isShiftOf` c2) `shouldBe` False+      (c2 `isShiftOf` c1) `shouldBe` False+      (c1 `isShiftOf` c3) `shouldBe` False+      (c3 `isShiftOf` c1) `shouldBe` False+    it "cyclic shift tests" $+      property $ \(xs :: NonEmpty Int) i -> do+                   let cs  = fromNonEmpty xs+                       cs' = rotateNR i cs+                   (cs `isShiftOf` cs') `shouldBe` True+                   (cs `isShiftOf` cs') `shouldBe` (isShiftOfNaive cs cs')+      -- property $ \(xs :: NonEmpty Int) i ->+      --              let cs  = fromNonEmpty xs+      --                  cs' = rotateNR i cs+      --              in++++    -- it "cyclic shift is symmetric" $+    --   property $ \(xs :: NonEmpty Int) i ->+    --                let cs  = fromNonEmpty xs+    --                    cs' = rotateNR i cs+    --                in (cs `isShiftOf` cs') `shouldBe` (cs' `isShiftOf` cs)+++isShiftOfNaive       :: Eq a => CSeq a -> CSeq a -> Bool+isShiftOfNaive xs ys = xs `elem` allRotations ys
+ test/Data/EdgeOracleSpec.hs view
@@ -0,0 +1,64 @@+module Data.EdgeOracleSpec where++import           Control.Arrow+import           Data.Ext+import           Data.PlanarGraph.EdgeOracle+import           Data.PlanarGraph.Core+import           Data.Semigroup+import qualified Data.Set as S+import           Test.Hspec++--------------------------------------------------------------------------------++data TestG++type Vertex = VertexId TestG Primal+++testEdges :: [(Vertex,[Vertex])]+testEdges = map (\(i,vs) -> (VertexId i, map VertexId vs))+            [ (0, [1])+            , (1, [0,1,2,4])+            , (2, [1,3,4])+            , (3, [2,5])+            , (4, [1,2,5])+            , (5, [3,4])+            ]++buildEdgeOracle'  :: [(Vertex,[Vertex])] -> EdgeOracle TestG Primal ()+buildEdgeOracle' = buildEdgeOracle . map (second $ fmap ext)++-- | Flattens an adjacencylist representation into a set of edges+flattenEdges :: [(t, [a])] -> [(t, a)]+flattenEdges = concatMap (\(i,vs) -> map (i,) vs)++-- | Given a set of edges, generates all non-edges, i.e. all pairs of vertices+-- that do not form an edge+nonEdges    :: [(VertexId s w, [VertexId s w])] -> [(VertexId s w, VertexId s w)]+nonEdges es = flattenEdges . map (second $ f . S.fromList) $ es+  where+    f vs  = filter (`S.notMember` vs) allVs+    allVs = map fst es++-- | Retains only the edges in the graph+hasEdges         :: EdgeOracle s w a -> [(VertexId s w, VertexId s w)]+                 -> [(VertexId s w, VertexId s w)]+oracle `hasEdges` es = filter (\(u,v) -> hasEdge u v oracle) es+++-- | Tests all edges es+edgeOracleSpec      :: String -> [(Vertex, [Vertex])]  -> Spec+edgeOracleSpec s es = do+    let oracle = buildEdgeOracle' es+    describe ("EdgeOracle on " <> s) $ do+      it "test postitive edges" $+          (oracle `hasEdges` flattenEdges es) `shouldBe` flattenEdges es+      it "test negative edges " $+          (oracle `hasEdges` nonEdges es) `shouldBe` []++      -- it "test maximum adjacency-list lengths" $+      --     (filter (\v -> length v > 6) . _unEdgeOracle $ oracle) `shouldBe` []++spec :: Spec+spec = do+         edgeOracleSpec "testEdges" testEdges
+ test/Data/OrdSeqSpec.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE ScopedTypeVariables #-}+module Data.OrdSeqSpec where++import qualified Data.Foldable as F+import qualified Data.List as List+import           Data.OrdSeq (OrdSeq)+import qualified Data.OrdSeq as OrdSeq+import           Test.Hspec+import           Test.QuickCheck++spec :: Spec+spec = do+  describe "OrdSeq tests" $ do+    it "fromListBy" $+      property $ \(xs :: [Int]) ->+          F.toList (OrdSeq.fromListBy compare xs) `shouldBe` List.sort xs+    it "splitOn, <" $+      property $ \x (xs :: OrdSeq Int) ->+          let (l,_,_) = OrdSeq.splitOn id x xs+          in all (< x) l+    it "splitOn, ==" $+      property $ \x (xs :: OrdSeq Int) ->+          let (_,m,_) = OrdSeq.splitOn id x xs+          in all (== x) m+    it "splitOn, >=" $+      property $ \x (xs :: OrdSeq Int) ->+          let (_,_,r) = OrdSeq.splitOn id x xs+          in all (> x) r+    it "join" $+      property $ \x (xs :: [Int]) -> let (ys,zs) = List.partition (<= x) $ xs in+          (F.toList $ OrdSeq.fromListByOrd ys <> OrdSeq.fromListByOrd zs)+          `shouldBe`+          List.sort (ys <> zs)+    it "positive member" $+      property $ \(xs :: OrdSeq Int) ->+         all (\x -> OrdSeq.memberBy compare x xs) xs+    it "member" $+      property $ \x (xs :: OrdSeq Int) ->+         OrdSeq.memberBy compare x xs+         `shouldBe`+         F.elem x (F.toList xs)+    it "lookupMin" $+       property $ \(xs :: OrdSeq Int) ->+         OrdSeq.lookupMin xs+         `shouldBe`+         (safe minimum $ F.toList xs)+    it "lookupMax" $+       property $ \(xs :: OrdSeq Int) ->+         OrdSeq.lookupMax xs+         `shouldBe`+         (safe maximum $ F.toList xs)+++safe      :: ([t] -> a) -> [t] -> Maybe a+safe _ [] = Nothing+safe f xs = Just . f $ xs
+ test/Data/PlanarGraph/myGraph.yaml view
@@ -0,0 +1,60 @@+faces:+- incidentEdge:+  - 0+  - 1+  fData: []+- incidentEdge:+  - 1+  - 4+  fData: []+- incidentEdge:+  - 2+  - 4+  fData: []+ajacencies:+- adj:+  - - 1+    - []+  id: 0+  vData: []+- adj:+  - - 0+    - []+  - - 2+    - []+  - - 4+    - []+  id: 1+  vData: []+- adj:+  - - 1+    - []+  - - 3+    - []+  - - 4+    - []+  id: 2+  vData: []+- adj:+  - - 2+    - []+  - - 5+    - []+  id: 3+  vData: []+- adj:+  - - 1+    - []+  - - 2+    - []+  - - 5+    - []+  id: 4+  vData: []+- adj:+  - - 3+    - []+  - - 4+    - []+  id: 5+  vData: []
+ test/Data/PlanarGraphSpec.hs view
@@ -0,0 +1,116 @@+{-# LANGUAGE ScopedTypeVariables #-}+module Data.PlanarGraphSpec where+++import           Data.Bifunctor+import qualified Data.ByteString.Char8 as B+import qualified Data.Foldable as F+import qualified Data.Map.Strict as SM+import           Data.Permutation (toCycleRep)+import           Data.PlanarGraph+import qualified Data.PlanarGraph as PlanarGraph+import           Data.PlanarGraph.IO+import qualified Data.Set as S+import           Data.Util+import qualified Data.Vector as V+import           Data.Yaml (prettyPrintParseException)+import           Data.Yaml.Util+import           Test.Hspec+import           Test.QuickCheck++--------------------------------------------------------------------------------+data TestG++type Vertex = VertexId TestG Primal++-- | Report all adjacnecies from g missing in h+missingAdjacencies     :: PlanarGraph s w v e f -> PlanarGraph s w v e f+                    -> [(VertexId s w, VertexId s w)]+missingAdjacencies g h = concatMap f . vertices' $ g+  where+    f u = let adjUh = S.fromList . F.toList $ neighboursOf u h+          in F.toList . fmap (u,) . V.filter (`S.notMember` adjUh) $ neighboursOf u g+++sameGraphs s g h = do+    describe ("Same Adjacencies " <> s) $ do+      it "Missing edges from g in h" $+          (missingAdjacencies g h) `shouldBe` []+      it "Missing edges from h in g" $+          (missingAdjacencies h g) `shouldBe` []++spec :: Spec+spec = do+    describe "PlanarGraph spec" $ do+      sameGraphs "testEdges" (fromAdjacencyLists testEdges) (fromAdjacencyListsOld testEdges)+    it "quickheck Dart:  (toEnum (fromEnum d)) = d" $+      property $ \(d :: Dart TestG) -> toEnum (fromEnum d) `shouldBe` d+    it "quickheck Dart: fromEnum (toEnum i) = i" $+      property $ \(NonNegative i) -> fromEnum ((toEnum i) :: Dart TestG) `shouldBe` i+    it "encode yaml test" $ do+      b <- B.readFile "test/Data/PlanarGraph/myGraph.yaml"+      encodeYaml (fromAdjacencyLists testEdges) `shouldBe` b+    it "decode yaml test" $ do+      (first prettyPrintParseException <$> decodeYamlFile "test/Data/PlanarGraph/myGraph.yaml")+      `shouldReturn`+      (Right $ fromAdjacencyLists testEdges)+++testEdges :: [(Vertex,[Vertex])]+testEdges = map (\(i,vs) -> (VertexId i, map VertexId vs))+            [ (0, [1])+            , (1, [0,2,4])+            , (2, [1,3,4])+            , (3, [2,5])+            , (4, [1,2,5])+            , (5, [3,4])+            ]++-- testGraph = fromAdjacencyLists testEdges++-- enccode = let g =+--           in encodeYamlFile++--------------------------------------------------------------------------------+++-- - m: a Map, mapping edges, represented by a pair of vertexId's (u,v) with+--            u < v, to arcId's.+-- - a: the next available unused arcID+-- - x: the data value we are interested in computing+type STR' s b = STR (SM.Map (VertexId s Primal,VertexId s Primal) Int) Int b++-- | Construct a planar graph from a adjacency matrix. For every vertex, all+-- vertices should be given in counter clockwise order.+--+-- running time: $O(n \log n)$.+fromAdjacencyListsOld      :: forall s f.(Foldable f, Functor f)+                        => [(VertexId s Primal, f (VertexId s Primal))]+                        -> PlanarGraph s Primal () () ()+fromAdjacencyListsOld adjM = planarGraph' . toCycleRep n $ perm+  where+    n    = sum . fmap length $ perm+    perm = trd' . foldr toOrbit (STR mempty 0 mempty) $ adjM+++    -- | Given a vertex with its adjacent vertices (u,vs) (in CCW order) convert this+    -- vertex with its adjacent vertices into an Orbit+    toOrbit                     :: Foldable f+                                => (VertexId s Primal, f (VertexId s Primal))+                                -> STR' s [[Dart s]]+                                -> STR' s [[Dart s]]+    toOrbit (u,vs) (STR m a dss) =+      let (STR m' a' ds') = foldr (toDart . (u,)) (STR m a mempty) . F.toList $ vs+      in STR m' a' (ds':dss)+++    -- | Given an edge (u,v) and a triplet (m,a,ds) we construct a new dart+    -- representing this edge.+    toDart                    :: (VertexId s Primal,VertexId s Primal)+                              -> STR' s [Dart s]+                              -> STR' s [Dart s]+    toDart (u,v) (STR m a ds) = let dir = if u < v then PlanarGraph.Positive else PlanarGraph.Negative+                                    t'  = (min u v, max u v)+                               in case SM.lookup t' m of+      Just a' -> STR m                  a     (Dart (Arc a') dir : ds)+      Nothing -> STR (SM.insert t' a m) (a+1) (Dart (Arc a)  dir : ds)
+ test/Data/RangeSpec.hs view
@@ -0,0 +1,47 @@+module Data.RangeSpec where++import Data.Intersection+import Data.Range+import Test.Hspec++--------------------------------------------------------------------------------++spec :: Spec+spec = do+  describe "RangeRange Intersection" $ do+    it "openRange cap openrange" $ do+      ((OpenRange 1 (10 :: Int))  `intersect` (OpenRange 5 (10 :: Int)))+      `shouldBe` (coRec $ OpenRange 5 (10 :: Int))+    it "disjoint open ranges" $ do+      ((OpenRange 1 (10 :: Int)) `intersect` (OpenRange 10 (12 :: Int)))+      `shouldBe` (coRec NoIntersection)+    it "closed cap open, disjoint" $ do+      ((ClosedRange (1::Int) 10) `intersect` (OpenRange 50 (60 :: Int)))+      `shouldBe` (coRec NoIntersection)+    -- it "closed intersect open" $+    --   ((OpenRange 1 (10 :: Int)) `intersect` (ClosedRange 10 (12 :: Int)))+    --   `shouldBe` (coRec NoIntersection)++    -- it "open rage intersect closed " $ do+    --   ((OpenRange 1 (10 :: Int)) `intersect` (ClosedRange 10 (12 :: Int)))+    --   `shouldBe` (coRec $ Range (Open 10) (Open (10 :: Int)))+  -- (Col Range {_lower = Closed 10, _upper = Open 10})+  -- >>> (OpenRange 1 10) `intersect` (ClosedRange 10 12)+++    -- it "closed open " $ do+    --   ((ClosedRange 1 10) `intersect` (OpenRange 5 10))+    --   `shouldBe`+    --   (Col (Range (Open 5) (Closed 10)))+            -- encode "no-padding!!" `shouldBe` "bm8tcGFkZGluZyEh"++    -- |+  --+  -- >>>+  --+  -- >>>+  -- (Col NoIntersection)+  -- >>> (OpenRange 1 10) `intersect` (ClosedRange 10 12)+  -- (Col Range {_lower = Closed 10, _upper = Open 10})+  -- >>> (OpenRange 1 10) `intersect` (ClosedRange 10 12)+  -- FALSE
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}