Not in RDF

Volume 7, Issue 54; 02 Apr 2004; last modified 08 Oct 2010

There isn’t really a simple “not” operator in RDF. Nevertheless, it’s useful, particularly for establishing default values. So what can we do?

Perhaps, but let's not get bogged down in semantics.

Homer J. Simpson

The semantics of “not” (more accurately, of “complement”) turn out to be tricky to express in RDF, not just in practice, but in theory as well. To understand why, we have to consider world views. RDF generally subscribes to an “open world” view, it accepts that at any given time, the available statements represent limited knowledge and that there’s more out there somewhere, it just hasn’t been encountered yet.

The semantics of “not” require a closed world view: informally, “not” asks if, in the known universe of information, is it the case that some statement has not been made? Consider the following statements:

  1. Maple trees have green leaves.

  2. Red Maple trees have red leaves.

  3. Oak trees have green leaves.

  4. Elm trees have brown bark.

  5. Cherry trees have edible fruit.

Now ponder the question, “which trees do not have green leaves?” If we take those five statements as the total universe of information, the answer is elm and cherry trees, but anyone who’s seen an elm or cherry tree knows that’s not true.

Nevertheless, it is sometimes useful to be able to express “not,” particularly for establishing default values. So what can we do?

Before continuing, let’s pause to reflect on the fact that we can’t express “not” in RDF any more than we can express “blue, italic text” in XML. An XML document is just a tree of information items and an RDF document is just a collection of statements. We need an application to interpret our XML markup to make some text blue and italic. Similarly, we need an application to interpret the semantics of our RDF statements. In this essay, we use cwm to interpret the RDF.

Let’s work through this with a concrete example. We know that most trees have green leaves, so let’s try to make that the default. Here are our four statements, recast as RDF using N3 notation.

Example 1. /2004/04/02/examples/trees.n3

      @prefix tree: <> .
@prefix desc: <> .
@prefix :     <> .

:maple    a tree:Tree; desc:leaves "green" .
:redMaple a tree:Tree; desc:leaves "red" .
:oak      a tree:Tree; desc:leaves "green" .
:elm      a tree:Tree; desc:bark   "brown" .
:cherry   a tree:Tree; desc:fruit  "edible" .


That describes five resources, says they’re each trees as defined by our tree schema, and gives them some descriptive characteristics. We want to find a way to say that if the color of a tree’s leaves is not specified, assume they’re green.

The answer to our “not” question lies in cwm’s log:semantics, log:includes and log:notIncludes operators:


This operator loads an RDF document and returns a formula, a closed set of statements.


Allows us to ask if a particular statement occurs in a given formula.


Allows us to ask if a particular statement does not occur in a given formula.

In other words, these operators allow us to treat a single document as a closed world and that gives the “not” operator something to sink its teeth into.

With these tools, we can construct a rule for cwm to evaluate:

Example 2. /2004/04/02/examples/rules.n3

	@prefix log:  <> .
@prefix tree: <> .
@prefix desc: <> .
@prefix :     <> .

this log:forAll :TREE .

{ <trees.n3> log:semantics ?t .
          ?t log:includes { :TREE a tree:Tree } .
          ?t log:notIncludes { :TREE desc:leaves [] } .
  } => { :TREE tree:leaves "green" } .


What does this mean?


First, we establish that :TREE is a universal variable so that cwm will allow it to range over all the subjects.


Next, we construct a formula from the statements in trees.n3.


At this point, :TREE will range over all the statements in the formula. We want to select only the trees, so we limit the range to those subjects that are tree:Trees.


Our real goal, of course, is to narrow the selection to only those subjects that do not have a desc:leaves property. That’s what log:notIncludes does. In this statement, [] represents a blank node; blank nodes only match if nothing else does. If we wanted to make some other default, for example, for trees that had green leaves, we could use the value "green" here instead. In any event, this statements limits :TREE to range over only those subjects that do not have a tree:leaves property that has a value.


Finally, we end with an implication. For any subject that is selected, we give it the property tree:leaves with the value “green”.

Now we just have to get cwm to apply our rule:

cwm --n3 trees.n3 rules.n3 --think --data > output.n3

And voilá:

Example 3. /2004/04/02/examples/output.n3

      #Processed by Id:,v 1.145 2004/01/29 23:22:22 timbl Exp 
        #    using base
#  Notation3 generation by
#,v 1.151 2004/01/30 17:27:52 timbl Exp

#   Base was:
     @prefix : <> .
     @prefix desc: <> .
     @prefix log: <> .
     @prefix tree: <> .
    :cherry     a tree:Tree;
         tree:leaves "green";
         desc:fruit "edible" .
    :elm     a tree:Tree;
         tree:leaves "green";
         desc:bark "brown" .
    :maple     a tree:Tree;
         desc:leaves "green" .
    :oak     a tree:Tree;
         desc:leaves "green" .
    :redMaple     a tree:Tree;
         desc:leaves "red" .


Our elm and cherry trees have grown green leaves!

Credit where it’s due: several folks on irc://, particularly Dan Connolly, patiently talked me through this the other day. I think Dan pointed me to the answer once before, but I didn’t grok it at the time.


I would interpret that as saying, "If a resource is a tree and the color of its leaves is unknown, then it has green leaves."

If you want to state that a particular true does not have green leaves, I think something like this would work:

:redMaple rdf:type [ a owl:Class ; owl:complementOf [ a owl:Restriction ; owl:onProperty desc:leaves ; owl:hasValue "green" ] ] .

Meaning, ":redMaple belongs to the complement of the class of things with green leaves."

—Posted by David Menendez on 03 Apr 2004 @ 02:38 UTC #

How about this... suppose you declare a prefix/namespace like:

@prefix desc: &lt;; . @prefix descNot: &lt;!&gt; .

"descNot" is the same as the "desc" namespace you originally gave, except that it includes a "!" after the hash. Generated URI references are still legal. In other words, you end up with something like:!leaves

Now, for an engine that understands the negation syntax, this would be detectable. If it also understood the vocabulary, detection of such URI references could be easily optimized.

If the engine doesn't understand the syntax, regardless of whether it understands the vocabulary or not, it will just be treated as an unrecognized predicate, like any other, and handled appropriately.

Or has all this been tried before? Oh, and if you are shaking your head, I should point out that I am relatively new to RDF. If you are nodding, then ignore that last bit. :)

—Posted by Seairth Jacobs on 04 Apr 2004 @ 03:06 UTC #

Another good look at negation in a purely logical, semantic construction is the constructed language lojban.

There are a variety of ways to negate things in lojban, depending on what it is that you're negating.

Doing a quick google search for "lojban negation" yields me:

someone mentioning the conceptual roots of lojban negation:

a quick summary of lojbanic negation:

and lastly, the chapter in the reference grammar on the subject:

I'm sure there are many other good resources out there on the subject, but this is one nice example of prior-thought on the subject.

—Posted by Steve Pomeroy on 04 Apr 2004 @ 10:08 UTC #