From 9ce65c5a963b03ee97fe9cb6c5aa65a3c04a80a8 Mon Sep 17 00:00:00 2001 From: yzhou Date: Tue, 21 Apr 2015 10:34:27 +0100 Subject: initial version --- src/uk/ac/ox/cs/pagoda/approx/RLPlusOntology.java | 608 ++++++++++++++++++++++ 1 file changed, 608 insertions(+) create mode 100644 src/uk/ac/ox/cs/pagoda/approx/RLPlusOntology.java (limited to 'src/uk/ac/ox/cs/pagoda/approx/RLPlusOntology.java') diff --git a/src/uk/ac/ox/cs/pagoda/approx/RLPlusOntology.java b/src/uk/ac/ox/cs/pagoda/approx/RLPlusOntology.java new file mode 100644 index 0000000..a43d9af --- /dev/null +++ b/src/uk/ac/ox/cs/pagoda/approx/RLPlusOntology.java @@ -0,0 +1,608 @@ +package uk.ac.ox.cs.pagoda.approx; + +import java.io.BufferedOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +import org.semanticweb.HermiT.Configuration; +import org.semanticweb.HermiT.model.DLClause; +import org.semanticweb.HermiT.model.DLOntology; +import org.semanticweb.HermiT.structural.OWLClausification; +import org.semanticweb.owlapi.model.IRI; +import org.semanticweb.owlapi.model.OWLAnnotationAssertionAxiom; +import org.semanticweb.owlapi.model.OWLAxiom; +import org.semanticweb.owlapi.model.OWLClass; +import org.semanticweb.owlapi.model.OWLClassAssertionAxiom; +import org.semanticweb.owlapi.model.OWLClassExpression; +import org.semanticweb.owlapi.model.OWLDataFactory; +import org.semanticweb.owlapi.model.OWLDataHasValue; +import org.semanticweb.owlapi.model.OWLDataMaxCardinality; +import org.semanticweb.owlapi.model.OWLDataMinCardinality; +import org.semanticweb.owlapi.model.OWLDataPropertyAssertionAxiom; +import org.semanticweb.owlapi.model.OWLDataSomeValuesFrom; +import org.semanticweb.owlapi.model.OWLDatatype; +import org.semanticweb.owlapi.model.OWLNamedIndividual; +import org.semanticweb.owlapi.model.OWLObjectAllValuesFrom; +import org.semanticweb.owlapi.model.OWLObjectComplementOf; +import org.semanticweb.owlapi.model.OWLObjectHasValue; +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.OWLOntology; +import org.semanticweb.owlapi.model.OWLOntologyCreationException; +import org.semanticweb.owlapi.model.OWLOntologyManager; +import org.semanticweb.owlapi.model.OWLOntologyStorageException; +import org.semanticweb.owlapi.profiles.OWL2RLProfile; +import org.semanticweb.owlapi.profiles.OWLProfileReport; +import org.semanticweb.owlapi.profiles.OWLProfileViolation; + +import uk.ac.ox.cs.pagoda.constraints.NullaryBottom; +import uk.ac.ox.cs.pagoda.constraints.UnaryBottom; +import uk.ac.ox.cs.pagoda.owl.OWLHelper; +import uk.ac.ox.cs.pagoda.util.Namespace; +import uk.ac.ox.cs.pagoda.util.Utility; + +public class RLPlusOntology implements KnowledgeBase { + + OWLOntologyManager manager; + OWLDataFactory factory; + String ontologyIRI; + String corrFileName = null; + String outputPath, aBoxPath; + + OWLOntology inputOntology = null; + OWLOntology tBox = null; + OWLOntology aBox = null; + OWLOntology restOntology = null; + OWLOntology outputOntology = null; //RL ontology + + DLOntology dlOntology = null; + int rlCounter = 0; + + LinkedList clauses; + Map correspondence; + + BottomStrategy botStrategy; + + @Override + public void load(OWLOntology o, uk.ac.ox.cs.pagoda.constraints.BottomStrategy bottomStrategy) { + if (bottomStrategy instanceof UnaryBottom) + botStrategy = BottomStrategy.UNARY; + else if (bottomStrategy instanceof NullaryBottom) + botStrategy = BottomStrategy.NULLARY; + else + botStrategy = BottomStrategy.TOREMOVE; + + if (corrFileName == null) + corrFileName = "rlplus.crr"; + manager = o.getOWLOntologyManager(); +// manager = OWLManager.createOWLOntologyManager(); + factory = manager.getOWLDataFactory(); + inputOntology = o; + + try { + String path = OWLHelper.getOntologyPath(inputOntology); + String name = path.substring(path.lastIndexOf(Utility.JAVA_FILE_SEPARATOR)); + String originalExtension = name.lastIndexOf(".") >= 0 ? name.substring(name.lastIndexOf(".")) : ""; + + if (inputOntology.getOntologyID().getOntologyIRI() == null) + ontologyIRI = "http://www.example.org/anonymous-ontology" + originalExtension; + else + ontologyIRI = inputOntology.getOntologyID().getOntologyIRI().toString(); + + String tOntoIRI = ontologyIRI; + if (!tOntoIRI.endsWith(originalExtension)) tOntoIRI += originalExtension; + + String rlOntologyIRI = originalExtension.isEmpty() ? tOntoIRI + "-RL.owl" : tOntoIRI.replaceFirst(originalExtension, "-RL.owl"); + String rlDocumentIRI = (outputPath = Utility.TempDirectory + "RL.owl"); + outputOntology = manager.createOntology(IRI.create(rlOntologyIRI)); + manager.setOntologyDocumentIRI(outputOntology, IRI.create(Utility.toFileIRI(rlDocumentIRI))); + + String tBoxOntologyIRI, aBoxOntologyIRI; + tBoxOntologyIRI = originalExtension.isEmpty() ? tOntoIRI + "-TBox.owl" : tOntoIRI.replaceFirst(originalExtension, "-TBox.owl"); + aBoxOntologyIRI = originalExtension.isEmpty() ? tOntoIRI + "-ABox.owl" : tOntoIRI.replaceFirst(originalExtension, "-ABox.owl"); + + String tBoxDocumentIRI = (Utility.TempDirectory + "TBox.owl"); + String aBoxDocumentIRI = (aBoxPath = Utility.TempDirectory + "ABox.owl"); + tBox = manager.createOntology(IRI.create(tBoxOntologyIRI)); + aBox = manager.createOntology(IRI.create(aBoxOntologyIRI)); + manager.setOntologyDocumentIRI(tBox, IRI.create(Utility.toFileIRI(tBoxDocumentIRI))); + manager.setOntologyDocumentIRI(aBox, IRI.create(Utility.toFileIRI(aBoxDocumentIRI))); + + FileOutputStream aBoxOut = new FileOutputStream(aBoxPath); + manager.saveOntology(aBox, aBoxOut); + aBoxOut.close(); + + restOntology = manager.createOntology(); + } + catch (OWLOntologyCreationException e) { + e.printStackTrace(); + } catch (OWLOntologyStorageException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public OWLOntology getTBox() { + return tBox; + } + + public String getABoxPath() { + return aBoxPath; + } + + private void add2SubCounter(OWLClassExpression exp) { + Integer count = subCounter.get(exp); + if (count == null) count = 0; + ++count; + subCounter.put(exp, count); + } + + public void simplify() { + if (simplifyABox()) { + save(aBox); +// save(tBox); + } + else + tBox = inputOntology; + } + + @Override + public void transform() { + simplify(); + filter(); + clausify(); + + subCounter = new HashMap(); + clauses = new LinkedList(); + Clausifier clausifier = Clausifier.getInstance(restOntology); + + for (DLClause c: dlOntology.getDLClauses()) { + Clause clause = new Clause(clausifier, c); + clauses.add(clause); + + /* + * count the expressions in the left + */ + for (OWLClassExpression exp: clause.getSubClasses()) { + if (exp instanceof OWLClass) + add2SubCounter(exp); + else if (exp instanceof OWLObjectSomeValuesFrom) { + OWLObjectSomeValuesFrom someValue = (OWLObjectSomeValuesFrom)exp; + add2SubCounter(factory.getOWLObjectSomeValuesFrom(someValue.getProperty(), factory.getOWLThing())); + add2SubCounter(someValue.getFiller()); + } + else if (exp instanceof OWLObjectMinCardinality) { + OWLObjectMinCardinality minCard = (OWLObjectMinCardinality)exp; + add2SubCounter(factory.getOWLObjectSomeValuesFrom(minCard.getProperty(), factory.getOWLThing())); + add2SubCounter(minCard.getFiller()); + } + else + Utility.logError("strange class expression: " + exp); + + } + } + + correspondence = new HashMap(); + Set addedAxioms = new HashSet(); + OWLClassExpression subExp; + for (Clause clause: clauses) { + subExp = uk.ac.ox.cs.pagoda.owl.OWLHelper.getSimplifiedConjunction(factory, clause.getSubClasses()); + addedAxioms.clear(); + for (OWLClassExpression exp: getDisjunctionApprox0(clause.getSuperClasses())) { + addedAxioms.add(factory.getOWLSubClassOfAxiom(subExp, transform(exp, addedAxioms))); + for (OWLAxiom a: addedAxioms) + addAxiom2output(a, factory.getOWLSubClassOfAxiom(subExp, + OWLHelper.getSimplifiedDisjunction(factory, clause.getSuperClasses()))); + } + } + + subCounter.clear(); + } + + @Override + public void save() { + if (corrFileName != null) + save(correspondence, corrFileName); + save(outputOntology); + } + + private void save(Map map, String corrFileName) { + if (corrFileName == null) return ; + ObjectOutput output; + try { + output = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(corrFileName))); + output.writeObject(map); + output.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + protected void save(OWLOntology onto) { + try { + onto.getOWLOntologyManager().saveOntology(onto); + } catch (OWLOntologyStorageException e) { + e.printStackTrace(); + } + } + + /* + * treat disjunction as conjunction + */ + private Set getDisjunctionApprox0(Set superClasses) { + return superClasses; + } + + /* + * choose one simple class disjunct + */ + @SuppressWarnings("unused") + private Set getDisjunctionApprox1(Set superClasses) { + if (superClasses.isEmpty() || superClasses.size() == 1) + return superClasses; + + OWLClassExpression rep = null; + int min = Integer.MAX_VALUE, o; + for (OWLClassExpression exp: superClasses) + if (exp instanceof OWLClass && (o = getOccurrence(exp)) < min) { + min = o; + rep = exp; + } + + if (rep == null) rep = superClasses.iterator().next(); + + return Collections.singleton(rep); + } + + Random random = new Random(19900114); + /* + * randomly choose a class expression to represent this disjunction + */ + @SuppressWarnings("unused") + private Set getDisjunctionApprox2(Set superClasses) { + if (superClasses.isEmpty() || superClasses.size() == 1) + return superClasses; + + int index = random.nextInt() % superClasses.size(); + if (index < 0) index += superClasses.size(); + + int i = 0; + for (OWLClassExpression exp: superClasses) + if (i++ == index) + return Collections.singleton(exp); + return null; + } + + private Map subCounter = null; + /* + * choose the one that appears least in the l.h.s. + */ + @SuppressWarnings("unused") + private Set getDisjunctionApprox3(Set superClasses) { + if (superClasses.isEmpty() || superClasses.size() == 1) + return superClasses; + + OWLClassExpression rep = null, exp1; + int occurrence = Integer.MAX_VALUE, o; + for (OWLClassExpression exp: superClasses) { + o = 0; + exp1 = exp; + if (exp instanceof OWLObjectMinCardinality) { + OWLObjectMinCardinality minCard = (OWLObjectMinCardinality)exp; + if (minCard.getCardinality() == 1) + exp1 = factory.getOWLObjectSomeValuesFrom(minCard.getProperty(), minCard.getFiller()); + } + + if (!subCounter.containsKey(exp1) || (o = subCounter.get(exp1)) < occurrence) { + rep = exp; + occurrence = o; + } + } + + return Collections.singleton(rep); + } + + private int getOccurrence(OWLClassExpression exp) { + if (!subCounter.containsKey(exp)) + return 0; + return subCounter.get(exp); + } + + @SuppressWarnings("unused") + private Set getDisjunctionApprox4(Set superClasses) { + if (superClasses.isEmpty() || superClasses.size() == 1) + return superClasses; + + OWLClassExpression rep = null; + int occurrence = Integer.MAX_VALUE, o; + for (OWLClassExpression exp: superClasses) { + o = 0; + if (exp instanceof OWLObjectMinCardinality) { + OWLObjectMinCardinality minCard = (OWLObjectMinCardinality)exp; + if (minCard.getCardinality() == 1) { + o = getOccurrence((factory.getOWLObjectSomeValuesFrom(minCard.getProperty(), factory.getOWLThing()))); + o += getOccurrence(minCard.getFiller()); +// if (o < o1) o = o1; + } + } + else + o = getOccurrence(exp); + + if (o < occurrence || o == occurrence && !(rep instanceof OWLClass)) { + rep = exp; + occurrence = o; + } + } + + return Collections.singleton(rep); + } + + private boolean simplifyABox() { + boolean flag = false; + Map complex2atomic= new HashMap(); + + OWLDatatype anyURI = factory.getOWLDatatype(IRI.create(Namespace.XSD_NS + "anyURI")); + for (OWLOntology imported: inputOntology.getImportsClosure()) + for (OWLAxiom axiom: imported.getAxioms()) { + if (axiom instanceof OWLClassAssertionAxiom) { + flag = true; + OWLClassAssertionAxiom assertion = (OWLClassAssertionAxiom)axiom; + OWLClassExpression clsExp = assertion.getClassExpression(); + OWLClass cls; + if (clsExp instanceof OWLClass) { + if (((OWLClass) clsExp).toStringID().startsWith("owl:")) + manager.addAxiom(tBox, axiom); + else manager.addAxiom(aBox, axiom); + } + else { + if ((cls = complex2atomic.get(clsExp)) == null) { + complex2atomic.put(clsExp, cls = getNewConcept(tBox, rlCounter++)); + manager.addAxiom(tBox, factory.getOWLSubClassOfAxiom(cls, clsExp)); + } + manager.addAxiom(aBox, factory.getOWLClassAssertionAxiom(cls, assertion.getIndividual())); + } + } + else if (axiom instanceof OWLObjectPropertyAssertionAxiom || axiom instanceof OWLDataPropertyAssertionAxiom || axiom instanceof OWLAnnotationAssertionAxiom) { + if (axiom.containsEntityInSignature(anyURI)) continue; + flag = true; + manager.addAxiom(aBox, axiom); + } + else + manager.addAxiom(tBox, axiom); + } + + return flag; + } + + private void filter() { + OWL2RLProfile profile = new OWL2RLProfile(); + OWLProfileReport report = profile.checkOntology(tBox); + Set rlAxioms = tBox.getAxioms(); + OWLAxiom axiom; + + for (OWLProfileViolation violation: report.getViolations()) { + manager.addAxiom(restOntology, axiom = violation.getAxiom()); + rlAxioms.remove(axiom); + } + + for (Iterator iter = rlAxioms.iterator(); iter.hasNext(); ) + addAxiom2output(iter.next(), null); + } + + private void clausify() { + Configuration conf = new Configuration(); + OWLClausification clausifier = new OWLClausification(conf); + dlOntology = (DLOntology)clausifier.preprocessAndClausify(restOntology, null)[1]; + clausifier = null; + } + + protected void addAxiom2output(OWLAxiom axiom, OWLAxiom correspondingAxiom) { + manager.addAxiom(outputOntology, axiom); + if (correspondingAxiom != null) + correspondence.put(axiom, correspondingAxiom); + } + + private Map atomic2negation = new HashMap(); + + private OWLClassExpression transform(OWLClassExpression exp, Set addedAxioms) { + if (exp instanceof OWLClass) + return exp; + + if (exp instanceof OWLObjectHasValue) + return exp; + + if (exp instanceof OWLObjectSomeValuesFrom) { + OWLObjectSomeValuesFrom someValueExp = (OWLObjectSomeValuesFrom)exp; + + OWLClassExpression tExp = someValueExp.getFiller(); + if (tExp.equals(factory.getOWLThing())) + exp = factory.getOWLObjectMinCardinality(1, someValueExp.getProperty()); + else + exp = factory.getOWLObjectMinCardinality(1, someValueExp.getProperty(), someValueExp.getFiller()); + } + + if (exp instanceof OWLObjectMinCardinality) { + OWLObjectMinCardinality minExp = (OWLObjectMinCardinality)exp; + OWLObjectPropertyExpression r; + + if (minExp.getFiller().equals(factory.getOWLThing())) { + r = minExp.getProperty(); + } + //TODO to be restored ... + //else if ((r = exists2role.get(someValueExp)) == null) { + // deal with r' \subseteq r & range(r') \subseteq C + else { + r = getNewRole(outputOntology, rlCounter); + addedAxioms.add(factory.getOWLSubObjectPropertyOfAxiom(r, minExp.getProperty())); + OWLClassExpression tExp = minExp.getFiller(); + if (!(tExp instanceof OWLObjectComplementOf)) { + if (tExp.equals(factory.getOWLThing())); + else + addedAxioms.add(factory.getOWLObjectPropertyRangeAxiom(r, tExp)); + } + else if (botStrategy != BottomStrategy.TOREMOVE) { + OWLClass cls = (OWLClass) ((OWLObjectComplementOf) tExp).getComplementNNF(); + OWLClass neg; + if ((neg = atomic2negation.get(cls)) == null) { + neg = getNewConcept(outputOntology, rlCounter); + addedAxioms.add(factory.getOWLDisjointClassesAxiom(neg, cls)); + atomic2negation.put(cls, neg); + } + addedAxioms.add(factory.getOWLObjectPropertyRangeAxiom(r, neg)); + } +// exists2role.put(someValueExp, (OWLObjectProperty) r); + } + + // deal with r'(x,c) + Set ret = new HashSet(); + int num = minExp.getCardinality(); + + Set cs = new HashSet(); + OWLNamedIndividual c; + for (int i = 0; i < num; ++i) { + c = getNewIndividual(outputOntology, rlCounter++); + ret.add(factory.getOWLObjectHasValue(r, c)); + cs.add(c); + } + + if (botStrategy != BottomStrategy.TOREMOVE && cs.size() > 1) { + addedAxioms.add(factory.getOWLDifferentIndividualsAxiom(cs)); + } + + return OWLHelper.getSimplifiedConjunction(factory, ret); + } + + if (exp instanceof OWLObjectMaxCardinality) { + OWLObjectMaxCardinality maxExp = (OWLObjectMaxCardinality)exp; + OWLClassExpression tExp = maxExp.getFiller(); + int card = maxExp.getCardinality() >= 1 ? 1 : 0; + if (!(tExp instanceof OWLObjectComplementOf)) + return factory.getOWLObjectMaxCardinality(card, maxExp.getProperty(), tExp); + else { + Utility.logDebug("oh, to be tested ... "); + OWLClassExpression tExp1 = factory.getOWLObjectAllValuesFrom(maxExp.getProperty(), tExp.getComplementNNF()); + if (card == 0) + return tExp1; + else { + OWLClassExpression tExp2 = factory.getOWLObjectMaxCardinality(1, maxExp.getProperty()); + return factory.getOWLObjectIntersectionOf(tExp1, tExp2); + } + } + } + + if (exp instanceof OWLObjectAllValuesFrom) + return exp; + + if (exp instanceof OWLObjectOneOf) + if (((OWLObjectOneOf) exp).getIndividuals().size() == 1) + return exp; + else + return null; + + if (exp instanceof OWLDataHasValue) + return exp; + + //TODO overapproximation - dealing with OWLDataMinCardinality + + if (exp instanceof OWLDataSomeValuesFrom) { + return exp; + } + + if (exp instanceof OWLDataMinCardinality) { + return exp; + } + + if (exp instanceof OWLDataMaxCardinality) { + return exp; + } + + + Set exps = exp.asConjunctSet(); + if (exps.size() == 1 && exps.iterator().next() == exp) { + Utility.logError(exp, "error in transform of Ontology~~~~"); + } + Set nexps = new HashSet(); + OWLClassExpression ne; + boolean changes = false; + for (OWLClassExpression e: exps) { + ne = transform(e, addedAxioms); + if (ne != e) changes = true; + nexps.add(ne); + } + if (changes) + return OWLHelper.getSimplifiedConjunction(factory, nexps); + else + return exp; + } + + protected OWLNamedIndividual getNewIndividual(OWLOntology onto, int number) { + OWLOntologyManager manager = onto.getOWLOntologyManager(); + OWLDataFactory factory = manager.getOWLDataFactory(); + OWLNamedIndividual newIndividual = factory.getOWLNamedIndividual(IRI.create(Namespace.PAGODA_ANONY + "NI" + number)); + manager.addAxiom(onto, factory.getOWLDeclarationAxiom(newIndividual)); + return newIndividual; + } + + protected OWLObjectProperty getNewRole(OWLOntology onto, int number) { + OWLOntologyManager manager = onto.getOWLOntologyManager(); + OWLDataFactory factory = manager.getOWLDataFactory(); + OWLObjectProperty newProperty = factory.getOWLObjectProperty(IRI.create(Namespace.PAGODA_AUX + "NR" + number)); + manager.addAxiom(onto, factory.getOWLDeclarationAxiom(newProperty)); + return newProperty; + } + + private OWLClass getNewConcept(OWLOntology onto, int number) { + OWLOntologyManager manager = onto.getOWLOntologyManager(); + OWLDataFactory factory = manager.getOWLDataFactory(); + OWLClass newClass = factory.getOWLClass(IRI.create(Namespace.PAGODA_AUX + "NC" + number)); + manager.addAxiom(onto, factory.getOWLDeclarationAxiom(newClass)); + return newClass; + } + + public OWLOntologyManager getOWLOntologyManager() { + return inputOntology.getOWLOntologyManager(); + } + + public String getOntologyIRI() { + return ontologyIRI; + } + + public OWLOntology getOutputOntology() { + return outputOntology; + } + + @Override + public String getOutputPath() { + return outputPath; + } + + @Override + public String getDirectory() { + return outputPath.substring(0, outputPath.lastIndexOf(Utility.FILE_SEPARATOR)); + } + + public void setCorrespondenceFileLoc(String path) { + corrFileName = path; + } + + private static enum BottomStrategy { TOREMOVE, NULLARY, UNARY } +} + -- cgit v1.2.3