package uk.ac.manchester.cs.jfact.kernel; /* This file is part of the JFact DL reasoner Copyright 2011-2013 by Ignazio Palmisano, Dmitry Tsarkov, University of Manchester This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*/ import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.semanticweb.owlapi.model.OWLRuntimeException; import org.semanticweb.owlapi.reasoner.InconsistentOntologyException; import org.semanticweb.owlapi.reasoner.ReasonerInternalException; import uk.ac.manchester.cs.jfact.helpers.DLTree; import uk.ac.manchester.cs.jfact.helpers.DLTreeFactory; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomConceptInclusion; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomDRoleDomain; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomDRoleFunctional; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomDRoleRange; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomDRoleSubsumption; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomDeclaration; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomDifferentIndividuals; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomDisjointConcepts; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomDisjointDRoles; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomDisjointORoles; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomDisjointUnion; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomEquivalentConcepts; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomEquivalentDRoles; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomEquivalentORoles; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomFairnessConstraint; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomInstanceOf; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomORoleDomain; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomORoleFunctional; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomORoleRange; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomORoleSubsumption; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomRelatedTo; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomRelatedToNot; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomRoleAsymmetric; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomRoleInverse; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomRoleInverseFunctional; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomRoleIrreflexive; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomRoleReflexive; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomRoleSymmetric; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomRoleTransitive; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomSameIndividuals; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomValueOf; import uk.ac.manchester.cs.jfact.kernel.dl.axioms.AxiomValueOfNot; import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.AxiomInterface; import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.Expression; import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.IndividualExpression; import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.RoleExpression; import uk.ac.manchester.cs.jfact.split.SplitVarEntry; import uk.ac.manchester.cs.jfact.split.TSplitVar; import uk.ac.manchester.cs.jfact.visitors.DLAxiomVisitor; import conformance.PortedFrom; /** ontology loader */ @PortedFrom(file = "tOntologyLoader.h", name = "TOntologyLoader") public class OntologyLoader implements DLAxiomVisitor, Serializable { private static final long serialVersionUID = 11000L; /** KB to load the ontology */ @PortedFrom(file = "tOntologyLoader.h", name = "kb") private final TBox tbox; /** Transforms TDLExpression hierarchy to the DLTree */ @PortedFrom(file = "tOntologyLoader.h", name = "ETrans") private final ExpressionTranslator expressionTranslator; /** * get role by the DLTree; throw exception if unable * * @param r * r * @param reason * reason * @return role */ @PortedFrom(file = "tOntologyLoader.h", name = "getRole") private Role getRole(RoleExpression r, String reason) { try { return Role.resolveRole(r.accept(expressionTranslator)); } catch (OWLRuntimeException e) { throw new ReasonerInternalException(reason + '\t' + e.getMessage(), e); } } /** * @param I * I * @param reason * reason * @return an individual be the DLTree; throw exception if unable */ @PortedFrom(file = "tOntologyLoader.h", name = "getIndividual") public Individual getIndividual(IndividualExpression I, String reason) { DLTree i = I.accept(expressionTranslator); if (i == null) { throw new ReasonerInternalException(reason); } return (Individual) tbox.getCI(i); } /** * ensure that the expression EXPR has its named entities linked to the KB * ones * * @param Expr * Expr */ @PortedFrom(file = "tOntologyLoader.h", name = "ensureNames") public void ensureNames(Expression Expr) { assert Expr != null; // temporarily } /** * prepare arguments for the [begin,end) interval * * @param c * c * @param <T> * type * @return list of arguments */ @PortedFrom(file = "tOntologyLoader.h", name = "prepareArgList") private <T extends Expression> List<DLTree> prepareArgList(Collection<T> c) { List<DLTree> ArgList = new ArrayList<DLTree>(); for (T t : c) { ensureNames(t); ArgList.add(t.accept(expressionTranslator)); } return ArgList; } @PortedFrom(file = "tOntologyLoader.h", name = "fillSplit") private void fillSplit(TSplitVar sv) { sv.setC(tbox.getConcept(sv.getOldName().getName())); sv.getC().setNonClassifiable(true); for (SplitVarEntry p : sv.getEntries()) { Concept C = tbox.getConcept(p.name.getName()); C.setSystem(); p.concept = C; } } @Override public void visit(AxiomDeclaration axiom) { ensureNames(axiom.getDeclaration()); // names in the KB axiom.getDeclaration().accept(expressionTranslator); } // n-ary axioms @Override public void visit(AxiomEquivalentConcepts axiom) { tbox.processEquivalentC(prepareArgList(axiom.getArguments())); } @Override public void visit(AxiomDisjointConcepts axiom) { tbox.processDisjointC(prepareArgList(axiom.getArguments())); } @Override public void visit(AxiomEquivalentORoles axiom) { tbox.processEquivalentR(prepareArgList(axiom.getArguments())); } @Override public void visit(AxiomEquivalentDRoles axiom) { tbox.processEquivalentR(prepareArgList(axiom.getArguments())); } @Override public void visit(AxiomDisjointORoles axiom) { tbox.processDisjointR(prepareArgList(axiom.getArguments())); } @Override public void visit(AxiomDisjointDRoles axiom) { tbox.processDisjointR(prepareArgList(axiom.getArguments())); } @Override public void visit(AxiomDisjointUnion axiom) { // first make a disjoint axiom tbox.processDisjointC(prepareArgList(axiom.getArguments())); // now define C as a union-of axiom List<DLTree> ArgList = new ArrayList<DLTree>(); ensureNames(axiom.getConcept()); ArgList.add(axiom.getConcept().accept(expressionTranslator)); List<DLTree> list = new ArrayList<DLTree>(); for (Expression p : axiom.getArguments()) { list.add(p.accept(expressionTranslator)); } ArgList.add(DLTreeFactory.createSNFOr(list)); tbox.processEquivalentC(ArgList); } @Override public void visit(AxiomSameIndividuals axiom) { tbox.processSame(prepareArgList(axiom.getArguments())); } @Override public void visit(AxiomDifferentIndividuals axiom) { tbox.processDifferent(prepareArgList(axiom.getArguments())); } @Override public void visit(AxiomFairnessConstraint axiom) { tbox.setFairnessConstraintDLTrees(prepareArgList(axiom.getArguments())); } // role axioms @Override public void visit(AxiomRoleInverse axiom) { ensureNames(axiom.getRole()); ensureNames(axiom.getInvRole()); Role R = getRole(axiom.getRole(), "Role expression expected in Role Inverse axiom"); Role iR = getRole(axiom.getInvRole(), "Role expression expected in Role Inverse axiom"); tbox.getRM(R).addRoleSynonym(iR.inverse(), R); } @Override public void visit(AxiomORoleSubsumption axiom) { ensureNames(axiom.getRole()); ensureNames(axiom.getSubRole()); DLTree Sub = axiom.getSubRole().accept(expressionTranslator); Role R = getRole(axiom.getRole(), "Role expression expected in Object Roles Subsumption axiom"); tbox.getRM(R).addRoleParent(Sub, R); } @Override public void visit(AxiomDRoleSubsumption axiom) { ensureNames(axiom.getRole()); ensureNames(axiom.getSubRole()); Role R = getRole(axiom.getRole(), "Role expression expected in Data Roles Subsumption axiom"); Role S = getRole(axiom.getSubRole(), "Role expression expected in Data Roles Subsumption axiom"); tbox.getDRM().addRoleParentProper(S, R); } @Override public void visit(AxiomORoleDomain axiom) { ensureNames(axiom.getRole()); ensureNames(axiom.getDomain()); Role R = getRole(axiom.getRole(), "Role expression expected in Object Role Domain axiom"); DLTree C = axiom.getDomain().accept(expressionTranslator); if (R.isTop()) { // add GCI tbox.addSubsumeAxiom(DLTreeFactory.createTop(), C); } else if (!R.isBottom()) { // nothing to do for bottom R.setDomain(C); } } @Override public void visit(AxiomDRoleDomain axiom) { ensureNames(axiom.getRole()); ensureNames(axiom.getDomain()); Role R = getRole(axiom.getRole(), "Role expression expected in Data Role Domain axiom"); DLTree C = axiom.getDomain().accept(expressionTranslator); if (R.isTop()) { // add GCI tbox.addSubsumeAxiom(DLTreeFactory.createTop(), C); } else if (!R.isBottom()) { // nothing to do for bottom R.setDomain(C); } } @Override public void visit(AxiomORoleRange axiom) { ensureNames(axiom.getRole()); ensureNames(axiom.getRange()); Role R = getRole(axiom.getRole(), "Role expression expected in Object Role Range axiom"); DLTree C = axiom.getRange().accept(expressionTranslator); if (R.isTop()) { // add GCI tbox.addSubsumeAxiom(DLTreeFactory.createTop(), C); } else if (!R.isBottom()) { // nothing to do for bottom R.setRange(C); } } @Override public void visit(AxiomDRoleRange axiom) { ensureNames(axiom.getRole()); ensureNames(axiom.getRange()); getRole(axiom.getRole(), "Role expression expected in Data Role Range axiom").setRange( axiom.getRange().accept(expressionTranslator)); } @Override public void visit(AxiomRoleTransitive axiom) { ensureNames(axiom.getRole()); Role role = getRole(axiom.getRole(), "Role expression expected in Role Transitivity axiom"); if (!role.isTop() && !role.isBottom()) { role.setTransitive(true); } } @Override public void visit(AxiomRoleReflexive axiom) { ensureNames(axiom.getRole()); Role role = getRole(axiom.getRole(), "Role expression expected in Role Reflexivity axiom"); if (role.isBottom()) { throw new InconsistentOntologyException(); } if (!role.isTop()) { role.setReflexive(true); } } @Override public void visit(AxiomRoleIrreflexive axiom) { ensureNames(axiom.getRole()); Role R = getRole(axiom.getRole(), "Role expression expected in Role Irreflexivity axiom"); if (R.isTop()) { throw new InconsistentOntologyException(); } if (!R.isBottom()) { R.setDomain(DLTreeFactory.createSNFNot(DLTreeFactory .createSNFSelf(axiom.getRole().accept(expressionTranslator)))); R.setDomain(DLTreeFactory.createSNFNot(DLTreeFactory.buildTree( new Lexeme(Token.SELF), axiom.getRole().accept(expressionTranslator)))); R.setIrreflexive(true); } } @Override public void visit(AxiomRoleSymmetric axiom) { ensureNames(axiom.getRole()); Role R = getRole(axiom.getRole(), "Role expression expected in Role Symmetry axiom"); if (!R.isTop() && !R.isBottom()) { R.setSymmetric(true); tbox.getORM().addRoleParentProper(R, R.inverse()); } } @Override public void visit(AxiomRoleAsymmetric axiom) { ensureNames(axiom.getRole()); Role R = getRole(axiom.getRole(), "Role expression expected in Role Asymmetry axiom"); if (R.isTop()) { throw new InconsistentOntologyException(); } if (!R.isBottom()) { R.setAsymmetric(true); tbox.getORM().addDisjointRoles(R, R.inverse()); } } @Override public void visit(AxiomORoleFunctional axiom) { ensureNames(axiom.getRole()); Role role = getRole(axiom.getRole(), "Role expression expected in Object Role Functionality axiom"); if (role.isTop()) { throw new InconsistentOntologyException(); } if (!role.isBottom()) { role.setFunctional(); } } @Override public void visit(AxiomDRoleFunctional axiom) { ensureNames(axiom.getRole()); Role role = getRole(axiom.getRole(), "Role expression expected in Data Role Functionality axiom"); if (role.isTop()) { throw new InconsistentOntologyException(); } if (!role.isBottom()) { role.setFunctional(); } } @Override public void visit(AxiomRoleInverseFunctional axiom) { ensureNames(axiom.getRole()); Role role = getRole(axiom.getRole(), "Role expression expected in Role Inverse Functionality axiom"); if (role.isTop()) { throw new InconsistentOntologyException(); } if (!role.isBottom()) { role.inverse().setFunctional(); } } // concept/individual axioms @Override public void visit(AxiomConceptInclusion axiom) { ensureNames(axiom.getSubConcept()); ensureNames(axiom.getSupConcept()); DLTree C = axiom.getSubConcept().accept(expressionTranslator); DLTree D = axiom.getSupConcept().accept(expressionTranslator); tbox.addSubsumeAxiom(C, D); } @Override public void visit(AxiomInstanceOf axiom) { ensureNames(axiom.getIndividual()); ensureNames(axiom.getC()); getIndividual(axiom.getIndividual(), "Individual expected in Instance axiom"); DLTree I = axiom.getIndividual().accept(expressionTranslator); DLTree C = axiom.getC().accept(expressionTranslator); tbox.addSubsumeAxiom(I, C); } @Override public void visit(AxiomRelatedTo axiom) { ensureNames(axiom.getIndividual()); ensureNames(axiom.getRelation()); ensureNames(axiom.getRelatedIndividual()); Role R = getRole(axiom.getRelation(), "Role expression expected in Related To axiom"); if (R.isBottom()) { throw new InconsistentOntologyException(); } if (!R.isTop()) { Individual I = getIndividual(axiom.getIndividual(), "Individual expected in Related To axiom"); Individual J = getIndividual(axiom.getRelatedIndividual(), "Individual expected in Related To axiom"); tbox.registerIndividualRelation(I, R, J); } } @Override public void visit(AxiomRelatedToNot axiom) { ensureNames(axiom.getIndividual()); ensureNames(axiom.getRelation()); ensureNames(axiom.getRelatedIndividual()); Role R = getRole(axiom.getRelation(), "Role expression expected in Related To Not axiom"); if (R.isTop()) { // inconsistent ontology throw new InconsistentOntologyException(); } if (!R.isBottom()) { // make sure everything is consistent getIndividual(axiom.getIndividual(), "Individual expected in Related To Not axiom"); getIndividual(axiom.getRelatedIndividual(), "Individual expected in Related To Not axiom"); // make an axiom i:AR.\neg{j} tbox.addSubsumeAxiom( axiom.getIndividual().accept(expressionTranslator), DLTreeFactory.createSNFForall( axiom.getRelation().accept(expressionTranslator), DLTreeFactory.createSNFNot(axiom .getRelatedIndividual().accept( expressionTranslator)))); } } @Override public void visit(AxiomValueOf axiom) { ensureNames(axiom.getIndividual()); ensureNames(axiom.getAttribute()); getIndividual(axiom.getIndividual(), "Individual expected in Value Of axiom"); Role R = getRole(axiom.getAttribute(), "Role expression expected in Value Of axiom"); if (R.isBottom()) { throw new InconsistentOntologyException(); } if (!R.isTop()) { // nothing to do for universal role // make an axiom i:EA.V tbox.addSubsumeAxiom( axiom.getIndividual().accept(expressionTranslator), DLTreeFactory.createSNFExists( axiom.getAttribute().accept(expressionTranslator), axiom.getValue().accept(expressionTranslator))); } } @Override public void visit(AxiomValueOfNot axiom) { ensureNames(axiom.getIndividual()); ensureNames(axiom.getAttribute()); getIndividual(axiom.getIndividual(), "Individual expected in Value Of Not axiom"); Role R = getRole(axiom.getAttribute(), "Role expression expected in Value Of Not axiom"); if (R.isTop()) { throw new InconsistentOntologyException(); } if (!R.isBottom()) { // make an axiom i:AA.\neg V tbox.addSubsumeAxiom( axiom.getIndividual().accept(expressionTranslator), DLTreeFactory.createSNFForall( axiom.getAttribute().accept(expressionTranslator), DLTreeFactory.createSNFNot(axiom.getValue().accept( expressionTranslator)))); } } /** * @param KB * KB */ public OntologyLoader(TBox KB) { tbox = KB; expressionTranslator = new ExpressionTranslator(KB); } /** * load ontology to a given KB * * @param ontology * ontology */ @PortedFrom(file = "tOntologyLoader.h", name = "visitOntology") public void visitOntology(Ontology ontology) { for (AxiomInterface p : ontology.getAxioms()) { if (p.isUsed()) { p.accept(this); } } for (TSplitVar q : ontology.getSplits().getEntries()) { fillSplit(q); } tbox.setSplitVars(ontology.getSplits()); tbox.finishLoading(); } }