packages feed

hegg 0.4.0.0 → 0.5.0.0

raw patch · 19 files changed

+592/−162 lines, 19 filesdep +deepseqdep +textdep ~graphvizPVP ok

version bump matches the API change (PVP)

Dependencies added: deepseq, text

Dependency ranges changed: graphviz

API changes (from Hackage documentation)

- Data.Equality.Graph.Lens: type Traversal s t a b = forall f. Applicative f => (a -> f b) -> (s -> f t)
+ Data.Equality.Analysis.Monadic: class (Monad m, Eq domain) => AnalysisM (m :: Type -> Type) domain (l :: Type -> Type)
+ Data.Equality.Analysis.Monadic: instance GHC.Base.Monad m => Data.Equality.Analysis.Monadic.AnalysisM m () l
+ Data.Equality.Analysis.Monadic: joinA :: AnalysisM m domain l => domain -> domain -> m domain
+ Data.Equality.Analysis.Monadic: makeA :: AnalysisM m domain l => l domain -> m domain
+ Data.Equality.Analysis.Monadic: modifyA :: AnalysisM m domain l => ClassId -> EGraph domain l -> m (EGraph domain l)
+ Data.Equality.Graph: addM :: forall a (l :: Type -> Type) m. (AnalysisM m a l, Language l) => ENode l -> EGraph a l -> m (ClassId, EGraph a l)
+ Data.Equality.Graph: mergeM :: forall a (l :: Type -> Type) m. (AnalysisM m a l, Language l) => ClassId -> ClassId -> EGraph a l -> m (ClassId, EGraph a l)
+ Data.Equality.Graph: newEClass :: forall (l :: Type -> Type) a. Language l => a -> EGraph a l -> (ClassId, EGraph a l)
+ Data.Equality.Graph: rebuildM :: forall a (l :: Type -> Type) m. (AnalysisM m a l, Language l) => EGraph a l -> m (EGraph a l)
+ Data.Equality.Graph: representM :: forall a (l :: Type -> Type) m. (AnalysisM m a l, Language l) => Fix l -> EGraph a l -> m (ClassId, EGraph a l)
+ Data.Equality.Graph.Lens: traverseOf :: Traversal s t a b -> forall (f :: Type -> Type). Applicative f => (a -> f b) -> s -> f t
+ Data.Equality.Graph.Lens: type ASetter s t a b = a -> Identity b -> s -> Identity t
+ Data.Equality.Graph.Lens: type Traversal s t a b = forall (f :: Type -> Type). Applicative f => a -> f b -> s -> f t
+ Data.Equality.Graph.Monad: addM :: forall (m :: Type -> Type) anl (l :: Type -> Type). (AnalysisM m anl l, Language l) => ENode l -> EGraphMT anl l m ClassId
+ Data.Equality.Graph.Monad: mergeM :: forall (m :: Type -> Type) anl (l :: Type -> Type). (AnalysisM m anl l, Language l) => ClassId -> ClassId -> EGraphMT anl l m ClassId
+ Data.Equality.Graph.Monad: rebuildM :: forall (m :: Type -> Type) anl (l :: Type -> Type). (AnalysisM m anl l, Language l) => EGraphMT anl l m ()
+ Data.Equality.Graph.Monad: representM :: forall (m :: Type -> Type) anl (l :: Type -> Type). (AnalysisM m anl l, Language l) => Fix l -> EGraphMT anl l m ClassId
+ Data.Equality.Graph.Monad: runEGraphMT :: forall anl (l :: Type -> Type) m a. EGraph anl l -> EGraphMT anl l m a -> m (a, EGraph anl l)
+ Data.Equality.Graph.Monad: type EGraphMT a (l :: Type -> Type) = StateT EGraph a l
- Data.Equality.Analysis: modifyA :: Analysis domain l => EClass domain l -> (EClass domain l, [Fix l])
+ Data.Equality.Analysis: modifyA :: Analysis domain l => ClassId -> EGraph domain l -> EGraph domain l
- Data.Equality.Extraction: type CostFunction l cost = l cost -> cost
+ Data.Equality.Extraction: type CostFunction (l :: Type -> Type) cost = l cost -> cost
- Data.Equality.Graph: add :: forall a l. (Analysis a l, Language l) => ENode l -> EGraph a l -> (ClassId, EGraph a l)
+ Data.Equality.Graph: add :: forall a (l :: Type -> Type). (Analysis a l, Language l) => ENode l -> EGraph a l -> (ClassId, EGraph a l)
- Data.Equality.Graph: canonicalize :: Functor l => ENode l -> EGraph a l -> ENode l
+ Data.Equality.Graph: canonicalize :: forall (l :: Type -> Type) a. Functor l => ENode l -> EGraph a l -> ENode l
- Data.Equality.Graph: data EGraph analysis language
+ Data.Equality.Graph: data EGraph analysis (language :: Type -> Type)
- Data.Equality.Graph: emptyEGraph :: Language l => EGraph a l
+ Data.Equality.Graph: emptyEGraph :: forall (l :: Type -> Type) a. Language l => EGraph a l
- Data.Equality.Graph: find :: ClassId -> EGraph a l -> ClassId
+ Data.Equality.Graph: find :: forall a (l :: Type -> Type). ClassId -> EGraph a l -> ClassId
- Data.Equality.Graph: merge :: forall a l. (Analysis a l, Language l) => ClassId -> ClassId -> EGraph a l -> (ClassId, EGraph a l)
+ Data.Equality.Graph: merge :: forall a (l :: Type -> Type). (Analysis a l, Language l) => ClassId -> ClassId -> EGraph a l -> (ClassId, EGraph a l)
- Data.Equality.Graph: rebuild :: (Analysis a l, Language l) => EGraph a l -> EGraph a l
+ Data.Equality.Graph: rebuild :: forall a (l :: Type -> Type). (Analysis a l, Language l) => EGraph a l -> EGraph a l
- Data.Equality.Graph: represent :: forall a l. (Analysis a l, Language l) => Fix l -> EGraph a l -> (ClassId, EGraph a l)
+ Data.Equality.Graph: represent :: forall a (l :: Type -> Type). (Analysis a l, Language l) => Fix l -> EGraph a l -> (ClassId, EGraph a l)
- Data.Equality.Graph.Classes: EClass :: {-# UNPACK #-} !ClassId -> !Set (ENode language) -> analysis_domain -> !SList (ClassId, ENode language) -> EClass analysis_domain language
+ Data.Equality.Graph.Classes: EClass :: {-# UNPACK #-} !ClassId -> !Set (ENode language) -> analysis_domain -> !SList (ClassId, ENode language) -> EClass analysis_domain (language :: Type -> Type)
- Data.Equality.Graph.Classes: [eClassData] :: EClass analysis_domain language -> analysis_domain
+ Data.Equality.Graph.Classes: [eClassData] :: EClass analysis_domain (language :: Type -> Type) -> analysis_domain
- Data.Equality.Graph.Classes: [eClassId] :: EClass analysis_domain language -> {-# UNPACK #-} !ClassId
+ Data.Equality.Graph.Classes: [eClassId] :: EClass analysis_domain (language :: Type -> Type) -> {-# UNPACK #-} !ClassId
- Data.Equality.Graph.Classes: [eClassNodes] :: EClass analysis_domain language -> !Set (ENode language)
+ Data.Equality.Graph.Classes: [eClassNodes] :: EClass analysis_domain (language :: Type -> Type) -> !Set (ENode language)
- Data.Equality.Graph.Classes: [eClassParents] :: EClass analysis_domain language -> !SList (ClassId, ENode language)
+ Data.Equality.Graph.Classes: [eClassParents] :: EClass analysis_domain (language :: Type -> Type) -> !SList (ClassId, ENode language)
- Data.Equality.Graph.Classes: data EClass analysis_domain language
+ Data.Equality.Graph.Classes: data EClass analysis_domain (language :: Type -> Type)
- Data.Equality.Graph.Lens: (%~) :: Lens' s a -> (a -> a) -> s -> s
+ Data.Equality.Graph.Lens: (%~) :: ASetter s t a b -> (a -> b) -> s -> t
- Data.Equality.Graph.Lens: _class :: ClassId -> Lens' (EGraph a l) (EClass a l)
+ Data.Equality.Graph.Lens: _class :: forall a (l :: Type -> Type). ClassId -> Lens' (EGraph a l) (EClass a l)
- Data.Equality.Graph.Lens: _classes :: Traversal (EGraph a l) (EGraph b l) (EClass a l) (EClass b l)
+ Data.Equality.Graph.Lens: _classes :: forall a (l :: Type -> Type) b f. Applicative f => (EClass a l -> f (EClass b l)) -> EGraph a l -> f (EGraph b l)
- Data.Equality.Graph.Lens: _data :: Lens' (EClass domain l) domain
+ Data.Equality.Graph.Lens: _data :: forall domain (l :: Type -> Type) domain' f. Functor f => (domain -> f domain') -> EClass domain l -> f (EClass domain' l)
- Data.Equality.Graph.Lens: _iclasses :: Traversal (EGraph a l) (EGraph b l) (ClassId, EClass a l) (EClass b l)
+ Data.Equality.Graph.Lens: _iclasses :: forall a (l :: Type -> Type) b f. Applicative f => ((ClassId, EClass a l) -> f (EClass b l)) -> EGraph a l -> f (EGraph b l)
- Data.Equality.Graph.Lens: _memo :: Lens' (EGraph a l) (NodeMap l ClassId)
+ Data.Equality.Graph.Lens: _memo :: forall a (l :: Type -> Type) f. Functor f => (NodeMap l ClassId -> f (NodeMap l ClassId)) -> EGraph a l -> f (EGraph a l)
- Data.Equality.Graph.Lens: _nodes :: Lens' (EClass a l) (Set (ENode l))
+ Data.Equality.Graph.Lens: _nodes :: forall a (l :: Type -> Type) f. Functor f => (Set (ENode l) -> f (Set (ENode l))) -> EClass a l -> f (EClass a l)
- Data.Equality.Graph.Lens: _parents :: Lens' (EClass a l) (SList (ClassId, ENode l))
+ Data.Equality.Graph.Lens: _parents :: forall a (l :: Type -> Type) f. Functor f => (SList (ClassId, ENode l) -> f (SList (ClassId, ENode l))) -> EClass a l -> f (EClass a l)
- Data.Equality.Graph.Lens: over :: Lens' s a -> (a -> a) -> s -> s
+ Data.Equality.Graph.Lens: over :: ASetter s t a b -> (a -> b) -> s -> t
- Data.Equality.Graph.Monad: add :: (Analysis anl l, Language l) => ENode l -> EGraphM anl l ClassId
+ Data.Equality.Graph.Monad: add :: forall anl (l :: Type -> Type). (Analysis anl l, Language l) => ENode l -> EGraphM anl l ClassId
- Data.Equality.Graph.Monad: canonicalize :: Functor l => ENode l -> EGraph a l -> ENode l
+ Data.Equality.Graph.Monad: canonicalize :: forall (l :: Type -> Type) a. Functor l => ENode l -> EGraph a l -> ENode l
- Data.Equality.Graph.Monad: data EGraph analysis language
+ Data.Equality.Graph.Monad: data EGraph analysis (language :: Type -> Type)
- Data.Equality.Graph.Monad: egraph :: Language l => EGraphM anl l a -> (a, EGraph anl l)
+ Data.Equality.Graph.Monad: egraph :: forall (l :: Type -> Type) anl a. Language l => EGraphM anl l a -> (a, EGraph anl l)
- Data.Equality.Graph.Monad: emptyEGraph :: Language l => EGraph a l
+ Data.Equality.Graph.Monad: emptyEGraph :: forall (l :: Type -> Type) a. Language l => EGraph a l
- Data.Equality.Graph.Monad: find :: ClassId -> EGraph a l -> ClassId
+ Data.Equality.Graph.Monad: find :: forall a (l :: Type -> Type). ClassId -> EGraph a l -> ClassId
- Data.Equality.Graph.Monad: merge :: (Analysis anl l, Language l) => ClassId -> ClassId -> EGraphM anl l ClassId
+ Data.Equality.Graph.Monad: merge :: forall anl (l :: Type -> Type). (Analysis anl l, Language l) => ClassId -> ClassId -> EGraphM anl l ClassId
- Data.Equality.Graph.Monad: rebuild :: (Analysis anl l, Language l) => EGraphM anl l ()
+ Data.Equality.Graph.Monad: rebuild :: forall anl (l :: Type -> Type). (Analysis anl l, Language l) => EGraphM anl l ()
- Data.Equality.Graph.Monad: represent :: (Analysis anl l, Language l) => Fix l -> EGraphM anl l ClassId
+ Data.Equality.Graph.Monad: represent :: forall anl (l :: Type -> Type). (Analysis anl l, Language l) => Fix l -> EGraphM anl l ClassId
- Data.Equality.Graph.Monad: runEGraphM :: EGraph anl l -> EGraphM anl l a -> (a, EGraph anl l)
+ Data.Equality.Graph.Monad: runEGraphM :: forall anl (l :: Type -> Type) a. EGraph anl l -> EGraphM anl l a -> (a, EGraph anl l)
- Data.Equality.Graph.Monad: type EGraphM a l = State (EGraph a l)
+ Data.Equality.Graph.Monad: type EGraphM a (l :: Type -> Type) = State EGraph a l
- Data.Equality.Graph.Nodes: Node :: l ClassId -> ENode l
+ Data.Equality.Graph.Nodes: Node :: l ClassId -> ENode (l :: Type -> Type)
- Data.Equality.Graph.Nodes: Operator :: l () -> Operator l
+ Data.Equality.Graph.Nodes: Operator :: l () -> Operator (l :: Type -> Type)
- Data.Equality.Graph.Nodes: [unNode] :: ENode l -> l ClassId
+ Data.Equality.Graph.Nodes: [unNode] :: ENode (l :: Type -> Type) -> l ClassId
- Data.Equality.Graph.Nodes: [unOperator] :: Operator l -> l ()
+ Data.Equality.Graph.Nodes: [unOperator] :: Operator (l :: Type -> Type) -> l ()
- Data.Equality.Graph.Nodes: children :: Traversable l => ENode l -> [ClassId]
+ Data.Equality.Graph.Nodes: children :: forall (l :: Type -> Type). Traversable l => ENode l -> [ClassId]
- Data.Equality.Graph.Nodes: deleteNM :: Ord (l ClassId) => ENode l -> NodeMap l a -> NodeMap l a
+ Data.Equality.Graph.Nodes: deleteNM :: forall (l :: Type -> Type) a. Ord (l ClassId) => ENode l -> NodeMap l a -> NodeMap l a
- Data.Equality.Graph.Nodes: foldlWithKeyNM' :: Ord (l ClassId) => (b -> ENode l -> a -> b) -> b -> NodeMap l a -> b
+ Data.Equality.Graph.Nodes: foldlWithKeyNM' :: forall (l :: Type -> Type) b a. Ord (l ClassId) => (b -> ENode l -> a -> b) -> b -> NodeMap l a -> b
- Data.Equality.Graph.Nodes: foldrWithKeyNM' :: Ord (l ClassId) => (ENode l -> a -> b -> b) -> b -> NodeMap l a -> b
+ Data.Equality.Graph.Nodes: foldrWithKeyNM' :: forall (l :: Type -> Type) a b. Ord (l ClassId) => (ENode l -> a -> b -> b) -> b -> NodeMap l a -> b
- Data.Equality.Graph.Nodes: insertLookupNM :: Ord (l ClassId) => ENode l -> a -> NodeMap l a -> (Maybe a, NodeMap l a)
+ Data.Equality.Graph.Nodes: insertLookupNM :: forall (l :: Type -> Type) a. Ord (l ClassId) => ENode l -> a -> NodeMap l a -> (Maybe a, NodeMap l a)
- Data.Equality.Graph.Nodes: insertNM :: Ord (l ClassId) => ENode l -> a -> NodeMap l a -> NodeMap l a
+ Data.Equality.Graph.Nodes: insertNM :: forall (l :: Type -> Type) a. Ord (l ClassId) => ENode l -> a -> NodeMap l a -> NodeMap l a
- Data.Equality.Graph.Nodes: lookupNM :: Ord (l ClassId) => ENode l -> NodeMap l a -> Maybe a
+ Data.Equality.Graph.Nodes: lookupNM :: forall (l :: Type -> Type) a. Ord (l ClassId) => ENode l -> NodeMap l a -> Maybe a
- Data.Equality.Graph.Nodes: newtype ENode l
+ Data.Equality.Graph.Nodes: newtype ENode (l :: Type -> Type)
- Data.Equality.Graph.Nodes: newtype Operator l
+ Data.Equality.Graph.Nodes: newtype Operator (l :: Type -> Type)
- Data.Equality.Graph.Nodes: operator :: Traversable l => ENode l -> Operator l
+ Data.Equality.Graph.Nodes: operator :: forall (l :: Type -> Type). Traversable l => ENode l -> Operator l
- Data.Equality.Graph.Nodes: sizeNM :: NodeMap l a -> Int
+ Data.Equality.Graph.Nodes: sizeNM :: forall (l :: Type -> Type) a. NodeMap l a -> Int
- Data.Equality.Graph.Nodes: traverseWithKeyNM :: Applicative t => (ENode l -> a -> t b) -> NodeMap l a -> t (NodeMap l b)
+ Data.Equality.Graph.Nodes: traverseWithKeyNM :: forall t (l :: Type -> Type) a b. Applicative t => (ENode l -> a -> t b) -> NodeMap l a -> t (NodeMap l b)
- Data.Equality.Language: class (forall a. Ord a => Ord (l a), Traversable l) => Language l
+ Data.Equality.Language: class (forall a. Ord a => Ord l a, Traversable l) => Language (l :: Type -> Type)
- Data.Equality.Matching: compileToQuery :: Traversable lang => Pattern lang -> (Query lang, Var)
+ Data.Equality.Matching: compileToQuery :: forall (lang :: Type -> Type). Traversable lang => Pattern lang -> (Query lang, Var)
- Data.Equality.Matching: eGraphToDatabase :: Language l => EGraph a l -> Database l
+ Data.Equality.Matching: eGraphToDatabase :: forall (l :: Type -> Type) a. Language l => EGraph a l -> Database l
- Data.Equality.Matching: ematch :: Language l => Database l -> Pattern l -> [Match]
+ Data.Equality.Matching: ematch :: forall (l :: Type -> Type). Language l => Database l -> Pattern l -> [Match]
- Data.Equality.Matching.Database: Atom :: !ClassIdOrVar -> !lang ClassIdOrVar -> Atom lang
+ Data.Equality.Matching.Database: Atom :: !ClassIdOrVar -> !lang ClassIdOrVar -> Atom (lang :: Type -> Type)
- Data.Equality.Matching.Database: DB :: Map (Operator lang) IntTrie -> Database lang
+ Data.Equality.Matching.Database: DB :: Map (Operator lang) IntTrie -> Database (lang :: Type -> Type)
- Data.Equality.Matching.Database: Query :: ![Var] -> ![Atom lang] -> Query lang
+ Data.Equality.Matching.Database: Query :: ![Var] -> ![Atom lang] -> Query (lang :: Type -> Type)
- Data.Equality.Matching.Database: SelectAllQuery :: {-# UNPACK #-} !Var -> Query lang
+ Data.Equality.Matching.Database: SelectAllQuery :: {-# UNPACK #-} !Var -> Query (lang :: Type -> Type)
- Data.Equality.Matching.Database: data Atom lang
+ Data.Equality.Matching.Database: data Atom (lang :: Type -> Type)
- Data.Equality.Matching.Database: data Query lang
+ Data.Equality.Matching.Database: data Query (lang :: Type -> Type)
- Data.Equality.Matching.Database: genericJoin :: forall l. Language l => Database l -> Query l -> [Subst]
+ Data.Equality.Matching.Database: genericJoin :: forall (l :: Type -> Type). Language l => Database l -> Query l -> [Subst]
- Data.Equality.Matching.Database: newtype Database lang
+ Data.Equality.Matching.Database: newtype Database (lang :: Type -> Type)
- Data.Equality.Matching.Pattern: NonVariablePattern :: lang (Pattern lang) -> Pattern lang
+ Data.Equality.Matching.Pattern: NonVariablePattern :: lang (Pattern lang) -> Pattern (lang :: Type -> Type)
- Data.Equality.Matching.Pattern: VariablePattern :: Var -> Pattern lang
+ Data.Equality.Matching.Pattern: VariablePattern :: Var -> Pattern (lang :: Type -> Type)
- Data.Equality.Matching.Pattern: data Pattern lang
+ Data.Equality.Matching.Pattern: data Pattern (lang :: Type -> Type)
- Data.Equality.Saturation: (:=) :: !Pattern lang -> !Pattern lang -> Rewrite anl lang
+ Data.Equality.Saturation: (:=) :: !Pattern lang -> !Pattern lang -> Rewrite anl (lang :: Type -> Type)
- Data.Equality.Saturation: (:|) :: !Rewrite anl lang -> !RewriteCondition anl lang -> Rewrite anl lang
+ Data.Equality.Saturation: (:|) :: !Rewrite anl lang -> !RewriteCondition anl lang -> Rewrite anl (lang :: Type -> Type)
- Data.Equality.Saturation: Fix :: f (Fix f) -> Fix f
+ Data.Equality.Saturation: Fix :: f (Fix f) -> Fix (f :: Type -> Type)
- Data.Equality.Saturation: [unFix] :: Fix f -> f (Fix f)
+ Data.Equality.Saturation: [unFix] :: Fix (f :: Type -> Type) -> f (Fix f)
- Data.Equality.Saturation: data Rewrite anl lang
+ Data.Equality.Saturation: data Rewrite anl (lang :: Type -> Type)
- Data.Equality.Saturation: equalitySaturation :: forall a l cost. (Analysis a l, Language l, Ord cost) => Fix l -> [Rewrite a l] -> CostFunction l cost -> (Fix l, EGraph a l)
+ Data.Equality.Saturation: equalitySaturation :: (Analysis a l, Language l, Ord cost) => Fix l -> [Rewrite a l] -> CostFunction l cost -> (Fix l, EGraph a l)
- Data.Equality.Saturation: equalitySaturation' :: forall a l schd cost. (Analysis a l, Language l, Scheduler schd, Ord cost) => schd -> Fix l -> [Rewrite a l] -> CostFunction l cost -> (Fix l, EGraph a l)
+ Data.Equality.Saturation: equalitySaturation' :: (Analysis a l, Language l, Scheduler schd, Ord cost) => schd -> Fix l -> [Rewrite a l] -> CostFunction l cost -> (Fix l, EGraph a l)
- Data.Equality.Saturation: newtype Fix f
+ Data.Equality.Saturation: newtype Fix (f :: Type -> Type)
- Data.Equality.Saturation: runEqualitySaturation :: forall a l schd. (Analysis a l, Language l, Scheduler schd) => schd -> [Rewrite a l] -> EGraphM a l ()
+ Data.Equality.Saturation: runEqualitySaturation :: forall a (l :: Type -> Type) schd. (Analysis a l, Language l, Scheduler schd) => schd -> [Rewrite a l] -> EGraphM a l ()
- Data.Equality.Saturation: type CostFunction l cost = l cost -> cost
+ Data.Equality.Saturation: type CostFunction (l :: Type -> Type) cost = l cost -> cost
- Data.Equality.Saturation: type RewriteCondition anl lang = Subst -> EGraph anl lang -> Bool
+ Data.Equality.Saturation: type RewriteCondition anl (lang :: Type -> Type) = Subst -> EGraph anl lang -> Bool
- Data.Equality.Saturation.Rewrites: (:=) :: !Pattern lang -> !Pattern lang -> Rewrite anl lang
+ Data.Equality.Saturation.Rewrites: (:=) :: !Pattern lang -> !Pattern lang -> Rewrite anl (lang :: Type -> Type)
- Data.Equality.Saturation.Rewrites: (:|) :: !Rewrite anl lang -> !RewriteCondition anl lang -> Rewrite anl lang
+ Data.Equality.Saturation.Rewrites: (:|) :: !Rewrite anl lang -> !RewriteCondition anl lang -> Rewrite anl (lang :: Type -> Type)
- Data.Equality.Saturation.Rewrites: data Rewrite anl lang
+ Data.Equality.Saturation.Rewrites: data Rewrite anl (lang :: Type -> Type)
- Data.Equality.Saturation.Rewrites: type RewriteCondition anl lang = Subst -> EGraph anl lang -> Bool
+ Data.Equality.Saturation.Rewrites: type RewriteCondition anl (lang :: Type -> Type) = Subst -> EGraph anl lang -> Bool
- Data.Equality.Utils: Fix :: f (Fix f) -> Fix f
+ Data.Equality.Utils: Fix :: f (Fix f) -> Fix (f :: Type -> Type)
- Data.Equality.Utils: [unFix] :: Fix f -> f (Fix f)
+ Data.Equality.Utils: [unFix] :: Fix (f :: Type -> Type) -> f (Fix f)
- Data.Equality.Utils: newtype Fix f
+ Data.Equality.Utils: newtype Fix (f :: Type -> Type)
- Data.Equality.Utils.IntToIntMap: data IntToIntMap
+ Data.Equality.Utils.IntToIntMap: data IntToIntMap :: UnliftedType
- Data.Equality.Utils.IntToIntMap: unliftedFoldr :: forall a {b :: TYPE ('BoxedRep 'Unlifted)}. (a -> b -> b) -> b -> [a] -> b
+ Data.Equality.Utils.IntToIntMap: unliftedFoldr :: forall a {b :: UnliftedType}. (a -> b -> b) -> b -> [a] -> b

Files

CHANGELOG.md view
@@ -2,6 +2,27 @@  ## Unreleased +## 0.5.0.0 -- 2023-10-31++* Change `'modifyA'` to instead operate over e-graphs, instead of being+    constrained to editing the e-class that prompted the modification.+    (Remember that the e-graph lenses in `'Data.Equality.Graph.Lens'` are the+    preferred way to edit the e-graph and the desired e-class (by id), and its+    data, etc...)++* Fix compilation of Data.Equality.Graph.Dot, the graphviz rendering backend+    (despite there being some usability bugs still) (by @BinderDavid)++* Dropped support for GHC 9.0 because of the QuantifiedConstraints bug (by @phadej)++* Add `AnalysisM`, a class for e-graph analysis that are only well-defined+    within a certain monadic context. Accordingly, we also add versions of the+    current e-graph transformation functions (such as `add` and `merge`) for+    analysis defined monadically (such as `addM` and `mergeM`).++* Add operation to create empty e-classes with explicit domain data+    (experimental, not sure whether this is something good to keep in the API)+ ## 0.4.0.0 -- 2023-06-24  * Make `Language` a constraint type synonym instead of a standalone empty class
README.md view
@@ -117,7 +117,7 @@ e-node has a constant value or otherwise return `Nothing`:  ```hs-makeA :: SymExpr (Maybe Double) -> Maybe Int+makeA :: SymExpr (Maybe Double) -> Maybe Double makeA = \case   Const x -> Just x   Symbol _ -> Nothing@@ -144,19 +144,22 @@ Finally, `modifyA` describes how an e-class should (optionally) be modified according to the e-class data and what new language expressions are to be added to the e-class also w.r.t. the e-class data.-Its type is `EClass domain l -> (EClass domain l, [Fix l])`, where the argument-is the class to modify, the first element of the return tuple is the-(optionally) modified e-class and the second element is a list of the-expressions to represent and merge with this e-class.-For our example, if the e-class has a constant value associated to it, we want-to create a new e-class with that constant value and merge it to this e-class.+Its type is `ClassId -> EGraph domain l -> EGraph domain l`, where the first argument+is the id of the class to modify (the class which prompted the modification),+and then receives and returns an e-graph, in which the e-class has been+modified.  For our example, if the e-class has a constant value associated to+it, we want to create a new e-class with that constant value and merge it to+this e-class.  ```hs--- import Data.Equality.Graph.Lens ((^.), _data)-modifyA :: EClass (Maybe Double) SymExpr -> (EClass (Maybe Double) SymExpr, [Fix SymExpr])-modifyA c = case c^._data of-              Nothing -> (c, [])-              Just i  -> (c, [Fix (Const i)])+-- import Data.Equality.Graph.Lens ((^.), _class, _data)+modifyA :: ClassId -> EGraph (Maybe Double) SymExpr -> EGraph (Maybe Double) SymExpr+modifyA c egr+    = case egr ^._class c._data of+        Nothing -> egr+        Just i ->+          let (c', egr') = represent (Fix (Const i)) egr+           in snd $ merge c c' egr' ```  Modify is a bit trickier than the other methods, but it allows our e-graph to@@ -179,15 +182,6 @@ instance Analysis () lang where   makeA _ = ()   joinA _ _ = ()-```--### Language, again--With this setup, we can now express that `SymExpr` forms a `Language` which we-can represent and manipulate in an e-graph by simply instancing it (there are no-additional functions to define).-```hs-instance Language SymExpr ```  ### Equality saturation
hegg.cabal view
@@ -1,7 +1,7 @@ cabal-version:      2.4 name:               hegg-version:            0.4.0.0-Tested-With:        GHC ==9.4.2 || ==9.2.2 || ==9.0.2 || ==8.10.7+version:            0.5.0.0+Tested-With:        GHC ==9.6.2 || ==9.4.5 || ==9.2.7 || ==8.10.7 synopsis:           Fast equality saturation in Haskell  description:        Fast equality saturation and equality graphs based on "egg:@@ -38,7 +38,7 @@ maintainer:         Rodrigo Mesquita <rodrigo.m.mesquita@gmail.com> copyright:          Copyright (C) 2022 Rodrigo Mesquita category:           Data-extra-source-files: CHANGELOG.md+extra-doc-files:    CHANGELOG.md                     README.md  source-repository head@@ -46,6 +46,13 @@     location: https://github.com/alt-romes/hegg  library+    other-extensions: BlockArguments StandaloneKindSignatures++    -- QuantifiedConstraints are quite broken with GHC-9.0+    -- Ord (Pattern l) instance triggers same issue like+    -- https://github.com/haskell/mtl/issues/138+    build-depends: base >=4.16  || <4.15+     ghc-options:      -Wall -Wcompat                        -- -fno-prof-auto@@ -77,6 +84,7 @@                       Data.Equality.Extraction,                       Data.Equality.Language,                       Data.Equality.Analysis,+                      Data.Equality.Analysis.Monadic,                       Data.Equality.Saturation.Scheduler,                       Data.Equality.Saturation.Rewrites,                       Data.Equality.Utils,@@ -91,11 +99,13 @@     -- other-modules:      -- LANGUAGE extensions used by modules in this package.-    build-depends:    base         >= 4.4 && < 5,+    -- base-4.13, because foldMap' is used.+    build-depends:    base         >= 4.13 && < 5,                       transformers >= 0.4 && < 0.7,                       containers   >= 0.4 && < 0.7     if flag(vizdot)-        build-depends: graphviz >= 2999.6 && < 2999.7+        build-depends: graphviz >= 2999.20 && < 2999.21,+                       text     hs-source-dirs:   src     default-language: Haskell2010 @@ -108,7 +118,7 @@     hs-source-dirs:   test     main-is:          Test.hs     other-modules:    Invariants, Sym, Lambda, SimpleSym,-                      T1, T2+                      T1, T2, T3      other-extensions: OverloadedStrings     build-depends:    base,@@ -129,8 +139,11 @@                   tasty,                   tasty-hunit,                   tasty-quickcheck,-                  tasty-bench >= 0.2  && < 0.4-  ghc-options:    -with-rtsopts=-A32m -threaded+                  tasty-bench >= 0.2 && < 0.4,+                  deepseq >= 1.4 && < 1.6+  ghc-options:    -with-rtsopts=-A32m+  if impl(ghc >= 8.6)+    ghc-options: -fproc-alignment=64  Flag vizdot     Description: Compile 'Data.Equality.Graph.Dot' module to visualize e-graphs
src/Data/Equality/Analysis.hs view
@@ -30,8 +30,10 @@ import Data.Kind (Type) import Control.Arrow ((***)) -import Data.Equality.Utils+import Data.Function ((&))+import Data.Equality.Graph.Lens import Data.Equality.Language+import Data.Equality.Graph.Internal (EGraph) import Data.Equality.Graph.Classes  -- | An e-class analysis with domain @domain@ defined for a language @l@.@@ -70,31 +72,29 @@     -- e-node to c. Modify should be idempotent if no other changes occur to     -- the e-class, i.e., modify(modify(c)) = modify(c)     ---    -- The return value of the modify function is both the modified class and-    -- the expressions (in their fixed-point form) to add to this class. We-    -- can't manually add them because not only would it skip some of the-    -- internal steps of representing + merging, but also because it's-    -- impossible to add any expression with depth > 0 without access to the-    -- e-graph (since we must represent every sub-expression in the e-graph-    -- first).-    ---    -- That's why we must return the modified class and the expressions to add-    -- to this class.-    --     -- === Example     --     -- Pruning an e-class with a constant value of all its nodes except for the     -- leaf values, and adding a constant value node     --     -- @-    --  -- Prune all except leaf e-nodes-    --  modifyA cl =-    --    case cl^._data of-    --      Nothing -> (cl, [])-    --      Just d -> ((_nodes %~ S.filter (F.null .unNode)) cl, [Fix (Const d)])+    -- modifyA cl eg0+    --   = case eg0^._class cl._data of+    --       Nothing -> eg0+    --       Just d  ->+    --             -- Add constant as e-node+    --         let (new_c,eg1) = represent (Fix (Const d)) eg0+    --             (rep, eg2)  = merge cl new_c eg1+    --             -- Prune all except leaf e-nodes+    --          in eg2 & _class rep._nodes %~ S.filter (F.null .unNode)     -- @-    modifyA :: EClass domain l -> (EClass domain l, [Fix l])-    modifyA c = (c, [])+    modifyA :: ClassId+            -- ^ Id of class @c@ whose new data @d_c@ triggered the modify call+            -> EGraph domain l+            -- ^ E-graph where class @c@ being modified exists+            -> EGraph domain l+            -- ^ E-graph resulting from the modification+    modifyA _ = id     {-# INLINE modifyA #-}  @@ -105,13 +105,14 @@   joinA = (<>)  --- This instance is not necessarily well behaved for any two analysis, so care+-- | This instance is not necessarily well behaved for any two analysis, so care -- must be taken when using it. -- -- A possible criterion is: -- -- For any two analysis, where 'modifyA' is called @m1@ and @m2@ respectively,--- this instance is well behaved if @m1@ and @m2@ commute.+-- this instance is well behaved if @m1@ and @m2@ commute, and the analysis+-- only change the e-class being modified. -- -- That is, if @m1@ and @m2@ satisfy the following law: -- @@@ -133,10 +134,12 @@   joinA :: (a,b) -> (a,b) -> (a,b)   joinA (x,y) = joinA @a @l x *** joinA @b @l y -  modifyA :: EClass (a, b) l -> (EClass (a, b) l, [Fix l])-  modifyA c =-    let (ca, la) = modifyA @a (c { eClassData = fst (eClassData c) })-        (cb, lb) = modifyA @b (c { eClassData = snd (eClassData c) })-     in ( EClass (eClassId c) (eClassNodes ca <> eClassNodes cb) (eClassData ca, eClassData cb) (eClassParents ca <> eClassParents cb)-        , la <> lb-        )+  modifyA :: ClassId -> EGraph (a, b) l -> EGraph (a, b) l+  modifyA c egr =+    let egra = modifyA @a c (egr & _classes._data %~ fst)+        egrb = modifyA @b c (egr & _classes._data %~ snd)+        ca = egra ^._class c+        cb = egrb ^._class c+     in+      egr &+        _class c .~ (EClass c (eClassNodes ca <> eClassNodes cb) (eClassData ca, eClassData cb) (eClassParents ca <> eClassParents cb))
+ src/Data/Equality/Analysis/Monadic.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE AllowAmbiguousTypes #-} -- joinA+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ImpredicativeTypes #-}+{-|++Like 'Data.Equality.Analysis' but for 'Analysis' that are only well-defined+within an (effectful) context. Mostly used with the monadic operations+'representM', 'addM', 'mergeM', and 'rebuildM'.++This effectful 'Analysis' could almost be trivially defined in terms of the+other, through a "contextful" domain and by means of the '_classes' 'Traversal'.++However, that would require an instance of 'Eq' for the monadic domain, which+is usually unnattainable.++Therefore, we do need this class for monadic 'Analysis'.++-}+module Data.Equality.Analysis.Monadic where+++import Data.Kind (Type)++import Data.Equality.Graph.Internal (EGraph)+import Data.Equality.Graph.Classes++-- | An e-class analysis with domain @domain@ defined for a language @l@, whose operations are only well-defined within some effectful context.+--+-- The @domain@ is the type of the domain of the e-class analysis, that is, the+-- type of the data stored in an e-class according to this e-class analysis+class (Monad m, Eq domain) => AnalysisM m domain (l :: Type -> Type) where++    -- | When a new e-node is added into a new, singleton e-class, construct a+    -- new value of the domain to be associated with the new e-class, by+    -- accessing the associated data of the node's children+    --+    -- The argument is the e-node term populated with its children data+    makeA :: l domain -> m domain++    -- | When e-classes c1 c2 are being merged into c, join d_c1 and+    -- d_c2 into a new value d_c to be associated with the new+    -- e-class c+    joinA :: domain -> domain -> m domain++    -- | Optionally modify the e-class c (based on d_c), typically by adding an+    -- e-node to c. Modify should be idempotent if no other changes occur to+    -- the e-class, i.e., modify(modify(c)) = modify(c)+    modifyA :: ClassId+            -- ^ Id of class @c@ whose new data @d_c@ triggered the modify call+            -> EGraph domain l+            -- ^ E-graph where class @c@ being modified exists+            -> m (EGraph domain l)+            -- ^ E-graph resulting from the modification+    modifyA _ = pure+    {-# INLINE modifyA #-}+++-- | The simplest analysis that defines the domain to be () and does nothing otherwise+instance Monad m => AnalysisM m () l where+  makeA _ = pure ()+  joinA _ _ = pure ()+
src/Data/Equality/Graph.hs view
@@ -5,7 +5,8 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE TupleSections #-}+{-# OPTIONS_GHC -ddump-to-file -ddump-simpl #-} {-|    An e-graph efficiently represents a congruence relation over many expressions. @@ -13,35 +14,45 @@  -} module Data.Equality.Graph     (-      -- * Definition of e-graph+      -- ** Definition of e-graph       EGraph -      -- * Functions on e-graphs-    , emptyEGraph--      -- ** Transformations+      -- ** E-graph transformations     , represent, add, merge, rebuild     -- , repair, repairAnal        -- ** Querying     , find, canonicalize +      -- ** Functions on e-graphs+    , emptyEGraph, newEClass++      -- * E-graph transformations for monadic analysis+      -- | These are the same operations over e-graphs as above but over a monad in which the analysis is defined.+      -- It is common to only have a valid 'Analysis' under a monadic context.+      -- In that case, these are the functions to use -- they are just like the+      -- non-monadic ones, but have require an 'Analysis' defined in a+      -- monadic context ('AnalysisM').+    , representM, addM, mergeM, rebuildM+       -- * Re-exports     , module Data.Equality.Graph.Classes     , module Data.Equality.Graph.Nodes     , module Data.Equality.Language     ) where --- ROMES:TODO: Is the E-Graph a Monad if the analysis data were the type arg? i.e. Monad (EGraph language)?+-- ROMES:TODO: Is the E-Graph a Monad if the analysis data were the type arg? i.e. instance Monad (EGraph language)?  -- import GHC.Conc import Prelude hiding (lookup)  import Data.Function+import Data.Foldable (foldlM) import Data.Bifunctor import Data.Containers.ListUtils  import Control.Monad+import Control.Monad.Trans.Class import Control.Monad.Trans.State import Control.Exception (assert) @@ -55,6 +66,7 @@ import Data.Equality.Graph.Classes import Data.Equality.Graph.Nodes import Data.Equality.Analysis+import qualified Data.Equality.Analysis.Monadic as AM import Data.Equality.Language import Data.Equality.Graph.Lens @@ -89,12 +101,7 @@             (new_eclass_id, new_uf) = makeNewSet (unionFind egr)              -- New singleton e-class stores the e-node and its analysis data-            -- which is modified according to analysis-            ---            -- The modification also produces a list of expressions to-            -- represent and merge with this class, which we'll do before-            -- returning from this function-            (new_eclass, added_nodes) = modifyA $ EClass new_eclass_id (S.singleton new_en) (makeA @a ((\i -> egr^._class i._data @a) <$> unNode new_en)) mempty+            new_eclass = EClass new_eclass_id (S.singleton new_en) (makeA @a ((\i -> egr^._class i._data @a) <$> unNode new_en)) mempty              -- TODO:Performance: All updates can be done to the map first? Parallelize?             --@@ -138,20 +145,14 @@             -- Add the e-node's e-class id at the e-node's id             new_memo         = insertNM new_en new_eclass_id (memo egr) -            -- So we have our almost final e-graph. We just need to represent-            -- and merge in it all expressions which resulted from 'modifyA'-            -- above-            egr1             = egr { unionFind = new_uf-                                   , classes   = new_classes-                                   , worklist  = new_worklist-                                   , memo      = new_memo-                                   }--            egr2             = foldr (representAndMerge new_eclass_id) egr1 added_nodes--          in ( new_eclass_id-            , egr2+            , egr { unionFind = new_uf+                  , classes   = new_classes+                  , worklist  = new_worklist+                  , memo      = new_memo+                  }+                  -- Modify created node according to analysis+                  & modifyA new_eclass_id             ) {-# INLINABLE add #-} @@ -184,11 +185,10 @@             -- Update leader class with all e-nodes and parents from the            -- subsumed class-           (updatedLeader, added_nodes) = leader_class-                                            & _parents %~ (sub_class^._parents <>)-                                            & _nodes   %~ (sub_class^._nodes <>)-                                            & _data    .~ new_data-                                            & modifyA+           updatedLeader = leader_class+                             & _parents %~ (sub_class^._parents <>)+                             & _nodes   %~ (sub_class^._nodes <>)+                             & _data    .~ new_data             new_data = joinA @a @l (leader_class^._data) (sub_class^._data) @@ -226,10 +226,10 @@              , worklist  = new_worklist              , analysisWorklist = new_analysis_worklist              }--           egr2 = foldr (representAndMerge leader) egr1 added_nodes+             -- Modify according to analysis+             & modifyA new_id -        in (new_id, egr2)+        in (new_id, egr1) {-# INLINEABLE merge #-}              @@ -276,22 +276,18 @@ repairAnal :: forall a l. (Analysis a l, Language l) => (ClassId, ENode l) -> EGraph a l -> EGraph a l repairAnal (repair_id, node) egr =     let-        c1                = egr^._class repair_id-        new_data          = joinA @a @l (c1^._data) (makeA @a ((\i -> egr^._class i^._data @a) <$> unNode node))-        (c2, added_nodes) = modifyA (c1 & _data .~ new_data)+        c                = egr^._class repair_id+        new_data          = joinA @a @l (c^._data) (makeA @a ((\i -> egr^._class i^._data @a) <$> unNode node))     in     -- Take action if the new_data is different from the existing data-    if c1^._data /= new_data+    if c^._data /= new_data         -- Merge result is different from original class data, update class         -- with new_data        then-        let-            new_classes = IM.insert repair_id c2 (classes egr)-            egr1 = egr { analysisWorklist = toListSL (c1^._parents) <> analysisWorklist egr-                       , classes = new_classes-                       }-            egr2 = foldr (representAndMerge repair_id) egr1 added_nodes-         in egr2+         egr { analysisWorklist = toListSL (c^._parents) <> analysisWorklist egr+             , classes = IM.adjust (_data .~ new_data) repair_id (classes egr)+             }+             & modifyA repair_id        else egr {-# INLINE repairAnal #-} @@ -319,7 +315,192 @@ emptyEGraph = EGraph emptyUF mempty mempty mempty mempty {-# INLINE emptyEGraph #-} --- | Represent an expression (in fix-point form) and merge it with the e-class with the given id-representAndMerge :: (Analysis a l, Language l) => ClassId -> Fix l -> EGraph a l -> EGraph a l-representAndMerge o f g = case represent f g of-                        (i, e) -> snd $ merge o i e+-- | Creates an empty e-class in an e-graph, with the explicitly given domain analysis data.+-- (That is, an e-class with no e-nodes)+newEClass :: (Language l) => a -> EGraph a l -> (ClassId, EGraph a l)+newEClass adata egr =+  let+    -- Make new equivalence class with a new id in the union-find+    (new_eclass_id, new_uf) = makeNewSet (unionFind egr)++    -- New empty e-class stores just the analysis data+    new_eclass = EClass new_eclass_id S.empty adata mempty+   in ( new_eclass_id+      , egr { unionFind = new_uf+            , classes   = IM.insert new_eclass_id new_eclass (classes egr)+            }+      )+{-# INLINE newEClass #-}++----- Monadic operations on e-graphs+-- Unfortunately, these cannot be defined in terms of the primary ones.+-- This could almost be done by defining the domain of the standard Analysis to+-- be (m a), for some Monad m, but this would require an instance Eq (m a),+-- which often won't exist.+--+-- Anyway, this allows us to have a better story for monadic analysis because+-- the type-class functions arguments don't need to be of the same monadic type+-- as the result (unlike if we were using a normal analysis with a monadic domain).+--+-- Be sure to update these functions if the above "canonical" versions are changed.++-- TODO: Move these to new module?++-- * E-graph operations for analysis defined monadically ('AM.AnalysisM')++-- | Like 'represent', but for a monadic analysis+representM :: forall a l m. (AM.AnalysisM m a l, Language l) => Fix l -> EGraph a l -> m (ClassId, EGraph a l)+representM = cata $ \l e -> do+  -- Canonical implementation is represent, this is just the monadic variant of it+  (l', e') <- (`runStateT` e) $ traverse (\f -> get >>= lift . f >>= StateT . const . pure) l+  addM (Node l') e'++-- | Like 'add', but for a monadic analysis+addM :: forall a l m. (AM.AnalysisM m a l, Language l) => ENode l -> EGraph a l -> m (ClassId, EGraph a l)+addM uncanon_e egr =+  -- Canonical implementation is add, this is just the monadic variant of it+    let !new_en = canonicalize uncanon_e egr++     in case lookupNM new_en (memo egr) of+      Just canon_enode_id -> pure (find canon_enode_id egr, egr)+      Nothing -> do+        let+            (new_eclass_id, new_uf) = makeNewSet (unionFind egr)++        new_data <- AM.makeA @m @a ((\i -> egr^._class i._data @a) <$> unNode new_en)++        let+            new_eclass   =  EClass new_eclass_id (S.singleton new_en) new_data mempty+            new_parents  = ((new_eclass_id, new_en) |:)+            new_classes  = IM.insert new_eclass_id new_eclass $+                                foldr  (IM.adjust (_parents %~ new_parents))+                                       (classes egr)+                                       (unNode new_en)++            new_worklist = (new_eclass_id, new_en):worklist egr++            new_memo     = insertNM new_en new_eclass_id (memo egr)++        egr1 <- egr { unionFind = new_uf+                    , classes   = new_classes+                    , worklist  = new_worklist+                    , memo      = new_memo+                    }+                    & AM.modifyA new_eclass_id++        return ( new_eclass_id, egr1 )+{-# INLINABLE addM #-}++-- | Like 'merge', but for a monadic analysis+mergeM :: forall a l m. (AM.AnalysisM m a l, Language l) => ClassId -> ClassId -> EGraph a l -> m (ClassId, EGraph a l)+mergeM a b egr0 = do+  -- Canonical implementation is merge, this is just the monadic variant of it+  let+      a' = find a egr0+      b' = find b egr0+   in+   if a' == b'+     then return (a', egr0)+     else do+       let+           class_a = egr0 ^._class a'+           class_b = egr0 ^._class b'++           (leader, leader_class, sub, sub_class) =+               if sizeSL (class_a^._parents) < sizeSL (class_b^._parents)+                  then (b', class_b, a', class_a) -- b is leader+                  else (a', class_a, b', class_b) -- a is leader++           (new_id, new_uf) = unionSets leader sub (unionFind egr0)+                                & first (\n -> assert (leader == n) n)++       new_data <- AM.joinA @m @a @l (leader_class^._data) (sub_class^._data)++       let+           updatedLeader = leader_class+                             & _parents %~ (sub_class^._parents <>)+                             & _nodes   %~ (sub_class^._nodes <>)+                             & _data    .~ new_data++           new_classes = (IM.insert leader updatedLeader . IM.delete sub) (classes egr0)++           -- Add all subsumed parents to worklist We can do this instead of+           -- adding the new e-class itself to the worklist because it would end+           -- up adding its parents anyway+           new_worklist = toListSL (sub_class^._parents) <> worklist egr0++           -- If the new_data is different from the classes, the parents of the+           -- class whose data is different from the merged must be put on the+           -- analysisWorklist+           new_analysis_worklist =+             (if new_data /= (sub_class^._data)+                then toListSL (sub_class^._parents)+                else mempty) <>+             (if new_data /= (leader_class^._data)+                then toListSL (leader_class^._parents)+                else mempty) <>+             analysisWorklist egr0++       -- ROMES:TODO: The code that makes the -1 * cos test pass when some other things are tweaked+       -- new_memo = foldr (`insertNM` leader) (memo egr0) (sub_class^._nodes)++       -- Build new e-graph+       egr1 <- egr0 { unionFind = new_uf+                    , classes   = new_classes+                    -- , memo      = new_memo+                    , worklist  = new_worklist+                    , analysisWorklist = new_analysis_worklist+                    }+                    & AM.modifyA new_id++       return (new_id, egr1)+{-# INLINEABLE mergeM #-}++-- | Like 'rebuild', but for a monadic analysis+rebuildM :: forall a l m. (AM.AnalysisM m a l, Language l) => EGraph a l -> m (EGraph a l)+rebuildM (EGraph uf cls mm wl awl) = do+  -- Canonical implementation is rebuild, this is just the monadic variant of it+  let+    emptiedEgr = EGraph uf cls mm mempty mempty++    wl' = nubOrd $ bimap (`find` emptiedEgr) (`canonicalize` emptiedEgr) <$> wl++  egr'  <- foldlM (flip repairM) emptiedEgr wl'++  let awl' = nubIntOn fst $ first (`find` egr') <$> awl++  egr'' <- foldlM (flip repairAnalM) egr' awl'++  if null (worklist egr'') && null (analysisWorklist egr'')+     then return egr''+     else rebuildM egr''+{-# INLINEABLE rebuildM #-}++-- | Like 'repair', but for a monadic analysis+repairM :: forall a l m. (AM.AnalysisM m a l, Language l) => (ClassId, ENode l) -> EGraph a l -> m (EGraph a l)+repairM (repair_id, node) egr =+  -- Canonical implementation is repair, this is just the monadic variant of it+   case insertLookupNM node repair_id (memo egr) of++      (Nothing, memo') -> return $ egr { memo = memo' }++      (Just existing_class, memo') -> snd <$> (mergeM existing_class repair_id egr{memo = memo'})+{-# INLINE repairM #-}++-- | Like 'repairAnal', but for a monadic analysis+repairAnalM :: forall a l m. (AM.AnalysisM m a l, Language l) => (ClassId, ENode l) -> EGraph a l -> m (EGraph a l)+repairAnalM (repair_id, node) egr = do+  -- Canonical implementation is repairAnal, this is just the monadic variant of it+    let c = egr^._class repair_id++    new_data <- AM.joinA @m @a @l (c^._data) =<< AM.makeA @m @a ((\i -> egr^._class i^._data @a) <$> unNode node)++    if c^._data /= new_data+       then+         egr { analysisWorklist = toListSL (c^._parents) <> analysisWorklist egr+             , classes = IM.adjust (_data .~ new_data) repair_id (classes egr)+             }+             & AM.modifyA repair_id+       else+        return egr+{-# INLINE repairAnalM #-}
src/Data/Equality/Graph/Dot.hs view
@@ -23,22 +23,21 @@ import Data.GraphViz.Attributes (style, dotted, textLabel) import Data.GraphViz.Attributes.Complete -import Data.Equality.Saturation import Data.Equality.Graph-import Data.Equality.Matching-import Database+import Data.Equality.Graph.Internal +txt :: Show a => a -> Text txt = pack . show -writeDemo :: (Functor f, Foldable f, Show (ENode f)) => EGraph f -> IO ()+writeDemo :: (Language language, Show (ENode language)) => EGraph analysis language -> IO () writeDemo = writeDotFile "demo.gv" . toDotGraph -toDotGraph :: (Functor f, Foldable f, Show (ENode f)) => EGraph f -> DotGraph Text+toDotGraph :: (Language language, Show (ENode language)) => EGraph analysis language -> DotGraph Text toDotGraph eg = digraph (Str "egraph") $ do      graphAttrs [Compound True, ClusterRank Local] -    forM_ (IM.toList $ classes eg) $ \(class_id, EClass _ nodes parents) ->+    forM_ (IM.toList $ classes eg) $ \(class_id, EClass _ nodes _ _) ->          subgraph (Str ("cluster_" <> txt class_id)) $ do             graphAttrs [style dotted]@@ -46,17 +45,16 @@                 let n' = canonicalize n eg                 node (txt class_id <> "." <> txt (find i eg)) [textLabel (txt n')] -    forM_ (IM.toList $ classes eg) $ \(class_id, EClass _ nodes parents) -> do+    forM_ (IM.toList $ classes eg) $ \(class_id, EClass _ nodes _ _) -> do          forM_ (zip (S.toList nodes) [0..]) $ \(n, i_in_class) -> do              let n' = canonicalize n eg             let i_in_class' = find i_in_class eg -            forM_ (zip (children n') [0..]) $ \(child, arg_i) -> do+            forM_ (zip (children n') [(0 :: Integer)..]) $ \(child, arg_i) -> do                 -- TODO: On anchors and labels...?                 let child_leader = find child eg                 if child_leader == class_id-                   then edge (txt class_id <> "." <> txt i_in_class') (txt class_id <> "." <> txt i_in_class') [textLabel (txt arg_i)] -- LHead ("cluster_" <> txt class_id), +                   then edge (txt class_id <> "." <> txt i_in_class') (txt class_id <> "." <> txt i_in_class') [textLabel (txt arg_i)] -- LHead ("cluster_" <> txt class_id),                    else edge (txt class_id <> "." <> txt i_in_class') (txt child <> ".0") [LHead ("cluster_" <> txt child_leader), textLabel (txt arg_i)]-    
src/Data/Equality/Graph/Lens.hs view
@@ -22,8 +22,11 @@ import Data.Equality.Graph.Classes import Data.Equality.Graph.ReprUnionFind --- | A 'Lens'' as defined in other lenses libraries+-- | A 'Lens'' as defined in lens type Lens' s a = forall f. Functor f => (a -> f a) -> (s -> f s)+-- | A 'Lens' as defined in lens+type Lens s t a b = forall f. Functor f => (a -> f b) -> (s -> f t)+-- | A 'Traversal' as defined in lens type Traversal s t a b = forall f. Applicative f => (a -> f b) -> (s -> f t)  -- outdated comment for "getClass":@@ -36,7 +39,7 @@ -- -- Invariant: The e-class exists. --- | Lens for the e-class with the given id in an e-graph+-- | Lens for the e-class at the representative of the given id in an e-graph -- -- Calls 'error' when the e-class doesn't exist _class :: ClassId -> Lens' (EGraph a l) (EClass a l)@@ -62,8 +65,8 @@ {-# INLINE _iclasses #-}  -- | Lens for the 'Domain' of an e-class-_data :: Lens' (EClass domain l) domain-_data afa EClass{..} = (\d1 -> EClass eClassId eClassNodes d1 eClassParents) <$> afa eClassData+_data :: Lens (EClass domain l) (EClass domain' l) domain domain'+_data afb EClass{..} = (\d1 -> EClass eClassId eClassNodes d1 eClassParents) <$> afb eClassData {-# INLINE _data #-}  -- | Lens for the parent e-classes of an e-class@@ -89,7 +92,7 @@ {-# INLINE (.~) #-}  -- | Synonym for @'over'@-(%~) :: Lens' s a -> (a -> a) -> (s -> s)+(%~) :: ASetter s t a b -> (a -> b) -> (s -> t) (%~) = over infixr 4 %~ {-# INLINE (%~) #-}@@ -105,13 +108,27 @@ {-# INLINE set #-}  -- | Applies a function to the target-over :: Lens' s a -> (a -> a) -> (s -> s)+over :: ASetter s t a b -> (a -> b) -> (s -> t) over ln f = runIdentity . ln (Identity . f) {-# INLINE over #-} +-- | Basically 'traverse' over a 'Traversal'+traverseOf :: Traversal s t a b -> forall f. Applicative f => (a -> f b) -> s -> f t +traverseOf t = t+{-# INLINE traverseOf #-}+ -- | Returns True if every target of a Traversable satisfies a predicate. allOf :: Traversal s t a b -> (a -> Bool) -> s -> Bool allOf trv f = getAll . getConst . trv (Const . All . f) {-# INLINE allOf #-} +-- * Utilities +-- We need to use 'ASetter' instead of 'Lens' in %~ to ensure type inference can+-- figure out the Functor or Applicative is 'Identity'. Otherwise, we won't be+-- able to use the 'Traversal' to modify something through a 'Lens'.++-- | Used instead of 'Lens' in 'over' and '%~' to ensure one can call those+-- combinators on 'Lens's and 'Traversal's. Essentially, it helps type+-- inference in such function applications+type ASetter s t a b = (a -> Identity b) -> s -> Identity t
src/Data/Equality/Graph/Monad.hs view
@@ -4,7 +4,12 @@    Monadic interface to e-graph stateful computations  -} module Data.Equality.Graph.Monad-  ( egraph+  (+    -- * Threading e-graphs in a stateful computation+    --+    -- | These are the same operations over e-graphs as in 'Data.Equality.Graph',+    -- but defined in the context of a 'State' monad threading around the e-graph.+    egraph   , represent   , add   , merge@@ -13,9 +18,17 @@   , EG.find   , EG.emptyEGraph +    -- * E-graph transformations for monadic analysis+    --+    -- | The same e-graph operations in a stateful computation threading around+    -- the e-graph, but for 'Analysis' defined monadically ('AnalysisM').+  , representM, addM, mergeM, rebuildM+   -- * E-graph stateful computations   , EGraphM+  , EGraphMT   , runEGraphM+  , runEGraphMT    -- * E-graph definition re-export   , EG.EGraph@@ -30,11 +43,14 @@ import Data.Equality.Utils (Fix, cata)  import Data.Equality.Analysis+import qualified Data.Equality.Analysis.Monadic as AM import Data.Equality.Graph (EGraph, ClassId, Language, ENode(..)) import qualified Data.Equality.Graph as EG  -- | E-graph stateful computation type EGraphM a l = State (EGraph a l)+-- | E-graph stateful computation over an arbitrary monad+type EGraphMT a l = StateT (EGraph a l)  -- | Run EGraph computation on an empty e-graph --@@ -84,3 +100,30 @@ runEGraphM = flip runState {-# INLINE runEGraphM #-} +--------------------------------------------------------------------------------+-- Monadic Analysis interface++-- | Run 'EGraphM' computation on a given e-graph over a monadic analysis+runEGraphMT :: EGraph anl l -> EGraphMT anl l m a -> m (a, EGraph anl l)+runEGraphMT = flip runStateT+{-# INLINE runEGraphMT #-}++-- | Like 'represent', but for a monadic analysis+representM :: (AM.AnalysisM m anl l, Language l) => Fix l -> EGraphMT anl l m ClassId+representM = StateT . EG.representM+{-# INLINE representM #-}++-- | Like 'add', but for a monadic analysis+addM :: (AM.AnalysisM m anl l, Language l) => ENode l -> EGraphMT anl l m ClassId+addM = StateT . EG.addM+{-# INLINE addM #-}++-- | Like 'merge', but for a monadic analysis+mergeM :: (AM.AnalysisM m anl l, Language l) => ClassId -> ClassId -> EGraphMT anl l m ClassId+mergeM a b = StateT (EG.mergeM a b)+{-# INLINE mergeM #-}++-- | Like 'rebuild', but for a monadic analysis+rebuildM :: (AM.AnalysisM m anl l, Language l) => EGraphMT anl l m ()+rebuildM = StateT (fmap ((),) . EG.rebuildM)+{-# INLINE rebuildM #-}
src/Data/Equality/Matching/Database.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE CPP #-} {-|    Custom database implemented with trie-maps specialized to run conjunctive    queries using a (worst-case optimal) generic join algorithm.@@ -31,6 +32,9 @@ import Data.Maybe (mapMaybe) import Control.Monad +#if MIN_VERSION_base(4,20,0)+import Data.Foldable as F (toList, length)+#endif import Data.Foldable as F (toList, foldl', length) import qualified Data.Map.Strict    as M import qualified Data.IntMap.Strict as IM
src/Data/Equality/Saturation.hs view
@@ -123,7 +123,7 @@       -- Read-only phase, invariants are preserved       -- With backoff scheduler       -- ROMES:TODO parMap with chunks-      let (!matches, newStats) = mconcat (fmap (matchWithScheduler db i stats) (zip [1..] rewrites))+      let (!matches, newStats) = mconcat (fmap (\(rw_id,rw) -> first (map (rw,)) $ matchWithScheduler db i stats rw_id rw) (zip [1..] rewrites))        -- Write-only phase, temporarily break invariants       forM_ matches applyMatchesRhs@@ -141,10 +141,10 @@                 && IM.size afterClasses == IM.size beforeClasses)           (runEqualitySaturation' (i+1) newStats) -  matchWithScheduler :: Database l -> Int -> IM.IntMap (Stat schd) -> (Int, Rewrite a l) -> ([(Rewrite a l, Match)], IM.IntMap (Stat schd))-  matchWithScheduler db i stats = \case-      (rw_id, rw :| cnd) -> first (map (first (:| cnd))) $ matchWithScheduler db i stats (rw_id, rw)-      (rw_id, lhs := rhs) -> do+  matchWithScheduler :: Database l -> Int -> IM.IntMap (Stat schd) -> Int -> Rewrite a l -> ([Match], IM.IntMap (Stat schd))+  matchWithScheduler db i stats rw_id = \case+      rw  :| _ -> matchWithScheduler db i stats rw_id rw+      lhs := _ -> do           case IM.lookup rw_id stats of             -- If it's banned until some iteration, don't match this rule             -- against anything.@@ -159,7 +159,7 @@                 -- Backoff scheduler: update stats                 let newStats = updateStats schd i rw_id x stats matches' -                (map (lhs := rhs,) matches', newStats)+                (matches', newStats)    applyMatchesRhs :: (Rewrite a l, Match) -> EGraphM a l ()   applyMatchesRhs =
src/Data/Equality/Utils.hs view
@@ -1,11 +1,14 @@-{-# LANGUAGE UnicodeSyntax, RankNTypes, QuantifiedConstraints, UndecidableInstances #-}+{-# LANGUAGE UnicodeSyntax, RankNTypes, QuantifiedConstraints, UndecidableInstances, CPP #-} {-|  Misc utilities used accross modules  -} module Data.Equality.Utils where  -- import GHC.Conc+#if MIN_VERSION_base(4,20,0)+#else import Data.Foldable+#endif import Data.Bits  -- import qualified Data.Set    as S
test/Bench.hs view
@@ -1,18 +1,43 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StandaloneDeriving, FlexibleInstances, DeriveAnyClass, RankNTypes, QuantifiedConstraints, UndecidableInstances, DeriveGeneric #-} import Test.Tasty.Bench +import GHC.Generics+import Control.DeepSeq+ import Data.Equality.Utils import Invariants import Sym-import Lambda-import SimpleSym +-- Instances for benchmarking. It's amazing this works!+deriving instance (forall a. Generic a => Generic (f a)) => Generic (Fix f)+deriving instance NFData UOp+deriving instance NFData BOp+deriving instance NFData a => NFData (Expr a)+deriving instance (forall a. NFData a => NFData (f a), forall a. Generic a => Generic (f a)) => NFData (Fix f)+ tests :: [Benchmark] tests = [ bgroup "Tests"-  [ symTests-  , lambdaTests-  , simpleSymTests-  , invariants+  [ bgroup "Symbolic bench"+    [ bench "i1" $+        nf rewrite (Fix $ BinOp Integral 1 "x")++    , bench "i2" $+        nf rewrite (Fix $ BinOp Integral (Fix $ UnOp Cos "x") "x")++    , bench "i3" $+        nf rewrite (Fix $ BinOp Integral (Fix $ BinOp Pow "x" 1) "x")++    , bench "i4" $+        nf rewrite (_i ((*) "x" (_cos "x")) "x")++    , bench "i5" $+        nf rewrite (_i ((*) (_cos "x") "x") "x")++    , bench "i6" $+        nf rewrite (_i (_ln "x") "x")+    ]+  -- , invariants   ] ]  main :: IO ()
test/Invariants.hs view
@@ -68,7 +68,6 @@                            | _:xs <- queryHeadVars q ->                                L.sort xs == L.sort (vars p)                                  && length atoms == numNonVarPatterns p-                         _ -> error "impossible! testCompileToQuery"     where         numNonVarPatterns :: Foldable lang => Pattern lang -> Int         numNonVarPatterns (VariablePattern _) = 0
test/Lambda.hs view
@@ -73,14 +73,16 @@ instance Analysis (Maybe (Lambda ())) Lambda where   makeA = evalL   joinA = (<|>)-  modifyA c = case c^._data of-                Nothing -> (c, [])-                Just v  -> (c, [f v])-                  where-                    f = \case-                      Bool b -> Fix $ Bool b-                      Num i  -> Fix $ Num i-                      _ -> error "impossible, lambda () can't construct this"+  modifyA c eg+    = case eg^._class c._data of+        Nothing -> eg+        Just v  -> let (c', eg') = represent (f v) eg+                    in snd $ merge c c' eg'+          where+            f = \case+              Bool b -> Fix $ Bool b+              Num i  -> Fix $ Num i+              _ -> error "impossible, lambda () can't construct this"                         -- Free variable analysis for lambda
test/SimpleSym.hs view
@@ -13,7 +13,8 @@ import Data.Equality.Matching import Data.Equality.Saturation import Data.Equality.Analysis-import Data.Equality.Graph.Lens ((^.), _data)+import Data.Equality.Graph+import Data.Equality.Graph.Lens  data SymExpr a = Const Double                | Symbol String@@ -37,9 +38,12 @@   joinA Nothing Nothing  = Nothing   joinA (Just x) (Just y) = if x == y then Just x else error "ouch, that shouldn't have happened" -  modifyA c = case c^._data of-                Nothing -> (c, [])-                Just i  -> (c, [Fix (Const i)])+  modifyA c eg+    = case eg^._class c._data of+        Nothing -> eg+        Just i  ->+          let (c', eg') = represent (Fix (Const i)) eg+           in snd $ merge c c' eg'  cost :: CostFunction SymExpr Int cost = \case
test/Sym.hs view
@@ -6,8 +6,11 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE CPP #-} module Sym where +import GHC.Generics import Test.Tasty import Test.Tasty.HUnit @@ -18,9 +21,13 @@  import qualified Data.Foldable as F +#if MIN_VERSION_base(4,18,0)+#else import Control.Applicative (liftA2)+#endif import Control.Monad (unless) +import Data.Function ((&)) import Data.Equality.Graph.Lens import Data.Equality.Graph import Data.Equality.Extraction@@ -35,6 +42,7 @@             | BinOp !BOp !a !a             deriving ( Eq, Ord, Show                      , Functor, Foldable, Traversable+                     , Generic                      ) data BOp = Add          | Sub@@ -43,13 +51,13 @@          | Pow          | Diff          | Integral-        deriving (Eq, Ord, Show)+        deriving (Eq, Ord, Show, Generic)  data UOp = Sin          | Cos          | Sqrt          | Ln-         deriving (Eq, Ord, Show)+         deriving (Eq, Ord, Show, Generic)  instance IsString (Fix Expr) where     fromString = Fix . Sym@@ -112,17 +120,15 @@         !_ <- unless (a == b || (a == 0 && b == (-0)) || (a == (-0) && b == 0)) (error "Merged non-equal constants!")         return a -    modifyA cl = case cl^._data of-                 Nothing -> (cl, [])-                 Just d -> ((_nodes %~ S.filter (F.null .unNode)) cl, [Fix (Const d)])--    --         -- Add constant as e-node-    --         new_c <- represent (Fix $ Const d)-    --         _     <- GM.merge i new_c--    --         -- Prune all except leaf e-nodes-    --         modify (_class i._nodes %~ S.filter (F.null . unNode))-+    modifyA cl eg0+      = case eg0^._class cl._data of+          Nothing -> eg0+          Just d  ->+                -- Add constant as e-node+            let (new_c,eg1) = represent (Fix (Const d)) eg0+                (rep, eg2)  = merge cl new_c eg1+                -- Prune all except leaf e-nodes+             in eg2 & _class rep._nodes %~ S.filter (F.null .unNode)   evalConstant :: Expr (Maybe Double) -> Maybe Double
+ test/T3.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+module T3 where++-- Some e-graph unit tests++import Prelude hiding (not)++-- import Test.Tasty.HUnit+import Data.Equality.Graph+import Data.Equality.Utils+import qualified Data.Equality.Graph.Monad as EGM++data Lang a = And a a+            | Or a a+            | Not a+            | ToElim a+            | Sym Int+            deriving (Functor, Foldable, Traversable, Eq, Ord, Show)++main :: IO ()+main = do+  let _ = EGM.egraph @Lang @() $ do+        id1 <- EGM.represent (Fix (Sym 1))+        id2 <- EGM.represent (Fix (Not (Fix (Not (Fix (Sym 1))))))+        id3 <- EGM.represent (Fix (Sym 2))+        a1  <- EGM.add (Node (And id3 id1))+        a2  <- EGM.add (Node (And id3 id2))+        _ <- EGM.merge a1 a2+        EGM.rebuild -- even rebuilding this fails...+        return (id1,id2)++  -- The children should now be in the same e-class?+  --+  -- Turns out, they don't. So this test should actually be the other way+  -- around (we do not learn s1 ~= s2 from merging a1 and a2)+  --+  -- A counter example:+  -- Consider `f` that returns its second argument (f _ x = x):+  -- so f(a,c) = f(b,c), but a != b+  --+  -- find s1 eg @=? find s2 eg++  return ()+
test/Test.hs view
@@ -13,6 +13,7 @@  import qualified T1 import qualified T2+import qualified T3  tests :: TestTree tests = testGroup "Tests"@@ -22,6 +23,7 @@   , invariants   , testCase "T1" (T1.main `catch` (\(e :: SomeException) -> assertFailure (show e)))   , testCase "T2" (T2.main `catch` (\(e :: SomeException) -> assertFailure (show e)))+  , testCase "T3" (T3.main `catch` (\(e :: SomeException) -> assertFailure (show e)))   ]  main :: IO ()