001: /******************************************************************
002: * File: LPBackwardRuleInfGraph.java
003: * Created by: Dave Reynolds
004: * Created on: 21-Jul-2003
005: *
006: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
007: * [See end of file]
008: * $Id: LPBackwardRuleInfGraph.java,v 1.13 2008/01/02 12:07:47 andy_seaborne Exp $
009: *****************************************************************/package com.hp.hpl.jena.reasoner.rulesys;
010:
011: import com.hp.hpl.jena.reasoner.rulesys.impl.*;
012: import com.hp.hpl.jena.reasoner.*;
013: import com.hp.hpl.jena.graph.*;
014:
015: import java.util.*;
016:
017: import com.hp.hpl.jena.util.OneToManyMap;
018: import com.hp.hpl.jena.util.iterator.*;
019:
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.LogFactory;
022:
023: /**
024: * Inference graph for accessing the LP version of the backward chaining
025: * rule engine.
026: *
027: * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
028: * @version $Revision: 1.13 $ on $Date: 2008/01/02 12:07:47 $
029: */
030: public class LPBackwardRuleInfGraph extends BaseInfGraph implements
031: BackwardRuleInfGraphI {
032:
033: // =======================================================================
034: // variables
035:
036: /** The LP rule engine controller which handles the processing for this graph */
037: protected LPBRuleEngine engine;
038:
039: /** Table of derivation records, maps from triple to RuleDerivation */
040: protected OneToManyMap derivations;
041:
042: /** An optional graph of separate schema assertions that should also be processed */
043: protected FGraph fschema;
044:
045: /** Cache of deductions made from the rules */
046: protected FGraph fdeductions;
047:
048: /** A finder that searches across the data, schema and axioms */
049: protected Finder dataFind;
050:
051: /** Cache of temporary property values inferred through getTemp calls */
052: protected TempNodeCache tempNodecache;
053:
054: static Log logger = LogFactory.getLog(LPBackwardRuleInfGraph.class);
055:
056: // =======================================================================
057: // Core methods
058:
059: /**
060: * Constructor. Create a new backward inference graph to process
061: * the given data. The parent reasoner supplies the ruleset and
062: * any additional schema graph.
063: *
064: * @param reasoner the parent reasoner
065: * @param ruleStore the indexed set of rules to use
066: * @param data the data graph to be processed
067: * @param schema optional precached schema (use null if not required)
068: */
069: public LPBackwardRuleInfGraph(Reasoner reasoner,
070: LPRuleStore ruleStore, Graph data, Graph schema) {
071: super (data, reasoner);
072: if (schema != null) {
073: fschema = new FGraph(schema);
074: }
075: engine = new LPBRuleEngine(this , ruleStore);
076: tempNodecache = new TempNodeCache(this );
077: }
078:
079: /**
080: * Return the schema graph, if any, bound into this inference graph.
081: */
082: public Graph getSchemaGraph() {
083: return fschema.getGraph();
084: }
085:
086: /**
087: * Perform any initial processing and caching. This call is optional. Most
088: * engines either have negligable set up work or will perform an implicit
089: * "prepare" if necessary. The call is provided for those occasions where
090: * substantial preparation work is possible (e.g. running a forward chaining
091: * rule system) and where an application might wish greater control over when
092: * this prepration is done.
093: */
094: public void prepare() {
095: if (!isPrepared) {
096: fdeductions = new FGraph(Factory.createGraphMem());
097: extractAxioms();
098: dataFind = fdata;
099: if (fdeductions != null) {
100: dataFind = FinderUtil.cascade(dataFind, fdeductions);
101: }
102: if (fschema != null) {
103: dataFind = FinderUtil.cascade(dataFind, fschema);
104: }
105: }
106:
107: isPrepared = true;
108: }
109:
110: /**
111: * Replace the underlying data graph for this inference graph and start any
112: * inferences over again. This is primarily using in setting up ontology imports
113: * processing to allow an imports multiunion graph to be inserted between the
114: * inference graph and the raw data, before processing.
115: * @param data the new raw data graph
116: */
117: public synchronized void rebind(Graph data) {
118: engine.checkSafeToUpdate();
119: fdata = new FGraph(data);
120: isPrepared = false;
121: }
122:
123: /**
124: * Cause the inference graph to reconsult the underlying graph to take
125: * into account changes. Normally changes are made through the InfGraph's add and
126: * remove calls are will be handled appropriately. However, in some cases changes
127: * are made "behind the InfGraph's back" and this forces a full reconsult of
128: * the changed data.
129: */
130: public synchronized void rebind() {
131: version++;
132: engine.checkSafeToUpdate();
133: isPrepared = false;
134: }
135:
136: /**
137: * Flush out all cached results. Future queries have to start from scratch.
138: */
139: public synchronized void reset() {
140: version++;
141: engine.checkSafeToUpdate();
142: engine.reset();
143: }
144:
145: /**
146: * Extended find interface used in situations where the implementator
147: * may or may not be able to answer the complete query. It will
148: * attempt to answer the pattern but if its answers are not known
149: * to be complete then it will also pass the request on to the nested
150: * Finder to append more results.
151: * @param pattern a TriplePattern to be matched against the data
152: * @param continuation either a Finder or a normal Graph which
153: * will be asked for additional match results if the implementor
154: * may not have completely satisfied the query.
155: */
156: public synchronized ExtendedIterator findWithContinuation(
157: TriplePattern pattern, Finder continuation) {
158: checkOpen();
159: if (!isPrepared)
160: prepare();
161: ExtendedIterator result = new UniqueExtendedIterator(engine
162: .find(pattern));
163: if (continuation != null) {
164: result = result.andThen(continuation.find(pattern));
165: }
166: return result.filterDrop(Functor.acceptFilter);
167: }
168:
169: /**
170: * Returns an iterator over Triples.
171: * This implementation assumes that the underlying findWithContinuation
172: * will have also consulted the raw data.
173: */
174: public ExtendedIterator graphBaseFind(Node subject, Node property,
175: Node object) {
176: return findWithContinuation(new TriplePattern(subject,
177: property, object), null);
178: }
179:
180: /**
181: * Basic pattern lookup interface.
182: * This implementation assumes that the underlying findWithContinuation
183: * will have also consulted the raw data.
184: * @param pattern a TriplePattern to be matched against the data
185: * @return a ExtendedIterator over all Triples in the data set
186: * that match the pattern
187: */
188: public ExtendedIterator find(TriplePattern pattern) {
189: return findWithContinuation(pattern, null);
190: }
191:
192: /**
193: * Add one triple to the data graph, run any rules triggered by
194: * the new data item, recursively adding any generated triples.
195: */
196: public synchronized void performAdd(Triple t) {
197: version++;
198: engine.checkSafeToUpdate();
199: fdata.getGraph().add(t);
200: isPrepared = false;
201: }
202:
203: /**
204: * Removes the triple t (if possible) from the set belonging to this graph.
205: */
206: public synchronized void performDelete(Triple t) {
207: version++;
208: engine.checkSafeToUpdate();
209: fdata.getGraph().delete(t);
210: isPrepared = false;
211: }
212:
213: /**
214: * Set a predicate to be tabled/memoized by the LP engine.
215: */
216: public void setTabled(Node predicate) {
217: engine.tablePredicate(predicate);
218: if (isTraceOn()) {
219: logger.info("LP TABLE " + predicate);
220: }
221: }
222:
223: // =======================================================================
224: // support for proof traces
225:
226: /**
227: * Set to true to enable derivation caching
228: */
229: public void setDerivationLogging(boolean recordDerivations) {
230: engine.setDerivationLogging(recordDerivations);
231: if (recordDerivations) {
232: derivations = new OneToManyMap();
233: } else {
234: derivations = null;
235: }
236: }
237:
238: /**
239: * Return the derivation of at triple.
240: * The derivation is a List of DerivationRecords
241: */
242: public Iterator getDerivation(Triple t) {
243: if (derivations == null) {
244: return new NullIterator();
245: } else {
246: return derivations.getAll(t);
247: }
248: }
249:
250: /**
251: * Set the state of the trace flag. If set to true then rule firings
252: * are logged out to the Log at "INFO" level.
253: */
254: public void setTraceOn(boolean state) {
255: engine.setTraceOn(state);
256: }
257:
258: /**
259: * Return true if tracing is switched on
260: */
261: public boolean isTraceOn() {
262: return engine.isTraceOn();
263: }
264:
265: // =======================================================================
266: // Interface between infGraph and the goal processing machinery
267:
268: /**
269: * Log a dervivation record against the given triple.
270: */
271: public void logDerivation(Triple t, Object derivation) {
272: derivations.put(t, derivation);
273: }
274:
275: /**
276: * Match a pattern just against the stored data (raw data, schema,
277: * axioms) but no derivation.
278: */
279: public ExtendedIterator findDataMatches(TriplePattern pattern) {
280: return dataFind.find(pattern);
281: }
282:
283: /**
284: * Process a call to a builtin predicate
285: * @param clause the Functor representing the call
286: * @param env the BindingEnvironment for this call
287: * @param rule the rule which is invoking this call
288: * @return true if the predicate succeeds
289: */
290: public boolean processBuiltin(ClauseEntry clause, Rule rule,
291: BindingEnvironment env) {
292: throw new ReasonerException(
293: "Internal error in FBLP rule engine, incorrect invocation of building in rule "
294: + rule);
295: }
296:
297: /**
298: * Assert a new triple in the deduction graph, bypassing any processing machinery.
299: */
300: public void silentAdd(Triple t) {
301: fdeductions.getGraph().add(t);
302: }
303:
304: /**
305: * Retrieve or create a bNode representing an inferred property value.
306: * @param instance the base instance node to which the property applies
307: * @param prop the property node whose value is being inferred
308: * @param pclass the (optional, can be null) class for the inferred value.
309: * @return the bNode representing the property value
310: */
311: public Node getTemp(Node instance, Node prop, Node pclass) {
312: return tempNodecache.getTemp(instance, prop, pclass);
313: }
314:
315: // =======================================================================
316: // Rule engine extras
317:
318: /**
319: * Find any axioms (rules with no body) in the rule set and
320: * add those to the auxilliary graph to be included in searches.
321: */
322: protected void extractAxioms() {
323: Graph axioms = fdeductions.getGraph();
324: BBRuleContext contextForBuiltins = null;
325: for (Iterator i = engine.getRuleStore().getAllRules()
326: .iterator(); i.hasNext();) {
327: Rule rule = (Rule) i.next();
328: if (rule.bodyLength() == 0) {
329: // An axiom
330: for (int j = 0; j < rule.headLength(); j++) {
331: ClauseEntry axiom = rule.getHeadElement(j);
332: if (axiom instanceof TriplePattern) {
333: axioms.add(((TriplePattern) axiom).asTriple());
334: } else if (axiom instanceof Functor) {
335: if (contextForBuiltins == null) {
336: contextForBuiltins = new BBRuleContext(this );
337: }
338: Functor f = (Functor) axiom;
339: Builtin implementation = f.getImplementor();
340: if (implementation == null) {
341: throw new ReasonerException(
342: "Attempted to invoke undefined functor: "
343: + f);
344: }
345: Node[] args = f.getArgs();
346: contextForBuiltins.setEnv(new BindingVector(
347: args));
348: contextForBuiltins.setRule(rule);
349: implementation.headAction(args, args.length,
350: contextForBuiltins);
351: }
352: }
353: }
354: }
355: }
356:
357: }
358:
359: /*
360: (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
361: All rights reserved.
362:
363: Redistribution and use in source and binary forms, with or without
364: modification, are permitted provided that the following conditions
365: are met:
366:
367: 1. Redistributions of source code must retain the above copyright
368: notice, this list of conditions and the following disclaimer.
369:
370: 2. Redistributions in binary form must reproduce the above copyright
371: notice, this list of conditions and the following disclaimer in the
372: documentation and/or other materials provided with the distribution.
373:
374: 3. The name of the author may not be used to endorse or promote products
375: derived from this software without specific prior written permission.
376:
377: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
378: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
379: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
380: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
381: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
382: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
383: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
384: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
385: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
386: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
387: */
|