001: package org.mandarax.reference;
002:
003: /*
004: * Copyright (C) 1999-2004 <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</a>
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: import java.util.*;
021: import org.apache.commons.collections.iterators.SingletonIterator;
022: import org.mandarax.kernel.*;
023:
024: /**
025: * Reference implementation for (simple) facts. In older versions (prior to 1.9)
026: * there was no separate Query interface/class - facts were used instead.
027: * In order to facilitate maintanance of older applications, this class still implements
028: * Query. Some newer features, in particular DerivationEventListeners, are not supported.
029: * For queries, QueryImpl should be used instead.
030: * @see QueryImpl
031: * @author <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</A>
032: * @version 3.4 <7 March 05>
033: * @since 1.1
034: * Prova re-integration modifications
035: * @author <A HREF="mailto:a.kozlenkov@city.ac.uk">Alex Kozlenkov</A>
036: * @version 3.4 <7 March 05>
037: */
038: public class FactImpl extends Complex implements Fact, Query {
039:
040: private java.util.List posLiterals = null;
041: private static java.util.List negLiterals = new java.util.Vector();
042: private Predicate predicate = null;
043: private transient Vector clauseSetChangeListener = new Vector();
044: private ClauseSet container = this ;
045: // utility vars for the query interface
046: private Fact[] facts = { this };
047: private String name = null;
048: private Properties delegate = null;
049: private int containsVariables = -1;
050:
051: /**
052: * Constructor.
053: */
054: public FactImpl() {
055: super ();
056: }
057:
058: /**
059: * Constructor.
060: * @param p the predicate
061: */
062: FactImpl(org.mandarax.kernel.Predicate p) {
063: super ();
064: setPredicate(p);
065: }
066:
067: /**
068: * Constructor.
069: * @param p the predicate
070: * @param t the terms
071: */
072: FactImpl(org.mandarax.kernel.Predicate p, Term[] t) {
073: super ();
074: setPredicate(p);
075: for (int i = 0; i < t.length; i++) {
076: setTerm(t[i], i);
077: }
078: }
079:
080: /**
081: * Add a clause set listener.
082: * @param l a listener
083: */
084: public void addClauseSetChangeListener(ClauseSetChangeListener l) {
085: clauseSetChangeListener.add(l);
086: }
087:
088: /**
089: * Apply a set of replacements to a clause. Returns a new clause!
090: * @return the fact (clause) resulting from the application of the replacements
091: * @param r a collection of replacements
092: */
093: public Clause apply(java.util.Collection r) {
094: return applyToFact(r);
095: }
096:
097: /**
098: * Apply a single replacement to a fact. Returns a new clause!
099: * @return the fact (clause) resulting from the application of the replacemen
100: * @param r the replacement
101: */
102: public Clause apply(Replacement r) {
103: return applyToFact(r);
104: }
105:
106: /**
107: * Apply a set of replacements to a fact. Returns a new fact!
108: * @return the fact resulting from the application of the replacement
109: * @param r a collection of replacement
110: */
111: public Fact applyToFact(java.util.Collection r) {
112: Term[] t = getTerms();
113: Term newTerm = null;
114:
115: // create a new fact
116: FactImpl f = new FactImpl();
117: copyStructure(f);
118: for (int i = 0; i < t.length; i++) {
119: newTerm = t[i];
120: for (java.util.Iterator it = r.iterator(); it.hasNext();) {
121: newTerm = newTerm.apply((Replacement) it.next());
122: }
123: f.setTerm(newTerm, i);
124: }
125:
126: return f;
127: }
128:
129: /**
130: * Apply a single replacement to a fact. Returns a new fact!
131: * @return the fact (clause) resulting from the application of the replacement
132: * @param r a replacement
133: */
134: public Fact applyToFact(Replacement r) {
135: Term[] t = getTerms();
136: // create a new fact
137: FactImpl f = new FactImpl();
138: copyStructure(f);
139: for (int i = 0; i < t.length; i++) {
140: f.setTerm(t[i].apply(r), i);
141: }
142: return f;
143: }
144:
145: /**
146: * Whether the fact contains variables
147: * @return boolean
148: */
149: public boolean isBound() {
150: if (containsVariables >= 0)
151: return containsVariables == 0;
152:
153: Term[] tt = this .getTerms();
154: for (int i = 0; i < tt.length; i++) {
155: if (tt[i].containsVariables()) {
156: containsVariables = 1;
157: return false;
158: }
159: }
160: containsVariables = 0;
161: return true;
162: }
163:
164: /**
165: * Get an iterator for clauses.
166: * @return a clause iterator
167: */
168: public org.mandarax.util.ClauseIterator clauses() {
169: return new org.mandarax.util.SingleClauseIterator(this );
170: }
171:
172: /**
173: * Get an iterator for clauses. The parameters are ignored and <code>clauses()</code> is called!
174: * @return a clause iterator
175: * @param query a query
176: * @param additionalParameter an additional parameter
177: */
178: public org.mandarax.util.ClauseIterator clauses(Clause query,
179: Object additionalParameter) {
180: return clauses();
181: }
182:
183: /**
184: * Copy the structure, i.e. length of the terms, types of the terms and methods,
185: * @param f the fact that takes the structure from this object
186: */
187: protected void copyStructure(FactImpl f) {
188: f.types = types;
189: f.terms = new Term[terms.length];
190: f.predicate = predicate;
191: }
192:
193: /**
194: * Check whether objects are equal.
195: * @param obj the object to compare this object with
196: * @return true if the objects are equal, false otherwise
197: */
198: public boolean equals(Object obj) {
199: if ((obj != null) && (obj instanceof FactImpl)) {
200: FactImpl f = (FactImpl) obj;
201: boolean result = (predicate == null) ? f.predicate == null
202: : predicate.equals(f.predicate);
203: Term[] terms1 = terms;
204: Term[] terms2 = f.terms;
205: if (terms1 == null)
206: result = result && terms2 == null;
207: else {
208: for (int i = 0; i < terms.length; i++) {
209: result = result
210: && (((terms[i] == null) && (terms2[i] == null)) || (terms1[i]
211: .equals(terms2[i])));
212:
213: if (!result) {
214: return false;
215: }
216: }
217: }
218: return result;
219: }
220: return false;
221: }
222:
223: /**
224: * Fire a clause set change event
225: * @param e the event
226: */
227: protected void fireClauseSetChangeEvent(ClauseSetChangeEvent e) {
228: ClauseSetChangeListener l;
229:
230: for (Iterator it = clauseSetChangeListener.iterator(); it
231: .hasNext();) {
232: l = (ClauseSetChangeListener) it.next();
233: l.clauseSetChanged(e);
234: }
235: }
236:
237: /**
238: * Get the object constructing the complex.
239: * @return the predicate of this fact
240: */
241: protected org.mandarax.kernel.Constructor getConstructor() {
242: return getPredicate();
243: }
244:
245: /**
246: * Get the clause set containing the clause. This method is in particular useful for analyzing derivations,
247: * since derivations show only the clauses used, not the clause set generating this clauses (e.g., AutoFacts). On the other
248: * hand, knowledge bases contain often clause sets. So it could be hard to find the clause sets in the knowledge base
249: * that caused a certain result. For some clauses such as facts, the container is just the fact itself.
250: * @return a clause set
251: */
252: public ClauseSet getContainer() {
253: return container;
254: }
255:
256: /**
257: * Get a key for fast access. The key is usually the predicate, but subclasses
258: * might want to use different keys. Note that keys are mainly used by inference engines and
259: * knowledge bases to improve performance and inference engine and knowledge bases
260: * must know about the semantics of keys to use them correctly!
261: * @return the key object
262: */
263: public Object getKey() {
264: return getPredicate();
265: }
266:
267: /**
268: * Get the negative literals.
269: * @return the collection of negative literals, this is an empty collection!
270: */
271: public java.util.List getNegativeLiterals() {
272: return negLiterals;
273: }
274:
275: /**
276: * Get the positive literals.
277: * @return the collection of positive literals, this is a singleton containing only this object
278: */
279: public java.util.List getPositiveLiterals() {
280: if (posLiterals == null) {
281: posLiterals = new java.util.Vector(1);
282: posLiterals.add(this );
283: }
284:
285: return posLiterals;
286: }
287:
288: /**
289: * Get the predicate.
290: * @return the predicate
291: */
292: public org.mandarax.kernel.Predicate getPredicate() {
293: return predicate;
294: }
295:
296: /**
297: * Get the hash code of a fact.
298: * @return the hash value
299: */
300: public int hashCode() {
301: int i = (predicate == null) ? 0 : predicate.hashCode();
302:
303: if (terms.length == 0) {
304: return i;
305: }
306:
307: if (terms.length == 1) {
308: return i ^ ((terms[0] == null) ? 0 : terms[0].hashCode());
309: } else {
310: return i
311: ^ ((terms[0] == null) ? 0 : terms[0].hashCode())
312: ^ ((terms[terms.length - 1] == null) ? 0
313: : terms[terms.length - 1].hashCode());
314: }
315: }
316:
317: /**
318: * Indicates whether the clause is atomic.
319: * @return a boolean
320: */
321: public boolean isAtomic() {
322: return true;
323: }
324:
325: /**
326: * Indicates whether the clause is the empty clause.
327: * @return false
328: */
329: public boolean isEmpty() {
330: return false;
331: }
332:
333: /**
334: * Indicates whether the object (usually a term or a clause set) can be performed
335: * using the java semantics.
336: * @return a boolean
337: */
338: public boolean isExecutable() {
339: if ((predicate != null) && predicate.isExecutable()) {
340: Term[] t = getTerms();
341: for (int i = 0; i < t.length; i++) {
342: if (!t[i].isExecutable()) {
343: return false;
344: }
345: }
346:
347: return true;
348: }
349:
350: return false;
351: }
352:
353: /**
354: * Remove a clause set listener.
355: * @param l a listener
356: */
357: public void removeClauseSetChangeListener(ClauseSetChangeListener l) {
358: clauseSetChangeListener.remove(l);
359: }
360:
361: /**
362: * Resolve a fact: if supported, the predicate
363: * should be performed using its semantic. E.g., for a fact
364: * like <i>isFather(Max,Jens)</i> the function <i>isFather</i> is performed
365: * for the objects (constant terms) <i>Max</i> and <i>Jens</i> and the result (e.g., <i>true</i>) is returned.
366: * Note that not all predicates support this (since not all predicates
367: * have a semantic), and the operation can also fail
368: * in case one term is variable. In these cases we throw appropriate exceptions.
369: * @param session a session object
370: * @return the result of resolving the term
371: * @throws java.lang.UnsupportedOperationException
372: * @throws java.lang.IllegalArgumentException
373: */
374: public Object resolve(Session session)
375: throws UnsupportedOperationException,
376: IllegalArgumentException {
377: return predicate.perform(terms, session);
378: }
379:
380: /**
381: * Set a container.
382: * @param aContainerthe new container
383: */
384: public void setContainer(ClauseSet aContainer) {
385: container = aContainer;
386: }
387:
388: /**
389: * Set a new predicate.
390: * @param p the predicate
391: */
392: public void setPredicate(org.mandarax.kernel.Predicate p) {
393: Predicate oldPredicate = predicate;
394: predicate = p;
395: terms = new Term[p.getStructure().length];
396: types = p.getStructure();
397: if ((oldPredicate == null) ? p != null : !(oldPredicate
398: .equals(p))) {
399: fireClauseSetChangeEvent(new ClauseSetChangeEvent(this ,
400: oldPredicate, p, ClauseSetChangeEvent.KEY_CHANGED));
401: }
402: }
403:
404: /**
405: * Get the facts.
406: * @see org.mandarax.kernel.Query
407: * @return an array of facts
408: */
409: public Fact[] getFacts() {
410: return facts;
411: }
412:
413: /**
414: * Set the facts. Not supported by facts, throws an exception!
415: * Please use QueryImpl for queries!
416: * @see org.mandarax.kernel.Query
417: * @param facts an array of facts
418: */
419: public void setFacts(Fact[] facts) {
420: throw new UnsupportedOperationException(
421: "FactImpl does not support setFacts(). Please use QueryImpl for queries!");
422: }
423:
424: /**
425: * Get the common name of this query, i.e., something like "Find the oncle of a person".
426: * @return a string
427: */
428: public String getName() {
429: return name;
430: }
431:
432: /**
433: * Set the common name of this query.
434: * @param a name
435: */
436: public void setName(String queryName) {
437: name = queryName;
438: }
439:
440: /**
441: * Indicates whether the fact is negated (negation as failure)
442: * @return always false
443: * @see PrerequisiteImpl
444: */
445: public boolean isNegatedAF() {
446: return false;
447: }
448:
449: /**
450: * Set a property.
451: * @param key the key
452: * @param value the value
453: * @return the previous value of the specified key in this property list, or null if it did not have one.
454: */
455: public Object setProperty(String key, String value) {
456: if (delegate == null)
457: delegate = new Properties();
458: return delegate.setProperty(key, value);
459: }
460:
461: /**
462: * Get a property.
463: * @param key the property key
464: * @return the respective value. The method returns null if the property is not found.
465: */
466: public String getProperty(String key) {
467: if (delegate == null)
468: delegate = new Properties();
469: return delegate.getProperty(key);
470: }
471:
472: /**
473: * Returns an enumeration of all the keys in this property list, including distinct
474: * keys in the default property list if a key of the same name has not already been
475: * found from the main properties list.
476: * @return an enumeration of all the keys in this property list, including the keys in
477: * the default property list
478: */
479: public Enumeration propertyNames() {
480: if (delegate == null)
481: delegate = new Properties();
482: return delegate.propertyNames();
483: }
484:
485: /**
486: * Remove a property.
487: * @param key the property key
488: * @return the value to which the key had been mapped, or null if the key did not have a mapping.
489: */
490: public Object removeProperty(String key) {
491: if (delegate != null)
492: return delegate.remove(key);
493: return null;
494: }
495:
496: /**
497: * Get the properties as one "properties" instance.
498: * @return a properties instance
499: */
500: public Properties getProperties() {
501: if (delegate == null)
502: delegate = new Properties();
503: return delegate;
504: }
505:
506: /**
507: * Set the properties. Not required by the interface, but useful for bean (introspection-) based
508: * tools.
509: * @param properties the properties
510: */
511: public void setProperties(Properties properties) {
512: delegate = properties;
513: }
514:
515: /**
516: * Get an iterator iterating over the predicates contained in this clause set.
517: * @return an iterator
518: */
519: public Iterator predicates() {
520: return new SingletonIterator(predicate);
521: }
522:
523: /**
524: * Get the registered derivation event listeners.
525: * @return an array of listeners
526: */
527: public DerivationEventListener[] getDerivationEventListeners() {
528: throw new UnsupportedOperationException(
529: "Please use QueryImpl instead");
530: }
531:
532: /**
533: * Set the derivation event listeners.
534: * @param listeners listeners
535: */
536: public void setDerivationEventListeners(
537: DerivationEventListener[] listeners) {
538: throw new UnsupportedOperationException(
539: "Please use QueryImpl instead");
540: }
541:
542: /**
543: * Indicates whether the clause is ground (= does not have variables).
544: * @return a boolean
545: */
546: public boolean isGround() {
547: if (terms == null)
548: return true;
549: for (int i = 0; i < terms.length; i++)
550: if (terms[i].containsVariables())
551: return false;
552: return true;
553: }
554: }
|