001: /******************************************************************
002: * File: TestRETE.java
003: * Created by: Dave Reynolds
004: * Created on: 10-Jun-2003
005: *
006: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
007: * [See end of file]
008: * $Id: TestRETE.java,v 1.14 2008/01/02 12:08:19 andy_seaborne Exp $
009: *****************************************************************/package com.hp.hpl.jena.reasoner.rulesys.test;
010:
011: import java.util.*;
012:
013: import com.hp.hpl.jena.graph.*;
014: import com.hp.hpl.jena.reasoner.*;
015: import com.hp.hpl.jena.reasoner.rulesys.*;
016: import com.hp.hpl.jena.reasoner.rulesys.impl.*;
017: import com.hp.hpl.jena.reasoner.test.TestUtil;
018:
019: import junit.framework.TestCase;
020: import junit.framework.TestSuite;
021:
022: /**
023: *
024: * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
025: * @version $Revision: 1.14 $ on $Date: 2008/01/02 12:08:19 $
026: */
027: public class TestRETE extends TestCase {
028:
029: // Useful constants
030: Node_RuleVariable x = new Node_RuleVariable("x", 0);
031: Node_RuleVariable y = new Node_RuleVariable("y", 1);
032: Node_RuleVariable z = new Node_RuleVariable("z", 2);
033: Node p = Node.createURI("p");
034: Node q = Node.createURI("q");
035: Node a = Node.createURI("a");
036: Node b = Node.createURI("b");
037: Node c = Node.createURI("c");
038: Node d = Node.createURI("d");
039: Node e = Node.createURI("e");
040: Node r = Node.createURI("r");
041: Node s = Node.createURI("s");
042: Node n1 = Node.createURI("n1");
043: Node n2 = Node.createURI("n2");
044: Node n3 = Node.createURI("n3");
045: Node n4 = Node.createURI("n4");
046: Node res = Node.createURI("res");
047:
048: /**
049: * Boilerplate for junit
050: */
051: public TestRETE(String name) {
052: super (name);
053: }
054:
055: /**
056: * Boilerplate for junit.
057: * This is its own test suite
058: */
059: public static TestSuite suite() {
060: return new TestSuite(TestRETE.class);
061: // TestSuite suite = new TestSuite();
062: // suite.addTest(new TestRETE( "foo" ));
063: // return suite;
064: }
065:
066: /**
067: * Test clause compiler and clause filter implementation.
068: */
069: public void testClauseFilter() {
070: doTestClauseFilter(new TriplePattern(a, p, x), new Triple(a, p,
071: b), new Node[] { b, null, null });
072: doTestClauseFilter(new TriplePattern(x, p, b), new Triple(a, p,
073: b), new Node[] { a, null, null });
074: doTestClauseFilter(new TriplePattern(a, p, x), new Triple(b, p,
075: a), null);
076: doTestClauseFilter(new TriplePattern(a, p, x), new Triple(a, q,
077: a), null);
078: doTestClauseFilter(new TriplePattern(x, p, x), new Triple(a, p,
079: a), new Node[] { a, null, null });
080: doTestClauseFilter(new TriplePattern(x, p, x), new Triple(a, p,
081: b), null);
082: doTestClauseFilter(new TriplePattern(a, p, Functor
083: .makeFunctorNode("f", new Node[] { x, c })),
084: new Triple(a, p, a), null);
085: doTestClauseFilter(new TriplePattern(a, p, x), new Triple(a, p,
086: Functor.makeFunctorNode("f", new Node[] { b, c })),
087: new Node[] {
088: Functor.makeFunctorNode("f",
089: new Node[] { b, c }), null, null });
090: doTestClauseFilter(new TriplePattern(a, p, Functor
091: .makeFunctorNode("g", new Node[] { x, c })),
092: new Triple(a, p, Functor.makeFunctorNode("f",
093: new Node[] { b, c })), null);
094: doTestClauseFilter(new TriplePattern(a, p, Functor
095: .makeFunctorNode("f", new Node[] { x, c })),
096: new Triple(a, p, Functor.makeFunctorNode("f",
097: new Node[] { b, c })), new Node[] { b, null,
098: null });
099: doTestClauseFilter(new TriplePattern(x, p, Functor
100: .makeFunctorNode("f", new Node[] { x, c })),
101: new Triple(a, p, Functor.makeFunctorNode("f",
102: new Node[] { a, c })), new Node[] { a, null,
103: null });
104: doTestClauseFilter(new TriplePattern(x, p, Functor
105: .makeFunctorNode("f", new Node[] { x, c })),
106: new Triple(a, p, Functor.makeFunctorNode("f",
107: new Node[] { b, c })), null);
108: }
109:
110: /**
111: * Helper for testing clause filters.
112: */
113: private void doTestClauseFilter(TriplePattern pattern, Triple test,
114: Node[] expected) {
115: RETETestNode tnode = new RETETestNode();
116: RETEClauseFilter cf = RETEClauseFilter.compile(pattern, 3,
117: new LinkedList());
118: cf.setContinuation(tnode);
119: cf.fire(test, true);
120: if (expected == null) {
121: assertTrue(tnode.firings == 0);
122: } else {
123: assertTrue(tnode.firings == 1);
124: assertTrue(tnode.isAdd);
125: assertEquals(new BindingVector(expected), tnode.env);
126: }
127: }
128:
129: /**
130: * Inner class usable as a dummy RETENode end point for testing.
131: */
132: protected static class RETETestNode implements RETESinkNode {
133: /** The environment passed in */
134: BindingVector env;
135:
136: /** The mode flag */
137: boolean isAdd;
138:
139: /** True if the fire has been called */
140: int firings = 0;
141:
142: /**
143: * Propagate a token to this node.
144: * @param env a set of variable bindings for the rule being processed.
145: * @param isAdd distinguishes between add and remove operations.
146: */
147: public void fire(BindingVector env, boolean isAdd) {
148: firings++;
149: this .env = env;
150: this .isAdd = isAdd;
151: }
152:
153: /**
154: * Clone this node in the network across to a different context.
155: * @param netCopy a map from RETENodes to cloned instance so far.
156: * @param context the new context to which the network is being ported
157: */
158: public RETENode clone(Map netCopy, RETERuleContext context) {
159: // Dummy, not used in testing
160: return this ;
161: }
162:
163: }
164:
165: /**
166: * Minimal rule tester to check basic pattern match.
167: */
168: public void testRuleMatcher() {
169: doRuleTest(
170: "[r1: (?a p ?b), (?b q ?c) -> (?a, q, ?c)]"
171: + "[r2: (?a p ?b), (?b p ?c) -> (?a, p, ?c)]"
172: + "[r3: (?a p ?a), (n1 p ?c), (n1, p, ?a) -> (?a, p, ?c)]"
173: + "[r4: (n4 ?p ?a) -> (n4, ?a, ?p)]",
174: new Triple[] { new Triple(n1, p, n2),
175: new Triple(n2, p, n3), new Triple(n2, q, n3),
176: new Triple(n4, p, n4) }, new Triple[] {
177: new Triple(n1, p, n2), new Triple(n2, p, n3),
178: new Triple(n2, q, n3), new Triple(n4, p, n4),
179: new Triple(n1, p, n3), new Triple(n1, q, n3),
180: new Triple(n4, n4, p), });
181:
182: doRuleTest("[testRule1: (n1 p ?a) -> (n2, p, ?a)]"
183: + "[testRule2: (n1 q ?a) -> (n2, q, ?a)]"
184: + "[testRule3: (n2 p ?a), (n2 q ?a) -> (res p ?a)]"
185: + "[axiom1: -> (n1 p n3)]", new Triple[] {},
186: new Triple[] { new Triple(n1, p, n3),
187: new Triple(n2, p, n3) });
188:
189: doRuleTest("[testRule1: (n1 p ?a) -> (n2, p, ?a)]"
190: + "[testRule2: (n1 q ?a) -> (n2, q, ?a)]"
191: + "[testRule3: (n2 p ?a), (n2 q ?a) -> (res p ?a)]"
192: + "[axiom1: -> (n1 p n3)]", new Triple[] {
193: new Triple(n1, q, n4), new Triple(n1, q, n3) },
194: new Triple[] { new Triple(n1, p, n3),
195: new Triple(n2, p, n3), new Triple(n1, q, n4),
196: new Triple(n2, q, n4), new Triple(n1, q, n3),
197: new Triple(n2, q, n3), new Triple(res, p, n3) });
198: doRuleTest("[rule1: (?x p ?y), (?x q ?y) -> remove(0)]",
199: new Triple[] { new Triple(n1, p, Util.makeIntNode(1)),
200: new Triple(n1, p, Util.makeIntNode(2)),
201: new Triple(n1, q, Util.makeIntNode(2)) },
202: new Triple[] { new Triple(n1, p, Util.makeIntNode(1)),
203: new Triple(n1, q, Util.makeIntNode(2)) });
204: }
205:
206: /**
207: * Perform a rule test on the raw RETE engine. This requires some fiddling
208: * with dummy parent graphs.
209: */
210: private void doRuleTest(String rules, Triple[] adds,
211: Triple[] expected) {
212: List ruleList = Rule.parseRules(rules);
213: BasicForwardRuleInfGraph infgraph = new BasicForwardRuleInfGraph(
214: null, new ArrayList(), null, Factory.createGraphMem());
215: // infgraph.setTraceOn(true);
216: RETEEngine engine = new RETEEngine(infgraph, ruleList);
217: infgraph.prepare();
218: engine.init(true, new FGraph(Factory.createGraphMem()));
219: for (int i = 0; i < adds.length; i++) {
220: engine.addTriple(adds[i], true);
221: }
222: engine.runAll();
223: TestUtil.assertIteratorValues(this , infgraph.find(null, null,
224: null), expected);
225: }
226:
227: /**
228: * Check that the rulestate cloning keeps two descendent graphs independent.
229: *
230: */
231: public void testRuleClone() {
232: String rules = "[testRule1: (a p ?x) (b p ?x) -> (n1 p ?x) ]"
233: + "[testRule2: (?x q ?y) -> (?x p ?y)]";
234: List ruleList = Rule.parseRules(rules);
235: Graph schema = Factory.createGraphMem();
236: schema.add(new Triple(a, q, c));
237: schema.add(new Triple(a, q, d));
238:
239: Graph data1 = Factory.createGraphMem();
240: data1.add(new Triple(b, q, c));
241:
242: Graph data2 = Factory.createGraphMem();
243: data2.add(new Triple(b, q, d));
244:
245: GenericRuleReasoner reasoner = new GenericRuleReasoner(ruleList);
246: reasoner.setMode(GenericRuleReasoner.FORWARD_RETE);
247: Reasoner boundReasoner = reasoner.bindSchema(schema);
248: InfGraph infgraph1 = boundReasoner.bind(data1);
249: InfGraph infgraph2 = boundReasoner.bind(data2);
250:
251: TestUtil.assertIteratorValues(this , infgraph1.find(null, p,
252: null), new Triple[] { new Triple(a, p, c),
253: new Triple(a, p, d), new Triple(b, p, c),
254: new Triple(n1, p, c) });
255:
256: TestUtil.assertIteratorValues(this , infgraph2.find(null, p,
257: null), new Triple[] { new Triple(a, p, c),
258: new Triple(a, p, d), new Triple(b, p, d),
259: new Triple(n1, p, d) });
260: }
261: }
262:
263: /*
264: (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
265: All rights reserved.
266:
267: Redistribution and use in source and binary forms, with or without
268: modification, are permitted provided that the following conditions
269: are met:
270:
271: 1. Redistributions of source code must retain the above copyright
272: notice, this list of conditions and the following disclaimer.
273:
274: 2. Redistributions in binary form must reproduce the above copyright
275: notice, this list of conditions and the following disclaimer in the
276: documentation and/or other materials provided with the distribution.
277:
278: 3. The name of the author may not be used to endorse or promote products
279: derived from this software without specific prior written permission.
280:
281: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
282: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
283: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
284: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
285: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
286: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
287: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
288: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
289: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
290: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
291: */
|