001: /******************************************************************
002: * File: TestGenericRules.java
003: * Created by: Dave Reynolds
004: * Created on: 08-Jun-2003
005: *
006: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
007: * [See end of file]
008: * $Id: TestGenericRules.java,v 1.25 2008/01/02 12:08:20 andy_seaborne Exp $
009: *****************************************************************/package com.hp.hpl.jena.reasoner.rulesys.test;
010:
011: import com.hp.hpl.jena.rdf.model.*;
012: import com.hp.hpl.jena.reasoner.*;
013: import com.hp.hpl.jena.reasoner.rulesys.*;
014: import com.hp.hpl.jena.reasoner.test.TestUtil;
015: import com.hp.hpl.jena.util.PrintUtil;
016: import com.hp.hpl.jena.vocabulary.RDF;
017: import com.hp.hpl.jena.vocabulary.RDFS;
018: import com.hp.hpl.jena.vocabulary.ReasonerVocabulary;
019: import com.hp.hpl.jena.graph.*;
020:
021: import junit.framework.TestCase;
022: import junit.framework.TestSuite;
023:
024: import java.util.*;
025:
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028:
029: /**
030: * Test the packaging of all the reasoners into the GenericRuleReasoner.
031: * The other tests check out this engine. These tests just need to touch
032: * enough to validate the packaging.
033: *
034: * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
035: * @version $Revision: 1.25 $ on $Date: 2008/01/02 12:08:20 $
036: */
037: public class TestGenericRules extends TestCase {
038:
039: protected static Log logger = LogFactory.getLog(TestFBRules.class);
040:
041: // Useful constants
042: Node p = Node.createURI("p");
043: Node q = Node.createURI("q");
044: Node r = Node.createURI("r");
045: Node s = Node.createURI("s");
046: Node t = Node.createURI("t");
047: Node a = Node.createURI("a");
048: Node b = Node.createURI("b");
049: Node c = Node.createURI("c");
050: Node d = Node.createURI("d");
051: Node C1 = Node.createURI("C1");
052: Node C2 = Node.createURI("C2");
053: Node C3 = Node.createURI("C3");
054: Node ty = RDF.Nodes.type;
055: Node sC = RDFS.Nodes.subClassOf;
056:
057: List ruleList = Rule
058: .parseRules("[r1: (?a p ?b), (?b p ?c) -> (?a p ?c)]"
059: + "[r2: (?a q ?b) -> (?a p ?c)]"
060: + "-> table(p). -> table(q).");
061: Triple[] ans = new Triple[] { new Triple(a, p, b),
062: new Triple(b, p, c), new Triple(a, p, c) };
063:
064: /**
065: * Boilerplate for junit
066: */
067: public TestGenericRules(String name) {
068: super (name);
069: }
070:
071: /**
072: * Boilerplate for junit.
073: * This is its own test suite
074: */
075: public static TestSuite suite() {
076: return new TestSuite(TestGenericRules.class);
077: // TestSuite suite = new TestSuite();
078: // suite.addTest(new TestGenericRules( "testAddRemove2" ));
079: // return suite;
080: }
081:
082: /**
083: * Minimal rule tester to check basic pattern match, forward style.
084: */
085: public void testForward() {
086: Graph test = Factory.createGraphMem();
087: test.add(new Triple(a, p, b));
088: test.add(new Triple(b, p, c));
089:
090: GenericRuleReasoner reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory
091: .theInstance().create(null);
092: reasoner.setRules(ruleList);
093: reasoner.setMode(GenericRuleReasoner.FORWARD);
094:
095: // Check data bind version
096: InfGraph infgraph = reasoner.bind(test);
097: TestUtil.assertIteratorValues(this , infgraph
098: .find(null, p, null), ans);
099:
100: // Check schema bind version
101: infgraph = reasoner.bindSchema(test).bind(
102: Factory.createGraphMem());
103: TestUtil.assertIteratorValues(this , infgraph
104: .find(null, p, null), ans);
105: }
106:
107: /**
108: * Minimal rule tester to check basic pattern match, backward style.
109: */
110: public void testBackward() {
111: Graph test = Factory.createGraphMem();
112: test.add(new Triple(a, p, b));
113: test.add(new Triple(b, p, c));
114:
115: GenericRuleReasoner reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory
116: .theInstance().create(null);
117: reasoner.setRules(ruleList);
118: reasoner.setMode(GenericRuleReasoner.BACKWARD);
119:
120: // Check data bind version
121: InfGraph infgraph = reasoner.bind(test);
122: TestUtil.assertIteratorValues(this , infgraph
123: .find(null, p, null), ans);
124:
125: // Check schema bind version
126: infgraph = reasoner.bindSchema(test).bind(
127: Factory.createGraphMem());
128: TestUtil.assertIteratorValues(this , infgraph
129: .find(null, p, null), ans);
130: }
131:
132: /**
133: * Test example hybrid rule.
134: */
135: public void testHybrid() {
136: Graph data = Factory.createGraphMem();
137: data.add(new Triple(a, r, b));
138: data.add(new Triple(p, ty, s));
139: List rules = Rule
140: .parseRules("[a1: -> (a rdf:type t)]"
141: + "[r0: (?x r ?y) -> (?x p ?y)]"
142: + "[r1: (?p rdf:type s) -> [r1b: (?x ?p ?y) <- (?y ?p ?x)]]"
143: + "[r2: (?p rdf:type s) -> [r2b: (?x ?p ?x) <- (?x rdf:type t)]]"
144: + "-> tableAll().");
145: GenericRuleReasoner reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory
146: .theInstance().create(null);
147: reasoner.setRules(rules);
148: reasoner.setMode(GenericRuleReasoner.HYBRID);
149:
150: InfGraph infgraph = reasoner.bind(data);
151: infgraph.setDerivationLogging(true);
152: TestUtil.assertIteratorValues(this , infgraph
153: .find(null, p, null), new Object[] {
154: new Triple(a, p, a), new Triple(a, p, b),
155: new Triple(b, p, a) });
156:
157: // Check derivation tracing as well
158: Iterator di = infgraph.getDerivation(new Triple(b, p, a));
159: assertTrue(di.hasNext());
160: RuleDerivation d = (RuleDerivation) di.next();
161: // java.io.PrintWriter out = new java.io.PrintWriter(System.out);
162: // d.printTrace(out, true);
163: // out.close();
164: assertTrue(d.getRule().getName().equals("r1b"));
165: TestUtil.assertIteratorValues(this , d.getMatches().iterator(),
166: new Object[] { new Triple(a, p, b) });
167: assertTrue(!di.hasNext());
168: }
169:
170: /**
171: * Test early detection of illegal backward rules.
172: */
173: public void testBRuleErrorHandling() {
174: Graph data = Factory.createGraphMem();
175: List rules = Rule
176: .parseRules("[a1: -> [(?x eg:p ?y) (?x eg:q ?y) <- (?x eg:r ?y)]]");
177: boolean foundException = false;
178: try {
179: GenericRuleReasoner reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory
180: .theInstance().create(null);
181: reasoner.setRules(rules);
182: reasoner.setMode(GenericRuleReasoner.HYBRID);
183: InfGraph infgraph = reasoner.bind(data);
184: infgraph.prepare();
185: } catch (ReasonerException e) {
186: foundException = true;
187: }
188: assertTrue("Catching use of multi-headed brules",
189: foundException);
190: }
191:
192: /**
193: * Test example parameter setting
194: */
195: public void testParameters() {
196: Graph data = Factory.createGraphMem();
197: data.add(new Triple(a, r, b));
198: data.add(new Triple(p, ty, s));
199:
200: Model m = ModelFactory.createDefaultModel();
201: Resource configuration = m
202: .createResource(GenericRuleReasonerFactory.URI);
203: configuration.addProperty(
204: ReasonerVocabulary.PROPderivationLogging, "true");
205: configuration.addProperty(ReasonerVocabulary.PROPruleMode,
206: "hybrid");
207: configuration.addProperty(ReasonerVocabulary.PROPruleSet,
208: "testing/reasoners/genericRuleTest.rules");
209: GenericRuleReasoner reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory
210: .theInstance().create(configuration);
211:
212: InfGraph infgraph = reasoner.bind(data);
213: TestUtil.assertIteratorValues(this , infgraph
214: .find(null, p, null), new Object[] {
215: new Triple(a, p, a), new Triple(a, p, b),
216: new Triple(b, p, a) });
217:
218: // Check derivation tracing as well
219: Iterator di = infgraph.getDerivation(new Triple(b, p, a));
220: assertTrue(di.hasNext());
221: RuleDerivation d = (RuleDerivation) di.next();
222: assertTrue(d.getRule().getName().equals("r1b"));
223: TestUtil.assertIteratorValues(this , d.getMatches().iterator(),
224: new Object[] { new Triple(a, p, b) });
225: assertTrue(!di.hasNext());
226:
227: // Check retrieval of configuration
228: Model m2 = ModelFactory.createDefaultModel();
229: Resource newConfig = m2.createResource();
230: reasoner.addDescription(m2, newConfig);
231: TestUtil
232: .assertIteratorValues(
233: this ,
234: newConfig.listProperties(),
235: new Statement[] {
236: m2
237: .createStatement(
238: newConfig,
239: ReasonerVocabulary.PROPderivationLogging,
240: "true"),
241: m2
242: .createStatement(
243: newConfig,
244: ReasonerVocabulary.PROPruleMode,
245: "hybrid"),
246: m2
247: .createStatement(
248: newConfig,
249: ReasonerVocabulary.PROPruleSet,
250: "testing/reasoners/genericRuleTest.rules") });
251:
252: // Manual reconfig and check retrieval of changes
253: reasoner.setParameter(ReasonerVocabulary.PROPderivationLogging,
254: "false");
255: newConfig = m2.createResource();
256: reasoner.addDescription(m2, newConfig);
257: TestUtil
258: .assertIteratorValues(
259: this ,
260: newConfig.listProperties(),
261: new Statement[] {
262: m2
263: .createStatement(
264: newConfig,
265: ReasonerVocabulary.PROPderivationLogging,
266: "false"),
267: m2
268: .createStatement(
269: newConfig,
270: ReasonerVocabulary.PROPruleMode,
271: "hybrid"),
272: m2
273: .createStatement(
274: newConfig,
275: ReasonerVocabulary.PROPruleSet,
276: "testing/reasoners/genericRuleTest.rules") });
277:
278: // Mutiple rule file loading
279: m = ModelFactory.createDefaultModel();
280: configuration = m
281: .createResource(GenericRuleReasonerFactory.URI);
282: configuration.addProperty(ReasonerVocabulary.PROPruleMode,
283: "hybrid");
284: configuration.addProperty(ReasonerVocabulary.PROPruleSet,
285: "testing/reasoners/ruleset1.rules");
286: configuration.addProperty(ReasonerVocabulary.PROPruleSet,
287: "testing/reasoners/ruleset2.rules");
288: reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory
289: .theInstance().create(configuration);
290:
291: infgraph = reasoner.bind(Factory.createGraphMem());
292: Node an = Node.createURI(PrintUtil.egNS + "a");
293: Node C = Node.createURI(PrintUtil.egNS + "C");
294: Node D = Node.createURI(PrintUtil.egNS + "D");
295: TestUtil.assertIteratorValues(this , infgraph.find(null, null,
296: null), new Object[] {
297: new Triple(an, RDF.Nodes.type, C),
298: new Triple(an, RDF.Nodes.type, D), });
299:
300: // Test that the parameter initialization is not be overridden by subclasses
301: m = ModelFactory.createDefaultModel();
302: configuration = m
303: .createResource(GenericRuleReasonerFactory.URI);
304: configuration.addProperty(
305: ReasonerVocabulary.PROPenableTGCCaching, m
306: .createLiteral("true"));
307: reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory
308: .theInstance().create(configuration);
309: InfModel im = ModelFactory.createInfModel(reasoner,
310: ModelFactory.createDefaultModel());
311: Resource Ac = im.createResource(PrintUtil.egNS + "A");
312: Resource Bc = im.createResource(PrintUtil.egNS + "B");
313: Resource Cc = im.createResource(PrintUtil.egNS + "C");
314: im.add(Ac, RDFS.subClassOf, Bc);
315: im.add(Bc, RDFS.subClassOf, Cc);
316: assertTrue("TGC enabled correctly", im.contains(Ac,
317: RDFS.subClassOf, Cc));
318:
319: }
320:
321: /**
322: * Check that the use of typed literals in the configuration also works
323: */
324: public void testTypedConfigParameters() {
325: Model m = ModelFactory.createDefaultModel();
326: Resource configuration = m
327: .createResource(GenericRuleReasonerFactory.URI);
328: configuration.addProperty(
329: ReasonerVocabulary.PROPenableTGCCaching, m
330: .createTypedLiteral(Boolean.TRUE));
331:
332: GenericRuleReasoner reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory
333: .theInstance().create(configuration);
334: InfModel im = ModelFactory.createInfModel(reasoner,
335: ModelFactory.createDefaultModel());
336: Resource Ac = im.createResource(PrintUtil.egNS + "A");
337: Resource Bc = im.createResource(PrintUtil.egNS + "B");
338: Resource Cc = im.createResource(PrintUtil.egNS + "C");
339: im.add(Ac, RDFS.subClassOf, Bc);
340: im.add(Bc, RDFS.subClassOf, Cc);
341: assertTrue("TGC enabled correctly", im.contains(Ac,
342: RDFS.subClassOf, Cc));
343: }
344:
345: /**
346: * Test control of functor filtering
347: */
348: public void testHybridFunctorFilter() {
349: Graph data = Factory.createGraphMem();
350: data.add(new Triple(a, r, b));
351: data.add(new Triple(a, p, s));
352: List rules = Rule
353: .parseRules("[r0: (?x r ?y) (?x p ?z) -> (?x q func(?y, ?z)) ]");
354: GenericRuleReasoner reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory
355: .theInstance().create(null);
356: reasoner.setRules(rules);
357: reasoner.setMode(GenericRuleReasoner.HYBRID);
358:
359: InfGraph infgraph = reasoner.bind(data);
360: TestUtil.assertIteratorValues(this , infgraph
361: .find(null, q, null), new Object[] {});
362:
363: reasoner.setFunctorFiltering(false);
364: infgraph = reasoner.bind(data);
365: TestUtil
366: .assertIteratorValues(this , infgraph
367: .find(null, q, null),
368: new Object[] { new Triple(a, q, Functor
369: .makeFunctorNode("func", new Node[] {
370: b, s })) });
371: }
372:
373: /**
374: * Test the @prefix and @include extensions to the rule parser
375: */
376: public void testExtendedRuleParser() {
377: List rules = Rule
378: .rulesFromURL("file:testing/reasoners/ruleParserTest1.rules");
379: GenericRuleReasoner reasoner = new GenericRuleReasoner(rules);
380: reasoner.setTransitiveClosureCaching(true);
381: Model base = ModelFactory.createDefaultModel();
382: InfModel m = ModelFactory.createInfModel(reasoner, base);
383:
384: // Check prefix case
385: String NS1 = "http://jena.hpl.hp.com/newprefix#";
386: String NS2 = "http://jena.hpl.hp.com/newprefix2#";
387: String NS3 = "http://jena.hpl.hp.com/newprefix3#";
388: Resource A = m.getResource(NS1 + "A");
389: Resource C = m.getResource(NS1 + "C");
390: Property p = m.getProperty(NS2 + "p");
391: Property a = m.getProperty(NS3 + "a");
392: Resource foo = m.getResource(NS1 + "foo");
393: assertTrue("@prefix test", m.contains(A, p, foo));
394:
395: // Check RDFS rule inclusion
396: assertTrue("@include RDFS test", m.contains(A, RDFS.subClassOf,
397: C));
398: assertTrue("@include test", m.contains(a, a, a));
399: }
400:
401: /**
402: * Test add/remove support
403: */
404: public void testAddRemove() {
405: doTestAddRemove(false);
406: doTestAddRemove(true);
407: }
408:
409: /**
410: * Internals of add/remove test.
411: * @param useTGC set to true to use transitive caching
412: */
413: public void doTestAddRemove(boolean useTGC) {
414: Graph data = Factory.createGraphMem();
415: data.add(new Triple(a, p, C1));
416: data.add(new Triple(C1, sC, C2));
417: data.add(new Triple(C2, sC, C3));
418: List rules = Rule
419: .parseRules("-> table(rdf:type)."
420: + "[r1: (?x p ?c) -> (?x rdf:type ?c)] "
421: + "[rdfs9: (?x rdfs:subClassOf ?y) -> [ (?a rdf:type ?y) <- (?a rdf:type ?x)] ]");
422: if (!useTGC) {
423: rules
424: .add(Rule
425: .parseRule("[rdfs8: (?a rdfs:subClassOf ?b), (?b rdfs:subClassOf ?c) -> (?a rdfs:subClassOf ?c)] "));
426: }
427: GenericRuleReasoner reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory
428: .theInstance().create(null);
429: reasoner.setRules(rules);
430: // reasoner.setTraceOn(true);
431: reasoner.setMode(GenericRuleReasoner.HYBRID);
432: reasoner.setTransitiveClosureCaching(useTGC);
433:
434: InfGraph infgraph = reasoner.bind(data);
435: TestUtil.assertIteratorValues(this , infgraph.find(a, ty, null),
436: new Object[] { new Triple(a, ty, C1),
437: new Triple(a, ty, C2), new Triple(a, ty, C3) });
438:
439: logger.debug("Checkpoint 1");
440: infgraph.delete(new Triple(C1, sC, C2));
441: TestUtil.assertIteratorValues(this , infgraph.find(a, ty, null),
442: new Object[] { new Triple(a, ty, C1) });
443:
444: logger.debug("Checkpoint 2");
445: infgraph.add(new Triple(C1, sC, C3));
446: infgraph.add(new Triple(b, p, C2));
447: TestUtil.assertIteratorValues(this , infgraph.find(a, ty, null),
448: new Object[] { new Triple(a, ty, C1),
449: new Triple(a, ty, C3) });
450: TestUtil.assertIteratorValues(this , infgraph.find(b, ty, null),
451: new Object[] { new Triple(b, ty, C2),
452: new Triple(b, ty, C3) });
453:
454: TestUtil.assertIteratorValues(this ,
455: data.find(null, null, null),
456: new Object[] { new Triple(a, p, C1),
457: new Triple(b, p, C2), new Triple(C2, sC, C3),
458: new Triple(C1, sC, C3) });
459: }
460:
461: /**
462: * Resolve a bug using remove in rules themselves.
463: */
464: public void testAddRemove2() {
465: Graph data = Factory.createGraphMem();
466: data.add(new Triple(a, p, Util.makeIntNode(0)));
467: List rules = Rule
468: .parseRules("(?x p ?v)-> (?x q inc(1, a)).\n"
469: + "(?x p ?v)-> (?x q inc(1, b)).\n"
470: + "(?x p ?v) (?x q inc(?i, ?t)) noValue(?x r ?t) sum(?v, ?i, ?s) -> remove(0,1), (?x p ?s) (?x r ?t).\n");
471:
472: // Older version, relied on implicit rule ordering in Jena2.2 not value in 2.3
473: // "(?x p ?v) noValue(a r 1) -> (?x q inc(1, a)) (?x r 1).\n" +
474: // "(?x p ?v) noValue(a r 2) -> (?x q inc(1, b)) (?x r 2).\n" +
475: // "(?x p ?v) (?x q inc(?i, ?t)) sum(?v, ?i, ?s) -> remove(0,1), (?x p ?s).\n");
476:
477: GenericRuleReasoner reasoner = (GenericRuleReasoner) GenericRuleReasonerFactory
478: .theInstance().create(null);
479: reasoner.setRules(rules);
480: reasoner.setMode(GenericRuleReasoner.FORWARD_RETE);
481:
482: InfGraph infgraph = reasoner.bind(data);
483: TestUtil.assertIteratorValues(this , infgraph.find(a, p, null),
484: new Object[] { new Triple(a, p, Util.makeIntNode(2)) });
485: }
486: }
487:
488: /*
489: (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
490: All rights reserved.
491:
492: Redistribution and use in source and binary forms, with or without
493: modification, are permitted provided that the following conditions
494: are met:
495:
496: 1. Redistributions of source code must retain the above copyright
497: notice, this list of conditions and the following disclaimer.
498:
499: 2. Redistributions in binary form must reproduce the above copyright
500: notice, this list of conditions and the following disclaimer in the
501: documentation and/or other materials provided with the distribution.
502:
503: 3. The name of the author may not be used to endorse or promote products
504: derived from this software without specific prior written permission.
505:
506: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
507: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
508: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
509: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
510: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
511: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
512: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
513: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
514: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
515: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
516: */
|