{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}

--------------------------------------------------------------------------------
--  See end of this file for licence information.
--------------------------------------------------------------------------------
-- |
--  Module      :  ClassRestrictionRule
--  Copyright   :  (c) 2003, Graham Klyne, 2009 Vasili I Galchin,
--                 2011, 2012, 2014, 2018, 2022 Douglas Burke
--  License     :  GPL V2
--
--  Maintainer  :  Douglas Burke
--  Stability   :  experimental
--  Portability :  CPP, OverloadedStrings
--
--  This module implements an inference rule based on a restruction on class
--  membership of one or more values.
--
--------------------------------------------------------------------------------

module Swish.RDF.ClassRestrictionRule
       ( ClassRestriction(..), ClassRestrictionFn
       , makeDatatypeRestriction, makeDatatypeRestrictionFn
       , makeRDFClassRestrictionRules
       , makeRDFDatatypeRestrictionRules
       , falseGraph, falseGraphStr       
       )
       where

import Swish.Datatype (DatatypeVal(..), DatatypeRel(..), DatatypeRelFn)
import Swish.Namespace (Namespace, ScopedName, namespaceToBuilder)
import Swish.Rule (Rule(..), bwdCheckInference)
import Swish.VarBinding (VarBinding(..))

import Swish.RDF.Graph
    ( RDFLabel(..)
    , getScopedName
    , RDFGraph
    , getArcs
    , merge
    , toRDFGraph, emptyRDFGraph
    , Arc(..)
    , resRdfType
    , resRdfdMaxCardinality
    )

import Swish.RDF.Datatype (RDFDatatypeVal, fromRDFLabel, toRDFLabel)
import Swish.RDF.Ruleset (RDFRule, makeRDFGraphFromN3Builder)

import Swish.RDF.Query
    ( rdfQueryFind
    , rdfFindValSubj, rdfFindPredVal, rdfFindPredInt
    , rdfFindList
    )

import Swish.RDF.VarBinding (RDFVarBinding)
import Swish.RDF.Vocabulary (namespaceRDFD)

#if (!defined(__GLASGOW_HASKELL__)) || (__GLASGOW_HASKELL__ < 808)
import Control.Applicative ((<$>))
#endif

import Data.List (delete, nub, subsequences)
import Data.Maybe (fromJust, fromMaybe, mapMaybe)
import Data.Ord.Partial (minima, maxima, partCompareEq, partComparePair, partCompareListMaybe, partCompareListSubset)

#if (!defined(__GLASGOW_HASKELL__)) || (__GLASGOW_HASKELL__ < 710)
import Data.Monoid (Monoid (..))
#endif

import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Text.Lazy.Builder as B

------------------------------------------------------------
--  Class restriction data type
------------------------------------------------------------

-- |Type of function that evaluates missing node values in a
--  restriction from those supplied.
type ClassRestrictionFn = [Maybe RDFLabel] -> Maybe [[RDFLabel]]

-- |Datatype for named class restriction
data ClassRestriction = ClassRestriction
    { ClassRestriction -> ScopedName
crName    :: ScopedName
    , ClassRestriction -> ClassRestrictionFn
crFunc    :: ClassRestrictionFn
    }

-- | Equality of class restrictions is based on the name of the restriction.
instance Eq ClassRestriction where
    ClassRestriction
cr1 == :: ClassRestriction -> ClassRestriction -> Bool
== ClassRestriction
cr2  =  ClassRestriction -> ScopedName
crName ClassRestriction
cr1 ScopedName -> ScopedName -> Bool
forall a. Eq a => a -> a -> Bool
== ClassRestriction -> ScopedName
crName ClassRestriction
cr2

instance Show ClassRestriction where
    show :: ClassRestriction -> String
show ClassRestriction
cr = String
"ClassRestriction:" String -> ShowS
forall a. [a] -> [a] -> [a]
++ ScopedName -> String
forall a. Show a => a -> String
show (ClassRestriction -> ScopedName
crName ClassRestriction
cr)

------------------------------------------------------------
--  Instantiate a class restriction from a datatype relation
------------------------------------------------------------

-- |Make a class restriction from a datatype relation.
--
--  This lifts application of the datatype relation to operate
--  on 'RDFLabel' values, which are presumed to contain appropriately
--  datatyped values.
--
makeDatatypeRestriction ::
    RDFDatatypeVal vt -> DatatypeRel vt -> ClassRestriction
makeDatatypeRestriction :: RDFDatatypeVal vt -> DatatypeRel vt -> ClassRestriction
makeDatatypeRestriction RDFDatatypeVal vt
dtv DatatypeRel vt
dtrel = ClassRestriction :: ScopedName -> ClassRestrictionFn -> ClassRestriction
ClassRestriction
    { crName :: ScopedName
crName = DatatypeRel vt -> ScopedName
forall vt. DatatypeRel vt -> ScopedName
dtRelName DatatypeRel vt
dtrel
    , crFunc :: ClassRestrictionFn
crFunc = RDFDatatypeVal vt -> DatatypeRelFn vt -> ClassRestrictionFn
forall vt.
RDFDatatypeVal vt -> DatatypeRelFn vt -> ClassRestrictionFn
makeDatatypeRestrictionFn RDFDatatypeVal vt
dtv (DatatypeRel vt -> DatatypeRelFn vt
forall vt. DatatypeRel vt -> DatatypeRelFn vt
dtRelFunc DatatypeRel vt
dtrel)
    }

--  The core logic below is something like @(map toLabels . dtrelfn . map frLabel)@
--  but the extra lifting and catMaybes are needed to get the final result
--  type in the right form.

-- |Make a class restriction function from a datatype relation function.
--
makeDatatypeRestrictionFn ::
    RDFDatatypeVal vt -> DatatypeRelFn vt -> ClassRestrictionFn
makeDatatypeRestrictionFn :: RDFDatatypeVal vt -> DatatypeRelFn vt -> ClassRestrictionFn
makeDatatypeRestrictionFn RDFDatatypeVal vt
dtv DatatypeRelFn vt
dtrelfn =
    ([[vt]] -> [[RDFLabel]]) -> Maybe [[vt]] -> Maybe [[RDFLabel]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([vt] -> Maybe [RDFLabel]) -> [[vt]] -> [[RDFLabel]]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe [vt] -> Maybe [RDFLabel]
toLabels) (Maybe [[vt]] -> Maybe [[RDFLabel]])
-> ([Maybe RDFLabel] -> Maybe [[vt]]) -> ClassRestrictionFn
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DatatypeRelFn vt
dtrelfn DatatypeRelFn vt
-> ([Maybe RDFLabel] -> [Maybe vt])
-> [Maybe RDFLabel]
-> Maybe [[vt]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe RDFLabel -> Maybe vt) -> [Maybe RDFLabel] -> [Maybe vt]
forall a b. (a -> b) -> [a] -> [b]
map Maybe RDFLabel -> Maybe vt
frLabel
    where
        frLabel :: Maybe RDFLabel -> Maybe vt
