001: /*
002: * Copyright (C) 1999-2004 <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</a>
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package org.mandarax.examples.family.performance;
020:
021: import org.apache.log4j.BasicConfigurator;
022: import org.apache.log4j.Category;
023: import org.apache.log4j.Level;
024: import org.mandarax.kernel.InferenceEngine;
025: import org.mandarax.kernel.KnowledgeBase;
026: import org.mandarax.kernel.Predicate;
027: import org.mandarax.kernel.Query;
028: import org.mandarax.kernel.ResultSet;
029: import org.mandarax.kernel.Rule;
030: import org.mandarax.kernel.SimplePredicate;
031: import org.mandarax.reference.AdvancedKnowledgeBase;
032: import org.mandarax.reference.ResolutionInferenceEngine3;
033: import org.mandarax.util.LogicFactorySupport;
034:
035: /**
036: * Performance test based on a tree model with one root, NUMBER_OF_SONS children
037: * and NUMBER_OF_GRANDCHILDREN_PER_SON children for each child node.
038: * The tree is described by father facts, and there is one rule describing
039: * what it means to be sibling (brother). The number of expected results is:
040: * (using N for NUMBER_OF_SONS and G for NUMBER_OF_GRANDCHILDREN_PER_SON)
041: * <tt>N*(N-1) + N*G+(G-1)</tt>.
042: * E.g., in this class we use N=25 and G=3, this yields 750.
043: * <br>
044: * We run the computation 3 times to give JIT compilers time to optimize code execution.
045: * <br.
046: * This version uses 'non-optimized' (long) constant and variable names (sharing long prefixes)
047: * that are difficult to match (see String#equals).
048: * This version uses 'optimized' constant and variable names that are easy to match (see String#equals).
049: * Logging is switched on but set to INFO.
050: * Here is the result obtained using a Pentium 4 1.8, 512 MB RAM, Win XP Pro, SUN JDK 1.4.2, (version 3.3, 19 Feb 2004):<p>
051: * 1st run solutions found: 2750 time (in millis): 510<br>
052: * 2nd run solutions found: 2750 time (in millis): 341<br>
053: * 3nd run solutions found: 2750 time (in millis): 300<p>
054: * <p>
055: * Same as before, but uses BEA's jrockit 81 sp2_141_05 JVM:<p>
056: * 1st run solutions found: 2750 time (in millis): 431<br>
057: * 2nd run solutions found: 2750 time (in millis): 250<br>
058: * 3nd run solutions found: 2750 time (in millis): 381<p>
059: * @author <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</A>
060: * @version 3.4 <7 March 05>
061: * @since 2.1
062: */
063:
064: public class PerformanceTest2 {
065: public static final String FAMILY_ROOT = "root";
066: public static final int NUMBER_OF_SONS = 25;
067: public static final int NUMBER_OF_GRANDCHILDREN_PER_SON = 3;
068:
069: public static void main(String[] args) {
070: // disable deep level logging
071: BasicConfigurator.configure();
072: Category.getRoot().setLevel(Level.INFO);
073:
074: System.out.println("Run performance test "
075: + PerformanceTest2.class.getName());
076:
077: // get kb
078: KnowledgeBase kb = createKB();
079: System.out.println("kb created");
080:
081: // issue query
082: InferenceEngine ie = new ResolutionInferenceEngine3();
083: Query query = kb.getQuery("query");
084:
085: System.out.println("Inference engine performance test");
086: System.out.println("ie tested: " + ie);
087: System.out.println("kb size: " + kb.getClauseSets().size());
088:
089: System.out.println("1st run");
090: run(ie, query, kb, false);
091: System.out.println("2nd run");
092: run(ie, query, kb, false);
093: System.out.println("3nd run");
094: run(ie, query, kb, false);
095:
096: System.out.println("Computation finished !");
097: System.exit(0);
098:
099: }
100:
101: /**
102: * Run and time the computation.
103: */
104: private static void run(InferenceEngine ie, Query q,
105: KnowledgeBase kb, boolean logResults) {
106: try {
107: long before = System.currentTimeMillis();
108: ResultSet rs = ie.query(q, kb, InferenceEngine.ALL,
109: InferenceEngine.BUBBLE_EXCEPTIONS);
110: long after = System.currentTimeMillis();
111:
112: // count results
113: int solutions = 0;
114: while (rs.next()) {
115: solutions = solutions + 1;
116: if (logResults) {
117: System.out.print(rs.getResult(String.class, "x"));
118: System.out.print(" is brother of ");
119: System.out.println(rs.getResult(String.class, "y"));
120: }
121: }
122:
123: // report
124: System.out.println("solutions found: " + solutions);
125: System.out.println("time (in millis): " + (after - before));
126: } catch (Exception x) {
127: x.printStackTrace();
128: }
129: }
130:
131: /**
132: * Set up the knowledge base.
133: * @return the knowledge base.
134: */
135: private static KnowledgeBase createKB() {
136: LogicFactorySupport lfs = new LogicFactorySupport();
137:
138: // init predicates
139: Class[] struct = { String.class, String.class };
140: Predicate predicate_is_father = new SimplePredicate("father",
141: struct);
142: Predicate predicate_is_brother = new SimplePredicate("brother",
143: struct);
144:
145: // add knowledge - rule
146: KnowledgeBase kb = new AdvancedKnowledgeBase();
147: Rule rule = lfs.rule(lfs.prereq(predicate_is_father, lfs
148: .variable("person1"), lfs.variable("person3")), lfs
149: .prereq(predicate_is_father, lfs.variable("person2"),
150: lfs.variable("person3")), lfs.prereq(
151: org.mandarax.lib.text.StringArithmetic.NOT_EQUAL, lfs
152: .variable("person1"), lfs.variable("person2")),
153: lfs.fact(predicate_is_brother, lfs.variable("person1"),
154: lfs.variable("person2")));
155: kb.add(rule);
156:
157: // add facts for family tree
158: for (int i = 0; i < NUMBER_OF_SONS; i++) {
159: kb
160: .add(lfs.fact(predicate_is_father, lfs.cons("son"
161: + i, String.class), lfs.cons(FAMILY_ROOT,
162: String.class)));
163: for (int j = 0; j < NUMBER_OF_GRANDCHILDREN_PER_SON; j++) {
164: kb.add(lfs.fact(predicate_is_father, lfs.cons(
165: "grandson" + i + "." + j, String.class), lfs
166: .cons("son" + i, String.class)));
167: }
168: }
169: // add query
170: kb.addQuery(lfs.query(lfs.fact(predicate_is_brother, lfs
171: .variable("x", String.class), lfs.variable("y",
172: String.class)), "query"));
173:
174: // return
175: return kb;
176: }
177: }
|