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: package org.mandarax.util;
019:
020: import java.io.Serializable;
021: import java.util.*;
022:
023: import org.apache.commons.collections.iterators.ArrayIterator;
024: import org.mandarax.kernel.*;
025:
026: /**
027: * AutoFacts are generic clause sets. AutoFacts facilitate the task of integrating facts
028: * generated from data into the knowledge base at run time (=time when we run the inference engine).<br>
029: * It is very useful to subclass <code>AutoFacts</code>, overridding the method <code>getExtension(Class type)</code>.
030: * This method returns a collection of instances for the respective type. E.g., assume we have an
031: * instance <code>af</code> of such a subclass with <code>getExtension</code> returning
032: * (the <code>Integer</code> instances) 1,2 and 3 for <code>Integer.class</code>. Now assume that we perform
033: * <code>af.clauses(1<x,null)</code>, where <code>1<x</code> stands for the fact consisting of the
034: * <code>IntArithmetic.LESS_THAN</code> predicate, a constant term wrapping the integer 1,
035: * and a variable term of the type <code>Integer</code> named "x". Then the iterator returned
036: * iterates over two facts: <code>1<2</code> and <code>1<3</code>. If we perform
037: * <code>af.clauses(x<y,null)</code>
038: * (two variables!), the iterator iterates over three facts <code>1<2</code>,<code>1<3</code>,
039: * <code>2<3</code>. This will also work if the parameter(s) contains functions (with a known semantics),
040: * e.g., the iterator returned by <code>af.clauses(x*x<x+x,null)</code> (where * and + stand for
041: * the respective function defined as static members in <code>IntArithmetic</code>) will iterate over
042: * one fact only: <code>1*1<1+1</code>. <br>
043: * If <code>clauses()</code> is used without parameters, the set of facts iterated is defined as
044: * follows:
045: * <ul>
046: * <li> The predicate of each fact must be in the array returned by <code>getPredicates()</code>.
047: * <li> For each type of any slot of the predicate, the extension
048: * is computed, and a fact is build for each combination of these extensions.
049: * </ul>
050: * E.g., if <code>getPredicates()</code> returns <code>{IntArithmetic.LESS_THAN,IntArithmetic.EQUALS}</code>,
051: * and the extension for <code>Integer.class</code> is defined as {1,2,3}, then <code>clauses()</code> returns an
052: * iterator iterating over the following facts: <code>1=1</code>,<code>2=2<code> ,<code>3=3</code> ,
053: * <code>1<2</code>, <code>1<3</code> and <code>2<3</code>. <br>
054: * In the math test package and in the example.crm package are a couple of examples showing how to use
055: * auto facts.
056: * @author <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</A>
057: * @version 3.4 <7 March 05>
058: * @since 1.2
059: * @deprecated use JFunction and JPredicate instead. Warning: session support has not been added to AutoFacts
060: */
061: public class AutoFacts extends AbstractPropertiesSupport implements
062: ClauseSet, Serializable {
063:
064: protected transient List clauseSetChangeListener = new Vector();
065: protected org.mandarax.kernel.Predicate[] predicates;
066: private String name = "Automatically built fact base";
067:
068: /**
069: * Constructor.
070: */
071: public AutoFacts() {
072: super ();
073: }
074:
075: /**
076: * Add a clause set listener.
077: * @param l a listener
078: */
079: public void addClauseSetChangeListener(ClauseSetChangeListener l) {
080: clauseSetChangeListener.add(l);
081: }
082:
083: /**
084: * Iterate all clauses. We generate a set of clauses for all predicates
085: * returned by <code>getPredicates()</code> only if for all types
086: * of any term of this predicate a non empty extension is defined.
087: * (see also class comment)
088: */
089: public org.mandarax.util.ClauseIterator clauses() {
090: if (predicates == null) {
091: return new ZeroClauseIterator();
092: }
093:
094: List allIterators = new ArrayList(predicates.length);
095: ClauseIterator nextIterator = null;
096:
097: for (int i = 0; i < predicates.length; i++) {
098: nextIterator = getClauseIterator(predicates[i]);
099: if (nextIterator != null) {
100: allIterators.add(nextIterator);
101: }
102: }
103:
104: if (allIterators.isEmpty()) {
105: return new ZeroClauseIterator();
106: } else {
107: return new MergedClauseIterator(allIterators);
108: }
109: }
110:
111: /**
112: * Get a clause iterator.
113: * @return a clause iterator
114: * @param query the query clause
115: * @param additionalParameter an additional parameter
116: */
117: public ClauseIterator clauses(org.mandarax.kernel.Clause query,
118: Object additionalParameter) {
119: Fact leadingFact = getFact(query);
120:
121: // extract the variables
122: Object[] obj = extractVariables(leadingFact).toArray();
123: VariableTerm[] vars = new VariableTerm[obj.length];
124:
125: System.arraycopy(obj, 0, vars, 0, obj.length);
126:
127: // get the extension for each variable
128: Collection[] extensions = new Collection[vars.length];
129:
130: for (int i = 0; i < extensions.length; i++) {
131: extensions[i] = getExtension(vars[i].getType());
132: }
133:
134: // iterate over the extensions
135: if (vars.length == 0) {
136: return new SingleAutoFactIterator(leadingFact, this );
137: } else {
138: return new AutoFactIterator(leadingFact,
139: new MultipleCollectionIterator(extensions), vars,
140: this );
141: }
142: }
143:
144: /**
145: * Extract the variables from a fact or complex term.
146: * @return a collection of variables
147: * @param tc a fact or complex term
148: */
149: private Collection extractVariables(TermContainer tc) {
150: Collection coll = new HashSet();
151: Term[] terms = tc.getTerms();
152: Term t;
153:
154: for (int i = 0; i < terms.length; i++) {
155: t = terms[i];
156:
157: if (t.isCompound()) {
158: coll.addAll(extractVariables((ComplexTerm) t));
159: } else {
160: if (terms[i].isVariable()) {
161: coll.add(t);
162: }
163: }
164: }
165:
166: return coll;
167: }
168:
169: /**
170: * Fire a clause set change event
171: * @param e an event
172: */
173: protected void fireClauseSetChangeEvent(ClauseSetChangeEvent e) {
174: ClauseSetChangeListener l;
175:
176: for (Iterator it = clauseSetChangeListener.iterator(); it
177: .hasNext();) {
178: l = (ClauseSetChangeListener) it.next();
179:
180: l.clauseSetChanged(e);
181: }
182: }
183:
184: /**
185: * Get a clause iterator for the respective predicate.
186: * @return a clause iterator.
187: * @param p a predicate
188: */
189: private ClauseIterator getClauseIterator(Predicate p) {
190: Class[] struct = p.getStructure();
191: LogicFactory lfact = LogicFactory.getDefaultFactory();
192: VariableTerm[] vars = new VariableTerm[struct.length];
193: Collection[] extensions = new Collection[struct.length];
194: Collection ex = null;
195:
196: for (int i = 0; i < struct.length; i++) {
197: ex = getExtension(struct[i]);
198:
199: if ((ex == null) || ex.isEmpty()) {
200: return null;
201:
202: // in this case we cannot build an iterator since we do not know which objects do use in facts
203: }
204:
205: extensions[i] = ex;
206: vars[i] = lfact.createVariableTerm("x" + i, struct[i]);
207: }
208:
209: Fact template = lfact.createFact(p, vars);
210:
211: return new AutoFactIterator(template,
212: new MultipleCollectionIterator(extensions), vars, this );
213: }
214:
215: /**
216: * Get the extension for a type. Note that by default
217: * an empty set is returned. This will lead to a clause set
218: * containing at most one fact. If the auto fact set should
219: * build facts for combinations of variable replacements, then
220: * this method needs to be overridden by a subclass.
221: * @return a collection of objects of the respective type
222: * @param type a type
223: */
224: protected Collection getExtension(Class type) {
225: return new ArrayList();
226: }
227:
228: /**
229: * Get the fact for a query. The query clause is passed
230: * by the inference engine, so we basically implement a selection rule here!
231: * @todo .. add a method that takes a selection rules as parameter ?
232: * @return org.mandarax.kernel.Fact
233: * @param query org.mandarax.kernel.Clause
234: */
235: private Fact getFact(Clause query) {
236: return (Fact) query.getNegativeLiterals().get(0);
237: }
238:
239: /**
240: * Get the key
241: * @return the key (i.e., the predicates for this clause set)
242: */
243: public Object getKey() {
244: return predicates;
245: }
246:
247: /**
248: * Get the name of the auto fact set.
249: * @return a name
250: */
251: public String getName() {
252: return name;
253: }
254:
255: /**
256: * Get the predicates.
257: * @return the predicates
258: */
259: public org.mandarax.kernel.Predicate[] getPredicates() {
260: return predicates;
261: }
262:
263: /**
264: * Get an iterator iterating over the predicates contained in this clause set.
265: * @return an iterator
266: */
267: public Iterator predicates() {
268: if (predicates == null)
269: return new ArrayIterator(new Predicate[] {});
270: else
271: return new ArrayIterator(predicates);
272: }
273:
274: /**
275: * Remove a clause set listener.
276: * @param l a listener
277: */
278: public void removeClauseSetChangeListener(ClauseSetChangeListener l) {
279: clauseSetChangeListener.remove(l);
280: }
281:
282: /**
283: * Set a name.
284: * @param aName a name
285: */
286: public void setName(String aName) {
287: name = aName;
288: }
289:
290: /**
291: * Set the predicates,
292: * @param newPredicates the predicates
293: */
294: public void setPredicates(
295: org.mandarax.kernel.Predicate[] newPredicates) {
296: predicates = newPredicates;
297: }
298:
299: /**
300: * Convert the object to a string.
301: * @return the string representation of this object
302: */
303: public String toString() {
304: return getName();
305: }
306: }
|