Repository: ontodev/robot
Pull request #109 (2016-11-16 02:04:28)

do not materialize self-referencing axioms
ensure that trivial materialized parents are not asserted in materialize command for the reflexivity case.

E.g. if we have

```
Class: A
```

And a property `P` that is reflexive, formally this is a valid materialization:

```
Class: A
SubClassOf: P some A
```

but this is trivial



Patch:
diff --git a/robot-core/src/main/java/org/obolibrary/robot/MaterializeOperation.java b/robot-core/src/main/java/org/obolibrary/robot/MaterializeOperation.java
index 03d815f5..29db8dda 100644
--- a/robot-core/src/main/java/org/obolibrary/robot/MaterializeOperation.java
+++ b/robot-core/src/main/java/org/obolibrary/robot/MaterializeOperation.java
@@ -112,9 +112,19 @@ public class MaterializeOperation {
                 return;
             }
             for (OWLClassExpression sce : sces) {
+                
+                // do not make assertions involving Thing;
+                // while valid, these are trivial
                 if (!sce.getSignature().contains(dataFactory.getOWLThing())) {
-                    OWLAxiom ax = dataFactory.getOWLSubClassOfAxiom(c, sce);
-                    newAxioms.add(ax);
+                    
+                    // avoid materializing parents with child in signature;
+                    // this can happen if a property P is reflexive
+                    // -- every class C is a subclass of P some C
+                    // while valid, this is trivial, so we avoid asserting
+                    if (!sce.getSignature().contains(c)) {
+                        OWLAxiom ax = dataFactory.getOWLSubClassOfAxiom(c, sce);
+                        newAxioms.add(ax);
+                    }
                 }
             }
         }
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 12a8b41b..bfeb0643 100644
--- a/robot-core/src/main/java/org/obolibrary/robot/ReduceOperation.java
+++ b/robot-core/src/main/java/org/obolibrary/robot/ReduceOperation.java
@@ -236,7 +236,8 @@ public class ReduceOperation {
     }
 
     /**
-     * Map a class expression to a class.
+     * Map a class expression to an equivalent named class; creates temp class plus
+     * axiom if not already present
      *
      * @param dataFactory A datafactory for creating the mapped class expression
      * @param rxmap A map from class expressions to classes


Test patch:
diff --git a/robot-core/src/test/java/org/obolibrary/robot/MaterializeOperationTest.java b/robot-core/src/test/java/org/obolibrary/robot/MaterializeOperationTest.java
index cd588d0b..a562f77e 100644
--- a/robot-core/src/test/java/org/obolibrary/robot/MaterializeOperationTest.java
+++ b/robot-core/src/test/java/org/obolibrary/robot/MaterializeOperationTest.java
@@ -17,8 +17,8 @@ import org.semanticweb.owlapi.reasoner.OWLReasonerFactory;
  * Tests for ReasonOperation.
  */
 public class MaterializeOperationTest extends CoreTest {
-    
- 
+
+
     /**
      * Test reasoning with Expression Materializing Reasoner.
      *
@@ -37,7 +37,28 @@ public class MaterializeOperationTest extends CoreTest {
         MaterializeOperation.materialize(reasoned, coreReasonerFactory, null, opts);
         assertIdentical("/relax_equivalence_axioms_expressions_materialized.obo", reasoned);
     }
-    
+
+    /**
+     * Test reasoning with Expression Materializing Reasoner.
+     *
+     * This test ensures that o trivial "C SubClassOf R some C" axioms are materialized
+     * for case where R is reflexive
+     *
+     * @throws IOException on file problem
+     * @throws OWLOntologyCreationException on ontology problem
+     */
+    @Test
+    public void testMaterializeWithReflexivity()
+            throws IOException, OWLOntologyCreationException {
+        OWLOntology reasoned = loadOntology("/mat_reflexivity_test.obo");
+        OWLReasonerFactory coreReasonerFactory = new ElkReasonerFactory();
+        Map<String, String> opts = ReasonOperation.getDefaultOptions();
+        //opts.put("exclude-owl-thing", "true");
+        MaterializeOperation.materialize(reasoned, coreReasonerFactory, null, opts);
+        assertIdentical("/mat_reflexivity_test_materialized.obo", reasoned);
+    }
+
+
     /**
      * Test reasoning with Expression Materializing Reasoner.
      *
@@ -56,6 +77,6 @@ public class MaterializeOperationTest extends CoreTest {
         MaterializeOperation.materialize(reasoned, coreReasonerFactory, null, opts);
         assertIdentical("/gci_example_materialized.obo", reasoned);
     }
-    
+
 
 }
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 5e25e091..da91b073 100644
--- a/robot-core/src/test/java/org/obolibrary/robot/ReduceOperationTest.java
+++ b/robot-core/src/test/java/org/obolibrary/robot/ReduceOperationTest.java
@@ -51,6 +51,27 @@ public class ReduceOperationTest extends CoreTest {
         ReduceOperation.reduce(reasoned, reasonerFactory, options);
         assertIdentical("/redundant_expr_reduced.obo", reasoned);
     }
+    
+    /**
+     * If P is reflexive, and we have
+     *  "A SubClassOf B" and "A SubClassOf P some B",
+     * then the second becomes redundant
+     *
+     * @throws IOException on file problem
+     */
+    @Test
+    public void testReduceWithReflexivity()
+            throws IOException {
+        OWLOntology reasoned = loadOntology("/reduce_reflexivity_test.obo");
+        OWLReasonerFactory reasonerFactory = new org.semanticweb
+            .elk.owlapi.ElkReasonerFactory();
+
+        Map<String, String> options = new HashMap<String, String>();
+        options.put("remove-redundant-subclass-axioms", "true");
+
+        ReduceOperation.reduce(reasoned, reasonerFactory, options);
+        assertIdentical("/reduce_reflexivity_test_reduced.obo", reasoned);
+    }
 
     /**
      * Test removing GCIs.
diff --git a/robot-core/src/test/resources/mat_reflexivity_test.obo b/robot-core/src/test/resources/mat_reflexivity_test.obo
new file mode 100644
index 00000000..79c8b3b8
--- /dev/null
+++ b/robot-core/src/test/resources/mat_reflexivity_test.obo
@@ -0,0 +1,15 @@
+ontology: relax
+
+[Term]
+id: X:2
+name: x2
+
+[Term]
+id: X:1
+is_a: X:2
+
+[Typedef]
+id: part_of
+xref: BFO:0000050
+is_transitive: true
+is_reflexive: true
diff --git a/robot-core/src/test/resources/mat_reflexivity_test_materialized.obo b/robot-core/src/test/resources/mat_reflexivity_test_materialized.obo
new file mode 100644
index 00000000..79c8b3b8
--- /dev/null
+++ b/robot-core/src/test/resources/mat_reflexivity_test_materialized.obo
@@ -0,0 +1,15 @@
+ontology: relax
+
+[Term]
+id: X:2
+name: x2
+
+[Term]
+id: X:1
+is_a: X:2
+
+[Typedef]
+id: part_of
+xref: BFO:0000050
+is_transitive: true
+is_reflexive: true
diff --git a/robot-core/src/test/resources/reduce_reflexivity_test.obo b/robot-core/src/test/resources/reduce_reflexivity_test.obo
new file mode 100644
index 00000000..998f45d7
--- /dev/null
+++ b/robot-core/src/test/resources/reduce_reflexivity_test.obo
@@ -0,0 +1,24 @@
+ontology: relax
+
+[Term]
+id: X:1
+is_a: X:2
+relationship: part_of X:2
+
+[Term]
+id: X:2
+is_a: X:4
+relationship: part_of X:3
+
+[Term]
+id: X:3
+relationship: part_of X:4
+
+[Term]
+id: X:4
+
+[Typedef]
+id: part_of
+xref: BFO:0000050
+is_transitive: true
+is_reflexive: true
diff --git a/robot-core/src/test/resources/reduce_reflexivity_test_reduced.obo b/robot-core/src/test/resources/reduce_reflexivity_test_reduced.obo
new file mode 100644
index 00000000..896e2434
--- /dev/null
+++ b/robot-core/src/test/resources/reduce_reflexivity_test_reduced.obo
@@ -0,0 +1,23 @@
+ontology: relax
+
+[Term]
+id: X:1
+is_a: X:2
+
+[Term]
+id: X:2
+is_a: X:4
+relationship: part_of X:3
+
+[Term]
+id: X:3
+relationship: part_of X:4
+
+[Term]
+id: X:4
+
+[Typedef]
+id: part_of
+xref: BFO:0000050
+is_transitive: true
+is_reflexive: true