Browse Source

Basic operation tests pass.

Stefano Cossu 5 years ago
parent
commit
170e27ca65

+ 4 - 2
lakesuperior/model/graph/graph.pxd

@@ -45,12 +45,14 @@ cdef class SimpleGraph:
 
         # Basic graph operations.
         void ip_union(self, SimpleGraph other) except *
+        void ip_subtraction(self, SimpleGraph other) except *
         void ip_intersection(self, SimpleGraph other) except *
         void ip_xor(self, SimpleGraph other) except *
 
-    cpdef SimpleGraph xor(self, SimpleGraph other)
-    cpdef SimpleGraph intersection(self, SimpleGraph other)
     cpdef SimpleGraph union(self, SimpleGraph other)
+    cpdef SimpleGraph subtraction(self, SimpleGraph other)
+    cpdef SimpleGraph intersection(self, SimpleGraph other)
+    cpdef SimpleGraph xor(self, SimpleGraph other)
     cpdef void set(self, tuple trp) except *
     cpdef void remove_triples(self, pattern) except *
     cpdef object as_rdflib(self)

+ 74 - 12
lakesuperior/model/graph/graph.pyx

@@ -440,7 +440,8 @@ cdef class SimpleGraph:
         """
         In-place graph intersection.
 
-        Triples in common with another graph are removed from the current one.
+        Triples not in common with another graph are removed from the current
+        one.
 
         :param SimpleGraph other: The other graph to intersect.
 
@@ -457,6 +458,56 @@ cdef class SimpleGraph:
                 self._remove_triple(bt)
 
 
+    cpdef SimpleGraph subtraction(self, SimpleGraph other):
+        """
+        Graph set-theoretical subtraction.
+
+        Create a new graph with the triples of this graph minus the ones in
+        common with the other graph.
+
+        :param SimpleGraph other: The other graph to subtract to this.
+
+        :rtype: SimpleGraph
+        :return: A new SimpleGraph instance.
+        """
+        cdef:
+            void *cur
+            cc.HashSetIter it
+            SimpleGraph new_gr = SimpleGraph()
+
+        cc.hashset_iter_init(&it, self._triples)
+        while cc.hashset_iter_next(&it, &cur) != cc.CC_ITER_END:
+            bt = <BufferTriple*>cur
+            #print('Checking: <0x{:02x}> <0x{:02x}> <0x{:02x}>'.format(
+            #    <size_t>bt.s, <size_t>bt.p, <size_t>bt.o))
+            if not other._trp_contains(bt):
+                #print('Adding.')
+                new_gr._add_triple(bt)
+
+        return new_gr
+
+
+    cdef void ip_subtraction(self, SimpleGraph other) except *:
+        """
+        In-place graph subtraction.
+
+        Triples in common with another graph are removed from the current one.
+
+        :param SimpleGraph other: The other graph to intersect.
+
+        :rtype: void
+        """
+        cdef:
+            void *cur
+            cc.HashSetIter it
+
+        cc.hashset_iter_init(&it, self._triples)
+        while cc.hashset_iter_next(&it, &cur) != cc.CC_ITER_END:
+            bt = <BufferTriple*>cur
+            if other._trp_contains(bt):
+                self._remove_triple(bt)
+
+
     cpdef SimpleGraph xor(self, SimpleGraph other):
         """
         Graph Exclusive disjunction (XOR).
@@ -731,7 +782,7 @@ cdef class SimpleGraph:
 
     def __eq__(self, other):
         """ Equality operator between ``SimpleGraph`` instances. """
-        return graph_eq_fn(self, other)
+        return len(self ^ other) == 0
 
 
     def __repr__(self):
@@ -752,45 +803,56 @@ cdef class SimpleGraph:
         return str(self.data)
 
 
+    def __add__(self, other):
+        """ Alias for set-theoretical union. """
+        return self.union(other)
+
+
+    def __iadd__(self, other):
+        """ Alias for in-place set-theoretical union. """
+        self.ip_union(other)
+        return self
+
+
     def __sub__(self, other):
