Test cases combining MINUS and NOT EXISTS

I've added test cases to the negation test suite after I was asked how
one might query for subset relationships. The queries calculate which
sets are subsets of other sets in the data, look for set quality and
find proper subsets.

There are other ways to achieve the tasks, and probably lost of better
ways but these provide combinations of MINUS and NOT EXISTS in the same
query.  The tests do illustrate the different styles of negation for
MINUS and NOT EXISTS.

Style point: I've committed SPARQL XML Results format files.  Does
anyone mind if we use the JSON format as well?

	Andy

Data:
------
:a rdf:type :Set .
:a :member 1 .
:a :member 2 .
:a :member 3 .

:b rdf:type :Set .
:b :member 1 .
:b :member 9 .

:c rdf:type :Set .
:c :member 1 .
:c :member 2 .

:d rdf:type :Set .
:d :member 1 .
:d :member 9 .

:e rdf:type :Set .
:e :member 1 .
:e :member 2 .

:empty rdf:type :Set .
-------
	:b,:d and :c,:e have the same members.
	:c and :e are proper subsets of :a

Having "rdf:type :Set" makes it easy to find the sets.  Otherwise, we'd
need subqueries: { SELECT DISTINCT ?s { :s :member [] } } and the empty
set would not be there.


query for subset-01:
Find subsets, include the case of same elements.

Could eliminate the case of (A,B) and (B,A) by
    FILTER(str(?s1) < str(?s2))
but that only works because the data uses IRIs, not bnodes.



------
PREFIX :    <http://example/>
PREFIX  rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
# SPARQL 1.1
SELECT (?s1 AS ?subset) (?s2 AS ?superset)
WHERE
{
    # All pairs of sets
    ?s2 rdf:type :Set .
    ?s1 rdf:type :Set .
    FILTER(?s1 != ?s2)
    MINUS
    {
    	# The MINUS RHS is (?s1, ?s2) where ?s1 has a member not in ?s2
        # All pairs of sets ...

        ?s1 rdf:type :Set .
        ?s2 rdf:type :Set .

        ?s1 :member ?x .
        FILTER NOT EXISTS { ?s2 :member ?x . }
    }
}

------

query for subset-02:
Look for only proper subsets.
Imperfect - it does not do set equality testing, so it leaves in (:b,:d)
(:c,:e) and the reverse pairs but it does use MINUS twice and a ||
FILTER with NOT EXISTS

Because this uses "?s1 :member ?x" it assumes that ?s1 does have at
least member, so (:emptyset, :emptyset) is left in the answers.

The second MINUS eliminates that case by testing existence with a free
variable, unlike the previous part of the query.

------
PREFIX :    <http://example/>
PREFIX  rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT (?s1 AS ?subset) (?s2 AS ?superset)
WHERE
{
    # All pairs of sets
    ?s2 rdf:type :Set .
    ?s1 rdf:type :Set .
    MINUS {
        ?s1 rdf:type :Set .
        ?s2 rdf:type :Set .
        # Assumes ?s1 has at least one member
        ?s1 :member ?x .
        # If we want to exclude A as a subset of A.
        # This is not perfect as "?s1 = ?s2" is not a
	# contents based comparison.
        FILTER ( ?s1 = ?s2 || NOT EXISTS { ?s2 :member ?x . } )
    }
    MINUS {
        # If we don't want the empty set being a subset of itself.
        ?s1 rdf:type :Set .
        ?s2 rdf:type :Set .
        # Choose the pair (empty set, empty set)
        FILTER ( NOT EXISTS { ?s1 :member ?y . } )
        FILTER ( NOT EXISTS { ?s2 :member ?y . } )
        }
}
------

query for set-equality-1.rq
Find all pairs that are different resources but the set has the same
members.

----
PREFIX :    <http://example/>
PREFIX  rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

# Find sets that have exactly the same members.
# Find all (s1,s2) such that (s1 subset of s) and (s2 subset of s1).

SELECT DISTINCT ?s1 ?s2
WHERE
{
    ?s2 rdf:type :Set .
    ?s1 rdf:type :Set .
    FILTER(str(?s1) < str(?s2))
    MINUS
    {
        ?s1 rdf:type :Set .
        ?s2 rdf:type :Set .
        ?s1 :member ?x .
        FILTER NOT EXISTS { ?s2 :member ?x . }
    }
    MINUS
    {
        ?s1 rdf:type :Set .
        ?s2 rdf:type :Set .
        ?s2 :member ?x .
        FILTER NOT EXISTS { ?s1 :member ?x . }
    }
}
----

query for subset-03:
Putting this all together, combining subset-01 and set-equality-1.rq, we
get use of nested MINUS.  There must be a better way.

----
PREFIX :    <http://example/>
PREFIX  rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT (?s1 AS ?subset) (?s2 AS ?superset)
WHERE
{
    # All pairs of sets except (S,S)
    ?s2 rdf:type :Set .
    ?s1 rdf:type :Set .
    MINUS {
        # See subset-01 ...
        ?s1 rdf:type :Set .
        ?s2 rdf:type :Set .
        ?s1 :member ?x .
        FILTER ( NOT EXISTS { ?s2 :member ?x . } )
    }
    # Remove those that are the pairs with the same elements.
    # See set-equals-1
    MINUS {
        ?s2 rdf:type :Set .
        ?s1 rdf:type :Set .
        MINUS
        {
            ?s1 rdf:type :Set .
            ?s2 rdf:type :Set .
            ?s1 :member ?x .
            FILTER NOT EXISTS { ?s2 :member ?x . }
        }
        MINUS
        {
            ?s1 rdf:type :Set .
            ?s2 rdf:type :Set .
            ?s2 :member ?x .
            FILTER NOT EXISTS { ?s1 :member ?x . }
        }
    }
}
----

Received on Saturday, 24 July 2010 19:34:30 UTC