module ProjectM36.TupleSet where
import ProjectM36.Base
import ProjectM36.Tuple
import ProjectM36.Error
import qualified Data.HashSet as HS
import qualified Data.Vector as V
import qualified Control.Parallel.Strategies as P
import Data.Either

emptyTupleSet :: RelationTupleSet
emptyTupleSet :: RelationTupleSet
emptyTupleSet = [RelationTuple] -> RelationTupleSet
RelationTupleSet []

singletonTupleSet :: RelationTupleSet
singletonTupleSet :: RelationTupleSet
singletonTupleSet = [RelationTuple] -> RelationTupleSet
RelationTupleSet [RelationTuple
emptyTuple]

--ensure that all maps have the same keys and key count

verifyTupleSet :: Attributes -> RelationTupleSet -> Either RelationalError RelationTupleSet
verifyTupleSet :: Attributes
-> RelationTupleSet -> Either RelationalError RelationTupleSet
verifyTupleSet Attributes
attrs RelationTupleSet
tupleSet = do
  --check that all tuples have the same attributes and that the atom types match
  let tupleList :: [Either RelationalError RelationTuple]
tupleList = (RelationTuple -> Either RelationalError RelationTuple)
-> [RelationTuple] -> [Either RelationalError RelationTuple]
forall a b. (a -> b) -> [a] -> [b]
map (Attributes -> RelationTuple -> Either RelationalError RelationTuple
verifyTuple Attributes
attrs) (RelationTupleSet -> [RelationTuple]
asList RelationTupleSet
tupleSet) [Either RelationalError RelationTuple]
-> Strategy [Either RelationalError RelationTuple]
-> [Either RelationalError RelationTuple]
forall a. a -> Strategy a -> a
`P.using` Int
-> Strategy (Either RelationalError RelationTuple)
-> Strategy [Either RelationalError RelationTuple]
forall a. Int -> Strategy a -> Strategy [a]
P.parListChunk Int
chunkSize Strategy (Either RelationalError RelationTuple)
forall a. Strategy a
P.r0
      chunkSize :: Int
chunkSize = ([RelationTuple] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([RelationTuple] -> Int)
-> (RelationTupleSet -> [RelationTuple]) -> RelationTupleSet -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RelationTupleSet -> [RelationTuple]
asList) RelationTupleSet
tupleSet Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
24
  --let tupleList = P.parMap P.rdeepseq (verifyTuple attrs) (HS.toList tupleSet)
  if Bool -> Bool
not ([RelationalError] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Either RelationalError RelationTuple] -> [RelationalError]
forall a b. [Either a b] -> [a]
lefts [Either RelationalError RelationTuple]
tupleList)) then
    RelationalError -> Either RelationalError RelationTupleSet
forall a b. a -> Either a b
Left (RelationalError -> Either RelationalError RelationTupleSet)
-> RelationalError -> Either RelationalError RelationTupleSet
forall a b. (a -> b) -> a -> b
$ [RelationalError] -> RelationalError
forall a. [a] -> a
head ([Either RelationalError RelationTuple] -> [RelationalError]
forall a b. [Either a b] -> [a]
lefts [Either RelationalError RelationTuple]
tupleList)
   else
     RelationTupleSet -> Either RelationalError RelationTupleSet
forall (m :: * -> *) a. Monad m => a -> m a
return (RelationTupleSet -> Either RelationalError RelationTupleSet)
-> RelationTupleSet -> Either RelationalError RelationTupleSet
forall a b. (a -> b) -> a -> b
$ [RelationTuple] -> RelationTupleSet
RelationTupleSet ([RelationTuple] -> RelationTupleSet)
-> [RelationTuple] -> RelationTupleSet
forall a b. (a -> b) -> a -> b
$ (HashSet RelationTuple -> [RelationTuple]
forall a. HashSet a -> [a]
HS.toList (HashSet RelationTuple -> [RelationTuple])
-> ([RelationTuple] -> HashSet RelationTuple)
-> [RelationTuple]
-> [RelationTuple]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [RelationTuple] -> HashSet RelationTuple
forall a. (Eq a, Hashable a) => [a] -> HashSet a
HS.fromList) ([Either RelationalError RelationTuple] -> [RelationTuple]
forall a b. [Either a b] -> [b]
rights [Either RelationalError RelationTuple]
tupleList)

