package uk.ac.manchester.cs.jfact.kernel.modelcaches; /* 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 static uk.ac.manchester.cs.jfact.kernel.modelcaches.ModelCacheState.*; import static uk.ac.manchester.cs.jfact.kernel.modelcaches.ModelCacheType.mctIan; import java.util.BitSet; import java.util.List; import uk.ac.manchester.cs.jfact.helpers.DLVertex; import uk.ac.manchester.cs.jfact.helpers.FastSet; import uk.ac.manchester.cs.jfact.helpers.FastSetFactory; import uk.ac.manchester.cs.jfact.helpers.LogAdapter; import uk.ac.manchester.cs.jfact.helpers.UnreachableSituationException; import uk.ac.manchester.cs.jfact.kernel.ClassifiableEntry; import uk.ac.manchester.cs.jfact.kernel.ConceptWDep; import uk.ac.manchester.cs.jfact.kernel.DLDag; import uk.ac.manchester.cs.jfact.kernel.DlCompletionTree; import uk.ac.manchester.cs.jfact.kernel.DlCompletionTreeArc; import uk.ac.manchester.cs.jfact.kernel.RAStateTransitions; import uk.ac.manchester.cs.jfact.kernel.RATransition; import uk.ac.manchester.cs.jfact.kernel.Role; import conformance.Original; import conformance.PortedFrom; /** model cache Ian (Horrocks) */ @PortedFrom(file = "modelCacheIan.h", name = "modelCacheIan") public class ModelCacheIan extends ModelCacheInterface { private static final long serialVersionUID = 11000L; // sets for the cache /** named concepts that appears positively det-lly in a root node of a cache */ @PortedFrom(file = "modelCacheIan.h", name = "posDConcepts") private final BitSet posDConcepts = new BitSet(); /** named concepts that appears positively non-det in a root node of a cache */ @PortedFrom(file = "modelCacheIan.h", name = "posNConcepts") private final BitSet posNConcepts = new BitSet(); /** named concepts that appears negatively det-lly in a root node of a cache */ @PortedFrom(file = "modelCacheIan.h", name = "negDConcepts") private final BitSet negDConcepts = new BitSet(); /** named concepts that appears negatively non-det in a root node of a cache */ @PortedFrom(file = "modelCacheIan.h", name = "negNConcepts") private final BitSet negNConcepts = new BitSet(); /** extra det-lly concepts that are (partial) Simple Rule applications */ @PortedFrom(file = "modelCacheIan.h", name = "extraDConcepts") private final FastSet extraDConcepts = FastSetFactory.create(); /** extra non-det concepts that are (partial) Simple Rule applications */ @PortedFrom(file = "modelCacheIan.h", name = "extraNConcepts") private final FastSet extraNConcepts = FastSetFactory.create(); /** role names that are labels of the outgoing edges from the root node */ @PortedFrom(file = "modelCacheIan.h", name = "existsRoles") private final FastSet existsRoles = FastSetFactory.create(); /** role names that appears in the \A restrictions in the root node */ @PortedFrom(file = "modelCacheIan.h", name = "forallRoles") private final FastSet forallRoles = FastSetFactory.create(); /** role names that appears in the atmost restrictions in the root node */ @PortedFrom(file = "modelCacheIan.h", name = "funcRoles") private final FastSet funcRoles = FastSetFactory.create(); /** current state of cache model; recalculates on every change */ @PortedFrom(file = "modelCacheIan.h", name = "curState") private ModelCacheState curState; // XXX these two fields should be used somehow private final int nC; private final int nR; // XXX move to config @Original private final boolean simpleRules; /** * process CT label in given interval; set Deterministic accordingly * * @param DLHeap * DLHeap * @param start * start */ @PortedFrom(file = "modelCacheIan.h", name = "processLabelInterval") private void processLabelInterval(DLDag DLHeap, List<ConceptWDep> start) { for (int i = 0; i < start.size(); i++) { ConceptWDep p = start.get(i); int bp = p.getConcept(); processConcept(DLHeap.get(bp), bp > 0, p.getDep().isEmpty()); } } /** * fills cache sets by tree.Label; set Deterministic accordingly * * @param DLHeap * DLHeap * @param pCT * pCT */ @PortedFrom(file = "modelCacheIan.h", name = "initCacheByLabel") private void initCacheByLabel(DLDag DLHeap, DlCompletionTree pCT) { processLabelInterval(DLHeap, pCT.beginl_sc()); processLabelInterval(DLHeap, pCT.beginl_cc()); } /** * Create cache model of given CompletionTree using given HEAP * * @param heap * heap * @param p * p * @param flagNominals * flagNominals * @param nC * nC * @param nR * nR * @param simpleRules * simpleRules */ public ModelCacheIan(DLDag heap, DlCompletionTree p, boolean flagNominals, int nC, int nR, boolean simpleRules) { this(flagNominals, nC, nR, simpleRules); initCacheByLabel(heap, p); initRolesFromArcs(p); } /** * @param flagNominals * flagNominals * @param nC * nC * @param nR * nR * @param simpleRules * simpleRules */ public ModelCacheIan(boolean flagNominals, int nC, int nR, boolean simpleRules) { super(flagNominals); curState = csValid; this.simpleRules = simpleRules; this.nC = nC; this.nR = nR; } @Override @PortedFrom(file = "modelCacheIan.h", name = "getState") public ModelCacheState getState() { return curState; } @PortedFrom(file = "modelCacheIan.h", name = "getDConcepts") private BitSet getDConcepts(boolean pos) { return pos ? posDConcepts : negDConcepts; } /** * @param pos * pos * @return N-concepts wrt polarity */ @PortedFrom(file = "modelCacheIan.h", name = "getNConcepts") private BitSet getNConcepts(boolean pos) { return pos ? posNConcepts : negNConcepts; } /** * @param det * det * @return extra concepts wrt deterministic flag */ @PortedFrom(file = "modelCacheIan.h", name = "getExtra") private FastSet getExtra(boolean det) { return det ? extraDConcepts : extraNConcepts; } /** * init existRoles from arcs; can be used to create pseudo-cache with deps * of CT edges * * @param pCT * pCT */ @PortedFrom(file = "modelCacheIan.h", name = "initRolesFromArcs") public void initRolesFromArcs(DlCompletionTree pCT) { List<DlCompletionTreeArc> list = pCT.getNeighbour(); for (int i = 0; i < list.size(); i++) { if (!list.get(i).isIBlocked()) { addExistsRole(list.get(i).getRole()); } } curState = csValid; } /** Get the tag identifying the cache type */ @Override @PortedFrom(file = "modelCacheIan.h", name = "getCacheType") public ModelCacheType getCacheType() { return mctIan; } /** get type of cache (deep or shallow) */ @Override @PortedFrom(file = "modelCacheIan.h", name = "shallowCache") public boolean shallowCache() { return existsRoles.isEmpty(); } /** clear the cache */ @PortedFrom(file = "modelCacheIan.h", name = "clear") public void clear() { posDConcepts.clear(); posNConcepts.clear(); negDConcepts.clear(); negNConcepts.clear(); if (simpleRules) { extraDConcepts.clear(); extraNConcepts.clear(); } existsRoles.clear(); forallRoles.clear(); funcRoles.clear(); curState = csValid; } /** * @param cur * cur * @param pos * pos * @param det * det */ @PortedFrom(file = "modelCacheIan.h", name = "processConcept") public void processConcept(DLVertex cur, boolean pos, boolean det) { switch (cur.getType()) { case dtTop: case dtDataType: case dtDataValue: case dtDataExpr: throw new UnreachableSituationException( cur.toString() + " Top datatype property, datatype, data value or data expression used in an unexpected position"); case dtNConcept: case dtPConcept: case dtNSingleton: case dtPSingleton: int toAdd = ((ClassifiableEntry) cur.getConcept()).getIndex(); (det ? getDConcepts(pos) : getNConcepts(pos)).set(toAdd); break; case dtIrr: // for \neg \ER.Self: add R to AR-set case dtForall: // add AR.C roles to forallRoles case dtLE: // for <= n R: add R to forallRoles if (cur.getRole().isTop()) { (pos ? forallRoles : existsRoles).completeSet(nR); } else if (pos) { // no need to deal with existentials here: they would be // created through edges if (cur.getRole().isSimple()) { forallRoles.add(cur.getRole().getIndex()); } else { processAutomaton(cur); } } break; default: // all other -- nothing to do break; } } /** * @param cur * cur */ @PortedFrom(file = "modelCacheIan.h", name = "processAutomaton") public void processAutomaton(DLVertex cur) { RAStateTransitions RST = cur.getRole().getAutomaton().getBase() .get(cur.getState()); // for every transition starting from a given state, // add the role that is accepted by a transition List<RATransition> begin = RST.begin(); for (int i = 0; i < begin.size(); i++) { for (Role r : begin.get(i).begin()) { forallRoles.add(r.getIndex()); } } } /** * adds role to exists- and func-role if necessary * * @param R * R */ @PortedFrom(file = "modelCacheIan.h", name = "addRoleToCache") private void addRoleToCache(Role R) { existsRoles.add(R.getIndex()); if (R.isTopFunc()) { funcRoles.add(R.getIndex()); } } /** * adds role (and all its super-roles) to exists- and funcRoles * * @param R * R */ @PortedFrom(file = "modelCacheIan.h", name = "addExistsRole") private void addExistsRole(Role R) { addRoleToCache(R); List<Role> list = R.getAncestor(); int size = list.size(); for (int i = 0; i < size; i++) { addRoleToCache(list.get(i)); } } @Override @PortedFrom(file = "modelCacheIan.h", name = "canMerge") public ModelCacheState canMerge(ModelCacheInterface p) { if (hasNominalClash(p)) { return csFailed; } if (p.getState() != csValid || curState != csValid) { return mergeStatus(p.getState(), curState); } switch (p.getCacheType()) { case mctConst: return csValid; case mctSingleton: int Singleton = ((ModelCacheSingleton) p).getValue(); return isMergableSingleton(Math.abs(Singleton), Singleton > 0); case mctIan: return isMergableIan((ModelCacheIan) p); case mctBadType: default: return csUnknown; } } /** * @param Singleton * Singleton * @param pos * pos * @return invalid, failed or valid depending on whether singleton is * included */ @PortedFrom(file = "modelCacheIan.h", name = "isMergableSingleton") public ModelCacheState isMergableSingleton(int Singleton, boolean pos) { assert Singleton != 0; // deterministic clash if (getDConcepts(!pos).get(Singleton)) { return csInvalid; } else if (getNConcepts(!pos).get(Singleton)) { return csFailed; } return csValid; } /** * @param q * q * @return invalid, failed or valid */ @PortedFrom(file = "modelCacheIan.h", name = "isMergableIan") public ModelCacheState isMergableIan(ModelCacheIan q) { if (posDConcepts.intersects(q.negDConcepts) || q.posDConcepts.intersects(negDConcepts) // || IfDefs.RKG_USE_SIMPLE_RULES // && getExtra(true).intersect(q.getExtra(true)) ) { return csInvalid; } else if (existsRoles.intersect(q.forallRoles) || q.existsRoles.intersect(forallRoles) || funcRoles.intersect(q.funcRoles) || posDConcepts.intersects(q.negNConcepts) || posNConcepts.intersects(q.negDConcepts) || posNConcepts.intersects(q.negNConcepts) || q.posDConcepts.intersects(negNConcepts) || q.posNConcepts.intersects(negDConcepts) || q.posNConcepts.intersects(negNConcepts) // || IfDefs.RKG_USE_SIMPLE_RULES // && (getExtra(true).intersect(q.getExtra(false)) // || getExtra(false).intersect(q.getExtra(true)) || getExtra( // false).intersect(q.getExtra(false))) ) { return csFailed; } else { if (simpleRules && getExtra(true).intersect(q.getExtra(true))) { return csInvalid; } if (simpleRules && (getExtra(true).intersect(q.getExtra(false)) || getExtra(false).intersect(q.getExtra(true)) || getExtra( false).intersect(q.getExtra(false)))) { return csFailed; } return csValid; } } /** * @param p * p * @return invalid, failed or valid */ @PortedFrom(file = "modelCacheIan.h", name = "merge") public ModelCacheState merge(ModelCacheInterface p) { assert p != null; // check for nominal clash if (hasNominalClash(p)) { curState = csFailed; return curState; } switch (p.getCacheType()) { case mctConst: // adds TOP/BOTTOM curState = mergeStatus(curState, p.getState()); break; case mctSingleton: // adds Singleton int Singleton = ((ModelCacheSingleton) p).getValue(); mergeSingleton(Math.abs(Singleton), Singleton > 0); break; case mctIan: mergeIan((ModelCacheIan) p); break; default: throw new UnreachableSituationException(); } updateNominalStatus(p); return curState; } /** * actual merge with a singleton cache * * @param Singleton * Singleton * @param pos * pos */ @PortedFrom(file = "modelCacheIan.h", name = "mergeSingleton") private void mergeSingleton(int Singleton, boolean pos) { ModelCacheState newState = isMergableSingleton(Singleton, pos); if (newState != csValid) { curState = mergeStatus(curState, newState); } else { getDConcepts(pos).set(Singleton); } } /** * actual merge with an Ian's cache * * @param p * p */ @PortedFrom(file = "modelCacheIan.h", name = "mergeIan") private void mergeIan(ModelCacheIan p) { // setup curState curState = isMergableIan(p); // merge all sets: posDConcepts.or(p.posDConcepts); posNConcepts.or(p.posNConcepts); negDConcepts.or(p.negDConcepts); negNConcepts.or(p.negNConcepts); if (simpleRules) { extraDConcepts.addAll(p.extraDConcepts); extraNConcepts.addAll(p.extraNConcepts); } existsRoles.addAll(p.existsRoles); forallRoles.addAll(p.forallRoles); funcRoles.addAll(p.funcRoles); } @Override @PortedFrom(file = "modelCacheIan.h", name = "logCacheEntry") public void logCacheEntry(int level, LogAdapter l) { l.print("\nIan cache: posDConcepts = {", posDConcepts, "}, posNConcepts = {", posNConcepts, "}, negDConcepts = {", negDConcepts, "}, negNConcepts = {", negNConcepts, "}, existsRoles = {", existsRoles, "}, forallRoles = {", forallRoles, "}, funcRoles = {", funcRoles, "}"); } @PortedFrom(file = "modelCacheInterface.h", name = "mergeStatus") private ModelCacheState mergeStatus(ModelCacheState s1, ModelCacheState s2) { // if one of caches is definitely UNSAT, then merge will be the same if (s1 == csInvalid || s2 == csInvalid) { return csInvalid; } // if one of caches is unsure then result will be the same if (s1 == csFailed || s2 == csFailed) { return csFailed; } // if one of caches is not inited, than result would be the same if (s1 == csUnknown || s2 == csUnknown) { return csUnknown; } else { // valid+valid = valid return csValid; } } }