Source code for djangordf.reasoning.rdfs

"""Canonical RDFS reasoner.

Five rules covering ``rdfs:subClassOf`` transitivity, type
propagation through ``subClassOf`` / ``subPropertyOf``, and ``domain``
/ ``range`` inference. Implemented as SPARQL ``INSERT-WHERE``
templates so they execute against any SPARQL 1.1 backend.
"""
from typing import Sequence

from rdflib import URIRef

from .base import Reasoner


_RDF_TYPE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
_RDFS_SUBCLASS_OF = "http://www.w3.org/2000/01/rdf-schema#subClassOf"
_RDFS_SUBPROP_OF = "http://www.w3.org/2000/01/rdf-schema#subPropertyOf"
_RDFS_DOMAIN = "http://www.w3.org/2000/01/rdf-schema#domain"
_RDFS_RANGE = "http://www.w3.org/2000/01/rdf-schema#range"


def _rule(template: str, src: URIRef, tgt: URIRef) -> str:
    return template.format(src=src, tgt=tgt)


[docs] class RDFSReasoner(Reasoner): """Run canonical RDFS entailment rules to a fixpoint.""" _SUBCLASS_TRANSITIVE = ( "INSERT {{ GRAPH <{tgt}> {{ ?a <" + _RDFS_SUBCLASS_OF + "> ?c }} }} " "WHERE {{ GRAPH <{src}> {{ " "?a <" + _RDFS_SUBCLASS_OF + "> ?b . " "?b <" + _RDFS_SUBCLASS_OF + "> ?c . " "}} " "FILTER (?a != ?c) " "FILTER NOT EXISTS {{ GRAPH <{tgt}> {{ " "?a <" + _RDFS_SUBCLASS_OF + "> ?c " "}} }} }}" ) _TYPE_VIA_SUBCLASS = ( "INSERT {{ GRAPH <{tgt}> {{ ?s <" + _RDF_TYPE + "> ?y }} }} " "WHERE {{ GRAPH <{src}> {{ " "?s <" + _RDF_TYPE + "> ?x . " "?x <" + _RDFS_SUBCLASS_OF + "> ?y . " "}} " "FILTER NOT EXISTS {{ GRAPH <{tgt}> {{ " "?s <" + _RDF_TYPE + "> ?y " "}} }} }}" ) _SUBPROP_TRANSITIVE = ( "INSERT {{ GRAPH <{tgt}> {{ ?s ?q ?o }} }} " "WHERE {{ GRAPH <{src}> {{ " "?p <" + _RDFS_SUBPROP_OF + "> ?q . " "?s ?p ?o . " "}} " "FILTER NOT EXISTS {{ GRAPH <{tgt}> {{ ?s ?q ?o }} }} }}" ) _DOMAIN_INFERENCE = ( "INSERT {{ GRAPH <{tgt}> {{ ?s <" + _RDF_TYPE + "> ?d }} }} " "WHERE {{ GRAPH <{src}> {{ " "?p <" + _RDFS_DOMAIN + "> ?d . " "?s ?p ?o . " "}} " "FILTER NOT EXISTS {{ GRAPH <{tgt}> {{ " "?s <" + _RDF_TYPE + "> ?d " "}} }} }}" ) _RANGE_INFERENCE = ( "INSERT {{ GRAPH <{tgt}> {{ ?o <" + _RDF_TYPE + "> ?r }} }} " "WHERE {{ GRAPH <{src}> {{ " "?p <" + _RDFS_RANGE + "> ?r . " "?s ?p ?o . " "}} " "FILTER (isIRI(?o) || isBlank(?o)) " "FILTER NOT EXISTS {{ GRAPH <{tgt}> {{ " "?o <" + _RDF_TYPE + "> ?r " "}} }} }}" )
[docs] def rules(self, source_graph: URIRef, target_graph: URIRef) -> Sequence[str]: return [ _rule(self._SUBCLASS_TRANSITIVE, source_graph, target_graph), _rule(self._TYPE_VIA_SUBCLASS, source_graph, target_graph), _rule(self._SUBPROP_TRANSITIVE, source_graph, target_graph), _rule(self._DOMAIN_INFERENCE, source_graph, target_graph), _rule(self._RANGE_INFERENCE, source_graph, target_graph), ]