001: /******************************************************************
002: * File: TriplePattern.java
003: * Created by: Dave Reynolds
004: * Created on: 18-Jan-03
005: *
006: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
007: * [See end of file]
008: * $Id: TriplePattern.java,v 1.28 2008/01/02 12:07:00 andy_seaborne Exp $
009: *****************************************************************/package com.hp.hpl.jena.reasoner;
010:
011: import java.util.Map;
012:
013: import com.hp.hpl.jena.graph.*;
014: import com.hp.hpl.jena.reasoner.rulesys.ClauseEntry;
015: import com.hp.hpl.jena.reasoner.rulesys.Functor;
016: import com.hp.hpl.jena.reasoner.rulesys.Node_RuleVariable;
017: import com.hp.hpl.jena.util.CollectionFactory;
018: import com.hp.hpl.jena.vocabulary.RDF;
019: import com.hp.hpl.jena.vocabulary.RDFS;
020:
021: /**
022: * Datastructure which defines a triple pattern as used in simple
023: * rules and in find interfaces.
024: * <p>
025: * Wildcards are recorded by using Node_RuleVariable entries rather than
026: * nulls because they can be named. If a null is specified that is
027: * converted to a variable of name "". Note that whilst some engines might simply
028: * require Node_Variables the forward engine requires variables represented using
029: * the more specialized subclass - Node_RuleVariable.</p>
030: * <p>
031: * It would make more sense to have TriplePattern subclass Triple
032: * but that is final for some strange reason.</p>
033: *
034: * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
035: * @version $Revision: 1.28 $ on $Date: 2008/01/02 12:07:00 $
036: */
037: public class TriplePattern implements ClauseEntry {
038:
039: /** The subject element of the pattern */
040: protected Node subject;
041:
042: /** The predicate element of the pattern */
043: protected Node predicate;
044:
045: /** The object element of the pattern */
046: protected Node object;
047:
048: /**
049: * Constructor - builds a pattern from three nodes,
050: * use Node_RuleVariables as variables, use a variable
051: * with an empty name as a wildcard, can also use null
052: * as a wildcard.
053: */
054: public TriplePattern(Node subject, Node predicate, Node object) {
055: this .subject = normalize(subject);
056: this .predicate = normalize(predicate);
057: this .object = normalize(object);
058: }
059:
060: /**
061: * Constructor - builds a pattern from a standard triple match.
062: * Node that any filter part of the triple match will not be
063: * represented within the pattern and will need to be checked
064: * for separately.
065: */
066: public TriplePattern(TripleMatch match) {
067: this .subject = normalize(match.getMatchSubject());
068: this .predicate = normalize(match.getMatchPredicate());
069: this .object = normalize(match.getMatchObject());
070: }
071:
072: /**
073: * Constructor - builds a dgenerate pattern from a simple triple.
074: * This would be much easier if we merged Triples and TriplePatterns!
075: */
076: public TriplePattern(Triple match) {
077: this .subject = normalize(match.getSubject());
078: this .predicate = normalize(match.getPredicate());
079: this .object = normalize(match.getObject());
080: }
081:
082: /**
083: * Returns the object.
084: * @return Node
085: */
086: public Node getObject() {
087: return object;
088: }
089:
090: /**
091: * Returns the predicate.
092: * @return Node
093: */
094: public Node getPredicate() {
095: return predicate;
096: }
097:
098: /**
099: * Returns the subject.
100: * @return Node
101: */
102: public Node getSubject() {
103: return subject;
104: }
105:
106: /**
107: * Return the triple pattern as a triple match
108: */
109: public TripleMatch asTripleMatch() {
110: return Triple.createMatch(toMatch(subject), toMatch(predicate),
111: toMatch(object));
112: }
113:
114: /**
115: * Return the triple pattern as a triple
116: */
117: public Triple asTriple() {
118: return new Triple(subject, predicate, object);
119: }
120:
121: /**
122: * Compare two patterns for compatibility - i.e. potentially unifiable.
123: * Two patterns are "compatible" in the sense we mean here
124: * if all their ground terms match. A variable in either pattern
125: * can match a ground term or a variable in the other. We are not,
126: * currently, checking for multiple occurances of the same variable.
127: * Functor-valued object literals are treated as a special case which
128: * are only checked for name/arity matching.
129: */
130: public boolean compatibleWith(TriplePattern pattern) {
131: boolean ok = subject.isVariable()
132: || pattern.subject.isVariable()
133: || subject.equals(pattern.subject);
134: if (!ok)
135: return false;
136: ok = predicate.isVariable() || pattern.predicate.isVariable()
137: || predicate.equals(pattern.predicate);
138: if (!ok)
139: return false;
140: if (object.isVariable() || pattern.object.isVariable())
141: return true;
142: // Left with checking compatibility of ground literals
143: if (Functor.isFunctor(object)
144: && Functor.isFunctor(pattern.object)) {
145: Functor functor = (Functor) object.getLiteralValue();
146: Functor pFunctor = (Functor) pattern.object
147: .getLiteralValue();
148: return (functor.getName().equals(pFunctor.getName()) && functor
149: .getArgs().length == pFunctor.getArgs().length);
150: } else {
151: return object.sameValueAs(pattern.object);
152: }
153: }
154:
155: /**
156: * Test if a pattern is just a variant of this pattern. I.e. it is the same
157: * up to variable renaming. This takes into account multiple occurances
158: * of the same variable.
159: */
160: public boolean variantOf(TriplePattern pattern) {
161: Map vmap = CollectionFactory.createHashedMap();
162: if (!variantOf(subject, pattern.subject, vmap))
163: return false;
164: if (!variantOf(predicate, pattern.predicate, vmap))
165: return false;
166: if (Functor.isFunctor(object)
167: && Functor.isFunctor(pattern.object)) {
168: Functor functor = (Functor) object.getLiteralValue();
169: Functor pFunctor = (Functor) pattern.object
170: .getLiteralValue();
171: if (!functor.getName().equals(pFunctor.getName()))
172: return false;
173: Node[] args = functor.getArgs();
174: Node[] pargs = pFunctor.getArgs();
175: if (args.length != pargs.length)
176: return false;
177: for (int i = 0; i < args.length; i++) {
178: if (!variantOf(args[i], pargs[i], vmap))
179: return false;
180: }
181: return true;
182: } else {
183: return variantOf(object, pattern.object, vmap);
184: }
185: }
186:
187: /**
188: * Test if one node is a variant of another give a table of variable matches.
189: */
190: private boolean variantOf(Node n, Node p, Map vmap) {
191: if (n instanceof Node_RuleVariable) {
192: if (p instanceof Node_RuleVariable) {
193: Object nMatch = vmap.get(n);
194: if (nMatch == null) {
195: // First match of these pairs
196: vmap.put(n, p);
197: return true;
198: } else {
199: return nMatch == p;
200: }
201: } else {
202: return false;
203: }
204: } else {
205: return n.sameValueAs(p);
206: }
207: }
208:
209: /**
210: * Check a pattern to see if it is legal, used to exclude backchaining goals that
211: * could never be satisfied. A legal pattern cannot have literals in the subject or
212: * predicate positions and is not allowed nested functors in the object.
213: */
214: public boolean isLegal() {
215: if (subject.isLiteral() || predicate.isLiteral())
216: return false;
217: if (Functor.isFunctor(subject))
218: return false;
219: if (Functor.isFunctor(object)) {
220: Node[] args = ((Functor) object.getLiteralValue())
221: .getArgs();
222: for (int i = 0; i < args.length; i++) {
223: if (Functor.isFunctor(args[i]))
224: return false;
225: }
226: }
227: return true;
228: }
229:
230: /**
231: * Compare two patterns and return true if arg is a more
232: * specific (more grounded) version of this one.
233: * Does not handle functors.
234: */
235: public boolean subsumes(TriplePattern arg) {
236: return (subject.isVariable() || subject.equals(arg.subject))
237: && (predicate.isVariable() || predicate
238: .equals(arg.predicate))
239: && (object.isVariable() || object.equals(arg.object));
240: }
241:
242: /**
243: * Test if the pattern is ground, contains no variables.
244: */
245: public boolean isGround() {
246: if (subject.isVariable() || predicate.isVariable()
247: || object.isVariable())
248: return false;
249: if (Functor.isFunctor(object)) {
250: return ((Functor) object.getLiteralValue()).isGround();
251: }
252: return true;
253: }
254:
255: /**
256: * Printable string
257: */
258: public String toString() {
259: return simplePrintString(subject) + " @"
260: + simplePrintString(predicate) + " "
261: + simplePrintString(object);
262: }
263:
264: /**
265: * Simplified printable name for a triple
266: */
267: public static String simplePrintString(Triple t) {
268: return simplePrintString(t.getSubject()) + " @"
269: + simplePrintString(t.getPredicate()) + " "
270: + simplePrintString(t.getObject());
271: }
272:
273: /**
274: * Simplified printable name for a node
275: */
276: public static String simplePrintString(Node n) {
277: if (n instanceof Node_URI) {
278: String uri = n.getURI();
279: int split = uri.lastIndexOf('#');
280: if (split == -1) {
281: split = uri.lastIndexOf('/');
282: if (split == -1)
283: split = -1;
284: }
285: String ns = uri.substring(0, split + 1);
286: String prefix = "";
287: if (ns.equals(RDF.getURI())) {
288: prefix = "rdf:";
289: } else if (ns.equals(RDFS.getURI())) {
290: prefix = "rdfs:";
291: }
292: return prefix + uri.substring(split + 1);
293: } else {
294: return n.toString();
295: }
296: }
297:
298: /**
299: * Convert any null wildcards to Node_RuleVariable wildcards.
300: */
301: private static Node normalize(Node node) {
302: if (node == null || node == Node.ANY)
303: return Node_RuleVariable.WILD;
304: // if (node == null) return Node.ANY;
305: return node;
306: }
307:
308: /**
309: * Convert any Node_RuleVariable wildcards to null. This loses
310: * the variable named but is used when converting a singleton
311: * pattern to a TripleMtch
312: */
313: private static Node toMatch(Node node) {
314: return node.isVariable() ? null : node;
315: }
316:
317: /**
318: * Equality override - used so that TriplePattern variants (same to within variable renaming) test as equals
319: */
320: public boolean equals(Object o) {
321: // return o instanceof TriplePattern &&
322: // subject.equals(((TriplePattern)o).subject) &&
323: // predicate.equals(((TriplePattern)o).predicate) &&
324: // object.equals(((TriplePattern)o).object);
325: return o instanceof TriplePattern
326: && nodeEqual(subject, ((TriplePattern) o).subject)
327: && nodeEqual(predicate, ((TriplePattern) o).predicate)
328: && nodeEqual(object, ((TriplePattern) o).object);
329: }
330:
331: /** Helper - equality override on nodes */
332: private boolean nodeEqual(Node n1, Node n2) {
333: if ((n1 instanceof Node_RuleVariable)
334: && (n2 instanceof Node_RuleVariable)) {
335: return true;
336: } else {
337: return n1.equals(n2);
338: }
339: }
340:
341: /** hash function override */
342: public int hashCode() {
343: int hash = 0;
344: if (!(subject instanceof Node_RuleVariable))
345: hash ^= (subject.hashCode() >> 1);
346: if (!(predicate instanceof Node_RuleVariable))
347: hash ^= predicate.hashCode();
348: if (!(object instanceof Node_RuleVariable))
349: hash ^= (object.hashCode() << 1);
350: return hash;
351: // return (subject.hashCode() >> 1) ^ predicate.hashCode() ^ (object.hashCode() << 1);
352: }
353:
354: /**
355: * Compare triple patterns, taking into account variable indices.
356: * The equality function ignores differences between variables.
357: */
358: public boolean sameAs(Object o) {
359: if (!(o instanceof TriplePattern))
360: return false;
361: TriplePattern other = (TriplePattern) o;
362: return Node_RuleVariable.sameNodeAs(subject, other.subject)
363: && Node_RuleVariable.sameNodeAs(predicate,
364: other.predicate)
365: && Node_RuleVariable.sameNodeAs(object, other.object);
366: }
367:
368: }
369:
370: /*
371: (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
372: All rights reserved.
373:
374: Redistribution and use in source and binary forms, with or without
375: modification, are permitted provided that the following conditions
376: are met:
377:
378: 1. Redistributions of source code must retain the above copyright
379: notice, this list of conditions and the following disclaimer.
380:
381: 2. Redistributions in binary form must reproduce the above copyright
382: notice, this list of conditions and the following disclaimer in the
383: documentation and/or other materials provided with the distribution.
384:
385: 3. The name of the author may not be used to endorse or promote products
386: derived from this software without specific prior written permission.
387:
388: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
389: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
390: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
391: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
392: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
393: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
394: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
395: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
396: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
397: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
398: */
|