diff --git a/OWLTools-Core/src/main/java/owltools/reasoner/AxiomJenga.java b/OWLTools-Core/src/main/java/owltools/reasoner/AxiomJenga.java new file mode 100644 index 000000000..8e9522b6b --- /dev/null +++ b/OWLTools-Core/src/main/java/owltools/reasoner/AxiomJenga.java @@ -0,0 +1,231 @@ +package owltools.reasoner; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.log4j.Logger; +import org.semanticweb.owlapi.model.AxiomType; +import org.semanticweb.owlapi.model.OWLAxiom; +import org.semanticweb.owlapi.model.OWLClass; +import org.semanticweb.owlapi.model.OWLClassExpression; +import org.semanticweb.owlapi.model.OWLDataFactory; +import org.semanticweb.owlapi.model.OWLEquivalentClassesAxiom; +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.OWLSubClassOfAxiom; +import org.semanticweb.owlapi.reasoner.OWLReasoner; +import org.semanticweb.owlapi.util.InferredAxiomGenerator; +import org.semanticweb.owlapi.util.InferredOntologyGenerator; +import org.semanticweb.owlapi.util.InferredSubClassAxiomGenerator; + +/** + * Utility for abductive reasoning + * + * @author cjm + * + */ +public class AxiomJenga { + + private static final Logger LOG = Logger.getLogger(AxiomJenga.class); + + public static JengaTower makeJengaTower(OWLOntology ontology, OWLReasoner reasoner) throws OWLOntologyCreationException { + return makeJengaTower(ontology, reasoner, false); + } + + public static JengaTower makeJengaTower(OWLOntology ontology, OWLReasoner reasoner, + boolean isReplaceRedundant) throws OWLOntologyCreationException { + + Map axiomJengaScoreMap = new HashMap<>(); + OWLOntologyManager manager = ontology.getOWLOntologyManager(); + OWLDataFactory dataFactory = manager.getOWLDataFactory(); + List> gens = + new ArrayList>(); + + // TODO + gens.add(new InferredSubClassAxiomGenerator()); + InferredOntologyGenerator generator = + new InferredOntologyGenerator(reasoner, gens); + LOG.info("Using these axiom generators:"); + for (InferredAxiomGenerator inf: generator.getAxiomGenerators()) { + LOG.info(" " + inf); + } + OWLOntology newAxiomOntology; + newAxiomOntology = manager.createOntology(); + generator.fillOntology(dataFactory, newAxiomOntology); + + Set entailedAxioms = newAxiomOntology.getAxioms(); + Set redundantAxioms = new HashSet<>(); + + OWLAxiom axiomWithMaxJenga = null; + int maxJengaScore = 0; + int totJengaScore = 0; + int totEquivJengaScore = 0; + int n = 0; + int nEquiv = 0; + int tot = ontology.getLogicalAxioms().size(); + for (OWLAxiom axiom : ontology.getLogicalAxioms()) { + n++; + if (n % 100 == 1) { + LOG.info("Axiom "+n+"/"+tot); + } + manager.removeAxiom(ontology, axiom); + reasoner.flush(); + newAxiomOntology = manager.createOntology(); + generator.fillOntology(dataFactory, newAxiomOntology); + Set entailedAxiomsX = newAxiomOntology.getAxioms(); + Set unjustifiedAxioms = new HashSet<>(); + for (OWLAxiom ea : entailedAxioms) { + if (!entailedAxiomsX.contains(ea)) { + unjustifiedAxioms.add(ea); + } + } + int s = unjustifiedAxioms.size(); + axiomJengaScoreMap.put(axiom, s); + if (s > maxJengaScore) { + maxJengaScore = s; + axiomWithMaxJenga = axiom; + } + if (s == 0) { + redundantAxioms.add(axiom); + } + totJengaScore += s; + + if (axiom instanceof OWLEquivalentClassesAxiom) { + nEquiv ++; + totEquivJengaScore += s; + } + + // put it back, if it is either non-redundant or we choose to do this + if (s > 0 || isReplaceRedundant) { + manager.addAxiom(ontology, axiom); + } + } + JengaTower jt = new JengaTower(); + jt.axiomJengaScoreMap = axiomJengaScoreMap; + List aa = new ArrayList<>(axiomJengaScoreMap.keySet()); + aa.sort( (OWLAxiom a1, OWLAxiom a2) -> + axiomJengaScoreMap.get(a1) - axiomJengaScoreMap.get(a2) ); + jt.sortedAxioms = aa; + jt.maxJenga = maxJengaScore; + jt.redundantAxioms = redundantAxioms; + jt.axiomWithMaxJenga = axiomWithMaxJenga; + jt.avgJenga = totJengaScore/((double)n); + if (nEquiv > 0) + jt.avgEquivJenga = totEquivJengaScore/((double)nEquiv); + for (OWLAxiom a : aa) { + int s = axiomJengaScoreMap.get(a); + if (s > 1) { + LOG.info(a+" SCORE: " + s); + } + } + + return jt; + } + + public static JengaTower makeJengaTowerNEW(OWLOntology ontology, OWLReasoner reasoner, + boolean isReplaceRedundant) throws OWLOntologyCreationException { + + Map axiomJengaScoreMap = new HashMap<>(); + OWLOntologyManager manager = ontology.getOWLOntologyManager(); + OWLDataFactory dataFactory = manager.getOWLDataFactory(); + List> gens = + new ArrayList>(); + + // TODO + gens.add(new InferredSubClassAxiomGenerator()); + InferredOntologyGenerator generator = + new InferredOntologyGenerator(reasoner, gens); + LOG.info("Using these axiom generators:"); + for (InferredAxiomGenerator inf: generator.getAxiomGenerators()) { + LOG.info(" " + inf); + } + OWLOntology newAxiomOntology; + newAxiomOntology = manager.createOntology(); + generator.fillOntology(dataFactory, newAxiomOntology); + + Set entailedAxioms = newAxiomOntology.getAxioms(); + Set redundantAxioms = new HashSet<>(); + + OWLAxiom axiomWithMaxJenga = null; + int maxJengaScore = 0; + int totJengaScore = 0; + int totEquivJengaScore = 0; + int n = 0; + int nEquiv = 0; + int tot = ontology.getLogicalAxioms().size(); + for (OWLAxiom axiom : ontology.getLogicalAxioms()) { + n++; + if (n % 100 == 1) { + LOG.info("Axiom "+n+"/"+tot); + } + manager.removeAxiom(ontology, axiom); + reasoner.flush(); + reasoner.isEntailed(axiom); + if (axiom instanceof OWLSubClassOfAxiom) { + OWLSubClassOfAxiom sca = (OWLSubClassOfAxiom)axiom; + reasoner.getSuperClasses(sca.getSubClass(), false); + } + newAxiomOntology = manager.createOntology(); + generator.fillOntology(dataFactory, newAxiomOntology); + Set entailedAxiomsX = newAxiomOntology.getAxioms(); + Set unjustifiedAxioms = new HashSet<>(); + for (OWLAxiom ea : entailedAxioms) { + if (!entailedAxiomsX.contains(ea)) { + unjustifiedAxioms.add(ea); + } + } + int s = unjustifiedAxioms.size(); + axiomJengaScoreMap.put(axiom, s); + if (s > maxJengaScore) { + maxJengaScore = s; + axiomWithMaxJenga = axiom; + } + if (s == 0) { + redundantAxioms.add(axiom); + } + totJengaScore += s; + + if (axiom instanceof OWLEquivalentClassesAxiom) { + nEquiv ++; + totEquivJengaScore += s; + } + + // put it back, if it is either non-redundant or we choose to do this + if (s > 0 || isReplaceRedundant) { + manager.addAxiom(ontology, axiom); + } + } + JengaTower jt = new JengaTower(); + jt.axiomJengaScoreMap = axiomJengaScoreMap; + List aa = new ArrayList<>(axiomJengaScoreMap.keySet()); + aa.sort( (OWLAxiom a1, OWLAxiom a2) -> + axiomJengaScoreMap.get(a1) - axiomJengaScoreMap.get(a2) ); + jt.sortedAxioms = aa; + jt.maxJenga = maxJengaScore; + jt.redundantAxioms = redundantAxioms; + jt.axiomWithMaxJenga = axiomWithMaxJenga; + jt.avgJenga = totJengaScore/((double)n); + if (nEquiv > 0) + jt.avgEquivJenga = totEquivJengaScore/((double)nEquiv); + for (OWLAxiom a : aa) { + int s = axiomJengaScoreMap.get(a); + if (s > 1) { + LOG.info(a+" SCORE: " + s); + } + } + + return jt; + } + + public boolean isEntailed(OWLAxiom axiom, OWLReasoner reasoner) { + return false; + + } +} diff --git a/OWLTools-Core/src/main/java/owltools/reasoner/JengaTower.java b/OWLTools-Core/src/main/java/owltools/reasoner/JengaTower.java new file mode 100644 index 000000000..42e741f40 --- /dev/null +++ b/OWLTools-Core/src/main/java/owltools/reasoner/JengaTower.java @@ -0,0 +1,35 @@ +package owltools.reasoner; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.semanticweb.owlapi.model.OWLAxiom; + +public class JengaTower { + public Map axiomJengaScoreMap; + public List sortedAxioms; + public Integer maxJenga; + public OWLAxiom axiomWithMaxJenga; + public Double avgJenga = 0.0; + public Double avgEquivJenga = 0.0; + public Set redundantAxioms; + + public JengaTower() { + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "JengaTower [axiomJengaScoreMap=" + axiomJengaScoreMap.size() + + ", sortedAxioms=" + sortedAxioms.size() + ", maxJenga=" + maxJenga + + ", redundantAxioms=" + redundantAxioms.size() + + " " + axiomWithMaxJenga + + ", avgJenga=" + avgJenga + ", avgEquivJenga=" + avgEquivJenga + + "]"; + } + + +} \ No newline at end of file diff --git a/OWLTools-Core/src/test/resources/jenga.obo b/OWLTools-Core/src/test/resources/jenga.obo new file mode 100644 index 000000000..e6ad27868 --- /dev/null +++ b/OWLTools-Core/src/test/resources/jenga.obo @@ -0,0 +1,54 @@ +[Term] +id: X:1 +equivalent_to: Y:1 + +[Term] +id: X:2 +is_a: X:1 +equivalent_to: Y:2 + +[Term] +id: X:3 +is_a: X:2 +equivalent_to: Y:3 + +[Term] +id: X:4 +is_a: X:3 +equivalent_to: Y:4 + + +[Term] +id: Y:1 +equivalent_to: Z:1 + +[Term] +id: Y:2 +is_a: Y:1 +equivalent_to: Z:2 + +[Term] +id: Y:3 +is_a: Y:2 +equivalent_to: Z:3 + +[Term] +id: Y:4 +is_a: Y:3 +equivalent_to: Z:4 + + +[Term] +id: Z:1 + +[Term] +id: Z:2 +is_a: Z:1 + +[Term] +id: Z:3 +is_a: Z:2 + +[Term] +id: Z:4 +is_a: Z:3 diff --git a/OWLTools-Core/src/test/resources/jenga_ld.obo b/OWLTools-Core/src/test/resources/jenga_ld.obo new file mode 100644 index 000000000..ff14371e2 --- /dev/null +++ b/OWLTools-Core/src/test/resources/jenga_ld.obo @@ -0,0 +1,69 @@ +[Term] +id: G:1 + +[Term] +id: GY:1 + +[Term] +id: X:1 +intersection_of: G:1 +intersection_of: part_of Y:1 + +[Term] +id: X:2 +is_a: X:1 +intersection_of: G:1 +intersection_of: part_of Y:2 + +[Term] +id: X:3 +is_a: X:2 +intersection_of: G:1 +intersection_of: part_of Y:3 + +[Term] +id: X:4 +is_a: X:3 +intersection_of: G:1 +intersection_of: part_of Y:4 + +[Term] +id: Y:1 +intersection_of: GY:1 +intersection_of: part_of Z:1 + +[Term] +id: Y:2 +is_a: Y:1 +intersection_of: GY:1 +intersection_of: part_of Z:2 + +[Term] +id: Y:3 +is_a: Y:2 +intersection_of: GY:1 +intersection_of: part_of Z:3 + +[Term] +id: Y:4 +is_a: Y:3 +intersection_of: GY:1 +intersection_of: part_of Z:4 + +[Term] +id: Z:1 + +[Term] +id: Z:2 +is_a: Z:1 + +[Term] +id: Z:3 +is_a: Z:2 + +[Term] +id: Z:4 +is_a: Z:3 + +[Typedef] +id: part_of