@@ -1,14 +1,14 @@
1-- this is an implementation of the Relation typeclass which creates a GADT DSL
1-- this is an implementation of the Relation typeclass which creates a GADT DSL
2{-# LANGUAGE GADTs,ExistentialQuantification,NoImplicitPrelude #-}
2{-# LANGUAGE GADTs,ExistentialQuantification,NoImplicitPrelude #-}
3module ProjectM36.Relation where
3module ProjectM36.Relation where
4−import qualified Data.Map as M
5import qualified Data.Set as S
4import qualified Data.Set as S
6import qualified Data.HashSet as HS
5import qualified Data.HashSet as HS
7import Control.Monad
6import Control.Monad
7+import qualified Data.Vector as V
9import ProjectM36.Base
9import ProjectM36.Base
10import ProjectM36.Tuple
10import ProjectM36.Tuple
11−import ProjectM36.Attribute
11+import qualified ProjectM36.Attribute as A
12import ProjectM36.TupleSet
12import ProjectM36.TupleSet
13import ProjectM36.Error
13import ProjectM36.Error
14import Prelude hiding (join)
14import Prelude hiding (join)
@@ -17,48 +17,48 @@ attributes :: Relation -> Attributes
17attributes (Relation attrs _ ) = attrs
17attributes (Relation attrs _ ) = attrs
19attributeNames :: Relation -> S.Set AttributeName
19attributeNames :: Relation -> S.Set AttributeName
20−attributeNames (Relation attrs _) = M.keysSet attrs
20+attributeNames (Relation attrs _) = A.attributeNameSet attrs
22attributeForName :: AttributeName -> Relation -> Maybe Attribute
22attributeForName :: AttributeName -> Relation -> Maybe Attribute
23−attributeForName attrName (Relation attrs _) = M.lookup attrName attrs
23+attributeForName attrName (Relation attrs _) = A.attributeForName attrName attrs
25attributesForNames :: S.Set AttributeName -> Relation -> Attributes
25attributesForNames :: S.Set AttributeName -> Relation -> Attributes
26−attributesForNames attrNameSet (Relation attrs _) = M.intersection attrs hollowMap
26+attributesForNames attrNameSet (Relation attrs _) = A.attributesForNames attrNameSet attrs
28− hollowMap = M.fromList $ zip (S.toList attrNameSet) (repeat (Attribute "" StringAtomType))
30−attributeTypeForName :: AttributeName -> Relation -> Maybe AtomType
28+atomTypeForName :: AttributeName -> Relation -> Maybe AtomType
31−attributeTypeForName attrName rel = case attr of
29+atomTypeForName attrName (Relation attrs _) = A.atomTypeForAttributeName attrName attrs
32− (Just (Attribute _ atomType)) -> Just atomType
35− attr = attributeForName attrName rel
37atomValueType :: Atom -> AtomType
31atomValueType :: Atom -> AtomType
38atomValueType (StringAtom _) = StringAtomType
32atomValueType (StringAtom _) = StringAtomType
39atomValueType (IntAtom _) = IntAtomType
33atomValueType (IntAtom _) = IntAtomType
40atomValueType (RelationAtom rel) = RelationAtomType (attributes rel)
34atomValueType (RelationAtom rel) = RelationAtomType (attributes rel)
36+mkRelationFromList :: Attributes -> [[Atom]] -> Either RelationalError Relation
37+mkRelationFromList attrs atomMatrix = do
38+ tupSet <- mkTupleSetFromList attrs atomMatrix
39+ return $ Relation attrs tupSet
42mkRelation :: Attributes -> RelationTupleSet -> Either RelationalError Relation
41mkRelation :: Attributes -> RelationTupleSet -> Either RelationalError Relation
43mkRelation attrs tupleSet = do
42mkRelation attrs tupleSet = do
44 --check that all tuples have the same keys
43 --check that all tuples have the same keys
45 --check that all tuples have keys (1-N) where N is the attribute count
44 --check that all tuples have keys (1-N) where N is the attribute count
46− case verifyRelationTupleSet attrs tupleSet of
45+ case verifyTupleSet attrs tupleSet of
47 Left err -> Left err
46 Left err -> Left err
48 Right verifiedTupleSet -> return $ Relation attrs verifiedTupleSet
47 Right verifiedTupleSet -> return $ Relation attrs verifiedTupleSet
50relationTrue :: Relation
49relationTrue :: Relation
51−relationTrue = Relation M.empty $ HS.singleton (RelationTuple M.empty)
50+relationTrue = Relation A.emptyAttributes singletonTupleSet
53relationFalse :: Relation
52relationFalse :: Relation
54−relationFalse = Relation M.empty emptyTupleSet
53+relationFalse = Relation A.emptyAttributes emptyTupleSet
56madeTrue :: Either RelationalError Relation
55madeTrue :: Either RelationalError Relation
57−madeTrue = mkRelation M.empty (HS.fromList [])
56+madeTrue = mkRelation A.emptyAttributes (HS.fromList [])
59madeFalse :: Either RelationalError Relation
58madeFalse :: Either RelationalError Relation
60−madeFalse = mkRelation M.empty emptyTupleSet
59+madeFalse = mkRelation A.emptyAttributes emptyTupleSet
62--used for predicate filtering- instead of allowing for tuple types to be floating around in Tutorial D, just created a "singleton value" relation with cardinality and arity 1 for tuple atom comparison purposes
62--used for predicate filtering- instead of allowing for tuple types to be floating around in Tutorial D, just created a "singleton value" relation with cardinality and arity 1 for tuple atom comparison purposes
63singletonValueFromRelation :: Relation -> Either RelationalError Atom
63singletonValueFromRelation :: Relation -> Either RelationalError Atom
64singletonValueFromRelation rel@(Relation _ tupSet) = if cardinality rel /= Countable 1 then
64singletonValueFromRelation rel@(Relation _ tupSet) = if cardinality rel /= Countable 1 then
@@ -71,6 +71,7 @@ singletonValueFromRelation rel@(Relation _ tupSet) = if cardinality rel /= Count
71 value = snd $ head $ M.toList tupMap
71 value = snd $ head $ M.toList tupMap
72 tupMap = tup2Map $ head (HS.toList tupSet)
72 tupMap = tup2Map $ head (HS.toList tupSet)
73 tup2Map (RelationTuple tupmap) = tupmap
73 tup2Map (RelationTuple tupmap) = tupmap
75union :: Relation -> Relation -> Either RelationalError Relation
76union :: Relation -> Relation -> Either RelationalError Relation
76union (Relation attrs1 tupSet1) (Relation attrs2 tupSet2) =
77union (Relation attrs1 tupSet1) (Relation attrs2 tupSet2) =
@@ -83,7 +84,7 @@ union (Relation attrs1 tupSet1) (Relation attrs2 tupSet2) =
84project :: S.Set AttributeName -> Relation -> Either RelationalError Relation
85project :: S.Set AttributeName -> Relation -> Either RelationalError Relation
85project projectionAttrNames rel =
86project projectionAttrNames rel =
86− if not $ attributeNamesContained projectionAttrNames (attributeNames rel)
87+ if not $ A.attributeNamesContained projectionAttrNames (attributeNames rel)
87 then Left $ AttributeNameMismatchError ""
88 then Left $ AttributeNameMismatchError ""
89 relFold folder (Right $ Relation newAttrs HS.empty) rel
90 relFold folder (Right $ Relation newAttrs HS.empty) rel
@@ -94,12 +95,6 @@ project projectionAttrNames rel =
94 Left err -> Left err
95 Left err -> Left err
95 Right acc2 -> union acc2 (Relation newAttrs (HS.singleton (tupleProject projectionAttrNames tupleToProject)))
96 Right acc2 -> union acc2 (Relation newAttrs (HS.singleton (tupleProject projectionAttrNames tupleToProject)))
97−tupleProject :: S.Set AttributeName -> RelationTuple -> RelationTuple
98−tupleProject projectAttrs (RelationTuple tupleInMap) = RelationTuple $ M.filterWithKey attrFilter tupleInMap
100− attrFilter key _ = S.member key projectAttrs
102−--the expensive rename is why I wanted to use IntMap instead of attribute names in the tupleset
103rename :: AttributeName -> AttributeName -> Relation -> Either RelationalError Relation
98rename :: AttributeName -> AttributeName -> Relation -> Either RelationalError Relation
104rename oldAttrName newAttrName rel@(Relation oldAttrs oldTupSet) =
99rename oldAttrName newAttrName rel@(Relation oldAttrs oldTupSet) =
105 if not attributeValid
100 if not attributeValid
@@ -109,15 +104,15 @@ rename oldAttrName newAttrName rel@(Relation oldAttrs oldTupSet) =
110 mkRelation newAttrs newTupSet
105 mkRelation newAttrs newTupSet
112− newAttributeInUse = attributeNamesContained (S.singleton newAttrName) (attributeNames rel)
107+ newAttributeInUse = A.attributeNamesContained (S.singleton newAttrName) (attributeNames rel)
113− attributeValid = attributeNamesContained (S.singleton oldAttrName) (attributeNames rel)
108+ attributeValid = A.attributeNamesContained (S.singleton oldAttrName) (attributeNames rel)
114− newAttrs = M.delete oldAttrName $ M.insert newAttrName (renameAttribute newAttrName (oldAttrs M.! oldAttrName)) oldAttrs
109+ newAttrs = A.renameAttributes oldAttrName newAttrName oldAttrs
115 newTupSet = HS.map tupsetmapper oldTupSet
110 newTupSet = HS.map tupsetmapper oldTupSet
116 tupsetmapper tuple = tupleRenameAttribute oldAttrName newAttrName tuple
111 tupsetmapper tuple = tupleRenameAttribute oldAttrName newAttrName tuple
118--the algebra should return a relation of one attribute and one row with the arity
113--the algebra should return a relation of one attribute and one row with the arity
119arity :: Relation -> Int
114arity :: Relation -> Int
120−arity (Relation attrs _) = M.size attrs
115+arity (Relation attrs _) = A.arity attrs
122cardinality :: Relation -> RelationCardinality
117cardinality :: Relation -> RelationCardinality
123cardinality (Relation _ tupSet) = Countable (HS.size tupSet)
118cardinality (Relation _ tupSet) = Countable (HS.size tupSet)
@@ -151,31 +146,33 @@ group groupAttrNames newAttrName rel = do
151 nonGroupProjection <- project nonGroupAttrNames rel
146 nonGroupProjection <- project nonGroupAttrNames rel
152 relFold folder (Right $ Relation newAttrs emptyTupleSet) nonGroupProjection
147 relFold folder (Right $ Relation newAttrs emptyTupleSet) nonGroupProjection
154− newAttrs = M.insert newAttrName groupAttr (attributesForNames nonGroupAttrNames rel)
149+ newAttrs = A.addAttribute groupAttr (attributesForNames nonGroupAttrNames rel)
155 groupAttr = Attribute newAttrName (RelationAtomType (attributesForNames nonGroupAttrNames rel))
150 groupAttr = Attribute newAttrName (RelationAtomType (attributesForNames nonGroupAttrNames rel))
156− nonGroupAttrNames = nonMatchingAttributeNameSet groupAttrNames (attributeNames rel)
151+ nonGroupAttrNames = A.nonMatchingAttributeNameSet groupAttrNames (attributeNames rel)
157 folder tupleIn acc = case acc of
152 folder tupleIn acc = case acc of
158 Left err -> Left err
153 Left err -> Left err
159 Right acc2 -> union acc2 (Relation newAttrs (HS.singleton (tupleExtend tupleIn (matchingRelTuple tupleIn))))
154 Right acc2 -> union acc2 (Relation newAttrs (HS.singleton (tupleExtend tupleIn (matchingRelTuple tupleIn))))
160 matchingRelTuple groupTuple = case imageRelationFor groupTuple rel of
155 matchingRelTuple groupTuple = case imageRelationFor groupTuple rel of
161− Right rel2 -> RelationTuple $ M.singleton newAttrName (RelationAtom rel2)
156+ Right rel2 -> RelationTuple (V.singleton groupAttr) (V.singleton (RelationAtom rel2))
162 Left _ -> undefined
157 Left _ -> undefined
164--help restriction function
159--help restriction function
165--returns a subrelation of
160--returns a subrelation of
166restrictEq :: RelationTuple -> Relation -> Either RelationalError Relation
161restrictEq :: RelationTuple -> Relation -> Either RelationalError Relation
167−restrictEq (RelationTuple tupMap) rel = restrict rfilter rel
162+restrictEq tuple rel = restrict rfilter rel
169 rfilter :: RelationTuple -> Bool
164 rfilter :: RelationTuple -> Bool
170− rfilter (RelationTuple tupMap2) = M.isSubmapOf tupMap tupMap2
165+ rfilter tupleIn = tupleIntersection tuple tupleIn /= emptyTuple
172-- unwrap relation-valued attribute
167-- unwrap relation-valued attribute
173-- return error if relval attrs and nongroup attrs overlap
168-- return error if relval attrs and nongroup attrs overlap
174ungroup :: AttributeName -> Relation -> Either RelationalError Relation
169ungroup :: AttributeName -> Relation -> Either RelationalError Relation
170+ungroup relvalAttrName rel = case attributesForRelval relvalAttrName rel of
171+ Left err -> Left err
175−ungroup relvalAttrName rel = relFold relFolder (Right $ Relation newAttrs emptyTupleSet) rel
172+ Right relvalAttrs -> relFold relFolder (Right $ Relation newAttrs emptyTupleSet) rel
177− newAttrs = M.union (attributesForRelval relvalAttrName rel) nonGroupAttrs
174+ newAttrs = A.addAttributes relvalAttrs nonGroupAttrs
178− nonGroupAttrs = M.delete relvalAttrName (attributes rel)
175+ nonGroupAttrs = A.deleteAttributeName relvalAttrName (attributes rel)
179 relFolder :: RelationTuple -> Either RelationalError Relation -> Either RelationalError Relation
176 relFolder :: RelationTuple -> Either RelationalError Relation -> Either RelationalError Relation
180 relFolder tupleIn acc = case (tupleUngroup relvalAttrName newAttrs tupleIn) of
177 relFolder tupleIn acc = case (tupleUngroup relvalAttrName newAttrs tupleIn) of
181 Right ungroupRelation -> case acc of
178 Right ungroupRelation -> case acc of
@@ -187,36 +184,20 @@ ungroup relvalAttrName rel = relFold relFolder (Right $ Relation newAttrs emptyT
188--take an relval attribute name and a tuple and ungroup the relval
185--take an relval attribute name and a tuple and ungroup the relval
189tupleUngroup :: AttributeName -> Attributes -> RelationTuple -> Either RelationalError Relation
186tupleUngroup :: AttributeName -> Attributes -> RelationTuple -> Either RelationalError Relation
190−tupleUngroup relvalAttrName newAttrs tuple@(RelationTuple tupMap) = case (tupMap M.! relvalAttrName) of
187+tupleUngroup relvalAttrName newAttrs tuple = do
188+ relvalRelation <- relationForAttributeName relvalAttrName tuple
191− (RelationAtom relvalRelation) -> relFold folder (Right $ Relation newAttrs emptyTupleSet) relvalRelation
189+ relFold folder (Right $ Relation newAttrs emptyTupleSet) relvalRelation
193− nonGroupTupleProjection = tupleProject nonGroupAttrNames tuple
194− nonGroupAttrNames = M.keysSet newAttrs
195− folder tupleIn acc = case acc of
196− Left err -> Left err
197− Right accRel -> union accRel $ Relation newAttrs (HS.singleton (tupleExtend nonGroupTupleProjection tupleIn))
198− relvalRelation = unsafeRelValFromAtom $ tupleAtomForAttribute tuple relvalAttrName
200− unsafeRelValFromAtom :: Atom -> Relation
201− unsafeRelValFromAtom (RelationAtom rel) = rel
202− unsafeRelValFromAtom (StringAtom _) = undefined
203− unsafeRelValFromAtom (IntAtom _) = undefined
204− _ -> Left $ AttributeIsNotRelationValuedError relvalAttrName
206−--this is a hack needed because the relation attributes are untyped so we must dig into the relval to get the attribute names
207−attributesForRelval :: AttributeName -> Relation -> Attributes
208−attributesForRelval relvalAttrName (Relation _ tupleSet) = attributes relvalRelation
210− --this is only temporarily needed until the Relation stores the types of the columns as data- hack alert
191+ nonGroupTupleProjection = tupleProject nonGroupAttrNames tuple
211− --find a tuple with attributes to steal to ungroup
192+ nonGroupAttrNames = A.attributeNameSet newAttrs
212− oneTuple :: RelationTupleSet -> RelationTuple
193+ folder tupleIn acc = case acc of
213− oneTuple tupSet = head $ HS.toList $ HS.filter (\(RelationTuple tupMap) -> M.size tupMap > 0) tupSet
194+ Left err -> Left err
214− relvalRelation = unsafeRelValFromAtom $ tupleAtomForAttribute (oneTuple tupleSet) relvalAttrName
195+ Right accRel -> union accRel $ Relation newAttrs (HS.singleton (tupleExtend nonGroupTupleProjection tupleIn))
216− unsafeRelValFromAtom :: Atom -> Relation
197+attributesForRelval :: AttributeName -> Relation -> Either RelationalError Attributes
217− unsafeRelValFromAtom (RelationAtom rel) = rel
198+attributesForRelval relvalAttrName (Relation attrs _) = case A.atomTypeForAttributeName relvalAttrName attrs of
218− unsafeRelValFromAtom (StringAtom _) = undefined
199+ (Just (RelationAtomType relAttrs)) -> Right relAttrs
219− unsafeRelValFromAtom (IntAtom _) = undefined
200+ _ -> Left $ AttributeIsNotRelationValuedError relvalAttrName
221restrict :: (RelationTuple -> Bool) -> Relation -> Either RelationalError Relation
202restrict :: (RelationTuple -> Bool) -> Relation -> Either RelationalError Relation
222restrict rfilter (Relation attrs tupset) = Right $ Relation attrs $ HS.filter rfilter tupset
203restrict rfilter (Relation attrs tupset) = Right $ Relation attrs $ HS.filter rfilter tupset
@@ -225,11 +206,11 @@ restrict rfilter (Relation attrs tupset) = Right $ Relation attrs $ HS.filter rf
225--after changing from string atoms, there needs to be a type-checking step!
206--after changing from string atoms, there needs to be a type-checking step!
226--this is a "nested loop" scan as described by the postgresql documentation
207--this is a "nested loop" scan as described by the postgresql documentation
227join :: Relation -> Relation -> Either RelationalError Relation
208join :: Relation -> Relation -> Either RelationalError Relation
228−join (Relation attrs1 tupSet1) (Relation attrs2 tupSet2) = Right $ Relation newAttrs newTupSet
209+join (Relation attrs1 tupSet1) (Relation attrs2 tupSet2) = do
230− newAttrs = M.union attrs1 attrs2
231− newTupSet = HS.foldr tupleSetJoiner emptyTupleSet tupSet1
210+ let newTupSet = HS.foldr tupleSetJoiner emptyTupleSet tupSet1
232− tupleSetJoiner tuple1 accumulator = HS.union (singleTupleSetJoin tuple1 tupSet2) accumulator
211+ tupleSetJoiner tuple1 accumulator = HS.union (singleTupleSetJoin tuple1 tupSet2) accumulator
212+ newAttrs <- A.joinAttributes attrs1 attrs2
213+ return $ Relation newAttrs newTupSet
234--a map should NOT change the structure of a relation, so attributes should be constant
215--a map should NOT change the structure of a relation, so attributes should be constant
235relMap :: (RelationTuple -> RelationTuple) -> Relation -> Either RelationalError Relation
216relMap :: (RelationTuple -> RelationTuple) -> Relation -> Either RelationalError Relation
@@ -242,7 +223,7 @@ relMap mapper (Relation attrs tupleSet) = do
242 let remappedTuple = mapper tupleIn
223 let remappedTuple = mapper tupleIn
243 if tupleAttributes remappedTuple == tupleAttributes tupleIn
224 if tupleAttributes remappedTuple == tupleAttributes tupleIn
244 then Right remappedTuple
225 then Right remappedTuple
245− else Left $ TupleAttributeTypeMismatchError (attributesDifference (tupleAttributes tupleIn) attrs)
226+ else Left $ TupleAttributeTypeMismatchError (A.attributesDifference (tupleAttributes tupleIn) attrs)
247--in the future, the mapper should be able to return a RelationalError likely
228--in the future, the mapper should be able to return a RelationalError likely
248relMogrify :: (RelationTuple -> RelationTuple) -> Attributes -> Relation -> Either RelationalError Relation
229relMogrify :: (RelationTuple -> RelationTuple) -> Attributes -> Relation -> Either RelationalError Relation
@@ -258,12 +239,8 @@ relFold folder acc (Relation _ tupleSet) = HS.foldr folder acc tupleSet
258imageRelationFor :: RelationTuple -> Relation -> Either RelationalError Relation
239imageRelationFor :: RelationTuple -> Relation -> Either RelationalError Relation
259imageRelationFor matchTuple rel = do
240imageRelationFor matchTuple rel = do
260 restricted <- restrictEq matchTuple rel --restrict across matching tuples
241 restricted <- restrictEq matchTuple rel --restrict across matching tuples
261− project (nonMatchingAttributeNameSet (attributeNames rel) (tupleAttributeNameSet matchTuple)) restricted --project across attributes not in rel
242+ project (A.nonMatchingAttributeNameSet (attributeNames rel) (tupleAttributeNameSet matchTuple)) restricted --project across attributes not in rel
263−imageRelationTest :: Either RelationalError Relation
264−imageRelationTest = imageRelationFor tup s
266− tup = mkRelationTuple (S.fromList ["SNAME", "CITY", "S#"]) (M.fromList [("SNAME", StringAtom "Smith"), ("S#", StringAtom "S1"), ("CITY", StringAtom "London")])
268--returns a relation-valued attribute image relation for each tuple in rel1
245--returns a relation-valued attribute image relation for each tuple in rel1
269--algorithm:
246--algorithm:
@@ -278,61 +255,15 @@ imageRelationJoin rel1@(Relation attrNameSet1 tupSet1) rel2@(Relation attrNameSe
278 tupleSetJoiner tup1 acc = undefined
255 tupleSetJoiner tup1 acc = undefined
281−{- C.J. Date's canonical example relvars -}
283−relvarS :: Either RelationalError Relation
284−relvarS = mkRelation attributeSet tupleSet
286− attributeSet = M.fromList [("S#", Attribute "S#" StringAtomType),
287− ("SNAME", Attribute "SNAME" StringAtomType),
288− ("STATUS", Attribute "STATUS" IntAtomType),
289− ("CITY", Attribute "CITY" StringAtomType)]
290− tupleSet = HS.fromList $ mkRelationTuples attributeSet [
291− M.fromList [("S#", StringAtom "S1") , ("SNAME", StringAtom "Smith"), ("STATUS", IntAtom 20) , ("CITY", StringAtom "London")],
292− M.fromList [("S#", StringAtom "S2"), ("SNAME", StringAtom "Jones"), ("STATUS", IntAtom 10), ("CITY", StringAtom "Paris")],
293− M.fromList [("S#", StringAtom "S3"), ("SNAME", StringAtom "Blake"), ("STATUS", IntAtom 30), ("CITY", StringAtom "Paris")],
294− M.fromList [("S#", StringAtom "S4"), ("SNAME", StringAtom "Clark"), ("STATUS", IntAtom 20), ("CITY", StringAtom "London")],
295− M.fromList [("S#", StringAtom "S5"), ("SNAME", StringAtom "Adams"), ("STATUS", IntAtom 30), ("CITY", StringAtom "Athens")]]
298−s = case relvarS of { Right r -> r }
300−relvarP :: Either RelationalError Relation
301−relvarP = mkRelation attributeSet tupleSet
303− attributeSet = M.fromList [("P#", Attribute "P#" StringAtomType),
304− ("PNAME", Attribute "PNAME" StringAtomType),
305− ("COLOR", Attribute "COLOR" StringAtomType),
306− ("WEIGHT", Attribute "WEIGHT" StringAtomType),
307− ("CITY", Attribute "CITY" StringAtomType)]
308− tupleSet = HS.fromList $ mkRelationTuples attributeSet [
309− M.fromList [("P#", StringAtom "P1"), ("PNAME", StringAtom "Nut"), ("COLOR", StringAtom "Red"), ("WEIGHT", IntAtom 12), ("CITY", StringAtom "London")]
312−p = case relvarP of { Right r -> r }
314−relvarSP :: Either RelationalError Relation
315−relvarSP = mkRelation attributeSet tupleSet
317− attributeSet = M.fromList [("S#", Attribute "S#" StringAtomType),
318− ("P#", Attribute "P#" StringAtomType),
319− ("QTY", Attribute "QTY" StringAtomType)]
320− tupleSet = HS.fromList $ mkRelationTuples attributeSet [
321− M.fromList [("S#", StringAtom "S1"), ("P#", StringAtom "P1"), ("QTY", IntAtom 300)]
325−sp = case relvarSP of { Right r -> r }
328-- returns a relation with tupleCount tuples with a set of integer attributes attributesCount long
258-- returns a relation with tupleCount tuples with a set of integer attributes attributesCount long
329-- this is useful for performance and resource usage testing
259-- this is useful for performance and resource usage testing
330matrixRelation :: Int -> Int -> Either RelationalError Relation
260matrixRelation :: Int -> Int -> Either RelationalError Relation
331−matrixRelation attributeCount tupleCount = mkRelation attributeSet tupleSet
261+matrixRelation attributeCount tupleCount = do
333− attributeSet = M.fromList $ map (\c-> (show c, Attribute (show c) IntAtomType)) [0 .. attributeCount]
262+ let attrs = A.attributesFromList $ map (\c-> Attribute (show c) IntAtomType) [0 .. attributeCount]
334− tupleSet = HS.fromList $ mkRelationTuples attributeSet $ map (\c -> tuple c) [0 .. tupleCount]
263+ tuple tupleX = RelationTuple attrs (V.generate attributeCount (\_ -> IntAtom tupleX))
335− tuple tupleX = M.fromList $ map (\c -> (show c, IntAtom tupleX)) [0..attributeCount]
264+ tupleSet <- mkTupleSet attrs $ map (\c -> tuple c) [0 .. tupleCount]
265+ mkRelation attrs tupleSet