mkTupleSet :: Attributes -> [RelationTuple] -> Either RelationalError RelationTupleSet
mkTupleSet :: Attributes
-> [RelationTuple] -> Either RelationalError RelationTupleSet
mkTupleSet Attributes
attrs [RelationTuple]
tuples = Attributes
-> RelationTupleSet -> Either RelationalError RelationTupleSet
verifyTupleSet Attributes
attrs ([RelationTuple] -> RelationTupleSet
RelationTupleSet [RelationTuple]
tuples)

mkTupleSetFromList :: Attributes -> [[Atom]] -> Either RelationalError RelationTupleSet
mkTupleSetFromList :: Attributes -> [[Atom]] -> Either RelationalError RelationTupleSet
mkTupleSetFromList Attributes
attrs [[Atom]]
atomMatrix = Attributes
-> [RelationTuple] -> Either RelationalError RelationTupleSet
mkTupleSet Attributes
attrs ([RelationTuple] -> Either RelationalError RelationTupleSet)
-> [RelationTuple] -> Either RelationalError RelationTupleSet
forall a b. (a -> b) -> a -> b
$ ([Atom] -> RelationTuple) -> [[Atom]] -> [RelationTuple]
forall a b. (a -> b) -> [a] -> [b]
map (Attributes -> Vector Atom -> RelationTuple
mkRelationTuple Attributes
attrs (Vector Atom -> RelationTuple)
-> ([Atom] -> Vector Atom) -> [Atom] -> RelationTuple
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Atom] -> Vector Atom
forall a. [a] -> Vector a
V.fromList) [[Atom]]
atomMatrix


-- | Union two tuplesets while reordering their attribute/atom mapping properly.
tupleSetUnion :: Attributes -> RelationTupleSet -> RelationTupleSet -> RelationTupleSet
tupleSetUnion :: Attributes
-> RelationTupleSet -> RelationTupleSet -> RelationTupleSet
tupleSetUnion Attributes
targetAttrs RelationTupleSet
tupSet1 RelationTupleSet
tupSet2 = [RelationTuple] -> RelationTupleSet
RelationTupleSet ([RelationTuple] -> RelationTupleSet)
-> [RelationTuple] -> RelationTupleSet
forall a b. (a -> b) -> a -> b
$ HashSet RelationTuple -> [RelationTuple]
forall a. HashSet a -> [a]
HS.toList (HashSet RelationTuple -> [RelationTuple])
-> ([RelationTuple] -> HashSet RelationTuple)
-> [RelationTuple]
-> [RelationTuple]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [RelationTuple] -> HashSet RelationTuple
forall a. (Eq a, Hashable a) => [a] -> HashSet a
HS.fromList ([RelationTuple] -> [RelationTuple])
-> [RelationTuple] -> [RelationTuple]
forall a b. (a -> b) -> a -> b
$ [RelationTuple] -> [RelationTuple]
reorder (RelationTupleSet -> [RelationTuple]
asList RelationTupleSet
tupSet1) [RelationTuple] -> [RelationTuple] -> [RelationTuple]
forall a. [a] -> [a] -> [a]
++ [RelationTuple] -> [RelationTuple]
reorder (RelationTupleSet -> [RelationTuple]
asList RelationTupleSet
tupSet2)
  where
    reorder :: [RelationTuple] -> [RelationTuple]
reorder = (RelationTuple -> RelationTuple)
-> [RelationTuple] -> [RelationTuple]
forall a b. (a -> b) -> [a] -> [b]
map (Attributes -> RelationTuple -> RelationTuple
reorderTuple Attributes
targetAttrs)