-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
- Loading branch information
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
module Data.RDF.PatriciaTreeGraph where | ||
|
||
import Data.RDF.Namespace | ||
import Data.RDF.Query | ||
import Data.RDF.Types | ||
|
||
import qualified Data.Graph.Inductive.Graph as G | ||
import qualified Data.Graph.Inductive.PatriciaTree as PT | ||
import qualified Data.Graph.Inductive.Query.DFS as DFS | ||
import qualified Data.IntMap as IntMap | ||
import Data.List | ||
import qualified Data.Map as Map | ||
import Data.Maybe | ||
import qualified Data.Text as T | ||
|
||
newtype PatriciaTreeGraph = PatriciaTreeGraph (PT.Gr Node Node,IntMap.IntMap Node, Maybe BaseUrl, PrefixMappings) | ||
deriving (Show) | ||
|
||
instance RDF PatriciaTreeGraph where | ||
baseUrl = baseUrl' | ||
prefixMappings = prefixMappings' | ||
addPrefixMappings = addPrefixMappings' | ||
empty = empty' | ||
mkRdf = mkRdf' | ||
triplesOf = uniqTriplesOf' | ||
uniqTriplesOf = uniqTriplesOf' | ||
select = select' | ||
query = query' | ||
|
||
empty' :: PatriciaTreeGraph | ||
empty' = PatriciaTreeGraph (G.empty,IntMap.empty, Nothing, PrefixMappings Map.empty) | ||
|
||
prefixMappings' :: PatriciaTreeGraph -> PrefixMappings | ||
prefixMappings' (PatriciaTreeGraph (_,_,_,pms')) = pms' | ||
|
||
addPrefixMappings' :: PatriciaTreeGraph -> PrefixMappings -> Bool -> PatriciaTreeGraph | ||
addPrefixMappings' (PatriciaTreeGraph (g, idxLookup, baseURL, pms)) pms' replace = | ||
let merge = if replace then flip mergePrefixMappings else mergePrefixMappings | ||
in PatriciaTreeGraph (g, idxLookup, baseURL, merge pms pms') | ||
|
||
baseUrl' :: PatriciaTreeGraph -> Maybe BaseUrl | ||
baseUrl' (PatriciaTreeGraph _) = Nothing | ||
|
||
-- in case we want to expand UNode nodes in each triple in mkRdf' | ||
expandNode (Just (BaseUrl b)) (UNode t) = UNode (b `T.append` t) | ||
expandNode _ node = node | ||
|
||
mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> PatriciaTreeGraph | ||
mkRdf' ts base' pms' = | ||
let xs = concatMap (\(Triple s _p o) -> [s,o]) ts | ||
lnodes = zip [0..length xs-1] xs | ||
|
||
uriIdx = Map.fromList (map (\(a,b) -> (b,a)) lnodes) | ||
intIdx = IntMap.fromList lnodes | ||
|
||
ledges = map (\(Triple s p o) -> | ||
let si = fromJust $ Map.lookup s uriIdx | ||
oi = fromJust $ Map.lookup o uriIdx | ||
in (si,oi,expandNode base' p)) ts | ||
|
||
ptGraph = G.mkGraph lnodes ledges | ||
|
||
in PatriciaTreeGraph (ptGraph ,intIdx, base', pms') | ||
|
||
{- will this remain as an RDF method? | ||
This comment has been minimized.
Sorry, something went wrong. |
||
triplesOf' :: PatriciaTreeGraph -> Triples | ||
triplesOf' (PatriciaTreeGraph (g,idxLookup,_,_)) = | ||
map (\(sIdx,oIdx,p) -> | ||
let [s,o] = map (\idx -> fromJust $ IntMap.lookup idx idxLookup) [sIdx,oIdx] | ||
in Triple s p o) (G.labEdges g) | ||
-} | ||
|
||
uniqTriplesOf' :: PatriciaTreeGraph -> Triples | ||
uniqTriplesOf' ptG@(PatriciaTreeGraph (g,idxLookup,_,_)) = | ||
nub $ map (\(sIdx,oIdx,p) -> | ||
let [s,o] = map (\idx -> fromJust $ IntMap.lookup idx idxLookup) [sIdx,oIdx] | ||
in expandTriple ptG (Triple s p o)) (G.labEdges g) | ||
|
||
select' :: PatriciaTreeGraph -> NodeSelector -> NodeSelector -> NodeSelector -> Triples | ||
select' ptG@(PatriciaTreeGraph (g,idxLookup,_,_)) maybeSubjSel maybePredSel maybeObjSel = | ||
let mkTriples nodeIdx = map (\(p,subjIdx) -> | ||
let o = fromJust (IntMap.lookup nodeIdx idxLookup) | ||
s = fromJust (IntMap.lookup subjIdx idxLookup) | ||
in expandTriple ptG (Triple s p o) ) -- expand the triple | ||
|
||
cfun ( adjsIn , nodeIdx , _nodeLbl , _adjsOut ) = | ||
let ts | isJust maybeSubjSel && isNothing maybePredSel && isNothing maybeObjSel = | ||
let ss = filter (\(_p,idxSubj) -> let subjNode = fromJust (IntMap.lookup idxSubj idxLookup) | ||
in fromJust maybeSubjSel subjNode) adjsIn | ||
|
||
in mkTriples nodeIdx ss | ||
|
||
| isJust maybeSubjSel && isJust maybePredSel && isNothing maybeObjSel = | ||
let ss = filter (\(p,idxSubj) -> let subjNode = fromJust (IntMap.lookup idxSubj idxLookup) | ||
in fromJust maybeSubjSel subjNode | ||
&& fromJust maybePredSel p) adjsIn | ||
|
||
in mkTriples nodeIdx ss | ||
|
||
| isJust maybeSubjSel && isNothing maybePredSel && isJust maybeObjSel = | ||
let ss = filter (\(_p,idxSubj) -> let subjNode = fromJust (IntMap.lookup idxSubj idxLookup); objNode = fromJust (IntMap.lookup nodeIdx idxLookup) | ||
in fromJust maybeSubjSel subjNode | ||
&& fromJust maybeObjSel objNode) adjsIn | ||
|
||
in mkTriples nodeIdx ss | ||
|
||
| isJust maybeSubjSel && isJust maybePredSel && isJust maybeObjSel = | ||
let ss = filter (\(p,idxSubj) -> let subjNode = fromJust (IntMap.lookup idxSubj idxLookup); objNode = fromJust (IntMap.lookup nodeIdx idxLookup) | ||
in fromJust maybeSubjSel subjNode | ||
&& fromJust maybePredSel p | ||
&& fromJust maybeObjSel objNode) adjsIn | ||
|
||
in mkTriples nodeIdx ss | ||
|
||
| isNothing maybeSubjSel && isJust maybePredSel && isNothing maybeObjSel = | ||
let ss = filter (\(p,_idxSubj) -> fromJust maybePredSel p) adjsIn | ||
|
||
in mkTriples nodeIdx ss | ||
|
||
| isNothing maybeSubjSel && isJust maybePredSel && isJust maybeObjSel = | ||
let ss = filter (\(p,_idxSubj) -> let objNode = fromJust (IntMap.lookup nodeIdx idxLookup) | ||
in fromJust maybePredSel p | ||
&& fromJust maybeObjSel objNode) adjsIn | ||
|
||
in mkTriples nodeIdx ss | ||
|
||
| isNothing maybeSubjSel && isNothing maybePredSel && isJust maybeObjSel = | ||
let objNode = fromJust (IntMap.lookup nodeIdx idxLookup) | ||
in if fromJust maybeObjSel objNode | ||
then mkTriples nodeIdx adjsIn | ||
else [] | ||
|
||
| isNothing maybeSubjSel && isNothing maybePredSel && isNothing maybeObjSel = | ||
mkTriples nodeIdx adjsIn | ||
in ts | ||
|
||
-- is depth first better or worse than breadth first? | ||
in concat $ DFS.dfsWith' cfun g | ||
|
||
query' :: PatriciaTreeGraph -> Maybe Subject -> Maybe Predicate -> Maybe Object -> Triples | ||
query' ptG@(PatriciaTreeGraph (g,idxLookup,_,_)) maybeSubj maybePred maybeObj = | ||
let mkTriples nodeIdx = map (\(p,subjIdx) -> | ||
let o = fromJust (IntMap.lookup nodeIdx idxLookup) | ||
s = fromJust (IntMap.lookup subjIdx idxLookup) | ||
in expandTriple ptG (Triple s p o) ) -- expand the triple | ||
|
||
cfun ( adjsIn , nodeIdx , _nodeLbl , _adjsOut ) = | ||
let ts | isJust maybeSubj && isNothing maybePred && isNothing maybeObj = | ||
let ss = filter (\(_p,idxSubj) -> fromJust (IntMap.lookup idxSubj idxLookup) == fromJust maybeSubj ) adjsIn | ||
in mkTriples nodeIdx ss | ||
|
||
| isJust maybeSubj && isJust maybePred && isNothing maybeObj = | ||
let ss = filter (\(p,idxSubj) -> fromJust (IntMap.lookup idxSubj idxLookup) == fromJust maybeSubj | ||
&& p == fromJust maybePred) adjsIn | ||
in mkTriples nodeIdx ss | ||
|
||
| isJust maybeSubj && isJust maybePred && isJust maybeObj = | ||
let objNode = fromJust (IntMap.lookup nodeIdx idxLookup) | ||
ss = filter (\(p,idxSubj) -> fromJust (IntMap.lookup idxSubj idxLookup) == fromJust maybeSubj | ||
&& p == fromJust maybePred) adjsIn | ||
in if objNode == fromJust maybeObj | ||
then mkTriples nodeIdx ss | ||
else [] | ||
|
||
| isNothing maybeSubj && isJust maybePred && isNothing maybeObj = | ||
let ss = filter (\(p,_idxSubj) -> p == fromJust maybePred) adjsIn | ||
in mkTriples nodeIdx ss | ||
|
||
| isNothing maybeSubj && isJust maybePred && isJust maybeObj = | ||
let objNode = fromJust (IntMap.lookup nodeIdx idxLookup) | ||
ss = filter (\(p,_idxSubj) -> p == fromJust maybePred) adjsIn | ||
in if objNode == fromJust maybeObj | ||
then mkTriples nodeIdx ss | ||
else [] | ||
|
||
| isNothing maybeSubj && isNothing maybePred && isJust maybeObj = | ||
let objNode = fromJust (IntMap.lookup nodeIdx idxLookup) | ||
in if objNode == fromJust maybeObj | ||
then mkTriples nodeIdx adjsIn | ||
else [] | ||
|
||
| isNothing maybeSubj && isNothing maybePred && isNothing maybeObj = | ||
mkTriples nodeIdx adjsIn | ||
|
||
in ts | ||
|
||
-- is depth first better or worse than breadth first? | ||
in concat $ DFS.dfsWith' cfun g |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
module Data.RDF.PatriciaTreeGraph_Test (triplesOf',empty',mkRdf') where | ||
|
||
import Data.RDF.Types | ||
import Data.RDF.PatriciaTreeGraph (PatriciaTreeGraph) | ||
import Data.RDF.GraphTestUtils | ||
import qualified Data.Map as Map | ||
import Control.Monad | ||
|
||
import Test.QuickCheck | ||
|
||
instance Arbitrary PatriciaTreeGraph where | ||
arbitrary = liftM3 mkRdf arbitraryTs (return Nothing) (return $ PrefixMappings Map.empty) | ||
--coarbitrary = undefined | ||
|
||
empty' :: PatriciaTreeGraph | ||
empty' = empty | ||
|
||
mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> PatriciaTreeGraph | ||
mkRdf' = mkRdf | ||
|
||
triplesOf' :: PatriciaTreeGraph -> Triples | ||
triplesOf' = triplesOf |
8 comments
on commit e1282b4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an RDF
implementation using a Patricia tree from Martin Erwig's Functional Graph Library. It fails most tests, primarily due to the unresolved discussion in #12 . I don't know whether it performs terribly or adequately. I chose the Patricia tree implementation because the document says that the GHC RULES pragma is used in a number of graph functions for performance (though I haven't investigated whether we trigger them for rdf4h's use case.
@cordawyn code review?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@robstewart57 I'll do the code review, sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, thanks. I'll re-add that tonight.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks OK, but don't forget to uncomment the rest of the tests. Also note that a few functions had their arguments changed in #19 , maybe you'll want to merge that first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, I'll merge your master branch with my patricia-tree branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've rebased the patricia-tree
branch with your master
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should also get rid of uniqTriplesOf
and related URI/Node/Triple expansion functions, if that's how we roll now ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This initial effort is not quite right, easily identified with the existing QuickCheck tests :-) I'll have a 2nd go in the next few weeks.
Well, and I'd rather
triplesOf
stayed instead ofuniqTriplesOf
. But this is related to that absolute/relative/prefixed URI issue. We must be absolutely sure about what we have inside ofUNode
and whether we care about duplicates or not. This dictates the actual implementation of RDF graphs.