package de.unikiel.inf.comsys.neo4j.inference.rules; /* * #%L * neo4j-sparql-extension * %% * Copyright (C) 2014 Niclas Hoyer * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ import com.google.common.base.Joiner; import java.util.Arrays; import java.util.List; import org.openrdf.query.algebra.Join; import org.openrdf.query.algebra.QueryModelNode; import org.openrdf.query.algebra.StatementPattern; import org.openrdf.query.algebra.TupleExpr; import org.openrdf.query.algebra.Union; import org.openrdf.query.algebra.Var; /** * A rule that transforms a statement pattern according to the * SubObjectPropertyOf(ObjectPropertyChain) OWL-2 Axiom. * * @see * <a href="http://www.w3.org/TR/owl2-semantics/#Object_Property_Expression_Axioms"> * OWL-2 property expression axioms * </a> */ public class ObjectPropertyChain extends AbstractRule { private final String op; private final List<String> chain; /** * Create a new object property chain rule with a property and * a list of chain elements. * * @param op a property * @param chain the chain elements */ public ObjectPropertyChain(String op, String... chain) { this(op, Arrays.asList(chain)); } /** * Create a new object property chain rule with a property and * a list of chain elements. * * @param op a property * @param chain the chain elements */ public ObjectPropertyChain(String op, List<String> chain) { this.op = op; this.chain = chain; } /** * Returns true if this rule is applicable to a node. * * @param node to a node * @return true if the rule is applicable, false otherwise */ @Override public boolean canApply(StatementPattern node) { // empty chains are never applicable if (chain.isEmpty()) { return false; } // check if predicate is given object property String op1 = getPredicate(node); return op1 != null && op1.equals(op); } /** * Transform a statement pattern according to OWL-2 property chain * axiom. * * @param node the node to transform * @return list of nodes to visit next */ @Override public List<QueryModelNode> apply(StatementPattern node) { List<QueryModelNode> next = newNextList(); Var s = node.getSubjectVar(); Var o = node.getObjectVar(); Var c = node.getContextVar(); TupleExpr left = node.clone(); TupleExpr right = getChain(s, o, c); node.replaceWith(new Union(left, right)); next.add(left); next.add(right); return next; } /** * Create a object property chain for a given triple. * * @param subject the subject of the triple * @param object the object of the triple * @param context the graph that the triple is stored in * @return an object property chain expression */ private TupleExpr getChain(Var subject, Var object, Var context) { TupleExpr ret; if (chain.size() == 1) { // if the chain has just one element treat it as a SubObjectProperty // axiom Var p = new ConstVar(vf.createURI(chain.get(0))); ret = new StatementPattern(subject, p, object, context); } else { Var p; Var p2; Var o; StatementPattern left; StatementPattern right; Join join; Join newjoin; // start with a chain with two elements p = new ConstVar(vf.createURI(chain.get(0))); p2 = new ConstVar(vf.createURI(chain.get(1))); o = new Var(); o.setName(p.getName() + "-0"); o.setAnonymous(true); left = new StatementPattern(subject, p, o, context); right = new StatementPattern(o, p2, object, context); join = new Join(left, right); ret = join; // for each additional element replace the right side of the last // join with a new join that matches the chain element for (int i=2; i < chain.size(); i++) { p = new ConstVar(vf.createURI(chain.get(i))); o = new Var(); o.setName(p.getName() + "-" + i); o.setAnonymous(true); right.setObjectVar(o); left = right; right = new StatementPattern(o, p, object, context); newjoin = new Join(left, right); join.setRightArg(newjoin); join = newjoin; } } return ret; } @Override public String toString() { String str = ""; if (!chain.isEmpty()) { str += " <"; str += Joiner.on("> <").join(chain) + ">"; } return "ObjectPropertyChain(<" + op + ">" + str + ")"; } }