package uk.ac.manchester.cs.jfact.kernel; /* 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.helpers.Helper.*; import static uk.ac.manchester.cs.jfact.kernel.DagTag.*; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import uk.ac.manchester.cs.jfact.dep.DepSet; import uk.ac.manchester.cs.jfact.helpers.ArrayIntMap; import uk.ac.manchester.cs.jfact.helpers.DLVertex; import uk.ac.manchester.cs.jfact.helpers.LogAdapter; import uk.ac.manchester.cs.jfact.helpers.Reference; import uk.ac.manchester.cs.jfact.helpers.Templates; import uk.ac.manchester.cs.jfact.kernel.options.JFactReasonerConfiguration; import uk.ac.manchester.cs.jfact.kernel.state.DLCompletionTreeSaveState; import uk.ac.manchester.cs.jfact.kernel.state.SaveList; import conformance.Original; import conformance.PortedFrom; /** completion tree */ @PortedFrom(file = "dlCompletionTree.h", name = "DlCompletionTree") public class DlCompletionTree implements Comparable<DlCompletionTree>, Serializable { private static final long serialVersionUID = 11000L; /** restore blocked node */ static class UnBlock extends Restorer { private static final long serialVersionUID = 11000L; private final DlCompletionTree p; private final DlCompletionTree unblockBlocker; private final DepSet dep; private final boolean pBlocked; private final boolean dBlocked; public UnBlock(DlCompletionTree q) { p = q; unblockBlocker = q.blocker; dep = DepSet.create(q.pDep); pBlocked = q.pBlocked; dBlocked = q.dBlocked; } @Override public void restore() { p.setBlocker(unblockBlocker); p.pDep = DepSet.create(dep); p.pBlocked = pBlocked; p.dBlocked = dBlocked; } } /** restore (un)cached node */ static class CacheRestorer extends Restorer { private static final long serialVersionUID = 11000L; private final DlCompletionTree p; private final boolean isCached; public CacheRestorer(DlCompletionTree q) { p = q; isCached = q.cached; } @Override public void restore() { p.cached = isCached; } } /** restore node after IR set change */ class IRRestorer extends Restorer { private static final long serialVersionUID = 11000L; private final int n; public IRRestorer() { n = inequalityRelation.size(); } @Override public void restore() { resize(inequalityRelation, n); inequalityRelation_helper.clear(); // TODO check performances of this for (int i = 0; i < inequalityRelation.size(); i++) { if (inequalityRelation.get(i) != null) { inequalityRelation_helper.put(inequalityRelation.get(i) .getConcept(), inequalityRelation.get(i)); } } } } /** label of a node */ private final CGLabel label = new CGLabel(); // TODO check for better access /** inequality relation information respecting current node */ protected final List<ConceptWDep> inequalityRelation = new ArrayList<ConceptWDep>(); protected final Map<Integer, ConceptWDep> inequalityRelation_helper = new HashMap<Integer, ConceptWDep>(); // TODO check whether access should be improved /** Neighbours information */ private final List<DlCompletionTreeArc> neighbour = new ArrayList<DlCompletionTreeArc>(); private int neighbourSize = 0; /** pointer to last saved node */ private final SaveList saves = new SaveList(); /** ID of node (used in print) */ private final int id; /** concept that init the newly created node */ private int init; /** blocker of a node */ protected DlCompletionTree blocker; /** dep-set for Purge op */ protected DepSet pDep = DepSet.create(); // save state information protected int curLevel; /** is given node a data node */ private boolean flagDataNode = false; /** flag if node is Cached */ protected boolean cached = true; /** flag whether node is permanently/temporarily blocked */ protected boolean pBlocked = true; /** flag whether node is directly/indirectly blocked */ protected boolean dBlocked = true; /** * Whether node is affected by change of some potential blocker. This flag * may be viewed as a cache for a 'blocked' status */ private boolean affected = true; /** level of a nominal node; 0 means blockable one */ private int nominalLevel; @Original private final JFactReasonerConfiguration options; /** * check if B2 holds for given DL vertex with C=V * * @param v * v * @param C * C * @return true if b2 holds */ private boolean B2(DLVertex v, int C) { assert hasParent(); RAStateTransitions RST = v.getRole().getAutomaton().getBase() .get(v.getState()); if (v.getRole().isSimple()) { return B2Simple(RST, v.getConceptIndex()); } else { if (RST.isEmpty()) { return true; } if (RST.isSingleton()) { return B2Simple(RST, C - v.getState() + RST.getTransitionEnd()); } return B2Complex(RST, C - v.getState()); } } /** * @param C * C * @return check whether a node can block another one with init concept C */ public boolean canBlockInit(int C) { if (C == bpBOTTOM) { return false; } if (C == bpTOP) { return true; } return label.contains(C); } /** * log saving/restoring node * * @param action * action */ private void logSRNode(String action) { options.getLog().printTemplate(Templates.LOG_SR_NODE, action, id, neighbour.size(), curLevel); } /** @return letter corresponding to the blocking mode */ private String getBlockingStatusName() { return isPBlocked() ? "p" : isDBlocked() ? "d" : isIBlocked() ? "i" : "u"; } /** @return log node status (d-,i-,p-blocked or cached) */ private String logNodeBStatus() { StringBuilder toReturn = new StringBuilder(); // blocking status information if (blocker != null) { toReturn.append(getBlockingStatusName()).append(blocker.id); } if (isCached()) { toReturn.append('c'); } return toReturn.toString(); } /** * @param newId * newId * @param c * c */ public DlCompletionTree(int newId, JFactReasonerConfiguration c) { id = newId; options = c; } /** * add given arc P as a neighbour * * @param p * p */ public void addNeighbour(DlCompletionTreeArc p) { neighbour.add(p); neighbourSize++; } /** @return Node's id */ public int getId() { return id; } /** @return check if the node is cached (IE need not to be expanded) */ public boolean isCached() { return cached; } /** * set cached status of given node * * @param val * val * @return restorer */ public Restorer setCached(boolean val) { if (cached == val) { return null; } Restorer ret = new CacheRestorer(this); cached = val; return ret; } // data node methods /** @return true if datanode */ public boolean isDataNode() { return flagDataNode; } /** set data node to true */ public void setDataNode() { flagDataNode = true; } // nominal node methods /** @return true if blockable */ public boolean isBlockableNode() { return nominalLevel == BLOCKABLE_LEVEL; } /** @return true if nominal */ public boolean isNominalNode() { return nominalLevel != BLOCKABLE_LEVEL; } /** set nominal level to 0 */ public void setNominalLevel() { setNominalLevel(0); } /** * @param newLevel * newLevel */ public void setNominalLevel(int newLevel) { nominalLevel = newLevel; } /** @return nominal level */ public int getNominalLevel() { return nominalLevel; } /** * adds concept P to a label, defined by TAG; update blocked status if * necessary * * @param p * p * @param tag * tag */ public void addConcept(ConceptWDep p, DagTag tag) { label.add(tag, p); } /** * set the Init concept * * @param p * p */ public void setInit(int p) { init = p; } /** @return init value */ public int getInit() { return init; } /** @return neighbour list */ public List<DlCompletionTreeArc> getNeighbour() { return neighbour; } /** @return true if node is a non-root; works for reflexive roles */ public boolean hasParent() { if (neighbourSize == 0) { return false; } return neighbour.get(0).isPredEdge(); } /** * check if SOME rule is applicable; includes transitive SOME support * * @param R * R * @param C * C * @return completion tree */ public DlCompletionTree isSomeApplicable(Role R, int C) { return R.isTransitive() ? isTSomeApplicable(R, C) : isNSomeApplicable( R, C); } /** @return label */ public CGLabel label() { return label; } // label iterators /** @return simple concepts */ public List<ConceptWDep> beginl_sc() { return label.get_sc(); } /** @return complex concepts */ public List<ConceptWDep> beginl_cc() { return label.get_cc(); } /** @return map for label with simple concepts */ public ArrayIntMap beginl_sc_concepts() { return label.get_sc_concepts(); } /** @return map for a label with complex concepts */ public ArrayIntMap beginl_cc_concepts() { return label.get_cc_concepts(); } /** * @param p * p * @return check whether node's label contains P */ public boolean isLabelledBy(int p) { return label.contains(p); } // Blocked-By methods for different logics /** * @param p * p * @return check blocking condition for SH logic */ public boolean isBlockedBy_SH(DlCompletionTree p) { return label.lesserequal(p.label); } /** * @param dag * dag * @param p * p * @return check blocking condition for SHI logic */ public boolean isBlockedBy_SHI(DLDag dag, DlCompletionTree p) { return isCommonlyBlockedBy(dag, p); } /** * @param dag * dag * @param p * p * @return check blocking condition for SHIQ logic using optimised blocking */ public boolean isBlockedBy_SHIQ(DLDag dag, DlCompletionTree p) { return isCommonlyBlockedBy(dag, p) && (isCBlockedBy(dag, p) || isABlockedBy(dag, p)); } private DlCompletionTree cachedParent = null; // WARNING!! works only for blockable nodes // every non-root node will have first upcoming edge pointed to a parent /** * @return RW pointer to the parent node; WARNING: correct only for nodes * with hasParent()==TRUE */ public DlCompletionTree getParentNode() { if (cachedParent == null) { cachedParent = neighbour.get(0).getArcEnd(); } return cachedParent; } // managing AFFECTED flag /** @return check whether node is affected by blocking-related changes */ public boolean isAffected() { return affected; } /** set node (and all subnodes) affected */ public void setAffected() { // don't mark already affected, nominal or p-blocked nodes if (isAffected() || isNominalNode() || isPBlocked()) { return; } affected = true; for (int i = 0; i < neighbourSize; i++) { DlCompletionTreeArc q = neighbour.get(i); if (q.isSuccEdge()) { q.getArcEnd().setAffected(); } } } /** clear affected flag */ public void clearAffected() { affected = false; } // just returns calculated values /** @return check if node is directly blocked */ public boolean isDBlocked() { return blocker != null && !pBlocked && dBlocked; } /** @return check if node is indirectly blocked */ public boolean isIBlocked() { return blocker != null && !pBlocked && !dBlocked; } /** @return check if node is purged (and so indirectly blocked) */ public boolean isPBlocked() { return blocker != null && pBlocked && !dBlocked; } /** @return true if node is blocked */ public boolean isBlockedPBlockedNominalNodeCached() { return cached || isNominalNode() || isBlocked() || isPBlocked(); } /** @return check if node is blocked (d/i) */ public boolean isBlocked() { return blocker != null && !pBlocked; } /** @return check the legality of the direct block */ public boolean isIllegallyDBlocked() { return isDBlocked() && blocker.isBlocked(); } /** @return blocker */ public DlCompletionTree getBlocker() { return blocker; } /** @return get purge dep-set of a given node */ public DepSet getPurgeDep() { return pDep; } /** @return get node to which current one was merged */ public DlCompletionTree resolvePBlocker() { if (isPBlocked()) { return blocker.resolvePBlocker(); } else { return this; } } /** * @param dep * dep * @return get node to which current one was merged; fills DEP from pDep's */ public DlCompletionTree resolvePBlocker(DepSet dep) { if (!isPBlocked()) { return this; } dep.add(pDep); return blocker.resolvePBlocker(dep); } /** * @param c * c * @return check whether the loop between a DBlocked NODE and it's parent * blocked contains C */ public boolean isLoopLabelled(int c) { assert isDBlocked(); if (blocker.isLabelledBy(c)) { return true; } // Blocker is the 1st node in the loop int n = 1; for (DlCompletionTree p = getParentNode(); p.hasParent() && !p.equals(blocker); p = p.getParentNode()) { if (p.isLabelledBy(c)) { return true; } else { ++n; } } options.getLog().print(" loop(").print(n).print(")"); return false; } // re-building blocking hierarchy /** * set node blocked * * @param blocker * blocker * @param permanently * permanently * @param directly * directly * @return restorer */ private Restorer setBlocked(DlCompletionTree blocker, boolean permanently, boolean directly) { Restorer ret = new UnBlock(this); setBlocker(blocker); pBlocked = permanently; dBlocked = directly; options.getLog().printTemplate(Templates.LOG_NODE_BLOCKED, getBlockingStatusName(), id, blocker == null ? "" : ",", blocker == null ? "" : blocker.id); return ret; } /** * mark node d-blocked * * @param blocker * blocker * @return restorer */ public Restorer setDBlocked(DlCompletionTree blocker) { return setBlocked(blocker, false, true); } /** * mark node i-blocked * * @param blocker * blocker * @return restorer */ public Restorer setIBlocked(DlCompletionTree blocker) { return setBlocked(blocker, false, false); } /** * mark node unblocked * * @return restorer */ public Restorer setUBlocked() { return setBlocked(null, true, true); } /** * mark node purged * * @param blocker * blocker * @param dep * dep * @return restorer */ public Restorer setPBlocked(DlCompletionTree blocker, DepSet dep) { Restorer ret = new UnBlock(this); setBlocker(blocker); if (isNominalNode()) { pDep = DepSet.create(dep); } pBlocked = true; dBlocked = false; options.getLog().printTemplate(Templates.LOG_NODE_BLOCKED, getBlockingStatusName(), id, blocker == null ? "" : ",", blocker == null ? "" : blocker.id); return ret; } // checking edge labelling /** * check if edge to NODE is labelled by R; * * @param R * R * @param node * node * @return null if does not */ public DlCompletionTreeArc getEdgeLabelled(Role R, DlCompletionTree node) { for (int i = 0; i < neighbourSize; i++) { DlCompletionTreeArc p = neighbour.get(i); if (p.getArcEnd().equals(node) && p.isNeighbour(R)) { return p; } } return null; } /** * check if parent arc is labelled by R; works only for blockable nodes * * @param R * R * @return true if parent labelled */ private boolean isParentArcLabelled(Role R) { return getEdgeLabelled(R, getParentNode()) != null; } // inequality relation interface /** * init IR with given entry and dep-set; * * @param level * level * @param ds * ds * @return true if IR already has this label */ public boolean initIR(int level, DepSet ds) { Reference<DepSet> dummy = new Reference<DepSet>(DepSet.create()); // we don't need a clash-set here if (inIRwithC(level, ds, dummy)) { return true; } ConceptWDep conceptWDep = new ConceptWDep(level, ds); inequalityRelation.add(conceptWDep); inequalityRelation_helper.put(level, conceptWDep); return false; } /** * check if IR for the node contains C * * @param level * level * @param ds * ds * @param dep * dep * @return true if C contained */ private boolean inIRwithC(int level, DepSet ds, Reference<DepSet> dep) { if (inequalityRelation.isEmpty()) { return false; } ConceptWDep p = inequalityRelation_helper.get(level); if (p != null) { dep.getReference().add(p.getDep()); dep.getReference().add(ds); return true; } return false; } // saving/restoring /** * @param newLevel * newLevel * @return check if node needs to be saved */ public boolean needSave(int newLevel) { return curLevel < newLevel; } /** * save node using internal stack * * @param level * level */ public void save(int level) { DLCompletionTreeSaveState node = new DLCompletionTreeSaveState(); saves.push(node); save(node); curLevel = level; } /** * @param restLevel * restLevel * @return check if node needs to be restored */ public boolean needRestore(int restLevel) { return curLevel > restLevel; } /** * @param level * level number restore node to given level */ public void restore(int level) { restore(saves.pop(level)); } // output /** @return log node information (number, i/d blockers, cached) */ public String logNode() { return id + logNodeBStatus(); } private boolean isCommonlyBlockedBy(DLDag dag, DlCompletionTree p) { assert hasParent(); if (!label.lesserequal(p.label)) { return false; } ArrayIntMap list = p.beginl_cc_concepts(); int size = list.size(); for (int i = 0; i < size; i++) { int bp = list.keySet(i); if (bp > 0) { DLVertex v = dag.get(bp); if (v.getType() == dtForall && !B2(v, bp)) { return false; } } } return true; } private boolean isABlockedBy(DLDag dag, DlCompletionTree p) { ArrayIntMap list = p.beginl_cc_concepts(); for (int i = 0; i < list.size(); i++) { int bp = list.keySet(i); DLVertex v = dag.get(bp); if (v.getType() == dtForall && bp < 0) { if (!B4(1, v.getRole(), -v.getConceptIndex())) { return false; } } else if (v.getType() == dtLE) { if (bp > 0) { if (!B3(p, v.getNumberLE(), v.getRole(), v.getConceptIndex())) { return false; } } else { if (!B4(v.getNumberGE(), v.getRole(), v.getConceptIndex())) { return false; } } } } return true; } private boolean isCBlockedBy(DLDag dag, DlCompletionTree p) { List<ConceptWDep> list = p.beginl_cc(); for (int i = 0; i < list.size(); i++) { int bp = list.get(i).getConcept(); if (bp > 0) { DLVertex v = dag.get(bp); if (v.getType() == dtLE && !B5(v.getRole(), v.getConceptIndex())) { return false; } } } list = getParentNode().beginl_cc(); for (int i = 0; i < list.size(); i++) { int bp = list.get(i).getConcept(); if (bp < 0) { DLVertex v = dag.get(bp); if (v.getType() == dtLE && !B6(v.getRole(), v.getConceptIndex())) { return false; } } } return true; } private boolean B2Simple(RAStateTransitions RST, int C) { DlCompletionTree parent = getParentNode(); CGLabel parLab = parent.label(); if (parLab.contains(C)) { return true; } for (int i = 0; i < neighbourSize; i++) { DlCompletionTreeArc p = neighbour.get(i); if (!p.isIBlocked() && p.getArcEnd().equals(parent) && RST.recognise(p.getRole())) { return false; } } return true; } private boolean B2Complex(RAStateTransitions RST, int C) { DlCompletionTree parent = getParentNode(); CGLabel parLab = parent.label(); for (int i = 0; i < neighbourSize; i++) { DlCompletionTreeArc p = neighbour.get(i); if (p.isIBlocked() || !p.getArcEnd().equals(parent)) { continue; } Role R = p.getRole(); if (RST.recognise(R)) { List<RATransition> list = RST.begin(); for (int j = 0; j < list.size(); j++) { RATransition q = list.get(i); if (q.applicable(R) && !parLab.containsCC(C + q.final_state())) { return false; } } } } return true; } private boolean B3(DlCompletionTree p, int n, Role S, int C) { assert hasParent(); boolean ret; if (!isParentArcLabelled(S)) { ret = true; } else if (getParentNode().isLabelledBy(-C)) { ret = true; } else if (!getParentNode().isLabelledBy(C)) { ret = false; } else { int m = 0; for (int i = 0; i < p.neighbourSize; i++) { DlCompletionTreeArc q = p.neighbour.get(i); if (q.isSuccEdge() && q.isNeighbour(S) && q.getArcEnd().isLabelledBy(C)) { ++m; } } ret = m < n; } return ret; } private boolean B4(int m, Role T, int E) { assert hasParent(); if (isParentArcLabelled(T) && m == 1 && getParentNode().isLabelledBy(E)) { return true; } int n = 0; for (int i = 0; i < neighbourSize; i++) { DlCompletionTreeArc q = neighbour.get(i); if (q.isSuccEdge() && q.isNeighbour(T) && q.getArcEnd().isLabelledBy(E) && ++n >= m) { return true; } } return false; } private boolean B5(Role T, int E) { assert hasParent(); if (!isParentArcLabelled(T)) { return true; } if (getParentNode().isLabelledBy(-E)) { return true; } return false; } private boolean B6(Role U, int F) { assert hasParent(); if (!isParentArcLabelled(U.inverse())) { return true; } if (isLabelledBy(-F)) { return true; } return false; } /** default level for the Blockable node */ public static final int BLOCKABLE_LEVEL = Integer.MAX_VALUE; /** * @param level * level */ public void init(int level) { flagDataNode = false; nominalLevel = BLOCKABLE_LEVEL; curLevel = level; cached = false; affected = true; // every (newly created) node can be blocked dBlocked = true; pBlocked = true; // unused flag combination // cleans the cache where Label is involved label.init(); init = bpTOP; // node was used -- clear all previous content saves.clear(); inequalityRelation.clear(); inequalityRelation_helper.clear(); neighbour.clear(); cachedParent = null; neighbourSize = 0; setBlocker(null); pDep.clear(); } private DlCompletionTree isTSuccLabelled(Role R, int C) { if (isLabelledBy(C)) { return this; } if (isNominalNode()) { return null; } DlCompletionTree ret = null; for (int i = 0; i < neighbourSize; i++) { DlCompletionTreeArc p = neighbour.get(i); if (p.isSuccEdge() && p.isNeighbour(R) && !p.isReflexiveEdge() && (ret = p.getArcEnd().isTSuccLabelled(R, C)) != null) { return ret; } } return null; } private DlCompletionTree isTPredLabelled(Role R, int C, DlCompletionTree from) { if (isLabelledBy(C)) { return this; } if (isNominalNode()) { return null; } DlCompletionTree ret = null; for (int i = 0; i < neighbourSize; i++) { DlCompletionTreeArc p = neighbour.get(i); if (p.isSuccEdge() && p.isNeighbour(R) && !p.getArcEnd().equals(from) && (ret = p.getArcEnd().isTSuccLabelled(R, C)) != null) { return ret; } } if (hasParent() && isParentArcLabelled(R)) { return getParentNode().isTPredLabelled(R, C, this); } else { return null; } } private DlCompletionTree isNSomeApplicable(Role R, int C) { for (int i = 0; i < neighbourSize; i++) { DlCompletionTreeArc p = neighbour.get(i); if (p.isNeighbour(R) && p.getArcEnd().isLabelledBy(C)) { return p.getArcEnd(); } } return null; } private DlCompletionTree isTSomeApplicable(Role R, int C) { DlCompletionTree ret = null; for (int i = 0; i < neighbourSize; i++) { DlCompletionTreeArc p = neighbour.get(i); if (p.isNeighbour(R)) { if (p.isPredEdge()) { ret = p.getArcEnd().isTPredLabelled(R, C, this); } else { ret = p.getArcEnd().isTSuccLabelled(R, C); } if (ret != null) { return ret; } } } return null; } private void save(DLCompletionTreeSaveState nss) { nss.setCurLevel(curLevel); nss.setnNeighbours(neighbourSize); label.save(nss.getLab()); logSRNode("SaveNode"); } private void restore(DLCompletionTreeSaveState nss) { if (nss == null) { return; } curLevel = nss.getCurLevel(); label.restore(nss.getLab(), curLevel); resize(neighbour, nss.getnNeighbours()); neighbourSize = nss.getnNeighbours(); if (neighbourSize == 0) { cachedParent = null; } affected = true; logSRNode("RestNode"); } /** * @param o * o */ public void printBody(LogAdapter o) { o.print(id); if (isNominalNode()) { o.print("o").print(nominalLevel); } o.print("(").print(curLevel).print(")"); if (isDataNode()) { o.print("d"); } o.print(label).print(logNodeBStatus()); } @Override public String toString() { StringBuilder o = new StringBuilder(); o.append(id); if (isNominalNode()) { o.append('o').append(nominalLevel); } o.append('(').append(curLevel).append(')'); if (isDataNode()) { o.append('d'); } o.append(label).append(logNodeBStatus()); return o.toString(); } /** * @param node * node * @param dep * dep * @return check if the NODE's and current node's IR are labelled with the * same level */ public boolean nonMergable(DlCompletionTree node, Reference<DepSet> dep) { if (inequalityRelation.isEmpty() || node.inequalityRelation.isEmpty()) { return false; } for (ConceptWDep p : node.inequalityRelation) { if (inIRwithC(p.getConcept(), p.getDep(), dep)) { return true; } } return false; } /** * update IR of the current node with IR from NODE and additional clash-set; * * @param node * node * @param toAdd * toAdd * @return restorer */ public Restorer updateIR(DlCompletionTree node, DepSet toAdd) { if (node.inequalityRelation.isEmpty()) { throw new IllegalArgumentException(); } // save current state Restorer ret = new IRRestorer(); // copy all elements from NODE's IR to current node. // FIXME!! do not check if some of them are already in there for (ConceptWDep p : node.inequalityRelation) { // not adding those already there, they would be ignored anyway if (!inequalityRelation_helper.containsKey(p.getConcept())) { ConceptWDep conceptWDep = new ConceptWDep(p.getConcept(), toAdd); inequalityRelation.add(conceptWDep); inequalityRelation_helper.put(p.getConcept(), conceptWDep); } } return ret; } @Override public int compareTo(DlCompletionTree o) { if (nominalLevel == o.nominalLevel) { return id - o.id; } return nominalLevel - o.nominalLevel; } @Override public boolean equals(Object arg0) { if (arg0 == null) { return false; } if (this == arg0) { return true; } if (arg0 instanceof DlCompletionTree) { DlCompletionTree arg02 = (DlCompletionTree) arg0; return nominalLevel == arg02.nominalLevel && id == arg02.id; } return false; } @Override public int hashCode() { return nominalLevel * id; } /** * @param blocker * blocker */ public void setBlocker(DlCompletionTree blocker) { this.blocker = blocker; } }