frLabel Maybe RDFLabel
Nothing  = Maybe vt
forall a. Maybe a
Nothing
        frLabel (Just RDFLabel
l) = RDFDatatypeVal vt -> RDFLabel -> Maybe vt
forall vt. RDFDatatypeVal vt -> RDFLabel -> Maybe vt
fromRDFLabel RDFDatatypeVal vt
dtv RDFLabel
l
        toLabels :: [vt] -> Maybe [RDFLabel]
toLabels         = (vt -> Maybe RDFLabel) -> [vt] -> Maybe [RDFLabel]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM vt -> Maybe RDFLabel
toLabel   -- Maybe [RDFLabel]
        toLabel :: vt -> Maybe RDFLabel
toLabel          = RDFDatatypeVal vt -> vt -> Maybe RDFLabel
forall vt. RDFDatatypeVal vt -> vt -> Maybe RDFLabel
toRDFLabel RDFDatatypeVal vt
dtv

------------------------------------------------------------
--  Make rules from supplied class restrictions and graph
------------------------------------------------------------

mkPrefix :: Namespace -> B.Builder
mkPrefix :: Namespace -> Builder
mkPrefix = Namespace -> Builder
namespaceToBuilder

ruleQuery :: RDFGraph
ruleQuery :: RDFGraph
ruleQuery = Builder -> RDFGraph
makeRDFGraphFromN3Builder (Builder -> RDFGraph) -> Builder -> RDFGraph
forall a b. (a -> b) -> a -> b
$
            [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat
            [ Namespace -> Builder
mkPrefix Namespace
namespaceRDFD
            , Builder
" ?c a rdfd:GeneralRestriction ; "
            , Builder
"    rdfd:onProperties ?p ; "     
            , Builder
"    rdfd:constraint   ?r . "
            ]
            
-- | The graph
--
-- > _:a <http://id.ninebynine.org/2003/rdfext/rdfd#false> _:b .
--
-- Exported for testing.
falseGraph :: RDFGraph
falseGraph :: RDFGraph
falseGraph = Builder -> RDFGraph
makeRDFGraphFromN3Builder (Builder -> RDFGraph) -> Builder -> RDFGraph
forall a b. (a -> b) -> a -> b
$
             Namespace -> Builder
mkPrefix Namespace
namespaceRDFD Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Builder
falseGraphStr

-- | Exported for testing.
falseGraphStr :: B.Builder
falseGraphStr :: Builder
falseGraphStr = Builder
"_:a rdfd:false _:b . "

-- |Make a list of class restriction rules given a list of class restriction
--  values and a graph containing one or more class restriction definitions.
--
makeRDFClassRestrictionRules :: [ClassRestriction] -> RDFGraph -> [RDFRule]
makeRDFClassRestrictionRules :: [ClassRestriction] -> RDFGraph -> [RDFRule]
makeRDFClassRestrictionRules [ClassRestriction]
crs RDFGraph
gr =
    (RDFVarBinding -> Maybe RDFRule) -> [RDFVarBinding] -> [RDFRule]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe RDFVarBinding -> Maybe RDFRule
constructRule (RDFGraph -> [RDFVarBinding]
queryForRules RDFGraph
gr)
    where
        queryForRules :: RDFGraph -> [RDFVarBinding]
queryForRules = RDFGraph -> RDFGraph -> [RDFVarBinding]
rdfQueryFind RDFGraph
ruleQuery
        constructRule :: RDFVarBinding -> Maybe RDFRule
constructRule = [ClassRestriction] -> RDFGraph -> RDFVarBinding -> Maybe RDFRule
makeRestrictionRule1 [ClassRestriction]
crs RDFGraph
gr

makeRestrictionRule1 ::
    [ClassRestriction] -> RDFGraph -> RDFVarBinding -> Maybe RDFRule
makeRestrictionRule1 :: [ClassRestriction] -> RDFGraph -> RDFVarBinding -> Maybe RDFRule
makeRestrictionRule1 [ClassRestriction]
crs RDFGraph
gr RDFVarBinding
vb =
    Maybe ClassRestriction
-> RDFLabel -> [RDFLabel] -> [Int] -> Maybe RDFRule
makeRestrictionRule2 Maybe ClassRestriction
rn RDFLabel
c [RDFLabel]
ps [Int]
cs
    where
        c :: RDFLabel
c  = RDFLabel -> Maybe RDFLabel -> RDFLabel
forall a. a -> Maybe a -> a
fromMaybe RDFLabel
NoNode (Maybe RDFLabel -> RDFLabel) -> Maybe RDFLabel -> RDFLabel
forall a b. (a -> b) -> a -> b
$ RDFVarBinding -> RDFLabel -> Maybe RDFLabel
forall a b. VarBinding a b -> a -> Maybe b
vbMap RDFVarBinding
vb (String -> RDFLabel
Var String
"c")
        p :: RDFLabel
p  = RDFLabel -> Maybe RDFLabel -> RDFLabel
forall a. a -> Maybe a -> a
fromMaybe RDFLabel
NoNode (Maybe RDFLabel -> RDFLabel) -> Maybe RDFLabel -> RDFLabel
forall a b. (a -> b) -> a -> b
$ RDFVarBinding -> RDFLabel -> Maybe RDFLabel
forall a b. VarBinding a b -> a -> Maybe b
vbMap RDFVarBinding
vb (String -> RDFLabel
Var String
"p")
        r :: RDFLabel
r  = RDFLabel -> Maybe RDFLabel -> RDFLabel
forall a. a -> Maybe a -> a
fromMaybe RDFLabel
NoNode (Maybe RDFLabel -> RDFLabel) -> Maybe RDFLabel -> RDFLabel
forall a b. (a -> b) -> a -> b
$ RDFVarBinding -> RDFLabel -> Maybe RDFLabel
forall a b. VarBinding a b -> a -> Maybe b
vbMap RDFVarBinding
vb (String -> RDFLabel
Var String
"r")
        cs :: [Int]
cs = (Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ (Integer -> Int) -> [Integer] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map Integer -> Int
forall a. Num a => Integer -> a
fromInteger ([Integer] -> [Int]) -> [Integer] -> [Int]
forall a b. (a -> b) -> a -> b
$
             RDFLabel -> RDFLabel -> RDFGraph -> [Integer]
rdfFindPredInt RDFLabel
c RDFLabel
resRdfdMaxCardinality RDFGraph
gr
        ps :: [RDFLabel]
ps = RDFGraph -> RDFLabel -> [RDFLabel]
rdfFindList RDFGraph
gr RDFLabel
p

        -- TODO: do not need to go via a map since looking through a list
        rn :: Maybe ClassRestriction
rn = ScopedName
-> Map ScopedName ClassRestriction -> Maybe ClassRestriction
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup (RDFLabel -> ScopedName
getScopedName RDFLabel
r) (Map ScopedName ClassRestriction -> Maybe ClassRestriction)
-> Map ScopedName ClassRestriction -> Maybe ClassRestriction
forall a b. (a -> b) -> a -> b
$ [(ScopedName, ClassRestriction)] -> Map ScopedName ClassRestriction
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ([(ScopedName, ClassRestriction)]
 -> Map ScopedName ClassRestriction)
-> [(ScopedName, ClassRestriction)]
-> Map ScopedName ClassRestriction
forall a b. (a -> b) -> a -> b
$ (ClassRestriction -> (ScopedName, ClassRestriction))
-> [ClassRestriction] -> [(ScopedName, ClassRestriction)]
forall a b. (a -> b) -> [a] -> [b]
map (\ClassRestriction
cr -> (ClassRestriction -> ScopedName
crName ClassRestriction
cr, ClassRestriction
cr)) [ClassRestriction]
crs

makeRestrictionRule2 ::
    Maybe ClassRestriction -> RDFLabel -> [RDFLabel] -> [Int]
    -> Maybe RDFRule
makeRestrictionRule2 :: Maybe ClassRestriction
-> RDFLabel -> [RDFLabel] -> [Int] -> Maybe RDFRule
makeRestrictionRule2 (Just ClassRestriction
restriction) cls :: RDFLabel
cls@(Res ScopedName
cname) [RDFLabel]
props [Int]
cs =
    RDFRule -> Maybe RDFRule
forall a. a -> Maybe a
Just RDFRule
restrictionRule
    where
        restrictionRule :: RDFRule
restrictionRule = Rule :: forall ex.
ScopedName
-> ([ex] -> [ex])
-> (ex -> [[ex]])
-> ([ex] -> ex -> Bool)
-> Rule ex
Rule
            { ruleName :: ScopedName
ruleName = ScopedName
cname
              -- fwdApply :: [ex] -> [ex]
            , fwdApply :: [RDFGraph] -> [RDFGraph]
fwdApply = ClassRestriction
-> RDFLabel -> [RDFLabel] -> [Int] -> [RDFGraph] -> [RDFGraph]
fwdApplyRestriction ClassRestriction
restriction RDFLabel
cls [RDFLabel]
props [Int]
cs
              -- bwdApply :: ex -> [[ex]]
            , bwdApply :: RDFGraph -> [[RDFGraph]]
bwdApply = ClassRestriction
-> RDFLabel -> [RDFLabel] -> [Int] -> RDFGraph -> [[RDFGraph]]
bwdApplyRestriction ClassRestriction
restriction RDFLabel
cls [RDFLabel]
props [Int]
cs
            , checkInference :: [RDFGraph] -> RDFGraph -> Bool
checkInference = RDFRule -> [RDFGraph] -> RDFGraph -> Bool
forall ex. Eq ex => Rule ex -> [ex] -> ex -> Bool
bwdCheckInference RDFRule
restrictionRule
            }
makeRestrictionRule2 Maybe ClassRestriction
_ RDFLabel
_ [RDFLabel]
_ [Int]
_ = Maybe RDFRule
forall a. Maybe a
Nothing
    -- trace "\nmakeRestrictionRule: missing class restriction"

--  Forward apply class restriction.
fwdApplyRestriction ::
    ClassRestriction -> RDFLabel -> [RDFLabel] -> [Int] -> [RDFGraph]
    -> [RDFGraph]
fwdApplyRestriction :: ClassRestriction
-> RDFLabel -> [RDFLabel] -> [Int] -> [RDFGraph] -> [RDFGraph]
fwdApplyRestriction ClassRestriction
restriction RDFLabel
cls [RDFLabel]
props [Int]
cs [RDFGraph]
antgrs =
    [RDFGraph]
-> ([[RDFGraph]] -> [RDFGraph]) -> Maybe [[RDFGraph]] -> [RDFGraph]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [RDFGraph
falseGraph] [[RDFGraph]] -> [RDFGraph]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat Maybe [[RDFGraph]]
newgrs
      where
        -- Instances of the named class in the graph:
        ris :: [RDFLabel]
ris = [RDFLabel] -> [RDFLabel]
forall a. Eq a => [a] -> [a]
nub ([RDFLabel] -> [RDFLabel]) -> [RDFLabel] -> [RDFLabel]
forall a b. (a -> b) -> a -> b
$ RDFLabel -> RDFLabel -> RDFGraph -> [RDFLabel]
rdfFindValSubj RDFLabel
resRdfType RDFLabel
cls RDFGraph
antgr
        --  Merge antecedent graphs into one (with bnode renaming):
        --  (Uses 'if' and 'foldl1' to avoid merging in the common case
        --  of just one graph supplied.)
        antgr :: RDFGraph
antgr = if [RDFGraph] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [RDFGraph]
antgrs then RDFGraph
emptyRDFGraph else (RDFGraph -> RDFGraph -> RDFGraph) -> [RDFGraph] -> RDFGraph
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldl1 RDFGraph -> RDFGraph -> RDFGraph
forall lb. Label lb => NSGraph lb -> NSGraph lb -> NSGraph lb
merge [RDFGraph]
antgrs
        --  Apply class restriction to single instance of the restricted class
        newgr :: RDFLabel -> Maybe [RDFGraph]
        newgr :: RDFLabel -> Maybe [RDFGraph]
newgr RDFLabel
ri = ClassRestriction
-> RDFLabel -> [RDFLabel] -> [Int] -> RDFGraph -> Maybe [RDFGraph]
fwdApplyRestriction1 ClassRestriction
restriction RDFLabel
ri [RDFLabel]
props [Int]
cs RDFGraph
antgr
        newgrs :: Maybe [[RDFGraph]]
        newgrs :: Maybe [[RDFGraph]]
newgrs = (RDFLabel -> Maybe [RDFGraph]) -> [RDFLabel] -> Maybe [[RDFGraph]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM RDFLabel -> Maybe [RDFGraph]
newgr [RDFLabel]
ris

--  Forward apply class restriction to single class instance (ci).
--  Return single set of inferred results, for each combination of
--  property values, or an empty list, or Nothing if the supplied values
--  are inconsistent with the restriction.
fwdApplyRestriction1 ::
    ClassRestriction -> RDFLabel -> [RDFLabel] -> [Int] -> RDFGraph
    -> Maybe [RDFGraph]
fwdApplyRestriction1 :: ClassRestriction
-> RDFLabel -> [RDFLabel] -> [Int] -> RDFGraph -> Maybe [RDFGraph]
fwdApplyRestriction1 ClassRestriction
restriction RDFLabel
ci [RDFLabel]
props [Int]
cs RDFGraph
antgr =
    if Bool
grConsistent then [RDFGraph] -> Maybe [RDFGraph]
forall a. a -> Maybe a
Just [RDFGraph]
newgrs else Maybe [RDFGraph]
forall a. Maybe a
Nothing
    where
        --  Apply restriction to graph
        (Bool
grConsistent,[[RDFLabel]]
_,[([Maybe RDFLabel], [[RDFLabel]])]
_,[[Maybe RDFLabel]]
sts) = ClassRestriction
-> RDFLabel
-> [RDFLabel]
-> [Int]
-> RDFGraph
-> (Bool, [[RDFLabel]], [([Maybe RDFLabel], [[RDFLabel]])],
    [[Maybe RDFLabel]])
applyRestriction ClassRestriction
restriction RDFLabel
ci [RDFLabel]
props [Int]
cs RDFGraph
antgr
        --  Select results, eliminate those with unknowns
        nts :: [[RDFLabel]]
        nts :: [[RDFLabel]]
nts = ([Maybe RDFLabel] -> Maybe [RDFLabel])
-> [[Maybe RDFLabel]] -> [[RDFLabel]]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe [Maybe RDFLabel] -> Maybe [RDFLabel]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence [[Maybe RDFLabel]]
sts
        --  Make new graph from results, including only newly generated arcs
        newarcs :: Set (Arc RDFLabel)
newarcs = [Arc RDFLabel] -> Set (Arc RDFLabel)
forall a. Ord a => [a] -> Set a
S.fromList [RDFLabel -> RDFLabel -> RDFLabel -> Arc RDFLabel
forall lb. lb -> lb -> lb -> Arc lb
Arc RDFLabel
ci RDFLabel
p RDFLabel
v | [RDFLabel]
vs <- [[RDFLabel]]
nts, (RDFLabel
p,RDFLabel
v) <- [RDFLabel] -> [RDFLabel] -> [(RDFLabel, RDFLabel)]
forall a b. [a] -> [b] -> [(a, b)]
zip [RDFLabel]
props [RDFLabel]
vs ]
                  Set (Arc RDFLabel) -> Set (Arc RDFLabel) -> Set (Arc RDFLabel)
forall a. Ord a => Set a -> Set a -> Set a
`S.difference` RDFGraph -> Set (Arc RDFLabel)
forall (lg :: * -> *) lb. LDGraph lg lb => lg lb -> ArcSet lb
getArcs RDFGraph
antgr
        newgrs :: [RDFGraph]
newgrs  = if Set (Arc RDFLabel) -> Bool
forall a. Set a -> Bool
S.null Set (Arc RDFLabel)
newarcs then [] else [Set (Arc RDFLabel) -> RDFGraph
toRDFGraph Set (Arc RDFLabel)
newarcs]

--  Backward apply class restriction.
--
--  Returns a list of alternatives, any one of which is sufficient to
--  satisfy the given consequent.
--
bwdApplyRestriction ::
    ClassRestriction -> RDFLabel -> [RDFLabel] -> [Int] -> RDFGraph
    -> [[RDFGraph]]
bwdApplyRestriction :: ClassRestriction
-> RDFLabel -> [RDFLabel] -> [Int] -> RDFGraph -> [[RDFGraph]]
bwdApplyRestriction ClassRestriction
restriction RDFLabel
cls [RDFLabel]
props [Int]
cs RDFGraph
congr =
    [[RDFGraph]] -> Maybe [[RDFGraph]] -> [[RDFGraph]]
forall a. a -> Maybe a -> a
fromMaybe [[RDFGraph
falseGraph]] Maybe [[RDFGraph]]
newgrs
    where
        -- Instances of the named class in the graph:
        ris :: [RDFLabel]
ris = RDFLabel -> RDFLabel -> RDFGraph -> [RDFLabel]
rdfFindValSubj RDFLabel
resRdfType RDFLabel
cls RDFGraph
congr
        --  Apply class restriction to single instance of the restricted class
        newgr :: RDFLabel -> Maybe [[RDFGraph]]
        newgr :: RDFLabel -> Maybe [[RDFGraph]]
newgr RDFLabel
ri = ClassRestriction
-> RDFLabel
-> RDFLabel
-> [RDFLabel]
-> [Int]
-> RDFGraph
-> Maybe [[RDFGraph]]
bwdApplyRestriction1 ClassRestriction
restriction RDFLabel
cls RDFLabel
ri [RDFLabel]
props [Int]
cs RDFGraph
congr
        --  'map newgr ris' is conjunction of disjunctions, where
        --  each disjunction is itself a conjunction of conjunctions.
        --  'sequence' distributes the conjunction over the disjunction,
        --  yielding an equivalent disjunction of conjunctions
        --  map concat flattens the conjunctions of conjuctions
        newgrs :: Maybe [[RDFGraph]]
        newgrs :: Maybe [[RDFGraph]]
newgrs = ([[RDFGraph]] -> [RDFGraph]) -> [[[RDFGraph]]] -> [[RDFGraph]]
forall a b. (a -> b) -> [a] -> [b]
map [[RDFGraph]] -> [RDFGraph]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[[RDFGraph]]] -> [[RDFGraph]])
-> ([[[RDFGraph]]] -> [[[RDFGraph]]])
-> [[[RDFGraph]]]
-> [[RDFGraph]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[[RDFGraph]]] -> [[[RDFGraph]]]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence ([[[RDFGraph]]] -> [[RDFGraph]])
-> Maybe [[[RDFGraph]]] -> Maybe [[RDFGraph]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (RDFLabel -> Maybe [[RDFGraph]])
-> [RDFLabel] -> Maybe [[[RDFGraph]]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM RDFLabel -> Maybe [[RDFGraph]]
newgr [RDFLabel]
ris

--  Backward apply a class restriction to single class instance (ci).
--  Return one or more sets of antecedent results from which the consequence
--  can be derived in the defined relation, an empty list if the supplied
--  consequence cannot be inferred, or Nothing if the consequence is
--  inconsistent with the restriction.
bwdApplyRestriction1 ::
    ClassRestriction -> RDFLabel -> RDFLabel -> [RDFLabel] -> [Int] -> RDFGraph
    -> Maybe [[RDFGraph]]
bwdApplyRestriction1 :: ClassRestriction
-> RDFLabel
-> RDFLabel
-> [RDFLabel]
-> [Int]
-> RDFGraph
-> Maybe [[RDFGraph]]
bwdApplyRestriction1 ClassRestriction
restriction RDFLabel
cls RDFLabel
ci [RDFLabel]
props [Int]
cs RDFGraph
congr =
    if Bool
grConsistent then [[RDFGraph]] -> Maybe [[RDFGraph]]
forall a. a -> Maybe a
Just [[RDFGraph]]
grss else Maybe [[RDFGraph]]
forall a. Maybe a
Nothing
    where
        --  Apply restriction to graph
        (Bool
grConsistent,[[RDFLabel]]
pvs,[([Maybe RDFLabel], [[RDFLabel]])]
cts,[[Maybe RDFLabel]]
_) =
            ClassRestriction
-> RDFLabel
-> [RDFLabel]
-> [Int]
-> RDFGraph
-> (Bool, [[RDFLabel]], [([Maybe RDFLabel], [[RDFLabel]])],
    [[Maybe RDFLabel]])
applyRestriction ClassRestriction
restriction RDFLabel
ci [RDFLabel]
props [Int]
cs RDFGraph
congr
        --  Build list of all full tuples consistent with the values supplied
        fts :: [[RDFLabel]]
        fts :: [[RDFLabel]]
fts = (([Maybe RDFLabel], [[RDFLabel]]) -> [[RDFLabel]])
-> [([Maybe RDFLabel], [[RDFLabel]])] -> [[RDFLabel]]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Maybe RDFLabel], [[RDFLabel]]) -> [[RDFLabel]]
forall a b. (a, b) -> b
snd [([Maybe RDFLabel], [[RDFLabel]])]
cts
        --  Construct partial tuples from members of fts from which at least
        --  one of the supplied values can be derived
        pts :: [([Maybe RDFLabel],[RDFLabel])]
        pts :: [([Maybe RDFLabel], [RDFLabel])]
pts = ([RDFLabel] -> [([Maybe RDFLabel], [RDFLabel])])
-> [[RDFLabel]] -> [([Maybe RDFLabel], [RDFLabel])]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (ClassRestriction -> [RDFLabel] -> [([Maybe RDFLabel], [RDFLabel])]
deriveTuple ClassRestriction
restriction) [[RDFLabel]]
fts
        --  Select combinations of members of pts from which all the
        --  supplied values can be derived
        dtss :: [[[Maybe RDFLabel]]]
        dtss :: [[[Maybe RDFLabel]]]
dtss = [[RDFLabel]]
-> [([Maybe RDFLabel], [RDFLabel])] -> [[[Maybe RDFLabel]]]
forall a. Eq a => [[a]] -> [([Maybe a], [a])] -> [[[Maybe a]]]
coverSets [[RDFLabel]]
pvs [([Maybe RDFLabel], [RDFLabel])]
pts
        --  Filter members of dtss that fully cover the values
        --  obtained from the consequence graph.
        ftss :: [[[Maybe RDFLabel]]]
        ftss :: [[[Maybe RDFLabel]]]
ftss = ([[Maybe RDFLabel]] -> Bool)
-> [[[Maybe RDFLabel]]] -> [[[Maybe RDFLabel]]]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool)
-> ([[Maybe RDFLabel]] -> Bool) -> [[Maybe RDFLabel]] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (\[[Maybe RDFLabel]]
t -> (Maybe RDFLabel -> [RDFLabel] -> [RDFLabel])
-> [[Maybe RDFLabel]] -> [[RDFLabel]] -> Bool
forall a b. (a -> [b] -> [b]) -> [[a]] -> [[b]] -> Bool
coversVals Maybe RDFLabel -> [RDFLabel] -> [RDFLabel]
forall a. Eq a => Maybe a -> [a] -> [a]
deleteMaybe [[Maybe RDFLabel]]
t [[RDFLabel]]
pvs)) [[[Maybe RDFLabel]]]
dtss
        --  Make new graphs for all alternatives
        grss :: [[RDFGraph]]
        grss :: [[RDFGraph]]
