module Nominal.Set (
Set,
empty,
atoms,
fromList,
singleton,
insert,
insertAll,
delete,
deleteAll,
isEmpty,
isNotEmpty,
map,
filter,
mapFilter,
sum,
exists,
forAll,
partition,
contains,
notContains,
member,
notMember,
isSubsetOf,
isNotSubsetOf,
isProperSubsetOf,
isNotProperSubsetOf,
union,
unions,
intersection,
intersect,
disjoint,
difference,
(\\),
pairs,
pairsWith,
pairsWithFilter,
square,
atomsPairs,
differentAtomsPairs,
triples,
triplesWith,
triplesWithFilter,
atomsTriples,
mapList,
replicateSet,
replicateSetUntil,
replicateAtoms,
replicateAtomsUntil,
hasSizeLessThan,
hasSize,
listSize,
listSizeWith,
listMaxSize,
listMaxSizeWith,
size,
sizeWith,
maxSize,
maxSizeWith,
isSingleton,
range,
openRange,
isLowerBound,
hasLowerBound,
isUpperBound,
hasUpperBound,
isMinimum,
hasMinimum,
isMaximum,
hasMaximum,
isInfimum,
isSupremum,
isConnected,
isOpen,
isClosed,
isCompact) where
import Control.DeepSeq (NFData)
import Data.IORef (IORef, readIORef, newIORef, writeIORef)
import qualified Data.List as List ((\\))
import Data.List.Utils (join)
import qualified Data.Maybe as Maybe
import Data.Map (Map)
import qualified Data.Map as Map
import qualified Data.Set as Set
import Data.Word (Word)
import GHC.Generics (Generic)
import Nominal.Atoms
import Nominal.Atoms.Logic (exclusiveConditions)
import Nominal.Conditional
import Nominal.Contextual
import Nominal.Formula
import Nominal.Formula.Constructors (constraint)
import Nominal.Formula.Operators (getEquationsFromFormula)
import Nominal.Maybe
import qualified Nominal.Text.Symbols as Symbols
import Nominal.Type (FoldVarFun, MapVarFun, BareNominalType(..), NominalType(..), Scope(..), collectWith, freeVariables, getAllVariables, mapVariablesIf, neq, replaceVariables)
import qualified Nominal.Util.InsertionSet as ISet
import Nominal.Util.UnionFind (representatives)
import Nominal.Variable (Identifier, Variable, changeIterationLevel, clearIdentifier, getIterationLevel, hasIdentifierEquals,
hasIdentifierNotEquals, iterationVariablesList, iterationVariable, setIdentifier, variableName)
import Nominal.Variants (Variants, fromVariant, toList, variant)
import qualified Nominal.Variants as V
import Prelude hiding (or, and, not, sum, map, filter)
import qualified Prelude as P
import System.IO.Unsafe (unsafePerformIO)
type SetElementCondition = (Set.Set Variable, Formula)
getCondition :: SetElementCondition -> Formula
getCondition (vs, c) = Set.foldr (∃) c vs
sumCondition :: SetElementCondition -> SetElementCondition -> SetElementCondition
sumCondition (vs1, c1) (vs2, c2) = (Set.union vs1 vs2, c1 \/ c2)
checkVariablesInElement :: NominalType a => (a, SetElementCondition) -> (a, SetElementCondition)
checkVariablesInElement (v, (vs, c)) =
let iterVars = foldVariables (All, \var -> if Set.member var vs then ISet.insert var else id) ISet.empty v
formulaVars = getAllVariables c
c' = getCondition (Set.intersection formulaVars (vs Set.\\ ISet.toSet iterVars), c)
in if ISet.null iterVars
then (v, (Set.empty, c'))
else let oldIterVars = ISet.toList iterVars
newIterVars = iterationVariablesList (minimum $ fmap (Maybe.fromJust . getIterationLevel) $ Set.elems vs)
(length oldIterVars)
in if oldIterVars == newIterVars
then (v, (Set.fromList oldIterVars, c'))
else let replaceMap = (Map.fromList $ zip oldIterVars newIterVars)
in (replaceVariables replaceMap v, (Set.fromList newIterVars, replaceVariables replaceMap c'))
checkVariables :: NominalType a => Map a SetElementCondition -> Map a SetElementCondition
checkVariables = Map.fromListWith sumCondition . Map.foldrWithKey (\v c es -> checkVariablesInElement (v, c) : es) []
filterSetElems :: NominalType a => (a -> SetElementCondition) -> Map a SetElementCondition -> Map a SetElementCondition
filterSetElems f = filterNotFalse . Map.mapWithKey (\v (vs, c) -> let fv = f v in (Set.union vs $ fst fv, c /\ snd fv))
filterNotFalse :: Map a SetElementCondition -> Map a SetElementCondition
filterNotFalse = Map.filter ((/= false) . snd)
checkEquality :: NominalType a => (a, SetElementCondition) -> (a, SetElementCondition)
checkEquality (v, (vs, c)) =
if Set.null eqs
then (v, (vs, c))
else if Map.null eqsMap
then (v, (vs, c))
else checkVariablesInElement (replaceVariables eqsMap v, (vs', replaceVariables eqsMap c))
where eqs = getEquationsFromFormula c
(vs', eqsMap) = foldr checkVars (vs, Map.empty) $ representatives $ Set.elems eqs
checkVars (x1, x2) (vs, m)
| Set.member x1 vs = (Set.delete x1 vs, Map.insert x1 x2 m)
| Set.member x2 vs = (Set.delete x2 vs, Map.insert x2 x1 m)
| otherwise = (vs, m)
checkIdentifiers :: (NominalType a, NominalType b) => Identifier -> (a, (b, SetElementCondition)) -> (a, (b, SetElementCondition))
checkIdentifiers id (oldV, (newV, cond)) =
let otherVarsLevels = Set.toAscList $ collectWith (\var -> if hasIdentifierNotEquals id var then getIterationLevel var else Nothing) (oldV, newV)
iterVarsLevels = Set.toAscList $ collectWith (\var -> if hasIdentifierEquals id var then getIterationLevel var else Nothing) (newV, cond)
newIterVarsLevels = [0..] List.\\ otherVarsLevels
changeLevelsMap = Map.fromList $ zip iterVarsLevels newIterVarsLevels
in mapVariablesIf (hasIdentifierEquals id) (clearIdentifier . changeIterationLevel changeLevelsMap) (oldV, (newV, cond))
counter :: IORef Word
counter = unsafePerformIO $ newIORef 0
getVariableId :: Set.Set Variable -> Word
getVariableId vs = unsafePerformIO $
do
i <- readIORef counter
writeIORef counter (i + (fromIntegral $ Set.size vs) + 1)
return i
applyWithIdentifiers :: (NominalType a, NominalType b) => (a -> b) -> (a, SetElementCondition) -> [(a, (b, SetElementCondition))]
applyWithIdentifiers f (v, cond) =
let id = getVariableId $ fst $ cond
(v', cond') = mapVariablesIf (flip Set.member $ fst cond) (setIdentifier id) (v, cond)
in fmap (\(v'', c) -> checkIdentifiers id (v', (v'', fmap (/\ c) cond'))) (toList $ variants $ f v')
newtype Set a = Set {setElements :: Map a SetElementCondition} deriving (Eq, Ord, Generic, NFData)
instance Show a => Show (Set a) where
show s = "{" ++ (join ", " (fmap showSetElement (Map.assocs $ setElements s))) ++ "}"
where showSetElement (v, (vs, c)) =
let formula = if c == true then "" else " " ++ show c
variables = if Set.null vs
then ""
else " for " ++ (join "," (fmap show $ Set.elems vs)) ++ " " ++ Symbols.inSet ++ " " ++ Symbols.atoms
condition = formula ++ variables
in show v ++ (if null condition then "" else " :" ++ condition)
instance NominalType a => Conditional (Set a) where
cond c s1 s2 = union (filter (const c) s1) (filter (const $ not c) s2)
instance (Contextual a, Ord a) => Contextual (Set a) where
when ctx (Set es) = Set $ filterNotFalse
$ Map.fromListWith sumCondition
$ fmap (\(v,(vs, c)) -> (when (ctx /\ c) v, when ctx (vs, c)))
$ Map.assocs es
mapWithout :: Set.Set Variable -> (Variable -> Variable) -> Variable -> Variable
mapWithout vs f x = if Set.member x vs then x else f x
mapSetVariables :: NominalType a => MapVarFun -> (a, SetElementCondition) -> (a, SetElementCondition)
mapSetVariables (All, f) se = mapVariables (All, f) se
mapSetVariables (Free, f) (v, (vs, c)) = mapVariables (Free, (mapWithout vs f)) (v, (vs, c))
foldWithout :: Set.Set Variable -> (Variable -> b -> b) -> Variable -> b -> b
foldWithout vs f x = if Set.member x vs then id else f x
foldSetVariables :: NominalType a => FoldVarFun b -> b -> (a, SetElementCondition) -> b
foldSetVariables (All, f) acc se = foldVariables (All, f) acc se
foldSetVariables (Free, f) acc (v, (vs, c)) = foldVariables (Free, (foldWithout vs f)) acc (v, (vs, c))
instance NominalType a => BareNominalType (Set a) where
eq s1 s2 = (isSubsetOf s1 s2) /\ (isSubsetOf s2 s1)
variants = variant
mapVariables f (Set es) = Set $ Map.fromListWith sumCondition $ fmap (mapSetVariables f) (Map.assocs es)
foldVariables f acc (Set es) = foldl (foldSetVariables f) acc (Map.assocs es)
instance NominalType a => BareNominalType (Set.Set a) where
eq s1 s2 = eq (fromList $ Set.elems s1) (fromList $ Set.elems s2)
variants = variant
mapVariables f = Set.map (mapVariables f)
foldVariables f acc = foldVariables f acc . Set.elems
instance (NominalType k, NominalType a) => BareNominalType (Map k a) where
eq m1 m2 = eq (fromList $ Map.assocs m1) (fromList $ Map.assocs m2)
variants = variant
mapVariables f = Map.fromList . mapVariables f . Map.assocs
foldVariables f acc = foldVariables f acc . Map.assocs
empty :: Set a
empty = Set Map.empty
isNotEmpty :: Set a -> Formula
isNotEmpty (Set es) = or $ fmap getCondition $ Map.elems es
insert :: NominalType a => a -> Set a -> Set a
insert e (Set es) = Set $ foldr insertVariant es (toList $ variants e)
where insertVariant (v, c) = Map.insertWith sumCondition v (Set.empty, c)
delete :: NominalType a => a -> Set a -> Set a
delete e = filter (not . (eq e)) . Set . (Map.delete e) . setElements
map :: (NominalType a, NominalType b) => (a -> b) -> Set a -> Set b
map f = Set . filterNotFalse
. checkVariables
. Map.fromListWith sumCondition
. Map.foldrWithKey (mapAndMerge f) []
. setElements
where mapAndMerge f v cond rs = fmap snd (applyWithIdentifiers f (v, cond)) ++ rs
filter :: NominalType a => (a -> Formula) -> Set a -> Set a
filter f = Set . filterNotFalse
. Map.fromListWith sumCondition
. Map.foldrWithKey (filterAndMerge f) []
. setElements
where filterAndMerge f v cond rs = fmap (\(v', (c, cond')) -> checkEquality (v', (fst cond', c /\ snd cond')))
(applyWithIdentifiers f (v, cond))
++ rs
sum :: NominalType a => Set (Set a) -> Set a
sum = Set . checkVariables
. Map.unionsWith sumCondition . fmap filterSetInSet . Map.assocs . setElements
where filterSetInSet (elemSet, elemSetCond) = filterSetElems (const elemSetCond) (setElements elemSet)
atoms :: Set Atom
atoms = let iterVar = iterationVariable 0 1
in Set $ Map.singleton (variant iterVar) (Set.singleton iterVar, true)
isEmpty :: Set a -> Formula
isEmpty = not . isNotEmpty
singleton :: NominalType a => a -> Set a
singleton e = insert e empty
insertAll :: NominalType a => [a] -> Set a -> Set a
insertAll es s = foldl (flip insert) s es
fromList :: NominalType a => [a] -> Set a
fromList es = insertAll es empty
mapFilter :: (NominalType a, NominalType b) => (a -> NominalMaybe b) -> Set a -> Set b
mapFilter f = map fromVariant . map fromJust . filter isJust . map f
deleteAll :: NominalType a => [a] -> Set a -> Set a
deleteAll es s = foldl (flip delete) s es
exists :: NominalType a => (a -> Formula) -> Set a -> Formula
exists f = isNotEmpty . (filter f)
forAll :: NominalType a => (a -> Formula) -> Set a -> Formula
forAll f = isEmpty . (filter $ \x -> not (f x))
partition :: NominalType a => (a -> Formula) -> Set a -> (Set a, Set a)
partition f s = let ss = map (\e -> (e, f e)) s
in (map fst $ filter snd ss, map fst $ filter (not . snd) ss)
union :: NominalType a => Set a -> Set a -> Set a
union s1 s2 = sum (insert s1 (singleton s2))
unions :: NominalType a => [Set a] -> Set a
unions = foldl union empty
contains :: NominalType a => Set a -> a -> Formula
contains s e = exists (eq e) s
notContains :: NominalType a => Set a -> a -> Formula
notContains s = not . contains s
member :: NominalType a => a -> Set a -> Formula
member = flip contains
notMember :: NominalType a => a -> Set a -> Formula
notMember = flip notContains
isSubsetOf :: NominalType a => Set a -> Set a -> Formula
isSubsetOf s1 s2 = forAll (contains s2) s1
isNotSubsetOf :: NominalType a => Set a -> Set a -> Formula
isNotSubsetOf s = not . isSubsetOf s
isProperSubsetOf :: NominalType a => Set a -> Set a -> Formula
isProperSubsetOf s1 s2 = (isSubsetOf s1 s2) /\ (isNotSubsetOf s2 s1)
isNotProperSubsetOf :: NominalType a => Set a -> Set a -> Formula
isNotProperSubsetOf s = not . isProperSubsetOf s
intersection :: NominalType a => Set a -> Set a -> Set a
intersection s1 s2 = filter (contains s1) s2
intersect :: NominalType a => Set a -> Set a -> Formula
intersect s1 s2 = isNotEmpty $ intersection s1 s2
disjoint :: NominalType a => Set a -> Set a -> Formula
disjoint s1 s2 = not (intersect s1 s2)
difference :: NominalType a => Set a -> Set a -> Set a
difference s1 s2 = filter (notContains s2) s1
infixl 9 \\
(\\) :: NominalType a => Set a -> Set a -> Set a
s1 \\ s2 = difference s1 s2
pairs :: (NominalType a, NominalType b) => Set a -> Set b -> Set (a, b)
pairs = pairsWith (,)
pairsWith :: (NominalType a, NominalType b, NominalType c) => (a -> b -> c) -> Set a -> Set b -> Set c
pairsWith f s1 s2 = sum $ map (\e1 -> map (f e1) s2) s1
pairsWithFilter :: (NominalType a, NominalType b, NominalType c) => (a -> b -> NominalMaybe c) -> Set a -> Set b -> Set c
pairsWithFilter f s1 s2 = mapFilter id (pairsWith f s1 s2)
square :: NominalType a => Set a -> Set (a, a)
square s = pairs s s
atomsPairs :: Set (Atom, Atom)
atomsPairs = square atoms
differentAtomsPairs :: Set (Atom, Atom)
differentAtomsPairs = filter (uncurry neq) atomsPairs
triples :: (NominalType a, NominalType b, NominalType c) => Set a -> Set b -> Set c -> Set (a, b, c)
triples = triplesWith (,,)
triplesWith :: (NominalType a, NominalType b, NominalType c, NominalType d)
=> (a -> b -> c -> d) -> Set a -> Set b -> Set c -> Set d
triplesWith f s1 s2 s3 = sum $ sum $ map (\e1 -> map (\e2 -> map (f e1 e2) s3) s2) s1
triplesWithFilter :: (NominalType a, NominalType b, NominalType c, NominalType d)
=> (a -> b -> c -> NominalMaybe d) -> Set a -> Set b -> Set c -> Set d
triplesWithFilter f s1 s2 s3 = mapFilter id (triplesWith f s1 s2 s3)
atomsTriples :: Set (Atom, Atom, Atom)
atomsTriples = triples atoms atoms atoms
mapList :: (NominalType a, NominalType b) => ([a] -> b) -> [Set a] -> Set b
mapList f sets = map f $ foldr (pairsWith (:)) (singleton []) sets
replicateSet :: NominalType a => Int -> Set a -> Set [a]
replicateSet n s = mapList id (replicate n s)
replicateSetUntil :: NominalType a => Int -> Set a -> Set [a]
replicateSetUntil n s = unions $ fmap (flip replicateSet s) [0..n]
replicateAtoms :: Int -> Set [Atom]
replicateAtoms n = replicateSet n atoms
replicateAtomsUntil :: Int -> Set [Atom]
replicateAtomsUntil n = replicateSetUntil n atoms
hasSizeLessThan :: NominalType a => Set a -> Int -> Formula
hasSizeLessThan s n = forAll id $ mapList (\xs -> let l = length xs in or [eq (xs!!i) (xs!!j) | i <- [0..l1], j <- [0..l1], i<j]) (replicate n s)
hasSize :: NominalType a => Set a -> Int -> Formula
hasSize s n = hasSizeLessThan s (succ n) /\ not (hasSizeLessThan s n)
isSingleton :: NominalType a => Set a -> Formula
isSingleton s = hasSize s 1
listSizeWith :: (a -> a -> Formula) -> [a] -> Variants Int
listSizeWith eq = simplify . go
where go [] = variant 0
go (e:l) = let s = go l in ite (or $ fmap (eq e) l) s (V.map (+1) s)
listSize :: NominalType a => [a] -> Variants Int
listSize = listSizeWith eq
listMaxSizeWith :: (a -> a -> Formula) -> [a] -> Int
listMaxSizeWith _ [] = 0
listMaxSizeWith eq (e:l) = let s = listMaxSizeWith eq l in if isTrue (or $ fmap (eq e) l) then s else (s+1)
listMaxSize :: NominalType a => [a] -> Int
listMaxSize = listMaxSizeWith eq
setValues :: (Contextual a, NominalType a) => Set a -> Maybe [a]
setValues s = if P.any Maybe.isNothing values
then Nothing
else Just $ concat $ fmap Maybe.fromJust values
where values = fmap elemValues $ Map.assocs $ setElements s
elemValues :: (Contextual a, NominalType a) => (a, SetElementCondition) -> Maybe [a]
elemValues (v, (vs, c)) = if all (\val -> Set.null $ Set.intersection vs $ freeVariables val) values
then Just values
else Nothing
where vars = Set.elems $ Set.union vs (freeVariables v)
conds = exclusiveConditions vars
values = fmap (flip when v) $ P.filter (/= false) $ fmap (simplifyFormula . (c /\)) conds
sizeWith :: (Contextual a, NominalType a) => (a -> a -> Formula) -> Set a -> Variants Int
sizeWith eq s = Maybe.maybe (findSize s 1) (listSizeWith eq) (setValues s)
where findSize s n = ite (hasSizeLessThan s n) (variant $ pred n) (findSize s (succ n))
size :: (Contextual a, NominalType a) => Set a -> Variants Int
size = sizeWith eq
maxSizeWith :: (Contextual a, NominalType a) => (a -> a -> Formula) -> Set a -> Int
maxSizeWith eq s = Maybe.maybe (findSize s 1) (listMaxSizeWith eq) (setValues s)
where findSize s n = if isTrue (hasSizeLessThan s n) then pred n else findSize s (succ n)
maxSize :: (Contextual a, NominalType a) => Set a -> Int
maxSize = maxSizeWith eq
range :: Atom -> Atom -> Set Atom
range l u = filter (\a -> ge a l /\ le a u) atoms
openRange :: Atom -> Atom -> Set Atom
openRange l u = filter (\a -> gt a l /\ lt a u) atoms
isLowerBound :: Atom -> Set Atom -> Formula
isLowerBound a s = forAll (le a) s
hasLowerBound :: Set Atom -> Formula
hasLowerBound s = exists (`isLowerBound` s) atoms
isUpperBound :: Atom -> Set Atom -> Formula
isUpperBound a s = forAll (ge a) s
hasUpperBound :: Set Atom -> Formula
hasUpperBound s = exists (`isUpperBound` s) atoms
isMinimum :: Atom -> Set Atom -> Formula
isMinimum a s = member a s /\ isLowerBound a s
hasMinimum :: Set Atom -> Formula
hasMinimum s = exists (`isLowerBound` s) s
isMaximum :: Atom -> Set Atom -> Formula
isMaximum a s = member a s /\ isUpperBound a s
hasMaximum :: Set Atom -> Formula
hasMaximum s = exists (`isUpperBound` s) s
isInfimum :: Atom -> Set Atom -> Formula
isInfimum a s = isMaximum a $ filter (`isLowerBound` s) atoms
isSupremum :: Atom -> Set Atom -> Formula
isSupremum a s = isMinimum a $ filter (`isUpperBound` s) atoms
isConnected :: Set Atom -> Formula
isConnected s = forAll (\a -> isUpperBound a s \/ isLowerBound a s) $ atoms \\ s
isOpen :: Set Atom -> Formula
isOpen s = forAll (\a -> exists (\(b,c) -> lt b a /\ lt a c /\ isSubsetOf (range b c) s) atomsPairs) s
isClosed :: Set Atom -> Formula
isClosed s = isOpen $ atoms \\ s
isCompact :: Set Atom -> Formula
isCompact s = isClosed s /\ hasUpperBound s /\ hasLowerBound s