Repository: ontodev/robot (java)

Issue:
unusual behavior with relax/reduce when superclass is inferred by domain
Ontology:

```
Prefix: : <http://x.org/>
Ontology: <http://x.org/>

ObjectProperty: supplies Domain: artery
        
Class: brain_artery
    EquivalentTo: artery and supplies some brain
    SubClassOf: artery
    SubClassOf: supplies some brain

Class: artery
Class: brain
```

The goal of the reduce command is to produce a subClassOf graph that is (1) complete and (2) non-redundant

in the above, we want to retain BA SubClassOf A

```
$ robot reduce  -i test-asserted2.omn  -o test2.ofn && (grep 'SubClassOf(:brain_artery :artery)' test2.ofn && echo YES || echo NO)
NO
```

The problem here is the interpretation of NR. The SubClassOf axiom is formally redundant if the Domain axiom is present. But we want robot to make an ontology that can be handed to simple tools that consume SubClassOf graphs and do not speak OWL or use reasoning

Pull request:
Changing behavior for reduce, fixes #321
Previously the procedure included axioms such as Domain in its test for redundant axioms.
This mean it was too vigorous in throwing out SubClassOf axioms.

Now an axiom is only reduced if it can be inferred purely from SubClassOf plus
OPCharacteristic axioms (e.g. transitivity)

Patch:
diff --git a/robot-core/src/main/java/org/obolibrary/robot/ReduceOperation.java b/robot-core/src/main/java/org/obolibrary/robot/ReduceOperation.java
index b391866b..915aeb2c 100644
--- a/robot-core/src/main/java/org/obolibrary/robot/ReduceOperation.java
+++ b/robot-core/src/main/java/org/obolibrary/robot/ReduceOperation.java
@@ -16,10 +16,12 @@ 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.OWLObjectPropertyCharacteristicAxiom;
 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.model.OWLTransitiveObjectPropertyAxiom;
 import org.semanticweb.owlapi.model.parameters.Imports;
 import org.semanticweb.owlapi.reasoner.Node;
 import org.semanticweb.owlapi.reasoner.OWLReasoner;
@@ -99,10 +101,10 @@ public class ReduceOperation {
     OWLDataFactory dataFactory = manager.getOWLDataFactory();
 
     // we treat an axiom as redundant if its is redundant within the
-    // subClassOf graph, excluding equivalence axioms
+    // subClassOf graph, including OP characteristic axioms (e.g. transitivity)
     OWLOntology subOntology = manager.createOntology();
     for (OWLAxiom a : ontology.getAxioms(Imports.INCLUDED)) {
-      if (!(a instanceof OWLEquivalentClassesAxiom)) {
+      if (a instanceof OWLSubClassOfAxiom || a instanceof OWLObjectPropertyCharacteristicAxiom) {
         manager.addAxiom(subOntology, a);
       }
     }


Test patch:
diff --git a/robot-core/src/test/java/org/obolibrary/robot/ReduceOperationTest.java b/robot-core/src/test/java/org/obolibrary/robot/ReduceOperationTest.java
index 5d06212f..c27c8eb5 100644
--- a/robot-core/src/test/java/org/obolibrary/robot/ReduceOperationTest.java
+++ b/robot-core/src/test/java/org/obolibrary/robot/ReduceOperationTest.java
@@ -120,7 +120,7 @@ public class ReduceOperationTest extends CoreTest {
     assertIdentical("/equiv_reduce_test_reduced.obo", reasoned);
   }
 
-  /**
+ /**
    * Edge case, taken from GO
    *
    * <p>See: 'central nervous system development' in the test file
@@ -135,8 +135,26 @@ public class ReduceOperationTest extends CoreTest {
 
     Map<String, String> options = new HashMap<String, String>();
     options.put("remove-redundant-subclass-axioms", "true");
-
+ 
     ReduceOperation.reduce(reasoned, reasonerFactory, options);
     assertIdentical("/reduce-edgecase-cnd-reduced.obo", reasoned);
   }
+  
+  /**
+   * Domain case, see https://github.com/ontodev/robot/issues/321
+   *
+   * 
+   * @throws IOException
+   * @throws OWLOntologyCreationException
+   */
+  @Test
+  public void testReduceDomainCase() throws IOException, OWLOntologyCreationException {
+    OWLOntology reasoned = loadOntology("/reduce-domain-test.owl");
+    OWLReasonerFactory reasonerFactory = new org.semanticweb.elk.owlapi.ElkReasonerFactory();
+
+    Map<String, String> options = new HashMap<String, String>();
+ 
+    ReduceOperation.reduce(reasoned, reasonerFactory, options);
+    assertIdentical("/reduce-domain-test.owl", reasoned);
+  }
 }
diff --git a/robot-core/src/test/resources/reduce-domain-test.owl b/robot-core/src/test/resources/reduce-domain-test.owl
new file mode 100644
index 00000000..e4606ea2
--- /dev/null
+++ b/robot-core/src/test/resources/reduce-domain-test.owl
@@ -0,0 +1,12 @@
+Prefix: : <http://x.org/>
+Ontology: <http://x.org/>
+
+ObjectProperty: supplies Domain: artery
+        
+Class: brain_artery
+    EquivalentTo: artery and supplies some brain
+    SubClassOf: artery
+    SubClassOf: supplies some brain
+
+Class: artery
+Class: brain