001: package org.drools.rule;
002:
003: /*
004: * Copyright 2005 JBoss Inc
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import java.io.File;
020: import java.io.FileOutputStream;
021: import java.io.IOException;
022: import java.io.ObjectInputStream;
023: import java.io.ObjectOutputStream;
024:
025: import org.drools.DroolsTestCase;
026: import org.drools.base.ClassObjectType;
027: import org.drools.spi.ObjectType;
028:
029: public class LogicTransformerTest extends DroolsTestCase {
030: /**
031: * (a||b)&&c
032: *
033: * <pre>
034: * and
035: * / \
036: * or c
037: * / \
038: * a b
039: * </pre>
040: *
041: * Should become (a&&c)||(b&&c)
042: *
043: * <pre>
044: *
045: * or
046: * / \
047: * / \
048: * / \
049: * and and
050: * / \ / \
051: * a c b c
052: * </pre>
053: */
054: public void testSingleOrAndOrTransformation()
055: throws InvalidPatternException {
056: final ObjectType type = new ClassObjectType(String.class);
057: final Pattern a = new Pattern(0, type, "a");
058: final Pattern b = new Pattern(1, type, "b");
059: final Pattern c = new Pattern(2, type, "c");
060:
061: final GroupElement or = GroupElementFactory.newOrInstance();
062: or.addChild(a);
063: or.addChild(b);
064:
065: final GroupElement parent = GroupElementFactory
066: .newAndInstance();
067: parent.addChild(or);
068: parent.addChild(c);
069:
070: LogicTransformer.getInstance().applyOrTransformation(parent);
071:
072: assertLength(2, parent.getChildren());
073: assertEquals(GroupElement.class, parent.getChildren().get(0)
074: .getClass());
075: assertEquals(GroupElement.class, parent.getChildren().get(1)
076: .getClass());
077:
078: final GroupElement and1 = (GroupElement) parent.getChildren()
079: .get(0);
080: assertTrue(and1.isAnd());
081:
082: // transformation MUST keep the order
083: assertEquals(a, and1.getChildren().get(0));
084: assertEquals(c, and1.getChildren().get(1));
085:
086: final GroupElement and2 = (GroupElement) parent.getChildren()
087: .get(1);
088: assertEquals(b, and2.getChildren().get(0));
089: assertEquals(c, and2.getChildren().get(1));
090:
091: }
092:
093: /**
094: * (a||b)&&c
095: *
096: * <pre>
097: * And
098: * /|\ \__
099: * _/ | \_ \_
100: * / | \ \
101: * or | or not
102: * / \ | / \ |
103: * a b c d e f
104: * </pre>
105: *
106: * Should become (a&&c)||(b&&c)
107: *
108: * <pre>
109: * /\
110: * _/ \_
111: * / \
112: * _/| |\_
113: * __/ | | \__
114: * __/ | | \__
115: * / | | \
116: * and and and and
117: * /||\ /||\ /||\ /||\
118: * a cd Not a ce Not b cd Not b ce Not
119: * | | | |
120: * f f f f
121: * </pre>
122: */
123: public void testMultipleOrAndOrTransformation()
124: throws InvalidPatternException {
125: final ObjectType type = new ClassObjectType(String.class);
126: final Pattern a = new Pattern(0, type, "a");
127: final Pattern b = new Pattern(1, type, "b");
128: final Pattern c = new Pattern(2, type, "c");
129: final Pattern d = new Pattern(3, type, "d");
130: final Pattern e = new Pattern(4, type, "e");
131: final Pattern f = new Pattern(5, type, "f");
132:
133: final GroupElement parent = GroupElementFactory
134: .newAndInstance();
135: final GroupElement or = GroupElementFactory.newOrInstance();
136: or.addChild(a);
137: or.addChild(b);
138: parent.addChild(or);
139: parent.addChild(c);
140:
141: final GroupElement or2 = GroupElementFactory.newOrInstance();
142:
143: or2.addChild(d);
144: or2.addChild(e);
145: parent.addChild(or2);
146:
147: final GroupElement not = GroupElementFactory.newNotInstance();
148: not.addChild(f);
149: parent.addChild(not);
150:
151: LogicTransformer.getInstance().applyOrTransformation(parent);
152:
153: assertEquals(GroupElement.OR, parent.getType());
154:
155: assertLength(4, parent.getChildren());
156: assertEquals(GroupElement.class, parent.getChildren().get(0)
157: .getClass());
158: assertEquals(GroupElement.class, parent.getChildren().get(1)
159: .getClass());
160: assertEquals(GroupElement.class, parent.getChildren().get(2)
161: .getClass());
162: assertEquals(GroupElement.class, parent.getChildren().get(3)
163: .getClass());
164:
165: GroupElement and1 = (GroupElement) parent.getChildren().get(0);
166: assertTrue(and1.isAnd());
167: assertLength(4, and1.getChildren());
168: assertEquals(a, and1.getChildren().get(0));
169: assertEquals(c, and1.getChildren().get(1));
170: assertEquals(d, and1.getChildren().get(2));
171: assertEquals(not, and1.getChildren().get(3));
172:
173: and1 = (GroupElement) parent.getChildren().get(1);
174: assertTrue(and1.isAnd());
175: assertLength(4, and1.getChildren());
176: assertEquals(a, and1.getChildren().get(0));
177: assertEquals(c, and1.getChildren().get(1));
178: assertEquals(e, and1.getChildren().get(2));
179: assertEquals(not, and1.getChildren().get(3));
180:
181: and1 = (GroupElement) parent.getChildren().get(2);
182: assertTrue(and1.isAnd());
183: assertLength(4, and1.getChildren());
184: assertEquals(b, and1.getChildren().get(0));
185: assertEquals(c, and1.getChildren().get(1));
186: assertEquals(d, and1.getChildren().get(2));
187: assertEquals(not, and1.getChildren().get(3));
188:
189: and1 = (GroupElement) parent.getChildren().get(3);
190: assertTrue(and1.isAnd());
191: assertLength(4, and1.getChildren());
192: assertEquals(b, and1.getChildren().get(0));
193: assertEquals(c, and1.getChildren().get(1));
194: assertEquals(e, and1.getChildren().get(2));
195: assertEquals(not, and1.getChildren().get(3));
196:
197: }
198:
199: /**
200: * This data structure is now valid
201: *
202: * (Not (OR (A B) ) )
203: *
204: * <pre>
205: * Not
206: * |
207: * or
208: * / \
209: * a b
210: * </pre>
211: *
212: * Should become:
213: *
214: * <pre>
215: * And
216: * / \
217: * Not Not
218: * | |
219: * a b
220: * </pre>
221: *
222: *
223: */
224: public void testNotOrTransformation()
225: throws InvalidPatternException {
226: final ObjectType type = new ClassObjectType(String.class);
227: final Pattern a = new Pattern(0, type, "a");
228: final Pattern b = new Pattern(1, type, "b");
229:
230: final GroupElement parent = GroupElementFactory
231: .newNotInstance();
232: final GroupElement or = GroupElementFactory.newOrInstance();
233: parent.addChild(or);
234:
235: or.addChild(a);
236: or.addChild(b);
237:
238: LogicTransformer.getInstance().applyOrTransformation(parent);
239:
240: assertTrue(parent.isAnd());
241: assertEquals(2, parent.getChildren().size());
242:
243: // we must ensure order
244: final GroupElement b1 = (GroupElement) parent.getChildren()
245: .get(0);
246: final GroupElement b2 = (GroupElement) parent.getChildren()
247: .get(1);
248: assertTrue(b1.isNot());
249: assertTrue(b2.isNot());
250:
251: assertEquals(1, b1.getChildren().size());
252: assertEquals(a, b1.getChildren().get(0));
253:
254: assertEquals(1, b2.getChildren().size());
255: assertEquals(b, b2.getChildren().get(0));
256: }
257:
258: /**
259: * This data structure is now valid (Exists (OR (A B) ) )
260: *
261: * <pre>
262: * Exists
263: * |
264: * or
265: * / \
266: * a b
267: * </pre>
268: *
269: * Should become:
270: *
271: * <pre>
272: * Or
273: * / \
274: * Exists Exists
275: * | |
276: * a b
277: * </pre>
278: */
279: public void testExistOrTransformation()
280: throws InvalidPatternException {
281: final ObjectType type = new ClassObjectType(String.class);
282: final Pattern a = new Pattern(0, type, "a");
283: final Pattern b = new Pattern(1, type, "b");
284:
285: final GroupElement parent = GroupElementFactory
286: .newExistsInstance();
287: final GroupElement or = GroupElementFactory.newOrInstance();
288: parent.addChild(or);
289:
290: or.addChild(a);
291: or.addChild(b);
292:
293: LogicTransformer.getInstance().applyOrTransformation(parent);
294:
295: assertTrue(parent.isOr());
296: assertEquals(2, parent.getChildren().size());
297:
298: // we must ensure order
299: final GroupElement b1 = (GroupElement) parent.getChildren()
300: .get(0);
301: final GroupElement b2 = (GroupElement) parent.getChildren()
302: .get(1);
303: assertTrue(b1.isExists());
304: assertTrue(b2.isExists());
305:
306: assertEquals(1, b1.getChildren().size());
307: assertEquals(a, b1.getChildren().get(0));
308:
309: assertEquals(1, b2.getChildren().size());
310: assertEquals(b, b2.getChildren().get(0));
311:
312: }
313:
314: public void testEliminateEmptyBranchesAndDuplications()
315: throws InvalidRuleException {
316: final ObjectType type = new ClassObjectType(String.class);
317: final Pattern a = new Pattern(0, type, "a");
318: final Pattern b = new Pattern(1, type, "b");
319: final Pattern c = new Pattern(2, type, "c");
320: final Pattern d = new Pattern(3, type, "d");
321:
322: final GroupElement and1 = GroupElementFactory.newAndInstance();
323: and1.addChild(a);
324: and1.addChild(b);
325:
326: final GroupElement and2 = GroupElementFactory.newAndInstance();
327: and2.addChild(c);
328: and2.addChild(d);
329:
330: and1.addChild(and2);
331:
332: final GroupElement or = GroupElementFactory.newOrInstance();
333: and1.addChild(or);
334:
335: final GroupElement[] result = LogicTransformer.getInstance()
336: .transform(and1);
337:
338: assertLength(1, result);
339: assertLength(4, result[0].getChildren());
340: // we must ensure order
341: assertEquals(a, result[0].getChildren().get(0));
342: assertEquals(b, result[0].getChildren().get(1));
343: assertEquals(c, result[0].getChildren().get(2));
344: assertEquals(d, result[0].getChildren().get(3));
345:
346: }
347:
348: /**
349: * <pre>
350: * _/|\_
351: * __/ | \__
352: * / | \
353: * __/ | \__
354: * / | \
355: * And and Not
356: * / | \ / \ |
357: * a And d e Or i
358: * / \ / \
359: * b Not h Exists
360: * | |
361: * Not g
362: * |
363: * c
364: * </pre>
365: *
366: * It is important to ensure that the order of
367: * the elements is not changed after transformation
368: *
369: * <pre>
370: * Or
371: * _/ \__
372: * __/ \___
373: * / \__
374: * __/ \__
375: * / \__
376: * / \__
377: * | \
378: * And And
379: * /| | | | | \ /| | | | | \
380: * a b Not d e h Not a b Not d e Exists Not
381: * | | | | |
382: * Not i Not g i
383: * | |
384: * c c
385: * </pre>
386: *
387: * @throws IOException
388: * @throws ClassNotFoundException
389: *
390: *
391: *
392: */
393: public void testProcessTree() throws IOException,
394: ClassNotFoundException, InvalidPatternException {
395: final ObjectType type = new ClassObjectType(String.class);
396: final Pattern a = new Pattern(0, type, "a");
397: final Pattern b = new Pattern(1, type, "b");
398: final Pattern c = new Pattern(2, type, "c");
399: final Pattern d = new Pattern(3, type, "d");
400: final Pattern e = new Pattern(4, type, "e");
401: final Pattern g = new Pattern(5, type, "g");
402: final Pattern h = new Pattern(6, type, "h");
403: final Pattern i = new Pattern(7, type, "i");
404:
405: final GroupElement and1 = GroupElementFactory.newAndInstance();
406: final GroupElement and2 = GroupElementFactory.newAndInstance();
407: and1.addChild(a);
408: and1.addChild(and2);
409: and2.addChild(b);
410: final GroupElement not1 = GroupElementFactory.newNotInstance();
411: final GroupElement not2 = GroupElementFactory.newNotInstance();
412: not1.addChild(not2);
413: not2.addChild(c);
414: and2.addChild(not1);
415: and1.addChild(d);
416:
417: final GroupElement and3 = GroupElementFactory.newAndInstance();
418: and3.addChild(e);
419: final GroupElement or1 = GroupElementFactory.newOrInstance();
420: and3.addChild(or1);
421: final GroupElement exist1 = GroupElementFactory
422: .newExistsInstance();
423: exist1.addChild(g);
424: or1.addChild(h);
425: or1.addChild(exist1);
426:
427: final GroupElement not3 = GroupElementFactory.newNotInstance();
428: not3.addChild(i);
429:
430: final GroupElement root = GroupElementFactory.newAndInstance();
431: root.addChild(and1);
432: root.addChild(and3);
433: root.addChild(not3);
434:
435: final GroupElement[] result = LogicTransformer.getInstance()
436: .transform(root);
437:
438: // ----------------------------------------------------------------------------------
439: // Now construct the result tree so we can test root against what it
440: // should look like
441: // ----------------------------------------------------------------------------------
442:
443: // Get known correct tree
444: // The binary stream was created from a handchecked correct output
445:
446: // Uncomment this when you need to output a new known correct tree
447: // result
448: // writeTree( result,
449: // "correct_processTree1.dat" );
450: final ObjectInputStream ois = new ObjectInputStream(this
451: .getClass().getResourceAsStream(
452: "/correct_processTree1.dat"));
453:
454: final GroupElement[] correctResultRoot = (GroupElement[]) ois
455: .readObject();
456:
457: // Make sure they are equal
458: for (int j = 0; j < correctResultRoot.length; j++) {
459: assertEquals(correctResultRoot[j], result[j]);
460: }
461: }
462:
463: public void testCloneable() {
464: final ObjectType type = new ClassObjectType(String.class);
465: final Pattern a = new Pattern(0, type, "a");
466: final Pattern b = new Pattern(1, type, "b");
467: final Pattern c = new Pattern(2, type, "c");
468: final Pattern d = new Pattern(3, type, "d");
469: final Pattern e = new Pattern(4, type, "e");
470: final Pattern f = new Pattern(5, type, "f");
471: final Pattern g = new Pattern(6, type, "g");
472: final Pattern h = new Pattern(7, type, "h");
473:
474: // Test against a known false tree
475: final GroupElement and = GroupElementFactory.newAndInstance();
476: and.addChild(a);
477: and.addChild(b);
478:
479: final GroupElement or = GroupElementFactory.newOrInstance();
480: or.addChild(c);
481: or.addChild(d);
482: and.addChild(or);
483: final GroupElement and2 = GroupElementFactory.newAndInstance();
484: and2.addChild(e);
485: and2.addChild(f);
486: or.addChild(and2);
487:
488: final GroupElement not = GroupElementFactory.newNotInstance();
489: and.addChild(not);
490: final GroupElement or2 = GroupElementFactory.newOrInstance();
491: not.addChild(or2);
492: or2.addChild(g);
493: or2.addChild(h);
494:
495: final GroupElement cloned = (GroupElement) and.clone();
496:
497: assertEquals(and, cloned);
498:
499: }
500:
501: /**
502: *
503: *
504: * /**
505: *
506: * <pre>
507: * _/|\_
508: * __/ | \__
509: * / | \
510: * __/ | \__
511: * / | \
512: * And or And
513: * / \ / \ / \
514: * a Or d e Not OR
515: * / \ | / |
516: * b c f g Not
517: * |
518: * h
519: *
520: *
521: *
522: * </pre>
523: *
524: * Each And is a Rete sub rule
525: *
526: * <pre>
527: *
528: *
529: * And___ And___ And___ And___ And__ And___ And___ And___
530: * ||| | \ ||| | \ ||| | \ ||| | \ ||| | \ ||| | \ ||| | \ ||| | \
531: * abd Not g abd Not Not abe Not g abe Not Not acd Not g acd Not Not ace Not g ace Not Not
532: * | | | | | | | | | | | |
533: * f f h f f h f f h f f h
534: *
535: *
536: * </pre>
537: *
538: * @throws IOException
539: * @throws ClassNotFoundException
540: *
541: *
542: *
543: *
544: * @throws IOException
545: * @throws ClassNotFoundException
546: *
547: */
548: public void testTransform() throws IOException,
549: ClassNotFoundException, InvalidPatternException {
550: final ObjectType type = new ClassObjectType(String.class);
551: final Pattern a = new Pattern(0, type, "a");
552: final Pattern b = new Pattern(1, type, "b");
553: final Pattern c = new Pattern(2, type, "c");
554: final Pattern d = new Pattern(3, type, "d");
555: final Pattern e = new Pattern(4, type, "e");
556: final Pattern f = new Pattern(5, type, "f");
557: final Pattern g = new Pattern(6, type, "g");
558: final Pattern h = new Pattern(7, type, "h");
559:
560: final GroupElement and = GroupElementFactory.newAndInstance();
561:
562: final GroupElement and1 = GroupElementFactory.newAndInstance();
563: and1.addChild(a);
564: final GroupElement or1 = GroupElementFactory.newOrInstance();
565: or1.addChild(b);
566: or1.addChild(c);
567: and1.addChild(or1);
568: and.addChild(and1);
569:
570: final GroupElement or2 = GroupElementFactory.newOrInstance();
571: or2.addChild(d);
572: or2.addChild(e);
573: and.addChild(or2);
574:
575: final GroupElement and2 = GroupElementFactory.newAndInstance();
576: final GroupElement not1 = GroupElementFactory.newNotInstance();
577: not1.addChild(f);
578: final GroupElement or3 = GroupElementFactory.newOrInstance();
579: or3.addChild(g);
580:
581: final GroupElement not2 = GroupElementFactory.newNotInstance();
582: not2.addChild(h);
583: or3.addChild(not2);
584:
585: and2.addChild(not1);
586: and2.addChild(or3);
587: and.addChild(and2);
588:
589: final GroupElement[] ands = LogicTransformer.getInstance()
590: .transform(and);
591:
592: // Uncomment this when you need to output a new known correct tree
593: // result
594: // writeTree( ands,
595: // "correct_transform1.dat" );
596:
597: // Now check the main tree
598:
599: // Get known correct tree
600: // The binary stream was created from a handchecked correct output
601: final ObjectInputStream ois = new ObjectInputStream(this
602: .getClass().getResourceAsStream(
603: "/correct_transform1.dat"));
604: final GroupElement[] correctResultAnds = (GroupElement[]) ois
605: .readObject();
606:
607: for (int j = 0; j < ands.length; j++) {
608: assertEquals(correctResultAnds[j], ands[j]);
609: }
610: }
611:
612: private void writeTree(final Object object, final String fileName)
613: throws IOException {
614: final String className = this .getClass().getName();
615:
616: File file = new File(this .getClass().getResource(
617: className.substring(className.lastIndexOf('.') + 1)
618: + ".class").getFile());
619:
620: file = new File(file.getParent(), fileName);
621:
622: new ObjectOutputStream(new FileOutputStream(file))
623: .writeObject(object);
624: }
625:
626: }
|