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:
021: import java.util.*;
022: import org.mandarax.kernel.*;
023: import org.mandarax.util.logging.LogCategories;
024:
025: /**
026: * Derivation nodes represent application of a single rule.
027: * @author <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</A>
028: * @version 3.4 <7 March 05>
029: * @since 1.0
030: * Prova re-integration modifications
031: * @author <A HREF="mailto:a.kozlenkov@city.ac.uk">Alex Kozlenkov</A>
032: * @version 3.4 <7 March 05>
033: */
034: public class DerivationNodeImpl implements
035: org.mandarax.kernel.DerivationNode, LogCategories {
036:
037: private List subNodes = new java.util.Vector();
038: private boolean failed = false;
039: private Unification unification = null;
040: private Clause appliedClause = null;
041: private Clause query = null;
042: private DerivationNodeImpl parent = null;
043: private SemanticEvaluationPolicy semanticEvaluationPolicy = null;
044: private static LogicFactory lfactory = LogicFactory
045: .getDefaultFactory();
046: Map varRenamings = new HashMap();
047: private int id = 0;
048: private boolean isLastNode = false;
049: private boolean isResultNode = false;
050: private boolean isCut = false;
051: // 2.2
052: // Further corrections 28/04/03
053: private Object cutPredicate = null;
054:
055: private BitSet supportedSolutions = null;
056:
057: /** Cache the string representation for optimized debugging. */
058: private transient String cachedToString = null;
059:
060: /**
061: * Constructor.
062: */
063: public DerivationNodeImpl() {
064: super ();
065: }
066:
067: /**
068: * Add a subnode.
069: * @param dn a child node
070: */
071: public void addSubNode(DerivationNodeImpl dn) {
072: subNodes.add(dn);
073: dn.parent = this ;
074: }
075:
076: /**
077: * Get the applied clause.
078: * @return the applied clause
079: */
080: public Clause getAppliedClause() {
081: return appliedClause;
082: }
083:
084: /**
085: * Get the parent derivation node.
086: * @return the parent node
087: */
088: public DerivationNodeImpl getParent() {
089: return parent;
090: }
091:
092: /**
093: * Get the query.
094: * @return the query
095: */
096: public Clause getQuery() {
097: return query;
098: }
099:
100: /**
101: * Get the state of this node.
102: * @see org.mandarax.kernel.DerivationNodeImpl
103: * @return the state, the value is one of the constants defined in org.mandarax.kernel.DerivationNodeImpl
104: */
105: public int getState() {
106: return isFailed() ? org.mandarax.kernel.DerivationNode.FAILED
107: : org.mandarax.kernel.DerivationNode.SUCCESS;
108: }
109:
110: /**
111: * Indicates whether the result at the given index is supported by this node.
112: * @param int resultNumber - the number of the result in the result set indexing starts with 0
113: * @return boolean
114: */
115: public boolean isSupported(int resultNumber) {
116: return supportedSolutions != null
117: && supportedSolutions.get(resultNumber);
118: }
119:
120: /**
121: * Set the result number as supported.
122: * @param int resultNumber - the number of the result in the result set indexing starts with 0
123: */
124: public void setSupported(int resultNumber) {
125: if (supportedSolutions == null)
126: supportedSolutions = new BitSet();
127: supportedSolutions.set(resultNumber);
128: }
129:
130: /**
131: * Get the sub nodes.
132: * @return a list containing the child nodes
133: */
134: public List getSubNodes() {
135: return subNodes;
136: }
137:
138: /**
139: * Get the unification.
140: * @return the unification applied
141: */
142: public Unification getUnification() {
143: return unification;
144: }
145:
146: /**
147: * Indicates whether this derivation step has failed.
148: * @return true if this proof step has failed, false otherwise
149: */
150: public boolean isFailed() {
151: return failed;
152: }
153:
154: /**
155: * Remove a subnode.
156: * @return boolean
157: * @param dn a child node
158: */
159: public boolean removeSubNode(DerivationNodeImpl dn) {
160: dn.parent = null;
161: return subNodes.remove(dn);
162: }
163:
164: /**
165: * Replace a term. Check unification and renamings - do not traverse children.
166: * Method has been changed in 1.9.2 to support complex terms!
167: * @return a term that is the result of applying the unification or a renaming to the original term
168: * @param original a term
169: */
170: private Term replaceByUnificationOrRenaming(Term original) {
171:
172: boolean debug = LOG_IE_RESULT.isDebugEnabled();
173: Term replacedHere = original;
174:
175: if (debug)
176: LOG_IE_RESULT.debug("Replace " + original + " in node "
177: + this );
178:
179: Replacement r = null;
180:
181: // first check the unification
182: if (getUnification() != null) {
183: Collection uni = getUnification().replacements;
184:
185: for (Iterator it = uni.iterator(); it.hasNext();) {
186: r = (Replacement) it.next();
187: replacedHere = replacedHere.apply(r);
188: if (debug)
189: LOG_IE_RESULT.debug("Replaced by unification "
190: + original + " -> " + replacedHere);
191: }
192: }
193:
194: // apply renamings
195: if (replacedHere instanceof VariableTerm) {
196: // more effective for variable terms
197: Object rp = varRenamings.get(replacedHere);
198: if (rp != null) {
199: replacedHere = (Term) rp;
200: if (debug)
201: LOG_IE_RESULT.debug("Replaced by var renaming "
202: + original + " -> " + replacedHere);
203: }
204:
205: } else {
206: // general, in particular for complex terms
207: for (Iterator iter = varRenamings.keySet().iterator(); iter
208: .hasNext();) {
209: Term nextKey = (Term) iter.next();
210: r = new Replacement();
211: r.original = nextKey;
212: r.replacement = (Term) varRenamings.get(nextKey);
213: replacedHere = replacedHere.apply(r);
214: if (debug)
215: LOG_IE_RESULT.debug("Replaced by var renaming "
216: + original + " -> " + replacedHere);
217: }
218: }
219:
220: // try to simplify terms - only necessary for complex terms
221: if (replacedHere instanceof ComplexTerm) {
222: // TODO pass session !
223: replacedHere = getSemanticEvaluationPolicy().evaluate(
224: (ComplexTerm) replacedHere, appliedClause, null,
225: debug);
226: }
227:
228: return replacedHere;
229:
230: }
231:
232: /**
233: * Replace a term.
234: * @return a term
235: * @param original a term
236: */
237: Term replace(Term original) {
238:
239: Term replacedHere = replaceByUnificationOrRenaming(original);
240:
241: // the following code has been replace as from version 1.8 !!
242: // now we check whether there are more subnodes. In this case we must continue replacing !!
243: /*
244: if(getSubNodes ().isEmpty ()) return replacedHere;
245: else {
246: List sn = getSubNodes ();
247: DerivationNodeImpl nextNode = (DerivationNodeImpl) sn.get(sn.size () - 1);
248: return nextNode.replace (replacedHere);
249: }
250: */
251:
252: // new code: look for the first successful node
253: for (Iterator iter = getSubNodes().iterator(); iter.hasNext();) {
254: DerivationNodeImpl nextNode = (DerivationNodeImpl) iter
255: .next();
256: if (!nextNode.isFailed())
257: return nextNode.replace(replacedHere);
258: }
259: return replacedHere;
260: }
261:
262: /**
263: * Replace a term and add any replacements found to the list,
264: * @return an array of lists, each containing a list of terms representing the
265: * solution for the variable at the respective position
266: * [Prova] Made public to be callable from ws.prova.reference.ProvaResultSetImpl2
267: * @param originals an array of terms
268: */
269: public void replace(List[] replacements, Term[] originals) {
270: boolean logOn = LOG_IE_RESULT.isDebugEnabled();
271: Term[] replacedHere = new Term[originals.length];
272: for (int i = 0; i < originals.length; i++) {
273: replacedHere[i] = replaceByUnificationOrRenaming(originals[i]);
274: }
275: if (logOn) {
276: LOG_IE_RESULT.debug("Replaced in derivation node " + this );
277: boolean somethingReplaced = false;
278: for (int i = 0; i < originals.length; i++) {
279: if (originals[i] != replacedHere[i]) {
280: LOG_IE_RESULT.debug(originals[i] + " -> "
281: + replacedHere[i]);
282: somethingReplaced = true;
283: }
284: if (!somethingReplaced)
285: LOG_IE_RESULT.debug("<nothing replaced>");
286: }
287: }
288: //boolean finalNode = true;
289: for (Iterator iter = getSubNodes().iterator(); iter.hasNext();) {
290: DerivationNodeImpl nextNode = (DerivationNodeImpl) iter
291: .next();
292: //finalNode = false;
293: if (!nextNode.isFailed())
294: nextNode.replace(replacements, replacedHere);
295: }
296: if (isResultNode) {
297: if (logOn)
298: LOG_IE_RESULT.debug("Add solution in node " + this );
299: for (int i = 0; i < originals.length; i++) {
300: replacements[i].add(replacedHere[i]);
301: }
302: }
303: }
304:
305: /**
306: * Set the applied clause.
307: * @param c the applied clause
308: */
309: public void setAppliedClause(Clause c) {
310: cachedToString = null;
311: appliedClause = c;
312: }
313:
314: /**
315: * Set the failed flag.
316: * @param f true if this node has failed, false otherwise
317: */
318: public void setFailed(boolean f) {
319: cachedToString = null;
320: failed = f;
321: }
322:
323: /**
324: * Set the query.
325: * @param f a query
326: */
327: public void setQuery(Clause f) {
328: query = f;
329: }
330:
331: /**
332: * Set the subnodes.
333: * @param sn a list of subnodes
334: */
335: public void setSubNodes(List sn) {
336: subNodes = sn;
337:
338: for (Iterator it = sn.iterator(); it.hasNext();) {
339: ((DerivationNodeImpl) it.next()).parent = this ;
340: }
341: }
342:
343: /**
344: * Set the unification.
345: * @param u a unification
346: */
347: public void setUnification(Unification u) {
348: unification = u;
349: }
350:
351: /**
352: * Convert the derivation node to a string.
353: * @return the string representation of this object
354: */
355: public String toString() {
356: if (cachedToString == null) {
357: StringBuffer buf = new StringBuffer();
358: buf.append("NODE ");
359: buf.append(id);
360: buf.append(" : CLAUSE: \"");
361: if (getAppliedClause() == null) {
362: buf.append("<NONE>");
363: } else
364: buf.append(getAppliedClause().toString());
365: buf.append("\" FAILED: ");
366: buf.append(isFailed());
367: buf.append(" IS_LAST_NODE: ");
368: buf.append(this .isLastNode);
369: cachedToString = buf.toString();
370: }
371: return cachedToString;
372: }
373:
374: /**
375: * Dump the derivation node and the subtree having this node as a root to the print writer.
376: * This method is for developer support only.
377: * @param out a print stream
378: */
379: public void dump(java.io.PrintStream out) {
380: dump(out, 0);
381: }
382:
383: /**
384: * Dump the derivation node and the subtree having this node as a root to the print writer.
385: * This method is for developer support only.
386: * @param out a print stream
387: * @param childLevel the child level (visualized by an indent)
388: */
389: private void dump(java.io.PrintStream out, int childLevel) {
390: startLine(out, childLevel);
391: out.println(this );
392: // recursion
393: List subNodes = getSubNodes();
394: for (Iterator iter = subNodes.iterator(); iter.hasNext();) {
395: ((DerivationNodeImpl) iter.next())
396: .dump(out, childLevel + 1);
397: }
398: }
399:
400: /**
401: * Start a line. Support method for dump.
402: * out a print stream
403: * @param childLevel the child level
404: */
405: private void startLine(java.io.PrintStream out, int childLevel) {
406: out.print(childLevel);
407: int maxIndent = 10;
408: int indent = 1 + Math.min(childLevel, maxIndent);
409: char indentChar = '.';
410: for (int i = 0; i < indent; i++)
411: out.print(indentChar);
412:
413: }
414:
415: /**
416: * Returns the semantic evaluation policy.
417: * @return the policy
418: */
419: SemanticEvaluationPolicy getSemanticEvaluationPolicy() {
420: return semanticEvaluationPolicy == null ? this .parent
421: .getSemanticEvaluationPolicy()
422: : semanticEvaluationPolicy;
423: }
424:
425: /**
426: * Propagate supported solutions to the parent node.
427: * [Prova] Changed to public to allow out of package inference engines.
428: */
429: public void propagateSupportedSolutions() {
430: if (supportedSolutions != null && parent != null) {
431: for (int i = 0; i < supportedSolutions.length(); i++) {
432: if (supportedSolutions.get(i)) {
433: parent.setSupported(i);
434: if (LOG_IE_STEP.isDebugEnabled())
435: LOG_IE_STEP
436: .debug("propagate supported result index "
437: + i + " in " + this );
438: }
439: }
440: parent.propagateSupportedSolutions();
441: }
442: }
443:
444: /**
445: * Sets the semantic evaluation policy.
446: * [Prova] Changed to public to allow out of package inference engines.
447: * @param policy The semantic evaluation policy to set
448: */
449: public void setSemanticEvaluationPolicy(
450: SemanticEvaluationPolicy policy) {
451: this .semanticEvaluationPolicy = policy;
452: }
453:
454: /**
455: * Get an array of integers containing the indexes of all solutions supported.
456: * @return an array of integer
457: */
458: public int[] getSupportedResults() {
459: if (supportedSolutions == null)
460: return new int[] {};
461: int[] resultIndexes = new int[supportedSolutions.length()];
462: int i, j = 0;
463: for (i = 0; i < supportedSolutions.length(); i++) {
464: if (supportedSolutions.get(i)) {
465: resultIndexes[j] = i;
466: j = j + 1;
467: }
468: }
469: int[] array = new int[j];
470: for (i = 0; i < j; i++)
471: array[i] = resultIndexes[i];
472: return array;
473: }
474:
475: public boolean isCut() {
476: return isCut;
477: }
478:
479: public void setCut(boolean cut) {
480: isCut = cut;
481: }
482:
483: public int getId() {
484: return id;
485: }
486:
487: public void setId(int id) {
488: this .id = id;
489: }
490:
491: public Object getCutPredicate() {
492: return cutPredicate;
493: }
494:
495: public void setCutPredicate(Object cutPredicate) {
496: this .cutPredicate = cutPredicate;
497: }
498:
499: public boolean isLastNode() {
500: return isLastNode;
501: }
502:
503: public void setLastNode(boolean lastNode) {
504: isLastNode = lastNode;
505: }
506:
507: public boolean isResultNode() {
508: return isResultNode;
509: }
510:
511: public void setResultNode(boolean resultNode) {
512: isResultNode = resultNode;
513: }
514: }
|