module Funcons.Operations.Multisets where import Funcons.Operations.Booleans import Funcons.Operations.Internal import qualified Data.MultiSet as MS library :: (HasValues t, Ord t) => Library t library = libFromList [ ("multisets", UnaryExpr Funcons.Operations.Multisets.multisets) , ("multiset", NaryExpr multiset_) , ("multiset-elements", UnaryExpr multiset_elements) , ("multiset-occurrences", BinaryExpr multiset_occurrences) , ("multiset-insert", BinaryExpr multiset_insert) , ("multiset-delete", TernaryExpr multiset_delete) , ("is-submultiset", BinaryExpr is_submultiset) ] multisets_ :: HasValues t => [OpExpr t] -> OpExpr t multisets_ = unaryOp Funcons.Operations.Multisets.multisets multisets :: HasValues t => OpExpr t -> OpExpr t multisets = vUnaryOp "multisets" op where op (ComputationType (Type t)) = Normal $ injectT $ Funcons.Operations.Internal.multisets t op _ = SortErr "multisets not applied to a type" multiset_ :: (Ord t, HasValues t) => [OpExpr t] -> OpExpr t multiset_ = vNaryOp "multiset" op where op vs = Normal $ inject $ Multiset (MS.fromList vs) multiset_elements_ :: HasValues t => [OpExpr t] -> OpExpr t multiset_elements_ = unaryOp multiset_elements multiset_elements :: HasValues t => OpExpr t -> OpExpr t multiset_elements = vUnaryOp "multiset-elements" op where op (Multiset s) = Normal $ inject $ multi $ map inject $ MS.toList s op _ = SortErr "multiset-elements not applied to a multiset" multiset_occurrences_ :: (Ord t, HasValues t) => [OpExpr t] -> OpExpr t multiset_occurrences_ = binaryOp multiset_occurrences multiset_occurrences :: (Ord t, HasValues t) => OpExpr t -> OpExpr t -> OpExpr t multiset_occurrences = vBinaryOp "multiset-occurrences" op where op v (Multiset ms) = Normal $ inject $ Int count where count = toInteger $ MS.occur v ms op _ _ = SortErr "multiset-occurrences not applied to a value and a multiset" multiset_insert_ :: (Ord t, HasValues t) => [OpExpr t] -> OpExpr t multiset_insert_ = binaryOp multiset_insert multiset_insert :: (HasValues t, Ord t) => OpExpr t -> OpExpr t -> OpExpr t multiset_insert = vBinaryOp "multiset-insert" op where op e (Multiset s) = Normal $ inject $ Multiset (e `MS.insert` s) op _ _ = SortErr "second argument of multiset-insert is not a multiset" multiset_delete_ :: (Ord t, HasValues t) => [OpExpr t] -> OpExpr t multiset_delete_ = ternaryOp multiset_delete multiset_delete :: (Ord t, HasValues t) => OpExpr t -> OpExpr t -> OpExpr t -> OpExpr t multiset_delete = vTernaryOp "multiset-delete" op where op (Multiset s) gv x | Nat n <- upcastNaturals x = Normal $ inject $ Multiset (MS.deleteMany gv (fromInteger n) s) op _ _ _ = SortErr "multiset-delete not applied to a multiset, a potential element, and a natural number" is_submultiset_ :: (Ord t, HasValues t) => [OpExpr t] -> OpExpr t is_submultiset_ = binaryOp is_submultiset is_submultiset :: (Ord t, HasValues t) => OpExpr t -> OpExpr t -> OpExpr t is_submultiset = vBinaryOp "is-submultiset" op where op (Multiset s1) (Multiset s2) = Normal $ inject $ tobool (s1 `MS.isSubsetOf` s2) op _ _ = SortErr "is-submultiset not applied to two multisets"