package uk.ac.manchester.cs.jfact.split;
/* This file is part of the JFact DL reasoner
Copyright 2011-2013 by Ignazio Palmisano, Dmitry Tsarkov, University of Manchester
This library 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 2.1 of the License, or (at your option) any later version.
This library 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 this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*/
import java.io.Serializable;
import uk.ac.manchester.cs.jfact.datatypes.Datatype;
import uk.ac.manchester.cs.jfact.datatypes.Literal;
import uk.ac.manchester.cs.jfact.datatypes.cardinality;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptAnd;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptBottom;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptDataExactCardinality;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptDataExists;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptDataForall;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptDataMaxCardinality;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptDataMinCardinality;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptDataValue;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptName;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptNot;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptObjectExactCardinality;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptObjectExists;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptObjectForall;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptObjectMaxCardinality;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptObjectMinCardinality;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptObjectSelf;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptObjectValue;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptOneOf;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptOr;
import uk.ac.manchester.cs.jfact.kernel.dl.ConceptTop;
import uk.ac.manchester.cs.jfact.kernel.dl.DataAnd;
import uk.ac.manchester.cs.jfact.kernel.dl.DataBottom;
import uk.ac.manchester.cs.jfact.kernel.dl.DataNot;
import uk.ac.manchester.cs.jfact.kernel.dl.DataOneOf;
import uk.ac.manchester.cs.jfact.kernel.dl.DataOr;
import uk.ac.manchester.cs.jfact.kernel.dl.DataRoleBottom;
import uk.ac.manchester.cs.jfact.kernel.dl.DataRoleName;
import uk.ac.manchester.cs.jfact.kernel.dl.DataRoleTop;
import uk.ac.manchester.cs.jfact.kernel.dl.DataTop;
import uk.ac.manchester.cs.jfact.kernel.dl.ObjectRoleBottom;
import uk.ac.manchester.cs.jfact.kernel.dl.ObjectRoleChain;
import uk.ac.manchester.cs.jfact.kernel.dl.ObjectRoleInverse;
import uk.ac.manchester.cs.jfact.kernel.dl.ObjectRoleName;
import uk.ac.manchester.cs.jfact.kernel.dl.ObjectRoleProjectionFrom;
import uk.ac.manchester.cs.jfact.kernel.dl.ObjectRoleProjectionInto;
import uk.ac.manchester.cs.jfact.kernel.dl.ObjectRoleTop;
import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.ConceptExpression;
import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.DataExpression;
import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.Expression;
import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.ObjectRoleExpression;
import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.RoleExpression;
import uk.ac.manchester.cs.jfact.visitors.DLExpressionVisitor;
import conformance.PortedFrom;
/**
* check whether class expressions are equivalent to bottom wrt given locality
* class
*/
// XXX verify unused parameters
@PortedFrom(file = "SyntacticLocalityChecker.h", name = "BotEquivalenceEvaluator")
public class BotEquivalenceEvaluator extends SigAccessor implements
DLExpressionVisitor, Serializable {
private static final long serialVersionUID = 11000L;
/** corresponding top evaluator */
@PortedFrom(file = "SyntacticLocalityChecker.h", name = "TopEval")
private TopEquivalenceEvaluator TopEval = null;
/** keep the value here */
@PortedFrom(file = "SyntacticLocalityChecker.h", name = "isBotEq")
private boolean isBotEq = false;
/**
* check whether the expression is top-equivalent
*
* @param expr
* expr
* @return true if top equivalent
*/
@PortedFrom(file = "SyntacticLocalityChecker.h", name = "isTopEquivalent")
private boolean isTopEquivalent(Expression expr) {
return TopEval.isTopEquivalent(expr);
}
/**
* @param expr
* expr
* @return true iff role expression in equivalent to const wrt locality
*/
@PortedFrom(file = "SyntacticLocalityChecker.h", name = "isREquivalent")
private boolean isREquivalent(Expression expr) {
return sig.topRLocal() ? isTopEquivalent(expr) : isBotEquivalent(expr);
}
// non-empty Concept/Data expression
/**
* @param C
* C
* @return true iff C^I is non-empty
*/
private boolean isBotDistinct(Expression C) {
// TOP is non-empty
if (isTopEquivalent(C)) {
return true;
}
// built-in DT are non-empty
// FIXME!! that's it for now
return C instanceof Datatype;
}
// cardinality of a concept/data expression interpretation
/**
* @param C
* C
* @param n
* n
* @return true if #C^I > n
*/
private boolean isCardLargerThan(Expression C, int n) {
// data top is infinite
if (C instanceof DataExpression && isTopEquivalent(C)) {
return true;
}
if (n == 0) {
return isBotDistinct(C);
}
if (C instanceof Datatype) { // string/time are infinite DT
return ((Datatype<?>) C).getCardinality() == cardinality.COUNTABLYINFINITE;
}
// FIXME!! try to be more precise
return false;
}
// QCRs
/**
* @param n
* n
* @param R
* R
* @param C
* C
* @return true iff (>= n R.C) is botEq
*/
private boolean isMinBotEquivalent(int n, RoleExpression R, Expression C) {
return n > 0 && (isBotEquivalent(R) || isBotEquivalent(C));
}
/**
* @param n
* n
* @param R
* R
* @param C
* C
* @return true iff (<= n R.C) is botEq
*/
private boolean isMaxBotEquivalent(int n, RoleExpression R, Expression C) {
return isTopEquivalent(R) && isCardLargerThan(C, n);
}
// set fields
/**
* set the corresponding top evaluator
*
* @param eval
* eval
*/
@PortedFrom(file = "SyntacticLocalityChecker.h", name = "setTopEval")
protected void setTopEval(TopEquivalenceEvaluator eval) {
TopEval = eval;
}
/**
* @param expr
* expr
* @return true iff an EXPRession is equivalent to bottom wrt defined policy
*/
@PortedFrom(file = "SyntacticLocalityChecker.h", name = "isBotEquivalent")
protected boolean isBotEquivalent(Expression expr) {
expr.accept(this);
return isBotEq;
}
// concept expressions
@Override
public void visit(ConceptTop expr) {
isBotEq = false;
}
@Override
public void visit(ConceptBottom expr) {
isBotEq = true;
}
// FaCT++ extension: equivalent to R(x,y) and C(x), so copy behaviour from
// ER.X
@Override
public void visit(ObjectRoleProjectionFrom expr) {
isBotEq = isMinBotEquivalent(1, expr.getOR(), expr.getConcept());
}
// FaCT++ extension: equivalent to R(x,y) and C(y), so copy behaviour from
// ER.X
@Override
public void visit(ObjectRoleProjectionInto expr) {
isBotEq = isMinBotEquivalent(1, expr.getOR(), expr.getConcept());
}
@Override
public void visit(ConceptName expr) {
isBotEq = !sig.topCLocal() && !sig.contains(expr);
}
@Override
public void visit(ConceptNot expr) {
isBotEq = isTopEquivalent(expr.getConcept());
}
@Override
public void visit(ConceptAnd expr) {
for (ConceptExpression p : expr.getArguments()) {
if (isBotEquivalent(p)) {
return;
}
}
isBotEq = false;
}
@Override
public void visit(ConceptOr expr) {
for (ConceptExpression p : expr.getArguments()) {
if (!isBotEquivalent(p)) {
return;
}
}
isBotEq = true;
}
@Override
public void visit(ConceptOneOf<?> expr) {
isBotEq = expr.isEmpty();
}
@Override
public void visit(ConceptObjectSelf expr) {
isBotEq = isBotEquivalent(expr.getOR());
}
@Override
public void visit(ConceptObjectValue expr) {
isBotEq = isBotEquivalent(expr.getOR());
}
@Override
public void visit(ConceptObjectExists expr) {
isBotEq = isMinBotEquivalent(1, expr.getOR(), expr.getConcept());
}
@Override
public void visit(ConceptObjectForall expr) {
isBotEq = isTopEquivalent(expr.getOR())
&& isBotEquivalent(expr.getConcept());
}
@Override
public void visit(ConceptObjectMinCardinality expr) {
isBotEq = expr.getCardinality() > 0
&& (isBotEquivalent(expr.getConcept()) || !sig.topRLocal()
&& isBotEquivalent(expr.getOR()));
}
@Override
public void visit(ConceptObjectMaxCardinality expr) {
isBotEq = sig.topRLocal() && expr.getCardinality() > 0
&& isTopEquivalent(expr.getOR())
&& isTopEquivalent(expr.getConcept());
}
@Override
public void visit(ConceptObjectExactCardinality expr) {
int n = expr.getCardinality();
ObjectRoleExpression R = expr.getOR();
ConceptExpression C = expr.getConcept();
isBotEq = isMinBotEquivalent(n, R, C) || isMaxBotEquivalent(n, R, C);
}
@Override
public void visit(ConceptDataValue expr) {
isBotEq = isBotEquivalent(expr.getDataRoleExpression());
}
@Override
public void visit(ConceptDataExists expr) {
isBotEq = isMinBotEquivalent(1, expr.getDataRoleExpression(),
expr.getExpr());
}
@Override
public void visit(ConceptDataForall expr) {
isBotEq = isTopEquivalent(expr.getDataRoleExpression())
&& !isTopEquivalent(expr.getExpr());
}
@Override
public void visit(ConceptDataMinCardinality expr) {
isBotEq = !sig.topRLocal() && expr.getCardinality() > 0
&& isBotEquivalent(expr.getDataRoleExpression());
}
@Override
public void visit(ConceptDataMaxCardinality expr) {
isBotEq = sig.topRLocal()
&& isTopEquivalent(expr.getDataRoleExpression())
&& (expr.getCardinality() <= 1 ? isTopOrBuiltInDataType(expr
.getExpr()) : isTopOrBuiltInDataType(expr.getExpr()));
}
@Override
public void visit(ConceptDataExactCardinality expr) {
isBotEq = isREquivalent(expr.getDataRoleExpression())
&& (sig.topRLocal() ? expr.getCardinality() == 0 ? isTopOrBuiltInDataType(expr
.getExpr()) : isTopOrBuiltInDataType(expr.getExpr())
: expr.getCardinality() > 0);
}
// object role expressions
@Override
public void visit(ObjectRoleTop expr) {
isBotEq = false;
}
@Override
public void visit(ObjectRoleBottom expr) {
isBotEq = true;
}
@Override
public void visit(ObjectRoleName expr) {
isBotEq = !sig.topRLocal() && !sig.contains(expr);
}
@Override
public void visit(ObjectRoleInverse expr) {
isBotEq = isBotEquivalent(expr.getOR());
}
@Override
public void visit(ObjectRoleChain expr) {
isBotEq = true;
for (ObjectRoleExpression p : expr.getArguments()) {
if (isBotEquivalent(p)) {
return;
}
}
isBotEq = false;
}
// data role expressions
@Override
public void visit(DataRoleTop expr) {
isBotEq = false;
}
@Override
public void visit(DataRoleBottom expr) {
isBotEq = true;
}
@Override
public void visit(DataRoleName expr) {
isBotEq = !sig.topRLocal() && !sig.contains(expr);
}
// data expressions
@Override
public void visit(DataTop arg) {
isBotEq = false;
}
@Override
public void visit(DataBottom arg) {
isBotEq = true;
}
@Override
public void visit(Datatype<?> arg) {
isBotEq = false;
}
@Override
public void visit(Literal<?> arg) {
isBotEq = false;
}
@Override
public void visit(DataNot expr) {
isBotEq = isTopEquivalent(expr.getExpr());
}
@Override
public void visit(DataAnd expr) {
for (DataExpression p : expr.getArguments()) {
if (isBotEquivalent(p)) {
return;
}
}
isBotEq = false;
}
@Override
public void visit(DataOr expr) {
for (DataExpression p : expr.getArguments()) {
if (!isBotEquivalent(p)) {
return;
}
}
isBotEq = true;
}
@Override
public void visit(DataOneOf expr) {
isBotEq = expr.isEmpty();
}
}