grss = ([[Maybe RDFLabel]] -> [RDFGraph])
-> [[[Maybe RDFLabel]]] -> [[RDFGraph]]
forall a b. (a -> b) -> [a] -> [b]
map ( [Arc RDFLabel] -> [RDFGraph]
makeGraphs ([Arc RDFLabel] -> [RDFGraph])
-> ([[Maybe RDFLabel]] -> [Arc RDFLabel])
-> [[Maybe RDFLabel]]
-> [RDFGraph]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Maybe RDFLabel]] -> [Arc RDFLabel]
newArcs ) [[[Maybe RDFLabel]]]
ftss

        --  Collect arcs for one alternative
        newArcs :: [[Maybe RDFLabel]] -> [Arc RDFLabel]
newArcs [[Maybe RDFLabel]]
dts =
            [ RDFLabel -> RDFLabel -> RDFLabel -> Arc RDFLabel
forall lb. lb -> lb -> lb -> Arc lb
Arc RDFLabel
ci RDFLabel
p RDFLabel
v | [Maybe RDFLabel]
mvs <- [[Maybe RDFLabel]]
dts, (RDFLabel
p,Just RDFLabel
v) <- [RDFLabel] -> [Maybe RDFLabel] -> [(RDFLabel, Maybe RDFLabel)]
forall a b. [a] -> [b] -> [(a, b)]
zip [RDFLabel]
props [Maybe RDFLabel]
mvs ]

        --  Make graphs for one alternative
        --  TODO: convert to sets
        makeGraphs :: [Arc RDFLabel] -> [RDFGraph]
