From 18ddefc7c9e9cfaca027a054495325737ae6b9e6 Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Thu, 22 Jul 2021 08:29:11 +0100 Subject: Move some generic commands from RSAOntology to Ontology --- .../scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala | 445 ++++++++++----------- .../cs/rsacomb/approximation/approximation.scala | 4 +- .../uk/ac/ox/cs/rsacomb/ontologies/Ontology.scala | 58 ++- 3 files changed, 248 insertions(+), 259 deletions(-) (limited to 'src/main/scala') diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala index 9902fcd..630d2a0 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala @@ -63,6 +63,7 @@ import uk.ac.ox.cs.rsacomb.suffix._ import uk.ac.ox.cs.rsacomb.sparql._ import uk.ac.ox.cs.rsacomb.util.{RDFoxUtil, RSA} import uk.ac.ox.cs.rsacomb.util.Logger +import uk.ac.ox.cs.rsacomb.ontology.Ontology object RSAUtil { @@ -94,82 +95,94 @@ object RSAOntology { /** Manager instance to interface with OWLAPI */ val manager = OWLManager.createOWLOntologyManager() - val factory = manager.getOWLDataFactory() /** Name of the RDFox data store used for CQ answering */ private val DataStore = "answer_computation" + /** Filtering program for a given query + * + * @param query the query to derive the filtering program + * @return the filtering program for the given query + */ + def filteringProgram(query: ConjunctiveQuery): FilteringProgram = + Logger.timed( + FilteringProgram(FilterType.REVISED)(query), + "Generating filtering program", + Logger.DEBUG + ) + def apply( axioms: List[OWLLogicalAxiom], datafiles: List[File] - ): RSAOntology = new RSAOntology(axioms, datafiles: _*) - - def apply( - ontofile: File, - datafiles: List[File], - approx: Option[Approximation] - ): RSAOntology = { - val ontology = manager.loadOntologyFromOntologyDocument(ontofile) - RSAOntology(ontology, datafiles, approx) - } + ): RSAOntology = new RSAOntology(axioms, datafiles) + + // def apply( + // ontofile: File, + // datafiles: List[File], + // approx: Option[Approximation] + // ): RSAOntology = { + // val ontology = manager.loadOntologyFromOntologyDocument(ontofile) + // RSAOntology(ontology, datafiles, approx) + // } - def apply( - ontology: OWLOntology, - datafiles: List[File], - approx: Option[Approximation] - ): RSAOntology = { - val normalizer = new Normalizer() - - /** TBox axioms */ - var tbox: List[OWLLogicalAxiom] = - ontology - .tboxAxioms(Imports.INCLUDED) - .collect(Collectors.toList()) - .collect { case a: OWLLogicalAxiom => a } - .flatMap(normalizer.normalize) - - /** RBox axioms */ - var rbox: List[OWLLogicalAxiom] = - ontology - .rboxAxioms(Imports.INCLUDED) - .collect(Collectors.toList()) - .collect { case a: OWLLogicalAxiom => a } - .flatMap(normalizer.normalize) - - /** ABox axioms - * - * @note this represents only the set of assertions contained in the - * ontology file. Data files specified in `datafiles` are directly - * imported in RDFox due to performance issues when trying to import - * large data files via OWLAPI. - */ - var abox: List[OWLLogicalAxiom] = - ontology - .aboxAxioms(Imports.INCLUDED) - .collect(Collectors.toList()) - .collect { case a: OWLLogicalAxiom => a } - .flatMap(normalizer.normalize) - - /** Collection of logical axioms in the input ontology */ - var axioms: List[OWLLogicalAxiom] = abox ::: tbox ::: rbox - - new RSAOntology( - approx match { - case Some(a) => a.approximate(axioms, datafiles) - case None => axioms - }, - datafiles: _* - ) - } + // def apply( + // ontology: OWLOntology, + // datafiles: List[File], + // approx: Option[Approximation] + // ): RSAOntology = { + // val normalizer = new Normalizer() + + // /** TBox axioms */ + // var tbox: List[OWLLogicalAxiom] = + // ontology + // .tboxAxioms(Imports.INCLUDED) + // .collect(Collectors.toList()) + // .collect { case a: OWLLogicalAxiom => a } + // .flatMap(normalizer.normalize) + + // /** RBox axioms */ + // var rbox: List[OWLLogicalAxiom] = + // ontology + // .rboxAxioms(Imports.INCLUDED) + // .collect(Collectors.toList()) + // .collect { case a: OWLLogicalAxiom => a } + // .flatMap(normalizer.normalize) + + // /** ABox axioms + // * + // * @note this represents only the set of assertions contained in the + // * ontology file. Data files specified in `datafiles` are directly + // * imported in RDFox due to performance issues when trying to import + // * large data files via OWLAPI. + // */ + // var abox: List[OWLLogicalAxiom] = + // ontology + // .aboxAxioms(Imports.INCLUDED) + // .collect(Collectors.toList()) + // .collect { case a: OWLLogicalAxiom => a } + // .flatMap(normalizer.normalize) + + // /** Collection of logical axioms in the input ontology */ + // var axioms: List[OWLLogicalAxiom] = abox ::: tbox ::: rbox + + // new RSAOntology( + // approx match { + // case Some(a) => a.approximate(axioms, datafiles) + // case None => axioms + // }, + // datafiles: _* + // ) + // } } -/** Wrapper class for an ontology in RSA +/** A wrapper for an RSA ontology * * @param ontology the input OWL2 ontology. * @param datafiles additinal data (treated as part of the ABox) */ -class RSAOntology(val axioms: List[OWLLogicalAxiom], val datafiles: File*) { +class RSAOntology(axioms: List[OWLLogicalAxiom], datafiles: List[File]) + extends Ontology(axioms, datafiles) { /** Simplify conversion between OWLAPI and RDFox concepts */ import implicits.RDFox._ @@ -179,34 +192,26 @@ class RSAOntology(val axioms: List[OWLLogicalAxiom], val datafiles: File*) { import uk.ac.ox.cs.rsacomb.implicits.JavaCollections._ /** Set of axioms removed during the approximation to RSA */ - private var removed: Seq[OWLAxiom] = Seq.empty - - /** Normalized Horn-ALCHOIQ ontology */ - val ontology = - RSAOntology.manager.createOntology((axioms: List[OWLAxiom]).asJava) - - /** OWLAPI internal reasoner instantiated over the approximated ontology */ - private val reasoner = - (new StructuralReasonerFactory()).createReasoner(ontology) + //private var removed: Seq[OWLAxiom] = Seq.empty /** Retrieve individuals/literals in the ontology */ - val individuals: List[IRI] = + private val individuals: List[IRI] = ontology .getIndividualsInSignature() .asScala .map(_.getIRI) .map(implicits.RDFox.owlapiToRdfoxIri) .toList - val literals: List[Literal] = + private val literals: List[Literal] = axioms .collect { case a: OWLDataPropertyAssertionAxiom => a } .map(_.getObject) .map(implicits.RDFox.owlapiToRdfoxLiteral) /** Retrieve concepts/roles in the ontology */ - val concepts: List[OWLClass] = + private val concepts: List[OWLClass] = ontology.getClassesInSignature().asScala.toList - val roles: List[OWLObjectPropertyExpression] = + private val roles: List[OWLObjectPropertyExpression] = axioms .flatMap(_.objectPropertyExpressionsInSignature) .distinct @@ -223,36 +228,36 @@ class RSAOntology(val axioms: List[OWLLogicalAxiom], val datafiles: File*) { * if there exists a role p2 appearing in an axiom of type T4 and * p1 is a subproperty of either p2 or the inverse of p2. */ - val unsafeRoles: List[OWLObjectPropertyExpression] = { - - /* Checking for unsafety condition (1) */ - val unsafe1 = for { - axiom <- axioms - if axiom.isT5 - role1 <- axiom.objectPropertyExpressionsInSignature - roleSuper = role1 +: reasoner.superObjectProperties(role1) - roleSuperInv = roleSuper.map(_.getInverseProperty) - axiom <- axioms - if axiom.isT3 && !axiom.isT3top - role2 <- axiom.objectPropertyExpressionsInSignature - if roleSuperInv contains role2 - } yield role1 - - /* Checking for unsafety condition (2) */ - val unsafe2 = for { - axiom <- axioms - if axiom.isT5 - role1 <- axiom.objectPropertyExpressionsInSignature - roleSuper = role1 +: reasoner.superObjectProperties(role1) - roleSuperInv = roleSuper.map(_.getInverseProperty) - axiom <- axioms - if axiom.isT4 - role2 <- axiom.objectPropertyExpressionsInSignature - if roleSuper.contains(role2) || roleSuperInv.contains(role2) - } yield role1 - - unsafe1 ++ unsafe2 - } + // val unsafeRoles: List[OWLObjectPropertyExpression] = { + + // /* Checking for unsafety condition (1) */ + // val unsafe1 = for { + // axiom <- axioms + // if axiom.isT5 + // role1 <- axiom.objectPropertyExpressionsInSignature + // roleSuper = role1 +: reasoner.superObjectProperties(role1) + // roleSuperInv = roleSuper.map(_.getInverseProperty) + // axiom <- axioms + // if axiom.isT3 && !axiom.isT3top + // role2 <- axiom.objectPropertyExpressionsInSignature + // if roleSuperInv contains role2 + // } yield role1 + + // /* Checking for unsafety condition (2) */ + // val unsafe2 = for { + // axiom <- axioms + // if axiom.isT5 + // role1 <- axiom.objectPropertyExpressionsInSignature + // roleSuper = role1 +: reasoner.superObjectProperties(role1) + // roleSuperInv = roleSuper.map(_.getInverseProperty) + // axiom <- axioms + // if axiom.isT4 + // role2 <- axiom.objectPropertyExpressionsInSignature + // if roleSuper.contains(role2) || roleSuperInv.contains(role2) + // } yield role1 + + // unsafe1 ++ unsafe2 + // } /** Approximate a Horn-ALCHOIQ ontology to RSA * @@ -396,31 +401,27 @@ class RSAOntology(val axioms: List[OWLLogicalAxiom], val datafiles: File*) { ) } + /** Canonical model of the ontology */ lazy val canonicalModel = Logger.timed( new CanonicalModel(this), "Generating canonical model program", Logger.DEBUG ) - def filteringProgram(query: ConjunctiveQuery): FilteringProgram = - Logger.timed( - FilteringProgram(FilterType.REVISED)(query), - "Generating filtering program", - Logger.DEBUG - ) - + /** Computes all roles conflicting with a given role + * + * @param role a role (object property expression). + * @return a set of roles conflicting with `role`. + */ def confl( role: OWLObjectPropertyExpression ): Set[OWLObjectPropertyExpression] = { - - val invSuperRoles = reasoner + reasoner .superObjectProperties(role) .collect(Collectors.toSet()) .asScala .addOne(role) .map(_.getInverseProperty) - - invSuperRoles .flatMap(x => reasoner .subObjectProperties(x) @@ -432,6 +433,77 @@ class RSAOntology(val axioms: List[OWLLogicalAxiom], val datafiles: File*) { .filterNot(_.getInverseProperty.isOWLTopObjectProperty()) } + /** Selfloop detection for a given axiom + * + * @param axiom an axiom of type [[OWLSubClassOfAxiom]] + * @return unfold set for the axiom + */ + def self(axiom: OWLSubClassOfAxiom): Set[Term] = { + val role = axiom.objectPropertyExpressionsInSignature(0) + if (this.confl(role).contains(role)) { + Set(RSA("v0_" ++ axiom.hashed), RSA("v1_" ++ axiom.hashed)) + } else { + Set() + } + } + + /** Cycle detection for a give axiom + * + * @param axiom an axiom of type [[OWLSubClassOfAxiom]] + * @return unfold set for the axiom + * + * @todo we can actually use `toTriple` from `RSAAxiom` to get the + * classes and the role for a given axiom + */ + def cycle(axiom: OWLSubClassOfAxiom): Set[Term] = { + val classes = + axiom.classesInSignature.collect(Collectors.toList()).asScala + val classA = classes(0) + val roleR = axiom + .objectPropertyExpressionsInSignature(0) + .asInstanceOf[OWLObjectProperty] + val classB = classes(1) + cycle_aux(classA, roleR, classB) + } + + /** Auxiliary function for [[RSAOntology.cycle]] */ + private def cycle_aux( + classA: OWLClass, + roleR: OWLObjectProperty, + classB: OWLClass + ): Set[Term] = { + val conflR = this.confl(roleR) + // TODO: technically we just need the TBox here + val terms = for { + axiom1 <- axioms + if axiom1.isT5 + // We expect only one role coming out of a T5 axiom + roleS <- axiom1.objectPropertyExpressionsInSignature + // Triples ordering is among triples involving safe roles. + if !unsafe.contains(roleS) + if conflR.contains(roleS) + tripleARB = RSAAxiom.hashed(classA, roleR, classB) + tripleDSC = axiom1.hashed + individual = + if (tripleARB > tripleDSC) { + RSA("v1_" ++ tripleDSC) + } else { + // Note that this is also the case for + // `tripleARB == tripleDSC` + RSA("v0_" ++ tripleDSC) + } + } yield individual + terms to Set + } + + /** Returns unfold set for self-loop and cycle for the input axiom + * + * @param axiom an axiom of type [[OWLSubClassOfAxiom]] + * @return unfold set for the axiom + */ + def unfold(axiom: OWLSubClassOfAxiom): Set[Term] = + this.self(axiom) | this.cycle(axiom) + /** Returns the answers to a query * * @param query query to execute @@ -439,10 +511,9 @@ class RSAOntology(val axioms: List[OWLLogicalAxiom], val datafiles: File*) { */ def ask(query: ConjunctiveQuery): ConjunctiveQueryAnswers = Logger.timed( { - import implicits.JavaCollections._ val (server, data) = RDFoxUtil.openConnection(RSAOntology.DataStore) val canon = this.canonicalModel - val filter = this.filteringProgram(query) + val filter = RSAOntology.filteringProgram(query) /* Upload data from data file */ RDFoxUtil.addData(data, datafiles: _*) @@ -460,12 +531,15 @@ class RSAOntology(val axioms: List[OWLLogicalAxiom], val datafiles: File*) { new java.util.HashMap[String, String] ) + /* Add canonical model */ Logger print s"Canonical model rules: ${canon.rules.length}" RDFoxUtil.addRules(data, canon.rules) Logger print s"Canonical model facts: ${canon.facts.length}" RDFoxUtil.addFacts(data, canon.facts) + RDFoxUtil printStatisticsFor data + //{ // import java.io.{PrintStream, FileOutputStream, File} // val rules1 = new FileOutputStream(new File("rules1-lubm200.dlog")) @@ -475,16 +549,13 @@ class RSAOntology(val axioms: List[OWLLogicalAxiom], val datafiles: File*) { // rules2.print(filter.rules.mkString("\n")) //} - //canon.facts.foreach(println) - //filter.rules.foreach(println) - - RDFoxUtil printStatisticsFor data - + /* Add filtering program */ Logger print s"Filtering program rules: ${filter.rules.length}" RDFoxUtil.addRules(data, filter.rules) RDFoxUtil printStatisticsFor data + /* Gather answers to the query */ val answers = { val ans = filter.answerQuery RDFoxUtil @@ -492,7 +563,9 @@ class RSAOntology(val axioms: List[OWLLogicalAxiom], val datafiles: File*) { .map(new ConjunctiveQueryAnswers(query.bcq, query.variables, _)) .get } + RDFoxUtil.closeConnection(server, data) + answers }, "Answers computation", @@ -503,14 +576,15 @@ class RSAOntology(val axioms: List[OWLLogicalAxiom], val datafiles: File*) { * * @note This method does not add any facts or rules to the data * store. It is most useful after the execution of a query using - * [[uk.ac.ox.cs.rsacomb.RSAOntology.ask RSAOntology.ask]]. - * @note This method has been introduced mostly for debugging purposes. + * [[RSAOntology.ask]]. * * @param query query to be executed against the environment * @param prefixes additional prefixes for the query. It defaults to * an empty set. * @param opts additional options to RDFox. * @return a collection of answers to the input query. + * + * @note This method has been introduced mostly for debugging purposes. */ def queryDataStore( query: String, @@ -532,122 +606,11 @@ class RSAOntology(val axioms: List[OWLLogicalAxiom], val datafiles: File*) { * [[uk.ac.ox.cs.rsacomb.RSAOntology.ask RSAOntology.ask]] * for the corresponding query has been called. */ - def askUnfiltered( - cq: ConjunctiveQuery - ): Option[Seq[(Long, Seq[Resource])]] = { - val query = RDFoxUtil.buildDescriptionQuery("QM", cq.variables.length) - queryDataStore(query, RSA.Prefixes) - } - - def self(axiom: OWLSubClassOfAxiom): Set[Term] = { - // Assuming just one role in the signature of a T5 axiom - val role = axiom.objectPropertyExpressionsInSignature(0) - if (this.confl(role).contains(role)) { - Set( - RSA("v0_" ++ axiom.hashed), - RSA("v1_" ++ axiom.hashed) - ) - } else { - Set() - } - } - - def cycle(axiom: OWLSubClassOfAxiom): Set[Term] = { - // TODO: we can actually use `toTriple` from `RSAAxiom` - val classes = - axiom.classesInSignature.collect(Collectors.toList()).asScala - val classA = classes(0) - val roleR = axiom - .objectPropertyExpressionsInSignature(0) - .asInstanceOf[OWLObjectProperty] - val classB = classes(1) - cycle_aux1(classA, roleR, classB) - } - - def cycle_aux0( - classA: OWLClass, - roleR: OWLObjectProperty, - classB: OWLClass - ): Set[Term] = { - val conflR = this.confl(roleR) - val classes = ontology - .classesInSignature(Imports.INCLUDED) - .collect(Collectors.toSet()) - .asScala - for { - classD <- classes - roleS <- conflR - classC <- classes - // Keeping this check for now - if !unsafeRoles.contains(roleS) - tripleARB = RSAAxiom.hashed(classA, roleR, classB) - tripleDSC = RSAAxiom.hashed(classD, roleS, classC) - individual = - if (tripleARB > tripleDSC) { - RSA("v1_" ++ tripleDSC) - } else { - // Note that this is also the case for - // `tripleARB == tripleDSC` - RSA("v0_" ++ tripleDSC) - } - } yield individual - } - - def cycle_aux1( - classA: OWLClass, - roleR: OWLObjectProperty, - classB: OWLClass - ): Set[Term] = { - val conflR = this.confl(roleR) - // We just need the TBox to find - val terms = for { - axiom1 <- axioms - if axiom1.isT5 - // We expect only one role coming out of a T5 axiom - roleS <- axiom1.objectPropertyExpressionsInSignature - // Triples ordering is among triples involving safe roles. - if !unsafeRoles.contains(roleS) - if conflR.contains(roleS) - tripleARB = RSAAxiom.hashed(classA, roleR, classB) - tripleDSC = axiom1.hashed - individual = - if (tripleARB > tripleDSC) { - RSA("v1_" ++ tripleDSC) - } else { - // Note that this is also the case for - // `tripleARB == tripleDSC` - RSA("v0_" ++ tripleDSC) - } - } yield individual - terms to Set - } - - def unfold(axiom: OWLSubClassOfAxiom): Set[Term] = - this.self(axiom) | this.cycle(axiom) - - /** Log normalization/approximation statistics */ - // def statistics(level: Logger.Level = Logger.DEBUG): Unit = { - // Logger.print( - // s"Logical axioms in original input ontology: ${original.getLogicalAxiomCount(true)}", - // level - // ) - // Logger.print( - // s"Logical axioms discarded in Horn-ALCHOIQ approximation: ${normalizer.discarded}", - // level - // ) - // Logger.print( - // s"Logical axioms shifted in Horn-ALCHOIQ approximation: ${normalizer.shifted}", - // level - // ) - // Logger.print( - // s"Logical axioms in Horn-ALCHOIQ ontology: ${ontology - // .getLogicalAxiomCount(true)} (${axioms.length}/${axioms.length}/${axioms.length})", - // level - // ) - // Logger.print( - // s"Logical axioms discarded in RSA approximation: ${removed.length}", - // level - // ) + // def askUnfiltered( + // cq: ConjunctiveQuery + // ): Option[Seq[(Long, Seq[Resource])]] = { + // val query = RDFoxUtil.buildDescriptionQuery("QM", cq.variables.length) + // queryDataStore(query, RSA.Prefixes) // } -} // class RSAOntology +} diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/approximation.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/approximation.scala index 1b49413..db2118f 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/approximation.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/approximation/approximation.scala @@ -8,8 +8,8 @@ trait Approximation { /** Approximate an ontology. * - * @param ontology input ontology - * @return a new approximated ontology + * @param ontology input ontology as a list of axioms + * @return the approximated ontology */ def approximate( ontology: List[OWLLogicalAxiom], diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/ontologies/Ontology.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/ontologies/Ontology.scala index 7856b3a..4a23ec7 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/ontologies/Ontology.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/ontologies/Ontology.scala @@ -27,7 +27,15 @@ import org.semanticweb.owlapi.apibinding.OWLManager import org.semanticweb.owlapi.model.{OWLOntology, OWLAxiom, OWLLogicalAxiom} import org.semanticweb.owlapi.model.{OWLObjectPropertyExpression} import org.semanticweb.owlapi.reasoner.structural.StructuralReasonerFactory -import tech.oxfordsemantic.jrdfox.logic.expression.Resource +import tech.oxfordsemantic.jrdfox.logic.datalog.Rule +import tech.oxfordsemantic.jrdfox.logic.expression.{Resource, Term, Variable} + +import uk.ac.ox.cs.rsacomb.approximation.Approximation +import uk.ac.ox.cs.rsacomb.converter._ +import uk.ac.ox.cs.rsacomb.suffix._ +import uk.ac.ox.cs.rsacomb.util.{RDFoxUtil, RSA} + +import uk.ac.ox.cs.rsacomb.RSAUtil object Ontology { @@ -44,7 +52,6 @@ object Ontology { * TODO: turn this into an implicit class parameter. */ val manager = OWLManager.createOWLOntologyManager() - //val factory = manager.getOWLDataFactory() /** Compute the RSA dependency graph for a set of axioms * @@ -66,22 +73,17 @@ object Ontology { unsafe: List[OWLObjectPropertyExpression] ): DependencyGraph = { - import org.semanticweb.owlapi.model.{ - OWLClassExpression, - OWLObjectSomeValuesFrom, - OWLDataSomeValuesFrom - } - import tech.oxfordsemantic.jrdfox.logic.datalog.Rule - import tech.oxfordsemantic.jrdfox.logic.expression.{Term, Variable} - import uk.ac.ox.cs.rsacomb.suffix._ - import uk.ac.ox.cs.rsacomb.converter._ - import uk.ac.ox.cs.rsacomb.util.{RDFoxUtil, RSA} - import uk.ac.ox.cs.rsacomb.RSAUtil - var nodemap = Map.empty[String, OWLAxiom] + /* Create custom converter */ object RSAConverter extends RDFoxConverter { + import org.semanticweb.owlapi.model.{ + OWLClassExpression, + OWLObjectSomeValuesFrom, + OWLDataSomeValuesFrom + } + override def convert( expr: OWLClassExpression, term: Term, @@ -156,6 +158,9 @@ object Ontology { } /** A wrapper for a generic OWL2 ontology + * + * @param axioms list of axioms (roughly) corresponding to the TBox. + * @param datafiles files containing ABox data. */ class Ontology(val axioms: List[OWLLogicalAxiom], val datafiles: List[File]) { @@ -170,11 +175,11 @@ class Ontology(val axioms: List[OWLLogicalAxiom], val datafiles: List[File]) { * This is mainly used to instantiate a new reasoner to be used in * the computation of unsafe roles. */ - private val ontology: OWLOntology = + protected val ontology: OWLOntology = Ontology.manager.createOntology((axioms: List[OWLAxiom]).asJava) /** OWLAPI internal reasoner for ontology */ - private val reasoner = + protected val reasoner = (new StructuralReasonerFactory()).createReasoner(ontology) /** Unsafe roles in the ontology @@ -219,7 +224,28 @@ class Ontology(val axioms: List[OWLLogicalAxiom], val datafiles: List[File]) { unsafe1 ++ unsafe2 } + /** Compute the dependency graph for the ontology */ lazy val dependencyGraph: Ontology.DependencyGraph = Ontology.dependencyGraph(axioms, datafiles, this.unsafe) + /** RSA check */ + lazy val isRSA: Boolean = ??? + + /** Normalize the ontology according to the given normalizer + * + * @param normalizer the normalization technique to be used. + * @return a new normalized [[Ontology]]. + */ + def normalize(normalizer: Normalizer): Ontology = ??? + + /** Approximate the ontology according to the given approximation + * technique. + * + * @param approximation the approximation to be used on the ontology. + * @return a new approximated [[Ontology]]. + */ + def approximate(approximation: Approximation): Ontology = { + val approx = approximation.approximate(axioms, datafiles) + new Ontology(approx, datafiles) + } } -- cgit v1.2.3