/* Copyright 2008, 2009, 2010 by the Oxford University Computing Laboratory
This file is part of HermiT.
HermiT 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 3 of the License, or
(at your option) any later version.
HermiT 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 HermiT. If not, see <http://www.gnu.org/licenses/>.
*/
package org.semanticweb.HermiT.structural;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.semanticweb.HermiT.Configuration;
import org.semanticweb.HermiT.Prefixes;
import org.semanticweb.HermiT.datatypes.DatatypeRegistry;
import org.semanticweb.HermiT.datatypes.UnsupportedDatatypeException;
import org.semanticweb.HermiT.model.AnnotatedEquality;
import org.semanticweb.HermiT.model.AtLeastConcept;
import org.semanticweb.HermiT.model.AtLeastDataRange;
import org.semanticweb.HermiT.model.Atom;
import org.semanticweb.HermiT.model.AtomicConcept;
import org.semanticweb.HermiT.model.AtomicRole;
import org.semanticweb.HermiT.model.Constant;
import org.semanticweb.HermiT.model.ConstantEnumeration;
import org.semanticweb.HermiT.model.DLClause;
import org.semanticweb.HermiT.model.DLOntology;
import org.semanticweb.HermiT.model.DLPredicate;
import org.semanticweb.HermiT.model.DatatypeRestriction;
import org.semanticweb.HermiT.model.DescriptionGraph;
import org.semanticweb.HermiT.model.Equality;
import org.semanticweb.HermiT.model.Individual;
import org.semanticweb.HermiT.model.Inequality;
import org.semanticweb.HermiT.model.InternalDatatype;
import org.semanticweb.HermiT.model.LiteralConcept;
import org.semanticweb.HermiT.model.LiteralDataRange;
import org.semanticweb.HermiT.model.NodeIDLessEqualThan;
import org.semanticweb.HermiT.model.NodeIDsAscendingOrEqual;
import org.semanticweb.HermiT.model.Role;
import org.semanticweb.HermiT.model.Term;
import org.semanticweb.HermiT.model.Variable;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassAssertionAxiom;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLClassExpressionVisitor;
import org.semanticweb.owlapi.model.OWLDataAllValuesFrom;
import org.semanticweb.owlapi.model.OWLDataComplementOf;
import org.semanticweb.owlapi.model.OWLDataExactCardinality;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLDataHasValue;
import org.semanticweb.owlapi.model.OWLDataIntersectionOf;
import org.semanticweb.owlapi.model.OWLDataMaxCardinality;
import org.semanticweb.owlapi.model.OWLDataMinCardinality;
import org.semanticweb.owlapi.model.OWLDataOneOf;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLDataPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLDataPropertyExpression;
import org.semanticweb.owlapi.model.OWLDataRange;
import org.semanticweb.owlapi.model.OWLDataSomeValuesFrom;
import org.semanticweb.owlapi.model.OWLDataUnionOf;
import org.semanticweb.owlapi.model.OWLDataVisitor;
import org.semanticweb.owlapi.model.OWLDataVisitorEx;
import org.semanticweb.owlapi.model.OWLDatatype;
import org.semanticweb.owlapi.model.OWLDatatypeRestriction;
import org.semanticweb.owlapi.model.OWLDifferentIndividualsAxiom;
import org.semanticweb.owlapi.model.OWLFacetRestriction;
import org.semanticweb.owlapi.model.OWLHasKeyAxiom;
import org.semanticweb.owlapi.model.OWLIndividual;
import org.semanticweb.owlapi.model.OWLIndividualAxiom;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLNegativeDataPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLNegativeObjectPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLObjectAllValuesFrom;
import org.semanticweb.owlapi.model.OWLObjectComplementOf;
import org.semanticweb.owlapi.model.OWLObjectExactCardinality;
import org.semanticweb.owlapi.model.OWLObjectHasSelf;
import org.semanticweb.owlapi.model.OWLObjectHasValue;
import org.semanticweb.owlapi.model.OWLObjectIntersectionOf;
import org.semanticweb.owlapi.model.OWLObjectInverseOf;
import org.semanticweb.owlapi.model.OWLObjectMaxCardinality;
import org.semanticweb.owlapi.model.OWLObjectMinCardinality;
import org.semanticweb.owlapi.model.OWLObjectOneOf;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLObjectPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLObjectPropertyExpression;
import org.semanticweb.owlapi.model.OWLObjectSomeValuesFrom;
import org.semanticweb.owlapi.model.OWLObjectUnionOf;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLSameIndividualAxiom;
import org.semanticweb.owlapi.model.SWRLAtom;
import org.semanticweb.owlapi.model.SWRLBuiltInAtom;
import org.semanticweb.owlapi.model.SWRLClassAtom;
import org.semanticweb.owlapi.model.SWRLDArgument;
import org.semanticweb.owlapi.model.SWRLDataPropertyAtom;
import org.semanticweb.owlapi.model.SWRLDataRangeAtom;
import org.semanticweb.owlapi.model.SWRLDifferentIndividualsAtom;
import org.semanticweb.owlapi.model.SWRLIArgument;
import org.semanticweb.owlapi.model.SWRLIndividualArgument;
import org.semanticweb.owlapi.model.SWRLLiteralArgument;
import org.semanticweb.owlapi.model.SWRLObjectPropertyAtom;
import org.semanticweb.owlapi.model.SWRLObjectVisitorEx;
import org.semanticweb.owlapi.model.SWRLRule;
import org.semanticweb.owlapi.model.SWRLSameIndividualAtom;
import org.semanticweb.owlapi.model.SWRLVariable;
import org.semanticweb.owlapi.util.OWLAxiomVisitorAdapter;
public class OWLClausification {
protected static final Variable X=Variable.create("X");
protected static final Variable Y=Variable.create("Y");
protected static final Variable Z=Variable.create("Z");
protected final Configuration m_configuration;
public OWLClausification(Configuration configuration) {
m_configuration=configuration;
}
public Object[] preprocessAndClausify(OWLOntology rootOntology,Collection<DescriptionGraph> descriptionGraphs) {
OWLDataFactory factory=rootOntology.getOWLOntologyManager().getOWLDataFactory();
String ontologyIRI=rootOntology.getOntologyID().getDefaultDocumentIRI()==null ? "urn:hermit:kb" : rootOntology.getOntologyID().getDefaultDocumentIRI().toString();
Collection<OWLOntology> importClosure=rootOntology.getImportsClosure();
OWLAxioms axioms=new OWLAxioms();
OWLNormalization normalization=new OWLNormalization(factory,axioms,0);
for (OWLOntology ontology : importClosure)
normalization.processOntology(ontology);
BuiltInPropertyManager builtInPropertyManager=new BuiltInPropertyManager(factory);
builtInPropertyManager.axiomatizeBuiltInPropertiesAsNeeded(axioms);
ObjectPropertyInclusionManager objectPropertyInclusionManager=new ObjectPropertyInclusionManager(axioms);
// now object property inclusion manager added all non-simple properties to axioms.m_complexObjectPropertyExpressions
// now that we know which roles are non-simple, we can decide which negative object property assertions have to be
// expressed as concept assertions so that transitivity rewriting applies properly.
objectPropertyInclusionManager.rewriteNegativeObjectPropertyAssertions(factory,axioms,normalization.m_definitions.size());
objectPropertyInclusionManager.rewriteAxioms(factory,axioms,0);
if (descriptionGraphs==null)
descriptionGraphs=Collections.emptySet();
OWLAxiomsExpressivity axiomsExpressivity=new OWLAxiomsExpressivity(axioms);
DLOntology dlOntology=clausify(factory,ontologyIRI,axioms,axiomsExpressivity,descriptionGraphs);
return new Object[] { objectPropertyInclusionManager,dlOntology };
}
public DLOntology clausify(OWLDataFactory factory,String ontologyIRI,OWLAxioms axioms,OWLAxiomsExpressivity axiomsExpressivity,Collection<DescriptionGraph> descriptionGraphs) {
Set<DLClause> dlClauses=new LinkedHashSet<DLClause>();
Set<Atom> positiveFacts=new HashSet<Atom>();
Set<Atom> negativeFacts=new HashSet<Atom>();
Set<DatatypeRestriction> allUnknownDatatypeRestrictions=new HashSet<DatatypeRestriction>();
for (OWLObjectPropertyExpression[] inclusion : axioms.m_simpleObjectPropertyInclusions) {
Atom subRoleAtom=getRoleAtom(inclusion[0],X,Y);
Atom superRoleAtom=getRoleAtom(inclusion[1],X,Y);
DLClause dlClause=DLClause.create(new Atom[] { superRoleAtom },new Atom[] { subRoleAtom });
dlClauses.add(dlClause);
}
for (OWLDataPropertyExpression[] inclusion : axioms.m_dataPropertyInclusions) {
Atom subProp=getRoleAtom(inclusion[0],X,Y);
Atom superProp=getRoleAtom(inclusion[1],X,Y);
DLClause dlClause=DLClause.create(new Atom[] { superProp },new Atom[] { subProp });
dlClauses.add(dlClause);
}
for (OWLObjectPropertyExpression objectPropertyExpression : axioms.m_asymmetricObjectProperties) {
Atom roleAtom=getRoleAtom(objectPropertyExpression,X,Y);
Atom inverseRoleAtom=getRoleAtom(objectPropertyExpression,Y,X);
DLClause dlClause=DLClause.create(new Atom[] {},new Atom[] { roleAtom,inverseRoleAtom });
dlClauses.add(dlClause);
}
for (OWLObjectPropertyExpression objectPropertyExpression : axioms.m_reflexiveObjectProperties) {
Atom roleAtom=getRoleAtom(objectPropertyExpression,X,X);
Atom bodyAtom=Atom.create(AtomicConcept.THING,X);
DLClause dlClause=DLClause.create(new Atom[] { roleAtom },new Atom[] { bodyAtom });
dlClauses.add(dlClause);
}
for (OWLObjectPropertyExpression objectPropertyExpression : axioms.m_irreflexiveObjectProperties) {
Atom roleAtom=getRoleAtom(objectPropertyExpression,X,X);
DLClause dlClause=DLClause.create(new Atom[] {},new Atom[] { roleAtom });
dlClauses.add(dlClause);
}
for (OWLObjectPropertyExpression[] properties : axioms.m_disjointObjectProperties)
for (int i=0;i<properties.length;i++)
for (int j=i+1;j<properties.length;j++) {
Atom atom_i=getRoleAtom(properties[i],X,Y);
Atom atom_j=getRoleAtom(properties[j],X,Y);
DLClause dlClause=DLClause.create(new Atom[] {},new Atom[] { atom_i,atom_j });
dlClauses.add(dlClause);
}
if (axioms.m_dataPropertyInclusions.contains(factory.getOWLDataProperty(IRI.create(AtomicRole.BOTTOM_DATA_ROLE.getIRI())))) {
Atom bodyAtom=Atom.create(AtomicRole.BOTTOM_DATA_ROLE,X,Y);
dlClauses.add(DLClause.create(new Atom[] {},new Atom[] { bodyAtom }));
}
for (OWLDataPropertyExpression[] properties : axioms.m_disjointDataProperties)
for (int i=0;i<properties.length;i++)
for (int j=i+1;j<properties.length;j++) {
Atom atom_i=getRoleAtom(properties[i],X,Y);
Atom atom_j=getRoleAtom(properties[j],X,Z);
Atom atom_ij=Atom.create(Inequality.create(),Y,Z);
DLClause dlClause=DLClause.create(new Atom[] { atom_ij },new Atom[] { atom_i,atom_j });
dlClauses.add(dlClause);
}
DataRangeConverter dataRangeConverter=new DataRangeConverter(m_configuration.warningMonitor,axioms.m_definedDatatypesIRIs,allUnknownDatatypeRestrictions,m_configuration.ignoreUnsupportedDatatypes);
NormalizedAxiomClausifier clausifier=new NormalizedAxiomClausifier(dataRangeConverter,positiveFacts,factory);
for (OWLClassExpression[] inclusion : axioms.m_conceptInclusions) {
for (OWLClassExpression description : inclusion)
description.accept(clausifier);
DLClause dlClause=clausifier.getDLClause();
dlClauses.add(dlClause.getSafeVersion(AtomicConcept.THING));
}
NormalizedDataRangeAxiomClausifier normalizedDataRangeAxiomClausifier=new NormalizedDataRangeAxiomClausifier(dataRangeConverter,factory,axioms.m_definedDatatypesIRIs);
for (OWLDataRange[] inclusion : axioms.m_dataRangeInclusions) {
for (OWLDataRange description : inclusion)
description.accept(normalizedDataRangeAxiomClausifier);
DLClause dlClause=normalizedDataRangeAxiomClausifier.getDLClause();
dlClauses.add(dlClause.getSafeVersion(InternalDatatype.RDFS_LITERAL));
}
for (OWLHasKeyAxiom hasKey : axioms.m_hasKeys)
dlClauses.add(clausifyKey(hasKey));
FactClausifier factClausifier=new FactClausifier(dataRangeConverter,positiveFacts,negativeFacts);
for (OWLIndividualAxiom fact : axioms.m_facts)
fact.accept(factClausifier);
for (DescriptionGraph descriptionGraph : descriptionGraphs)
descriptionGraph.produceStartDLClauses(dlClauses);
Set<AtomicConcept> atomicConcepts=new HashSet<AtomicConcept>();
Set<AtomicRole> atomicObjectRoles=new HashSet<AtomicRole>();
Set<Role> complexObjectRoles=new HashSet<Role>();
Set<AtomicRole> atomicDataRoles=new HashSet<AtomicRole>();
for (OWLClass owlClass : axioms.m_classes)
atomicConcepts.add(AtomicConcept.create(owlClass.getIRI().toString()));
Set<Individual> individuals=new HashSet<Individual>();
for (OWLNamedIndividual owlIndividual : axioms.m_namedIndividuals) {
Individual individual=Individual.create(owlIndividual.getIRI().toString());
individuals.add(individual);
// all named individuals are tagged with a concept, so that keys/rules are
// only applied to them
if (!axioms.m_hasKeys.isEmpty() || !axioms.m_rules.isEmpty())
positiveFacts.add(Atom.create(AtomicConcept.INTERNAL_NAMED,individual));
}
for (OWLObjectProperty objectProperty : axioms.m_objectProperties)
atomicObjectRoles.add(AtomicRole.create(objectProperty.getIRI().toString()));
for (OWLObjectPropertyExpression objectPropertyExpression : axioms.m_complexObjectPropertyExpressions)
complexObjectRoles.add(getRole(objectPropertyExpression));
for (OWLDataProperty dataProperty : axioms.m_dataProperties)
atomicDataRoles.add(AtomicRole.create(dataProperty.getIRI().toString()));
// Clausify SWRL rules
if (!axioms.m_rules.isEmpty())
new NormalizedRuleClausifier(axioms.m_objectPropertiesOccurringInOWLAxioms,descriptionGraphs,dataRangeConverter,dlClauses).processRules(axioms.m_rules);
// Create the DL ontology
return new DLOntology(ontologyIRI,dlClauses,positiveFacts,negativeFacts,atomicConcepts,atomicObjectRoles,complexObjectRoles,atomicDataRoles,allUnknownDatatypeRestrictions,axioms.m_definedDatatypesIRIs,individuals,axiomsExpressivity.m_hasInverseRoles,axiomsExpressivity.m_hasAtMostRestrictions,axiomsExpressivity.m_hasNominals,axiomsExpressivity.m_hasDatatypes);
}
protected DLClause clausifyKey(OWLHasKeyAxiom object) {
List<Atom> headAtoms=new ArrayList<Atom>();
List<Atom> bodyAtoms=new ArrayList<Atom>();
// we have two named individuals (corresponding to X1 and X2) that
// might have to be equated
Variable X2=Variable.create("X2");
Variable X1=Variable.create("X1");
headAtoms.add(Atom.create(Equality.INSTANCE,X1,X2));
// keys only work on datatypes and named individuals
bodyAtoms.add(Atom.create(AtomicConcept.INTERNAL_NAMED,X1));
bodyAtoms.add(Atom.create(AtomicConcept.INTERNAL_NAMED,X2));
// the concept expression of a hasKey statement is either a concept
// name or a negated concept name after normalization
OWLClassExpression description=object.getClassExpression();
if (description instanceof OWLClass) {
OWLClass owlClass=(OWLClass)description;
if (!owlClass.isOWLThing()) {
bodyAtoms.add(Atom.create(AtomicConcept.create(owlClass.getIRI().toString()),X1));
bodyAtoms.add(Atom.create(AtomicConcept.create(owlClass.getIRI().toString()),X2));
}
}
else if (description instanceof OWLObjectComplementOf) {
OWLClassExpression internal=((OWLObjectComplementOf)description).getOperand();
if (internal instanceof OWLClass) {
OWLClass owlClass=(OWLClass)internal;
headAtoms.add(Atom.create(AtomicConcept.create(owlClass.getIRI().toString()),X1));
headAtoms.add(Atom.create(AtomicConcept.create(owlClass.getIRI().toString()),X2));
}
else
throw new IllegalStateException("Internal error: invalid normal form.");
}
else
throw new IllegalStateException("Internal error: invalid normal form.");
int yIndex=1;
// object properties always go to the body
for (OWLObjectPropertyExpression p : object.getObjectPropertyExpressions()) {
Variable y;
y=Variable.create("Y"+yIndex);
yIndex++;
bodyAtoms.add(getRoleAtom(p,X1,y));
bodyAtoms.add(getRoleAtom(p,X2,y));
// also the key criteria are named in case of object properties
bodyAtoms.add(Atom.create(AtomicConcept.INTERNAL_NAMED,y));
}
// data properties go to the body, but with different variables
// the head gets an atom asserting inequality between that data values
for (OWLDataPropertyExpression d : object.getDataPropertyExpressions()) {
Variable y;
y=Variable.create("Y"+yIndex);
yIndex++;
bodyAtoms.add(getRoleAtom(d,X1,y));
Variable y2;
y2=Variable.create("Y"+yIndex);
yIndex++;
bodyAtoms.add(getRoleAtom(d,X2,y2));
headAtoms.add(Atom.create(Inequality.INSTANCE,y,y2));
}
Atom[] hAtoms=new Atom[headAtoms.size()];
headAtoms.toArray(hAtoms);
Atom[] bAtoms=new Atom[bodyAtoms.size()];
bodyAtoms.toArray(bAtoms);
DLClause clause=DLClause.create(hAtoms,bAtoms);
return clause;
}
protected static LiteralConcept getLiteralConcept(OWLClassExpression description) {
if (description instanceof OWLClass) {
return AtomicConcept.create(((OWLClass)description).getIRI().toString());
}
else if (description instanceof OWLObjectComplementOf) {
OWLClassExpression internal=((OWLObjectComplementOf)description).getOperand();
if (!(internal instanceof OWLClass))
throw new IllegalStateException("Internal error: invalid normal form.");
return AtomicConcept.create(((OWLClass)internal).getIRI().toString()).getNegation();
}
else
throw new IllegalStateException("Internal error: invalid normal form.");
}
protected static Role getRole(OWLObjectPropertyExpression objectPropertyExpression) {
objectPropertyExpression=objectPropertyExpression.getSimplified();
if (objectPropertyExpression instanceof OWLObjectProperty)
return AtomicRole.create(((OWLObjectProperty)objectPropertyExpression).getIRI().toString());
else if (objectPropertyExpression instanceof OWLObjectInverseOf) {
OWLObjectPropertyExpression internal=((OWLObjectInverseOf)objectPropertyExpression).getInverse();
if (!(internal instanceof OWLObjectProperty))
throw new IllegalStateException("Internal error: invalid normal form.");
return AtomicRole.create(((OWLObjectProperty)internal).getIRI().toString()).getInverse();
}
else
throw new IllegalStateException("Internal error: invalid normal form.");
}
protected static AtomicRole getAtomicRole(OWLDataPropertyExpression dataPropertyExpression) {
return AtomicRole.create(((OWLDataProperty)dataPropertyExpression).getIRI().toString());
}
protected static Atom getRoleAtom(OWLObjectPropertyExpression objectProperty,Term first,Term second) {
objectProperty=objectProperty.getSimplified();
if (!objectProperty.isAnonymous()) {
AtomicRole role=AtomicRole.create(objectProperty.asOWLObjectProperty().getIRI().toString());
return Atom.create(role,first,second);
}
else if (objectProperty.isAnonymous()) {
OWLObjectProperty internalObjectProperty=objectProperty.getNamedProperty();
AtomicRole role=AtomicRole.create(internalObjectProperty.getIRI().toString());
return Atom.create(role,second,first);
}
else
throw new IllegalStateException("Internal error: unsupported type of object property!");
}
protected static Atom getRoleAtom(OWLDataPropertyExpression dataProperty,Term first,Term second) {
if (dataProperty instanceof OWLDataProperty) {
AtomicRole property=AtomicRole.create(((OWLDataProperty)dataProperty).getIRI().toString());
return Atom.create(property,first,second);
}
else
throw new IllegalStateException("Internal error: unsupported type of data property!");
}
protected static Individual getIndividual(OWLIndividual individual) {
if (individual.isAnonymous())
return Individual.createAnonymous(individual.asOWLAnonymousIndividual().getID().toString());
else
return Individual.create(individual.asOWLNamedIndividual().getIRI().toString());
}
protected static class NormalizedAxiomClausifier implements OWLClassExpressionVisitor {
protected final DataRangeConverter m_dataRangeConverter;
protected final List<Atom> m_headAtoms;
protected final List<Atom> m_bodyAtoms;
protected final Set<Atom> m_positiveFacts;
protected final OWLDataFactory m_factory;
protected int m_yIndex;
protected int m_zIndex;
public NormalizedAxiomClausifier(DataRangeConverter dataRangeConverter,Set<Atom> positiveFacts,OWLDataFactory factory) {
m_dataRangeConverter=dataRangeConverter;
m_headAtoms=new ArrayList<Atom>();
m_bodyAtoms=new ArrayList<Atom>();
m_positiveFacts=positiveFacts;
m_factory=factory;
}
protected DLClause getDLClause() {
Atom[] headAtoms=new Atom[m_headAtoms.size()];
m_headAtoms.toArray(headAtoms);
Atom[] bodyAtoms=new Atom[m_bodyAtoms.size()];
m_bodyAtoms.toArray(bodyAtoms);
DLClause dlClause=DLClause.create(headAtoms,bodyAtoms);
m_headAtoms.clear();
m_bodyAtoms.clear();
m_yIndex=0;
m_zIndex=0;
return dlClause;
}
protected void ensureYNotZero() {
if (m_yIndex==0)
m_yIndex++;
}
protected Variable nextY() {
Variable result;
if (m_yIndex==0)
result=Y;
else
result=Variable.create("Y"+m_yIndex);
m_yIndex++;
return result;
}
protected Variable nextZ() {
Variable result;
if (m_zIndex==0)
result=Z;
else
result=Variable.create("Z"+m_zIndex);
m_zIndex++;
return result;
}
protected AtomicConcept getConceptForNominal(OWLIndividual individual) {
AtomicConcept result;
if (individual.isAnonymous()) {
result=AtomicConcept.create("internal:anon#"+individual.asOWLAnonymousIndividual().getID().toString());
}
else {
result=AtomicConcept.create("internal:nom#"+individual.asOWLNamedIndividual().getIRI().toString());
}
m_positiveFacts.add(Atom.create(result,getIndividual(individual)));
return result;
}
// Various types of descriptions
public void visit(OWLClass object) {
m_headAtoms.add(Atom.create(AtomicConcept.create(object.getIRI().toString()),X));
}
public void visit(OWLObjectIntersectionOf object) {
throw new IllegalStateException("Internal error: invalid normal form.");
}
public void visit(OWLObjectUnionOf object) {
throw new IllegalStateException("Internal error: invalid normal form.");
}
public void visit(OWLObjectComplementOf object) {
OWLClassExpression description=object.getOperand();
if (description instanceof OWLObjectHasSelf) {
OWLObjectPropertyExpression objectProperty=((OWLObjectHasSelf)description).getProperty();
Atom roleAtom=getRoleAtom(objectProperty,X,X);
m_bodyAtoms.add(roleAtom);
}
else if (description instanceof OWLObjectOneOf && ((OWLObjectOneOf)description).getIndividuals().size()==1) {
OWLIndividual individual=((OWLObjectOneOf)description).getIndividuals().iterator().next();
m_bodyAtoms.add(Atom.create(getConceptForNominal(individual),X));
}
else if (!(description instanceof OWLClass))
throw new IllegalStateException("Internal error: invalid normal form.");
else
m_bodyAtoms.add(Atom.create(AtomicConcept.create(((OWLClass)description).getIRI().toString()),X));
}
public void visit(OWLObjectOneOf object) {
for (OWLIndividual individual : object.getIndividuals()) {
Variable z=nextZ();
AtomicConcept conceptForNominal=getConceptForNominal(individual);
m_headAtoms.add(Atom.create(Equality.INSTANCE,X,z));
m_bodyAtoms.add(Atom.create(conceptForNominal,z));
}
}
public void visit(OWLObjectSomeValuesFrom object) {
OWLClassExpression filler=object.getFiller();
if (filler instanceof OWLObjectOneOf) {
for (OWLIndividual individual : ((OWLObjectOneOf)filler).getIndividuals()) {
Variable z=nextZ();
m_bodyAtoms.add(Atom.create(getConceptForNominal(individual),z));
m_headAtoms.add(getRoleAtom(object.getProperty(),X,z));
}
}
else {
LiteralConcept toConcept=getLiteralConcept(filler);
Role onRole=getRole(object.getProperty());
AtLeastConcept atLeastConcept=AtLeastConcept.create(1,onRole,toConcept);
if (!atLeastConcept.isAlwaysFalse())
m_headAtoms.add(Atom.create(atLeastConcept,X));
}
}
public void visit(OWLObjectAllValuesFrom object) {
Variable y=nextY();
m_bodyAtoms.add(getRoleAtom(object.getProperty(),X,y));
OWLClassExpression filler=object.getFiller();
if (filler instanceof OWLClass) {
AtomicConcept atomicConcept=AtomicConcept.create(((OWLClass)filler).getIRI().toString());
if (!atomicConcept.isAlwaysFalse())
m_headAtoms.add(Atom.create(atomicConcept,y));
}
else if (filler instanceof OWLObjectOneOf) {
for (OWLIndividual individual : ((OWLObjectOneOf)filler).getIndividuals()) {
Variable zInd=nextZ();
m_bodyAtoms.add(Atom.create(getConceptForNominal(individual),zInd));
m_headAtoms.add(Atom.create(Equality.INSTANCE,y,zInd));
}
}
else if (filler instanceof OWLObjectComplementOf) {
OWLClassExpression operand=((OWLObjectComplementOf)filler).getOperand();
if (operand instanceof OWLClass) {
AtomicConcept internalAtomicConcept=AtomicConcept.create(((OWLClass)operand).getIRI().toString());
if (!internalAtomicConcept.isAlwaysTrue())
m_bodyAtoms.add(Atom.create(internalAtomicConcept,y));
}
else if (operand instanceof OWLObjectOneOf && ((OWLObjectOneOf)operand).getIndividuals().size()==1) {
OWLIndividual individual=((OWLObjectOneOf)operand).getIndividuals().iterator().next();
m_bodyAtoms.add(Atom.create(getConceptForNominal(individual),y));
}
else
throw new IllegalStateException("Internal error: invalid normal form.");
}
else
throw new IllegalStateException("Internal error: invalid normal form.");
}
public void visit(OWLObjectHasValue object) {
throw new IllegalStateException("Internal error: invalid normal form.");
}
public void visit(OWLObjectHasSelf object) {
OWLObjectPropertyExpression objectProperty=object.getProperty();
Atom roleAtom=getRoleAtom(objectProperty,X,X);
m_headAtoms.add(roleAtom);
}
public void visit(OWLObjectMinCardinality object) {
LiteralConcept toConcept=getLiteralConcept(object.getFiller());
Role onRole=getRole(object.getProperty());
AtLeastConcept atLeastConcept=AtLeastConcept.create(object.getCardinality(),onRole,toConcept);
if (!atLeastConcept.isAlwaysFalse())
m_headAtoms.add(Atom.create(atLeastConcept,X));
}
public void visit(OWLObjectMaxCardinality object) {
int cardinality=object.getCardinality();
OWLObjectPropertyExpression onObjectProperty=object.getProperty();
OWLClassExpression filler=object.getFiller();
ensureYNotZero();
boolean isPositive;
AtomicConcept atomicConcept;
if (filler instanceof OWLClass) {
isPositive=true;
atomicConcept=AtomicConcept.create(((OWLClass)filler).getIRI().toString());
if (atomicConcept.isAlwaysTrue())
atomicConcept=null;
}
else if (filler instanceof OWLObjectComplementOf) {
OWLClassExpression internal=((OWLObjectComplementOf)filler).getOperand();
if (!(internal instanceof OWLClass))
throw new IllegalStateException("Internal error: Invalid ontology normal form.");
isPositive=false;
atomicConcept=AtomicConcept.create(((OWLClass)internal).getIRI().toString());
if (atomicConcept.isAlwaysFalse())
atomicConcept=null;
}
else
throw new IllegalStateException("Internal error: Invalid ontology normal form.");
Role onRole=getRole(onObjectProperty);
LiteralConcept toConcept=getLiteralConcept(filler);
AnnotatedEquality annotatedEquality=AnnotatedEquality.create(cardinality,onRole,toConcept);
Variable[] yVars=new Variable[cardinality+1];
for (int i=0;i<yVars.length;i++) {
yVars[i]=nextY();
m_bodyAtoms.add(getRoleAtom(onObjectProperty,X,yVars[i]));
if (atomicConcept!=null) {
Atom atom=Atom.create(atomicConcept,yVars[i]);
if (isPositive)
m_bodyAtoms.add(atom);
else
m_headAtoms.add(atom);
}
}
// Node ID comparisons are not needed in case of functionality axioms,
// as the effect of these is simulated by the way in which the rules are applied.
if (yVars.length>2) {
for (int i=0;i<yVars.length-1;i++)
m_bodyAtoms.add(Atom.create(NodeIDLessEqualThan.INSTANCE,yVars[i],yVars[i+1]));
m_bodyAtoms.add(Atom.create(NodeIDsAscendingOrEqual.create(yVars.length),yVars));
}
for (int i=0;i<yVars.length;i++)
for (int j=i+1;j<yVars.length;j++)
m_headAtoms.add(Atom.create(annotatedEquality,yVars[i],yVars[j],X));
}
public void visit(OWLObjectExactCardinality object) {
throw new IllegalStateException("Internal error: invalid normal form.");
}
public void visit(OWLDataSomeValuesFrom object) {
if (!object.getProperty().isOWLBottomDataProperty()) {
AtomicRole atomicRole=getAtomicRole(object.getProperty());
LiteralDataRange literalRange=m_dataRangeConverter.convertDataRange(object.getFiller());
AtLeastDataRange atLeastDataRange=AtLeastDataRange.create(1,atomicRole,literalRange);
if (!atLeastDataRange.isAlwaysFalse())
m_headAtoms.add(Atom.create(atLeastDataRange,X));
}
}
public void visit(OWLDataAllValuesFrom object) {
LiteralDataRange literalRange=m_dataRangeConverter.convertDataRange(object.getFiller());
if (object.getProperty().isOWLTopDataProperty()) {
if (literalRange.isAlwaysFalse())
return; // bottom
}
Variable y=nextY();
m_bodyAtoms.add(getRoleAtom(object.getProperty(),X,y));
if (literalRange.isNegatedInternalDatatype()) {
InternalDatatype negatedRange=(InternalDatatype)literalRange.getNegation();
if (!negatedRange.isAlwaysTrue())
m_bodyAtoms.add(Atom.create(negatedRange,y));
}
else {
if (!literalRange.isAlwaysFalse())
m_headAtoms.add(Atom.create((DLPredicate)literalRange,y));
}
}
public void visit(OWLDataHasValue object) {
throw new IllegalStateException("Internal error: Invalid normal form.");
}
public void visit(OWLDataMinCardinality object) {
if (!object.getProperty().isOWLBottomDataProperty() || object.getCardinality()==0) {
AtomicRole atomicRole=getAtomicRole(object.getProperty());
LiteralDataRange literalRange=m_dataRangeConverter.convertDataRange(object.getFiller());
AtLeastDataRange atLeast=AtLeastDataRange.create(object.getCardinality(),atomicRole,literalRange);
if (!atLeast.isAlwaysFalse())
m_headAtoms.add(Atom.create(atLeast,X));
}
}
public void visit(OWLDataMaxCardinality object) {
int number=object.getCardinality();
LiteralDataRange negatedDataRange=m_dataRangeConverter.convertDataRange(object.getFiller()).getNegation();
ensureYNotZero();
Variable[] yVars=new Variable[number+1];
for (int i=0;i<yVars.length;i++) {
yVars[i]=nextY();
m_bodyAtoms.add(getRoleAtom(object.getProperty(),X,yVars[i]));
if (negatedDataRange.isNegatedInternalDatatype()) {
InternalDatatype negated=(InternalDatatype)negatedDataRange.getNegation();
if (!negated.isAlwaysTrue())
m_bodyAtoms.add(Atom.create(negated,yVars[i]));
}
else {
if (!negatedDataRange.isAlwaysFalse())
m_headAtoms.add(Atom.create((DLPredicate)negatedDataRange,yVars[i]));
}
}
for (int i=0;i<yVars.length;i++)
for (int j=i+1;j<yVars.length;j++)
m_headAtoms.add(Atom.create(Equality.INSTANCE,yVars[i],yVars[j]));
}
public void visit(OWLDataExactCardinality object) {
throw new IllegalStateException("Internal error: invalid normal form.");
}
}
protected static class NormalizedDataRangeAxiomClausifier implements OWLDataVisitor {
protected final DataRangeConverter m_dataRangeConverter;
protected final Set<String> m_definedDatatypeIRIs;
protected final List<Atom> m_headAtoms;
protected final List<Atom> m_bodyAtoms;
protected final OWLDataFactory m_factory;
protected int m_yIndex;
public NormalizedDataRangeAxiomClausifier(DataRangeConverter dataRangeConverter,OWLDataFactory factory,Set<String> definedDatatypeIRIs) {
m_dataRangeConverter=dataRangeConverter;
m_definedDatatypeIRIs=definedDatatypeIRIs;
m_headAtoms=new ArrayList<Atom>();
m_bodyAtoms=new ArrayList<Atom>();
m_factory=factory;
}
protected DLClause getDLClause() {
Atom[] headAtoms=new Atom[m_headAtoms.size()];
m_headAtoms.toArray(headAtoms);
Atom[] bodyAtoms=new Atom[m_bodyAtoms.size()];
m_bodyAtoms.toArray(bodyAtoms);
DLClause dlClause=DLClause.create(headAtoms,bodyAtoms);
m_headAtoms.clear();
m_bodyAtoms.clear();
m_yIndex=0;
return dlClause;
}
protected void ensureYNotZero() {
if (m_yIndex==0)
m_yIndex++;
}
protected Variable nextY() {
Variable result;
if (m_yIndex==0)
result=Y;
else
result=Variable.create("Y"+m_yIndex);
m_yIndex++;
return result;
}
// Various types of descriptions
public void visit(OWLDatatype dt) {
LiteralDataRange literalRange=m_dataRangeConverter.convertDataRange(dt);
m_headAtoms.add(Atom.create((DLPredicate)literalRange,X));
}
public void visit(OWLDataIntersectionOf dr) {
throw new IllegalStateException("Internal error: invalid normal form.");
}
public void visit(OWLDataUnionOf dr) {
throw new IllegalStateException("Internal error: invalid normal form.");
}
public void visit(OWLDataComplementOf dr) {
OWLDataRange description=dr.getDataRange();
if (description.isDatatype() && (Prefixes.isInternalIRI(description.asOWLDatatype().getIRI().toString()) || m_definedDatatypeIRIs.contains(description.asOWLDatatype()))) {
m_bodyAtoms.add(Atom.create(InternalDatatype.create(description.asOWLDatatype().getIRI().toString()),X));
}
else {
LiteralDataRange literalRange=m_dataRangeConverter.convertDataRange(dr);
if (literalRange.isNegatedInternalDatatype()) {
InternalDatatype negatedDatatype=(InternalDatatype)literalRange.getNegation();
if (!negatedDatatype.isAlwaysTrue())
m_bodyAtoms.add(Atom.create(negatedDatatype,X));
}
else {
if (!literalRange.isAlwaysFalse())
m_headAtoms.add(Atom.create((DLPredicate)literalRange,X));
}
}
}
public void visit(OWLDataOneOf object) {
LiteralDataRange literalRange=m_dataRangeConverter.convertDataRange(object);
m_headAtoms.add(Atom.create((DLPredicate)literalRange,X));
}
public void visit(OWLFacetRestriction node) {
throw new IllegalStateException("Internal error: Invalid normal form. ");
}
public void visit(OWLDatatypeRestriction node) {
LiteralDataRange literalRange=m_dataRangeConverter.convertDataRange(node);
m_headAtoms.add(Atom.create((DLPredicate)literalRange,X));
}
public void visit(OWLLiteral node) {
throw new IllegalStateException("Internal error: Invalid normal form. ");
}
}
protected static class DataRangeConverter implements OWLDataVisitorEx<Object> {
protected final Configuration.WarningMonitor m_warningMonitor;
protected final boolean m_ignoreUnsupportedDatatypes;
protected final Set<String> m_definedDatatypeIRIs; // contains custom datatypes from DatatypeDefinition axioms
protected final Set<DatatypeRestriction> m_allUnknownDatatypeRestrictions;
public DataRangeConverter(Configuration.WarningMonitor warningMonitor,Set<String> definedDatatypeIRIs,Set<DatatypeRestriction> allUnknownDatatypeRestrictions,boolean ignoreUnsupportedDatatypes) {
m_warningMonitor=warningMonitor;
m_definedDatatypeIRIs=definedDatatypeIRIs;
m_ignoreUnsupportedDatatypes=ignoreUnsupportedDatatypes;
m_allUnknownDatatypeRestrictions=allUnknownDatatypeRestrictions;
}
public LiteralDataRange convertDataRange(OWLDataRange dataRange) {
return (LiteralDataRange)dataRange.accept(this);
}
public Object visit(OWLDatatype object) {
String datatypeURI=object.getIRI().toString();
if (InternalDatatype.RDFS_LITERAL.getIRI().equals(datatypeURI))
return InternalDatatype.RDFS_LITERAL;
if (datatypeURI.startsWith("internal:defdata#") || m_definedDatatypeIRIs.contains(object.getIRI().toString()))
return InternalDatatype.create(datatypeURI);
DatatypeRestriction datatype=DatatypeRestriction.create(datatypeURI,DatatypeRestriction.NO_FACET_URIs,DatatypeRestriction.NO_FACET_VALUES);
if (datatypeURI.startsWith("internal:unknown-datatype#"))
m_allUnknownDatatypeRestrictions.add(datatype);
else {
try {
DatatypeRegistry.validateDatatypeRestriction(datatype);
}
catch (UnsupportedDatatypeException e) {
if (m_ignoreUnsupportedDatatypes) {
if (m_warningMonitor!=null)
m_warningMonitor.warning("Ignoring unsupported datatype '"+object.getIRI().toString()+"'.");
m_allUnknownDatatypeRestrictions.add(datatype);
}
else
throw e;
}
}
return datatype;
}
public Object visit(OWLDataComplementOf object) {
return convertDataRange(object.getDataRange()).getNegation();
}
public Object visit(OWLDataOneOf object) {
Set<Constant> constants=new HashSet<Constant>();
for (OWLLiteral literal : object.getValues())
constants.add((Constant)literal.accept(this));
Constant[] constantsArray=new Constant[constants.size()];
constants.toArray(constantsArray);
return ConstantEnumeration.create(constantsArray);
}
public Object visit(OWLDatatypeRestriction object) {
if (!(object.getDatatype().isOWLDatatype()))
throw new IllegalArgumentException("Datatype restrictions are supported only on OWL datatypes.");
String datatypeURI=object.getDatatype().getIRI().toString();
if (InternalDatatype.RDFS_LITERAL.getIRI().equals(datatypeURI)) {
if (!object.getFacetRestrictions().isEmpty())
throw new IllegalArgumentException("rdfs:Literal does not support any facets.");
return InternalDatatype.RDFS_LITERAL;
}
String[] facetURIs=new String[object.getFacetRestrictions().size()];
Constant[] facetValues=new Constant[object.getFacetRestrictions().size()];
int index=0;
for (OWLFacetRestriction facet : object.getFacetRestrictions()) {
facetURIs[index]=facet.getFacet().getIRI().toURI().toString();
facetValues[index]=(Constant)facet.getFacetValue().accept(this);
index++;
}
DatatypeRestriction datatype=DatatypeRestriction.create(datatypeURI,facetURIs,facetValues);
DatatypeRegistry.validateDatatypeRestriction(datatype);
return datatype;
}
public Object visit(OWLFacetRestriction object) {
throw new IllegalStateException("Internal error: should not get in here.");
}
public Object visit(OWLLiteral object) {
try {
if (object.isRDFPlainLiteral()) {
if (object.hasLang())
return Constant.create(object.getLiteral()+"@"+object.getLang(),Prefixes.s_semanticWebPrefixes.get("rdf:")+"PlainLiteral");
else
return Constant.create(object.getLiteral()+"@",Prefixes.s_semanticWebPrefixes.get("rdf:")+"PlainLiteral");
}
else
return Constant.create(object.getLiteral(),object.getDatatype().getIRI().toString());
}
catch (UnsupportedDatatypeException e) {
if (m_ignoreUnsupportedDatatypes) {
if (m_warningMonitor!=null)
m_warningMonitor.warning("Ignoring unsupported datatype '"+object.toString()+"'.");
return Constant.createAnonymous(object.getLiteral());
}
else
throw e;
}
}
public Object visit(OWLDataIntersectionOf node) {
throw new IllegalStateException("Internal error: invalid normal form.");
}
public Object visit(OWLDataUnionOf node) {
throw new IllegalStateException("Internal error: invalid normal form.");
}
}
protected static class FactClausifier extends OWLAxiomVisitorAdapter {
protected final DataRangeConverter m_dataRangeConverter;
protected final Set<Atom> m_positiveFacts;
protected final Set<Atom> m_negativeFacts;
public FactClausifier(DataRangeConverter dataRangeConverter,Set<Atom> positiveFacts,Set<Atom> negativeFacts) {
m_dataRangeConverter=dataRangeConverter;
m_positiveFacts=positiveFacts;
m_negativeFacts=negativeFacts;
}
public void visit(OWLSameIndividualAxiom object) {
OWLIndividual[] individuals=new OWLIndividual[object.getIndividuals().size()];
object.getIndividuals().toArray(individuals);
for (int i=0;i<individuals.length-1;i++)
m_positiveFacts.add(Atom.create(Equality.create(),getIndividual(individuals[i]),getIndividual(individuals[i+1])));
}
public void visit(OWLDifferentIndividualsAxiom object) {
OWLIndividual[] individuals=new OWLIndividual[object.getIndividuals().size()];
object.getIndividuals().toArray(individuals);
for (int i=0;i<individuals.length;i++)
for (int j=i+1;j<individuals.length;j++)
m_positiveFacts.add(Atom.create(Inequality.create(),getIndividual(individuals[i]),getIndividual(individuals[j])));
}
public void visit(OWLClassAssertionAxiom object) {
OWLClassExpression description=object.getClassExpression();
if (description instanceof OWLClass) {
AtomicConcept atomicConcept=AtomicConcept.create(((OWLClass)description).getIRI().toString());
m_positiveFacts.add(Atom.create(atomicConcept,getIndividual(object.getIndividual())));
}
else if (description instanceof OWLObjectComplementOf && ((OWLObjectComplementOf)description).getOperand() instanceof OWLClass) {
AtomicConcept atomicConcept=AtomicConcept.create(((OWLClass)((OWLObjectComplementOf)description).getOperand()).getIRI().toString());
m_negativeFacts.add(Atom.create(atomicConcept,getIndividual(object.getIndividual())));
}
else if (description instanceof OWLObjectHasSelf) {
OWLObjectHasSelf self=(OWLObjectHasSelf)description;
m_positiveFacts.add(getRoleAtom(self.getProperty(),getIndividual(object.getIndividual()),getIndividual(object.getIndividual())));
}
else if (description instanceof OWLObjectComplementOf && ((OWLObjectComplementOf)description).getOperand() instanceof OWLObjectHasSelf) {
OWLObjectHasSelf self=(OWLObjectHasSelf)(((OWLObjectComplementOf)description).getOperand());
m_negativeFacts.add(getRoleAtom(self.getProperty(),getIndividual(object.getIndividual()),getIndividual(object.getIndividual())));
}
else
throw new IllegalStateException("Internal error: invalid normal form.");
}
public void visit(OWLObjectPropertyAssertionAxiom object) {
m_positiveFacts.add(getRoleAtom(object.getProperty(),getIndividual(object.getSubject()),getIndividual(object.getObject())));
}
public void visit(OWLNegativeObjectPropertyAssertionAxiom object) {
m_negativeFacts.add(getRoleAtom(object.getProperty(),getIndividual(object.getSubject()),getIndividual(object.getObject())));
}
public void visit(OWLDataPropertyAssertionAxiom object) {
Constant targetValue=(Constant)object.getObject().accept(m_dataRangeConverter);
m_positiveFacts.add(getRoleAtom(object.getProperty(),getIndividual(object.getSubject()),targetValue));
}
public void visit(OWLNegativeDataPropertyAssertionAxiom object) {
Constant targetValue=(Constant)object.getObject().accept(m_dataRangeConverter);
m_negativeFacts.add(getRoleAtom(object.getProperty(),getIndividual(object.getSubject()),targetValue));
}
}
protected final static class NormalizedRuleClausifier implements SWRLObjectVisitorEx<Atom> {
protected final Set<OWLObjectProperty> m_objectPropertiesOccurringInOWLAxioms;
protected final DataRangeConverter m_dataRangeConverter;
protected final Set<DLClause> m_dlClauses;
protected final List<Atom> m_headAtoms;
protected final List<Atom> m_bodyAtoms;
protected final Set<Variable> m_abstractVariables;
protected final Set<OWLObjectProperty> m_graphObjectProperties=new HashSet<OWLObjectProperty>();
protected boolean m_containsObjectProperties;
protected boolean m_containsGraphObjectProperties;
protected boolean m_containsNonGraphObjectProperties;
protected boolean m_containsUndeterminedObjectProperties;
public NormalizedRuleClausifier(Set<OWLObjectProperty> objectPropertiesOccurringInOWLAxioms,Collection<DescriptionGraph> descriptionGraphs,DataRangeConverter dataRangeConverter,Set<DLClause> dlClauses) {
m_objectPropertiesOccurringInOWLAxioms=objectPropertiesOccurringInOWLAxioms;
m_dataRangeConverter=dataRangeConverter;
m_dlClauses=dlClauses;
m_headAtoms=new ArrayList<Atom>();
m_bodyAtoms=new ArrayList<Atom>();
m_abstractVariables=new HashSet<Variable>();
OWLDataFactory factory=OWLManager.createOWLOntologyManager().getOWLDataFactory();
for (DescriptionGraph descriptionGraph : descriptionGraphs)
for (int i=0;i<descriptionGraph.getNumberOfEdges();i++)
m_graphObjectProperties.add(factory.getOWLObjectProperty(IRI.create(descriptionGraph.getEdge(i).getAtomicRole().getIRI())));
for (OWLObjectProperty objectProperty : m_graphObjectProperties)
if (objectPropertiesOccurringInOWLAxioms.contains(objectProperty))
throw new IllegalArgumentException("Mixing graph and non-graph object properties is not supported.");
}
public void processRules(Collection<OWLAxioms.DisjunctiveRule> rules) {
List<OWLAxioms.DisjunctiveRule> unprocessedRules=new ArrayList<OWLAxioms.DisjunctiveRule>(rules);
boolean changed=true;
while (!unprocessedRules.isEmpty() && changed) {
changed=false;
Iterator<OWLAxioms.DisjunctiveRule> iterator=unprocessedRules.iterator();
while (iterator.hasNext()) {
OWLAxioms.DisjunctiveRule rule=iterator.next();
determineRuleType(rule);
if (m_containsGraphObjectProperties && m_containsNonGraphObjectProperties)
throw new IllegalArgumentException("A SWRL rule mixes graph and non-graph object properties, which is not supported.");
determineUndeterminedObjectProperties(rule);
if (!m_containsUndeterminedObjectProperties) {
iterator.remove();
clausify(rule,m_containsNonGraphObjectProperties || !m_containsObjectProperties);
changed=true;
}
}
}
m_containsObjectProperties=false;
m_containsGraphObjectProperties=false;
m_containsNonGraphObjectProperties=true;
m_containsUndeterminedObjectProperties=false;
for (OWLAxioms.DisjunctiveRule rule : unprocessedRules) {
determineUndeterminedObjectProperties(rule);
clausify(rule,true);
}
}
protected void determineRuleType(OWLAxioms.DisjunctiveRule rule) {
m_containsObjectProperties=false;
m_containsGraphObjectProperties=false;
m_containsNonGraphObjectProperties=false;
m_containsUndeterminedObjectProperties=false;
for (SWRLAtom atom : rule.m_body)
checkRuleAtom(atom);
for (SWRLAtom atom : rule.m_head)
checkRuleAtom(atom);
}
protected void checkRuleAtom(SWRLAtom atom) {
if (atom instanceof SWRLObjectPropertyAtom) {
m_containsObjectProperties=true;
OWLObjectProperty objectProperty=((SWRLObjectPropertyAtom)atom).getPredicate().getNamedProperty();
boolean isGraphObjectProperty=m_graphObjectProperties.contains(objectProperty);
boolean isNonGraphObjectProperty=m_objectPropertiesOccurringInOWLAxioms.contains(objectProperty);
if (isGraphObjectProperty)
m_containsGraphObjectProperties=true;
if (isNonGraphObjectProperty)
m_containsNonGraphObjectProperties=true;
if (!isGraphObjectProperty && !isNonGraphObjectProperty)
m_containsUndeterminedObjectProperties=true;
}
}
protected void determineUndeterminedObjectProperties(OWLAxioms.DisjunctiveRule rule) {
if (m_containsUndeterminedObjectProperties) {
if (m_containsGraphObjectProperties) {
for (SWRLAtom atom : rule.m_body)
makeGraphObjectProperty(atom);
for (SWRLAtom atom : rule.m_head)
makeGraphObjectProperty(atom);
m_containsUndeterminedObjectProperties=false;
}
else if (m_containsNonGraphObjectProperties) {
for (SWRLAtom atom : rule.m_body)
makeNonGraphObjectProperty(atom);
for (SWRLAtom atom : rule.m_head)
makeNonGraphObjectProperty(atom);
m_containsUndeterminedObjectProperties=false;
}
}
}
protected void makeGraphObjectProperty(SWRLAtom atom) {
if (atom instanceof SWRLObjectPropertyAtom) {
OWLObjectProperty objectProperty=((SWRLObjectPropertyAtom)atom).getPredicate().getNamedProperty();
m_graphObjectProperties.add(objectProperty);
}
}
protected void makeNonGraphObjectProperty(SWRLAtom atom) {
if (atom instanceof SWRLObjectPropertyAtom) {
OWLObjectProperty objectProperty=((SWRLObjectPropertyAtom)atom).getPredicate().getNamedProperty();
m_objectPropertiesOccurringInOWLAxioms.add(objectProperty);
}
}
protected void clausify(OWLAxioms.DisjunctiveRule rule,boolean restrictToNamed) {
m_headAtoms.clear();
m_bodyAtoms.clear();
m_abstractVariables.clear();
for (SWRLAtom atom : rule.m_body)
m_bodyAtoms.add(atom.accept(this));
for (SWRLAtom atom : rule.m_head)
m_headAtoms.add(atom.accept(this));
if (restrictToNamed) {
for (Variable variable : m_abstractVariables)
m_bodyAtoms.add(Atom.create(AtomicConcept.INTERNAL_NAMED,variable));
}
DLClause dlClause=DLClause.create(m_headAtoms.toArray(new Atom[m_headAtoms.size()]),m_bodyAtoms.toArray(new Atom[m_bodyAtoms.size()]));
m_dlClauses.add(dlClause);
m_headAtoms.clear();
m_bodyAtoms.clear();
m_abstractVariables.clear();
}
public Atom visit(SWRLClassAtom atom) {
if (atom.getPredicate().isAnonymous())
throw new IllegalStateException("Internal error: SWRL rule class atoms should be normalized to contain only named classes, but this class atom has a complex concept: "+atom.getPredicate());
Variable variable=toVariable(atom.getArgument());
m_abstractVariables.add(variable);
return Atom.create(AtomicConcept.create(atom.getPredicate().asOWLClass().getIRI().toString()),variable);
}
public Atom visit(SWRLDataRangeAtom atom) {
Variable variable=toVariable(atom.getArgument());
LiteralDataRange literalRange=m_dataRangeConverter.convertDataRange(atom.getPredicate());
return Atom.create((DLPredicate)literalRange,variable);
}
public Atom visit(SWRLObjectPropertyAtom atom) {
Variable variable1=toVariable(atom.getFirstArgument());
Variable variable2=toVariable(atom.getSecondArgument());
m_abstractVariables.add(variable1);
m_abstractVariables.add(variable2);
return getRoleAtom(atom.getPredicate().asOWLObjectProperty(),variable1,variable2);
}
public Atom visit(SWRLDataPropertyAtom atom) {
Variable variable1=toVariable(atom.getFirstArgument());
Variable variable2=toVariable(atom.getSecondArgument());
m_abstractVariables.add(variable1);
return getRoleAtom(atom.getPredicate().asOWLDataProperty(),variable1,variable2);
}
public Atom visit(SWRLSameIndividualAtom atom) {
Variable variable1=toVariable(atom.getFirstArgument());
Variable variable2=toVariable(atom.getSecondArgument());
return Atom.create(Equality.INSTANCE,variable1,variable2);
}
public Atom visit(SWRLDifferentIndividualsAtom atom) {
Variable variable1=toVariable(atom.getFirstArgument());
Variable variable2=toVariable(atom.getSecondArgument());
return Atom.create(Inequality.INSTANCE,variable1,variable2);
}
public Atom visit(SWRLBuiltInAtom node) {
throw new UnsupportedOperationException("Rules with SWRL built-in atoms are not yet supported. ");
}
public Atom visit(SWRLRule rule) {
throw new IllegalStateException("Internal error: this part of the code is unused.");
}
public Atom visit(SWRLVariable node) {
throw new IllegalStateException("Internal error: this part of the code is unused.");
}
public Atom visit(SWRLIndividualArgument atom) {
throw new IllegalStateException("Internal error: this part of the code is unused.");
}
public Atom visit(SWRLLiteralArgument arg) {
throw new IllegalStateException("Internal error: this part of the code is unused.");
}
protected static Variable toVariable(SWRLIArgument argument) {
if (argument instanceof SWRLVariable)
return Variable.create(((SWRLVariable)argument).getIRI().toString());
else
throw new IllegalStateException("Internal error: all arguments in a SWRL rule should have been normalized to variables.");
}
protected static Variable toVariable(SWRLDArgument argument) {
if (argument instanceof SWRLVariable)
return Variable.create(((SWRLVariable)argument).getIRI().toString());
else
throw new IllegalStateException("Internal error: all arguments in a SWRL rule should have been normalized to variables.");
}
}
}