makeGraphs = (Arc RDFLabel -> RDFGraph) -> [Arc RDFLabel] -> [RDFGraph]
forall a b. (a -> b) -> [a] -> [b]
map (Set (Arc RDFLabel) -> RDFGraph
toRDFGraph (Set (Arc RDFLabel) -> RDFGraph)
-> (Arc RDFLabel -> Set (Arc RDFLabel)) -> Arc RDFLabel -> RDFGraph
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Arc RDFLabel] -> Set (Arc RDFLabel)
forall a. Ord a => [a] -> Set a
S.fromList ([Arc RDFLabel] -> Set (Arc RDFLabel))
-> (Arc RDFLabel -> [Arc RDFLabel])
-> Arc RDFLabel
-> Set (Arc RDFLabel)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Arc RDFLabel -> [Arc RDFLabel] -> [Arc RDFLabel]
forall a. a -> [a] -> [a]
:[])) ([Arc RDFLabel] -> [RDFGraph])
-> ([Arc RDFLabel] -> [Arc RDFLabel])
-> [Arc RDFLabel]
-> [RDFGraph]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (RDFLabel -> RDFLabel -> RDFLabel -> Arc RDFLabel
forall lb. lb -> lb -> lb -> Arc lb
Arc RDFLabel
ci RDFLabel
resRdfType RDFLabel
cls Arc RDFLabel -> [Arc RDFLabel] -> [Arc RDFLabel]
forall a. a -> [a] -> [a]
:)

