overeasy 0.1.1 → 0.2.0
raw patch · 2 files changed
+45/−30 lines, 2 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Overeasy.Matching: [pgRoot] :: PatGraph f v -> !VarId
- Overeasy.Matching: instance (GHC.Classes.Eq v, GHC.Classes.Eq (f Overeasy.Matching.VarId)) => GHC.Classes.Eq (Overeasy.Matching.PatGraph f v)
- Overeasy.Matching: instance (GHC.Show.Show v, GHC.Show.Show (f Overeasy.Matching.VarId)) => GHC.Show.Show (Overeasy.Matching.PatGraph f v)
+ Overeasy.Matching: [pgRoots] :: PatGraph g f v -> !g VarId
+ Overeasy.Matching: instance (GHC.Classes.Eq v, GHC.Classes.Eq (g Overeasy.Matching.VarId), GHC.Classes.Eq (f Overeasy.Matching.VarId)) => GHC.Classes.Eq (Overeasy.Matching.PatGraph g f v)
+ Overeasy.Matching: instance (GHC.Show.Show v, GHC.Show.Show (g Overeasy.Matching.VarId), GHC.Show.Show (f Overeasy.Matching.VarId)) => GHC.Show.Show (Overeasy.Matching.PatGraph g f v)
+ Overeasy.Matching: singlePatGraph :: PatGraphC f v => Pat f v -> PatGraph Identity f v
+ Overeasy.Matching: type PatGroup g f v = g (Pat f v)
- Overeasy.Example: ArithConstF :: !Int -> ArithF r_aIXb
+ Overeasy.Example: ArithConstF :: !Int -> ArithF r_aJ60
- Overeasy.Example: ArithPlusF :: r_aIXb -> r_aIXb -> ArithF r_aIXb
+ Overeasy.Example: ArithPlusF :: r_aJ60 -> r_aJ60 -> ArithF r_aJ60
- Overeasy.Example: ArithShiftLF :: r_aIXb -> !Int -> ArithF r_aIXb
+ Overeasy.Example: ArithShiftLF :: r_aJ60 -> !Int -> ArithF r_aJ60
- Overeasy.Example: ArithShiftRF :: r_aIXb -> !Int -> ArithF r_aIXb
+ Overeasy.Example: ArithShiftRF :: r_aJ60 -> !Int -> ArithF r_aJ60
- Overeasy.Example: ArithTimesF :: r_aIXb -> r_aIXb -> ArithF r_aIXb
+ Overeasy.Example: ArithTimesF :: r_aJ60 -> r_aJ60 -> ArithF r_aJ60
- Overeasy.Example: data ArithF r_aIXb
+ Overeasy.Example: data ArithF r_aJ60
- Overeasy.Matching: PatGraph :: !VarId -> !IntLikeMap VarId (PatF f v VarId) -> !HashMap v VarId -> PatGraph f v
+ Overeasy.Matching: PatGraph :: !g VarId -> !IntLikeMap VarId (PatF f v VarId) -> !HashMap v VarId -> PatGraph g f v
- Overeasy.Matching: [pgNodes] :: PatGraph f v -> !IntLikeMap VarId (PatF f v VarId)
+ Overeasy.Matching: [pgNodes] :: PatGraph g f v -> !IntLikeMap VarId (PatF f v VarId)
- Overeasy.Matching: [pgVars] :: PatGraph f v -> !HashMap v VarId
+ Overeasy.Matching: [pgVars] :: PatGraph g f v -> !HashMap v VarId
- Overeasy.Matching: data PatGraph f v
+ Overeasy.Matching: data PatGraph g f v
- Overeasy.Matching: patGraph :: PatGraphC f v => Pat f v -> PatGraph f v
+ Overeasy.Matching: patGraph :: (Traversable g, PatGraphC f v) => PatGroup g f v -> PatGraph g f v
- Overeasy.Matching: solGraph :: SolGraphC f => PatGraph f v -> EGraph d f -> SolGraph EClassId f
+ Overeasy.Matching: solGraph :: SolGraphC f => PatGraph g f v -> EGraph d f -> SolGraph EClassId f
- Overeasy.Matching: solve :: SolveC c f v => SolStream c f v (MatchSubst c f v)
+ Overeasy.Matching: solve :: (Foldable g, SolveC c f v) => SolStream c g f v (MatchSubst c f v)
- Overeasy.Matching: type PatGraphC f v = (Traversable f, Eq v, Eq (f VarId), Hashable v, Hashable (f VarId))
+ Overeasy.Matching: type PatGraphC f v = (Traversable f, Traversable f, Eq v, Eq (f VarId), Hashable v, Hashable (f VarId))
- Overeasy.Matching: type SolStream c f v z = Stream (SolEnv c f v) (SolState c) z
+ Overeasy.Matching: type SolStream c g f v z = Stream (SolEnv c g f v) (SolState c) z
Files
- overeasy.cabal +1/−1
- src/Overeasy/Matching.hs +44/−29
overeasy.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: overeasy-version: 0.1.1+version: 0.2.0 synopsis: A purely functional E-Graph library description: Please see the README on GitHub at <https://github.com/ejconlon/overeasy#readme> category: Data Structures
src/Overeasy/Matching.hs view
@@ -5,12 +5,14 @@ module Overeasy.Matching ( Pat , patVars+ , PatGroup , Subst , substVars , VarId (..) , PatGraphC , PatGraph (..) , patGraph+ , singlePatGraph , Match (..) , MatchPat (..) , MatchF (..)@@ -30,6 +32,7 @@ import Control.Applicative (Alternative (..)) import Control.DeepSeq (NFData) import Control.Monad (void)+import Control.Monad.Identity (Identity (..)) import Control.Monad.Reader (asks) import Control.Monad.State.Strict (MonadState (..), State, evalState, execState, gets, modify', runState) import Data.Bifunctor (bimap)@@ -65,6 +68,11 @@ patVars :: (Foldable f, Eq v, Hashable v) => Pat f v -> HashSet v patVars = foldMap' HashSet.singleton +-- | A pattern group is some container with patterns inside.+-- This container might be 'Identity' for one pattern, or a list or+-- map for many patterns.+type PatGroup g f v = g (Pat f v)+ -- | A substitution. type Subst c v = HashMap v c @@ -142,17 +150,19 @@ -- | A pattern graph - can be created once for each pattern and reused -- for many iterations of search.-data PatGraph f v = PatGraph- { pgRoot :: !VarId+-- 'g' is the pattern group functor.+-- 'f' is the language functor.+data PatGraph g f v = PatGraph+ { pgRoots :: !(g VarId) , pgNodes :: !(IntLikeMap VarId (PatF f v VarId)) , pgVars :: !(HashMap v VarId) } -deriving stock instance (Eq v, Eq (f VarId)) => Eq (PatGraph f v)-deriving stock instance (Show v, Show (f VarId)) => Show (PatGraph f v)+deriving stock instance (Eq v, Eq (g VarId), Eq (f VarId)) => Eq (PatGraph g f v)+deriving stock instance (Show v, Show (g VarId), Show (f VarId)) => Show (PatGraph g f v) -- | The set of constraints necessary to build a pattern graph.-type PatGraphC f v = (Traversable f, Eq v, Eq (f VarId), Hashable v, Hashable (f VarId))+type PatGraphC f v = (Traversable f, Traversable f, Eq v, Eq (f VarId), Hashable v, Hashable (f VarId)) data GraphState f v = GraphState { gsSrc :: !(Source VarId)@@ -186,14 +196,20 @@ equiv = assocEquiv assoc in fmap (fmap (`efLookupRoot` equiv)) fwd --- | Builds a pattern graph from a pattern.-patGraph :: PatGraphC f v => Pat f v -> PatGraph f v-patGraph p =- let (i, st) = runState (graphEnsurePat p) emptyGraphState+-- | Builds a pattern graph from a group of patterns.+patGraph :: (Traversable g, PatGraphC f v) => PatGroup g f v -> PatGraph g f v+patGraph ps =+ let (gr, st) = runState (traverse graphEnsurePat ps) emptyGraphState m = graphCanonicalize st n = HashMap.fromList (ILM.toList m >>= \(j, x) -> case x of { FreePureF v -> [(v, j)]; _ -> [] })- in PatGraph i m n+ in PatGraph gr m n +-- | Builds a pattern graph from a single pattern.+-- If you have more than one pattern, building the group all at once is going to+-- make finding solutions more efficient.+singlePatGraph :: PatGraphC f v => Pat f v -> PatGraph Identity f v+singlePatGraph = patGraph . Identity+ -- | A solution graph - must be created from an e-graph each merge/rebuild. data SolGraph c f = SolGraph { sgByVar :: !(IntLikeMap VarId (IntLikeSet c))@@ -212,7 +228,7 @@ type SolGraphC f = (Functor f, Foldable f, Eq (f ()), Hashable (f ())) -- | Builds a solution graph from an e-graph.-solGraph :: SolGraphC f => PatGraph f v -> EGraph d f -> SolGraph EClassId f+solGraph :: SolGraphC f => PatGraph g f v -> EGraph d f -> SolGraph EClassId f solGraph pg eg = -- For each class, use footprint of reverse node assoc to find set of node ids -- Start with just the embedded nodes@@ -258,8 +274,8 @@ -- Finally update the map; if missing set the positions as is, otherwise take intersection modify' $ \m -> foldl' (\mx r -> case r of {RecordPure j cs -> ILM.alter (Just . maybe cs (ILS.intersection cs)) j mx; _ -> mx}) m rs -data SolEnv c f v = SolEnv- { sePatGraph :: !(PatGraph f v)+data SolEnv c g f v = SolEnv+ { sePatGraph :: !(PatGraph g f v) , seSolGraph :: !(SolGraph c f) } @@ -267,9 +283,8 @@ { ssClasses :: IntLikeMap VarId c } deriving (Eq, Show) --- | A stream of solutions. Can be demanded all at once, unconsed one at a time,--- or interleaved.-type SolStream c f v z = Stream (SolEnv c f v) (SolState c) z+-- | A stream of solutions. Can be demanded all at once or interleaved.+type SolStream c g f v z = Stream (SolEnv c g f v) (SolState c) z -- | The set of constraints necessary to search for solutions. type SolveC c f v = (Traversable f, Coercible c Int, Eq v, Hashable v, Eq (f c), Hashable (f c))@@ -290,30 +305,31 @@ constructSubst :: HashMap v VarId -> IntLikeMap VarId a -> Subst a v constructSubst vars classes = fmap (`ILM.partialLookup` classes) vars -solveYield :: Traversable f => SolStream c f v (MatchSubst c f v)-solveYield = do+solveYield :: Traversable f => VarId -> SolStream c g f v (MatchSubst c f v)+solveYield i = do pg <- asks sePatGraph classes <- gets ssClasses- let mat = constructMatch (pgNodes pg) classes (pgRoot pg)+ let mat = constructMatch (pgNodes pg) classes i subst = constructSubst (pgVars pg) classes ms = MatchSubst mat subst pure ms -- | Produces a stream of solutions (e-matches).-solve :: SolveC c f v => SolStream c f v (MatchSubst c f v)+solve :: (Foldable g, SolveC c f v) => SolStream c g f v (MatchSubst c f v) solve = do- i <- asks (pgRoot . sePatGraph)- void (solveRec i)- solveYield+ roots <- asks (pgRoots . sePatGraph)+ chooseWith roots $ \i -> do+ void (solveRec i)+ solveYield i -solveChoose :: SolveC c f v => VarId -> IntLikeSet c -> SolStream c f v c+solveChoose :: SolveC c f v => VarId -> IntLikeSet c -> SolStream c g f v c solveChoose i cs = chooseWith (ILS.toList cs) (solveSet i) -solveSet :: VarId -> c -> SolStream c f v c+solveSet :: VarId -> c -> SolStream c g f v c solveSet i c = c <$ modify' (\ss -> ss { ssClasses = ILM.insert i c (ssClasses ss) }) -solveRec :: SolveC c f v => VarId -> SolStream c f v c+solveRec :: SolveC c f v => VarId -> SolStream c g f v c solveRec i = do ms <- gets (ILM.lookup i . ssClasses) case ms of@@ -336,11 +352,10 @@ Just c -> solveSet i c -- | The easiest way to do e-matching: given a pattern and an e-graph, yield the list of matches.--- Note that it might be more efficient to keep a 'PatGraph' on hand and uncons the matches--- one by one.+-- Note that it's more efficient to keep a 'PatGraph' and use the same solution graph for multiple patterns.) match :: (PatGraphC f v, SolGraphC f, SolveC EClassId f v) => Pat f v -> EGraph d f -> [MatchSubst EClassId f v] match p eg =- let pg = patGraph p+ let pg = singlePatGraph p sg = solGraph pg eg in if any ILS.null (ILM.elems (sgByVar sg)) -- If any var id has no patches, the pattern won't match, so don't try to solve