001: /******************************************************************
002: * File: OWLRuleReasoner.java
003: * Created by: Dave Reynolds
004: * Created on: 11-Apr-2003
005: *
006: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
007: * [See end of file]
008: * $Id: OWLRuleReasoner.java,v 1.9 2008/01/02 12:09:44 andy_seaborne Exp $
009: *****************************************************************/package com.hp.hpl.jena.reasoner.rulesys.impl.oldCode;
010:
011: import java.util.*;
012: import org.apache.commons.logging.Log;
013: import org.apache.commons.logging.LogFactory;
014:
015: import com.hp.hpl.jena.reasoner.*;
016: import com.hp.hpl.jena.reasoner.rulesys.BasicForwardRuleInfGraph;
017: import com.hp.hpl.jena.reasoner.rulesys.BasicForwardRuleReasoner;
018: import com.hp.hpl.jena.reasoner.rulesys.ClauseEntry;
019: import com.hp.hpl.jena.reasoner.rulesys.Functor;
020: import com.hp.hpl.jena.reasoner.rulesys.Node_RuleVariable;
021: import com.hp.hpl.jena.reasoner.rulesys.Rule;
022: import com.hp.hpl.jena.reasoner.rulesys.Util;
023: import com.hp.hpl.jena.shared.WrappedIOException;
024: import com.hp.hpl.jena.vocabulary.*;
025: import com.hp.hpl.jena.graph.*;
026:
027: /**
028: * @deprecated Obsoleted post jena2.0, replaced by
029: * {@link com.hp.hpl.jena.reasoner.rulesys.OWLFBRuleReasoner}.
030: *
031: * An pure forward chaining implementation of the experimental OWL closure rules
032: * based upon the basic forward rule interpreter. This is not a serious or
033: * usable OWL implementation, it is a tool for developing the rules.
034: * <p>
035: * TODO: Replace intersection-translation step by rule based alternative (or failing that
036: * figure out what should be done at the bindSchema stage).
037: *
038: * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
039: * @version $Revision: 1.9 $ on $Date: 2008/01/02 12:09:44 $
040: */
041: public class OWLRuleReasoner extends BasicForwardRuleReasoner {
042:
043: /** The location of the OWL rule definitions on the class path */
044: protected static final String RULE_FILE = "etc/owl.rules";
045:
046: /** The parsed rules */
047: protected static List ruleSet;
048:
049: protected static Log logger = LogFactory
050: .getLog(OWLRuleReasoner.class);
051:
052: /** Performance statistics - the total number of rule firings used during data bind operations so far. */
053: protected static long nRulesFired = 0;
054:
055: /** Performance statistics - the total elapsed time spent during data bind operations so far, in ms. */
056: protected static long timeCost = 0;
057:
058: /**
059: * Constructor
060: */
061: public OWLRuleReasoner() {
062: super (loadRules(), OWLRuleReasonerFactory.theInstance());
063:
064: }
065:
066: /**
067: * Internal constructor, used to generated a partial binding of a schema
068: * to a rule reasoner instance.
069: */
070: private OWLRuleReasoner(List rules, InfGraph schemaGraph) {
071: super (rules, OWLRuleReasonerFactory.theInstance());
072: this .rules = rules;
073: this .schemaGraph = schemaGraph;
074: }
075:
076: /**
077: * Return the RDFS rule set, loading it in if necessary
078: */
079: public static List loadRules() {
080: if (ruleSet == null) {
081: try {
082: ruleSet = Rule.parseRules(Util
083: .loadRuleParserFromResourceFile(RULE_FILE));
084: } catch (WrappedIOException e) {
085: throw new ReasonerException("Can't load rules file: "
086: + RULE_FILE, e);
087: }
088: }
089: return ruleSet;
090: }
091:
092: /**
093: * Precompute the implications of a schema graph.
094: * The practical benefit of this has not yet been fully checked out.
095: */
096: public Reasoner bindSchema(Graph tbox) throws ReasonerException {
097: InfGraph graph = new BasicForwardRuleInfGraph(this , rules, tbox);
098: // Process the scehma looking for any intersection declarations
099: // that we translate into addtiional rules procedurally (for now at least)
100: Iterator i = tbox.find(null, OWL.intersectionOf.asNode(), null);
101: ArrayList rules = (ArrayList) ruleSet;
102: if (i.hasNext()) {
103: rules = (ArrayList) rules.clone();
104: while (i.hasNext()) {
105: translateIntersectionOf((Triple) i.next(), rules, tbox);
106: }
107: }
108: return new OWLRuleReasoner(rules, graph);
109: }
110:
111: /**
112: * Attach the reasoner to a set of RDF data to process.
113: * The reasoner may already have been bound to specific rules or ontology
114: * axioms (encoded in RDF) through earlier bindRuleset calls.
115: *
116: * @param data the RDF data to be processed, some reasoners may restrict
117: * the range of RDF which is legal here (e.g. syntactic restrictions in OWL).
118: * @return an inference graph through which the data+reasoner can be queried.
119: * @throws ReasonerException if the data is ill-formed according to the
120: * constraints imposed by this reasoner.
121: */
122: public InfGraph bind(Graph data) throws ReasonerException {
123: // First process the data looking for any intersection declarations
124: // that we translate into addtiional rules procedurally (for now at least)
125: long startTime = System.currentTimeMillis();
126: Iterator i = data.find(null, OWL.intersectionOf.asNode(), null);
127: ArrayList rules = (ArrayList) ruleSet;
128: if (i.hasNext()) {
129: rules = (ArrayList) rules.clone();
130: while (i.hasNext()) {
131: translateIntersectionOf((Triple) i.next(), rules, data);
132: }
133: }
134:
135: // Now create the inference graph
136: BasicForwardRuleInfGraph graph = new BasicForwardRuleInfGraph(
137: this , rules, schemaGraph);
138: graph.setDerivationLogging(recordDerivations);
139: graph.setTraceOn(traceOn);
140: graph.rebind(data);
141: long endTime = System.currentTimeMillis();
142: timeCost += (double) (endTime - startTime);
143: nRulesFired += graph.getNRulesFired();
144:
145: return graph;
146: }
147:
148: /**
149: * Print (to the default logging channel at Info level) a summary of the
150: * total number of rules fired and the time taken by
151: * the reasoner instances created thus far.
152: */
153: public static void printStats() {
154: logger.info("Fired " + nRulesFired + " over "
155: + (timeCost / 1000.0) + " s = "
156: + (nRulesFired * 1000 / timeCost) + " r/s");
157: }
158:
159: /**
160: * Translation code to compile intersectionOf declarations.
161: * In the future this will be replaced by a rule-baesd translator which will cope
162: * with dynamic expressions.
163: * @param decl a triple of the form (C owl:intersectionOf [..])
164: * @param rules a list of rules to be extended
165: * @param data the source data to use as a context for this processing
166: */
167: private void translateIntersectionOf(Triple decl, List rules,
168: Graph data) {
169: Node className = decl.getSubject();
170: List elements = new ArrayList();
171: translateIntersectionList(decl.getObject(), data, elements);
172: // Generate the corresponding ruleset
173: List recognitionBody = new ArrayList();
174: Node var = new Node_RuleVariable("?x", 0);
175: for (Iterator i = elements.iterator(); i.hasNext();) {
176: Node description = (Node) i.next();
177: // Implication rule
178: Rule ir = new Rule("intersectionImplication",
179: new ClauseEntry[] { new TriplePattern(className,
180: RDFS.subClassOf.asNode(), description) },
181: new ClauseEntry[0]);
182: rules.add(ir);
183: //System.out.println("Adding rule: " + ir.toString());
184: // Recognition rule elements
185: recognitionBody.add(new TriplePattern(var, RDF.type
186: .asNode(), description));
187: }
188: List recognitionHead = new ArrayList(1);
189: recognitionHead.add(new TriplePattern(var, RDF.type.asNode(),
190: className));
191: Rule rr = new Rule("intersectionRecognition", recognitionHead,
192: recognitionBody);
193: //System.out.println("Adding rule: " + rr.toString());
194: rules.add(rr);
195: }
196:
197: /**
198: * Translation code to translate a list of intersection elements into a
199: * Java list of corresponding class names or restriction functors.
200: * @param node the list node currently being processed
201: * @param data the source data to use as a context for this processing
202: * @param elements the list of elements found so far
203: */
204: private void translateIntersectionList(Node node, Graph data,
205: List elements) {
206: if (node.equals(RDF.nil.asNode())) {
207: return; // end of list
208: }
209: Node description = Util.getPropValue(node, RDF.first.asNode(),
210: data);
211: // Translate the first description element
212: if (data.contains(description, RDF.type.asNode(),
213: OWL.Restriction.asNode())) {
214: // Process a restriction element
215: Node onprop = Util.getPropValue(description, OWL.onProperty
216: .asNode(), data);
217: Node value;
218: if ((value = Util.getPropValue(description,
219: OWL.allValuesFrom.asNode(), data)) != null) {
220: elements.add(Functor.makeFunctorNode("all", new Node[] {
221: onprop, value }));
222: } else if ((value = Util.getPropValue(description,
223: OWL.someValuesFrom.asNode(), data)) != null) {
224: elements.add(Functor.makeFunctorNode("some",
225: new Node[] { onprop, value }));
226: } else if ((value = Util.getPropValue(description,
227: OWL.minCardinality.asNode(), data)) != null) {
228: elements.add(Functor.makeFunctorNode("min", new Node[] {
229: onprop, value }));
230: } else if ((value = Util.getPropValue(description,
231: OWL.maxCardinality.asNode(), data)) != null) {
232: elements.add(Functor.makeFunctorNode("max", new Node[] {
233: onprop, value }));
234: } else if ((value = Util.getPropValue(description,
235: OWL.cardinality.asNode(), data)) != null) {
236: elements.add(Functor.makeFunctorNode("max", new Node[] {
237: onprop, value }));
238: elements.add(Functor.makeFunctorNode("min", new Node[] {
239: onprop, value }));
240: }
241: } else {
242: // Assume its a class name
243: elements.add(description);
244: }
245: // Process the list tail
246: Node next = Util.getPropValue(node, RDF.rest.asNode(), data);
247: translateIntersectionList(next, data, elements);
248: }
249:
250: }
251:
252: /*
253: (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
254: All rights reserved.
255:
256: Redistribution and use in source and binary forms, with or without
257: modification, are permitted provided that the following conditions
258: are met:
259:
260: 1. Redistributions of source code must retain the above copyright
261: notice, this list of conditions and the following disclaimer.
262:
263: 2. Redistributions in binary form must reproduce the above copyright
264: notice, this list of conditions and the following disclaimer in the
265: documentation and/or other materials provided with the distribution.
266:
267: 3. The name of the author may not be used to endorse or promote products
268: derived from this software without specific prior written permission.
269:
270: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
271: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
272: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
273: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
274: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
275: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
276: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
277: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
278: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
279: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
280: */
|