--  Helper function to select sub-tuples from which some of a set of
--  values can be derived using a class restriction.
--
--  restriction is the restriction being evaluated.
--  ft          is a full tuple of values known to be consistent with
--              the restriction
--
--  The result returned is a list of pairs, whose first member is a partial
--  tuples from which the full tuple supplied can be derived, and the second
--  is the supplied tuple calculated from that input.
--
deriveTuple ::
    ClassRestriction -> [RDFLabel]
    -> [([Maybe RDFLabel], [RDFLabel])]
deriveTuple :: ClassRestriction -> [RDFLabel] -> [([Maybe RDFLabel], [RDFLabel])]
deriveTuple ClassRestriction
restriction [RDFLabel]
ft =
    ([Maybe RDFLabel] -> ([Maybe RDFLabel], [RDFLabel]))
-> [[Maybe RDFLabel]] -> [([Maybe RDFLabel], [RDFLabel])]
forall a b. (a -> b) -> [a] -> [b]
map ([RDFLabel] -> [Maybe RDFLabel] -> ([Maybe RDFLabel], [RDFLabel])
forall b a. b -> a -> (a, b)
tosnd [RDFLabel]
ft) ([[Maybe RDFLabel]] -> [([Maybe RDFLabel], [RDFLabel])])
-> [[Maybe RDFLabel]] -> [([Maybe RDFLabel], [RDFLabel])]
forall a b. (a -> b) -> a -> b
$ PartCompare [Maybe RDFLabel]
-> [[Maybe RDFLabel]] -> [[Maybe RDFLabel]]
forall a. PartCompare a -> [a] -> [a]
minima PartCompare [Maybe RDFLabel]
forall a. Eq a => [Maybe a] -> [Maybe a] -> Maybe Ordering
partCompareListMaybe ([[Maybe RDFLabel]] -> [[Maybe RDFLabel]])
-> [[Maybe RDFLabel]] -> [[Maybe RDFLabel]]
forall a b. (a -> b) -> a -> b
$ ([Maybe RDFLabel] -> Bool)
-> [[Maybe RDFLabel]] -> [[Maybe RDFLabel]]
forall a. (a -> Bool) -> [a] -> [a]
filter [Maybe RDFLabel] -> Bool
derives [[Maybe RDFLabel]]
partials
    where
        partials :: [[Maybe RDFLabel]]
