4.9.Duplicate Facts It is desirable to prevent SWORIER from generating the same fact more than once. To demonstrate the rationale, consider the program in the Table 12a. The query, fact(X, c, 1) would cause the system to return two copies of fact(a, c, 1); one because of rule 1, and the other through the interaction between rules 2 and 3. Although it is not difficult to remove repetitive facts in a post-processing procedure, a significant cost in efficiency can still result. 

Consider, for example, the query fact3(a, c, 3). To determine the answer, the system tests the first term in the body of line 3, fact(a, c, 1), and it succeeds twice. Then the system runs two tests on the second term, fact(a, c, 1), each time finding two results. Thus, the third term, slow(c), must be tested four times, unnecessarily quadrupling the time spent processing that term. And for the query fact3(a, c, 5), the slow(c)test is run 16 times. 

So it should be clear that, when duplicate facts are generated, they can potentially slow down the program significantly. 

To block duplicate facts, we can add the term, not(Y=c) to rule 2, as shown in Table 12b. This prevents fact(a, c, 1) from being generated via rule 2. But given the query fact(a, Y, 2), the system fails to return fact(a, b, 2), which should be proven by rules 2 and 3. This is because, in order to test not(Y=c), Prolog tries to prove Y=c. But this is easy, since Y is an unbound variable, so it can be set to c. This causes Y=c to succeed, and so not(Y=c) fails, and the rule is incorrectly blocked. 

 By changing rule 2 as shown in Table 12c, we can insure that Y is bound before not(Y=c) is tested. Now the program works correctly, and the duplicates are blocked. But unfortunately, the system must investigate the fact(X, Y, N-1) term, even if the block, not(Y=c), is doomed to fail. In addition, rule 2 is no longer tail recursive, so the Prolog compiler cannot utilize a significant efficiency improvement. 

![0_image_0.png](0_image_0.png)

| 1. fact(a, c, N) :- N>=0. 2. fact(X, Y, N) :- N>0, fact(X, Y, N-1).  3. fact3(X, Y, N) :- fact(a, Y, N-2), fact(X, c, N-2), slow(Y). 1. fact(a, c, N) :- N>=0. 2. fact(X, Y, N) :- not(Y=c), fact(X, Y, N-1).  3. fact(X, b, 1).   |                                                                                            |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
| c.                                                                                                                                                                                                                                 | 1. fact(a, c, N) :- N>=0. 2. fact(X, Y, N) :- N>0, fact(X, Y, N-1), not(Y=c).              |
| d.                                                                                                                                                                                                                                 | 1. fact(a, c, N) :- N>=0. 2. fact(X, Y, N) :- isLetter(Y), not(Y=c), N>0, fact(X, Y, N-1). |

## 4.10.Cyclic Hierarchies

 Cyclic class hierarchies and cyclic property hierarchies can be problematic. Suppose the given OWL ontology includes the facts shown in Table 13a. Then the computation of the transitive closure of subclass, using the rules from Table 13b, produces an infinite number of responses to the query, isSubClassOf(X, Y), as the system loops around and around the cycle. Even though we may claim that a cyclic hierarchy is erroneous, we cannot prevent the developer from creating one. So SWORIER should be able to handle it. 