-        """ Set subtraction. """
-        return self.subtract(other)
+        """ Set-theoretical subtraction. """
+        return self.subtraction(other)
 
 
     def __isub__(self, other):
-        """ In-place set subtraction. """
-        self.ip_subtract(other)
+        """ In-place set-theoretical subtraction. """
+        self.ip_subtraction(other)
         return self
 
     def __and__(self, other):
-        """ Set intersection. """
+        """ Set-theoretical intersection. """
         return self.intersection(other)
 
 
     def __iand__(self, other):
-        """ In-place set intersection. """
+        """ In-place set-theoretical intersection. """
         self.ip_intersection(other)
         return self
 
 
     def __or__(self, other):
-        """ Set union. """
+        """ Set-theoretical union. """
         return self.union(other)
 
 
     def __ior__(self, other):
-        """ In-place set union. """
+        """ In-place set-theoretical union. """
         self.ip_union(other)
         return self
 
 
     def __xor__(self, other):
-        """ Set exclusive disjunction (XOR). """
+        """ Set-theoretical exclusive disjunction (XOR). """
         return self.xor(other)
 
 
     def __ixor__(self, other):
-        """ In-place set exclusive disjunction (XOR). """
+        """ In-place set-theoretical exclusive disjunction (XOR). """
         self.ip_xor(other)
         return self
 

+ 85 - 0
tests/0_data_structures/test_graph.py

@@ -113,6 +113,91 @@ class TestGraphOps:
         assert trp[4] in gr1
 
 
+    def test_addition(self, trp):
+        """
+        Test graph addition.
+        """
+        gr1 = SimpleGraph()
+        gr2 = SimpleGraph()
+
+        gr1.add(trp[0:3])
+        gr2.add(trp[2:6])
+
+        gr3 = gr1 + gr2
+
+        assert len(gr3) == 5
+        assert trp[0] in gr3
+        assert trp[4] in gr3
+
+
+    def test_ip_addition(self, trp):
+        """
+        Test graph in-place addition.
+        """
+        gr1 = SimpleGraph()
+        gr2 = SimpleGraph()
+
+        gr1.add(trp[0:3])
+        gr2.add(trp[2:6])
+
+        gr1 += gr2
+
+        assert len(gr1) == 5
+        assert trp[0] in gr1
+        assert trp[4] in gr1
+
+
+    def test_subtraction(self, trp):
+        """
+        Test graph addition.
+        """
+        gr1 = SimpleGraph()
+        gr2 = SimpleGraph()
+
+        gr1.add(trp[0:4])
+        gr2.add(trp[2:6])
+
+        gr3 = gr1 - gr2
+
+        assert len(gr3) == 1
+        assert trp[0] in gr3
+        assert trp[1] in gr3
+        assert trp[2] not in gr3
+        assert trp[3] not in gr3
+        assert trp[4] not in gr3
+
+        gr3 = gr2 - gr1
+
+        assert len(gr3) == 2
+        assert trp[0] not in gr3
+        assert trp[1] not in gr3
+        assert trp[2] not in gr3
+        assert trp[3] not in gr3
+        assert trp[4] in gr3
+        assert trp[5] in gr3
+
+
+    def test_ip_subtraction(self, trp):
+        """
+        Test graph in-place addition.
+        """
+        gr1 = SimpleGraph()
+        gr2 = SimpleGraph()
+
+        gr1.add(trp[0:4])
+        gr2.add(trp[2:6])
+
+        gr1 -= gr2
+
+        assert len(gr1) == 1
+        assert trp[0] in gr1
+        assert trp[1] in gr1
+        assert trp[2] not in gr1
+        assert trp[3] not in gr1
+        assert trp[4] not in gr1
+
+
+
     def test_intersect(self, trp):
         """
         Test graph intersextion.