mappings 0.3.3.0 → 0.4.0.0
raw patch · 11 files changed
+1412/−1071 lines, 11 filesdep +transformersdep +trivial-constraintdep ~basedep ~containersPVP ok
version bump matches the API change (PVP)
Dependencies added: transformers, trivial-constraint
Dependency ranges changed: base, containers
API changes (from Hackage documentation)
- Data.Bijection: Bij :: IntMap Int -> IntMap Int -> Bij
- Data.Bijection: MaybeBij :: Maybe Bij -> MaybeBij
- Data.Bijection: [getMaybeBij] :: MaybeBij -> Maybe Bij
- Data.Bijection: [leftwards] :: Bij -> IntMap Int
- Data.Bijection: [rightwards] :: Bij -> IntMap Int
- Data.Bijection: closeBijection :: (Int -> Int -> Maybe Bij) -> Bij -> Maybe Bij
- Data.Bijection: combine :: Bij -> Bij -> Maybe Bij
- Data.Bijection: compatibleInsert :: Eq a => Int -> a -> IntMap a -> Maybe (IntMap a)
- Data.Bijection: compatibleUnion :: Eq a => IntMap a -> IntMap a -> Maybe (IntMap a)
- Data.Bijection: data Bij
- Data.Bijection: empty :: Bij
- Data.Bijection: instance GHC.Base.Monoid Data.Bijection.MaybeBij
- Data.Bijection: instance GHC.Base.Semigroup Data.Bijection.MaybeBij
- Data.Bijection: instance GHC.Classes.Eq Data.Bijection.Bij
- Data.Bijection: instance GHC.Classes.Eq Data.Bijection.MaybeBij
- Data.Bijection: instance GHC.Classes.Ord Data.Bijection.Bij
- Data.Bijection: instance GHC.Classes.Ord Data.Bijection.MaybeBij
- Data.Bijection: match :: Int -> Int -> Bij -> Maybe Bij
- Data.Bijection: msingleton :: Int -> Int -> MaybeBij
- Data.Bijection: newtype MaybeBij
- Data.Bijection: pop :: Bij -> Maybe ((Int, Int), Bij)
- Data.Bijection: singleton :: Int -> Int -> Bij
- Data.Bijection: unsafeDifference :: Bij -> Bij -> Bij
- Data.Bijection: unsafeUnion :: Bij -> Bij -> Bij
- Data.Mapping: instance (Data.Mapping.Mapping k m, Data.Mapping.Mapping l n) => Data.Mapping.Mapping (Data.Either.Either k l) (Data.Mapping.OnEither k l m n)
- Data.Mapping: instance (Data.Mapping.Mapping k m, Data.Mapping.Mapping l n, GHC.Classes.Ord a, Data.Algebra.Boolean.Boolean a) => Data.Algebra.Boolean.Boolean (Data.Mapping.OnEither k l m n a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, Data.Mapping.Mapping l n, GHC.Classes.Ord a, GHC.Base.Monoid a) => GHC.Base.Monoid (Data.Mapping.OnEither k l m n a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, Data.Mapping.Mapping l n, GHC.Classes.Ord a, GHC.Base.Monoid a, forall v. GHC.Classes.Ord v => GHC.Classes.Ord (n v)) => GHC.Base.Monoid (Data.Mapping.OnPair k l m n a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, Data.Mapping.Mapping l n, GHC.Classes.Ord a, GHC.Base.Semigroup a) => GHC.Base.Semigroup (Data.Mapping.OnEither k l m n a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, Data.Mapping.Mapping l n, GHC.Classes.Ord a, GHC.Base.Semigroup a, forall v. GHC.Classes.Ord v => GHC.Classes.Ord (n v)) => GHC.Base.Semigroup (Data.Mapping.OnPair k l m n a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, Data.Mapping.Mapping l n, GHC.Classes.Ord a, GHC.Num.Num a) => GHC.Num.Num (Data.Mapping.OnEither k l m n a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, Data.Mapping.Mapping l n, GHC.Classes.Ord a, GHC.Num.Num a, forall v. GHC.Classes.Ord v => GHC.Classes.Ord (n v)) => GHC.Num.Num (Data.Mapping.OnPair k l m n a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, Data.Mapping.Mapping l n, GHC.Classes.Ord b, Data.Algebra.Boolean.Boolean b, forall v. GHC.Classes.Ord v => GHC.Classes.Ord (n v)) => Data.Algebra.Boolean.Boolean (Data.Mapping.OnPair k l m n b)
- Data.Mapping: instance (Data.Mapping.Mapping k m, Data.Mapping.Mapping l n, forall v. GHC.Classes.Ord v => GHC.Classes.Ord (n v)) => Data.Mapping.Mapping (k, l) (Data.Mapping.OnPair k l m n)
- Data.Mapping: instance (Data.Mapping.Mapping k m, Data.PartialOrd.PartialOrd v) => Data.PartialOrd.PartialOrd (Data.Mapping.PartialOrdWrapper k m v)
- Data.Mapping: instance (Data.Mapping.Mapping k m, GHC.Classes.Ord a, Data.Algebra.Boolean.Boolean a) => Data.Algebra.Boolean.Boolean (Data.Mapping.AlgebraWrapper k m a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, GHC.Classes.Ord a, Data.Algebra.Boolean.Boolean a) => Data.Algebra.Boolean.Boolean (Data.Mapping.OnMaybe k m a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, GHC.Classes.Ord a, GHC.Base.Monoid a) => GHC.Base.Monoid (Data.Mapping.AlgebraWrapper k m a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, GHC.Classes.Ord a, GHC.Base.Monoid a) => GHC.Base.Monoid (Data.Mapping.OnMaybe k m a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, GHC.Classes.Ord a, GHC.Base.Semigroup a) => GHC.Base.Semigroup (Data.Mapping.AlgebraWrapper k m a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, GHC.Classes.Ord a, GHC.Base.Semigroup a) => GHC.Base.Semigroup (Data.Mapping.OnMaybe k m a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, GHC.Classes.Ord a, GHC.Num.Num a) => GHC.Num.Num (Data.Mapping.AlgebraWrapper k m a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, GHC.Classes.Ord a, GHC.Num.Num a) => GHC.Num.Num (Data.Mapping.OnMaybe k m a)
- Data.Mapping: instance (Data.Mapping.Mapping k m, GHC.Classes.Ord v) => Data.PartialOrd.PartialOrd (Data.Mapping.OrdWrapper k m v)
- Data.Mapping: instance (GHC.Classes.Ord a, GHC.Base.Monoid a) => GHC.Base.Monoid (Data.Mapping.OnBool a)
- Data.Mapping: instance (GHC.Classes.Ord a, GHC.Base.Semigroup a) => GHC.Base.Semigroup (Data.Mapping.OnBool a)
- Data.Mapping: instance (GHC.Classes.Ord a, GHC.Num.Num a) => GHC.Num.Num (Data.Mapping.OnBool a)
- Data.Mapping: instance (GHC.Classes.Ord b, Data.Algebra.Boolean.Boolean b) => Data.Algebra.Boolean.Boolean (Data.Mapping.OnBool b)
- Data.Mapping: instance (WithIndex.FoldableWithIndex k m, WithIndex.FoldableWithIndex l n) => WithIndex.FoldableWithIndex (Data.Either.Either k l) (Data.Mapping.OnEither k l m n)
- Data.Mapping: instance Data.Mapping.Mapping GHC.Types.Bool Data.Mapping.OnBool
- Data.Mapping: instance Data.Mapping.Mapping k (Data.Mapping.Constant k)
- Data.Mapping: instance Data.Mapping.Mapping k m => Data.Mapping.Mapping (GHC.Maybe.Maybe k) (Data.Mapping.OnMaybe k m)
- Data.Mapping: instance WithIndex.FoldableWithIndex k m => WithIndex.FoldableWithIndex (GHC.Maybe.Maybe k) (Data.Mapping.OnMaybe k m)
- Data.Mapping: instance forall k1 (k2 :: k1) k3 (l :: k3) k4 (m :: k4 -> *) (n :: k4 -> *) (v :: k4). (GHC.Classes.Eq (m v), GHC.Classes.Eq (n v)) => GHC.Classes.Eq (Data.Mapping.OnEither k2 l m n v)
- Data.Mapping: instance forall k1 (k2 :: k1) k3 (l :: k3) k4 (m :: k4 -> *) (n :: k4 -> *) (v :: k4). (GHC.Classes.Ord (m v), GHC.Classes.Ord (n v)) => GHC.Classes.Ord (Data.Mapping.OnEither k2 l m n v)
- Data.Mapping: instance forall k1 (k2 :: k1) k3 (l :: k3) k4 (m :: k4 -> *) k5 (n :: k5 -> k4) (v :: k5). GHC.Classes.Eq (m (n v)) => GHC.Classes.Eq (Data.Mapping.OnPair k2 l m n v)
- Data.Mapping: instance forall k1 (k2 :: k1) k3 (l :: k3) k4 (m :: k4 -> *) k5 (n :: k5 -> k4) (v :: k5). GHC.Classes.Ord (m (n v)) => GHC.Classes.Ord (Data.Mapping.OnPair k2 l m n v)
- Data.Mapping: instance forall k1 (m :: * -> *) (k2 :: k1). Data.Foldable.Foldable m => Data.Foldable.Foldable (Data.Mapping.OnMaybe k2 m)
- Data.Mapping: instance forall k1 k2 (m :: * -> *) (n :: * -> *) (k3 :: k1) (l :: k2). (Data.Foldable.Foldable m, Data.Foldable.Foldable n) => Data.Foldable.Foldable (Data.Mapping.OnEither k3 l m n)
- Data.Mapping: instance forall k1 k2 (m :: * -> *) (n :: * -> *) (k3 :: k1) (l :: k2). (Data.Foldable.Foldable m, Data.Foldable.Foldable n) => Data.Foldable.Foldable (Data.Mapping.OnPair k3 l m n)
- Data.Mapping.Decision: Base :: Seq v -> Seq (Node k1 m a) -> Base (k1 :: k) (m :: Type -> Type) a v
- Data.Mapping.Decision: BaseMap :: Seq v -> Seq v -> BaseMap v
- Data.Mapping.Decision: Builder :: Map v Int -> Map (Node k1 m a) Int -> Map o Int -> Builder o (k1 :: k) (m :: Type -> Type) a v
- Data.Mapping.Decision: Node :: !a -> !m Int -> Node (k1 :: k) (m :: Type -> Type) a
- Data.Mapping.Decision: [base] :: Decision (k1 :: k) (m :: Type -> Type) a v -> !Base k1 m a v
- Data.Mapping.Decision: [fromOld] :: Builder o (k1 :: k) (m :: Type -> Type) a v -> Map o Int
- Data.Mapping.Decision: [leavesMap] :: Builder o (k1 :: k) (m :: Type -> Type) a v -> Map v Int
- Data.Mapping.Decision: [leaves] :: Base (k1 :: k) (m :: Type -> Type) a v -> Seq v
- Data.Mapping.Decision: [nodeBranch] :: Node (k1 :: k) (m :: Type -> Type) a -> !m Int
- Data.Mapping.Decision: [nodeDecision] :: Node (k1 :: k) (m :: Type -> Type) a -> !a
- Data.Mapping.Decision: [nodesMap] :: Builder o (k1 :: k) (m :: Type -> Type) a v -> Map (Node k1 m a) Int
- Data.Mapping.Decision: [nodes] :: Base (k1 :: k) (m :: Type -> Type) a v -> Seq (Node k1 m a)
- Data.Mapping.Decision: [onLeaves] :: BaseMap v -> Seq v
- Data.Mapping.Decision: [onNodes] :: BaseMap v -> Seq v
- Data.Mapping.Decision: [start] :: Decision (k1 :: k) (m :: Type -> Type) a v -> !Int
- Data.Mapping.Decision: addLeaf :: forall {k1} o v (k2 :: k1) (m :: Type -> Type) a. (Ord o, Ord v) => v -> o -> Builder o k2 m a v -> Builder o k2 m a v
- Data.Mapping.Decision: addNode :: (Ord o, Ord (m Int), Ord a, Mapping k m) => a -> m o -> o -> Builder o k m a v -> Builder o k m a v
- Data.Mapping.Decision: baseGenMerge :: forall {k1} {k2} a w o l u v m n (h :: k1) (k3 :: k2). (Ord a, Ord w, Ord (o Int), Mapping l o) => (u -> v -> w) -> (forall x. Ord x => a -> m x -> o x) -> (forall y. Ord y => a -> n y -> o y) -> (forall x y. (Ord x, Ord y) => a -> m x -> n y -> o (x, y)) -> Base h m a u -> Base k3 n a v -> Set (Int, Int) -> Builder (Int, Int) l o a w
- Data.Mapping.Decision: baseLength :: forall {k1} (k2 :: k1) (m :: Type -> Type) a v. Base k2 m a v -> Int
- Data.Mapping.Decision: baseMap :: forall a (m :: Type -> Type) w k v. (Ord a, Ord (m Int), Ord w, Mapping k m) => (v -> w) -> Base k m a v -> Builder Int k m a w
- Data.Mapping.Decision: baseMerge :: forall a w (m :: Type -> Type) k u v. (Ord a, Ord w, Ord (m Int), Mapping k m) => (u -> v -> w) -> Base k m a u -> Base k m a v -> Set (Int, Int) -> Builder (Int, Int) k m a w
- Data.Mapping.Decision: baseMergeA :: forall f a w (m :: Type -> Type) k u v. (Applicative f, Ord a, Ord w, Ord (m Int), Mapping k m) => (u -> v -> f w) -> Base k m a u -> Base k m a v -> Set (Int, Int) -> f (Builder (Int, Int) k m a w)
- Data.Mapping.Decision: baseRecurse :: (Ord c, Mapping k m) => (v -> c) -> (a -> m c -> c) -> Base k m a v -> BaseMap c
- Data.Mapping.Decision: baseTransform :: forall {k1} a n l w v m (k2 :: k1). (Ord a, Ord (n Int), Mapping l n, Ord w) => (v -> w) -> (forall x. () => a -> m x -> n x) -> Base k2 m a v -> IntSet -> Builder Int l n a w
- Data.Mapping.Decision: baseTraverse :: forall f a (m :: Type -> Type) w k v. (Applicative f, Ord a, Ord (m Int), Ord w, Mapping k m) => (v -> f w) -> Base k m a v -> f (Builder Int k m a w)
- Data.Mapping.Decision: bestSuchThat :: (Mapping k m, Ord k, Ord a, Ord v) => (v -> Bool) -> (forall w. () => a -> m w -> Maybe (k, w)) -> Decision k m a v -> Maybe ([(a, k)], v)
- Data.Mapping.Decision: bindex :: BaseMap v -> Int -> v
- Data.Mapping.Decision: buildAll :: Mapping k m => Map a (m Bool) -> Decision k m a Bool
- Data.Mapping.Decision: buildAny :: Mapping k m => Map a (m Bool) -> Decision k m a Bool
- Data.Mapping.Decision: buildBase :: forall {k1} o (k2 :: k1) (m :: Type -> Type) a v. Builder o k2 m a v -> Base k2 m a v
- Data.Mapping.Decision: buildDecision :: forall {k1} o (k2 :: k1) (m :: Type -> Type) a v. Ord o => o -> Builder o k2 m a v -> Decision k2 m a v
- Data.Mapping.Decision: checkBijection :: forall a v k (m :: Type -> Type). (Eq a, Eq v, Mapping k m) => Base k m a v -> Base k m a v -> Bij -> Maybe Bij
- Data.Mapping.Decision: chunksTrue :: forall k (m :: Type -> Type) a. (Mapping k m, FoldableWithIndex k m, Ord k, Ord a) => Decision k m a Bool -> [Map a k]
- Data.Mapping.Decision: closure :: (Int -> IntSet) -> IntSet -> IntSet
- Data.Mapping.Decision: data Base (k1 :: k) (m :: Type -> Type) a v
- Data.Mapping.Decision: data BaseMap v
- Data.Mapping.Decision: data Builder o (k1 :: k) (m :: Type -> Type) a v
- Data.Mapping.Decision: data Decision (k1 :: k) (m :: Type -> Type) a v
- Data.Mapping.Decision: decisionLength :: forall {k1} (k2 :: k1) (m :: Type -> Type) a v. Decision k2 m a v -> Int
- Data.Mapping.Decision: decisionRecurse :: (Ord c, Mapping k m) => (v -> c) -> (a -> m c -> c) -> Decision k m a v -> c
- Data.Mapping.Decision: decisionTransform :: forall {k1} l n a w v m (k2 :: k1). (Mapping l n, Ord (n Int), Ord a, Ord w) => (v -> w) -> (forall x. () => a -> m x -> n x) -> Decision k2 m a v -> Decision l n a w
- Data.Mapping.Decision: emptyBuilder :: forall {k1} o (k2 :: k1) (m :: Type -> Type) a v. Builder o k2 m a v
- Data.Mapping.Decision: findBijection :: forall a v k (m :: Type -> Type). (Eq a, Eq v, Mapping k m) => Decision k m a v -> Decision k m a v -> Maybe Bij
- Data.Mapping.Decision: fromKeyVals :: Foldable f => f (Int, a) -> Seq a
- Data.Mapping.Decision: generalCounts :: (Ord a, Ord n, Mapping k m) => (a -> a -> Int) -> a -> a -> (v -> n) -> (m n -> n) -> Decision k m a v -> n
- Data.Mapping.Decision: instance (Data.Mapping.Mapping k m, Data.Mapping.Neighbourly m, GHC.Classes.Ord a, GHC.Classes.Ord (m GHC.Types.Int)) => Data.Mapping.Neighbourly (Data.Mapping.Decision.Decision k m a)
- Data.Mapping.Decision: instance (Data.Mapping.Mapping k m, GHC.Classes.Ord (m GHC.Types.Int), GHC.Classes.Ord a, GHC.Classes.Ord v, Data.Algebra.Boolean.Boolean v) => Data.Algebra.Boolean.Boolean (Data.Mapping.Decision.Decision k m a v)
- Data.Mapping.Decision: instance (Data.Mapping.Mapping k m, GHC.Classes.Ord (m GHC.Types.Int), GHC.Classes.Ord a, GHC.Classes.Ord v, GHC.Base.Monoid v) => GHC.Base.Monoid (Data.Mapping.Decision.Decision k m a v)
- Data.Mapping.Decision: instance (Data.Mapping.Mapping k m, GHC.Classes.Ord (m GHC.Types.Int), GHC.Classes.Ord a, GHC.Classes.Ord v, GHC.Base.Semigroup v) => GHC.Base.Semigroup (Data.Mapping.Decision.Decision k m a v)
- Data.Mapping.Decision: instance (Data.Mapping.Mapping k m, GHC.Classes.Ord (m GHC.Types.Int), GHC.Classes.Ord a, GHC.Classes.Ord v, GHC.Num.Num v) => GHC.Num.Num (Data.Mapping.Decision.Decision k m a v)
- Data.Mapping.Decision: instance (GHC.Classes.Eq a, GHC.Classes.Eq v, Data.Mapping.Mapping k m) => GHC.Classes.Eq (Data.Mapping.Decision.Decision k m a v)
- Data.Mapping.Decision: instance (GHC.Classes.Ord a, GHC.Classes.Ord (m GHC.Types.Int), Data.Mapping.Mapping k m) => Data.Mapping.Mapping (a -> k) (Data.Mapping.Decision.Decision k m a)
- Data.Mapping.Decision: instance (GHC.Classes.Ord a, GHC.Classes.Ord v, GHC.Classes.Ord (m GHC.Types.Int), Data.Mapping.Mapping k m) => GHC.Classes.Ord (Data.Mapping.Decision.Decision k m a v)
- Data.Mapping.Decision: instance forall k1 (k2 :: k1) (m :: * -> *) a. Data.Foldable.Foldable (Data.Mapping.Decision.Base k2 m a)
- Data.Mapping.Decision: instance forall k1 (m :: * -> *) (k2 :: k1) a. Data.Foldable.Foldable m => Data.Foldable.Foldable (Data.Mapping.Decision.Decision k2 m a)
- Data.Mapping.Decision: instance forall k1 a (m :: * -> *) (k2 :: k1). (GHC.Classes.Eq a, GHC.Classes.Eq (m GHC.Types.Int)) => GHC.Classes.Eq (Data.Mapping.Decision.Node k2 m a)
- Data.Mapping.Decision: instance forall k1 a (m :: * -> *) (k2 :: k1). (GHC.Classes.Ord a, GHC.Classes.Ord (m GHC.Types.Int)) => GHC.Classes.Ord (Data.Mapping.Decision.Node k2 m a)
- Data.Mapping.Decision: listTrue :: forall k (m :: Type -> Type) a. (Mapping k m, FoldableWithIndex k m, Ord k, Ord a) => Set a -> Decision k m a Bool -> [Map a k]
- Data.Mapping.Decision: makeBuilder :: (Mapping k m, Ord o, Ord (m Int), Ord a, Ord v) => Map o v -> Map o (a, m o) -> Builder o k m a v
- Data.Mapping.Decision: numberTrue :: Int -> Int -> Decision Bool OnBool Int Bool -> Integer
- Data.Mapping.Decision: numberTrueGeneral :: Mapping k m => (m Integer -> Integer) -> Int -> Int -> Decision k m Int Bool -> Integer
- Data.Mapping.Decision: singleNode :: (Mapping k m, Ord (m Int), Ord a, Ord v) => a -> m v -> Decision k m a v
- Data.Mapping.MapWithDefault: instance GHC.Classes.Ord k => Data.Mapping.Mapping k (Data.Mapping.MapWithDefault.MapWithDefault k)
- Data.Mapping.Piecewise: instance GHC.Classes.Ord k => Data.Mapping.Mapping k (Data.Mapping.Piecewise.Piecewise k)
- Data.Mapping.Piecewise: mjoin :: (Ord k, Eq w) => (v -> Piecewise k w) -> Piecewise k v -> Piecewise k w
- Data.Mapping.Piecewise: values :: Piecewise k v -> [v]
- Data.Mapping.Util: equating :: Eq a => (b -> a) -> b -> b -> Bool
- Data.Mapping.Util: insertIfAbsent :: Ord k => k -> v -> Map k v -> (v, Maybe (Map k v))
+ Data.Mapping: Reconstrained :: m a -> Reconstrained (c :: Type -> Constraint) (d :: Type -> Constraint) k (m :: Type -> Type) a
+ Data.Mapping: [preconstrained] :: Reconstrained (c :: Type -> Constraint) (d :: Type -> Constraint) k (m :: Type -> Type) a -> m a
+ Data.Mapping: bind :: (Mapping c k m, c u, c v, Ord u, c (Either v u)) => (u -> m v) -> m u -> m v
+ Data.Mapping: boolBind :: forall (c :: Type -> Constraint) k m v. (Mapping c k m, c v) => m v -> m v -> m Bool -> m v
+ Data.Mapping: instance (Data.Foldable.Foldable m, Data.Foldable.Foldable n) => Data.Foldable.Foldable (Data.Mapping.OnEither c k l m n)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, Data.Mapping.Mapping c l n, c a, forall x. c x => GHC.Classes.Eq x, forall x. c x => c (Data.Mapping.OnEither c k l m n x), Data.Algebra.Boolean.Boolean a) => Data.Algebra.Boolean.Boolean (Data.Mapping.OnEither c k l m n a)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, Data.Mapping.Mapping c l n, c a, forall x. c x => GHC.Classes.Eq x, forall x. c x => c (Data.Mapping.OnEither c k l m n x), GHC.Base.Monoid a) => GHC.Base.Monoid (Data.Mapping.OnEither c k l m n a)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, Data.Mapping.Mapping c l n, c a, forall x. c x => GHC.Classes.Eq x, forall x. c x => c (Data.Mapping.OnEither c k l m n x), GHC.Base.Semigroup a) => GHC.Base.Semigroup (Data.Mapping.OnEither c k l m n a)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, Data.Mapping.Mapping c l n, c a, forall x. c x => GHC.Classes.Eq x, forall x. c x => c (Data.Mapping.OnEither c k l m n x), GHC.Num.Num a) => GHC.Num.Num (Data.Mapping.OnEither c k l m n a)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, Data.Mapping.Mapping c l n, forall x. c x => GHC.Classes.Eq x, forall x. c x => c (Data.Mapping.OnEither c k l m n x)) => Data.Mapping.Mapping c (Data.Either.Either k l) (Data.Mapping.OnEither c k l m n)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, Data.Mapping.Mapping c l n, forall x. c x => c (Data.Mapping.OnPair c k l m n x)) => Data.Mapping.Mapping c (k, l) (Data.Mapping.OnPair c k l m n)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, Data.Mapping.Mapping c l n, forall x. c x => c (Data.Mapping.OnPair c k l m n x), c a, GHC.Base.Monoid a) => GHC.Base.Monoid (Data.Mapping.OnPair c k l m n a)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, Data.Mapping.Mapping c l n, forall x. c x => c (Data.Mapping.OnPair c k l m n x), c a, GHC.Base.Semigroup a) => GHC.Base.Semigroup (Data.Mapping.OnPair c k l m n a)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, Data.Mapping.Mapping c l n, forall x. c x => c (Data.Mapping.OnPair c k l m n x), c a, GHC.Num.Num a) => GHC.Num.Num (Data.Mapping.OnPair c k l m n a)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, Data.Mapping.Mapping c l n, forall x. c x => c (Data.Mapping.OnPair c k l m n x), c b, Data.Algebra.Boolean.Boolean b) => Data.Algebra.Boolean.Boolean (Data.Mapping.OnPair c k l m n b)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, c GHC.Base.Void, Data.PartialOrd.PartialOrd v) => Data.PartialOrd.PartialOrd (Data.Mapping.PartialOrdWrapper c k m v)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, c GHC.Base.Void, GHC.Classes.Ord v) => Data.PartialOrd.PartialOrd (Data.Mapping.OrdWrapper c k m v)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, c a, Data.Algebra.Boolean.Boolean a) => Data.Algebra.Boolean.Boolean (Data.Mapping.AlgebraWrapper c k m a)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, c a, GHC.Base.Monoid a) => GHC.Base.Monoid (Data.Mapping.AlgebraWrapper c k m a)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, c a, GHC.Base.Semigroup a) => GHC.Base.Semigroup (Data.Mapping.AlgebraWrapper c k m a)
+ Data.Mapping: instance (Data.Mapping.Mapping c k m, c a, GHC.Num.Num a) => GHC.Num.Num (Data.Mapping.AlgebraWrapper c k m a)
+ Data.Mapping: instance (GHC.Classes.Eq (m v), GHC.Classes.Eq (n v)) => GHC.Classes.Eq (Data.Mapping.OnEither c k l m n v)
+ Data.Mapping: instance (GHC.Classes.Eq a, GHC.Base.Monoid a) => GHC.Base.Monoid (Data.Mapping.OnBool a)
+ Data.Mapping: instance (GHC.Classes.Eq a, GHC.Base.Semigroup a) => GHC.Base.Semigroup (Data.Mapping.OnBool a)
+ Data.Mapping: instance (GHC.Classes.Eq a, GHC.Num.Num a) => GHC.Num.Num (Data.Mapping.OnBool a)
+ Data.Mapping: instance (GHC.Classes.Eq b, Data.Algebra.Boolean.Boolean b) => Data.Algebra.Boolean.Boolean (Data.Mapping.OnBool b)
+ Data.Mapping: instance (GHC.Classes.Ord (m v), GHC.Classes.Ord (n v)) => GHC.Classes.Ord (Data.Mapping.OnEither c k l m n v)
+ Data.Mapping: instance (WithIndex.FoldableWithIndex k m, WithIndex.FoldableWithIndex l n) => WithIndex.FoldableWithIndex (Data.Either.Either k l) (Data.Mapping.OnEither c k l m n)
+ Data.Mapping: instance (forall x. c x => GHC.Classes.Eq x, forall x. c x => c (Data.Mapping.OnMaybe c k m x), Data.Mapping.Mapping c k m) => Data.Mapping.Mapping c (GHC.Maybe.Maybe k) (Data.Mapping.OnMaybe c k m)
+ Data.Mapping: instance (forall x. c x => GHC.Classes.Eq x, forall x. c x => c (Data.Mapping.OnMaybe c k m x), Data.Mapping.Mapping c k m, c a, Data.Algebra.Boolean.Boolean a) => Data.Algebra.Boolean.Boolean (Data.Mapping.OnMaybe c k m a)
+ Data.Mapping: instance (forall x. c x => GHC.Classes.Eq x, forall x. c x => c (Data.Mapping.OnMaybe c k m x), Data.Mapping.Mapping c k m, c a, GHC.Base.Monoid a) => GHC.Base.Monoid (Data.Mapping.OnMaybe c k m a)
+ Data.Mapping: instance (forall x. c x => GHC.Classes.Eq x, forall x. c x => c (Data.Mapping.OnMaybe c k m x), Data.Mapping.Mapping c k m, c a, GHC.Base.Semigroup a) => GHC.Base.Semigroup (Data.Mapping.OnMaybe c k m a)
+ Data.Mapping: instance (forall x. c x => GHC.Classes.Eq x, forall x. c x => c (Data.Mapping.OnMaybe c k m x), Data.Mapping.Mapping c k m, c a, GHC.Num.Num a) => GHC.Num.Num (Data.Mapping.OnMaybe c k m a)
+ Data.Mapping: instance (forall x. d x => c x, forall x. d x => d (Data.Mapping.Reconstrained c d k m x), Data.Mapping.Mapping c k m) => Data.Mapping.Mapping d k (Data.Mapping.Reconstrained c d k m)
+ Data.Mapping: instance Data.Foldable.Foldable m => Data.Foldable.Foldable (Data.Mapping.Reconstrained c d k m)
+ Data.Mapping: instance Data.Mapping.Mapping Data.Constraint.Trivial.Unconstrained k (Data.Mapping.Constant k)
+ Data.Mapping: instance Data.Mapping.Mapping GHC.Classes.Eq GHC.Types.Bool Data.Mapping.OnBool
+ Data.Mapping: instance Data.Mapping.Neighbourly m => Data.Mapping.Neighbourly (Data.Mapping.Reconstrained c d k m)
+ Data.Mapping: instance GHC.Classes.Eq (m a) => GHC.Classes.Eq (Data.Mapping.Reconstrained c d k m a)
+ Data.Mapping: instance GHC.Classes.Ord (m a) => GHC.Classes.Ord (Data.Mapping.Reconstrained c d k m a)
+ Data.Mapping: instance WithIndex.FoldableWithIndex k m => WithIndex.FoldableWithIndex k (Data.Mapping.Reconstrained c d k m)
+ Data.Mapping: instance forall k1 (c :: k1) k2 (k3 :: k2) (m :: * -> *) v. (GHC.Classes.Eq v, GHC.Classes.Eq (m v)) => GHC.Classes.Eq (Data.Mapping.OnMaybe c k3 m v)
+ Data.Mapping: instance forall k1 (c :: k1) k2 (k3 :: k2) (m :: * -> *) v. (GHC.Classes.Ord v, GHC.Classes.Ord (m v)) => GHC.Classes.Ord (Data.Mapping.OnMaybe c k3 m v)
+ Data.Mapping: instance forall k1 (c :: k1) k2 (k3 :: k2) k4 (l :: k4) k5 (m :: k5 -> *) k6 (n :: k6 -> k5) (v :: k6). GHC.Classes.Eq (m (n v)) => GHC.Classes.Eq (Data.Mapping.OnPair c k3 l m n v)
+ Data.Mapping: instance forall k1 (c :: k1) k2 (k3 :: k2) k4 (l :: k4) k5 (m :: k5 -> *) k6 (n :: k6 -> k5) (v :: k6). GHC.Classes.Ord (m (n v)) => GHC.Classes.Ord (Data.Mapping.OnPair c k3 l m n v)
+ Data.Mapping: instance forall k1 (k2 :: k1) v. GHC.Classes.Eq v => GHC.Classes.Eq (Data.Mapping.Constant k2 v)
+ Data.Mapping: instance forall k1 (k2 :: k1) v. GHC.Classes.Ord v => GHC.Classes.Ord (Data.Mapping.Constant k2 v)
+ Data.Mapping: instance forall k1 k2 (m :: * -> *) (c :: k1) (k3 :: k2). Data.Foldable.Foldable m => Data.Foldable.Foldable (Data.Mapping.OnMaybe c k3 m)
+ Data.Mapping: instance forall k1 k2 (m :: * -> *) (c :: k1). WithIndex.FoldableWithIndex k2 m => WithIndex.FoldableWithIndex (GHC.Maybe.Maybe k2) (Data.Mapping.OnMaybe c k2 m)
+ Data.Mapping: instance forall k1 k2 (m :: * -> *) l (n :: * -> *) (c :: k1). (WithIndex.FoldableWithIndex k2 m, WithIndex.FoldableWithIndex l n) => WithIndex.FoldableWithIndex (k2, l) (Data.Mapping.OnPair c k2 l m n)
+ Data.Mapping: instance forall k1 k2 k3 (m :: * -> *) (n :: * -> *) (c :: k1) (k4 :: k2) (l :: k3). (Data.Foldable.Foldable m, Data.Foldable.Foldable n) => Data.Foldable.Foldable (Data.Mapping.OnPair c k4 l m n)
+ Data.Mapping: merge3 :: (Mapping c k m, c x) => (u -> v -> w -> x) -> m u -> m v -> m w -> m x
+ Data.Mapping: mergeA3 :: (Mapping c k m, Applicative f, c x) => (u -> v -> w -> f x) -> m u -> m v -> m w -> f (m x)
+ Data.Mapping: newtype Reconstrained (c :: Type -> Constraint) (d :: Type -> Constraint) k (m :: Type -> Type) a
+ Data.Mapping: values :: forall (c :: Type -> Constraint) k m v. (Mapping c k m, Ord v) => m v -> Set v
+ Data.Mapping.Decision: Branch :: a -> m (Serial (Node k m a v)) -> Node k (m :: Type -> Type) a v
+ Data.Mapping.Decision: Cache :: Map a (Serial a) -> Cache a
+ Data.Mapping.Decision: Leaf :: v -> Node k (m :: Type -> Type) a v
+ Data.Mapping.Decision: Serial :: !Int -> a -> Serial a
+ Data.Mapping.Decision: [content] :: Serial a -> a
+ Data.Mapping.Decision: [serial] :: Serial a -> !Int
+ Data.Mapping.Decision: [startDecision] :: Decision k (m :: Type -> Type) a v -> Serial (Node k m a v)
+ Data.Mapping.Decision: branchS :: (Mapping Eq k m, Ord a, Ord v, forall x. Ord x => Ord (m x)) => a -> m (Serial (Node k m a v)) -> State (Cache (Node k m a v)) (Serial (Node k m a v))
+ Data.Mapping.Decision: data Serial a
+ Data.Mapping.Decision: debugShowCache :: forall k (m :: Type -> Type) a v. (Mapping Eq k m, Show a, Show v, Show (m Int)) => Cache (Node k m a v) -> [String]
+ Data.Mapping.Decision: decideAll :: (Mapping Eq k m, Ord a, forall x. Ord x => Ord (m x)) => Map a (m Bool) -> Decision k m a Bool
+ Data.Mapping.Decision: decideAllS :: (Mapping Eq k m, Ord a, forall x. Ord x => Ord (m x)) => Map a (m Bool) -> State (Cache (Node k m a Bool)) (Serial (Node k m a Bool))
+ Data.Mapping.Decision: decideAny :: (Mapping Eq k m, Ord a, forall x. Ord x => Ord (m x)) => Map a (m Bool) -> Decision k m a Bool
+ Data.Mapping.Decision: decideAnyS :: (Mapping Eq k m, Ord a, forall x. Ord x => Ord (m x)) => Map a (m Bool) -> State (Cache (Node k m a Bool)) (Serial (Node k m a Bool))
+ Data.Mapping.Decision: decision :: (Mapping Eq k m, Ord a, Ord v, forall x. Ord x => Ord (m x)) => a -> m v -> Decision k m a v
+ Data.Mapping.Decision: decisionS :: (Mapping Eq k m, Ord a, Ord v, forall x. Ord x => Ord (m x)) => a -> m v -> State (Cache (Node k m a v)) (Serial (Node k m a v))
+ Data.Mapping.Decision: foldingCount :: forall k (m :: Type -> Type) n a v. (Mapping Eq k m, Num n) => (a -> Int) -> Int -> (v -> n) -> Decision k m a v -> n
+ Data.Mapping.Decision: foldingCountTrue :: forall k (m :: Type -> Type) n a. (Mapping Eq k m, Num n) => (a -> Int) -> Int -> Decision k m a Bool -> n
+ Data.Mapping.Decision: genTestS :: (Ord a, Ord b, Boolean b) => a -> State (Cache (Node Bool OnBool a b)) (Serial (Node Bool OnBool a b))
+ Data.Mapping.Decision: generalCount :: Mapping Eq k m => (a -> Int) -> Int -> (v -> n) -> (forall (f :: Type -> Type) z. Applicative f => (z -> f n) -> m z -> f n) -> Decision k m a v -> n
+ Data.Mapping.Decision: instance (Data.Mapping.Mapping GHC.Classes.Eq k m, GHC.Classes.Ord a, GHC.Classes.Eq v, forall x. GHC.Classes.Ord x => GHC.Classes.Ord (m x)) => GHC.Classes.Eq (Data.Mapping.Decision.Decision k m a v)
+ Data.Mapping.Decision: instance (Data.Mapping.Mapping GHC.Classes.Eq k m, GHC.Classes.Ord a, GHC.Classes.Ord v, Data.Algebra.Boolean.Boolean v, forall x. GHC.Classes.Ord x => GHC.Classes.Ord (m x)) => Data.Algebra.Boolean.Boolean (Data.Mapping.Decision.Decision k m a v)
+ Data.Mapping.Decision: instance (Data.Mapping.Mapping GHC.Classes.Eq k m, GHC.Classes.Ord a, GHC.Classes.Ord v, GHC.Base.Monoid v, forall x. GHC.Classes.Ord x => GHC.Classes.Ord (m x)) => GHC.Base.Monoid (Data.Mapping.Decision.Decision k m a v)
+ Data.Mapping.Decision: instance (Data.Mapping.Mapping GHC.Classes.Eq k m, GHC.Classes.Ord a, GHC.Classes.Ord v, GHC.Base.Semigroup v, forall x. GHC.Classes.Ord x => GHC.Classes.Ord (m x)) => GHC.Base.Semigroup (Data.Mapping.Decision.Decision k m a v)
+ Data.Mapping.Decision: instance (Data.Mapping.Mapping GHC.Classes.Eq k m, GHC.Classes.Ord a, GHC.Classes.Ord v, GHC.Num.Num v, forall x. GHC.Classes.Ord x => GHC.Classes.Ord (m x)) => GHC.Num.Num (Data.Mapping.Decision.Decision k m a v)
+ Data.Mapping.Decision: instance (Data.Mapping.Mapping GHC.Classes.Eq k m, GHC.Classes.Ord a, GHC.Classes.Ord v, forall x. GHC.Classes.Ord x => GHC.Classes.Ord (m x)) => GHC.Classes.Ord (Data.Mapping.Decision.Decision k m a v)
+ Data.Mapping.Decision: instance (Data.Mapping.Mapping GHC.Classes.Eq k m, GHC.Classes.Ord a, forall x. GHC.Classes.Ord x => GHC.Classes.Ord (m x)) => Data.Mapping.Mapping GHC.Classes.Ord (a -> k) (Data.Mapping.Decision.Decision k m a)
+ Data.Mapping.Decision: instance (GHC.Classes.Eq (m (Data.Mapping.Decision.Serial (Data.Mapping.Decision.Node k m a v))), GHC.Classes.Eq a, GHC.Classes.Eq v) => GHC.Classes.Eq (Data.Mapping.Decision.Node k m a v)
+ Data.Mapping.Decision: instance (GHC.Classes.Ord (m (Data.Mapping.Decision.Serial (Data.Mapping.Decision.Node k m a v))), GHC.Classes.Ord a, GHC.Classes.Ord v) => GHC.Classes.Ord (Data.Mapping.Decision.Node k m a v)
+ Data.Mapping.Decision: instance (GHC.Classes.Ord a, Data.Mapping.Mapping GHC.Classes.Eq k m, Data.Mapping.Neighbourly m) => Data.Mapping.Neighbourly (Data.Mapping.Decision.Decision k m a)
+ Data.Mapping.Decision: instance (GHC.Classes.Ord a, WithIndex.FoldableWithIndex k m, Data.Mapping.Mapping GHC.Classes.Eq k m) => WithIndex.FoldableWithIndex (Data.Map.Internal.Map a k) (Data.Mapping.Decision.Decision k m a)
+ Data.Mapping.Decision: instance Data.Foldable.Foldable m => Data.Foldable.Foldable (Data.Mapping.Decision.Decision k m a)
+ Data.Mapping.Decision: instance GHC.Classes.Eq (Data.Mapping.Decision.Serial a)
+ Data.Mapping.Decision: instance GHC.Classes.Ord (Data.Mapping.Decision.Serial a)
+ Data.Mapping.Decision: leafS :: forall (m :: Type -> Type) a v k. (forall x. Ord x => Ord (m x), Ord a, Ord v) => v -> State (Cache (Node k m a v)) (Serial (Node k m a v))
+ Data.Mapping.Decision: mapS :: forall k (m :: Type -> Type) a u v. (Mapping Eq k m, Ord a, Ord v, forall x. Ord x => Ord (m x)) => (u -> v) -> Serial (Node k m a u) -> State (Cache (Node k m a v)) (Serial (Node k m a v))
+ Data.Mapping.Decision: mergeAS :: forall k (m :: Type -> Type) a u v w f. (Mapping Eq k m, Ord a, Ord w, Applicative f, forall x. Ord x => Ord (m x)) => (u -> v -> f w) -> Serial (Node k m a u) -> Serial (Node k m a v) -> f (State (Cache (Node k m a w)) (Serial (Node k m a w)))
+ Data.Mapping.Decision: mergeS :: forall k (m :: Type -> Type) a u v w. (Mapping Eq k m, Ord a, Ord w, forall x. Ord x => Ord (m x)) => (u -> v -> w) -> Serial (Node k m a u) -> Serial (Node k m a v) -> State (Cache (Node k m a w)) (Serial (Node k m a w))
+ Data.Mapping.Decision: mergeS3 :: forall k (m :: Type -> Type) a u v w x. (Mapping Eq k m, Ord a, Ord x, forall y. Ord y => Ord (m y)) => (u -> v -> w -> x) -> Serial (Node k m a u) -> Serial (Node k m a v) -> Serial (Node k m a w) -> State (Cache (Node k m a x)) (Serial (Node k m a x))
+ Data.Mapping.Decision: newtype Cache a
+ Data.Mapping.Decision: newtype Decision k (m :: Type -> Type) a v
+ Data.Mapping.Decision: recoverCache :: forall k (m :: Type -> Type) a v. (Mapping Eq k m, Ord a, Ord v, forall x. Ord x => Ord (m x)) => Serial (Node k m a v) -> Cache (Node k m a v)
+ Data.Mapping.Decision: restrictS :: forall k (m :: Type -> Type) a v. (Mapping Eq k m, Ord a, Ord v, forall x. Ord x => Ord (m x)) => (a -> Maybe k) -> Serial (Node k m a v) -> State (Cache (Node k m a v)) (Serial (Node k m a v))
+ Data.Mapping.Decision: runOnEmptyCache :: forall k (m :: Type -> Type) a v. State (Cache (Node k m a v)) (Serial (Node k m a v)) -> Decision k m a v
+ Data.Mapping.Decision: testS :: Ord a => a -> State (Cache (Node Bool OnBool a Bool)) (Serial (Node Bool OnBool a Bool))
+ Data.Mapping.Decision: traverseS :: forall k (m :: Type -> Type) a u v f. (Mapping Eq k m, Ord a, Ord v, Applicative f, forall x. Ord x => Ord (m x)) => (u -> f v) -> Serial (Node k m a u) -> f (State (Cache (Node k m a v)) (Serial (Node k m a v)))
+ Data.Mapping.Decision: trueAssignments :: forall a k (m :: Type -> Type). (Ord a, FoldableWithIndex k m) => Decision k m a Bool -> [Map a k]
+ Data.Mapping.MapWithDefault: instance GHC.Classes.Ord k => Data.Mapping.Mapping GHC.Classes.Eq k (Data.Mapping.MapWithDefault.MapWithDefault k)
+ Data.Mapping.Piecewise: innerMerge :: Ord k => (x -> y -> z) -> x -> y -> [(k, x)] -> [(k, y)] -> [(k, z)]
+ Data.Mapping.Piecewise: innerMerge3 :: Ord k => (x -> y -> z -> w) -> x -> y -> z -> [(k, x)] -> [(k, y)] -> [(k, z)] -> [(k, w)]
+ Data.Mapping.Piecewise: innerMergeA :: (Ord k, Applicative f) => (x -> y -> f z) -> x -> y -> [(k, x)] -> [(k, y)] -> f [(k, z)]
+ Data.Mapping.Piecewise: innerMergeA3 :: (Applicative f, Ord k) => (x -> y -> z -> f w) -> x -> y -> z -> [(k, x)] -> [(k, y)] -> [(k, z)] -> f [(k, w)]
+ Data.Mapping.Piecewise: instance GHC.Classes.Ord k => Data.Mapping.Mapping GHC.Classes.Eq k (Data.Mapping.Piecewise.Piecewise k)
- Data.Mapping: AlgebraWrapper :: m a -> AlgebraWrapper (k2 :: k) (m :: k1 -> Type) (a :: k1)
+ Data.Mapping: AlgebraWrapper :: m a -> AlgebraWrapper (c :: Type -> Constraint) (k2 :: k) (m :: k1 -> Type) (a :: k1)
- Data.Mapping: OnEither :: m v -> n v -> OnEither (k3 :: k) (l :: k1) (m :: k2 -> Type) (n :: k2 -> Type) (v :: k2)
+ Data.Mapping: OnEither :: m v -> n v -> OnEither (c :: Type -> Constraint) k l (m :: Type -> Type) (n :: Type -> Type) v
- Data.Mapping: OnMaybe :: v -> m v -> OnMaybe (k1 :: k) (m :: Type -> Type) v
+ Data.Mapping: OnMaybe :: v -> m v -> OnMaybe (c :: k) (k2 :: k1) (m :: Type -> Type) v
- Data.Mapping: OnPair :: m (n v) -> OnPair (k4 :: k) (l :: k1) (m :: k2 -> Type) (n :: k3 -> k2) (v :: k3)
+ Data.Mapping: OnPair :: m (n v) -> OnPair (c :: k) (k5 :: k1) (l :: k2) (m :: k3 -> Type) (n :: k4 -> k3) (v :: k4)
- Data.Mapping: OrdWrapper :: m v -> OrdWrapper (k2 :: k) (m :: k1 -> Type) (v :: k1)
+ Data.Mapping: OrdWrapper :: m v -> OrdWrapper (c :: k) (k3 :: k1) (m :: k2 -> Type) (v :: k2)
- Data.Mapping: PartialOrdWrapper :: m v -> PartialOrdWrapper (k2 :: k) (m :: k1 -> Type) (v :: k1)
+ Data.Mapping: PartialOrdWrapper :: m v -> PartialOrdWrapper (c :: k) (k3 :: k1) (m :: k2 -> Type) (v :: k2)
- Data.Mapping: [algebraUnwrap] :: AlgebraWrapper (k2 :: k) (m :: k1 -> Type) (a :: k1) -> m a
+ Data.Mapping: [algebraUnwrap] :: AlgebraWrapper (c :: Type -> Constraint) (k2 :: k) (m :: k1 -> Type) (a :: k1) -> m a
- Data.Mapping: [asComposite] :: OnPair (k4 :: k) (l :: k1) (m :: k2 -> Type) (n :: k3 -> k2) (v :: k3) -> m (n v)
+ Data.Mapping: [asComposite] :: OnPair (c :: k) (k5 :: k1) (l :: k2) (m :: k3 -> Type) (n :: k4 -> k3) (v :: k4) -> m (n v)
- Data.Mapping: [getOrdMapping] :: OrdWrapper (k2 :: k) (m :: k1 -> Type) (v :: k1) -> m v
+ Data.Mapping: [getOrdMapping] :: OrdWrapper (c :: k) (k3 :: k1) (m :: k2 -> Type) (v :: k2) -> m v
- Data.Mapping: [getPartialOrdMapping] :: PartialOrdWrapper (k2 :: k) (m :: k1 -> Type) (v :: k1) -> m v
+ Data.Mapping: [getPartialOrdMapping] :: PartialOrdWrapper (c :: k) (k3 :: k1) (m :: k2 -> Type) (v :: k2) -> m v
- Data.Mapping: [onJust] :: OnMaybe (k1 :: k) (m :: Type -> Type) v -> m v
+ Data.Mapping: [onJust] :: OnMaybe (c :: k) (k2 :: k1) (m :: Type -> Type) v -> m v
- Data.Mapping: [onLeft] :: OnEither (k3 :: k) (l :: k1) (m :: k2 -> Type) (n :: k2 -> Type) (v :: k2) -> m v
+ Data.Mapping: [onLeft] :: OnEither (c :: Type -> Constraint) k l (m :: Type -> Type) (n :: Type -> Type) v -> m v
- Data.Mapping: [onNothing] :: OnMaybe (k1 :: k) (m :: Type -> Type) v -> v
+ Data.Mapping: [onNothing] :: OnMaybe (c :: k) (k2 :: k1) (m :: Type -> Type) v -> v
- Data.Mapping: [onRight] :: OnEither (k3 :: k) (l :: k1) (m :: k2 -> Type) (n :: k2 -> Type) (v :: k2) -> n v
+ Data.Mapping: [onRight] :: OnEither (c :: Type -> Constraint) k l (m :: Type -> Type) (n :: Type -> Type) v -> n v
- Data.Mapping: act :: Mapping k m => m v -> k -> v
+ Data.Mapping: act :: Mapping c k m => m v -> k -> v
- Data.Mapping: class Foldable m => Mapping k (m :: Type -> Type) | m -> k
+ Data.Mapping: class (Foldable m, forall x. c x => c m x) => Mapping (c :: Type -> Constraint) k (m :: Type -> Type) | m -> k, m -> c
- Data.Mapping: cst :: Mapping k m => v -> m v
+ Data.Mapping: cst :: Mapping c k m => v -> m v
- Data.Mapping: data OnEither (k3 :: k) (l :: k1) (m :: k2 -> Type) (n :: k2 -> Type) (v :: k2)
+ Data.Mapping: data OnEither (c :: Type -> Constraint) k l (m :: Type -> Type) (n :: Type -> Type) v
- Data.Mapping: data OnMaybe (k1 :: k) (m :: Type -> Type) v
+ Data.Mapping: data OnMaybe (c :: k) (k2 :: k1) (m :: Type -> Type) v
- Data.Mapping: isConst :: (Mapping k m, Ord v) => m v -> Maybe v
+ Data.Mapping: isConst :: (Mapping c k m, c v) => m v -> Maybe v
- Data.Mapping: isDisjoint :: Mapping k m => m Bool -> m Bool -> Bool
+ Data.Mapping: isDisjoint :: forall b (c :: Type -> Constraint) k m. (Boolean b, c Void, Mapping c k m) => m b -> m b -> b
- Data.Mapping: isSubset :: Mapping k m => m Bool -> m Bool -> Bool
+ Data.Mapping: isSubset :: forall b (c :: Type -> Constraint) k m. (Boolean b, c Void, Mapping c k m) => m b -> m b -> b
- Data.Mapping: merge :: (Mapping k m, Ord w) => (u -> v -> w) -> m u -> m v -> m w
+ Data.Mapping: merge :: (Mapping c k m, c w) => (u -> v -> w) -> m u -> m v -> m w
- Data.Mapping: mergeA :: (Mapping k m, Applicative f, Ord w) => (u -> v -> f w) -> m u -> m v -> f (m w)
+ Data.Mapping: mergeA :: (Mapping c k m, Applicative f, c w) => (u -> v -> f w) -> m u -> m v -> f (m w)
- Data.Mapping: mmap :: (Mapping k m, Ord v) => (u -> v) -> m u -> m v
+ Data.Mapping: mmap :: (Mapping c k m, c v) => (u -> v) -> m u -> m v
- Data.Mapping: mtraverse :: (Mapping k m, Applicative f, Ord v) => (u -> f v) -> m u -> f (m v)
+ Data.Mapping: mtraverse :: (Mapping c k m, Applicative f, c v) => (u -> f v) -> m u -> f (m v)
- Data.Mapping: mutualValues :: (Ord u, Ord v, Mapping k m) => m u -> m v -> Set (u, v)
+ Data.Mapping: mutualValues :: forall u v (c :: Type -> Constraint) k m. (Ord u, Ord v, c Void, Mapping c k m) => m u -> m v -> Set (u, v)
- Data.Mapping: newtype AlgebraWrapper (k2 :: k) (m :: k1 -> Type) (a :: k1)
+ Data.Mapping: newtype AlgebraWrapper (c :: Type -> Constraint) (k2 :: k) (m :: k1 -> Type) (a :: k1)
- Data.Mapping: newtype OnPair (k4 :: k) (l :: k1) (m :: k2 -> Type) (n :: k3 -> k2) (v :: k3)
+ Data.Mapping: newtype OnPair (c :: k) (k5 :: k1) (l :: k2) (m :: k3 -> Type) (n :: k4 -> k3) (v :: k4)
- Data.Mapping: newtype OrdWrapper (k2 :: k) (m :: k1 -> Type) (v :: k1)
+ Data.Mapping: newtype OrdWrapper (c :: k) (k3 :: k1) (m :: k2 -> Type) (v :: k2)
- Data.Mapping: newtype PartialOrdWrapper (k2 :: k) (m :: k1 -> Type) (v :: k1)
+ Data.Mapping: newtype PartialOrdWrapper (c :: k) (k3 :: k1) (m :: k2 -> Type) (v :: k2)
- Data.Mapping: pairMappings :: forall k m u v a. (Mapping k m, Monoid a) => (u -> v -> a) -> m u -> m v -> a
+ Data.Mapping: pairMappings :: (Mapping c k m, Monoid a, c Void) => (u -> v -> a) -> m u -> m v -> a
- Data.Mapping.Decision: Decision :: !Base k1 m a v -> !Int -> Decision (k1 :: k) (m :: Type -> Type) a v
+ Data.Mapping.Decision: Decision :: Serial (Node k m a v) -> Decision k (m :: Type -> Type) a v
- Data.Mapping.Decision: data Node (k1 :: k) (m :: Type -> Type) a
+ Data.Mapping.Decision: data Node k (m :: Type -> Type) a v
- Data.Mapping.Decision: debugShow :: forall {k1} a v (m :: Type -> Type) (k2 :: k1). (Show a, Show v, Show (m Int)) => Decision k2 m a v -> String
+ Data.Mapping.Decision: debugShow :: forall k (m :: Type -> Type) a v. (Mapping Eq k m, Ord a, Ord v, Show a, Show v, Show (m Int), forall x. Ord x => Ord (m x)) => Decision k m a v -> String
- Data.Mapping.Decision: genTest :: Boolean b => a -> Decision Bool OnBool a b
+ Data.Mapping.Decision: genTest :: (Ord a, Ord b, Boolean b) => a -> Decision Bool OnBool a b
- Data.Mapping.Decision: restrict :: forall (m :: Type -> Type) v a k. (Ord (m Int), Ord v, Ord a, Mapping k m) => (a -> Maybe k) -> Decision k m a v -> Decision k m a v
+ Data.Mapping.Decision: restrict :: forall k (m :: Type -> Type) a v. (Mapping Eq k m, Ord a, Ord v, forall x. Ord x => Ord (m x)) => (a -> Maybe k) -> Decision k m a v -> Decision k m a v
- Data.Mapping.Decision: test :: a -> Decision Bool OnBool a Bool
+ Data.Mapping.Decision: test :: Ord a => a -> Decision Bool OnBool a Bool
Files
- CHANGELOG.md +5/−0
- README.md +13/−22
- examples/View.hs +3/−3
- mappings.cabal +15/−10
- src/Data/Bijection.hs +0/−83
- src/Data/Mapping.hs +232/−113
- src/Data/Mapping/Decision.hs +829/−651
- src/Data/Mapping/MapWithDefault.hs +76/−18
- src/Data/Mapping/Piecewise.hs +109/−81
- src/Data/Mapping/Util.hs +0/−17
- test/Data/Mapping/DecisionSpec.hs +130/−73
CHANGELOG.md view
@@ -1,3 +1,8 @@+## [0.4.0.0] - 2026-02-18++* Constraint polymorphism+* Rewrite of the `Data.Mapping.Decision` module+ ## [0.3.1.0] - 2024-05-20 * Support for GHC 9.10
README.md view
@@ -1,30 +1,21 @@ # Mappings -## What's it do?--This package does two jobs:--* It offers a general typeclass [`Mapping`](src/Data/Mapping.hs) for- types which represent functions `k -> v` (for fixed `k`, but- arbitrary ordered `v`).-- There are some fairly straightforward examples which build up- mappings where `k` is `Either`, or a pair, or `Maybe`, or `Bool`.--* Three less trivial implementations are provided:-- * [Decision diagrams](src/Data/Mapping/Decision.hs), with nodes- which may themselves be an arbitrary `Mapping` (there is some- code for viewing these in the `examples` directory);+This package offers a general typeclass+[`Mapping`](src/Data/Mapping.hs) for data structures which represent+functions `k -> v` (possibly for fixed `k`, but arbitrary ordered+`v`). - * [Piecewise constant maps](src/Data/Mapping/Piecewise.hs) on an- ordered domain `k`;+There are some fairly straightforward examples: constant mappings, and+those which build up mappings where `k` is `Either`, or a pair, or+`Maybe`, or `Bool`. - * [Maps equipped with a default value](src/Data/Mapping/MapWithDefault.hs).+Three less trivial implementations are provided: +* [Decision diagrams](src/Data/Mapping/Decision.hs), with nodes+ which may themselves be an arbitrary `Mapping`; -## Why did I bother?+* [Piecewise constant maps](src/Data/Mapping/Piecewise.hs) on an+ ordered domain `k`; -The aim is to use decision diagrams with nodes that are piecewise-constant maps to store monomials for Grobner basis algorithms.+* [Maps equipped with a default value](src/Data/Mapping/MapWithDefault.hs).
examples/View.hs view
@@ -43,10 +43,10 @@ putStrLn "" do- putStrLn " independent sets in C_100"+ putStrLn " independent sets in C_10" putStrLn "-----------------------------"- let l2 = (100,1):[(n,n+1) | n <- [1..99]]- let l3 = (99,100,1):(100,1,2):[(n,n+1,n+2) | n <- [1..98]]+ let l2 = (10,1):[(n,n+1) | n <- [1..9]]+ let l3 = (9,10,1):(10,1,2):[(n,n+1,n+2) | n <- [1..8]] let independent = all (\(i,j) -> not (test i && test j)) l2 let maximal = all (\(i,j,k) -> test i || test j || test k) l3 let t = independent && maximal :: Decision Bool OnBool Int Bool
mappings.cabal view
@@ -1,11 +1,11 @@ cabal-version: 2.2 --- This file has been generated from package.yaml by hpack version 0.38.1.+-- This file has been generated from package.yaml by hpack version 0.39.1. -- -- see: https://github.com/sol/hpack name: mappings-version: 0.3.3.0+version: 0.4.0.0 synopsis: Types which represent functions k -> v description: A typeclass and a number of implementations; please read README.md on github category: Data structures@@ -13,7 +13,7 @@ bug-reports: https://github.com/jcranch/mapping/issues author: James Cranch maintainer: j.d.cranch@sheffield.ac.uk-copyright: 2023-25 James Cranch+copyright: 2023-26 James Cranch license: BSD-3-Clause build-type: Simple extra-doc-files:@@ -26,7 +26,6 @@ library exposed-modules:- Data.Bijection Data.Mapping Data.Mapping.Decision Data.Mapping.MapWithDefault@@ -40,12 +39,14 @@ src ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints build-depends:- base >=4.16 && <4.22+ base >=4.16 && <4.23 , cond >=0.5.1 && <0.6- , containers >=0.6.5 && <0.8+ , containers >=0.6.5 && <0.9 , formatting >=7.0.0 && <7.3 , indexed-traversable >=0.1.1 && <0.2 , partialord >=0.0.2 && <0.2+ , transformers ==0.6.*+ , trivial-constraint ==0.7.* default-language: GHC2021 executable view@@ -58,13 +59,15 @@ examples ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N build-depends:- base >=4.16 && <4.22+ base >=4.16 && <4.23 , cond >=0.5.1 && <0.6- , containers >=0.6.5 && <0.8+ , containers >=0.6.5 && <0.9 , formatting >=7.0.0 && <7.3 , indexed-traversable >=0.1.1 && <0.2 , mappings , partialord >=0.0.2 && <0.2+ , transformers ==0.6.*+ , trivial-constraint ==0.7.* default-language: GHC2021 test-suite mapping@@ -83,12 +86,14 @@ build-tool-depends: hspec-discover:hspec-discover ==2.11.* build-depends:- base >=4.16 && <4.22+ base >=4.16 && <4.23 , cond >=0.5.1 && <0.6- , containers >=0.6.5 && <0.8+ , containers >=0.6.5 && <0.9 , formatting >=7.0.0 && <7.3 , hspec ==2.11.* , indexed-traversable >=0.1.1 && <0.2 , mappings , partialord >=0.0.2 && <0.2+ , transformers ==0.6.*+ , trivial-constraint ==0.7.* default-language: GHC2021
− src/Data/Bijection.hs
@@ -1,83 +0,0 @@-{-# LANGUAGE CPP #-}--module Data.Bijection where--#if MIN_VERSION_GLASGOW_HASKELL(9,6,0,0)-#else-import Control.Applicative (liftA2)-#endif-import Data.IntMap.Strict (IntMap)-import qualified Data.IntMap.Strict as IM-import qualified Data.IntMap.Merge.Strict as IM---compatibleInsert :: (Eq a) => Int -> a -> IntMap a -> Maybe (IntMap a)-compatibleInsert x y = let- f (Just z) = if y == z then Just (Just y) else Nothing- f Nothing = Just (Just y)- in IM.alterF f x--compatibleUnion :: (Eq a) => IntMap a -> IntMap a -> Maybe (IntMap a)-compatibleUnion = let- f _ x y = if x == y then Just x else Nothing- in IM.mergeA IM.preserveMissing IM.preserveMissing (IM.zipWithAMatched f)--data Bij = Bij {- rightwards :: IntMap Int,- leftwards :: IntMap Int-} deriving (Eq, Ord)--empty :: Bij-empty = Bij IM.empty IM.empty--singleton :: Int -> Int -> Bij-singleton x y = Bij (IM.singleton x y) (IM.singleton y x)--match :: Int -> Int -> Bij -> Maybe Bij-match x y (Bij r l) = liftA2 Bij (compatibleInsert x y r) (compatibleInsert y x l)--combine :: Bij -> Bij -> Maybe Bij-combine (Bij r1 l1) (Bij r2 l2) = liftA2 Bij (compatibleUnion r1 r2) (compatibleUnion l1 l2)--pop :: Bij -> Maybe ((Int, Int), Bij)-pop (Bij r l) = case IM.minViewWithKey r of- Nothing -> Nothing- Just ((i, j), r') -> Just ((i, j), Bij r' (IM.delete j l))---- | Don't check consistency, just take a union-unsafeUnion :: Bij -> Bij -> Bij-unsafeUnion (Bij r1 l1) (Bij r2 l2) = Bij (IM.union r1 r2) (IM.union l1 l2)---- | Don't check consistency, just take a diff-unsafeDifference :: Bij -> Bij -> Bij-unsafeDifference (Bij r1 l1) (Bij r2 l2) = Bij (IM.difference r1 r2) (IM.difference l1 l2)----- | A newtype, just to get a partial monoidal structure representing consistent--- unions.-newtype MaybeBij = MaybeBij {- getMaybeBij :: Maybe Bij-} deriving (Eq, Ord)--instance Semigroup MaybeBij where- MaybeBij Nothing <> _ = MaybeBij Nothing- _ <> MaybeBij Nothing = MaybeBij Nothing- MaybeBij (Just a) <> MaybeBij (Just b) = MaybeBij (combine a b)--instance Monoid MaybeBij where- mempty = MaybeBij (Just empty)--msingleton :: Int -> Int -> MaybeBij-msingleton i j = MaybeBij . Just $ singleton i j---closeBijection :: (Int -> Int -> Maybe Bij) -> Bij -> Maybe Bij-closeBijection f s = let- inner a n = case pop n of- Nothing -> Just a- Just ((i,j), n') -> case f i j of- Nothing -> Nothing- Just b -> case combine a b of- Nothing -> Nothing- Just a' -> inner a' (unsafeUnion n' (unsafeDifference b a))- in inner s s
src/Data/Mapping.hs view
@@ -1,27 +1,23 @@-{-# LANGUAGE- CPP,- DeriveFunctor,- DerivingVia,- FlexibleInstances,- FunctionalDependencies,- QuantifiedConstraints,- ScopedTypeVariables- #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE QuantifiedConstraints #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UndecidableInstances #-} module Data.Mapping where -#if MIN_VERSION_GLASGOW_HASKELL(9,6,0,0)-#else-import Control.Applicative (liftA2)-#endif import Prelude hiding (not, (&&), (||))-import Data.Algebra.Boolean (Boolean(..))+import Data.Algebra.Boolean (Boolean(..), AllB(..))+import Data.Bool (bool)+import Data.Constraint.Trivial (Unconstrained) import Data.Foldable.WithIndex (FoldableWithIndex(..)) import Data.Function (on) import Data.Functor.Const (Const(..)) import Data.Functor.Identity (Identity(..))-import Data.Kind (Type)-import Data.Monoid (All(..))+import Data.Kind (Constraint, Type) import Data.PartialOrd import Data.Set (Set) import qualified Data.Set as S@@ -34,39 +30,86 @@ -- values that appear. Given that a value can be associated with a -- very large collection of keys, the only folds that normally make -- sense are those over idempotent monoids.-class Foldable m => Mapping k m | m -> k where+class (Foldable m, forall x. c x => c (m x)) => Mapping (c :: Type -> Constraint) (k :: Type) (m :: Type -> Type) | m -> k, m -> c where++ -- | Form a constant Mapping cst :: v -> m v + -- | Use a Mapping as a function act :: m v -> k -> v - isConst :: Ord v => m v -> Maybe v+ -- | Is the Mapping a constant (and if so with what value)?+ isConst :: c v => m v -> Maybe v - mtraverse :: (Applicative f, Ord v) => (u -> f v) -> m u -> f (m v)+ -- | A constrained Traverse+ mtraverse :: (Applicative f, c v) => (u -> f v) -> m u -> f (m v) - mmap :: Ord v => (u -> v) -> m u -> m v+ -- | A constrained Functor+ mmap :: c v => (u -> v) -> m u -> m v mmap p = runIdentity . mtraverse (Identity . p) - mergeA :: (Applicative f, Ord w) => (u -> v -> f w) -> m u -> m v -> f (m w)+ -- | Merge two Mappings, valued in an applicative+ mergeA :: (Applicative f, c w) => (u -> v -> f w) -> m u -> m v -> f (m w) - merge :: Ord w => (u -> v -> w) -> m u -> m v -> m w+ -- | Merge two Mappings+ merge :: c w => (u -> v -> w) -> m u -> m v -> m w merge p m n = let q x y = Identity $ p x y in runIdentity $ mergeA q m n + -- | Merge three Mappings+ merge3 :: c x+ => (u -> v -> w -> x)+ -> m u -> m v -> m w -> m x --- | A simultaneous foldMap over two maps-pairMappings :: forall k m u v a. (Mapping k m, Monoid a) => (u -> v -> a) -> m u -> m v -> a-pairMappings p m n = let- q :: u -> v -> Const a Void- q x y = Const $ p x y- in getConst (mergeA q m n)+ -- | Merge three Mappings+ mergeA3 :: (Applicative f, c x)+ => (u -> v -> w -> f x)+ -> m u -> m v -> m w -> f (m x) + -- | A simultaneous foldMap over two maps; pairMappings is to+ -- foldMap as mmerge is to mmap+ pairMappings :: forall a u v. (Monoid a, c Void) => (u -> v -> a) -> m u -> m v -> a+ pairMappings p m n = let+ q :: u -> v -> Const a Void+ q x y = Const $ p x y+ in getConst (mergeA q m n)++ -- | A monad-like structure+ bind :: (c u, c v, Ord u, c (Either v u)) => (u -> m v) -> m u -> m v+ bind f m = let+ start [] = error "bind: expected some values"+ start [x] = f x+ start (x:xs) = let+ p y z = if y == x then Left z else Right y+ in continue xs $ merge p m (f x)+ continue [] _ = error "bind: expected more values"+ continue [x] n = let+ p (Left z) _ = z+ p (Right _) z = z+ in merge p n (f x)+ continue (x:xs) n = let+ p (Left z) _ = Left z+ p (Right y) z = if y == x then Left z else Right y+ in continue xs $ merge p n (f x)+ in start . S.toList $ values m+++-- | This commonly-used function is the reason why we have three-way+-- merges in the typeclass+boolBind :: (Mapping c k m, c v) => m v -> m v -> m Bool -> m v+boolBind = merge3 bool+++values :: (Mapping c k m, Ord v) => m v -> Set v+values = foldMap S.singleton++ -- | What values can these two take simultaneously?-mutualValues :: (Ord u, Ord v, Mapping k m) => m u -> m v -> Set (u, v)+mutualValues :: (Ord u, Ord v, c Void, Mapping c k m) => m u -> m v -> Set (u, v) mutualValues = pairMappings $ curry S.singleton - -- | A class representing data structures which have a concept of neighbouring -- values class Neighbourly m where@@ -76,15 +119,15 @@ -- | A wrapper for representing pointwise algebraic structures on a Mapping -- -- Eventually would like to use this only for "deriving via"-newtype AlgebraWrapper k m a = AlgebraWrapper { algebraUnwrap :: m a }+newtype AlgebraWrapper (c :: Type -> Constraint) k m a = AlgebraWrapper { algebraUnwrap :: m a } -instance (Mapping k m, Ord a, Semigroup a) => Semigroup (AlgebraWrapper k m a) where+instance (Mapping c k m, c a, Semigroup a) => Semigroup (AlgebraWrapper c k m a) where (<>) = (AlgebraWrapper .) . merge (<>) `on` algebraUnwrap -instance (Mapping k m, Ord a, Monoid a) => Monoid (AlgebraWrapper k m a) where+instance (Mapping c k m, c a, Monoid a) => Monoid (AlgebraWrapper c k m a) where mempty = AlgebraWrapper $ cst mempty -instance (Mapping k m, Ord a, Num a) => Num (AlgebraWrapper k m a) where+instance (Mapping c k m, c a, Num a) => Num (AlgebraWrapper c k m a) where (+) = (AlgebraWrapper .) . merge (+) `on` algebraUnwrap (-) = (AlgebraWrapper .) . merge (-) `on` algebraUnwrap (*) = (AlgebraWrapper .) . merge (*) `on` algebraUnwrap@@ -93,7 +136,7 @@ negate = AlgebraWrapper . mmap negate . algebraUnwrap signum = AlgebraWrapper . mmap signum . algebraUnwrap -instance (Mapping k m, Ord a, Boolean a) => Boolean (AlgebraWrapper k m a) where+instance (Mapping c k m, c a, Boolean a) => Boolean (AlgebraWrapper c k m a) where true = AlgebraWrapper $ cst true false = AlgebraWrapper $ cst false not = AlgebraWrapper . mmap not . algebraUnwrap@@ -104,20 +147,26 @@ (<-->) = (AlgebraWrapper .) . merge (<-->) `on` algebraUnwrap + -- | Constant functions (on any domain) newtype Constant k v = Constant { constantValue :: v }+ deriving (Eq, Ord) instance Foldable (Constant k) where foldMap f (Constant a) = f a -instance Mapping k (Constant k) where+instance Mapping Unconstrained k (Constant k) where cst = Constant act (Constant x) _ = x+ isConst (Constant x) = Just x mmap f (Constant x) = Constant $ f x mtraverse f (Constant x) = Constant <$> f x- isConst (Constant x) = Just x merge f (Constant x) (Constant y) = Constant $ f x y+ merge3 f (Constant x) (Constant y) (Constant z) = Constant $ f x y z mergeA f (Constant x) (Constant y) = Constant <$> f x y+ mergeA3 f (Constant x) (Constant y) (Constant z) = Constant <$> f x y z+ pairMappings f (Constant x) (Constant y) = f x y+ bind f (Constant x) = f x instance Neighbourly (Constant k) where neighbours = const S.empty@@ -152,6 +201,7 @@ Constant x --> Constant y = Constant (x --> y) + -- | Binary decisions, as functions defined on Bool data OnBool a = OnBool { onFalse :: a,@@ -167,49 +217,57 @@ instance Traversable OnBool where traverse f (OnBool x y) = liftA2 OnBool (f x) (f y) -instance Mapping Bool OnBool where+instance Mapping Eq Bool OnBool where cst x = OnBool x x- mmap = fmap- mtraverse = traverse act (OnBool x _) False = x act (OnBool _ x) True = x isConst (OnBool x y) | x == y = Just x | otherwise = Nothing- mergeA h (OnBool x1 y1) (OnBool x2 y2) = liftA2 OnBool (h x1 x2) (h y1 y2)- merge h (OnBool x1 y1) (OnBool x2 y2) = OnBool (h x1 x2) (h y1 y2)+ mmap = fmap+ mtraverse = traverse+ mergeA h (OnBool x1 y1) (OnBool x2 y2) =+ liftA2 OnBool (h x1 x2) (h y1 y2)+ merge h (OnBool x1 y1) (OnBool x2 y2) =+ OnBool (h x1 x2) (h y1 y2)+ mergeA3 h (OnBool x1 y1) (OnBool x2 y2) (OnBool x3 y3) =+ liftA2 OnBool (h x1 x2 x3) (h y1 y2 y3)+ merge3 h (OnBool x1 y1) (OnBool x2 y2) (OnBool x3 y3) =+ OnBool (h x1 x2 x3) (h y1 y2 y3)+ pairMappings p (OnBool x1 y1) (OnBool x2 y2) = p x1 x2 <> p y1 y2+ bind f (OnBool u v) = OnBool (onFalse (f u)) (onTrue (f v)) instance Neighbourly OnBool where neighbours (OnBool x y) | x == y = S.empty | otherwise = S.singleton (x, y) -deriving via (AlgebraWrapper Bool OnBool a)- instance (Ord a, Semigroup a) => Semigroup (OnBool a)+deriving via (AlgebraWrapper Eq Bool OnBool a)+ instance (Eq a, Semigroup a) => Semigroup (OnBool a) -deriving via (AlgebraWrapper Bool OnBool a)- instance (Ord a, Monoid a) => Monoid (OnBool a)+deriving via (AlgebraWrapper Eq Bool OnBool a)+ instance (Eq a, Monoid a) => Monoid (OnBool a) -deriving via (AlgebraWrapper Bool OnBool a)- instance (Ord a, Num a) => Num (OnBool a)+deriving via (AlgebraWrapper Eq Bool OnBool a)+ instance (Eq a, Num a) => Num (OnBool a) -deriving via (AlgebraWrapper Bool OnBool b)- instance (Ord b, Boolean b) => Boolean (OnBool b)+deriving via (AlgebraWrapper Eq Bool OnBool b)+ instance (Eq b, Boolean b) => Boolean (OnBool b) -- | Maps on Maybe-data OnMaybe k m v = OnMaybe {+data OnMaybe c k m v = OnMaybe { onNothing :: v, onJust :: m v-}+} deriving (Eq, Ord) -instance Foldable m => Foldable (OnMaybe k m) where+instance Foldable m => Foldable (OnMaybe c k m) where foldMap f (OnMaybe x a) = f x <> foldMap f a -instance FoldableWithIndex k m => FoldableWithIndex (Maybe k) (OnMaybe k m) where+instance FoldableWithIndex k m => FoldableWithIndex (Maybe k) (OnMaybe c k m) where ifoldMap f (OnMaybe x a) = f Nothing x <> ifoldMap (f . Just) a -instance Mapping k m => Mapping (Maybe k) (OnMaybe k m) where+instance (forall x. c x => Eq x, forall x. c x => c (OnMaybe c k m x), Mapping c k m) => Mapping c (Maybe k) (OnMaybe c k m) where cst x = OnMaybe x $ cst x mmap p (OnMaybe x a) = OnMaybe (p x) (mmap p a) mtraverse p (OnMaybe x a) = liftA2 OnMaybe (p x) (mtraverse p a)@@ -218,37 +276,48 @@ isConst (OnMaybe x a) = do y <- isConst a if x == y then Just x else Nothing- merge h (OnMaybe x a) (OnMaybe y b) = OnMaybe (h x y) (merge h a b)- mergeA h (OnMaybe x a) (OnMaybe y b) = liftA2 OnMaybe (h x y) (mergeA h a b)+ merge h (OnMaybe x a) (OnMaybe y b) =+ OnMaybe (h x y) (merge h a b)+ mergeA h (OnMaybe x a) (OnMaybe y b) =+ liftA2 OnMaybe (h x y) (mergeA h a b)+ merge3 h (OnMaybe x a) (OnMaybe y b) (OnMaybe z c) =+ OnMaybe (h x y z) (merge3 h a b c)+ mergeA3 h (OnMaybe x a) (OnMaybe y b) (OnMaybe z c) =+ liftA2 OnMaybe (h x y z) (mergeA3 h a b c)+ pairMappings p (OnMaybe x a) (OnMaybe y b) = p x y <> pairMappings p a b+ bind f (OnMaybe x m) = OnMaybe (onNothing (f x)) (bind (onJust . f) m) -deriving via (AlgebraWrapper (Maybe k) (OnMaybe k m) a)- instance (Mapping k m, Ord a, Semigroup a) => Semigroup (OnMaybe k m a)+deriving via (AlgebraWrapper c (Maybe k) (OnMaybe c k m) a)+ instance (forall x. c x => Eq x, forall x. c x => c (OnMaybe c k m x), Mapping c k m, c a, Semigroup a) => Semigroup (OnMaybe c k m a) -deriving via (AlgebraWrapper (Maybe k) (OnMaybe k m) a)- instance (Mapping k m, Ord a, Monoid a) => Monoid (OnMaybe k m a)+deriving via (AlgebraWrapper c (Maybe k) (OnMaybe c k m) a)+ instance (forall x. c x => Eq x, forall x. c x => c (OnMaybe c k m x), Mapping c k m, c a, Monoid a) => Monoid (OnMaybe c k m a) -deriving via (AlgebraWrapper (Maybe k) (OnMaybe k m) a)- instance (Mapping k m, Ord a, Num a) => Num (OnMaybe k m a)+deriving via (AlgebraWrapper c (Maybe k) (OnMaybe c k m) a)+ instance (forall x. c x => Eq x, forall x. c x => c (OnMaybe c k m x), Mapping c k m, c a, Num a) => Num (OnMaybe c k m a) -deriving via (AlgebraWrapper (Maybe k) (OnMaybe k m) a)- instance (Mapping k m, Ord a, Boolean a) => Boolean (OnMaybe k m a)+deriving via (AlgebraWrapper c (Maybe k) (OnMaybe c k m) a)+ instance (forall x. c x => Eq x, forall x. c x => c (OnMaybe c k m x), Mapping c k m, c a, Boolean a) => Boolean (OnMaybe c k m a) -- | Maps on Either-data OnEither k l m n v = OnEither {+data OnEither (c :: Type -> Constraint) (k :: Type) (l :: Type) (m :: Type -> Type) (n :: Type -> Type) (v :: Type) = OnEither { onLeft :: m v, onRight :: n v } deriving (Eq, Ord) -instance (Foldable m, Foldable n) => Foldable (OnEither k l m n) where+instance (Foldable m, Foldable n) => Foldable (OnEither c k l m n) where foldMap p (OnEither f g) = foldMap p f <> foldMap p g -instance (FoldableWithIndex k m, FoldableWithIndex l n) => FoldableWithIndex (Either k l) (OnEither k l m n) where+instance (FoldableWithIndex k m, FoldableWithIndex l n)+ => FoldableWithIndex (Either k l) (OnEither c k l m n) where ifoldMap p (OnEither f g) = ifoldMap (p . Left) f <> ifoldMap (p . Right) g -instance (Mapping k m,- Mapping l n)- => Mapping (Either k l) (OnEither k l m n) where+instance (Mapping c k m,+ Mapping c l n,+ forall x. c x => Eq x,+ forall x. c x => c (OnEither c k l m n x))+ => Mapping c (Either k l) (OnEither c k l m n) where cst x = OnEither (cst x) (cst x) mmap p (OnEither f g) = OnEither (mmap p f) (mmap p g) mtraverse p (OnEither f g) = liftA2 OnEither (mtraverse p f) (mtraverse p g)@@ -258,34 +327,83 @@ x <- isConst f y <- isConst g if x == y then Just x else Nothing- mergeA h (OnEither f1 g1) (OnEither f2 g2) = liftA2 OnEither (mergeA h f1 f2) (mergeA h g1 g2)- merge h (OnEither f1 g1) (OnEither f2 g2) = OnEither (merge h f1 f2) (merge h g1 g2)+ mergeA h (OnEither f1 g1) (OnEither f2 g2) =+ liftA2 OnEither (mergeA h f1 f2) (mergeA h g1 g2)+ merge h (OnEither f1 g1) (OnEither f2 g2) =+ OnEither (merge h f1 f2) (merge h g1 g2)+ mergeA3 p (OnEither f1 g1) (OnEither f2 g2) (OnEither f3 g3) =+ liftA2 OnEither (mergeA3 p f1 f2 f3) (mergeA3 p g1 g2 g3)+ merge3 p (OnEither f1 g1) (OnEither f2 g2) (OnEither f3 g3) =+ OnEither (merge3 p f1 f2 f3) (merge3 p g1 g2 g3)+ pairMappings p (OnEither f1 g1) (OnEither f2 g2) = pairMappings p f1 f2 <> pairMappings p g1 g2+ bind f (OnEither u v) = OnEither (bind (onLeft . f) u) (bind (onRight . f) v) -deriving via (AlgebraWrapper (Either k l) (OnEither k l (m :: Type -> Type) n) a)- instance (Mapping k m, Mapping l n, Ord a, Semigroup a) => Semigroup (OnEither k l m n a)+deriving via (AlgebraWrapper c (Either k l) (OnEither c k l (m :: Type -> Type) n) a)+ instance (Mapping c k m,+ Mapping c l n,+ c a,+ forall x. c x => Eq x,+ forall x. c x => c (OnEither c k l m n x),+ Semigroup a) => Semigroup (OnEither c k l m n a) -deriving via (AlgebraWrapper (Either k l) (OnEither k l (m :: Type -> Type) n) a)- instance (Mapping k m, Mapping l n, Ord a, Monoid a) => Monoid (OnEither k l m n a)+deriving via (AlgebraWrapper c (Either k l) (OnEither c k l (m :: Type -> Type) n) a)+ instance (Mapping c k m,+ Mapping c l n,+ c a,+ forall x. c x => Eq x,+ forall x. c x => c (OnEither c k l m n x),+ Monoid a) => Monoid (OnEither c k l m n a) -deriving via (AlgebraWrapper (Either k l) (OnEither k l (m :: Type -> Type) n) a)- instance (Mapping k m, Mapping l n, Ord a, Num a) => Num (OnEither k l m n a)+deriving via (AlgebraWrapper c (Either k l) (OnEither c k l (m :: Type -> Type) n) a)+ instance (Mapping c k m,+ Mapping c l n,+ c a,+ forall x. c x => Eq x,+ forall x. c x => c (OnEither c k l m n x),+ Num a) => Num (OnEither c k l m n a) -deriving via (AlgebraWrapper (Either k l) (OnEither k l (m :: Type -> Type) n) a)- instance (Mapping k m, Mapping l n, Ord a, Boolean a) => Boolean (OnEither k l m n a)+deriving via (AlgebraWrapper c (Either k l) (OnEither c k l (m :: Type -> Type) n) a)+ instance (Mapping c k m,+ Mapping c l n,+ c a,+ forall x. c x => Eq x,+ forall x. c x => c (OnEither c k l m n x),+ Boolean a) => Boolean (OnEither c k l m n a) +newtype Reconstrained (c :: Type -> Constraint) (d :: Type -> Constraint) (k :: Type) (m :: Type -> Type) (a :: Type) = Reconstrained {+ preconstrained :: m a+} deriving (Eq, Ord, Foldable, FoldableWithIndex k, Neighbourly)++instance (forall x. d x => c x, forall x. d x => d (Reconstrained c d k m x), Mapping c k m) => Mapping d k (Reconstrained c d k m) where+ cst = Reconstrained . cst+ act = act . preconstrained+ isConst = isConst . preconstrained+ mtraverse f = fmap Reconstrained . mtraverse f . preconstrained+ mmap f = Reconstrained . mmap f . preconstrained+ mergeA p (Reconstrained m) (Reconstrained n) = Reconstrained <$> mergeA p m n+ merge p (Reconstrained m) (Reconstrained n) = Reconstrained $ merge p m n+ mergeA3 p (Reconstrained m) (Reconstrained n) (Reconstrained o) = Reconstrained <$> mergeA3 p m n o+ merge3 p (Reconstrained m) (Reconstrained n) (Reconstrained o) = Reconstrained $ merge3 p m n o++ -- | Maps on pairs-newtype OnPair k l m n v = OnPair {+newtype OnPair c k l m n v = OnPair { asComposite :: m (n v) } deriving (Eq, Ord) -instance (Foldable m, Foldable n) => Foldable (OnPair k l m n) where+instance (Foldable m, Foldable n) => Foldable (OnPair c k l m n) where foldMap p (OnPair f) = foldMap (foldMap p) f -instance (Mapping k m,- Mapping l n,- forall v. Ord v => Ord (n v))- => Mapping (k, l) (OnPair k l m n) where+instance (FoldableWithIndex k m, FoldableWithIndex l n) => FoldableWithIndex (k,l) (OnPair c k l m n) where+ ifoldMap p (OnPair f) = let+ h x = ifoldMap (p . (x,))+ in ifoldMap h f++instance (Mapping c k m,+ Mapping c l n,+ forall x. c x => c (OnPair c k l m n x))+ => Mapping c (k, l) (OnPair c k l m n) where cst x = OnPair . cst $ cst x mmap p (OnPair f) = OnPair (mmap (mmap p) f) mtraverse p (OnPair f) = OnPair <$> mtraverse (mtraverse p) f@@ -293,54 +411,55 @@ isConst (OnPair f) = isConst =<< isConst f mergeA h (OnPair f) (OnPair g) = OnPair <$> mergeA (mergeA h) f g merge h (OnPair f) (OnPair g) = OnPair $ merge (merge h) f g+ merge3 p (OnPair f) (OnPair g) (OnPair h) = OnPair $ merge3 (merge3 p) f g h+ mergeA3 p (OnPair f) (OnPair g) (OnPair h) = OnPair <$> mergeA3 (mergeA3 p) f g h+ pairMappings p (OnPair f) (OnPair g) = pairMappings (pairMappings p) f g -deriving via (AlgebraWrapper (k, l) (OnPair k l (m :: Type -> Type) (n :: Type -> Type)) a)- instance (Mapping k m, Mapping l n, Ord a, Semigroup a, forall v. Ord v => Ord (n v)) => Semigroup (OnPair k l m n a)+deriving via (AlgebraWrapper (c :: Type -> Constraint) (k, l) (OnPair c k l (m :: Type -> Type) (n :: Type -> Type)) a)+ instance (Mapping c k m, Mapping c l n,+ forall x. c x => c (OnPair c k l m n x), c a, Semigroup a) => Semigroup (OnPair c k l m n a) -deriving via (AlgebraWrapper (k, l) (OnPair k l (m :: Type -> Type) (n :: Type -> Type)) a)- instance (Mapping k m, Mapping l n, Ord a, Monoid a, forall v. Ord v => Ord (n v)) => Monoid (OnPair k l m n a)+deriving via (AlgebraWrapper (c :: Type -> Constraint) (k, l) (OnPair c k l (m :: Type -> Type) (n :: Type -> Type)) a)+ instance (Mapping c k m, Mapping c l n,+ forall x. c x => c (OnPair c k l m n x), c a, Monoid a) => Monoid (OnPair c k l m n a) -deriving via (AlgebraWrapper (k, l) (OnPair k l (m :: Type -> Type) (n :: Type -> Type)) a)- instance (Mapping k m, Mapping l n, Ord a, Num a, forall v. Ord v => Ord (n v)) => Num (OnPair k l m n a)+deriving via (AlgebraWrapper (c :: Type -> Constraint) (k, l) (OnPair c k l (m :: Type -> Type) (n :: Type -> Type)) a)+ instance (Mapping c k m, Mapping c l n,+ forall x. c x => c (OnPair c k l m n x), c a, Num a) => Num (OnPair c k l m n a) -deriving via (AlgebraWrapper (k, l) (OnPair k l (m :: Type -> Type) (n :: Type -> Type)) b)- instance (Mapping k m, Mapping l n, Ord b, Boolean b, forall v. Ord v => Ord (n v)) => Boolean (OnPair k l m n b)+deriving via (AlgebraWrapper (c :: Type -> Constraint) (k, l) (OnPair c k l (m :: Type -> Type) (n :: Type -> Type)) b)+ instance (Mapping c k m, Mapping c l n,+ forall x. c x => c (OnPair c k l m n x), c b, Boolean b) => Boolean (OnPair c k l m n b) --- Is the first a subset of the second?------ With a future version of cond, we should be able to generalise this-isSubset :: Mapping k m => m Bool -> m Bool -> Bool+-- | Is the first a subset of the second?+isSubset :: (Boolean b, c Void, Mapping c k m) => m b -> m b -> b isSubset m n = let- p True False = All False- p _ _ = All True- in getAll $ pairMappings p m n+ p x y = AllB (x --> y)+ in getAllB $ pairMappings p m n --- Are the two true on distinct values?------ Again, with a future version of cond, we should be able to generalise this-isDisjoint :: Mapping k m => m Bool -> m Bool -> Bool+-- | Are the two true on distinct values?+isDisjoint :: (Boolean b, c Void, Mapping c k m) => m b -> m b -> b isDisjoint m n = let- p True True = All False- p _ _ = All True- in getAll $ pairMappings p m n+ p x y = AllB (not (x && y))+ in getAllB $ pairMappings p m n -- | A wrapper to allow defining `PartialOrd` instances on mappings whose keys -- have an `Ord` instance.-newtype OrdWrapper k m v = OrdWrapper {+newtype OrdWrapper c k m v = OrdWrapper { getOrdMapping :: m v } -instance (Mapping k m, Ord v) => PartialOrd (OrdWrapper k m v) where+instance (Mapping c k m, c Void, Ord v) => PartialOrd (OrdWrapper c k m v) where compare' (OrdWrapper u) (OrdWrapper v) = pairMappings fromCompare u v -- | A wrapper to allow defining `PartialOrd` instances on mappings whose keys -- have a `PartialOrd` instance.-newtype PartialOrdWrapper k m v = PartialOrdWrapper {+newtype PartialOrdWrapper c k m v = PartialOrdWrapper { getPartialOrdMapping :: m v } -instance (Mapping k m, PartialOrd v) => PartialOrd (PartialOrdWrapper k m v) where+instance (Mapping c k m, c Void, PartialOrd v) => PartialOrd (PartialOrdWrapper c k m v) where compare' (PartialOrdWrapper u) (PartialOrdWrapper v) = pairMappings compare' u v
src/Data/Mapping/Decision.hs view
@@ -1,652 +1,830 @@-{-# LANGUAGE- CPP,- DerivingVia,- MultiParamTypeClasses,- OverloadedStrings,- RankNTypes,- StandaloneDeriving,- TupleSections- #-}---- | Decision diagrams, parametric in the mapping type for the decisions.------ This is inspired by binary decision diagrams (as described in detail in--- Knuth's The Art of Computer Programming, volume 4A); these are the specific--- case where m is `BoolMapping` and v is `Bool`. Our algorithms are mostly--- straightforward generalisations of those considered there.------- TODO--- * Format types of functions better--- * Decisions go upwards in order currently; should they go--- downwards, to coincide with lexicographical orderings on maps--- and hence maybe make smaller decision diagrams?--- We can use Down if necessary to amend this--- * Increase test coverage--- * Examples:--- - finding optima--- - finding random elements--- (as examples of the more general functions, already coded, I hope)--- * Separate out "Base" stuff into other modules?--- * Documentation------ MAYBE TO DO--- * Composition algorithm?--- * Optimisation by reordering-module Data.Mapping.Decision where--#if MIN_VERSION_GLASGOW_HASKELL(9,6,0,0)-#else-import Control.Applicative (liftA2)-#endif-import Control.Monad ((<=<))-import Data.Algebra.Boolean (Boolean(..))-import Data.Bifunctor (first)-import Data.Bijection (Bij)-import qualified Data.Bijection as B-import Data.Bits (complement)-import Data.Bool (bool)-import Data.Foldable (toList)-import Data.Foldable.WithIndex (FoldableWithIndex(..))-import Data.Functor.Identity (Identity(..))-import Data.IntSet (IntSet)-import qualified Data.IntSet as IS-import Data.Ord (comparing)-import Data.Sequence (Seq, (|>))-import qualified Data.Sequence as Q-import Data.Set (Set)-import qualified Data.Set as S-import Data.Map.Strict (Map)-import qualified Data.Map.Strict as M-import qualified Data.Map.Merge.Strict as M-import Data.Mapping.Util (insertIfAbsent)-import Formatting ((%))-import qualified Formatting as F--import Data.Mapping----- | A node of a decision diagram: which value do we scrutinise, and what do we--- do with it?-data Node k m a = Node {- nodeDecision :: !a,- nodeBranch :: !(m Int)-}--deriving instance (Eq a, Eq (m Int)) => Eq (Node k m a)--deriving instance (Ord a, Ord (m Int)) => Ord (Node k m a)----- | A decision diagram (with no preferred starting point), containing--- leaves (representing final values of the decision process) indexed--- from -1 downwards, and nodes (representing the need to scrutinise a--- value) indexed from 0 upwards-data Base k m a v = Base {- leaves :: Seq v,- nodes :: Seq (Node k m a)-}--baseLength :: Base k m a v -> Int-baseLength (Base l m) = Q.length l + Q.length m---- | A decision diagram with a starting point-data Decision k m a v = Decision {- base :: !(Base k m a v),- start :: !Int-}--decisionLength :: Decision k m a v -> Int-decisionLength = baseLength . base---- | A value for every node of a base-data BaseMap v = BaseMap {- onLeaves :: Seq v,- onNodes :: Seq v-}---- | Index a BaseMap-bindex :: BaseMap v -> Int -> v-bindex (BaseMap l m) x- | x < 0 = Q.index l $ complement x- | otherwise = Q.index m x----- | Close a set under an operation-closure :: (Int -> IntSet) -> IntSet -> IntSet-closure f = let- inner old new = case IS.minView new of- Nothing -> old- Just (x, new') -> let- old' = IS.insert x old- in inner old' (new' `IS.union` (f x `IS.difference` old'))- in inner IS.empty----- | A general kind of recursive function on a Base-baseRecurse :: (Ord c,- Mapping k m)- => (v -> c)- -- ^ What to do on a value- -> (a -> m c -> c)- -- ^ What do do on a node- -> Base k m a v- -- ^ Input base- -> BaseMap c-baseRecurse p q (Base l m) = let- l' = p <$> l- f v (Node x n) = v |> q x (mmap (bindex (BaseMap l' v)) n)- in BaseMap l' $ foldl f Q.empty m---- | A general kind of recursive function on a Decision-decisionRecurse :: (Ord c,- Mapping k m)- => (v -> c)- -- ^ What to do on a value- -> (a -> m c -> c)- -- ^ What do do on a node- -> Decision k m a v- -- ^ Input decision- -> c-decisionRecurse p q (Decision b s) = bindex (baseRecurse p q b) s----- | A general counting function-generalCounts :: (Ord a, Ord n, Mapping k m)- => (a -> a -> Int)- -- ^ In the list of decisions, how far apart are these?- -> a- -- ^ The first possible decision- -> a- -- ^ The last possible decision- -> (v -> n)- -- ^ The count of a value- -> (m n -> n)- -- ^ How to combine counts at a node- -> Decision k m a v- -- ^ The input decision diagram- -> n- -- ^ The count-generalCounts d x0 x1 onVal combine = let- d' Nothing Nothing = 2 + d x0 x1- d' Nothing (Just y) = 1 + d x0 y- d' (Just x) Nothing = 1 + d x x1- d' (Just x) (Just y) = d x y- p x (y, a) = let- q 1 v = v- q n v = q (n-1) . combine $ cst v- in q (d' x y) a- f x = (Nothing, onVal x)- g a m = let- b = Just a- in (b, combine $ mmap (p b) m)- in p Nothing . decisionRecurse f g---- | How many values are true in a decision diagram with integer leaves?-numberTrueGeneral :: Mapping k m => (m Integer -> Integer) -> Int -> Int -> Decision k m Int Bool -> Integer-numberTrueGeneral g x0 x1 = let- f a = if a then 1 else 0- in generalCounts subtract x0 x1 f g---- | How many values are True in a binary decision diagram with integer leaves?-numberTrue :: Int -> Int -> Decision Bool OnBool Int Bool -> Integer-numberTrue = numberTrueGeneral sum---- | Assignments of variables that result in True-chunksTrue :: (Mapping k m, FoldableWithIndex k m, Ord k, Ord a) => Decision k m a Bool -> [Map a k]-chunksTrue = let- f False = []- f True = [M.empty]- g a = ifoldMap (\x -> fmap (M.insert a x))- in decisionRecurse f g---- | All true values (may be a very long list even for reasonable Decisions)-listTrue :: forall k m a.- (Mapping k m,- FoldableWithIndex k m,- Ord k,- Ord a)- => Set a- -> Decision k m a Bool- -> [Map a k]-listTrue s = let- m = M.fromSet (const ()) s- u = ifoldMap (\i _ -> [i]) $ cst @k @m ()- fillIn = let- onL = M.traverseMissing (\_ () -> u)- onR = M.mapMissing (const (error "Expected a key"))- onB = M.zipWithMatched (\_ () -> id)- in M.mergeA onL onR onB- in fillIn m <=< chunksTrue---- | What is the best assignment of keys to values resulting in a--- value on which `p` is `True`?-bestSuchThat :: (Mapping k m, Ord k, Ord a, Ord v) => (v -> Bool) -> (forall w. a -> m w -> Maybe (k, w)) -> Decision k m a v -> Maybe ([(a,k)], v)-bestSuchThat p q = let- f x = if p x then Just ([], x) else Nothing- g i = uncurry (\x -> fmap (first ((i,x):))) <=< q i- in decisionRecurse f g---- | Build a sequence from key-value pairs; we take on trust that all--- values are represented once.-fromKeyVals :: (Foldable f) => f (Int,a) -> Seq a-fromKeyVals = fmap snd . Q.sortBy (comparing fst) . Q.fromList . toList----- | A data structure for work-in-progress decision diagrams-data Builder o k m a v = Builder {- leavesMap :: Map v Int,- nodesMap :: Map (Node k m a) Int,- fromOld :: Map o Int-}--emptyBuilder :: Builder o k m a v-emptyBuilder = Builder M.empty M.empty M.empty--addLeaf :: (Ord o,- Ord v)- => v- -> o- -> Builder o k m a v- -> Builder o k m a v-addLeaf x y (Builder l m o) = let- i = complement (M.size l)- (j, s) = insertIfAbsent x i l- o' = M.insert y j o- in case s of- Nothing -> Builder l m o'- Just l' -> Builder l' m o'--addNode :: (Ord o,- Ord (m Int),- Ord a,- Mapping k m)- => a- -> m o- -> o- -> Builder o k m a v- -> Builder o k m a v-addNode r a y (Builder l m o) = let- b = mmap (o M.!) a- in case isConst b of- Just j -> Builder l m (M.insert y j o)- Nothing -> let- i = M.size m- (j, s) = insertIfAbsent (Node r b) i m- o' = M.insert y j o- in case s of- Nothing -> Builder l m o'- Just m' -> Builder l m' o'--makeBuilder :: (Mapping k m,- Ord o,- Ord (m Int),- Ord a,- Ord v)- => Map o v- -> Map o (a, m o)- -> Builder o k m a v-makeBuilder l m = let- b0 = emptyBuilder- makeL b i x = addLeaf x i b- b1 = M.foldlWithKey' makeL b0 l- makeN b i (r, o) = addNode r o i b- b2 = M.foldlWithKey' makeN b1 m- in b2--buildBase :: Builder o k m a v -> Base k m a v-buildBase (Builder l m _) = let- l' = fromKeyVals . fmap (\(x,i) -> (complement i,x)) $ M.toList l- m' = fromKeyVals . fmap (\(x,i) -> (i,x)) $ M.toList m- in Base l' m'--buildDecision :: Ord o => o -> Builder o k m a v -> Decision k m a v-buildDecision s b@(Builder _ _ o) = Decision (buildBase b) (o M.! s)---- | A decision tree based on a single decision-singleNode :: (Mapping k m, Ord (m Int), Ord a, Ord v) => a -> m v -> Decision k m a v-singleNode r n = let- f b x = addLeaf x (Just x) b- d = addNode r (mmap Just n) Nothing $ foldl f emptyBuilder n- in buildDecision Nothing d---- | A building block for BDD's - tests if a variable is true-genTest :: Boolean b => a -> Decision Bool OnBool a b-genTest r = let- l = Q.fromList [false, true]- m = pure . Node r $ OnBool (-1) (-2)- s = 0- in Decision (Base l m) s---- | Test if a variable is true (specialised to `Bool`)-test :: a -> Decision Bool OnBool a Bool-test = genTest----- | Rapidly take the conjunction of the inputs-buildAll :: Mapping k m => Map a (m Bool) -> Decision k m a Bool-buildAll d = let- l = Q.fromList [true, false]- s = M.size d- m = Q.fromList $ do- (i,(r,n)) <- zip [0..] (M.toDescList d)- pure (Node r (mmap (bool (-2) (i-1)) n))- in Decision (Base l m) (s-1)---- | Rapidly take the disjunction of the inputs-buildAny :: Mapping k m => Map a (m Bool) -> Decision k m a Bool-buildAny d = let- l = Q.fromList [false, true]- s = M.size d- m = Q.fromList $ do- (i,(r,n)) <- zip [0..] (M.toDescList d)- pure (Node r (mmap (bool (i-1) (-2)) n))- in Decision (Base l m) (s-1)----- | Traverse bases-baseTraverse :: (Applicative f, Ord a, Ord (m Int), Ord w, Mapping k m) => (v -> f w) -> Base k m a v -> f (Builder Int k m a w)-baseTraverse p (Base l m) = let- t0 = pure emptyBuilder-- t1 = let- f b i x = liftA2 (\b' px' -> addLeaf px' (complement i) b') b (p x)- in Q.foldlWithIndex f t0 l-- t2 = let- f b i (Node r d) = addNode r d i <$> b- in Q.foldlWithIndex f t1 m-- in t2----- | Map bases-baseMap :: (Ord a, Ord (m Int), Ord w, Mapping k m) => (v -> w) -> Base k m a v -> Builder Int k m a w-baseMap p = runIdentity . baseTraverse (Identity . p)----- | A more general map for `Base`, where the shape of nodes can change-baseTransform :: (Ord a, Ord (n Int), Mapping l n, Ord w)- => (v -> w)- -> (forall x. a -> m x -> n x)- -> Base k m a v- -> IntSet- -> Builder Int l n a w-baseTransform p q (Base l m) = let-- close aL aN s = case IS.maxView s of- Nothing -> makeBuilder aL aN- Just (i, s') -> if i < 0- then let- x = p (Q.index l $ complement i)- in close (M.insert i x aL) aN s'- else let- Node r n = Q.index m i- o = q r n- s'' = IS.union s' . IS.fromList $ toList o- in close aL (M.insert i (r, o) aN) s''-- in close M.empty M.empty----- | A more general map for `Decision`, where the shape of nodes can change-decisionTransform :: (Mapping l n,- Ord (n Int),- Ord a,- Ord w)- => (v -> w)- -> (forall x. a -> m x -> n x)- -> Decision k m a v- -> Decision l n a w-decisionTransform p q (Decision b s) = let- in buildDecision s $ baseTransform p q b (IS.singleton s)----- | Fill in some values of a map--- > act (restrict h d) f = let--- > f' x = case h x of--- > Just y -> y--- > Nothing -> f x--- > in act d f'-restrict :: (Ord (m Int), Ord v, Ord a, Mapping k m) => (a -> Maybe k) -> Decision k m a v -> Decision k m a v-restrict f = let- g x m = case f x of- Nothing -> m- Just c -> cst (act m c)- in decisionTransform id g----- | A general function for merging bases-baseGenMerge :: (Ord a, Ord w, Ord (o Int), Mapping l o)- => (u -> v -> w)- -> (forall x . Ord x => a -> m x -> o x)- -> (forall y . Ord y => a -> n y -> o y)- -> (forall x y. (Ord x, Ord y) => a -> m x -> n y -> o (x, y))- -> Base h m a u -> Base k n a v -> Set (Int, Int) -> Builder (Int, Int) l o a w-baseGenMerge pLL pNL pLN pNN (Base l1 m1) (Base l2 m2) = let-- close aLL aNL aLN aNN s = case S.maxView s of- Nothing -> make aLL aNL aLN aNN- Just ((i1, i2), s') -> case (i1 < 0, i2 < 0) of- ( True, True) -> let- x = pLL (Q.index l1 $ complement i1) (Q.index l2 $ complement i2)- in close (M.insert (i1, i2) x aLL) aNL aLN aNN s'- ( True, False) -> let- Node r2 n2 = Q.index m2 i2- o = mmap (i1,) $ pLN r2 n2- s'' = S.union s' . S.fromList $ toList o- in close aLL aNL (M.insert (i1, i2) (r2, o) aLN) aNN s''- (False, True) -> let- Node r1 n1 = Q.index m1 i1- o = mmap (,i2) $ pNL r1 n1- s'' = S.union s' . S.fromList $ toList o- in close aLL (M.insert (i1, i2) (r1, o) aNL) aLN aNN s''- (False, False) -> let- Node r1 n1 = Q.index m1 i1- Node r2 n2 = Q.index m2 i2- (r, o) = case compare r1 r2 of- LT -> (r1, mmap (,i2) $ pNL r1 n1)- GT -> (r2, mmap (i1,) $ pLN r2 n2)- EQ -> (r1, pNN r1 n1 n2)- s'' = S.union s' . S.fromList $ toList o- in close aLL aNL aLN (M.insert (i1, i2) (r, o) aNN) s''-- make aLL aNL aLN aNN = let-- b0 = emptyBuilder-- makeL b (i, j) x = addLeaf x (i, j) b- b1 = M.foldlWithKey' makeL b0 aLL-- makeN b (i, j) (r, o) = addNode r o (i, j) b- b2 = M.foldlWithKey' makeN b1 aNL- b3 = M.foldlWithKey' makeN b2 aLN- b4 = M.foldlWithKey' makeN b3 aNN- in b4-- in close M.empty M.empty M.empty M.empty----- | Merge two bases in an applicative functor-baseMergeA :: (Applicative f, Ord a, Ord w, Ord (m Int), Mapping k m)- => (u -> v -> f w)- -> Base k m a u -> Base k m a v -> Set (Int, Int) -> f (Builder (Int, Int) k m a w)-baseMergeA p (Base l1 m1) (Base l2 m2) = let-- close aLL aNL aLN aNN s = case S.maxView s of- Nothing -> make aLL aNL aLN aNN- Just ((i1, i2), s') -> case (i1 < 0, i2 < 0) of- ( True, True) -> let- x = p (Q.index l1 $ complement i1) (Q.index l2 $ complement i2)- in close (M.insert (i1, i2) x aLL) aNL aLN aNN s'- ( True, False) -> let- Node r2 n2 = Q.index m2 i2- o = mmap (i1,) n2- s'' = S.union s' . S.fromList $ toList o- in close aLL aNL (M.insert (i1, i2) (r2, o) aLN) aNN s''- (False, True) -> let- Node r1 n1 = Q.index m1 i1- o = mmap (,i2) n1- s'' = S.union s' . S.fromList $ toList o- in close aLL (M.insert (i1, i2) (r1, o) aNL) aLN aNN s''- (False, False) -> let- Node r1 n1 = Q.index m1 i1- Node r2 n2 = Q.index m2 i2- (r,o) = case compare r1 r2 of- LT -> (r1, mmap (,i2) n1)- GT -> (r2, mmap (i1,) n2)- EQ -> (r1, merge (,) n1 n2)- s'' = S.union s' . S.fromList $ toList o- in close aLL aNL aLN (M.insert (i1, i2) (r, o) aNN) s''-- make aLL aNL aLN aNN = let-- b0 = pure emptyBuilder-- makeL b (i, j) = liftA2 (\b' x'-> addLeaf x' (i, j) b') b- b1 = M.foldlWithKey' makeL b0 aLL-- makeN b (i, j) (r, o) = addNode r o (i, j) <$> b- b2 = M.foldlWithKey' makeN b1 aNL- b3 = M.foldlWithKey' makeN b2 aLN- b4 = M.foldlWithKey' makeN b3 aNN- in b4-- in close M.empty M.empty M.empty M.empty----- | Merge two bases-baseMerge :: (Ord a, Ord w, Ord (m Int), Mapping k m)- => (u -> v -> w)- -> Base k m a u -> Base k m a v -> Set (Int, Int) -> Builder (Int, Int) k m a w-baseMerge p b1 b2 = let- p' x y = Identity $ p x y- in runIdentity . baseMergeA p' b1 b2----- | Folds over *all* the leaves; not something you want to do to an--- arbitrary base-instance Foldable (Base k m a) where- foldMap p = foldMap p . leaves--instance Foldable m => Foldable (Decision k m a) where- foldMap p (Decision (Base l m) s) = let- inner x old new = case IS.minView new of- Nothing -> x- Just (i, new') -> if i < 0- then inner (x <> p (Q.index l (complement i))) (IS.insert i old) new'- else let- old' = IS.insert i old- extra = IS.difference (IS.fromList . toList . nodeBranch $ Q.index m i) old'- in inner x old' (IS.union new' extra)- in inner mempty IS.empty $ IS.singleton s--instance (Ord a, Ord (m Int), Mapping k m) => Mapping (a -> k) (Decision k m a) where-- cst x = Decision (Base (Q.singleton x) Q.empty) (-1)-- act (Decision (Base l n) s) f = let- inner i- | i < 0 = Q.index l $ complement i- | otherwise = let- Node a m = Q.index n i- in inner . act m $ f a- in inner s-- -- We assume the diagram is optimised, so it is constant only if it starts- -- with a leaf.- isConst (Decision (Base l _) s)- | s < 0 = Just . Q.index l $ complement s- | otherwise = Nothing-- mtraverse p (Decision (Base l m) s) = buildDecision s <$> baseTraverse p (Base l m)-- mmap p (Decision b s) = buildDecision s $ baseMap p b-- merge p (Decision b1 s1) (Decision b2 s2) = buildDecision (s1, s2) $ baseMerge p b1 b2 (S.singleton (s1, s2))-- mergeA p (Decision b1 s1) (Decision b2 s2) = buildDecision (s1, s2) <$> baseMergeA p b1 b2 (S.singleton (s1, s2))---deriving via (AlgebraWrapper (a -> k) (Decision k m a) v)- instance (Mapping k m, Ord (m Int), Ord a, Ord v, Semigroup v) => Semigroup (Decision k m a v)--deriving via (AlgebraWrapper (a -> k) (Decision k m a) v)- instance (Mapping k m, Ord (m Int), Ord a, Ord v, Monoid v) => Monoid (Decision k m a v)--deriving via (AlgebraWrapper (a -> k) (Decision k m a) v)- instance (Mapping k m, Ord (m Int), Ord a, Ord v, Num v) => Num (Decision k m a v)--deriving via (AlgebraWrapper (a -> k) (Decision k m a) v)- instance (Mapping k m, Ord (m Int), Ord a, Ord v, Boolean v) => Boolean (Decision k m a v)----- | Attempt to extend to a bijection-checkBijection :: (Eq a, Eq v, Mapping k m) => Base k m a v -> Base k m a v -> Bij -> Maybe Bij-checkBijection (Base l1 m1) (Base l2 m2) = let- consequences i j = case (i < 0, j < 0) of- (True, True) -> if Q.index l1 (complement i) == Q.index l2 (complement j)- then Just B.empty- else Nothing- (False, False) -> let- Node r1 o1 = Q.index m1 i- Node r2 o2 = Q.index m2 j- in if r1 == r2- then B.getMaybeBij $ pairMappings B.msingleton o1 o2- else Nothing- _ -> Nothing- in B.closeBijection consequences---- | Are these Decisions isomorphic?-findBijection :: (Eq a, Eq v, Mapping k m) => Decision k m a v -> Decision k m a v -> Maybe Bij-findBijection (Decision b1 s1) (Decision b2 s2) = checkBijection b1 b2 (B.singleton s1 s2)--instance (Eq a, Eq v, Mapping k m) => Eq (Decision k m a v) where- u == v = case findBijection u v of- Just _ -> True- Nothing -> False----- | A ludicrously short definition!-instance (Ord a, Ord v, Ord (m Int), Mapping k m) => Ord (Decision k m a v) where- compare = pairMappings compare----- | Output the structure of a Decision-debugShow :: (Show a, Show v, Show (m Int)) => Decision k m a v -> String-debugShow (Decision (Base l m) s) = let-- p = 1 + max (1 + length (show (Q.length l))) (length (show (1 + Q.length m)))-- prefix i = ((if i == s then "->" else " ") <>)-- leafLine t i x = let- j = complement i- in prefix j (F.formatToString (F.left p ' ' % ": " % F.shown % "\n") j x) <> t-- nodeLine i (Node r n) t =- prefix i (F.formatToString (F.left p ' ' % ": " % F.shown % "; " % F.shown % "\n") i r n) <> t-- in Q.foldlWithIndex leafLine (Q.foldrWithIndex nodeLine "" m) l---instance (Mapping k m,- Neighbourly m,- Ord a,- Ord (m Int))- => Neighbourly (Decision k m a) where- neighbours (Decision (Base l m) s) = let- f v (Node _ n) = let- here = let- b = Base l m- e (i, j) = S.filter (uncurry (/=)) $ mutualValues (Decision b i) (Decision b j)- in foldMap e $ neighbours n- there = let- g i- | i < 0 = mempty- | otherwise = Q.index v i- in foldMap g n- in v |> (here <> there)- in Q.index (foldl f Q.empty m) s-+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuantifiedConstraints #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE UndecidableInstances #-}++-- | Decision diagrams, parametric in the mapping type for the decisions.+--+-- This is inspired by binary decision diagrams (as described in+-- detail in Knuth's The Art of Computer Programming, volume 4A);+-- these are the specific case where m is `OnBool` and v is+-- `Bool`. Our algorithms are mostly straightforward generalisations+-- of those considered there.+--+-- Some examples of how to use this code can be seen in+-- `examples/View.hs` and in `test/Data/Mapping/DecisionSpec.hs`.+--+-- Broadly speaking, there are two ways of using the code:+--+-- * It can be used directly as a `Mapping`. This is convenient, but+-- possibly wasteful: every operation builds a separate cache.+--+-- * Instead, one can (with a tiny bit more effort) use a layer of+-- functions which return in the State monad, enabling the user to+-- progressively build a shared cache. These functions mostly have+-- names ending in 'S' (for 'State').+--+-- Under the surface, the first layer mostly uses the second layer.++module Data.Mapping.Decision (+ Serial(..),+ Node(..),+ Cache(..),+ leafS,+ branchS,+ Decision(..),+ runOnEmptyCache,+ mapS,+ traverseS,+ mergeS,+ mergeAS,+ mergeS3,+ trueAssignments,+ generalCount,+ foldingCount,+ foldingCountTrue,+ genTestS,+ genTest,+ testS,+ test,+ decisionS,+ decision,+ decideAllS,+ decideAll,+ decideAnyS,+ decideAny,+ debugShowCache,+ recoverCache,+ debugShow,+ restrictS,+ restrict,+ ) where++import Prelude hiding ((||))+import Control.Monad ((<=<))+import Control.Monad.Trans.Class (lift)+import Control.Monad.Trans.State.Strict (+ State, StateT,+ evalState, evalStateT, execState,+ get, modify, state)+import Data.Algebra.Boolean (Boolean(..))+import Data.Foldable (traverse_)+import Data.Foldable.WithIndex (FoldableWithIndex(..))+import Data.Functor.Compose (Compose(..))+import Data.Functor.Identity (Identity(..))+import qualified Data.IntMap.Strict as IM+import Data.Kind (Type)+import Data.Monoid (All(..), Ap(..), Sum(..))+import qualified Data.Set as S+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as M+import GHC.Exts (reallyUnsafePtrEquality#)++import Data.Mapping+++-- | Data structures with serial number; within the same data+-- structure we expect serial numbers to be unique.+data Serial a = Serial {+ serial :: !Int,+ content :: a+}++instance Eq (Serial a) where+ Serial i _ == Serial j _ = i == j++-- | Rapid comparison, but it's meaningless: the order depends on the+-- order of discovery+instance Ord (Serial a) where+ compare (Serial i _) (Serial j _) = compare i j+++-- | A general-purpose monadic memoising function, which caches+-- partial results in an IntMap+memoComputeM :: Monad m+ => (a -> Int)+ -> (forall s. (a -> StateT s m b) -> a -> StateT s m b)+ -> a+ -> m b+memoComputeM s r = let++ go x = let+ i = s x+ inner m = case IM.lookup i m of+ Just y -> pure y+ Nothing -> do+ y <- r go x+ modify (IM.insert i y)+ pure y+ in inner =<< get++ in flip evalStateT IM.empty . go++-- | A slightly-less general-purpose memoising function, caching+-- partial results in an IntMap.+memoCompute :: (a -> Int)+ -> (forall s. (a -> State s b) -> a -> State s b)+ -> a+ -> b+memoCompute s r = runIdentity . memoComputeM s r+++-- | The raw material of a decision tree.+data Node (k :: Type) (m :: Type -> Type) (a :: Type) (v :: Type) =+ Leaf v |+ Branch a (m (Serial (Node k m a v)))++deriving instance (Eq (m (Serial (Node k m a v))), Eq a, Eq v) => Eq (Node k m a v)++deriving instance (Ord (m (Serial (Node k m a v))), Ord a, Ord v) => Ord (Node k m a v)++-- | A data structure for consistently assigning serial numbers+newtype Cache a = Cache (Map a (Serial a))++-- | Store something in a cache+stash :: Ord a => a -> State (Cache a) (Serial a)+stash x = let+ f (Cache m) = let+ g Nothing = let+ s = Serial (M.size m) x+ in (s, Just s)+ g (Just s) = (s, Just s)+ in Cache <$> M.alterF g x m+ in state f++-- | Create a leaf+leafS :: (forall x. Ord x => Ord (m x), Ord a, Ord v)+ => v+ -> State (Cache (Node k m a v)) (Serial (Node k m a v))+leafS = stash . Leaf++-- | Create a branch+branchS :: (Mapping Eq k m,+ Ord a,+ Ord v,+ forall x. Ord x => Ord (m x))+ => a+ -> m (Serial (Node k m a v))+ -> State (Cache (Node k m a v)) (Serial (Node k m a v))+branchS a n = case isConst n of+ Just s -> pure s+ Nothing -> stash (Branch a n)+++-- | Decision trees+--+-- Notes:+--+-- 1. The FoldableWithIndex instance can produce very large outputs+-- even with a modest-sized decision diagram.+--+-- 2. The traverse and mergeA methods are very inefficient, and can+-- visit nodes an exponential number of times (see documentation for+-- `traverseS`), but the mmap, foldMap and merge methods visit each+-- node only once.+--+-- 3. If you know two Decisions have been built from the same cache,+-- then comparing their serial numbers is a better equality test than+-- the more generic one provided.+newtype Decision k m a v = Decision {+ startDecision :: Serial (Node k m a v)+}+++-- | a Serial-specialised memoCompute+recurseMap :: (v -> x)+ -> (forall z s. (z -> State s x) -> a -> m z -> State s x)+ -> Serial (Node k m a v)+ -> x+recurseMap p q = let+ r f s = case content s of+ Leaf v -> pure (p v)+ Branch a m -> q f a m+ in memoCompute serial r++-- | a Serial-specialised memoComputeM+recurseMapM :: Monad n+ => (v -> n x)+ -> (forall z s. (z -> StateT s n x) -> a -> m z -> StateT s n x)+ -> Serial (Node k m a v)+ -> n x+recurseMapM p q = let+ r f s = case content s of+ Leaf v -> lift (p v)+ Branch a m -> q f a m+ in memoComputeM serial r+++-- | Run a state-based computation to make a decision tree+runOnEmptyCache :: State (Cache (Node k m a v)) (Serial (Node k m a v))+ -> Decision k m a v+runOnEmptyCache r = Decision . evalState r $ Cache M.empty+++-- | A function Int -> Int -> Int which is injective on nonnegative+-- integers+pairIntegers :: Int -> Int -> Int+pairIntegers i j = (((i+j)*(i+j+1)) `div` 2) + j+++-- | A function Int -> Int -> Int -> Int which is injective on nonnegative+-- integers+tripleIntegers :: Int -> Int -> Int -> Int+tripleIntegers i j k = (((i+j+k)*(i+j+k+1)*(i+j+k+2)) `div` 6) + pairIntegers i j+++instance Foldable m => Foldable (Decision k m a) where++ foldMap f = let+ p g _ = getAp . foldMap (Ap . g)+ in recurseMap f p . startDecision+++-- | A state-based mmap+mapS :: forall k m a u v.+ (Mapping Eq k m, Ord a, Ord v,+ forall x. Ord x => Ord (m x))+ => (u -> v)+ -> Serial (Node k m a u)+ -> State (Cache (Node k m a v)) (Serial (Node k m a v))+mapS f = let+ q :: forall z s.+ (z -> StateT s (State (Cache (Node k m a v))) (Serial (Node k m a v)))+ -> a+ -> m z+ -> StateT s (State (Cache (Node k m a v))) (Serial (Node k m a v))+ q r a = lift . branchS a <=< mtraverse r+ in recurseMapM (leafS . f) q+++-- | A state-based mtraverse.+--+-- It's far from clear whether it's possible or not to do a general+-- traverse fast in this setting. This algorithm is slow (it may visit+-- nodes an exponential number of times).+traverseS :: forall k m a u v f.+ (Mapping Eq k m, Ord a, Ord v, Applicative f,+ forall x. Ord x => Ord (m x))+ => (u -> f v)+ -> Serial (Node k m a u)+ -> f (State (Cache (Node k m a v)) (Serial (Node k m a v)))+traverseS p = let+ inner :: Serial (Node k m a u)+ -> f (State (Cache (Node k m a v)) (Serial (Node k m a v)))+ inner s = case content s of+ Leaf v -> leafS <$> p v+ Branch a m -> fmap (branchS a =<<) . getCompose $ mtraverse (Compose . inner) m+ in inner+++-- | A state-based merge+mergeS :: forall k m a u v w.+ (Mapping Eq k m, Ord a, Ord w,+ forall x. Ord x => Ord (m x))+ => (u -> v -> w)+ -> Serial (Node k m a u)+ -> Serial (Node k m a v)+ -> State (Cache (Node k m a w)) (Serial (Node k m a w))+mergeS f = let++ pairSerial (Serial i _, Serial j _) = pairIntegers i j++ calculate :: forall s.+ ((Serial (Node k m a u), Serial (Node k m a v))+ -> StateT s (State (Cache (Node k m a w))) (Serial (Node k m a w)))+ -> (Serial (Node k m a u), Serial (Node k m a v))+ -> StateT s (State (Cache (Node k m a w))) (Serial (Node k m a w))+ calculate r (s,t) = case (content s, content t) of+ (Leaf u, Leaf v) -> lift . leafS $ f u v+ (Leaf _, Branch b n) -> lift . branchS b =<< mtraverse (r . (s,)) n+ (Branch a m, Leaf _) -> lift . branchS a =<< mtraverse (r . (,t)) m+ (Branch a m, Branch b n) -> case compare a b of+ LT -> lift . branchS a =<< mtraverse (r . (,t)) m+ GT -> lift . branchS b =<< mtraverse (r . (s,)) n+ EQ -> lift . branchS a =<< mergeA (curry r) m n++ in curry $ memoComputeM pairSerial calculate+++-- | A state-based mergeA.+--+-- Just as for traverseS, this setting makes it seem unlikely that an+-- efficient algorithm will be possible.+mergeAS :: forall k m a u v w f.+ (Mapping Eq k m, Ord a, Ord w, Applicative f,+ forall x. Ord x => Ord (m x))+ => (u -> v -> f w)+ -> Serial (Node k m a u)+ -> Serial (Node k m a v)+ -> f (State (Cache (Node k m a w)) (Serial (Node k m a w)))+mergeAS f = let+ inner :: Serial (Node k m a u)+ -> Serial (Node k m a v)+ -> f (State (Cache (Node k m a w)) (Serial (Node k m a w)))+ inner s t = case (content s, content t) of+ (Leaf u, Leaf v) -> leafS <$> f u v+ (Leaf _, Branch b n) ->+ fmap (branchS b =<<) . getCompose $ mtraverse (Compose . inner s) n+ (Branch a m, Leaf _) ->+ fmap (branchS a =<<) . getCompose $ mtraverse (Compose . flip inner t) m+ (Branch a m, Branch b n) -> case compare a b of+ LT -> fmap (branchS a =<<) . getCompose $ mtraverse (Compose . flip inner t) m+ GT -> fmap (branchS b =<<) . getCompose $ mtraverse (Compose . inner s) n+ EQ -> fmap (branchS a =<<) . getCompose $ mergeA (\c -> Compose . inner c) m n+ in inner+++-- | A state-based merge3.+mergeS3 :: forall k m a u v w x.+ (Mapping Eq k m, Ord a, Ord x,+ forall y. Ord y => Ord (m y))+ => (u -> v -> w -> x)+ -> Serial (Node k m a u)+ -> Serial (Node k m a v)+ -> Serial (Node k m a w)+ -> State (Cache (Node k m a x)) (Serial (Node k m a x))+mergeS3 f = let++ tripleSerial (Serial i _, Serial j _, Serial k _) = tripleIntegers i j k++ calculate :: forall s.+ ( (Serial (Node k m a u), Serial (Node k m a v), Serial (Node k m a w))+ -> StateT s (State (Cache (Node k m a x))) (Serial (Node k m a x)))+ -> (Serial (Node k m a u), Serial (Node k m a v), Serial (Node k m a w))+ -> StateT s (State (Cache (Node k m a x))) (Serial (Node k m a x))+ calculate q (r,s,t) = case (content r, content s, content t) of+ (Leaf u, Leaf v, Leaf w) -> lift . leafS $ f u v w+ (Leaf _, Leaf _, Branch c o) -> lift . branchS c =<< mtraverse (q . (r,s,)) o+ (Leaf _, Branch b n, Leaf _) -> lift . branchS b =<< mtraverse (q . (r,,t)) n+ (Branch a m, Leaf _, Leaf _) -> lift . branchS a =<< mtraverse (q . (,s,t)) m+ (Branch a m, Branch b n, Leaf _) -> case compare a b of+ LT -> lift . branchS a =<< mtraverse (q . (,s,t)) m+ GT -> lift . branchS b =<< mtraverse (q . (r,,t)) n+ EQ -> lift . branchS a =<< mergeA (\x y -> q (x,y,t)) m n+ (Branch a m, Leaf _, Branch c o) -> case compare a c of+ LT -> lift . branchS a =<< mtraverse (q . (,s,t)) m+ GT -> lift . branchS c =<< mtraverse (q . (r,s,)) o+ EQ -> lift . branchS a =<< mergeA (\x z -> q (x,s,z)) m o+ (Leaf _, Branch b n, Branch c o) -> case compare b c of+ LT -> lift . branchS b =<< mtraverse (q . (r,,t)) n+ GT -> lift . branchS c =<< mtraverse (q . (r,s,)) o+ EQ -> lift . branchS b =<< mergeA (\y z -> q (r,y,z)) n o+ (Branch a m, Branch b n, Branch c o) -> case compare a b of+ LT -> case compare a c of+ LT -> lift . branchS a =<< mtraverse (q . (,s,t)) m+ GT -> lift . branchS c =<< mtraverse (q . (r,s,)) o+ EQ -> lift . branchS a =<< mergeA (\x z -> q (x,s,z)) m o+ GT -> case compare b c of+ LT -> lift . branchS b =<< mtraverse (q . (r,,t)) n+ GT -> lift . branchS c =<< mtraverse (q . (r,s,)) o+ EQ -> lift . branchS b =<< mergeA (\y z -> q (r,y,z)) n o+ EQ -> case compare a c of+ GT -> lift . branchS c =<< mtraverse (q . (r,s,)) o+ LT -> lift . branchS a =<< mergeA (\x y -> q (x,y,t)) m n+ EQ -> lift . branchS a =<< mergeA3 (\x y z -> q (x,y,z)) m n o++ start :: Serial (Node k m a u)+ -> Serial (Node k m a v)+ -> Serial (Node k m a w)+ -> State (Cache (Node k m a x)) (Serial (Node k m a x))+ start r s t = memoComputeM tripleSerial calculate (r,s,t)++ in start+++instance (Mapping Eq k m,+ Ord a,+ Eq v,+ forall x. Ord x => Ord (m x))+ => Eq (Decision k m a v) where++ a == b = case reallyUnsafePtrEquality# a b of+ 1# -> True+ _ -> getAll (pairMappings (\x y -> All (x == y)) a b)+++instance (Mapping Eq k m,+ Ord a,+ Ord v,+ forall x. Ord x => Ord (m x))+ => Ord (Decision k m a v) where+ compare = pairMappings compare+++instance (Mapping Eq k m,+ Ord a,+ forall x. Ord x => Ord (m x))+ => Mapping Ord (a -> k) (Decision k m a) where++ cst x = let+ n = Leaf x+ s = Serial 0 n+ in Decision s++ isConst (Decision (Serial _ (Leaf x))) = Just x+ isConst (Decision (Serial _ (Branch _ _))) = Nothing++ act = let+ inner (Leaf x) _ = x+ inner (Branch a m) f = inner (content (act m (f a))) f+ in inner . content . startDecision++ mmap p = runOnEmptyCache . mapS p . startDecision++ mtraverse p = fmap runOnEmptyCache . traverseS p . startDecision++ merge p (Decision a) (Decision b) = runOnEmptyCache $ mergeS p a b++ mergeA p (Decision a) (Decision b) = runOnEmptyCache <$> mergeAS p a b++ merge3 p (Decision a) (Decision b) (Decision c) = runOnEmptyCache $ mergeS3 p a b c++ mergeA3 = error "mergeA3 on Decision: not yet implemented"++ pairMappings f = let++ pairSerial (Serial i _, Serial j _) = pairIntegers i j++ calculate r (s,t) = case (content s, content t) of+ (Leaf u, Leaf v) -> pure $ f u v+ (Leaf _, Branch _ n) -> getAp $ foldMap (Ap . r . (s,)) n+ (Branch _ m, Leaf _) -> getAp $ foldMap (Ap . r . (,t)) m+ (Branch a m, Branch b n) -> case compare a b of+ LT -> getAp $ foldMap (Ap . r . (,t)) m+ GT -> getAp $ foldMap (Ap . r . (s,)) n+ EQ -> getAp $ pairMappings (curry (Ap . r)) m n++ go s t = memoCompute pairSerial calculate (startDecision s, startDecision t)++ in go+++instance (Ord a, Mapping Eq k m, Neighbourly m) => Neighbourly (Decision k m a) where++ neighbours = let++ serial (Left (Serial i _)) = pairIntegers i 0+ serial (Right (Serial i _, Serial j _)) = pairIntegers i (j+1)++ -- find neighbours in a node+ p r (Left s) = case content s of+ Leaf _ -> pure S.empty+ Branch _ m -> do+ now <- getAp . foldMap (Ap . r . Right) $ neighbours m+ later <- getAp $ foldMap (Ap . r . Left) m+ pure (now <> later)+ -- find common values in two nodes+ p r (Right (s,t)) = case (content s, content t) of+ (Leaf u, Leaf v) -> pure $ if u == v then S.empty else S.singleton (u,v)+ (Leaf _, Branch _ n) -> getAp $ foldMap (Ap . r . Right . (s,)) n+ (Branch _ m, Leaf _) -> getAp $ foldMap (Ap . r . Right . (,t)) m+ (Branch a m, Branch b n) -> case compare a b of+ LT -> getAp $ foldMap (Ap . r . Right . (,t)) m+ GT -> getAp $ foldMap (Ap . r . Right . (s,)) n+ EQ -> let+ q x y = Ap . r $ Right (x,y)+ in getAp $ pairMappings q m n++ in memoCompute serial p . Left . startDecision+++instance (Ord a, FoldableWithIndex k m, Mapping Eq k m)+ => FoldableWithIndex (Map a k) (Decision k m a) where++ ifoldMap f = let+ inner m (Leaf x) = f m x+ inner m (Branch a n) = let+ g k = inner (M.insert a k m) . content+ in ifoldMap g n+ in inner M.empty . content . startDecision+++-- | Find all assignments of variables that pass the test+--+-- Even for modest-sized decision diagrams, this can produce some very+-- large outputs!+satisfyingAssignments :: (Ord a, FoldableWithIndex k m)+ => (v -> Bool)+ -> Decision k m a v+ -> [Map a k]+satisfyingAssignments t = let+ p x = [M.empty | t x]+ q f a = let+ h k = Ap . fmap (fmap (M.insert a k)) . f+ in getAp . ifoldMap h+ in recurseMap p q . startDecision+++-- | Find all assignments that return True+--+-- Again, this can produce very large outputs even with modest-sized+-- inputs.+trueAssignments :: (Ord a, FoldableWithIndex k m)+ => Decision k m a Bool+ -> [Map a k]+trueAssignments = satisfyingAssignments id+++-- | A general algorithm for counts of a decision tree+generalCount :: (Mapping Eq k m)+ => (a -> Int)+ -- ^ The serial number of a decision+ -> Int+ -- ^ The number of decisions+ -> (v -> n)+ -- ^ The count of a value+ -> (forall f z. Applicative f => (z -> f n) -> m z -> f n)+ -- ^ How to combine counts at a node+ -> Decision k m a v+ -- ^ The input decision diagram+ -> n+ -- ^ The count+generalCount s n c d = let++ step i (j,x)+ | i+1 == j = x+ | otherwise = step i (j-1, runIdentity $ d Identity (cst x))++ p v = (n, c v)++ q f a = let+ i = s a+ in fmap (i,) . d (fmap (step i) . f)++ in step (-1) . recurseMap p q . startDecision+++-- | A more specialised summing count+foldingCount :: (Mapping Eq k m, Num n)+ => (a -> Int)+ -- ^ The serial number of a decision+ -> Int+ -- ^ The number of decisions+ -> (v -> n)+ -- ^ The count of a value+ -> Decision k m a v+ -- ^ The input decision diagram+ -> n+ -- ^ The count+foldingCount s n c = let+ q f = fmap getSum . getAp . foldMap (Ap . fmap Sum . f)+ in generalCount s n c q+++-- | Even more specialised: just counts true values+foldingCountTrue :: (Mapping Eq k m, Num n)+ => (a -> Int)+ -- ^ The serial number of a decision+ -> Int+ -- ^ The number of decisions+ -> Decision k m a Bool+ -- ^ The input decision diagram+ -> n+ -- ^ The count+foldingCountTrue s n = foldingCount s n (\x -> if x then 1 else 0)+++-- | Create a test for a variable (valued in any Boolean)+genTestS :: (Ord a, Ord b, Boolean b)+ => a+ -> State (Cache (Node Bool OnBool a b)) (Serial (Node Bool OnBool a b))+genTestS x = do+ n0 <- leafS false+ n1 <- leafS true+ branchS x $ OnBool n0 n1++-- | Tests if a variable is true (valued in any Boolean)+genTest :: (Ord a, Ord b, Boolean b)+ => a -> Decision Bool OnBool a b+genTest = runOnEmptyCache . genTestS+++-- | Test if a variable is true (specialised to `Bool`)+testS :: (Ord a)+ => a+ -> State (Cache (Node Bool OnBool a Bool)) (Serial (Node Bool OnBool a Bool))+testS = genTestS++-- | Test if a variable is true (specialised to `Bool`)+test :: (Ord a) => a -> Decision Bool OnBool a Bool+test = genTest+++-- | Make a single decision+decisionS :: (Mapping Eq k m,+ Ord a,+ Ord v,+ forall x. Ord x => Ord (m x))+ => a+ -> m v+ -> State (Cache (Node k m a v)) (Serial (Node k m a v))+decisionS a m = branchS a =<< mtraverse leafS m+++-- | A single decision+decision :: (Mapping Eq k m, Ord a, Ord v,+ forall x. Ord x => Ord (m x))+ => a+ -> m v+ -> Decision k m a v+decision a = runOnEmptyCache . decisionS a+++-- | Build a test imposing conditions which must be true for all+-- variables in the map+decideAllS :: forall k m a.+ (Mapping Eq k m, Ord a,+ forall x. Ord x => Ord (m x))+ => Map a (m Bool)+ -> State (Cache (Node k m a Bool)) (Serial (Node k m a Bool))+decideAllS = let++ begin :: [(a, m Bool)]+ -> State (Cache (Node k m a Bool)) (Serial (Node k m a Bool))+ begin [] = leafS True+ begin l = do+ f <- leafS False+ t <- leafS True+ continue f t l++ continue :: Serial (Node k m a Bool)+ -> Serial (Node k m a Bool)+ -> [(a, m Bool)]+ -> State (Cache (Node k m a Bool)) (Serial (Node k m a Bool))+ continue _ u [] = pure u+ continue f u ((a,m):xs) = do+ v <- branchS a (mmap (\i -> if i then u else f) m)+ continue f v xs++ in begin . M.toDescList+++-- | A test imposing conditions which must be true for all variables+-- in the map+decideAll :: (Mapping Eq k m, Ord a,+ forall x. Ord x => Ord (m x))+ => Map a (m Bool) -> Decision k m a Bool+decideAll = runOnEmptyCache . decideAllS+++-- | Build a test imposing conditions which must be true for at least+-- one variable in the map+decideAnyS :: forall k m a.+ (Mapping Eq k m, Ord a,+ forall x. Ord x => Ord (m x))+ => Map a (m Bool)+ -> State (Cache (Node k m a Bool)) (Serial (Node k m a Bool))+decideAnyS = let++ begin :: [(a, m Bool)]+ -> State (Cache (Node k m a Bool)) (Serial (Node k m a Bool))+ begin [] = leafS False+ begin l = do+ t <- leafS True+ f <- leafS False+ continue t f l++ continue :: Serial (Node k m a Bool)+ -> Serial (Node k m a Bool)+ -> [(a, m Bool)]+ -> State (Cache (Node k m a Bool)) (Serial (Node k m a Bool))+ continue _ u [] = pure u+ continue t u ((a,m):xs) = do+ v <- branchS a (mmap (\i -> if i then t else u) m)+ continue t v xs++ in begin . M.toDescList+++-- | A test imposing conditions which must be true for at least one+-- variable in the map+decideAny :: (Mapping Eq k m, Ord a,+ forall x. Ord x => Ord (m x)) => Map a (m Bool) -> Decision k m a Bool+decideAny = runOnEmptyCache . decideAnyS+++-- | Display the structure of a cache+debugShowCache :: (Mapping Eq k m, Show a, Show v, Show (m Int))+ => Cache (Node k m a v)+ -> [String]+debugShowCache (Cache c) = let++ entries = IM.fromList [(serial s,content s) | s <- M.elems c]++ padding = length (show (M.size c - 1))++ makeLine (n, s) = let+ lspace = replicate (padding - length (show n)) ' '+ rest = case s of+ Leaf v -> "Leaf " <> showsPrec 9 v ""+ Branch a m -> "Branch " <> showsPrec 9 a "" <> " " <> showsPrec 11 (mmap serial m) ""+ in lspace <> show n <> ": " <> rest++ in makeLine <$> IM.assocs entries+++-- | Provided for debugging purposes only: if you find yourself+-- wanting this, that's a sign you should be using the State-valued+-- functionality instead.+recoverCache :: (Mapping Eq k m, Ord a, Ord v,+ forall x. Ord x => Ord (m x))+ => Serial (Node k m a v)+ -> Cache (Node k m a v)+recoverCache = let+ inner s@(Serial _ n) = do+ m <- get+ case M.lookup n m of+ Just _ -> pure ()+ Nothing -> do+ case n of+ Leaf _ -> pure ()+ Branch _ a -> traverse_ inner a+ modify (M.insert n s)+ in Cache . flip execState M.empty . inner+++-- | Display the structure of a Decision+debugShow :: (Mapping Eq k m,+ Ord a,+ Ord v,+ Show a,+ Show v,+ Show (m Int),+ forall x. Ord x => Ord (m x))+ => Decision k m a v+ -> String+debugShow (Decision x@(Serial s _)) = let+ prefix i = ((if i == s then "* " else " ") <>)+ in unlines [prefix i l | (i,l) <- zip [0..] (debugShowCache (recoverCache x))]+++-- | Build a simplified decision, filling in some values in advance+restrictS :: forall k m a v.+ (Mapping Eq k m, Ord a, Ord v,+ forall x. Ord x => Ord (m x))+ => (a -> Maybe k)+ -> Serial (Node k m a v)+ -> State (Cache (Node k m a v)) (Serial (Node k m a v))+restrictS f = let+ q :: forall s z.+ (z -> StateT s (State (Cache (Node k m a v))) (Serial (Node k m a v)))+ -> a+ -> m z+ -> StateT s (State (Cache (Node k m a v))) (Serial (Node k m a v))+ q r a m = case f a of+ Just b -> r $ act m b+ Nothing -> lift . branchS a =<< mtraverse r m+ in recurseMapM leafS q+++-- | Simplify a Decision by filling in some values in advance+-- > act (restrict h d) f = let+-- > f' x = case h x of+-- > Just y -> y+-- > Nothing -> f x+-- > in act d f'+restrict :: (Mapping Eq k m, Ord a, Ord v,+ forall x. Ord x => Ord (m x))+ => (a -> Maybe k)+ -> Decision k m a v+ -> Decision k m a v+restrict f = runOnEmptyCache . restrictS f . startDecision+++deriving via (AlgebraWrapper Ord (a -> k) (Decision k m a) v)+ instance (Mapping Eq k m,+ Ord a,+ Ord v,+ Semigroup v,+ forall x. Ord x => Ord (m x))+ => Semigroup (Decision k m a v)++deriving via (AlgebraWrapper Ord (a -> k) (Decision k m a) v)+ instance (Mapping Eq k m,+ Ord a,+ Ord v,+ Monoid v,+ forall x. Ord x => Ord (m x))+ => Monoid (Decision k m a v)++deriving via (AlgebraWrapper Ord (a -> k) (Decision k m a) v)+ instance (Mapping Eq k m,+ Ord a,+ Ord v,+ Num v,+ forall x. Ord x => Ord (m x))+ => Num (Decision k m a v)++deriving via (AlgebraWrapper Ord (a -> k) (Decision k m a) v)+ instance (Mapping Eq k m,+ Ord a,+ Ord v,+ Boolean v,+ forall x. Ord x => Ord (m x))+ => Boolean (Decision k m a v)
src/Data/Mapping/MapWithDefault.hs view
@@ -8,6 +8,7 @@ import Control.Applicative (Applicative(..)) import Data.Algebra.Boolean import Data.Foldable (Foldable(..))+import Data.Functor.Const (Const(..)) import Data.List (groupBy) import Data.Map.Strict (Map) import qualified Data.Map.Strict as M@@ -16,6 +17,7 @@ import Data.Maybe (fromMaybe, mapMaybe) import qualified Data.Set as S import Data.Mapping.Util+import Data.Void (Void) -- | Mappings constant except on an enumerated set of values@@ -41,41 +43,97 @@ instance Foldable (MapWithDefault k) where foldMap p (MapWithDefault a f) = p a <> foldMap p f -instance Ord k => Mapping k (MapWithDefault k) where+instance Ord k => Mapping Eq k (MapWithDefault k) where+ cst x = MapWithDefault x M.empty+ mmap p (MapWithDefault a f) = let b = p a q x = let y = p x in if b == y then Nothing else Just y in MapWithDefault b $ M.mapMaybe q f+ mtraverse p (MapWithDefault a f) = let b = p a e x y = if x == y then Nothing else Just y g _ x = liftA2 e b (p x) in liftA2 MapWithDefault b $ M.traverseMaybeWithKey g f+ act (MapWithDefault a f) x = fromMaybe a (M.lookup x f)+ isConst (MapWithDefault a f) = if M.null f then Just a else Nothing- mergeA h (MapWithDefault a f) (MapWithDefault b g) = let++ mergeA p (MapWithDefault a f) (MapWithDefault b g) = let e x y = if x == y then Just x else Nothing- c = h a b- l = M.traverseMissing (\_ x -> h x b)- r = M.traverseMissing (\_ y -> h a y)- h' _ x y = liftA2 e c $ h x y- t = M.zipWithMaybeAMatched h'+ c = p a b+ p' x y = liftA2 e c $ p x y+ l = M.traverseMaybeMissing (\_ x -> p' x b)+ r = M.traverseMaybeMissing (\_ y -> p' a y)+ t = M.zipWithMaybeAMatched (const p') combine = M.mergeA l r t in liftA2 MapWithDefault c $ combine f g- merge h (MapWithDefault a f) (MapWithDefault b g) = let- c = h a b- l = M.mapMissing (\_ x -> h x b)- r = M.mapMissing (\_ y -> h a y)- h' _ x y = let- z = h x y++ merge p (MapWithDefault a f) (MapWithDefault b g) = let+ c = p a b+ p' x y = let+ z = p x y in if z == c then Nothing else Just z- t = M.zipWithMaybeMatched h'+ l = M.mapMaybeMissing (\_ x -> p' x b)+ r = M.mapMaybeMissing (\_ y -> p' a y)+ t = M.zipWithMaybeMatched (const p') combine = M.merge l r t in MapWithDefault c $ combine f g + merge3 p (MapWithDefault a f) (MapWithDefault b g) (MapWithDefault c h) = let+ d = p a b c+ l1 = M.mapMissing (const (,b))+ r1 = M.mapMissing (const (a,))+ t1 = M.zipWithMatched (const (,))+ combine1 = M.merge l1 r1 t1+ p' (x,y) z = let+ v = p x y z+ in if v == d then Nothing else Just v+ l2 = M.mapMaybeMissing (\_ (x,y) -> p' (x,y) c)+ r2 = M.mapMaybeMissing (\_ z -> p' (a,b) z)+ t2 = M.zipWithMaybeMatched (const p')+ combine2 = M.merge l2 r2 t2+ in MapWithDefault d $ combine2 (combine1 f g) h++ mergeA3 p (MapWithDefault a f) (MapWithDefault b g) (MapWithDefault c h) = let+ d = p a b c+ e x y+ | x == y = Nothing+ | otherwise = Just y+ l1 = M.mapMissing (const (,b))+ r1 = M.mapMissing (const (a,))+ t1 = M.zipWithMatched (const (,))+ combine1 = M.merge l1 r1 t1+ p' (x,y) z = liftA2 e d $ p x y z+ l2 = M.traverseMaybeMissing (\_ (x,y) -> p' (x,y) c)+ r2 = M.traverseMaybeMissing (\_ z -> p' (a,b) z)+ t2 = M.zipWithMaybeAMatched (const p')+ combine2 = M.mergeA l2 r2 t2+ in liftA2 MapWithDefault d $ combine2 (combine1 f g) h++ pairMappings :: forall a b m. Monoid m => (a -> b -> m) -> MapWithDefault k a -> MapWithDefault k b -> m+ pairMappings p (MapWithDefault a f) (MapWithDefault b g) = let+ t = M.zipWithAMatched (\_ x y -> Const $ p x y)+ l = M.traverseMissing (\_ x -> Const $ p x b)+ r = M.traverseMissing (\_ y -> Const $ p a y)+ combine = M.mergeA l r t+ in p a b <> getConst (combine f g :: Const m (Map k Void))++ bind f (MapWithDefault a m) = let+ MapWithDefault b n = f a+ g k x+ | y == b = Nothing+ | otherwise = Just y where+ y = act (f x) k+ h k x _ = g k x+ combine = M.merge (M.mapMaybeMissing g) M.preserveMissing (M.zipWithMaybeMatched h)+ in MapWithDefault b $ combine m n+ -- | This instance assumes that k is unbounded -- -- It would be possible to do something valid in greater generality (for@@ -86,14 +144,14 @@ d l = zip ([a] <> l) (l <> [a]) in S.fromList . concatMap (d . fmap snd) . groupBy c $ M.toAscList f -deriving via (AlgebraWrapper k (MapWithDefault k) b)+deriving via (AlgebraWrapper Eq k (MapWithDefault k) b) instance (Ord k, Ord b, Semigroup b) => Semigroup (MapWithDefault k b) -deriving via (AlgebraWrapper k (MapWithDefault k) b)+deriving via (AlgebraWrapper Eq k (MapWithDefault k) b) instance (Ord k, Ord b, Monoid b) => Monoid (MapWithDefault k b) -deriving via (AlgebraWrapper k (MapWithDefault k) b)+deriving via (AlgebraWrapper Eq k (MapWithDefault k) b) instance (Ord k, Ord b, Num b) => Num (MapWithDefault k b) -deriving via (AlgebraWrapper k (MapWithDefault k) b)+deriving via (AlgebraWrapper Eq k (MapWithDefault k) b) instance (Ord k, Ord b, Boolean b) => Boolean (MapWithDefault k b)
src/Data/Mapping/Piecewise.hs view
@@ -1,16 +1,10 @@-{-# LANGUAGE- CPP,- DerivingVia- #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DerivingVia #-} module Data.Mapping.Piecewise where -#if MIN_VERSION_GLASGOW_HASKELL(9,6,0,0)-#else-import Control.Applicative (liftA2)-#endif-import Control.Applicative (liftA3) import Data.Algebra.Boolean+import Data.Foldable (toList) import qualified Data.Map.Internal as MI import Data.Map.Strict (Map) import qualified Data.Map.Strict as M@@ -84,18 +78,88 @@ lessThanOrEqual :: Enum k => k -> Piecewise k Bool lessThanOrEqual = lessThan . succ --- | All values, in order of increasing key-values :: Piecewise k v -> [v]-values (Piecewise x m) = x : M.elems m- instance (Eq k) => Functor (Piecewise k) where fmap p (Piecewise a f) = fromAscListUnsafe (p a) (fmap p <$> M.toList f) instance Foldable (Piecewise k) where foldMap f (Piecewise a m) = f a <> foldMap f m -instance Ord k => Mapping k (Piecewise k) where +innerMerge :: Ord k => (x -> y -> z) -> x -> y -> [(k,x)] -> [(k,y)] -> [(k,z)]+innerMerge p = let+ go x _ [] v = fmap (p x) <$> v+ go _ y u [] = fmap (flip p y) <$> u+ go x y u@((a,x'):u') v@((b,y'):v') = case compare a b of+ LT -> (a,p x' y):go x' y u' v+ GT -> (b,p x y'):go x y' u v'+ EQ -> (a,p x' y'):go x' y' u' v'+ in go+++innerMergeA :: (Ord k, Applicative f)+ => (x -> y -> f z)+ -> x -> y+ -> [(k,x)] -> [(k,y)] -> f [(k,z)]+innerMergeA p = let+ go x _ [] v = traverse (traverse (p x)) v+ go _ y u [] = traverse (traverse (flip p y)) u+ go x y u@((a,x'):u') v@((b,y'):v') = case compare a b of+ LT -> liftA2 (:) ((a,) <$> p x' y) (go x' y u' v)+ GT -> liftA2 (:) ((b,) <$> p x y') (go x y' u v')+ EQ -> liftA2 (:) ((a,) <$> p x' y') (go x' y' u' v')+ in go+++innerMerge3 :: Ord k+ => (x -> y -> z -> w)+ -> x -> y -> z+ -> [(k,x)] -> [(k,y)] -> [(k,z)] -> [(k,w)]+innerMerge3 p = let+ go x y z [] v w = innerMerge (p x) y z v w+ go x y z u [] w = innerMerge (\i -> p i y) x z u w+ go x y z u v [] = innerMerge (\i j -> p i j z) x y u v+ go x y z u@((a,x'):u') v@((b,y'):v') w@((c,z'):w') = case compare a b of+ LT -> case compare a c of+ LT -> (a,p x' y z):go x' y z u' v w+ GT -> (c,p x y z'):go x y z' u v w'+ EQ -> (a,p x' y z'):go x' y z' u' v w'+ GT -> case compare b c of+ LT -> (b,p x y' z):go x y' z u v' w+ GT -> (c,p x y z'):go x y z' u v w'+ EQ -> (b,p x y' z'):go x y' z' u v' w'+ EQ -> case compare a c of+ LT -> (a,p x' y' z):go x' y' z u' v' w+ GT -> (c,p x y z'):go x y z' u v w'+ EQ -> (a,p x' y' z'):go x' y' z' u' v' w'+ in go+++innerMergeA3 :: (Applicative f, Ord k)+ => (x -> y -> z -> f w)+ -> x -> y -> z+ -> [(k,x)] -> [(k,y)] -> [(k,z)] -> f [(k,w)]+innerMergeA3 p = let+ go x y z [] v w = innerMergeA (p x) y z v w+ go x y z u [] w = innerMergeA (\i -> p i y) x z u w+ go x y z u v [] = innerMergeA (\i j -> p i j z) x y u v+ go x y z u@((a,x'):u') v@((b,y'):v') w@((c,z'):w') = case compare a b of+ LT -> case compare a c of+ LT -> liftA2 (:) ((a,) <$> p x' y z) (go x' y z u' v w)+ GT -> liftA2 (:) ((c,) <$> p x y z') (go x y z' u v w')+ EQ -> liftA2 (:) ((a,) <$> p x' y z') (go x' y z' u' v w')+ GT -> case compare b c of+ LT -> liftA2 (:) ((b,) <$> p x y' z) (go x y' z u v' w)+ GT -> liftA2 (:) ((c,) <$> p x y z') (go x y z' u v w')+ EQ -> liftA2 (:) ((b,) <$> p x y' z') (go x y' z' u v' w')+ EQ -> case compare a c of+ LT -> liftA2 (:) ((a,) <$> p x' y' z) (go x' y' z u' v' w)+ GT -> liftA2 (:) ((c,) <$> p x y z') (go x y z' u v w')+ EQ -> liftA2 (:) ((a,) <$> p x' y' z') (go x' y' z' u' v' w')+ in go+++instance Ord k => Mapping Eq k (Piecewise k) where+ cst x = Piecewise x M.empty act (Piecewise a f) x = case M.lookupLE x f of@@ -104,84 +168,59 @@ isConst (Piecewise a f) = if M.null f then Just a else Nothing - mmap = fmap-- mtraverse p (Piecewise a f) = liftA2 fromAscList (p a) (traverse (traverse p) $ M.toList f)+ mmap p (Piecewise a f) = fromAscList (p a) . fmap (fmap p) $ M.toList f - merge p = let+ mtraverse p (Piecewise a f) = liftA2 fromAscList (p a) . traverse (traverse p) $ M.toList f - inner a b c r@((x,a'):r') s@((y,b'):s') = case compare x y of- LT -> let- c' = p a' b- in if c' == c then inner a' b c r' s else (x,c'):inner a' b c' r' s- GT -> let- c' = p a b'- in if c' == c then inner a b' c r s' else (y,c'):inner a b' c' r s'- EQ -> let- c' = p a' b'- in if c' == c then inner a' b' c r' s' else (x,c'):inner a' b' c' r' s'- inner a _ c [] ((y,b'):s') = let- c' = p a b'- in if c' == c then inner a b' c [] s' else (y,c'):inner a b' c' [] s'- inner _ b c ((x,a'):r') [] = let- c' = p a' b- in if c' == c then inner a' b c r' [] else (x,c'):inner a' b c' r' []- inner _ _ _ [] [] = []+ merge p (Piecewise a f) (Piecewise b g) =+ fromAscList (p a b) $ innerMerge p a b (M.toList f) (M.toList g) - run (Piecewise a f) (Piecewise b g) = let- c = p a b- l = inner a b c (M.toList f) (M.toList g)- in Piecewise c $ M.fromList l+ mergeA p (Piecewise a f) (Piecewise b g) =+ liftA2 fromAscList (p a b) $ innerMergeA p a b (M.toList f) (M.toList g) - in run+ merge3 p (Piecewise a f) (Piecewise b g) (Piecewise c h) =+ fromAscList (p a b c) $ innerMerge3 p a b c (M.toList f) (M.toList g) (M.toList h) - mergeA p = let+ mergeA3 p (Piecewise a f) (Piecewise b g) (Piecewise c h) =+ liftA2 fromAscList (p a b c) $ innerMergeA3 p a b c (M.toList f) (M.toList g) (M.toList h) - maybePrepend x u v l- | u == v = l- | otherwise = (x,v):l+ pairMappings p = let - inner a b c r@((x,a'):r') s@((y,b'):s') = case compare x y of- LT -> let- c' = p a' b- in liftA3 (maybePrepend x) c c' $ inner a' b c' r' s- GT -> let- c' = p a b'- in liftA3 (maybePrepend y) c c' $ inner a b' c' r s'- EQ -> let- c' = p a' b'- in liftA3 (maybePrepend x) c c' $ inner a' b' c' r' s'- inner a _ c [] ((y,b'):s') = let- c' = p a b'- in liftA3 (maybePrepend y) c c' $ inner a b' c' [] s'- inner _ b c ((x,a'):r') [] = let- c' = p a' b- in liftA3 (maybePrepend x) c c' $ inner a' b c' r' []- inner _ _ _ [] [] = pure []+ inner z a b r@((x,a'):r') s@((y,b'):s') = case compare x y of+ LT -> inner (z <> p a' b) a' b r' s+ GT -> inner (z <> p a b') a b' r s'+ EQ -> inner (z <> p a' b') a' b' r' s'+ inner z a _ [] s = z <> foldMap (p a . snd) s+ inner z _ b r [] = z <> foldMap (flip p b . snd) r - run (Piecewise a f) (Piecewise b g) = let- c = p a b- l = inner a b c (M.toList f) (M.toList g)- in liftA2 Piecewise c (M.fromList <$> l)+ run (Piecewise a f) (Piecewise b g) = inner (p a b) a b (M.toList f) (M.toList g) in run + bind f (Piecewise a m) = let+ inner p [] = p+ inner p ((k,q):l) = let+ (p', _) = splitPiecewise k p+ (_ , q') = splitPiecewise k q+ in gluePiecewise p' k $ inner q' l+ in inner (f a) (fmap f <$> M.toList m)+ instance Neighbourly (Piecewise k) where neighbours m = let pairs (x:r@(y:_)) = (x,y):pairs r pairs _ = []- in S.fromList . pairs $ values m+ in S.fromList . pairs $ toList m -deriving via (AlgebraWrapper k (Piecewise k) b)+deriving via (AlgebraWrapper Eq k (Piecewise k) b) instance (Ord k, Ord b, Semigroup b) => Semigroup (Piecewise k b) -deriving via (AlgebraWrapper k (Piecewise k) b)+deriving via (AlgebraWrapper Eq k (Piecewise k) b) instance (Ord k, Ord b, Monoid b) => Monoid (Piecewise k b) -deriving via (AlgebraWrapper k (Piecewise k) b)+deriving via (AlgebraWrapper Eq k (Piecewise k) b) instance (Ord k, Ord b, Num b) => Num (Piecewise k b) -deriving via (AlgebraWrapper k (Piecewise k) b)+deriving via (AlgebraWrapper Eq k (Piecewise k) b) instance (Ord k, Ord b, Boolean b) => Boolean (Piecewise k b) -- | Alter keys according to a function, assumed to be monotone (not checked)@@ -217,14 +256,3 @@ gluePiecewise p@(Piecewise a m) k (Piecewise c n) = let b = rightEnd p in Piecewise a (if b == c then MI.link2 m n else MI.link k c m n)---- | This is almost a monad (with `cst` as `pure`) except that we need--- an `Eq` instance on the values.-mjoin :: (Ord k, Eq w) => (v -> Piecewise k w) -> Piecewise k v -> Piecewise k w-mjoin f (Piecewise a m) = let- inner p [] = p- inner p ((k,q):l) = let- (p', _) = splitPiecewise k p- (_ , q') = splitPiecewise k q- in gluePiecewise p' k $ inner q' l- in inner (f a) (fmap f <$> M.toList m)
src/Data/Mapping/Util.hs view
@@ -1,25 +1,8 @@ module Data.Mapping.Util where -import Data.Functor.Compose (Compose(..))-import Data.Map.Strict (Map)-import qualified Data.Map.Strict as M ---- | inserts key with value only if absent, returns map if changed-insertIfAbsent :: Ord k => k -> v -> Map k v -> (v, Maybe (Map k v))-insertIfAbsent k v = let- f (Just x) = (x, Nothing)- f Nothing = (v, Just (Just v))- in getCompose . M.alterF (Compose . f) k-- -- | For use in maps where we don't want to store default values nonDefault :: Eq a => a -> a -> Maybe a nonDefault d x | d == x = Nothing | otherwise = Just x----- | Helper function (not exported)-equating :: Eq a => (b -> a) -> b -> b -> Bool-equating f x y = f x == f y
test/Data/Mapping/DecisionSpec.hs view
@@ -1,13 +1,15 @@ module Data.Mapping.DecisionSpec where import Prelude hiding ((&&), (||), not, all)-import qualified Data.Map as M+import Data.Foldable (foldlM)+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as M import qualified Data.Set as S import Test.Hspec import Data.Algebra.Boolean ((&&), (||), not, all) import Data.Mapping import Data.Mapping.Decision-import Data.Mapping.Piecewise+import Data.Mapping.Piecewise (Piecewise, greaterThanOrEqual, fromAscList) boolAct :: Ord a@@ -17,104 +19,159 @@ boolAct a s = act a (`S.member` S.fromList s) +completeAssignments :: Ord a => [a] -> Map a Bool -> [Map a Bool]+completeAssignments [] m = pure m+completeAssignments (v:vs) m = let+ l = case M.lookup v m of+ Just _ -> pure m+ Nothing -> [M.insert v False m, M.insert v True m]+ in completeAssignments vs =<< l++ spec :: Spec spec = do - let x = test "x"- let y = test "y"+ describe "Boolean algebra" $ do - describe "Basic tests of act" $ do+ let x = test "x"+ let y = test "y" - it "x false on {}" $ do- boolAct x [] `shouldBe` False- it "x true on {x}" $ do- boolAct x ["x"] `shouldBe` True+ describe "Basic tests of act" $ do - describe "Basic tests of mmap" $ do+ it "x false on {}" $ do+ boolAct x [] `shouldBe` False+ it "x true on {x}" $ do+ boolAct x ["x"] `shouldBe` True - it "not x true on {}" $ do- boolAct (not x) [] `shouldBe` True- it "not x false on {x}" $ do- boolAct (not x) ["x"] `shouldBe` False+ describe "Basic tests of mmap" $ do - describe "Basic tests of merge" $ do+ it "not x true on {}" $ do+ boolAct (not x) [] `shouldBe` True+ it "not x false on {x}" $ do+ boolAct (not x) ["x"] `shouldBe` False - it "x && y true on {}" $ do- boolAct (x && y) [] `shouldBe` False- it "x && y true on {x}" $ do- boolAct (x && y) ["x"] `shouldBe` False- it "x && y true on {y}" $ do- boolAct (x && y) ["y"] `shouldBe` False- it "x && y true on {x,y}" $ do- boolAct (x && y) ["x", "y"] `shouldBe` True+ describe "Basic tests of merge" $ do - it "x || y true on {}" $ do- boolAct (x || y) [] `shouldBe` False- it "x || y true on {x}" $ do- boolAct (x || y) ["x"] `shouldBe` True- it "x || y true on {y}" $ do- boolAct (x || y) ["y"] `shouldBe` True- it "x || y true on {x,y}" $ do- boolAct (x || y) ["x", "y"] `shouldBe` True+ it "x && y true on {}" $ do+ boolAct (x && y) [] `shouldBe` False+ it "x && y true on {x}" $ do+ boolAct (x && y) ["x"] `shouldBe` False+ it "x && y true on {y}" $ do+ boolAct (x && y) ["y"] `shouldBe` False+ it "x && y true on {x,y}" $ do+ boolAct (x && y) ["x", "y"] `shouldBe` True - it "y && x true on {}" $ do- boolAct (y && x) [] `shouldBe` False- it "y && x true on {x}" $ do- boolAct (y && x) ["x"] `shouldBe` False- it "y && x true on {y}" $ do- boolAct (y && x) ["y"] `shouldBe` False- it "y && x true on {x,y}" $ do- boolAct (y && x) ["x", "y"] `shouldBe` True+ it "x || y true on {}" $ do+ boolAct (x || y) [] `shouldBe` False+ it "x || y true on {x}" $ do+ boolAct (x || y) ["x"] `shouldBe` True+ it "x || y true on {y}" $ do+ boolAct (x || y) ["y"] `shouldBe` True+ it "x || y true on {x,y}" $ do+ boolAct (x || y) ["x", "y"] `shouldBe` True - it "y || x true on {}" $ do- boolAct (y || x) [] `shouldBe` False- it "y || x true on {x}" $ do- boolAct (y || x) ["x"] `shouldBe` True- it "y || x true on {y}" $ do- boolAct (y || x) ["y"] `shouldBe` True- it "y || x true on {x,y}" $ do- boolAct (y || x) ["x", "y"] `shouldBe` True+ it "y && x true on {}" $ do+ boolAct (y && x) [] `shouldBe` False+ it "y && x true on {x}" $ do+ boolAct (y && x) ["x"] `shouldBe` False+ it "y && x true on {y}" $ do+ boolAct (y && x) ["y"] `shouldBe` False+ it "y && x true on {x,y}" $ do+ boolAct (y && x) ["x", "y"] `shouldBe` True - describe "Check of listTrue" $ do+ it "y || x true on {}" $ do+ boolAct (y || x) [] `shouldBe` False+ it "y || x true on {x}" $ do+ boolAct (y || x) ["x"] `shouldBe` True+ it "y || x true on {y}" $ do+ boolAct (y || x) ["y"] `shouldBe` True+ it "y || x true on {x,y}" $ do+ boolAct (y || x) ["x", "y"] `shouldBe` True - let x0y0 = M.fromList [("x", False), ("y", False)]- let x0y1 = M.fromList [("x", False), ("y", True)]- let x1y0 = M.fromList [("x", True), ("y", False)]- let x1y1 = M.fromList [("x", True), ("y", True)]+ describe "Check of trueAssignments" $ do - it "Should work on &&" $ do- S.fromList (listTrue (S.fromList ["x", "y"]) (x && y))- `shouldBe` S.fromList [x1y1]- it "Should work on ||" $ do- S.fromList (listTrue (S.fromList ["x", "y"]) (x || y))- `shouldBe` S.fromList [x0y1, x1y0, x1y1]- it "Should work on not (1)" $ do- S.fromList (listTrue (S.fromList ["x", "y"]) (not x))- `shouldBe` S.fromList [x0y0, x0y1]- it "Should work on not (2)" $ do- S.fromList (listTrue (S.fromList ["x", "y"]) (not y))- `shouldBe` S.fromList [x0y0, x1y0]+ let x0y0 = M.fromList [("x", False), ("y", False)]+ let x0y1 = M.fromList [("x", False), ("y", True)]+ let x1y0 = M.fromList [("x", True), ("y", False)]+ let x1y1 = M.fromList [("x", True), ("y", True)] - describe "Properties of independent sets in C_100" $ do+ it "Should work on &&" $ do+ S.fromList (completeAssignments ["x","y"] =<< trueAssignments (x && y))+ `shouldBe` S.fromList [x1y1]+ it "Should work on ||" $ do+ S.fromList (completeAssignments ["x","y"] =<< trueAssignments (x || y))+ `shouldBe` S.fromList [x0y1, x1y0, x1y1]+ it "Should work on not (1)" $ do+ S.fromList (completeAssignments ["x","y"] =<< trueAssignments (not x))+ `shouldBe` S.fromList [x0y0, x0y1]+ it "Should work on not (2)" $ do+ S.fromList (completeAssignments ["x","y"] =<< trueAssignments (not y))+ `shouldBe` S.fromList [x0y0, x1y0] - let l2 = (100,1):[(n,n+1) | n <- [1..99]]- let l3 = (99,100,1):(100,1,2):[(n,n+1,n+2) | n <- [1..98]]+ describe "Independent maximal sets in C_100 (mapping style)" $ do++ -- We build a decision tree representing all maximal subsets of+ -- {0,...,99} (regarded cyclically) with no consecutive elements.+ let l2 = (99,0):[(n,n+1) | n <- [0..98]]+ let l3 = (98,99,0):(99,0,1):[(n,n+1,n+2) | n <- [0..97]] let independent = all (\(i,j) -> not (test i && test j)) l2 let maximal = all (\(i,j,k) -> test i || test j || test k) l3- let t = independent && maximal+ let a = independent && maximal -- Mentioned in Knuth it "should have the right count" $ do- numberTrue (1::Int) 100 t `shouldBe` 1630580875002+ foldingCountTrue id 100 a `shouldBe` (1630580875002 :: Int) + describe "Independent maximal sets in C_100 (state style)" $ do++ -- As above, but using the state-based functionality++ let l2 = (99,0):[(n,n+1) | n <- [0..98]]+ let l3 = (98,99,0):(99,0,1):[(n,n+1,n+2) | n <- [0..97]]+ let { addIndependent m (i,j) = do+ x <- testS i+ y <- testS j+ z <- mergeS (&&) x y+ w <- mapS not z+ mergeS (&&) m w }+ let { addMaximal m (i,j,k) = do+ x <- testS i+ y <- testS j+ z <- testS k+ u <- mergeS (||) x y+ v <- mergeS (||) u z+ mergeS (&&) m v }+ let { a = runOnEmptyCache $ do+ t <- leafS True+ independent <- foldlM addIndependent t l2+ foldlM addMaximal independent l3 }++ it "should have the right count" $ do+ foldingCountTrue id 100 a `shouldBe` (1630580875002 :: Int)++ describe "Test of neighbours" $ do++ let m1 = decision "x" $ fromAscList 1 [(37,2),(74,3)]+ let m2 = decision "y" $ fromAscList 10 [(24,20),(83,30)]+ let m = m1 + m2 :: Decision Int (Piecewise Int) String Int+ it "should calculate neighbours correctly" $ do+ neighbours m `shouldBe` S.fromList [+ (11,12),(12,13),(21,22),(22,23),(31,32),(32,33),+ (11,21),(21,31),(12,22),(22,32),(13,23),(23,33)]+ describe "Decision trees for monomial divisibility" $ do - let xy2 = M.fromList [("X", 1::Int), ("Y", 2)]- let x2y = M.fromList [("X", 2), ("Y", 1)]- let xyz = M.fromList [("X", 1), ("Y", 1), ("Z", 1)]+ -- We build a decision tree which associates, to each monomial,+ -- the largest-numbered monomial that divides it (or 0 if no such+ -- exists).+ let xy2 = M.fromList [("X", 1::Int), ("Y", 2)] -- monomial 1+ let x2y = M.fromList [("X", 2), ("Y", 1)] -- monomial 2+ let xyz = M.fromList [("X", 1), ("Y", 1), ("Z", 1)] -- monomial 3 let monomials = M.fromList [(xy2, 1::Int), (x2y, 2), (xyz, 3)] let f i b = if b then i else 0- let d = M.foldlWithKey' (\t m i -> merge max t (mmap (f i) . buildAll $ fmap greaterThanOrEqual m)) (cst 0) monomials+ let { d = M.foldlWithKey' (\t m i -> merge max t (mmap (f i) $ decideAll (greaterThanOrEqual <$> m)))+ (cst 0)+ monomials :: Decision Int (Piecewise Int) String Int } let mapAct m = act d (\a -> M.findWithDefault 0 a $ M.fromList m) it "should get the right monomial for w^2y^4" $ do