/* Copyright 2008, 2009, 2010 by the Oxford University Computing Laboratory This file is part of HermiT. HermiT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. HermiT 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with HermiT. If not, see <http://www.gnu.org/licenses/>. */ package org.semanticweb.HermiT.model; import java.io.Serializable; import java.util.HashSet; import java.util.Set; import org.semanticweb.HermiT.Prefixes; /** * Represents a DL clause. The body is a conjunction of atoms and the head is a disjunction of atoms. */ public class DLClause implements Serializable { private static final long serialVersionUID=-4513910129515151732L; protected final Atom[] m_headAtoms; protected final Atom[] m_bodyAtoms; protected DLClause(Atom[] headAtoms,Atom[] bodyAtoms) { m_headAtoms=headAtoms; m_bodyAtoms=bodyAtoms; } public int getHeadLength() { return m_headAtoms.length; } public Atom getHeadAtom(int atomIndex) { return m_headAtoms[atomIndex]; } public Atom[] getHeadAtoms() { return m_headAtoms.clone(); } public int getBodyLength() { return m_bodyAtoms.length; } public Atom getBodyAtom(int atomIndex) { return m_bodyAtoms[atomIndex]; } public Atom[] getBodyAtoms() { return m_bodyAtoms.clone(); } public DLClause getSafeVersion(DLPredicate safeMakingPredicate) { Set<Variable> variables=new HashSet<Variable>(); // collect all the variables that occur in the head into the set variables for (int headIndex=0;headIndex<m_headAtoms.length;headIndex++) { Atom atom=m_headAtoms[headIndex]; for (int argumentIndex=0;argumentIndex<atom.getArity();argumentIndex++) { Variable variable=atom.getArgumentVariable(argumentIndex); if (variable!=null) variables.add(variable); } } // remove all those variables that occur in the body, so we get a set // with the unsafe variables for (int bodyIndex=0;bodyIndex<m_bodyAtoms.length;bodyIndex++) { Atom atom=m_bodyAtoms[bodyIndex]; for (int argumentIndex=0;argumentIndex<atom.getArity();argumentIndex++) { Variable variable=atom.getArgumentVariable(argumentIndex); if (variable!=null) variables.remove(variable); } } if (m_headAtoms.length==0 && m_bodyAtoms.length==0) variables.add(Variable.create("X")); if (variables.isEmpty()) return this; else { // we need to add a concept atom with the top concept for each of // the unsafe variables Atom[] newBodyAtoms=new Atom[m_bodyAtoms.length+variables.size()]; System.arraycopy(m_bodyAtoms,0,newBodyAtoms,0,m_bodyAtoms.length); int index=m_bodyAtoms.length; for (Variable variable : variables) newBodyAtoms[index++]=Atom.create(safeMakingPredicate,variable); return DLClause.create(m_headAtoms,newBodyAtoms); } } public DLClause getChangedDLClause(Atom[] headAtoms,Atom[] bodyAtoms) { if (headAtoms==null) headAtoms=m_headAtoms; if (bodyAtoms==null) bodyAtoms=m_bodyAtoms; return DLClause.create(headAtoms,bodyAtoms); } public boolean isGeneralConceptInclusion() { if (m_headAtoms.length==0) { // not a GCI if all body atoms are data ranges // could also be an asymmetry axiom of the form r(x, y) and r(y, x) -> bottom if (m_bodyAtoms.length==2 && m_bodyAtoms[0].getArity()==2 && m_bodyAtoms[1].getArity()==2) return false; for (Atom bodyAtom : m_bodyAtoms) if (bodyAtom.getArity()!=1 || !(bodyAtom.getDLPredicate() instanceof DataRange)) return true; } for (Atom headAtom : m_headAtoms) { DLPredicate predicate=headAtom.getDLPredicate(); if (predicate instanceof AtLeast || predicate instanceof LiteralConcept || predicate instanceof AnnotatedEquality || predicate instanceof NodeIDLessEqualThan || predicate instanceof NodeIDsAscendingOrEqual) return true; if (predicate instanceof Equality) { // could be a key, which we do not count as GCI // check if body uses the special named concept for (Atom bodyAtom : m_bodyAtoms) { DLPredicate bodyPredicate=bodyAtom.getDLPredicate(); if (bodyAtom.getArity()==1 && bodyPredicate instanceof AtomicConcept && ((AtomicConcept)bodyPredicate).equals(AtomicConcept.INTERNAL_NAMED)) return false; } } if (predicate instanceof DataRange) { // could be a data range inclusion or a universal, e.g., A -> for all dp.DR for (Atom bodyAtom : m_bodyAtoms) { if (bodyAtom.getArity()==2) return true; } return false; } if (predicate instanceof Role) // role inclusion return false; } return false; } public boolean isAtomicConceptInclusion() { if (m_bodyAtoms.length==1 && m_headAtoms.length==1) { Atom bodyAtom=m_bodyAtoms[0]; Atom headAtom=m_headAtoms[0]; if (bodyAtom.getArity()==1 && headAtom.getArity()==1 && bodyAtom.getDLPredicate() instanceof AtomicConcept && headAtom.getDLPredicate() instanceof AtomicConcept) { Term argument=bodyAtom.getArgument(0); return argument instanceof Variable && argument.equals(headAtom.getArgument(0)); } } return false; } public boolean isAtomicRoleInclusion() { if (m_bodyAtoms.length==1 && m_headAtoms.length==1) { Atom bodyAtom=m_bodyAtoms[0]; Atom headAtom=m_headAtoms[0]; if (bodyAtom.getArity()==2 && headAtom.getArity()==2 && bodyAtom.getDLPredicate() instanceof AtomicRole && headAtom.getDLPredicate() instanceof AtomicRole) { Term argument0=bodyAtom.getArgument(0); Term argument1=bodyAtom.getArgument(1); return argument0 instanceof Variable && argument1 instanceof Variable && !argument0.equals(argument1) && argument0.equals(headAtom.getArgument(0)) && argument1.equals(headAtom.getArgument(1)); } } return false; } public boolean isAtomicRoleInverseInclusion() { if (m_bodyAtoms.length==1 && m_headAtoms.length==1) { Atom bodyAtom=m_bodyAtoms[0]; Atom headAtom=m_headAtoms[0]; if (bodyAtom.getArity()==2 && headAtom.getArity()==2 && bodyAtom.getDLPredicate() instanceof AtomicRole && headAtom.getDLPredicate() instanceof AtomicRole) { Term argument0=bodyAtom.getArgument(0); Term argument1=bodyAtom.getArgument(1); return argument0 instanceof Variable && argument1 instanceof Variable && !argument0.equals(argument1) && argument0.equals(headAtom.getArgument(1)) && argument1.equals(headAtom.getArgument(0)); } } return false; } public boolean isFunctionalityAxiom() { if (m_bodyAtoms.length==2 && m_headAtoms.length==1) { DLPredicate atomicRole=getBodyAtom(0).getDLPredicate(); if (atomicRole instanceof AtomicRole) { if (getBodyAtom(1).getDLPredicate().equals(atomicRole) && (getHeadAtom(0).getDLPredicate() instanceof AnnotatedEquality)) { Variable x=getBodyAtom(0).getArgumentVariable(0); if (x!=null && x.equals(getBodyAtom(1).getArgument(0))) { Variable y1=getBodyAtom(0).getArgumentVariable(1); Variable y2=getBodyAtom(1).getArgumentVariable(1); Variable headY1=getHeadAtom(0).getArgumentVariable(0); Variable headY2=getHeadAtom(0).getArgumentVariable(1); if (y1!=null && y2!=null && !y1.equals(y2) && headY1!=null && headY2!=null && ((y1.equals(headY1) && y2.equals(headY2)) || (y1.equals(headY2) && y2.equals(headY1)))) return true; } } } } return false; } public boolean isInverseFunctionalityAxiom() { if (getBodyLength()==2 && getHeadLength()==1) { DLPredicate atomicRole=getBodyAtom(0).getDLPredicate(); if (atomicRole instanceof AtomicRole) { if (getBodyAtom(1).getDLPredicate().equals(atomicRole) && (getHeadAtom(0).getDLPredicate() instanceof AnnotatedEquality)) { Variable x=getBodyAtom(0).getArgumentVariable(1); if (x!=null && x.equals(getBodyAtom(1).getArgument(1))) { Variable y1=getBodyAtom(0).getArgumentVariable(0); Variable y2=getBodyAtom(1).getArgumentVariable(0); Variable headY1=getHeadAtom(0).getArgumentVariable(0); Variable headY2=getHeadAtom(0).getArgumentVariable(1); if (y1!=null && y2!=null && !y1.equals(y2) && headY1!=null && headY2!=null && ((y1.equals(headY1) && y2.equals(headY2)) || (y1.equals(headY2) && y2.equals(headY1)))) return true; } } } } return false; } public String toString(Prefixes prefixes) { StringBuffer buffer=new StringBuffer(); for (int headIndex=0;headIndex<m_headAtoms.length;headIndex++) { if (headIndex!=0) buffer.append(" v "); buffer.append(m_headAtoms[headIndex].toString(prefixes)); } buffer.append(" :- "); for (int bodyIndex=0;bodyIndex<m_bodyAtoms.length;bodyIndex++) { if (bodyIndex!=0) buffer.append(", "); buffer.append(m_bodyAtoms[bodyIndex].toString(prefixes)); } return buffer.toString(); } public String toString() { return toString(Prefixes.STANDARD_PREFIXES); } protected static InterningManager<DLClause> s_interningManager=new InterningManager<DLClause>() { protected boolean equal(DLClause object1,DLClause object2) { if (object1.m_headAtoms.length!=object2.m_headAtoms.length || object1.m_bodyAtoms.length!=object2.m_bodyAtoms.length) return false; for (int index=object1.m_headAtoms.length-1;index>=0;--index) if (object1.m_headAtoms[index]!=object2.m_headAtoms[index]) return false; for (int index=object1.m_bodyAtoms.length-1;index>=0;--index) if (object1.m_bodyAtoms[index]!=object2.m_bodyAtoms[index]) return false; return true; } protected int getHashCode(DLClause object) { int hashCode=0; for (int index=object.m_bodyAtoms.length-1;index>=0;--index) hashCode+=object.m_bodyAtoms[index].hashCode(); for (int index=object.m_headAtoms.length-1;index>=0;--index) hashCode+=object.m_headAtoms[index].hashCode(); return hashCode; } }; public static DLClause create(Atom[] headAtoms,Atom[] bodyAtoms) { return s_interningManager.intern(new DLClause(headAtoms,bodyAtoms)); } }