partials = (RDFLabel -> [Maybe RDFLabel]) -> [RDFLabel] -> [[Maybe RDFLabel]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (\RDFLabel
x -> [Maybe RDFLabel
forall a. Maybe a
Nothing, RDFLabel -> Maybe RDFLabel
forall a. a -> Maybe a
Just RDFLabel
x]) [RDFLabel]
ft
        derives :: [Maybe RDFLabel] -> Bool
derives  = ([[RDFLabel]
ft] [[RDFLabel]] -> [[RDFLabel]] -> Bool
forall a. Eq a => a -> a -> Bool
==) ([[RDFLabel]] -> Bool)
-> ([Maybe RDFLabel] -> [[RDFLabel]]) -> [Maybe RDFLabel] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe [[RDFLabel]] -> [[RDFLabel]]
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe [[RDFLabel]] -> [[RDFLabel]])
-> ClassRestrictionFn -> [Maybe RDFLabel] -> [[RDFLabel]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ClassRestriction -> ClassRestrictionFn
crFunc ClassRestriction
restriction
        tosnd :: b -> a -> (a, b)
tosnd    = (a -> b -> (a, b)) -> b -> a -> (a, b)
forall a b c. (a -> b -> c) -> b -> a -> c
flip (,)

--  Helper function to apply a restriction to selected information from
--  a supplied graph, and returns a tuple containing:
--  (a) an indication of whether the graph is consistent with the
--      restriction
--  (b) a list of values specified in the graph for each property
--  (c) a complete list of tuples that use combinations of values from
--      the graph and are consistent with the restriction.
--      Each member is a pair consisting of some combination of input
--      values, and a list of complete tuple values that can be
--      calculated from those inputs, or an empty list if there is
--      insufficient information.
--  (d) a set of tuples that are consistent with the restriction and use
--      as much information from the graph as possible.  This set is
--      minimal in the sense that they must all correspond to different
--      complete input tuples satisfying the restriction.
--
--  This function factors out logic that is common to forward and
--  backward chaining of a class restriction.
--
--  restriction is the class restriction being applied
--  ci          is the identifier of a graph node to be tested
--  props       is a list of properties of the graph noode whose values
--              are constrained by the class restriction.
--  cs          is a list of max cardinality constraints on the restriction,
--              the minimum of which is used as the cardinality constraint
--              on the restriction.  If the list is null, no cardinality
--              constraint is applied.
--  gr          is the graph from which property values are extracted.
--
applyRestriction ::
    ClassRestriction -> RDFLabel -> [RDFLabel] -> [Int] -> RDFGraph
    -> ( Bool
       , [[RDFLabel]]
       , [([Maybe RDFLabel],[[RDFLabel]])]
       , [[Maybe RDFLabel]]
       )
applyRestriction :: ClassRestriction
-> RDFLabel
-> [RDFLabel]
-> [Int]
-> RDFGraph
-> (Bool, [[RDFLabel]], [([Maybe RDFLabel], [[RDFLabel]])],
    [[Maybe RDFLabel]])
applyRestriction ClassRestriction
restriction RDFLabel
ci [RDFLabel]
props [Int]
cs RDFGraph
gr =
    ((Maybe RDFLabel -> [RDFLabel] -> [RDFLabel])
-> [[Maybe RDFLabel]] -> [[RDFLabel]] -> Bool
forall a b. (a -> [b] -> [b]) -> [[a]] -> [[b]] -> Bool
coversVals Maybe RDFLabel -> [RDFLabel] -> [RDFLabel]
forall a. Eq a => Maybe a -> [a] -> [a]
deleteMaybe [[Maybe RDFLabel]]
sts [[RDFLabel]]
pvs Bool -> Bool -> Bool
&& Bool
cardinalityOK, [[RDFLabel]]
pvs, [([Maybe RDFLabel], [[RDFLabel]])]
cts, [[Maybe RDFLabel]]
sts )
    where
        --  Extract from the antecedent graph all specified values of the
        --  restricted properties (constructs inner list for each property)
        pvs :: [[RDFLabel]]
        pvs :: [[RDFLabel]]
pvs = [ RDFLabel -> RDFLabel -> RDFGraph -> [RDFLabel]
rdfFindPredVal RDFLabel
ci RDFLabel
p RDFGraph
gr | RDFLabel
p <- [RDFLabel]
props ]
        --  Convert tuple of alternatives to list of alternative tuples
        --  (Each tuple is an inner list)
        pts :: [[Maybe RDFLabel]]
        pts :: [[Maybe RDFLabel]]
pts = ([RDFLabel] -> [Maybe RDFLabel])
-> [[RDFLabel]] -> [[Maybe RDFLabel]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM [RDFLabel] -> [Maybe RDFLabel]
forall a. [a] -> [Maybe a]
allJustAndNothing [[RDFLabel]]
pvs
        --  Try class restriction calculation for each tuple
        --  For each, result may be:
        --    Nothing  (inconsistent)
        --    Just []  (underspecified)
        --    Just [t] (single tuple of values derived from given values)
        --    Just ts  (alternative tuples derived from given values)
        rts :: [Maybe [[RDFLabel]]]
        rts :: [Maybe [[RDFLabel]]]
rts = ClassRestrictionFn -> [[Maybe RDFLabel]] -> [Maybe [[RDFLabel]]]
forall a b. (a -> b) -> [a] -> [b]
map (ClassRestriction -> ClassRestrictionFn
crFunc ClassRestriction
restriction) [[Maybe RDFLabel]]
pts
        
        --  Extract list of consistent tuples of given values
        cts :: [([Maybe RDFLabel],[[RDFLabel]])]
        cts :: [([Maybe RDFLabel], [[RDFLabel]])]
cts = (([Maybe RDFLabel], Maybe [[RDFLabel]])
 -> Maybe ([Maybe RDFLabel], [[RDFLabel]]))
-> [([Maybe RDFLabel], Maybe [[RDFLabel]])]
-> [([Maybe RDFLabel], [[RDFLabel]])]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe ([Maybe RDFLabel], Maybe [[RDFLabel]])
-> Maybe ([Maybe RDFLabel], [[RDFLabel]])
forall a b. (a, Maybe b) -> Maybe (a, b)
tupleConv ([[Maybe RDFLabel]]
-> [Maybe [[RDFLabel]]] -> [([Maybe RDFLabel], Maybe [[RDFLabel]])]
forall a b. [a] -> [b] -> [(a, b)]
zip [[Maybe RDFLabel]]
pts [Maybe [[RDFLabel]]]
rts)
        
        --  TODO: be more idiomatic?
        tupleConv :: (a, Maybe b) -> Maybe (a,b)
        tupleConv :: (a, Maybe b) -> Maybe (a, b)
tupleConv (a
a, Just b
b)  = (a, b) -> Maybe (a, b)
forall a. a -> Maybe a
Just (a
a,b
b)
        tupleConv (a, Maybe b)
_            = Maybe (a, b)
forall a. Maybe a
Nothing
        
        --  Build list of consistent tuples with maximum information
        --  based on that supplied and available
        -- mts = concatMap mostValues cts
        mts :: [[Maybe RDFLabel]]
mts = (([Maybe RDFLabel], [[RDFLabel]]) -> [Maybe RDFLabel])
-> [([Maybe RDFLabel], [[RDFLabel]])] -> [[Maybe RDFLabel]]
forall a b. (a -> b) -> [a] -> [b]
map ([Maybe RDFLabel], [[RDFLabel]]) -> [Maybe RDFLabel]
forall a. ([Maybe a], [[a]]) -> [Maybe a]
mostOneValue [([Maybe RDFLabel], [[RDFLabel]])]
cts
        --  Eliminate consistent results subsumed by others.
        --  This results in a mimimal possible set of consistent inputs,
        --  because if any pair could be consistently unified then their
        --  common subsumer would still be in the list, and both would be
        --  thereby eliminated.
        sts :: [[Maybe RDFLabel]]
        sts :: [[Maybe RDFLabel]]
sts = PartCompare [Maybe RDFLabel]
-> [[Maybe RDFLabel]] -> [[Maybe RDFLabel]]
forall a. PartCompare a -> [a] -> [a]
maxima PartCompare [Maybe RDFLabel]
forall a. Eq a => [Maybe a] -> [Maybe a] -> Maybe Ordering
partCompareListMaybe [[Maybe RDFLabel]]
mts
        --  Check the cardinality constraint
        cardinalityOK :: Bool
cardinalityOK = [Int] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Int]
cs Bool -> Bool -> Bool
|| [[Maybe RDFLabel]] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [[Maybe RDFLabel]]
sts Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [Int]
cs
        
--  Map a non-empty list of values to a list of Just values,
--  preceding each with a Nothing element.
--
--  Nothing corresponds to an unknown value.  This logic is used
--  as part of constructing a list of alternative tuples of known
--  data values (either supplied or calculated from the class
--  restriction).
--
allJustAndNothing :: [a] -> [Maybe a]
allJustAndNothing :: [a] -> [Maybe a]
allJustAndNothing [a]
as = Maybe a
forall a. Maybe a
NothingMaybe a -> [Maybe a] -> [Maybe a]
forall a. a -> [a] -> [a]
:(a -> Maybe a) -> [a] -> [Maybe a]
forall a b. (a -> b) -> [a] -> [b]
map a -> Maybe a
forall a. a -> Maybe a
Just [a]
as

{-
--  Get maximum information about possible tuple values from a
--  given pair of input tuple, which is known to be consistent with
--  the restriction, and calculated result tuples.  Where the result
--  tuple is not exactly calculated, return the input tuple.
--
--  imvs    tuple of Maybe element values, with Nothing for
--          unspecified values
--  movss   Maybe list of possible fully-specified result tuples,
--          an empty list if no result tuples can be computed
--          based on the input tuple, or Nothing if the input
--          tuple is inconsistent.
--
mostValues :: ([Maybe a],[[a]]) -> [[Maybe a]]
mostValues (imvs,([])) = [imvs]
mostValues (_,movss) = map (map Just) movss
-}

--  Get maximum information about possible tuple values from a
--  given pair of input and possible result tuples, which is
--  known to be consistent with the restriction.  If the result
--  tuple is not exactly calculated, return the input tuple.
--
--  This is a variant of mostValues that returns a single vector.
--  Multiple possible values are considered to be equivalent to
--  Just [], i.e. unknown result.
--
--  imvs    tuple of Maybe element values, with Nothing for
--          unspecified values
--  movss   Maybe list of possible fully-specified result tuples,
--          or an empty list if no result tuples can be computed
--          based on the input tuple.
--
mostOneValue :: ([Maybe a],[[a]]) -> [Maybe a]
mostOneValue :: ([Maybe a], [[a]]) -> [Maybe a]
mostOneValue ([Maybe a]
_,[[a]
movs]) = (a -> Maybe a) -> [a] -> [Maybe a]
forall a b. (a -> b) -> [a] -> [b]
map a -> Maybe a
forall a. a -> Maybe a
Just [a]
movs
mostOneValue ([Maybe a]
imvs,[[a]]
_)   = [Maybe a]
imvs

--  Helper function that returns subsets of dts that "cover" the indicated
--  values;  i.e. from which all of the supplied values can be deduced
--  by the enumerated function results.  The minima of all such subsets is
--  returned, as each of these corresponds to some minimum information needed
--  to deduce all of the given values.
--
--  pvs     is a list of lists of values to be covered.  The inner list
--          contains multiple values for each member of a tuple.
--  dts     is an enumerated list of function values from some subset of
--          the tuple space to complete tuples.  Each member is a pair
--          containing the partial tuple (using Nothing for unspecified
--          values) and the full tuple calculated from it.
--
--  The return value is a disjunction of conjunctions of partial tuples
--  that cover the indicated parameter values.
--
--  NOTE:
--  The result minimization is not perfect (cf. test2 below), but I believe
--  it is adequate for the practical situations I envisage, and in any
--  case will not result in incorrect values.  It's significance is for
--  search-tree pruning.  A perfect minimization might be achieved by
--  using a more subtle partial ordering that takes account of both subsets
--  and the partial ordering of set members in place of 'partCompareListSubset'.
--
coverSets  :: (Eq a) => [[a]] -> [([Maybe a],[a])] -> [[[Maybe a]]]
coverSets :: [[a]] -> [([Maybe a], [a])] -> [[[Maybe a]]]
coverSets [[a]]
pvs [([Maybe a], [a])]
dts =
    PartCompare [[Maybe a]] -> [[[Maybe a]]] -> [[[Maybe a]]]
forall a. PartCompare a -> [a] -> [a]
minima PartCompare [[Maybe a]]
forall a. Eq a => [a] -> [a] -> Maybe Ordering
partCompareListSubset ([[[Maybe a]]] -> [[[Maybe a]]]) -> [[[Maybe a]]] -> [[[Maybe a]]]
forall a b. (a -> b) -> a -> b
$ ([([Maybe a], [a])] -> [[Maybe a]])
-> [[([Maybe a], [a])]] -> [[[Maybe a]]]
forall a b. (a -> b) -> [a] -> [b]
map ((([Maybe a], [a]) -> [Maybe a])
-> [([Maybe a], [a])] -> [[Maybe a]]
forall a b. (a -> b) -> [a] -> [b]
map ([Maybe a], [a]) -> [Maybe a]
forall a b. (a, b) -> a
fst) [[([Maybe a], [a])]]
ctss
    where
        ctss :: [[([Maybe a], [a])]]
ctss = ([([Maybe a], [a])] -> Bool)
-> [[([Maybe a], [a])]] -> [[([Maybe a], [a])]]
forall a. (a -> Bool) -> [a] -> [a]
filter [([Maybe a], [a])] -> Bool
forall a. [(a, [a])] -> Bool
coverspvs ([[([Maybe a], [a])]] -> [[([Maybe a], [a])]])
-> [[([Maybe a], [a])]] -> [[([Maybe a], [a])]]
forall a b. (a -> b) -> a -> b
$ [[([Maybe a], [a])]] -> [[([Maybe a], [a])]]
forall a. [a] -> [a]
tail ([[([Maybe a], [a])]] -> [[([Maybe a], [a])]])
-> [[([Maybe a], [a])]] -> [[([Maybe a], [a])]]
forall a b. (a -> b) -> a -> b
$ [([Maybe a], [a])] -> [[([Maybe a], [a])]]
forall a. [a] -> [[a]]
subsequences [([Maybe a], [a])]
cts
        cts :: [([Maybe a], [a])]
cts  = PartCompare ([Maybe a], [a])
-> [([Maybe a], [a])] -> [([Maybe a], [a])]
forall a. PartCompare a -> [a] -> [a]
minima (PartCompare [Maybe a]
-> PartCompare [a] -> PartCompare ([Maybe a], [a])
forall a b.
PartCompare a
-> PartCompare b -> (a, b) -> (a, b) -> Maybe Ordering
partComparePair PartCompare [Maybe a]
forall a. Eq a => [Maybe a] -> [Maybe a] -> Maybe Ordering
partCompareListMaybe PartCompare [a]
forall a. Eq a => PartCompare a
partCompareEq) [([Maybe a], [a])]
dts
        coverspvs :: [(a, [a])] -> Bool
coverspvs [(a, [a])]
cs = (a -> [a] -> [a]) -> [[a]] -> [[a]] -> Bool
forall a b. (a -> [b] -> [b]) -> [[a]] -> [[b]] -> Bool
coversVals a -> [a] -> [a]
forall a. Eq a => a -> [a] -> [a]
delete (((a, [a]) -> [a]) -> [(a, [a])] -> [[a]]
forall a b. (a -> b) -> [a] -> [b]
map (a, [a]) -> [a]
forall a b. (a, b) -> b
snd [(a, [a])]
cs) [[a]]
pvs

--  Does a supplied list of tuples cover a list of possible alternative
--  values for each tuple member?
--
coversVals :: (a->[b]->[b]) -> [[a]] -> [[b]] -> Bool
coversVals :: (a -> [b] -> [b]) -> [[a]] -> [[b]] -> Bool
coversVals a -> [b] -> [b]
dropVal [[a]]
ts [[b]]
vss =
    -- all null (foldr dropUsed vss ts)
    ([[b]] -> Bool) -> [[[b]]] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (([b] -> Bool) -> [[b]] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all [b] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null) (([a] -> [[b]] -> [[b]]) -> [[b]] -> [[a]] -> [[[b]]]
forall a b. (a -> b -> b) -> b -> [a] -> [b]
scanr [a] -> [[b]] -> [[b]]
dropUsed [[b]]
vss [[a]]
ts)
    where
        --  Remove single tuple values from the list of supplied values:
        dropUsed :: [a] -> [[b]] -> [[b]]
dropUsed []       []     = []
        dropUsed (a
a:[a]
as) ([b]
bs:[[b]]
bss) = a -> [b] -> [b]
dropVal a
a [b]
bs [b] -> [[b]] -> [[b]]
forall a. a -> [a] -> [a]
: [a] -> [[b]] -> [[b]]
dropUsed [a]
as [[b]]
bss
        dropUsed [a]
_ [[b]]
_ = String -> [[b]]
forall a. HasCallStack => String -> a
error String
"coversVals.dropUsed: list length mismatch"

{-
--  Does a supplied list of possible alternative values for each
--  element of a tuple cover every tuple in a supplied list?
--
--  (See module spike-coverVals.hs for test cases)
--
coversAll :: ([a]->b->Bool) -> [[a]] -> [[b]] -> Bool
coversAll matchElem vss ts = all (invss vss) ts
    where
        --  Test if a given tuple is covered by vss
        invss vss t = and $ zipWith matchElem vss t

--  Test if the value in a Maybe is contained in a list.
maybeElem :: (Eq a) => Maybe a -> [a] -> Bool
maybeElem Nothing  = const True
maybeElem (Just t) = elem t
-}

-- |Delete a Maybe value from a list
deleteMaybe :: (Eq a) => Maybe a -> [a] -> [a]
deleteMaybe :: Maybe a -> [a] -> [a]
deleteMaybe Maybe a
Nothing  [a]
as = [a]
as
deleteMaybe (Just a
a) [a]
as = a -> [a] -> [a]
forall a. Eq a => a -> [a] -> [a]
delete a
a [a]
as

-- | Make restriction rules from the supplied datatype and graph.

makeRDFDatatypeRestrictionRules :: RDFDatatypeVal vt -> RDFGraph -> [RDFRule]
makeRDFDatatypeRestrictionRules :: RDFDatatypeVal vt -> RDFGraph -> [RDFRule]
makeRDFDatatypeRestrictionRules RDFDatatypeVal vt
dtval =
    [ClassRestriction] -> RDFGraph -> [RDFRule]
makeRDFClassRestrictionRules [ClassRestriction]
dcrs 
    where
        dcrs :: [ClassRestriction]
dcrs = (DatatypeRel vt -> ClassRestriction)
-> [DatatypeRel vt] -> [ClassRestriction]
forall a b. (a -> b) -> [a] -> [b]
map (RDFDatatypeVal vt -> DatatypeRel vt -> ClassRestriction
forall vt. RDFDatatypeVal vt -> DatatypeRel vt -> ClassRestriction
makeDatatypeRestriction RDFDatatypeVal vt
dtval) (RDFDatatypeVal vt -> [DatatypeRel vt]
forall ex vt lb vn. DatatypeVal ex vt lb vn -> [DatatypeRel vt]
tvalRel RDFDatatypeVal vt
dtval)

--------------------------------------------------------------------------------
--
--  Copyright (c) 2003, Graham Klyne, 2009 Vasili I Galchin,
--    2011, 2012, 2014, 2018, 2022 Douglas Burke
--  All rights reserved.
--
--  This file is part of Swish.
--
--  Swish is free software; you can redistribute it and/or modify
--  it under the terms of the GNU General Public License as published by
--  the Free Software Foundation; either version 2 of the License, or
--  (at your option) any later version.
--
--  Swish is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--  GNU General Public License for more details.
--
--  You should have received a copy of the GNU General Public License
--  along with Swish; if not, write to:
--    The Free Software Foundation, Inc.,
--    59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
--
--------------------------------------------------------------------------------