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 uk.ac.manchester.cs.jfact.datatypes.Datatype; import uk.ac.manchester.cs.jfact.datatypes.DatatypeExpression; import uk.ac.manchester.cs.jfact.datatypes.Literal; 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.Expression; import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.NAryExpression; import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.NamedEntity; import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.ObjectRoleExpression; import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.RoleExpression; abstract class CardinalityEvaluatorBase extends SigAccessor { private static final long serialVersionUID = 11000L; protected UpperBoundDirectEvaluator UBD; protected LowerBoundDirectEvaluator LBD; protected UpperBoundComplementEvaluator UBC; protected LowerBoundComplementEvaluator LBC; // / keep the value here protected int value; // methods to // / main method to use protected int getValue(Expression expr) { expr.accept(this); return value; } // visitor helpers protected boolean isBotEquivalent(Expression expr) { return getUpperBoundDirect(expr) == 0; } protected boolean isTopEquivalent(Expression expr) { return getUpperBoundComplement(expr) == 0; } // / helper for entities protected abstract int getEntityValue(NamedEntity entity); // / helper for All protected abstract int getForallValue(RoleExpression R, Expression C); // / helper for things like >= m R.C protected abstract int getMinValue(int m, RoleExpression R, Expression C); // / helper for things like <= m R.C protected abstract int getMaxValue(int m, RoleExpression R, Expression C); // / helper for things like = m R.C protected abstract int getExactValue(int m, RoleExpression R, Expression C); // / init c'tor public CardinalityEvaluatorBase(TSignature s) { super(s); value = 0; } // / set all other evaluators public void setEvaluators(UpperBoundDirectEvaluator pUD, LowerBoundDirectEvaluator pLD, UpperBoundComplementEvaluator pUC, LowerBoundComplementEvaluator pLC) { UBD = pUD; LBD = pLD; UBC = pUC; LBC = pLC; assert UBD == this || LBD == this || UBC == this || LBC == this; } // / implementation of evaluation public int getUpperBoundDirect(Expression expr) { return _getUpperBoundDirect(expr); } // / implementation of evaluation public int getUpperBoundComplement(Expression expr) { return _getUpperBoundComplement(expr); } // / implementation of evaluation public int getLowerBoundDirect(Expression expr) { return _getLowerBoundDirect(expr); } // / implementation of evaluation public int getLowerBoundComplement(Expression expr) { return _getLowerBoundComplement(expr); } // / implementation of evaluation private int _getUpperBoundDirect(Expression expr) { return UBD.getValue(expr); } // / implementation of evaluation private int _getUpperBoundComplement(Expression expr) { return UBC.getValue(expr); } // / implementation of evaluation private int _getLowerBoundDirect(Expression expr) { return LBD.getValue(expr); } // / implementation of evaluation private int _getLowerBoundComplement(Expression expr) { return LBC.getValue(expr); } // visitor implementation: common cases // concept expressions @Override public void visit(ConceptName expr) { value = getEntityValue(expr); } @Override public void visit(ConceptObjectExists expr) { value = getMinValue(1, expr.getOR(), expr.getConcept()); } @Override public void visit(ConceptObjectForall expr) { value = getForallValue(expr.getOR(), expr.getConcept()); } @Override public void visit(ConceptObjectMinCardinality expr) { value = getMinValue(expr.getCardinality(), expr.getOR(), expr.getConcept()); } @Override public void visit(ConceptObjectMaxCardinality expr) { value = getMaxValue(expr.getCardinality(), expr.getOR(), expr.getConcept()); } @Override public void visit(ConceptObjectExactCardinality expr) { value = getExactValue(expr.getCardinality(), expr.getOR(), expr.getConcept()); } @Override public void visit(ConceptDataExists expr) { value = getMinValue(1, expr.getDataRoleExpression(), expr.getExpr()); } @Override public void visit(ConceptDataForall expr) { value = getForallValue(expr.getDataRoleExpression(), expr.getExpr()); } @Override public void visit(ConceptDataMinCardinality expr) { value = getMinValue(expr.getCardinality(), expr.getDataRoleExpression(), expr.getExpr()); } @Override public void visit(ConceptDataMaxCardinality expr) { value = getMaxValue(expr.getCardinality(), expr.getDataRoleExpression(), expr.getExpr()); } @Override public void visit(ConceptDataExactCardinality expr) { value = getExactValue(expr.getCardinality(), expr.getDataRoleExpression(), expr.getExpr()); } // object role expressions @Override public void visit(ObjectRoleName expr) { value = getEntityValue(expr); } // FaCT++ extension: equivalent to R(x,y) and C(x), so copy behaviour from // ER.X @Override public void visit(ObjectRoleProjectionFrom expr) { value = getMinValue(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) { value = getMinValue(1, expr.getOR(), expr.getConcept()); } // data role expressions @Override public void visit(DataRoleName expr) { value = getEntityValue(expr); } } // / determine how many instances can an expression have class UpperBoundDirectEvaluator extends CardinalityEvaluatorBase { private static final long serialVersionUID = 11000L; // / define a special value for concepts that are not in C^{<= n} protected int getNoneValue() { return -1; } // / define a special value for concepts that are in C^{<= n} for all n protected int getAllValue() { return 0; } // / helper for entities TODO: checks only C top-locality, not R @Override protected int getEntityValue(NamedEntity entity) { return sig.botCLocal() && sig.nc(entity) ? getAllValue() : getNoneValue(); } // / helper for All @Override protected int getForallValue(RoleExpression R, Expression C) { if (isTopEquivalent(R) && getLowerBoundComplement(C) >= 1) { return getAllValue(); } else { return getNoneValue(); } } // / helper for things like >= m R.C @Override protected int getMinValue(int m, RoleExpression R, Expression C) { // m > 0 and... if (m <= 0) { return getNoneValue(); } // R = \bot or... if (isBotEquivalent(R)) { return getAllValue(); } // C \in C^{<= m-1} int ubC = getUpperBoundDirect(C); if (ubC != getNoneValue() && ubC < m) { return getAllValue(); } else { return getNoneValue(); } } // / helper for things like <= m R.C @Override protected int getMaxValue(int m, RoleExpression R, Expression C) { // R = \top and... if (!isTopEquivalent(R)) { return getNoneValue(); } // C\in C^{>= m+1} int lbC = getLowerBoundDirect(C); if (lbC != getNoneValue() && lbC > m) { return getAllValue(); } else { return getNoneValue(); } } // / helper for things like = m R.C @Override protected int getExactValue(int m, RoleExpression R, Expression C) { // here the maximal value between Mix and Max is an answer. The -1 case // will be dealt with automagically return Math.max(getMinValue(m, R, C), getMaxValue(m, R, C)); } // / helper for And protected <C extends Expression> int getAndValue(NAryExpression<C> expr) { int max = getNoneValue(); // we are looking for the maximal value here; -1 will be dealt with // automagically for (C p : expr.getArguments()) { max = Math.max(max, getUpperBoundDirect(p)); } return max; } // / helper for Or protected <C extends Expression> int getOrValue(NAryExpression<C> expr) { int sum = 0, n; for (C p : expr.getArguments()) { n = getUpperBoundDirect(p); if (n == getNoneValue()) { return getNoneValue(); } sum += n; } return sum; } public UpperBoundDirectEvaluator(TSignature s) { super(s); } // concept expressions @Override public void visit(ConceptTop c) { value = getNoneValue(); } @Override public void visit(ConceptBottom c) { value = getAllValue(); } @Override public void visit(ConceptNot expr) { value = getUpperBoundComplement(expr.getConcept()); } @Override public void visit(ConceptAnd expr) { value = getAndValue(expr); } @Override public void visit(ConceptOr expr) { value = getOrValue(expr); } @Override public void visit(ConceptOneOf<?> expr) { value = expr.size(); } @Override public void visit(ConceptObjectSelf expr) { value = isBotEquivalent(expr.getOR()) ? getAllValue() : getNoneValue(); } @Override public void visit(ConceptObjectValue expr) { value = isBotEquivalent(expr.getOR()) ? getAllValue() : getNoneValue(); } @Override public void visit(ConceptDataValue expr) { value = isBotEquivalent(expr.getDataRoleExpression()) ? getAllValue() : getNoneValue(); } // object role expressions @Override public void visit(ObjectRoleTop c) { value = getNoneValue(); } @Override public void visit(ObjectRoleBottom c) { value = getAllValue(); } @Override public void visit(ObjectRoleInverse expr) { value = getUpperBoundDirect(expr.getOR()); } @Override public void visit(ObjectRoleChain expr) { for (ObjectRoleExpression p : expr.getArguments()) { if (isBotEquivalent(p)) { value = getAllValue(); return; } } value = getNoneValue(); } // data role expressions @Override public void visit(DataRoleTop c) { value = getNoneValue(); } @Override public void visit(DataRoleBottom c) { value = getAllValue(); } // data expressions @Override public void visit(DataTop c) { value = getNoneValue(); } @Override public void visit(DataBottom c) { value = getAllValue(); } // FIXME!! not ready // public void visit ( DataTypeName ) { isBotEq = false; } // FIXME!! not ready // public void visit ( DataTypeRestriction ) { isBotEq = false; } @Override public void visit(Literal<?> c) { value = 1; } @Override public void visit(DataNot expr) { value = getUpperBoundComplement(expr.getExpr()); } @Override public void visit(DataAnd expr) { value = getAndValue(expr); } @Override public void visit(DataOr expr) { value = getOrValue(expr); } @Override public void visit(DataOneOf expr) { value = expr.size(); } } class UpperBoundComplementEvaluator extends CardinalityEvaluatorBase { private static final long serialVersionUID = 11000L; /** * define a special value for concepts that are not in C^{<= n} * * @return none value */ protected int getNoneValue() { return -1; } /** * define a special value for concepts that are in C^{<= n} for all n * * @return all value */ protected int getAllValue() { return 0; } /** helper for entities TODO: checks only C top-locality, not R */ @Override protected int getEntityValue(NamedEntity entity) { return topCLocal() && sig.nc(entity) ? getAllValue() : getNoneValue(); } /** helper for All */ @Override protected int getForallValue(RoleExpression R, Expression C) { if (isBotEquivalent(R) || getUpperBoundComplement(C) == 0) { return getAllValue(); } else { return getNoneValue(); } } // / helper for things like >= m R.C @Override protected int getMinValue(int m, RoleExpression R, Expression C) { // m == 0 or... if (m == 0) { return getAllValue(); } // R = \top and... if (!isTopEquivalent(R)) { return getNoneValue(); } // C \in C^{>= m} return getLowerBoundDirect(C) >= m ? getAllValue() : getNoneValue(); } // / helper for things like <= m R.C @Override protected int getMaxValue(int m, RoleExpression R, Expression C) { // R = \bot or... if (isBotEquivalent(R)) { return getAllValue(); } // C\in C^{<= m} int lbC = getUpperBoundDirect(C); if (lbC != getNoneValue() && lbC <= m) { return getAllValue(); } else { return getNoneValue(); } } // / helper for things like = m R.C @Override protected int getExactValue(int m, RoleExpression R, Expression C) { // here the minimal value between Mix and Max is an answer. The -1 case // will be dealt with automagically return Math.min(getMinValue(m, R, C), getMaxValue(m, R, C)); } // / helper for And protected <C extends Expression> int getAndValue(NAryExpression<C> expr) { int sum = 0, n; for (C p : expr.getArguments()) { n = getUpperBoundComplement(p); if (n == getNoneValue()) { return getNoneValue(); } sum += n; } return sum; } // / helper for Or protected <C extends Expression> int getOrValue(NAryExpression<C> expr) { int max = getNoneValue(); // we are looking for the maximal value here; -1 will be dealt with // automagically for (C p : expr.getArguments()) { max = Math.max(max, getUpperBoundComplement(p)); } return max; } // / init c'tor public UpperBoundComplementEvaluator(TSignature s) { super(s); } // concept expressions @Override public void visit(ConceptTop c) { value = getAllValue(); } @Override public void visit(ConceptBottom c) { value = getNoneValue(); } @Override public void visit(ConceptNot expr) { value = getUpperBoundDirect(expr.getConcept()); } @Override public void visit(ConceptAnd expr) { value = getAndValue(expr); } @Override public void visit(ConceptOr expr) { value = getOrValue(expr); } @Override public void visit(ConceptOneOf<?> c) { value = getNoneValue(); } @Override public void visit(ConceptObjectSelf expr) { value = isTopEquivalent(expr.getOR()) ? getAllValue() : getNoneValue(); } @Override public void visit(ConceptObjectValue expr) { value = isTopEquivalent(expr.getOR()) ? getAllValue() : getNoneValue(); } @Override public void visit(ConceptDataValue expr) { value = isTopEquivalent(expr.getDataRoleExpression()) ? getAllValue() : getNoneValue(); } // object role expressions @Override public void visit(ObjectRoleTop c) { value = getAllValue(); } @Override public void visit(ObjectRoleBottom c) { value = getNoneValue(); } @Override public void visit(ObjectRoleInverse expr) { value = getUpperBoundComplement(expr.getOR()); } @Override public void visit(ObjectRoleChain expr) { for (ObjectRoleExpression p : expr.getArguments()) { if (!isTopEquivalent(p)) { value = getNoneValue(); return; } } value = getAllValue(); } // data role expressions @Override public void visit(DataRoleTop c) { value = getAllValue(); } @Override public void visit(DataRoleBottom c) { value = getNoneValue(); } // data expressions @Override public void visit(DataTop c) { value = getAllValue(); } @Override public void visit(DataBottom c) { value = getNoneValue(); } // negated datatype is a union of all other DTs that are infinite @Override public void visit(Datatype<?> c) { value = getNoneValue(); } // negated restriction include negated DT @Override public void visit(DatatypeExpression<?> c) { value = getNoneValue(); } @Override public void visit(Literal<?> c) { value = getNoneValue(); } @Override public void visit(DataNot expr) { value = getUpperBoundDirect(expr.getExpr()); } @Override public void visit(DataAnd expr) { value = getAndValue(expr); } @Override public void visit(DataOr expr) { value = getOrValue(expr); } @Override public void visit(DataOneOf c) { value = getNoneValue(); } } class LowerBoundDirectEvaluator extends CardinalityEvaluatorBase { private static final long serialVersionUID = 11000L; // / define a special value for concepts that are not in C^{>= n} protected int getNoneValue() { return 0; } // / define a special value for concepts that are in C^{>= n} for all n protected int getAllValue() { return -1; } // / helper for entities TODO: checks only C top-locality, not R @Override protected int getEntityValue(NamedEntity entity) { return topCLocal() && sig.nc(entity) ? 1 : getNoneValue(); } // / helper for All @Override protected int getForallValue(RoleExpression R, Expression C) { if (isBotEquivalent(R) || getUpperBoundComplement(C) == 0) { return 1; } else { return getNoneValue(); } } // / helper for things like >= m R.C @Override protected int getMinValue(int m, RoleExpression R, Expression C) { // m == 0 or... if (m == 0) { return getAllValue(); } // R = \top and... if (!isTopEquivalent(R)) { return getNoneValue(); } // C \in C^{>= m} return getLowerBoundDirect(C) >= m ? m : getNoneValue(); } // / helper for things like <= m R.C @Override protected int getMaxValue(int m, RoleExpression R, Expression C) { // R = \bot or... if (isBotEquivalent(R)) { return 1; } // C\in C^{<= m} int lbC = getUpperBoundDirect(C); if (lbC != getNoneValue() && lbC <= m) { return 1; } else { return getNoneValue(); } } // / helper for things like = m R.C @Override protected int getExactValue(int m, RoleExpression R, Expression C) { int min = getMinValue(m, R, C), max = getMaxValue(m, R, C); // we need to take the lowest value if (min == getNoneValue() || max == getNoneValue()) { return getNoneValue(); } if (min == getAllValue()) { return max; } if (max == getAllValue()) { return min; } return Math.min(min, max); } // / helper for And // FIXME!! not done yet protected <C extends Expression> int getAndValue(NAryExpression<C> expr) { // return m - sumK, where boolean foundC = false; // true if found a conjunct that is in C^{>=} int foundM = 0; int mMax = 0, kMax = 0; // the m- and k- values for the C_j with max m+k int sumK = 0; // sum of all known k // 1st pass: check for none-case, deals with deterministic cases for (C p : expr.getArguments()) { int m = getLowerBoundDirect(p); // C_j \in C^{>= m} int k = getUpperBoundComplement(p); // C_j \in CC^{<= k} // case 0: if both aren't known then we don't know if (m == getNoneValue() && k == getNoneValue()) { return getNoneValue(); } // if only k exists then add it to k if (m == getNoneValue()) { // if ( k == getAllValue() ) // we don't have any bound then // return getNoneValue(); sumK += k; continue; } // if only m exists then set it to m if (k == getNoneValue()) { if (foundC) { return getNoneValue(); } foundC = true; foundM = m; continue; } // here both k and m are values sumK += k; // count k for the if (k + m > kMax + mMax) { kMax = k; mMax = m; } } // here we know the best candidate for M, and only need to set it up if (foundC) // found during the deterministic case { foundM -= sumK; return foundM > 0 ? foundM : getNoneValue(); } else // no deterministic option; choose the best one { sumK -= kMax; mMax -= sumK; return mMax > 0 ? mMax : getNoneValue(); } } // / helper for Or protected <C extends Expression> int getOrValue(NAryExpression<C> expr) { int max = getNoneValue(); // we are looking for the maximal value here; -1 need to be // special-cased for (C p : expr.getArguments()) { int n = getUpperBoundDirect(p); if (n == getAllValue()) { return getAllValue(); } max = Math.max(max, n); } return max; } // / init c'tor public LowerBoundDirectEvaluator(TSignature s) { super(s); } // concept expressions @Override public void visit(ConceptTop c) { value = 1; } @Override public void visit(ConceptBottom c) { value = getNoneValue(); } @Override public void visit(ConceptNot expr) { value = getLowerBoundComplement(expr.getConcept()); } @Override public void visit(ConceptAnd expr) { value = getAndValue(expr); } @Override public void visit(ConceptOr expr) { value = getOrValue(expr); } @Override public void visit(ConceptOneOf<?> expr) { value = expr.size() > 0 ? 1 : getNoneValue(); } @Override public void visit(ConceptObjectSelf expr) { value = isTopEquivalent(expr.getOR()) ? 1 : getNoneValue(); } // FIXME!! differ from the paper @Override public void visit(ConceptObjectValue expr) { value = isTopEquivalent(expr.getOR()) ? 1 : getNoneValue(); } @Override public void visit(ConceptDataValue expr) { value = isTopEquivalent(expr.getDataRoleExpression()) ? 1 : getNoneValue(); } // object role expressions @Override public void visit(ObjectRoleTop c) { value = getAllValue(); } @Override public void visit(ObjectRoleBottom c) { value = getNoneValue(); } @Override public void visit(ObjectRoleInverse expr) { value = getLowerBoundDirect(expr.getOR()); } @Override public void visit(ObjectRoleChain expr) { for (ObjectRoleExpression p : expr.getArguments()) { if (!isTopEquivalent(p)) { value = getNoneValue(); return; } } value = getAllValue(); } // data role expressions @Override public void visit(DataRoleTop c) { value = getAllValue(); } @Override public void visit(DataRoleBottom c) { value = getNoneValue(); } // data expressions @Override public void visit(DataTop c) { value = getAllValue(); } @Override public void visit(DataBottom c) { value = getNoneValue(); } // negated datatype is a union of all other DTs that are infinite @Override public void visit(Datatype<?> c) { value = getNoneValue(); } // negated restriction include negated DT @Override public void visit(DatatypeExpression<?> c) { value = getNoneValue(); } @Override public void visit(Literal<?> c) { value = getNoneValue(); } @Override public void visit(DataNot expr) { value = getLowerBoundComplement(expr.getExpr()); } @Override public void visit(DataAnd expr) { value = getAndValue(expr); } @Override public void visit(DataOr expr) { value = getOrValue(expr); } @Override public void visit(DataOneOf expr) { value = expr.size() > 0 ? 1 : getNoneValue(); } } class LowerBoundComplementEvaluator extends CardinalityEvaluatorBase { private static final long serialVersionUID = 11000L; // / define a special value for concepts that are not in C^{>= n} protected int getNoneValue() { return 0; } // / define a special value for concepts that are in C^{>= n} for all n protected int getAllValue() { return -1; } // / helper for entities TODO: checks only C top-locality, not R @Override protected int getEntityValue(NamedEntity entity) { return sig.botCLocal() && sig.nc(entity) ? 1 : getNoneValue(); } // / helper for All @Override protected int getForallValue(RoleExpression R, Expression C) { if (isTopEquivalent(R) && getLowerBoundComplement(C) >= 1) { return 1; } else { return getNoneValue(); } } // / helper for things like >= m R.C @Override protected int getMinValue(int m, RoleExpression R, Expression C) { // m > 0 and... if (m <= 0) { return getNoneValue(); } // R = \bot or... if (isBotEquivalent(R)) { return 1; } // C \in C^{<= m-1} int ubC = getUpperBoundDirect(C); if (ubC != getNoneValue() && ubC < m) { return 1; } else { return getNoneValue(); } } // / helper for things like <= m R.C @Override protected int getMaxValue(int m, RoleExpression R, Expression C) { // R = \top and... if (!isTopEquivalent(R)) { return getNoneValue(); } // C\in C^{>= m+1} int lbC = getLowerBoundDirect(C); if (lbC != getNoneValue() && lbC > m) { return m + 1; } else { return getNoneValue(); } } // / helper for things like = m R.C @Override protected int getExactValue(int m, RoleExpression R, Expression C) { // here the maximal value between Mix and Max is an answer. The -1 case // will be dealt with automagically // because both min and max are between 0 and m+1 return Math.max(getMinValue(m, R, C), getMaxValue(m, R, C)); } // / helper for And protected <C extends Expression> int getAndValue(NAryExpression<C> expr) { int max = getNoneValue(); // we are looking for the maximal value here; -1 need to be // special-cased for (C p : expr.getArguments()) { int n = getUpperBoundDirect(p); if (n == getAllValue()) { return getAllValue(); } max = Math.max(max, n); } return max; } // / helper for Or protected <C extends Expression> int getOrValue(NAryExpression<C> expr) { // return m - sumK, where boolean foundC = false; // true if found a conjunct that is in C^{>=} int foundM = 0; int mMax = 0, kMax = 0; // the m- and k- values for the C_j with max m+k int sumK = 0; // sum of all known k // 1st pass: check for none-case, deals with deterministic cases for (C p : expr.getArguments()) { int m = getLowerBoundComplement(p); // C_j \in CC^{>= m} int k = getUpperBoundDirect(p); // C_j \in C^{<= k} // case 0: if both aren't known then we don't know if (m == getNoneValue() && k == getNoneValue()) { return getNoneValue(); } // if only k exists then add it to k if (m == getNoneValue()) { // if ( k == getAllValue() ) // we don't have any bound then // return getNoneValue(); sumK += k; continue; } // if only m exists then set it to m if (k == getNoneValue()) { if (foundC) { return getNoneValue(); } foundC = true; foundM = m; continue; } // here both k and m are values sumK += k; // count k for the if (k + m > kMax + mMax) { kMax = k; mMax = m; } } // here we know the best candidate for M, and only need to set it up if (foundC) // found during the deterministic case { foundM -= sumK; return foundM > 0 ? foundM : getNoneValue(); } else // no deterministic option; choose the best one { sumK -= kMax; mMax -= sumK; return mMax > 0 ? mMax : getNoneValue(); } } // / init c'tor public LowerBoundComplementEvaluator(TSignature s) { super(s); } // concept expressions @Override public void visit(ConceptTop c) { value = getNoneValue(); } @Override public void visit(ConceptBottom c) { value = 1; } @Override public void visit(ConceptNot expr) { value = getLowerBoundDirect(expr.getConcept()); } @Override public void visit(ConceptAnd expr) { value = getAndValue(expr); } @Override public void visit(ConceptOr expr) { value = getOrValue(expr); } @Override public void visit(ConceptOneOf<?> c) { value = getNoneValue(); } @Override public void visit(ConceptObjectSelf expr) { value = isBotEquivalent(expr.getOR()) ? 1 : getNoneValue(); } @Override public void visit(ConceptObjectValue expr) { value = isBotEquivalent(expr.getOR()) ? 1 : getNoneValue(); } @Override public void visit(ConceptDataValue expr) { value = isBotEquivalent(expr.getDataRoleExpression()) ? 1 : getNoneValue(); } // object role expressions @Override public void visit(ObjectRoleTop c) { value = getNoneValue(); } @Override public void visit(ObjectRoleBottom c) { value = getAllValue(); } @Override public void visit(ObjectRoleInverse expr) { value = getLowerBoundComplement(expr.getOR()); } @Override public void visit(ObjectRoleChain expr) { for (ObjectRoleExpression p : expr.getArguments()) { if (isBotEquivalent(p)) { value = getAllValue(); return; } } value = getNoneValue(); } // data role expressions @Override public void visit(DataRoleTop c) { value = getNoneValue(); } @Override public void visit(DataRoleBottom c) { value = getAllValue(); } // data expressions @Override public void visit(DataTop c) { value = getNoneValue(); } @Override public void visit(DataBottom c) { value = getAllValue(); } // FIXME!! not ready // public void visit ( DataTypeName ) { isBotEq = false; } // FIXME!! not ready // public void visit ( DataTypeRestriction ) { isBotEq = false; } @Override public void visit(Literal<?> c) { value = 1; } @Override public void visit(DataNot expr) { value = getLowerBoundDirect(expr.getExpr()); } @Override public void visit(DataAnd expr) { value = getAndValue(expr); } @Override public void visit(DataOr expr) { value = getOrValue(expr); } @Override public void visit(DataOneOf c) { value = getNoneValue(); } } /** syntactic locality checker for DL axioms */ public class ExtendedSyntacticLocalityChecker extends GeneralSyntacticLocalityChecker { private static final long serialVersionUID = 11000L; protected final UpperBoundDirectEvaluator UBD; protected final LowerBoundDirectEvaluator LBD; protected final UpperBoundComplementEvaluator UBC; protected final LowerBoundComplementEvaluator LBC; /** @return true iff EXPR is top equivalent */ @Override protected boolean isTopEquivalent(Expression expr) { return UBC.getUpperBoundComplement(expr) == 0; } /** @return true iff EXPR is bottom equivalent */ @Override protected boolean isBotEquivalent(Expression expr) { return UBD.getUpperBoundDirect(expr) == 0; } /** * init c'tor * * @param s * s */ public ExtendedSyntacticLocalityChecker(TSignature s) { super(s); UBD = new UpperBoundDirectEvaluator(s); LBD = new LowerBoundDirectEvaluator(s); UBC = new UpperBoundComplementEvaluator(s); LBC = new LowerBoundComplementEvaluator(s); UBD.setEvaluators(UBD, LBD, UBC, LBC); LBD.setEvaluators(UBD, LBD, UBC, LBC); UBC.setEvaluators(UBD, LBD, UBC, LBC); LBC.setEvaluators(UBD, LBD, UBC, LBC); } }