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 static uk.ac.manchester.cs.jfact.kernel.Redo.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.semanticweb.owlapi.reasoner.TimeOutException;
import uk.ac.manchester.cs.jfact.datatypes.DataTypeReasoner;
import uk.ac.manchester.cs.jfact.datatypes.DatatypeEntry;
import uk.ac.manchester.cs.jfact.datatypes.DatatypeFactory;
import uk.ac.manchester.cs.jfact.datatypes.LiteralEntry;
import uk.ac.manchester.cs.jfact.dep.DepSet;
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.FastSetSimple;
import uk.ac.manchester.cs.jfact.helpers.LogAdapter;
import uk.ac.manchester.cs.jfact.helpers.Reference;
import uk.ac.manchester.cs.jfact.helpers.SaveStack;
import uk.ac.manchester.cs.jfact.helpers.Stats;
import uk.ac.manchester.cs.jfact.helpers.Templates;
import uk.ac.manchester.cs.jfact.helpers.Timer;
import uk.ac.manchester.cs.jfact.helpers.UnreachableSituationException;
import uk.ac.manchester.cs.jfact.kernel.dl.interfaces.NamedEntity;
import uk.ac.manchester.cs.jfact.kernel.modelcaches.ModelCacheConst;
import uk.ac.manchester.cs.jfact.kernel.modelcaches.ModelCacheIan;
import uk.ac.manchester.cs.jfact.kernel.modelcaches.ModelCacheInterface;
import uk.ac.manchester.cs.jfact.kernel.modelcaches.ModelCacheState;
import uk.ac.manchester.cs.jfact.kernel.options.JFactReasonerConfiguration;
import uk.ac.manchester.cs.jfact.kernel.todolist.ToDoEntry;
import uk.ac.manchester.cs.jfact.kernel.todolist.ToDoList;
import uk.ac.manchester.cs.jfact.split.TSplitRules.TSplitRule;
import conformance.Original;
import conformance.PortedFrom;
/** sat tester */
@PortedFrom(file = "Reasoner.h", name = "DlSatTester")
public class DlSatTester implements Serializable {
private static final long serialVersionUID = 11000L;
private class LocalFastSet implements FastSet, Serializable {
private static final long serialVersionUID = 11000L;
private BitSet pos = new BitSet();
public LocalFastSet() {}
@Override
public int[] toIntArray() {
throw new UnsupportedOperationException();
}
@Override
public int size() {
throw new UnsupportedOperationException();
}
@Override
public void removeAt(int o) {
throw new UnsupportedOperationException();
}
@Override
public void removeAllValues(int... values) {
throw new UnsupportedOperationException();
}
@Override
public void removeAll(int i, int end) {
throw new UnsupportedOperationException();
}
@Override
public void remove(int o) {
throw new UnsupportedOperationException();
}
@Override
public boolean isEmpty() {
throw new UnsupportedOperationException();
}
@Override
public boolean intersect(FastSet f) {
throw new UnsupportedOperationException();
}
@Override
public int get(int i) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAny(FastSet c) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(FastSet c) {
throw new UnsupportedOperationException();
}
private int asPositive(int p) {
return p >= 0 ? 2 * p : 1 - 2 * p;
}
@Override
public boolean contains(int o) {
return pos.get(asPositive(o));
}
@Override
public void clear() {
pos.clear();
}
@Override
public void addAll(FastSet c) {
throw new UnsupportedOperationException();
}
@Override
public void add(int e) {
pos.set(asPositive(e));
}
@Override
public void completeSet(int value) {
for (int i = 0; i <= value; i++) {
pos.set(i);
}
}
}
/** Enum for usage the Tactics to a ToDoEntry */
abstract class BranchingContext implements Serializable {
private static final long serialVersionUID = 11000L;
/** currently processed node */
protected DlCompletionTree node;
/** currently processed concept */
protected ConceptWDep concept = null;
/** dependences for branching clashes */
protected DepSet branchDep = DepSet.create();
/** size of a session GCIs vector */
protected int SGsize;
/** empty c'tor */
public BranchingContext() {
node = null;
}
/** init indeces (if necessary) */
public abstract void init();
/** give the next branching alternative */
public abstract void nextOption();
@Override
public String toString() {
return this.getClass().getSimpleName() + " dep '" + branchDep
+ "' curconcept '"
+ (concept == null ? new ConceptWDep(bpINVALID) : concept)
+ "' curnode '" + node + '\'';
}
}
abstract class BCChoose extends BranchingContext {
private static final long serialVersionUID = 11000L;
}
/** stack to keep BContext */
class BCStack extends SaveStack<BranchingContext> {
private static final long serialVersionUID = 11000L;
/** single entry for the barrier (good for nominal reasoner) */
private final BCBarrier bcBarrier;
/** push method to use */
@Override
public void push(BranchingContext p) {
p.init();
initBC(p);
super.push(p);
}
protected BCStack() {
bcBarrier = new BCBarrier();
}
/**
* get BC for Or-rule
*
* @return or
*/
protected BranchingContext pushOr() {
BCOr o = new BCOr();
push(o);
return o;
}
/**
* get BC for NN-rule
*
* @return nn
*/
protected BranchingContext pushNN() {
BCNN n = new BCNN();
push(n);
return n;
}
/**
* get BC for LE-rule
*
* @return le
*/
protected BCLE<DlCompletionTreeArc> pushLE() {
BCLE<DlCompletionTreeArc> e = new BCLE<DlCompletionTreeArc>();
push(e);
return e;
}
/**
* get BC for TopLE-rule
*
* @return le
*/
protected BCLE<DlCompletionTree> pushTopLE() {
// XXX verify if this is correct
BCLE<DlCompletionTree> e = new BCLE<DlCompletionTree>();
push(e);
return e;
}
/**
* get BC for Choose-rule
*
* @return choose
*/
protected BCChoose pushCh() {
BCChoose c = new BCChoose() {
private static final long serialVersionUID = 11000L;
@Override
public void nextOption() {}
@Override
public void init() {}
};
push(c);
return c;
}
/**
* get BC for the barrier
*
* @return barrier
*/
protected BCBarrier pushBarrier() {
push(bcBarrier);
return bcBarrier;
}
}
class BCBarrier extends BranchingContext {
private static final long serialVersionUID = 11000L;
@Override
public void init() {}
@Override
public void nextOption() {}
}
class BCLE<I> extends BranchingContext {
private static final long serialVersionUID = 11000L;
/** current branching index; used in several branching rules */
private int branchIndex;
/** index of a merge-candidate (in LE concept) */
private int mergeCandIndex;
/** vector of edges to be merged */
private List<I> edges = new ArrayList<I>();
/** init tag and indeces */
@Override
public void init() {
branchIndex = 0;
mergeCandIndex = 0;
}
public List<I> swap(List<I> values) {
List<I> temp = edges;
edges = values;
return temp;
}
/** correct mergeCandIndex after changing */
protected void resetMCI() {
mergeCandIndex = edges.size() - 1;
}
/** give the next branching alternative */
@Override
public void nextOption() {
--mergeCandIndex;
// get new merge candidate
if (mergeCandIndex == branchIndex) {
// nothing more can be mergeable to BI node
++branchIndex;
// change the candidate to merge to
resetMCI();
}
}
// access to the fields
/**
* get FROM pointer to merge
*
* @return from
*/
protected I getFrom() {
return edges.get(mergeCandIndex);
}
/**
* get FROM pointer to merge
*
* @return to
*/
protected I getTo() {
return edges.get(branchIndex);
}
/**
* check if the LE has no option to process
*
* @return true if more
*/
protected boolean noMoreLEOptions() {
return mergeCandIndex <= branchIndex;
}
protected List<I> getEdgesToMerge() {
return edges;
}
protected void setEdgesToMerge(List<I> edgesToMerge) {
edges = edgesToMerge;
}
}
class BCNN extends BranchingContext {
private static final long serialVersionUID = 11000L;
/** current branching index; used in several branching rules */
private int branchIndex;
/** init tag and indeces */
@Override
public void init() {
branchIndex = 1;
}
/** give the next branching alternative */
@Override
public void nextOption() {
++branchIndex;
}
// access to the fields
/**
* check if the NN has no option to process
*
* @param n
* n
* @return true if no more options
*/
protected boolean noMoreNNOptions(int n) {
return branchIndex > n;
}
protected int getBranchIndex() {
return branchIndex;
}
public void setBranchIndex(int branchIndex) {
this.branchIndex = branchIndex;
}
}
class BCOr extends BranchingContext {
private static final long serialVersionUID = 11000L;
/** current branching index; used in several branching rules */
private int branchIndex;
private int size = 0;
/** useful disjuncts (ready to add) in case of OR */
private List<ConceptWDep> applicableOrEntries = new ArrayList<ConceptWDep>();
/** init tag and indeces */
@Override
public void init() {
branchIndex = 0;
}
/** give the next branching alternative */
@Override
public void nextOption() {
++branchIndex;
}
// access to the fields
/**
* check if the current processing OR entry is the last one
*
* @return true if last
*/
protected boolean isLastOrEntry() {
return size == branchIndex + 1;
}
/**
* current element of OrIndex
*
* @return current or
*/
protected ConceptWDep orCur() {
return applicableOrEntries.get(branchIndex);
}
protected int getBranchIndex() {
return branchIndex;
}
protected int[] getApplicableOrEntriesConcepts() {
int[] toReturn = new int[branchIndex];
for (int i = 0; i < toReturn.length; i++) {
toReturn[i] = applicableOrEntries.get(i).getConcept();
}
return toReturn;
}
protected List<ConceptWDep> setApplicableOrEntries(
List<ConceptWDep> list) {
List<ConceptWDep> toReturn = applicableOrEntries;
applicableOrEntries = list;
size = applicableOrEntries.size();
return toReturn;
}
@Override
public String toString() {
StringBuilder o = new StringBuilder();
o.append("BCOR ");
o.append(branchIndex);
o.append(" dep ");
o.append(branchDep);
o.append(" curconcept ");
o.append(concept == null ? new ConceptWDep(bpINVALID) : concept);
o.append(" curnode ");
o.append(node);
o.append(" orentries [");
o.append(applicableOrEntries);
o.append(']');
return o.toString();
}
}
/** GCIs local to session */
@PortedFrom(file = "Reasoner.h", name = "SessionGCIs")
private final List<Integer> SessionGCIs = new ArrayList<Integer>();
/** set of active splits */
@PortedFrom(file = "Reasoner.h", name = "ActiveSplits")
private final FastSet ActiveSplits = FastSetFactory.create();
/** concept signature of current CGraph */
@PortedFrom(file = "Reasoner.h", name = "SessionSignature")
private final Set<NamedEntity> SessionSignature = new HashSet<NamedEntity>();
/** signature to dep-set map for current session */
@PortedFrom(file = "Reasoner.h", name = "SessionSigDepSet")
private final Map<NamedEntity, DepSet> SessionSigDepSet = new HashMap<NamedEntity, DepSet>();
/** nodes to merge in the TopRole-LE rules */
@PortedFrom(file = "Reasoner.h", name = "NodesToMerge")
private List<DlCompletionTree> NodesToMerge = new ArrayList<DlCompletionTree>();
@PortedFrom(file = "Reasoner.h", name = "EdgesToMerge")
private List<DlCompletionTreeArc> EdgesToMerge = new ArrayList<DlCompletionTreeArc>();
// CGraph-wide rules support
/**
* @param node
* node
* @return true if node is valid for the reasoning
*/
@PortedFrom(file = "Reasoner.h", name = "isNodeGloballyUsed")
private static boolean isNodeGloballyUsed(DlCompletionTree node) {
return !(node.isDataNode() || node.isIBlocked() || node.isPBlocked());
}
/**
* @param node
* node
* @return true if node is valid for the reasoning
*/
@PortedFrom(file = "Reasoner.h", name = "isObjectNodeUnblocked")
private static boolean isObjectNodeUnblocked(DlCompletionTree node) {
return isNodeGloballyUsed(node) && !node.isDBlocked();
}
/**
* put TODO entry for either BP or inverse(BP) in NODE's label
*
* @param node
* node
* @param bp
* bp
*/
@PortedFrom(file = "Reasoner.h", name = "updateName")
private void updateName(DlCompletionTree node, int bp) {
CGLabel lab = node.label();
ConceptWDep c = lab.getConceptWithBP(bp);
if (c == null) {
c = lab.getConceptWithBP(-bp);
}
if (c != null) {
addExistingToDoEntry(node, c, "sp");
}
}
/**
* re-do every BP or inverse(BP) in labels of CGraph
*
* @param bp
* bp
*/
@PortedFrom(file = "Reasoner.h", name = "updateName")
private void updateName(int bp) {
int n = 0;
DlCompletionTree node = cGraph.getNode(n++);
while (node != null) {
if (isNodeGloballyUsed(node)) {
this.updateName(node, bp);
}
node = cGraph.getNode(n++);
}
}
/** host TBox */
@PortedFrom(file = "Reasoner.h", name = "tBox")
protected final TBox tBox;
/** link to dag from TBox */
@PortedFrom(file = "Reasoner.h", name = "DLHeap")
protected final DLDag dlHeap;
/** all the reflexive roles */
@PortedFrom(file = "Reasoner.h", name = "ReflexiveRoles")
private final List<Role> reflexiveRoles = new ArrayList<Role>();
/** Completion Graph of tested concept(s) */
@PortedFrom(file = "Reasoner.h", name = "CGraph")
protected final DlCompletionGraph cGraph;
/** Todo list */
@PortedFrom(file = "Reasoner.h", name = "TODO")
private final ToDoList TODO;
@Original
private final FastSet used = new LocalFastSet();
/** GCI-related KB flags */
@PortedFrom(file = "Reasoner.h", name = "GCIs")
private final KBFlags gcis;
/** record nodes that were processed during Cascaded Cache construction */
@PortedFrom(file = "Reasoner.h", name = "inProcess")
private final FastSet inProcess = FastSetFactory.create();
/** timer for the SAT tests (ie, cache creation) */
@PortedFrom(file = "Reasoner.h", name = "satTimer")
private final Timer satTimer = new Timer();
/** timer for the SUB tests (ie, general subsumption) */
@PortedFrom(file = "Reasoner.h", name = "subTimer")
private final Timer subTimer = new Timer();
/** timer for a single test; use it as a timeout checker */
@PortedFrom(file = "Reasoner.h", name = "testTimer")
private final Timer testTimer = new Timer();
// save/restore option
/** stack for the local reasoner's state */
@PortedFrom(file = "Reasoner.h", name = "Stack")
protected final BCStack stack = new BCStack();
/** context from the restored branching rule */
@PortedFrom(file = "Reasoner.h", name = "bContext")
protected BranchingContext bContext;
/** index of last non-det situation */
@PortedFrom(file = "Reasoner.h", name = "tryLevel")
private int tryLevel;
/** shift in order to determine the 1st non-det application */
@PortedFrom(file = "Reasoner.h", name = "nonDetShift")
protected int nonDetShift;
/** last level when split rules were applied */
@PortedFrom(file = "Reasoner.h", name = "splitRuleLevel")
private int splitRuleLevel;
// current values
/** currently processed CTree node */
@PortedFrom(file = "Reasoner.h", name = "curNode")
protected DlCompletionTree curNode;
/** currently processed Concept */
@Original
private DepSet curConceptDepSet;
@Original
private int curConceptConcept;
/** size of the DAG with some extra space */
@PortedFrom(file = "Reasoner.h", name = "dagSize")
private int dagSize;
/** temporary array used in OR operation */
@PortedFrom(file = "Reasoner.h", name = "OrConceptsToTest")
private List<ConceptWDep> orConceptsToTest = new ArrayList<ConceptWDep>();
/** contains clash set if clash is encountered in a node label */
@PortedFrom(file = "Reasoner.h", name = "clashSet")
private DepSet clashSet = DepSet.create();
@Original
protected final JFactReasonerConfiguration options;
// session status flags:
/** true if nominal-related expansion rule was fired during reasoning */
@PortedFrom(file = "Reasoner.h", name = "encounterNominal")
private boolean encounterNominal;
/** flag to show if it is necessary to produce DT reasoning immediately */
@PortedFrom(file = "Reasoner.h", name = "checkDataNode")
private boolean checkDataNode;
/** cache for testing whether it's possible to non-expand newly created node */
@PortedFrom(file = "Reasoner.h", name = "newNodeCache")
private final ModelCacheIan newNodeCache;
/** auxilliary cache that is built from the edges of newly created node */
@PortedFrom(file = "Reasoner.h", name = "newNodeEdges")
private final ModelCacheIan newNodeEdges;
@Original
private final Stats stats = new Stats();
@Original
protected final DatatypeFactory datatypeFactory;
/**
* Adds ToDo entry which already exists in label of NODE. There is no need
* to add entry to label, but it is necessary to provide offset of existing
* concept. This is done by providing OFFSET of the concept in NODE's label
*
* @param node
* node
* @param C
* C
* @param reason
* reason
*/
@PortedFrom(file = "Reasoner.h", name = "addExistingToDoEntry")
private void addExistingToDoEntry(DlCompletionTree node, ConceptWDep C,
String reason) {
int bp = C.getConcept();
TODO.addEntry(node, dlHeap.get(bp).getType(), C);
logNCEntry(node, C.getConcept(), C.getDep(), "+", reason);
}
/**
* add all elements from NODE label into Todo list
*
* @param node
* node
* @param reason
* reason
*/
@PortedFrom(file = "Reasoner.h", name = "redoNodeLabel")
private void redoNodeLabel(DlCompletionTree node, String reason) {
CGLabel lab = node.label();
List<ConceptWDep> l = lab.get_sc();
for (int i = 0; i < l.size(); i++) {
addExistingToDoEntry(node, l.get(i), reason);
}
l = lab.get_cc();
for (int i = 0; i < l.size(); i++) {
addExistingToDoEntry(node, l.get(i), reason);
}
}
/** make sure that the DAG does not grow larger than that was recorded */
@PortedFrom(file = "Reasoner.h", name = "ensureDAGSize")
private void ensureDAGSize() {
if (dagSize < dlHeap.size()) {
dagSize = dlHeap.maxSize();
tBox.getSplitRules().ensureDagSize(dagSize);
}
}
// -- internal cache support
/**
* @return cache of given completion tree (implementation)
* @param p
* p
*/
@PortedFrom(file = "Reasoner.h", name = "createModelCache")
protected ModelCacheInterface createModelCache(DlCompletionTree p) {
return new ModelCacheIan(dlHeap, p, encounterNominal, tBox.nC, tBox.nR,
options.isRKG_USE_SIMPLE_RULES());
}
/**
* check whether node may be (un)cached; save node if something is changed
*
* @param node
* node
* @return cahe state
*/
@PortedFrom(file = "Reasoner.h", name = "tryCacheNode")
private ModelCacheState tryCacheNode(DlCompletionTree node) {
// TODO verify
ModelCacheState ret = canBeCached(node) ? reportNodeCached(node)
: ModelCacheState.csFailed;
// node is cached if RET is csvalid
boolean val = ret == ModelCacheState.csValid;
if (node.isCached() != val) {
Restorer setCached = node.setCached(val);
cGraph.saveRareCond(setCached);
}
return ret;
}
@PortedFrom(file = "Reasoner.h", name = "applyExtraRulesIf")
private boolean applyExtraRulesIf(Concept p) {
if (!p.hasExtraRules()) {
return false;
}
assert p.isPrimitive();
return applyExtraRules(p);
}
// -- internal nominal reasoning interface
/** @return check whether reasoning with nominals is performed */
@PortedFrom(file = "Reasoner.h", name = "hasNominals")
public boolean hasNominals() {
return false;
}
/** @return true iff current node is i-blocked (ie, no expansion necessary) */
@PortedFrom(file = "Reasoner.h", name = "isIBlocked")
private boolean isIBlocked() {
return curNode.isIBlocked();
}
/**
* @param R
* R
* @param C
* C
* @return true iff there is R-neighbour labelled with C
*/
@PortedFrom(file = "Reasoner.h", name = "isSomeExists")
private boolean isSomeExists(Role R, int C) {
// TODO verify whether a cache is worth the effort
if (!used.contains(C)) {
return false;
}
DlCompletionTree where = curNode.isSomeApplicable(R, C);
if (where != null) {
options.getLog().printTemplate(Templates.E, R.getName(),
where.getId(), C);
}
return where != null;
}
/*
* apply AR.C in and <= nR (if needed) in NODE's label where R is label of
* arcSample. Set of applicable concepts is defined by redoForallFlags
* value.
*/
/**
* check if branching rule was called for the 1st time
*
* @return true if first call
*/
@PortedFrom(file = "Reasoner.h", name = "isFirstBranchCall")
private boolean isFirstBranchCall() {
return bContext == null;
}
/**
* init branching context with given rule type
*
* @param c
* c
*/
@PortedFrom(file = "Reasoner.h", name = "initBC")
protected void initBC(BranchingContext c) {
// XXX move to BranchingContext
// save reasoning context
c.node = curNode;
c.concept = new ConceptWDep(curConceptConcept, curConceptDepSet);
c.branchDep = DepSet.create(curConceptDepSet);
// TODO check why these commented lines do not appear
// bContext.pUsedIndex = pUsed.size();
// bContext.nUsedIndex = nUsed.size();
c.SGsize = SessionGCIs.size();
}
/** create BC for Or rule */
@PortedFrom(file = "Reasoner.h", name = "createBCOr")
private void createBCOr() {
bContext = stack.pushOr();
}
/** create BC for NN-rule */
@PortedFrom(file = "Reasoner.h", name = "createBCNN")
private void createBCNN() {
bContext = stack.pushNN();
}
/** create BC for LE-rule */
@PortedFrom(file = "Reasoner.h", name = "createBCLE")
private void createBCLE() {
bContext = stack.pushLE();
}
/** create BC for Choose-rule */
@PortedFrom(file = "Reasoner.h", name = "createBCCh")
private void createBCCh() {
bContext = stack.pushCh();
}
/**
* check whether a node represents a functional one
*
* @param v
* v
* @return true if functional
*/
@PortedFrom(file = "Reasoner.h", name = "isFunctionalVertex")
private static boolean isFunctionalVertex(DLVertex v) {
return v.getType() == DagTag.dtLE && v.getNumberLE() == 1
&& v.getConceptIndex() == bpTOP;
}
/**
* check if ATLEAST and ATMOST entries are in clash. Both vertex MUST have
* dtLE type.
*
* @param atleast
* atleast
* @param atmost
* atmost
* @return true if clashing
*/
@PortedFrom(file = "Reasoner.h", name = "checkNRclash")
private static boolean checkNRclash(DLVertex atleast, DLVertex atmost) {
// >= n R.C clash with <= m S.D iff...
return (atmost.getConceptIndex() == bpTOP ||
// either D is TOP or C == D...
atleast.getConceptIndex() == atmost.getConceptIndex())
&&
// and n is greater than m...
atleast.getNumberGE() > atmost.getNumberLE() &&
// and R [= S
atleast.getRole().lesserequal(atmost.getRole());
}
/**
* quick check whether CURNODE has a clash with a given ATMOST restriction
*
* @param atmost
* atmost
* @return true if clash
*/
@PortedFrom(file = "Reasoner.h", name = "isQuickClashLE")
private boolean isQuickClashLE(DLVertex atmost) {
List<ConceptWDep> list = curNode.beginl_cc();
for (int i = 0; i < list.size(); i++) {
ConceptWDep q = list.get(i);
// need at-least restriction
if (q.getConcept() < 0
&& isNRClash(dlHeap.get(q.getConcept()), atmost, q)) {
return true;
}
}
return false;
}
/**
* quick check whether CURNODE has a clash with a given ATLEAST restriction
*
* @param atleast
* atleast
* @return true if clashing
*/
@PortedFrom(file = "Reasoner.h", name = "isQuickClashGE")
private boolean isQuickClashGE(DLVertex atleast) {
List<ConceptWDep> list = curNode.beginl_cc();
for (int i = 0; i < list.size(); i++) {
ConceptWDep q = list.get(i);
// need at-most restriction
if (q.getConcept() > 0
&& isNRClash(atleast, dlHeap.get(q.getConcept()), q)) {
return true;
}
}
return false;
}
/**
* aux method that fills the dep-set for either C or ~C found in the label;
*
* @param label
* label
* @param C
* C
* @param d
* depset to be changed if a clash is found
* @return whether C was found
*/
@PortedFrom(file = "Reasoner.h", name = "findChooseRuleConcept")
private boolean findChooseRuleConcept(CWDArray label, int C, DepSet d) {
if (C == bpTOP) {
return true;
}
if (findConceptClash(label, C, d)) {
if (d != null) {
d.add(clashSet);
}
return true;
} else if (findConceptClash(label, -C, d)) {
if (d != null) {
d.add(clashSet);
}
return false;
} else {
throw new UnreachableSituationException();
}
}
/**
* check whether clash occures EDGE to TO labelled with S disjoint with R
*
* @param edge
* edge
* @param to
* to
* @param R
* R
* @param dep
* dep
* @return true if clashing
*/
@PortedFrom(file = "Reasoner.h", name = "checkDisjointRoleClash")
private boolean checkDisjointRoleClash(DlCompletionTreeArc edge,
DlCompletionTree to, Role R, DepSet dep) {
// clash found
if (edge.getArcEnd().equals(to) && edge.getRole().isDisjoint(R)) {
this.setClashSet(dep);
updateClashSet(edge.getDep());
return true;
}
return false;
}
// support for FORALL expansion
/**
* Perform expansion of (\neg \ER.Self).DEP to an EDGE
*
* @param edge
* edge
* @param R
* R
* @param dep
* dep
* @return true if clashing
*/
@PortedFrom(file = "Reasoner.h", name = "checkIrreflexivity")
private boolean checkIrreflexivity(DlCompletionTreeArc edge, Role R,
DepSet dep) {
// only loops counts here...
if (!edge.getArcEnd().equals(edge.getReverse().getArcEnd())) {
return false;
}
// which are labelled either with R or with R-
if (!edge.isNeighbour(R) && !edge.isNeighbour(R.inverse())) {
return false;
}
// set up clash
this.setClashSet(dep);
updateClashSet(edge.getDep());
return true;
}
/**
* log the result of processing ACTION with entry (N,C{DEP})/REASON
*
* @param n
* n
* @param bp
* bp
* @param dep
* dep
* @param action
* action
* @param reason
* reason
*/
@PortedFrom(file = "Reasoner.h", name = "logNCEntry")
private void logNCEntry(DlCompletionTree n, int bp, DepSet dep,
String action, String reason) {
if (options.isLoggingActive()) {
LogAdapter logAdapter = options.getLog();
logAdapter.print(" ").print(action).print("(").print(n.logNode())
.print(",").print(bp).print(dep, ")");
if (reason != null) {
logAdapter.print(reason);
}
}
}
/**
* use this method in ALL dependency stuff (never use tryLevel directly)
*
* @return try level
*/
@PortedFrom(file = "Reasoner.h", name = "getCurLevel")
private int getCurLevel() {
return tryLevel;
}
/**
* set new branching level (never use tryLevel directly)
*
* @param level
* level
*/
@PortedFrom(file = "Reasoner.h", name = "setCurLevel")
private void setCurLevel(int level) {
tryLevel = level;
}
/**
* @return true if no branching ops were applied during reasoners; FIXME!!
* doesn't work properly with a nominal cloud
*/
@PortedFrom(file = "Reasoner.h", name = "noBranchingOps")
protected boolean noBranchingOps() {
return tryLevel == InitBranchingLevelValue + nonDetShift;
}
/**
* Get save/restore level based on either current- or DS level
*
* @param ds
* ds
* @return restore level
*/
@PortedFrom(file = "Reasoner.h", name = "getSaveRestoreLevel")
private int getSaveRestoreLevel(DepSet ds) {
// FIXME!!! see more precise it later
if (options.isRKG_IMPROVE_SAVE_RESTORE_DEPSET()) {
return ds.level() + 1;
} else {
return getCurLevel();
}
}
/** restore reasoning state to the latest saved position */
@PortedFrom(file = "Reasoner.h", name = "restore")
private void restore() {
this.restore(getCurLevel() - 1);
}
/**
* update level in N node and save it's state (if necessary)
*
* @param n
* n
* @param ds
* ds
*/
@PortedFrom(file = "Reasoner.h", name = "updateLevel")
private void updateLevel(DlCompletionTree n, DepSet ds) {
cGraph.saveNode(n, getSaveRestoreLevel(ds));
}
/** finalize branching OP processing making deterministic op */
@PortedFrom(file = "Reasoner.h", name = "determiniseBranchingOp")
private void determiniseBranchingOp() {
// clear context for the next branching op
bContext = null;
// remove unnecessary context from the stack
stack.pop();
}
/**
* set value of global dep-set to D
*
* @param d
* d
*/
@PortedFrom(file = "Reasoner.h", name = "setClashSet")
private void setClashSet(DepSet d) {
clashSet = d;
}
@PortedFrom(file = "Reasoner.h", name = "setClashSet")
private void setClashSet(List<DepSet> d) {
DepSet dep = DepSet.create();
for (int i = 0; i < d.size(); i++) {
dep.add(d.get(i));
}
clashSet = dep;
}
/**
* add D to global dep-set
*
* @param d
* d
*/
@PortedFrom(file = "Reasoner.h", name = "updateClashSet")
private void updateClashSet(DepSet d) {
clashSet.add(d);
}
/**
* get dep-set wrt current level
*
* @return current depset
*/
@PortedFrom(file = "Reasoner.h", name = "getCurDepSet")
private DepSet getCurDepSet() {
return DepSet.create(getCurLevel() - 1);
}
/** @return current branching dep-set */
@PortedFrom(file = "Reasoner.h", name = "getBranchDep")
private DepSet getBranchDep() {
return bContext.branchDep;
}
/** update cumulative branch-dep with current clash-set */
@PortedFrom(file = "Reasoner.h", name = "updateBranchDep")
private void updateBranchDep() {
getBranchDep().add(clashSet);
}
/** prepare cumulative dep-set to usage */
@PortedFrom(file = "Reasoner.h", name = "prepareBranchDep")
private void prepareBranchDep() {
getBranchDep().restrict(getCurLevel());
}
/** prepare cumulative dep-set and copy itto general clash-set */
@PortedFrom(file = "Reasoner.h", name = "useBranchDep")
private void useBranchDep() {
prepareBranchDep();
this.setClashSet(getBranchDep());
}
/**
* re-apply all the relevant expantion rules to a given unblocked NODE
*
* @param node
* node
* @param direct
* direct
*/
@PortedFrom(file = "Reasoner.h", name = "repeatUnblockedNode")
public void repeatUnblockedNode(DlCompletionTree node, boolean direct) {
if (direct) {
// re-apply all the generating rules
applyAllGeneratingRules(node);
} else {
redoNodeLabel(node, "ubi");
}
}
/** @return DAG associated with it (necessary for the blocking support) */
@PortedFrom(file = "Reasoner.h", name = "getDAG")
public DLDag getDAG() {
return tBox.getDLHeap();
}
/** @return the ROOT node of the completion graph */
@PortedFrom(file = "Reasoner.h", name = "getRootNode")
public DlCompletionTree getRootNode() {
return cGraph.getRoot();
}
/** init Todo list priority for classification */
@Original
public void initToDoPriorities() {
String iaoeflg = options.getIAOEFLG();
// inform about used rules order
options.getLog().print("\nInit IAOEFLG = ", iaoeflg);
TODO.initPriorities(iaoeflg);
}
/**
* set blocking method for a session
*
* @param hasInverse
* hasInverse
* @param hasQCR
* hasQCR
*/
@PortedFrom(file = "Reasoner.h", name = "setBlockingMethod")
public void setBlockingMethod(boolean hasInverse, boolean hasQCR) {
cGraph.setBlockingMethod(hasInverse, hasQCR);
}
/**
* @param sat
* sat
* @return create model cache for the just-classified entry
*/
@PortedFrom(file = "Reasoner.h", name = "buildCacheByCGraph")
public ModelCacheInterface buildCacheByCGraph(boolean sat) {
if (sat) {
return createModelCache(getRootNode());
} else {
// unsat => cache is just bottom
return ModelCacheConst.createConstCache(bpBOTTOM);
}
}
/**
* @param o
* o
*/
@PortedFrom(file = "Reasoner.h", name = "writeTotalStatistic")
public void writeTotalStatistic(LogAdapter o) {
if (options.isUSE_REASONING_STATISTICS()) {
// ensure that the last reasoning results are in
stats.accumulate();
stats.logStatisticData(o, false, cGraph, options);
}
o.print("\n");
}
/**
* @param p
* p
* @param f
* f
* @return new cache
*/
@PortedFrom(file = "Reasoner.h", name = "createCache")
public ModelCacheInterface createCache(int p, FastSet f) {
assert isValid(p);
ModelCacheInterface cache = dlHeap.getCache(p);
if (cache != null) {
return cache;
}
if (!tBox.testHasTopRole()) {
prepareCascadedCache(p, f);
}
cache = dlHeap.getCache(p);
if (cache != null) {
return cache;
}
cache = buildCache(p);
dlHeap.setCache(p, cache);
return cache;
}
@Original
private static final EnumSet<DagTag> handlecollection = EnumSet.of(dtAnd,
dtCollection);
@Original
private static final EnumSet<DagTag> handleforallle = EnumSet.of(dtForall,
dtLE);
@Original
private static final EnumSet<DagTag> handlesingleton = EnumSet.of(
dtPSingleton, dtNSingleton, dtNConcept, dtPConcept);
@PortedFrom(file = "Reasoner.h", name = "prepareCascadedCache")
private void prepareCascadedCache(int p, FastSet f) {
if (inProcess.contains(p)) {
return;
}
if (f.contains(p)) {
return;
}
DLVertex v = dlHeap.get(p);
boolean pos = p > 0;
if (v.getCache(pos) != null) {
return;
}
DagTag type = v.getType();
if (handlecollection.contains(type)) {
for (int q : v.begin()) {
int p2 = pos ? q : -q;
inProcess.add(p2);
prepareCascadedCache(p2, f);
inProcess.remove(p2);
}
} else if (handlesingleton.contains(type)) {
if (!pos && type.isPNameTag()) {
return;
}
inProcess.add(p);
prepareCascadedCache(
pos ? v.getConceptIndex() : -v.getConceptIndex(), f);
inProcess.remove(p);
} else if (handleforallle.contains(type)) {
Role R = v.getRole();
if (!R.isDataRole() && !R.isTop()) {
int x = pos ? v.getConceptIndex() : -v.getConceptIndex();
if (x != bpTOP) {
inProcess.add(x);
createCache(x, f);
inProcess.remove(x);
}
x = R.getBPRange();
if (x != bpTOP) {
inProcess.add(x);
createCache(x, f);
inProcess.remove(x);
}
}
}
// dttop, dtsplit, etc: do nothing
f.add(p);
}
@PortedFrom(file = "Reasoner.h", name = "buildCache")
private ModelCacheInterface buildCache(int p) {
LogAdapter logAdapter = options.getLog();
if (options.isLoggingActive()) {
logAdapter.print("\nChecking satisfiability of DAG entry ")
.print(p);
tBox.printDagEntry(logAdapter, p);
logAdapter.print(":\n");
}
boolean sat = this.runSat(p, bpTOP);
if (!sat) {
logAdapter.printTemplate(Templates.BUILD_CACHE_UNSAT, p);
}
return buildCacheByCGraph(sat);
}
// flags section
/** @return true iff active signature is in use */
@PortedFrom(file = "Reasoner.h", name = "useActiveSignature")
private boolean useActiveSignature() {
return !tBox.getSplits().empty();
}
@PortedFrom(file = "Reasoner.h", name = "resetSessionFlags")
protected void resetSessionFlags() {
// reflect possible change of DAG size
ensureDAGSize();
used.add(bpTOP);
used.add(bpBOTTOM);
encounterNominal = false;
checkDataNode = true;
splitRuleLevel = 0;
}
@PortedFrom(file = "Reasoner.h", name = "initNewNode")
protected boolean initNewNode(DlCompletionTree node, DepSet dep, int C) {
if (node.isDataNode()) {
checkDataNode = false;
}
node.setInit(C);
if (addToDoEntry(node, C, dep, null)) {
return true;
}
if (node.isDataNode()) {
return false;
}
if (addToDoEntry(node, tBox.getTG(), dep, null)) {
return true;
}
if (gcis.isReflexive() && applyReflexiveRoles(node, dep)) {
return true;
}
if (!SessionGCIs.isEmpty()) {
for (int i : SessionGCIs) {
if (addToDoEntry(node, i, dep, "sg")) {
return true;
}
}
}
return false;
}
/**
* @param p
* p
* @param q
* q
* @return true if satisfiable
*/
@PortedFrom(file = "Reasoner.h", name = "runSat")
public boolean runSat(int p, int q) {
prepareReasoner();
// use general method to init node with P and add Q then
if (initNewNode(cGraph.getRoot(), DepSet.create(), p)
|| addToDoEntry(cGraph.getRoot(), q, DepSet.create(), null)) {
// concept[s] unsatisfiable
return false;
}
// check satisfiability explicitly
Timer timer = q == bpTOP ? satTimer : subTimer;
timer.start();
boolean result = this.runSat();
timer.stop();
return result;
}
/**
* @param R
* R
* @param S
* S
* @return true if not satisfiable
*/
@PortedFrom(file = "Reasoner.h", name = "checkDisjointRoles")
public boolean checkDisjointRoles(Role R, Role S) {
prepareReasoner();
// use general method to init node...
DepSet dummy = DepSet.create();
if (initNewNode(cGraph.getRoot(), dummy, bpTOP)) {
return true;
}
// ... add edges with R and S...
curNode = cGraph.getRoot();
DlCompletionTreeArc edgeR = this.createOneNeighbour(R, dummy);
DlCompletionTreeArc edgeS = this.createOneNeighbour(S, dummy);
// init new nodes/edges. No need to apply restrictions, as no reasoning
// have been done yet.
if (initNewNode(edgeR.getArcEnd(), dummy, bpTOP)
|| initNewNode(edgeS.getArcEnd(), dummy, bpTOP)
|| setupEdge(edgeR, dummy, 0) || setupEdge(edgeS, dummy, 0)
|| merge(edgeS.getArcEnd(), edgeR.getArcEnd(), dummy)) {
return true;
}
// 2 roles are disjoint if current setting is unsatisfiable
curNode = null;
return !this.runSat();
}
/**
* @param R
* R
* @return true if not satisfiable
*/
@PortedFrom(file = "Reasoner.h", name = "checkIrreflexivity")
public boolean checkIrreflexivity(Role R) {
prepareReasoner();
// use general method to init node...
DepSet dummy = DepSet.create();
if (initNewNode(cGraph.getRoot(), dummy, bpTOP)) {
return true;
}
// ... add an R-loop
curNode = cGraph.getRoot();
DlCompletionTreeArc edgeR = this.createOneNeighbour(R, dummy);
// init new nodes/edges. No need to apply restrictions, as no reasoning
// have been done yet.
if (initNewNode(edgeR.getArcEnd(), dummy, bpTOP)
|| setupEdge(edgeR, dummy, 0)
|| merge(edgeR.getArcEnd(), cGraph.getRoot(), dummy)) {
return true;
}
// R is irreflexive if current setting is unsatisfiable
curNode = null;
return !this.runSat();
}
// restore implementation
@PortedFrom(file = "Reasoner.h", name = "backJumpedRestore")
private boolean backJumpedRestore() {
// if empty clash dep-set -- concept is unsatisfiable
if (clashSet == null || clashSet.isEmpty()) {
return true;
}
// some non-deterministic choices were done
this.restore(clashSet.level());
return false;
}
@PortedFrom(file = "Reasoner.h", name = "straightforwardRestore")
private boolean straightforwardRestore() {
if (noBranchingOps()) {
// ... the concept is unsatisfiable
return true;
} else {
// restoring the state
this.restore();
return false;
}
}
@PortedFrom(file = "Reasoner.h", name = "tunedRestore")
private boolean tunedRestore() {
if (options.getuseBackjumping()) {
return backJumpedRestore();
} else {
return straightforwardRestore();
}
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyAll")
private boolean commonTacticBodyAll(DLVertex cur) {
assert curConceptConcept > 0 && cur.getType() == dtForall;
if (cur.getRole().isTop()) {
stats.getnAllCalls().inc();
return addSessionGCI(cur.getConceptIndex(), curConceptDepSet);
}
// can't skip singleton models for complex roles due to empty
// transitions
if (cur.getRole().isSimple()) {
return commonTacticBodyAllSimple(cur);
} else {
return commonTacticBodyAllComplex(cur);
}
}
/**
* add C to a set of session GCIs; init all nodes with (C,dep)
*
* @param C
* C
* @param dep
* dep
* @return true if node existed
*/
@PortedFrom(file = "Reasoner.h", name = "addSessionGCI")
private boolean addSessionGCI(int C, DepSet dep) {
SessionGCIs.add(C);
int n = 0;
DlCompletionTree node = cGraph.getNode(n++);
while (node != null) {
if (isNodeGloballyUsed(node) && addToDoEntry(node, C, dep, "sg")) {
return true;
}
node = cGraph.getNode(n++);
}
return false;
}
protected DlSatTester(TBox tbox, JFactReasonerConfiguration Options,
DatatypeFactory datatypeFactory) {
options = Options;
this.datatypeFactory = datatypeFactory;
tBox = tbox;
dlHeap = tbox.getDLHeap();
cGraph = new DlCompletionGraph(1, this);
TODO = new ToDoList(cGraph.getRareStack());
newNodeCache = new ModelCacheIan(true, tbox.nC, tbox.nR,
options.isRKG_USE_SIMPLE_RULES());
newNodeEdges = new ModelCacheIan(false, tbox.nC, tbox.nR,
options.isRKG_USE_SIMPLE_RULES());
gcis = tbox.getGCIs();
bContext = null;
tryLevel = InitBranchingLevelValue;
nonDetShift = 0;
curNode = null;
dagSize = 0;
options.getLog().printTemplate(Templates.READCONFIG,
options.getuseSemanticBranching(), options.getuseBackjumping(),
options.getuseLazyBlocking(), options.getuseAnywhereBlocking());
if (tBox.hasFC() && options.getuseAnywhereBlocking()) {
options.setuseAnywhereBlocking(false);
options.getLog().print(
"Fairness constraints: set useAnywhereBlocking = false\n");
}
cGraph.initContext(tbox.getnSkipBeforeBlock(),
options.getuseLazyBlocking(), options.getuseAnywhereBlocking());
tbox.getORM().fillReflexiveRoles(reflexiveRoles);
resetSessionFlags();
}
/** @return configuration options */
@Original
public JFactReasonerConfiguration getOptions() {
return options;
}
@PortedFrom(file = "Reasoner.h", name = "prepareReasoner")
protected void prepareReasoner() {
cGraph.clear();
stack.clear();
TODO.clear();
used.clear();
SessionGCIs.clear();
curNode = null;
bContext = null;
tryLevel = InitBranchingLevelValue;
// clear last session information
resetSessionFlags();
}
/**
* try to add a concept to a label given by TAG; ~C can't appear in the
* label
*
* @param label
* label
* @param p
* p
* @return true if label contains p
*/
@PortedFrom(file = "Reasoner.h", name = "findConcept")
public boolean findConcept(CWDArray label, int p) {
assert isCorrect(p); // sanity checking
// constants are not allowed here
assert p != bpTOP;
assert p != bpBOTTOM;
stats.getnLookups().inc();
return label.contains(p);
}
@PortedFrom(file = "Reasoner.h", name = "checkAddedConcept")
private AddConceptResult checkAddedConcept(CWDArray lab, int p, DepSet dep) {
assert isCorrect(p); // sanity checking
// constants are not allowed here
assert p != bpTOP;
assert p != bpBOTTOM;
stats.getnLookups().inc();
stats.getnLookups().inc();
if (lab.contains(p)) {
return AddConceptResult.acrExist;
}
int inv_p = -p;
DepSet depset = lab.get(inv_p);
if (depset != null) {
clashSet = DepSet.plus(depset, dep);
return AddConceptResult.acrClash;
}
return AddConceptResult.acrDone;
}
/**
* try to add a concept to a label given by TAG; ~C can't appear in the
* label; setup clash-set if found
*
* @param lab
* lab
* @param bp
* bp
* @param dep
* dep
* @return true if clashing
*/
@PortedFrom(file = "Reasoner.h", name = "findConceptClash")
private boolean findConceptClash(CWDArray lab, int bp, DepSet dep) {
stats.getnLookups().inc();
DepSet depset = lab.get(bp);
if (depset != null) {
clashSet = DepSet.plus(depset, dep);
return true;
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "tryAddConcept")
private AddConceptResult tryAddConcept(CWDArray lab, int bp, DepSet dep) {
boolean canC = used.contains(bp);
boolean canNegC = used.contains(-bp);
if (canC) {
if (canNegC) {
return checkAddedConcept(lab, bp, dep);
} else {
stats.getnLookups().inc();
return findConcept(lab, bp) ? AddConceptResult.acrExist
: AddConceptResult.acrDone;
}
} else {
if (canNegC) {
return findConceptClash(lab, -bp, dep) ? AddConceptResult.acrClash
: AddConceptResult.acrDone;
} else {
return AddConceptResult.acrDone;
}
}
}
@PortedFrom(file = "Reasoner.h", name = "addToDoEntry")
protected boolean addToDoEntry(DlCompletionTree n, int bp, DepSet dep,
String reason) {
if (bp == bpTOP) {
return false;
}
if (bp == bpBOTTOM) {
this.setClashSet(dep);
logNCEntry(n, bp, dep, "x", dlHeap.get(bp).getType().getName());
return true;
}
DLVertex v = dlHeap.get(bp);
DagTag tag = v.getType();
if (tag == DagTag.dtCollection) {
if (bp < 0) {
return false;
}
stats.getnTacticCalls().inc();
DlCompletionTree oldNode = curNode;
int oldConceptConcept = curConceptConcept;
FastSetSimple oldConceptDepSetDelegate = curConceptDepSet
.getDelegate();
curNode = n;
curConceptConcept = bp;
curConceptDepSet = DepSet.create(curConceptDepSet);
boolean ret = commonTacticBodyAnd(v);
curNode = oldNode;
curConceptConcept = oldConceptConcept;
curConceptDepSet = DepSet.create(oldConceptDepSetDelegate);
return ret;
}
switch (tryAddConcept(n.label().getLabel(tag), bp, dep)) {
case acrClash:
logNCEntry(n, bp, dep, "x", dlHeap.get(bp).getType().getName());
return true;
case acrExist:
return false;
case acrDone:
return insertToDoEntry(n, bp, dep, tag, reason);
default:
throw new UnreachableSituationException();
}
}
@PortedFrom(file = "Reasoner.h", name = "insertToDoEntry")
private boolean insertToDoEntry(DlCompletionTree n, int bp, DepSet dep,
DagTag tag, String reason) {
ConceptWDep p = new ConceptWDep(bp, dep);
updateLevel(n, dep);
cGraph.addConceptToNode(n, p, tag);
used.add(bp);
if (n.isCached()) {
return correctCachedEntry(n);
}
TODO.addEntry(n, tag, p);
if (n.isDataNode()) {
return checkDataNode ? hasDataClash(n) : false;
}
logNCEntry(n, bp, dep, "+", reason);
return false;
}
@PortedFrom(file = "Reasoner.h", name = "canBeCached")
private boolean canBeCached(DlCompletionTree node) {
boolean shallow = true;
int size = 0;
// check whether node cache is allowed
if (!options.isUseNodeCache()) {
return false;
}
// nominal nodes can not be cached
if (node.isNominalNode()) {
return false;
}
stats.getnCacheTry().inc();
List<ConceptWDep> list = node.beginl_sc();
for (int i = 0; i < list.size(); i++) {
ConceptWDep p = list.get(i);
if (dlHeap.getCache(p.getConcept()) == null) {
stats.getnCacheFailedNoCache().inc();
options.getLog().printTemplate(Templates.CAN_BE_CACHED,
p.getConcept());
return false;
}
shallow &= dlHeap.getCache(p.getConcept()).shallowCache();
++size;
}
list = node.beginl_cc();
for (int i = 0; i < list.size(); i++) {
ConceptWDep p = list.get(i);
if (dlHeap.getCache(p.getConcept()) == null) {
stats.getnCacheFailedNoCache().inc();
options.getLog().printTemplate(Templates.CAN_BE_CACHED,
p.getConcept());
return false;
}
shallow &= dlHeap.getCache(p.getConcept()).shallowCache();
++size;
}
if (shallow && size != 0) {
stats.getnCacheFailedShallow().inc();
options.getLog().print(" cf(s)");
return false;
}
return true;
}
/**
* build cache of the node (it is known that caching is possible) in
* newNodeCache
*
* @param node
* node
*/
@PortedFrom(file = "Reasoner.h", name = "doCacheNode")
private void doCacheNode(DlCompletionTree node) {
List<DepSet> deps = new ArrayList<DepSet>();
newNodeCache.clear();
List<ConceptWDep> beginl_sc = node.beginl_sc();
for (int i = 0; i < beginl_sc.size(); i++) {
ConceptWDep p = beginl_sc.get(i);
deps.add(p.getDep());
ModelCacheState merge = newNodeCache.merge(dlHeap.getCache(p
.getConcept()));
if (merge != ModelCacheState.csValid) {
if (merge == ModelCacheState.csInvalid) {
this.setClashSet(deps);
}
return;
}
}
List<ConceptWDep> list = node.beginl_cc();
for (int i = 0; i < list.size(); i++) {
ConceptWDep p = list.get(i);
deps.add(p.getDep());
ModelCacheState merge = newNodeCache.merge(dlHeap.getCache(p
.getConcept()));
if (merge != ModelCacheState.csValid) {
if (merge == ModelCacheState.csInvalid) {
this.setClashSet(deps);
}
return;
}
}
// all concepts in label are mergable; now try to add input arc
newNodeEdges.clear();
newNodeEdges.initRolesFromArcs(node);
newNodeCache.merge(newNodeEdges);
}
@PortedFrom(file = "Reasoner.h", name = "reportNodeCached")
private ModelCacheState reportNodeCached(DlCompletionTree node) {
doCacheNode(node);
ModelCacheState status = newNodeCache.getState();
switch (status) {
case csValid:
stats.getnCachedSat().inc();
options.getLog().printTemplate(Templates.REPORT1, node.getId());
break;
case csInvalid:
stats.getnCachedUnsat().inc();
break;
case csFailed:
case csUnknown:
stats.getnCacheFailed().inc();
options.getLog().print(" cf(c)");
status = ModelCacheState.csFailed;
break;
default:
throw new UnreachableSituationException();
}
return status;
}
@PortedFrom(file = "Reasoner.h", name = "correctCachedEntry")
private boolean correctCachedEntry(DlCompletionTree n) {
assert n.isCached();
ModelCacheState status = tryCacheNode(n);
if (status == ModelCacheState.csFailed) {
redoNodeLabel(n, "uc");
}
return status.usageByState();
}
static class DataCall {
DagTag d;
NamedEntry dataEntry;
boolean positive;
ConceptWDep r;
@Override
public int hashCode() {
return ((positive ? 1 : 2) * 37 + d.hashCode()) * 37
+ dataEntry.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (!(obj instanceof DataCall)) {
return false;
}
DataCall o = (DataCall) obj;
return positive == o.positive && d.equals(o.d)
&& dataEntry.equals(o.dataEntry);
}
@Override
public String toString() {
Object o = null;
if (dataEntry instanceof DatatypeEntry) {
o = ((DatatypeEntry) dataEntry).getDatatype();
} else if (dataEntry instanceof LiteralEntry) {
o = ((LiteralEntry) dataEntry).getLiteral();
} else {
o = dataEntry;
}
return positive + ", " + d + ", \""
+ o.toString().replace("\"", "\\\"") + "\", "
+ r.getDep().toString().replace("{", "").replace("}", "");
}
}
// private static int counter = 0;
@PortedFrom(file = "Reasoner.h", name = "hasDataClash")
private boolean hasDataClash(DlCompletionTree node) {
assert node != null && node.isDataNode();
List<ConceptWDep> concepts = node.beginl_sc();
int size = concepts.size();
DataTypeReasoner datatypeReasoner = new DataTypeReasoner(options);
// counter++;
// System.out.print("@Test public void test" + counter +
// "() throws Exception {");
Set<DataCall> calls = new LinkedHashSet<DataCall>();
for (int i = 0; i < size; i++) {
ConceptWDep r = concepts.get(i);
DagTag d = dlHeap.get(r.getConcept()).getType();
NamedEntry dataEntry = dlHeap.get(r.getConcept()).getConcept();
boolean positive = r.getConcept() > 0;
if (dataEntry != null) {
DataCall dc = new DataCall();
dc.d = d;
dc.positive = positive;
dc.dataEntry = dataEntry;
dc.r = r;
calls.add(dc);
}
}
for (DataCall dc : calls) {
// System.out.print(" makeCall( " + dc + ");");
if (datatypeReasoner.addDataEntry(dc.positive, dc.d, dc.dataEntry,
dc.r.getDep())) {
this.setClashSet(datatypeReasoner.getClashSet());
// System.out.println("assertTrue(makeCall( " + dc + "));}");
return true;
}
}
boolean checkClash = datatypeReasoner.checkClash();
// System.out.println("assert" + (checkClash ? "True" : "False") +
// "(datatypeReasoner.checkClash());}");
if (checkClash) {
this.setClashSet(datatypeReasoner.getClashSet());
}
return checkClash;
}
@PortedFrom(file = "Reasoner.h", name = "runSat")
protected boolean runSat() {
testTimer.start();
boolean result = checkSatisfiability();
testTimer.stop();
options.getLog().print("\nChecking time was ")
.print(testTimer.getResultTime()).print(" milliseconds");
testTimer.reset();
finaliseStatistic();
if (result) {
cGraph.print(options.getLog());
}
return result;
}
@PortedFrom(file = "Reasoner.h", name = "finaliseStatistic")
private void finaliseStatistic() {
if (options.isUSE_REASONING_STATISTICS()) {
writeTotalStatistic(options.getLog());
}
cGraph.clearStatistics();
}
@PortedFrom(file = "Reasoner.h", name = "applyReflexiveRoles")
private boolean applyReflexiveRoles(DlCompletionTree node, DepSet dep) {
for (Role p : reflexiveRoles) {
DlCompletionTreeArc pA = cGraph.addRoleLabel(node, node, false, p,
dep);
if (setupEdge(pA, dep, 0)) {
return true;
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "checkSatisfiability")
protected boolean checkSatisfiability() {
int loop = 0;
for (;;) {
if (curNode == null) {
// no applicable rules
if (TODO.isEmpty()) {
// do run-once things
if (performAfterReasoning() && tunedRestore()) {
return false;
}
// if nothing added -- that's it
if (TODO.isEmpty()) {
return true;
}
}
ToDoEntry curTDE = TODO.getNextEntry();
assert curTDE != null;
curNode = curTDE.getNode();
curConceptConcept = curTDE.getOffsetConcept();
curConceptDepSet = DepSet.create(curTDE.getOffsetDepSet());
}
if (++loop == 50) {
loop = 0;
if (tBox.isCancelled().get()) {
return false;
}
if (testTimer.calcDelta() >= options.getTimeOut()) {
throw new TimeOutException();
}
}
if (commonTactic()) {
if (tunedRestore()) {
return false;
}
} else {
curNode = null;
}
}
}
/**
* perform all the actions that should be done once, after all normal rules
* are not applicable.
*
* @return true if the concept is unsat
*/
@PortedFrom(file = "Reasoner.h", name = "performAfterReasoning")
private boolean performAfterReasoning() {
// make sure all blocked nodes are still blocked
logIndentation();
options.getLog().print("ub:");
cGraph.retestCGBlockedStatus();
options.getLog().print("]");
if (!TODO.isEmpty()) {
return false;
}
// check if any split expansion rule could be fired
if (!tBox.getSplits().empty()) {
logIndentation();
options.getLog().print("split:");
boolean clash = checkSplitRules();
options.getLog().print("]");
if (clash) {
return true;
}
if (!TODO.isEmpty()) {
return false;
}
}
// check fairness constraints
if (options.isRKG_USE_FAIRNESS() && tBox.hasFC()) {
DlCompletionTree violator = null;
// for every given FC, if it is violated, reject current model
for (Concept p : tBox.getFairness()) {
violator = cGraph.getFCViolator(p.getpName());
if (violator != null) {
stats.getnFairnessViolations().inc();
// try to fix violators
if (addToDoEntry(violator, p.getpName(), getCurDepSet(),
"fair")) {
return true;
}
}
}
if (!TODO.isEmpty()) {
return false;
}
}
return false;
}
// split code implementation
/**
* apply split rule RULE to a reasoner.
*
* @param rule
* rule
* @return true if clash was found
*/
@PortedFrom(file = "Reasoner.h", name = "applySplitRule")
private boolean applySplitRule(TSplitRule rule) {
DepSet dep = rule.fireDep(SessionSignature, SessionSigDepSet);
int bp = rule.bp() - 1;
// p.bp points to Choose(C) node, p.bp-1 -- to the split node
// split became active
ActiveSplits.add(bp);
// add corresponding choose to all
if (addSessionGCI(bp + 1, dep)) {
return true;
}
// make sure that all existing splits will be re-applied
this.updateName(bp);
return false;
}
/**
* check whether any split rules should be run and do it.
*
* @return true iff clash was found
*/
@PortedFrom(file = "Reasoner.h", name = "checkSplitRules")
private boolean checkSplitRules() {
if (splitRuleLevel == 0) {
// 1st application OR return was made before previous set
ActiveSplits.clear();
SessionSignature.clear();
SessionSigDepSet.clear();
splitRuleLevel = getCurLevel();
}
// fills in session signature for current CGraph. combine dep-sets for
// the same entities
this.updateSessionSignature();
// now for every split expansion rule check whether it can be fired
for (TSplitRule p : tBox.getSplitRules().getRules()) {
if (!ActiveSplits.contains(p.bp() - 1)
&& p.canFire(SessionSignature) && applySplitRule(p)) {
return true;
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "restoreBC")
private void restoreBC() {
curNode = bContext.node;
if (bContext.concept == null) {
curConceptConcept = bpINVALID;
curConceptDepSet = DepSet.create();
} else {
curConceptConcept = bContext.concept.getConcept();
curConceptDepSet = DepSet.create(bContext.concept.getDep());
}
if (!SessionGCIs.isEmpty()) {
resize(SessionGCIs, bContext.SGsize);
}
updateBranchDep();
bContext.nextOption();
}
@PortedFrom(file = "Reasoner.h", name = "save")
protected void save() {
cGraph.save();
TODO.save();
++tryLevel;
bContext = null;
stats.getnStateSaves().inc();
options.getLog().printTemplate(Templates.SAVE, getCurLevel() - 1);
if (options.isDEBUG_SAVE_RESTORE()) {
cGraph.print(options.getLog());
options.getLog().print(TODO);
}
}
@PortedFrom(file = "Reasoner.h", name = "restore")
protected void restore(int newTryLevel) {
assert !stack.isEmpty();
assert newTryLevel > 0;
setCurLevel(newTryLevel);
// update split level
if (getCurLevel() < splitRuleLevel) {
splitRuleLevel = 0;
}
bContext = stack.top(getCurLevel());
restoreBC();
cGraph.restore(getCurLevel());
TODO.restore(getCurLevel());
stats.getnStateRestores().inc();
options.getLog().printTemplate(Templates.RESTORE, getCurLevel());
if (options.isDEBUG_SAVE_RESTORE()) {
cGraph.print(options.getLog());
options.getLog().print(TODO);
}
}
@PortedFrom(file = "Reasoner.h", name = "logIndentation")
private void logIndentation() {
LogAdapter logAdapter = options.getLog();
logAdapter.print("\n");
for (int i = 1; i < getCurLevel(); i++) {
logAdapter.print(' ');
}
logAdapter.print('[');
}
@PortedFrom(file = "Reasoner.h", name = "logStartEntry")
private void logStartEntry() {
if (options.isLoggingActive()) {
logIndentation();
LogAdapter logAdapter = options.getLog();
logAdapter.print("(");
logAdapter.print(curNode.logNode());
logAdapter.print(",");
logAdapter.print(curConceptConcept);
if (curConceptDepSet != null) {
logAdapter.print(curConceptDepSet);
}
logAdapter.print("){");
if (curConceptConcept < 0) {
logAdapter.print("~");
}
DLVertex v = dlHeap.get(curConceptConcept);
logAdapter.print(v.getType());
if (v.getConcept() != null) {
logAdapter.print("(", v.getConcept().getName(), ")");
}
logAdapter.print("}:");
logAdapter.print("}:");
}
}
@PortedFrom(file = "Reasoner.h", name = "logFinishEntry")
private void logFinishEntry(boolean res) {
if (options.isLoggingActive()) {
options.getLog().print("]");
if (res) {
options.getLog().printTemplate(Templates.LOG_FINISH_ENTRY,
clashSet);
}
}
}
/**
* @param o
* o
* @return reasoning time
*/
@PortedFrom(file = "Reasoner.h", name = "printReasoningTime")
public float printReasoningTime(LogAdapter o) {
o.print("\n SAT takes ", satTimer, " seconds\n SUB takes ",
subTimer, " seconds");
return satTimer.calcDelta() + subTimer.calcDelta();
}
/*
* Tactics section; Each Tactic should have a (small) Usability function
* <name> and a Real tactic function <name>Body Each tactic returns: - true
* - if expansion of CUR lead to clash - false - overwise
*/
@PortedFrom(file = "Reasoner.h", name = "commonTactic")
private boolean commonTactic() {
if (curNode.isCached() || curNode.isPBlocked()) {
return false;
}
logStartEntry();
boolean ret = false;
if (!isIBlocked()) {
ret = commonTacticBody(dlHeap.get(curConceptConcept));
}
logFinishEntry(ret);
return ret;
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBody")
private boolean commonTacticBody(DLVertex cur) {
stats.getnTacticCalls().inc();
switch (cur.getType()) {
case dtTop:
throw new UnreachableSituationException();
case dtDataType:
case dtDataValue:
stats.getnUseless().inc();
return false;
case dtPSingleton:
case dtNSingleton:
if (curConceptConcept > 0) {
return commonTacticBodySingleton(cur);
} else {
return commonTacticBodyId(cur);
}
case dtNConcept:
case dtPConcept:
return commonTacticBodyId(cur);
case dtAnd:
if (curConceptConcept > 0) {
return commonTacticBodyAnd(cur);
} else {
return commonTacticBodyOr(cur);
}
case dtForall:
if (curConceptConcept < 0) {
return commonTacticBodySome(cur);
}
return commonTacticBodyAll(cur);
case dtIrr:
if (curConceptConcept < 0) {
return commonTacticBodySomeSelf(cur.getRole());
} else {
return commonTacticBodyIrrefl(cur.getRole());
}
case dtLE:
if (curConceptConcept < 0) {
return commonTacticBodyGE(cur);
}
if (isFunctionalVertex(cur)) {
return commonTacticBodyFunc(cur);
} else {
return commonTacticBodyLE(cur);
}
case dtProj:
assert curConceptConcept > 0;
return commonTacticBodyProj(cur.getRole(),
cur.getConceptIndex(), cur.getProjRole());
case dtSplitConcept:
return commonTacticBodySplit(cur);
case dtChoose:
assert curConceptConcept > 0;
return applyChooseRule(curNode, cur.getConceptIndex());
default:
throw new UnreachableSituationException();
}
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyId")
private boolean commonTacticBodyId(DLVertex cur) {
assert cur.getType().isCNameTag(); // safety check
stats.getnIdCalls().inc();
// check if we have some simple rules
if (options.isRKG_USE_SIMPLE_RULES() && curConceptConcept > 0
&& applyExtraRulesIf((Concept) cur.getConcept())) {
return true;
}
// get either body(p) or inverse(body(p)), depends on sign of current ID
int C = curConceptConcept > 0 ? cur.getConceptIndex() : -cur
.getConceptIndex();
return addToDoEntry(curNode, C, curConceptDepSet, null);
}
/**
* add entity.dep to a session structures
*
* @param entity
* entity
* @param dep
* dep
*/
@PortedFrom(file = "Reasoner.h", name = "updateSessionSignature")
private void updateSessionSignature(NamedEntity entity, DepSet dep) {
if (entity != null) {
SessionSignature.add(entity);
SessionSigDepSet.get(entity).add(dep);
}
}
/**
* update session signature with all names from a given node
*
* @param node
* node
*/
@PortedFrom(file = "Reasoner.h", name = "updateSignatureByNode")
private void updateSignatureByNode(DlCompletionTree node) {
CGLabel lab = node.label();
for (ConceptWDep p : lab.get_sc()) {
this.updateSessionSignature(
tBox.getSplitRules().getEntity(p.getConcept()), p.getDep());
}
}
/** update session signature for all non-data nodes */
@PortedFrom(file = "Reasoner.h", name = "updateSessionSignature")
private void updateSessionSignature() {
int n = 0;
DlCompletionTree node = cGraph.getNode(n++);
while (node != null) {
if (isObjectNodeUnblocked(node)) {
updateSignatureByNode(node);
}
node = cGraph.getNode(n++);
}
}
@PortedFrom(file = "Reasoner.h", name = "applicable")
protected boolean applicable(SimpleRule rule) {
CWDArray lab = curNode.label().getLabel(DagTag.dtPConcept);
DepSet loc = DepSet.create(curConceptDepSet);
for (Concept p : rule.getBody()) {
if (p.getpName() != curConceptConcept) {
if (findConceptClash(lab, p.getpName(), loc)) {
loc.add(clashSet);
} else {
return false;
}
}
}
this.setClashSet(loc);
return true;
}
@PortedFrom(file = "Reasoner.h", name = "applyExtraRules")
private boolean applyExtraRules(Concept C) {
FastSet er_begin = C.getExtraRules();
for (int i = 0; i < er_begin.size(); i++) {
SimpleRule rule = tBox.getSimpleRule(er_begin.get(i));
stats.getnSRuleAdd().inc();
if (rule.applicable(this)) {
// apply the rule's head
stats.getnSRuleFire().inc();
if (addToDoEntry(curNode, rule.getBpHead(), clashSet, null)) {
return true;
}
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodySingleton")
private boolean commonTacticBodySingleton(DLVertex cur) {
// safety check
assert cur.getType() == dtPSingleton || cur.getType() == dtNSingleton;
stats.getnSingletonCalls().inc();
assert hasNominals();
encounterNominal = true;
Individual C = (Individual) cur.getConcept();
assert C.getNode() != null;
DepSet dep = DepSet.create(curConceptDepSet);
// blank nodes are set to be non classifiable and not initialized in
// initNominalCloud
// XXX not sure how it should be fixed, just trying to avoid null
// pointer here
if (C.isNonClassifiable()) {
return true;
}
DlCompletionTree realNode = C.getNode().resolvePBlocker(dep);
if (!realNode.equals(curNode)) {
return merge(curNode, realNode, dep);
}
return commonTacticBodyId(cur);
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyAnd")
private boolean commonTacticBodyAnd(DLVertex cur) {
assert curConceptConcept > 0 && cur.getType() == dtAnd; // safety check
stats.getnAndCalls().inc();
int[] begin = cur.begin();
for (int q : begin) {
if (addToDoEntry(curNode, q, curConceptDepSet, null)) {
return true;
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyOr")
private boolean commonTacticBodyOr(DLVertex cur) {
// safety check
assert curConceptConcept < 0 && cur.getType() == dtAnd;
stats.getnOrCalls().inc();
if (isFirstBranchCall()) {
Reference<DepSet> dep = new Reference<DepSet>(DepSet.create());
if (planOrProcessing(cur, dep)) {
options.getLog().printTemplate(Templates.COMMON_TACTIC_BODY_OR,
orConceptsToTest.get(orConceptsToTest.size() - 1));
return false;
}
if (orConceptsToTest.isEmpty()) {
this.setClashSet(dep.getReference());
return true;
}
if (orConceptsToTest.size() == 1) {
ConceptWDep C = orConceptsToTest.get(0);
return insertToDoEntry(curNode, C.getConcept(),
dep.getReference(), dlHeap.get(C.getConcept())
.getType(), "bcp");
}
createBCOr();
bContext.branchDep = DepSet.create(dep.getReference());
orConceptsToTest = ((BCOr) bContext)
.setApplicableOrEntries(orConceptsToTest);
}
return processOrEntry();
}
@PortedFrom(file = "Reasoner.h", name = "planOrProcessing")
private boolean planOrProcessing(DLVertex cur, Reference<DepSet> dep) {
orConceptsToTest.clear();
dep.setReference(DepSet.create(curConceptDepSet));
// check all OR components for the clash
CGLabel lab = curNode.label();
for (int q : cur.begin()) {
int inverse = -q;
switch (tryAddConcept(lab.getLabel(dlHeap.get(inverse).getType()),
inverse, null)) {
case acrClash:
// clash found -- OK
dep.getReference().add(clashSet);
continue;
case acrExist:
// already have such concept -- save it to the 1st position
orConceptsToTest.clear();
orConceptsToTest.add(new ConceptWDep(-q));
return true;
case acrDone:
orConceptsToTest.add(new ConceptWDep(-q));
continue;
default:
// safety check
throw new UnreachableSituationException();
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "processOrEntry")
private boolean processOrEntry() {
// save the context here as after save() it would be lost
BCOr bcOr = (BCOr) bContext;
String reason = null;
DepSet dep;
if (bcOr.isLastOrEntry()) {
// cumulative dep-set will be used
prepareBranchDep();
dep = getBranchDep();
// no more branching decisions
determiniseBranchingOp();
reason = "bcp";
} else {
// save current state
save();
// new (just branched) dep-set
dep = getCurDepSet();
stats.getnOrBrCalls().inc();
}
// if semantic branching is in use -- add previous entries to the label
if (options.getuseSemanticBranching()) {
for (int i : bcOr.getApplicableOrEntriesConcepts()) {
if (addToDoEntry(curNode, -i, dep, "sb")) {
return true;
// XXX should throw an exception only when debugging, but
// this is hard to figure out
// throw new
// UnreachableSituationException(curNode.toString());
// Both Exists and Clash are errors
}
}
}
// add new entry to current node; we know the result would be DONE
if (options.isRKG_USE_DYNAMIC_BACKJUMPING()) {
return addToDoEntry(curNode, bcOr.orCur().getConcept(), dep, reason);
} else {
return insertToDoEntry(curNode, bcOr.orCur().getConcept(), dep,
dlHeap.get(bcOr.orCur().getConcept()).getType(), reason);
}
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyAllComplex")
private boolean commonTacticBodyAllComplex(DLVertex cur) {
int state = cur.getState();
// corresponds to AR{0}.X
int C = curConceptConcept - state;
RAStateTransitions RST = cur.getRole().getAutomaton().getBase()
.get(state);
// apply all empty transitions
if (RST.hasEmptyTransition()) {
List<RATransition> list = RST.begin();
for (int i = 0; i < list.size(); i++) {
RATransition q = list.get(i);
stats.getnAutoEmptyLookups().inc();
if (q.isEmpty()
&& addToDoEntry(curNode, C + q.final_state(),
curConceptDepSet, "e")) {
return true;
}
}
}
// apply all top-role transitions
if (RST.hasTopTransition()) {
List<RATransition> list = RST.begin();
for (int i = 0; i < list.size(); i++) {
RATransition q = list.get(i);
if (q.isTop()
&& addSessionGCI(C + q.final_state(), curConceptDepSet)) {
return true;
}
}
}
// apply final-state rule
if (state == 1
&& addToDoEntry(curNode, cur.getConceptIndex(),
curConceptDepSet, null)) {
return true;
}
// check whether automaton applicable to any edges
stats.getnAllCalls().inc();
// check all neighbours
List<DlCompletionTreeArc> list = curNode.getNeighbour();
for (int i = 0; i < list.size(); i++) {
DlCompletionTreeArc p = list.get(i);
if (RST.recognise(p.getRole())
&& applyTransitions(p, RST, C,
DepSet.plus(curConceptDepSet, p.getDep()), null)) {
return true;
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyAllSimple")
private boolean commonTacticBodyAllSimple(DLVertex cur) {
RAStateTransitions RST = cur.getRole().getAutomaton().getBase().get(0);
int C = cur.getConceptIndex();
// check whether automaton applicable to any edges
stats.getnAllCalls().inc();
// check all neighbours; as the role is simple then recognise() ==
// applicable()
List<DlCompletionTreeArc> neighbour = curNode.getNeighbour();
int size = neighbour.size();
for (int i = 0; i < size; i++) {
DlCompletionTreeArc p = neighbour.get(i);
if (RST.recognise(p.getRole())
&& addToDoEntry(p.getArcEnd(), C,
DepSet.plus(curConceptDepSet, p.getDep()), null)) {
return true;
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "applyTransitions")
private boolean applyTransitions(DlCompletionTreeArc edge,
RAStateTransitions RST, int C, DepSet dep, String reason) {
Role R = edge.getRole();
DlCompletionTree node = edge.getArcEnd();
// fast lane: the single transition which is applicable
if (RST.isSingleton()) {
return addToDoEntry(node, C + RST.getTransitionEnd(), dep, reason);
}
// try to apply all transitions to edge
List<RATransition> begin = RST.begin();
int size = begin.size();
for (int i = 0; i < size; i++) {
RATransition q = begin.get(i);
stats.getnAutoTransLookups().inc();
if (q.applicable(R)
&& addToDoEntry(node, C + q.final_state(), dep, reason)) {
return true;
}
}
return false;
}
/**
* Perform expansion of (\AR.C).DEP to an EDGE for simple R with a given
* reason
*
* @param Node
* Node
* @param arcSample
* arcSample
* @param dep_
* dep_
* @param flags
* flags
* @return true if clashing
*/
@PortedFrom(file = "Reasoner.h", name = "applyUniversalNR")
private boolean applyUniversalNR(DlCompletionTree Node,
DlCompletionTreeArc arcSample, DepSet dep_, int flags) {
// check whether a flag is set
if (flags == 0) {
return false;
}
Role R = arcSample.getRole();
DepSet dep = DepSet.plus(dep_, arcSample.getDep());
List<ConceptWDep> base = Node.beginl_cc();
int size = base.size();
for (int i = 0; i < size; i++) {
ConceptWDep p = base.get(i);
// need only AR.C concepts where ARC is labelled with R
if (p.getConcept() < 0) {
continue;
}
DLVertex v = dlHeap.get(p.getConcept());
Role vR = v.getRole();
switch (v.getType()) {
case dtIrr:
if ((flags & redoIrr.getValue()) > 0
&& this.checkIrreflexivity(arcSample, vR, dep)) {
return true;
}
break;
case dtForall:
if ((flags & redoForall.getValue()) == 0) {
break;
}
if (vR.isTop()) {
break;
}
/** check whether transition is possible */
RAStateTransitions RST = vR.getAutomaton().getBase()
.get(v.getState());
if (!RST.recognise(R)) {
break;
}
if (vR.isSimple()) {
// R is recognised so just add the state!
if (addToDoEntry(arcSample.getArcEnd(),
v.getConceptIndex(),
DepSet.plus(dep, p.getDep()), "ae")) {
return true;
}
} else {
if (applyTransitions(arcSample, RST,
p.getConcept() - v.getState(),
DepSet.plus(dep, p.getDep()), "ae")) {
return true;
}
}
break;
case dtLE:
if (isFunctionalVertex(v)) {
if ((flags & redoFunc.getValue()) > 0
&& R.lesserequal(vR)) {
addExistingToDoEntry(Node, p, "f");
}
} else if ((flags & redoAtMost.getValue()) > 0
&& R.lesserequal(vR)) {
addExistingToDoEntry(Node, p, "le");
}
break;
default:
break;
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodySome")
private boolean commonTacticBodySome(DLVertex cur) {
Role R = cur.getRole();
int C = -cur.getConceptIndex();
if (R.isTop()) {
return commonTacticBodySomeUniv(cur);
}
if (isSomeExists(R, C)) {
return false;
}
if (C < 0 && dlHeap.get(C).getType() == dtAnd) {
for (int q : dlHeap.get(C).begin()) {
if (isSomeExists(R, -q)) {
return false;
}
}
}
if (C > 0 && tBox.testHasNominals()) {
DLVertex nom = dlHeap.get(C);
if (nom.getType() == dtPSingleton || nom.getType() == dtNSingleton) {
return commonTacticBodyValue(R, (Individual) nom.getConcept());
}
}
stats.getnSomeCalls().inc();
if (R.isFunctional()) {
List<Role> list = R.begin_topfunc();
for (int i = 0; i < list.size(); i++) {
int functional = list.get(i).getFunctional();
switch (tryAddConcept(curNode.label().getLabel(DagTag.dtLE),
functional, curConceptDepSet)) {
case acrClash:
return true;
case acrDone:
updateLevel(curNode, curConceptDepSet);
ConceptWDep rFuncRestriction1 = new ConceptWDep(
functional, curConceptDepSet);
cGraph.addConceptToNode(curNode, rFuncRestriction1,
DagTag.dtLE);
used.add(rFuncRestriction1.getConcept());
options.getLog().printTemplate(
Templates.COMMON_TACTIC_BODY_SOME,
rFuncRestriction1);
break;
case acrExist:
break;
default:
throw new UnreachableSituationException();
}
}
}
boolean rFunc = false;
Role RF = R;
ConceptWDep rFuncRestriction = null;
List<ConceptWDep> list = curNode.beginl_cc();
for (int i = 0; i < list.size(); i++) {
ConceptWDep LC = list.get(i);
DLVertex ver = dlHeap.get(LC.getConcept());
if (LC.getConcept() > 0 && isFunctionalVertex(ver)
&& R.lesserequal(ver.getRole())
&& (!rFunc || RF.lesserequal(ver.getRole()))) {
rFunc = true;
RF = ver.getRole();
rFuncRestriction = LC;
}
}
if (rFunc) {
DlCompletionTreeArc functionalArc = null;
DepSet newDep = DepSet.create();
for (int i = 0; i < curNode.getNeighbour().size()
&& functionalArc == null; i++) {
DlCompletionTreeArc pr = curNode.getNeighbour().get(i);
if (pr.isNeighbour(RF, newDep)) {
functionalArc = pr;
}
}
if (functionalArc != null) {
options.getLog().printTemplate(
Templates.COMMON_TACTIC_BODY_SOME2, rFuncRestriction);
DlCompletionTree succ = functionalArc.getArcEnd();
newDep.add(curConceptDepSet);
if (R.isDisjoint()
&& checkDisjointRoleClash(curNode, succ, R, newDep)) {
return true;
}
functionalArc = cGraph.addRoleLabel(curNode, succ,
functionalArc.isPredEdge(), R, newDep);
// adds concept to the end of arc
if (addToDoEntry(succ, C, newDep, null)) {
return true;
}
// if new role label was added...
if (!RF.equals(R)) {
// add Range and Domain of a new role; this includes
// functional, so remove it from the latter
if (initHeadOfNewEdge(curNode, R, newDep, "RD")) {
return true;
}
if (initHeadOfNewEdge(succ, R.inverse(), newDep, "RR")) {
return true;
}
/**
* check AR.C in both sides of functionalArc FIXME!! for
* simplicity, check the functionality here (see bEx017). It
* seems only necessary when R has several functional
* super-roles, so the condition can be simplified
*/
if (applyUniversalNR(curNode, functionalArc, newDep,
redoForall.getValue() | redoFunc.getValue())) {
return true;
}
/**
* if new role label was added to a functionalArc, some
* functional restrictions in the SUCC node might became
* applicable. See bFunctional1x test
*/
if (applyUniversalNR(succ, functionalArc.getReverse(),
newDep, redoForall.getValue() | redoFunc.getValue()
| redoAtMost.getValue())) {
return true;
}
}
return false;
}
}
return createNewEdge(cur.getRole(), C, Redo.redoForall.getValue()
| Redo.redoAtMost.getValue());
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyValue")
private boolean commonTacticBodyValue(Role R, Individual nom) {
DepSet dep = DepSet.create(curConceptDepSet);
if (isCurNodeBlocked()) {
return false;
}
stats.getnSomeCalls().inc();
assert nom.getNode() != null;
DlCompletionTree realNode = nom.getNode().resolvePBlocker(dep);
if (R.isDisjoint() && checkDisjointRoleClash(curNode, realNode, R, dep)) {
return true;
}
encounterNominal = true;
DlCompletionTreeArc edge = cGraph.addRoleLabel(curNode, realNode,
false, R, dep);
// add all necessary concepts to both ends of the edge
return setupEdge(edge, dep, redoForall.getValue() | redoFunc.getValue()
| redoAtMost.getValue() | redoIrr.getValue());
}
/**
* expansion rule for the existential quantifier with universal role
*
* @param cur
* cur
* @return true if clashing
*/
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodySomeUniv")
private boolean commonTacticBodySomeUniv(DLVertex cur) {
// check blocking conditions
if (isCurNodeBlocked()) {
return false;
}
stats.getnSomeCalls().inc();
int C = -cur.getConceptIndex();
// check whether C is already in CGraph
int i = 0;
DlCompletionTree node;
while ((node = cGraph.getNode(i++)) != null) {
if (isObjectNodeUnblocked(node) && node.label().contains(C)) {
return false;
}
}
// make new node labelled with C
node = cGraph.getNewNode();
return initNewNode(node, curConceptDepSet, C);
}
@PortedFrom(file = "Reasoner.h", name = "createNewEdge")
private boolean createNewEdge(Role R, int C, int flags) {
if (isCurNodeBlocked()) {
stats.getnUseless().inc();
return false;
}
DlCompletionTreeArc pA = this.createOneNeighbour(R, curConceptDepSet);
// add necessary label
return initNewNode(pA.getArcEnd(), curConceptDepSet, C)
|| setupEdge(pA, curConceptDepSet, flags);
}
@PortedFrom(file = "Reasoner.h", name = "createOneNeighbour")
private DlCompletionTreeArc createOneNeighbour(Role R, DepSet dep) {
return this
.createOneNeighbour(R, dep, DlCompletionTree.BLOCKABLE_LEVEL);
}
@PortedFrom(file = "Reasoner.h", name = "createOneNeighbour")
private DlCompletionTreeArc
createOneNeighbour(Role R, DepSet dep, int level) {
boolean forNN = level != DlCompletionTree.BLOCKABLE_LEVEL;
DlCompletionTreeArc pA = cGraph.createNeighbour(curNode, forNN, R, dep);
DlCompletionTree node = pA.getArcEnd();
if (forNN) {
node.setNominalLevel(level);
}
if (R.isDataRole()) {
node.setDataNode();
}
options.getLog()
.printTemplate(R.isDataRole() ? Templates.DN : Templates.CN,
node.getId(), dep);
return pA;
}
/**
* check whether current node is blocked
*
* @return true if blocked
*/
@PortedFrom(file = "Reasoner.h", name = "isCurNodeBlocked")
private boolean isCurNodeBlocked() {
if (!options.getuseLazyBlocking()) {
return curNode.isBlocked();
}
if (!curNode.isBlocked() && curNode.isAffected()) {
updateLevel(curNode, curConceptDepSet);
cGraph.detectBlockedStatus(curNode);
}
return curNode.isBlocked();
}
@PortedFrom(file = "Reasoner.h", name = "applyAllGeneratingRules")
private void applyAllGeneratingRules(DlCompletionTree node) {
List<ConceptWDep> base = node.label().get_cc();
for (int i = 0; i < base.size(); i++) {
ConceptWDep p = base.get(i);
if (p.getConcept() <= 0) {
DLVertex v = dlHeap.get(p.getConcept());
if (v.getType() == dtLE || v.getType() == dtForall) {
addExistingToDoEntry(node, p, "ubd");
}
}
}
}
/**
* @param pA
* pA
* @param dep
* dep
* @param flags
* flags
* @return false if all done
*/
@PortedFrom(file = "Reasoner.h", name = "setupEdge")
public boolean setupEdge(DlCompletionTreeArc pA, DepSet dep, int flags) {
DlCompletionTree child = pA.getArcEnd();
DlCompletionTree from = pA.getReverse().getArcEnd();
// adds Range and Domain
if (initHeadOfNewEdge(from, pA.getRole(), dep, "RD")) {
return true;
}
if (initHeadOfNewEdge(child, pA.getReverse().getRole(), dep, "RR")) {
return true;
}
// check if we have any AR.X concepts in current node
if (applyUniversalNR(from, pA, dep, flags)) {
return true;
}
// for nominal children and loops -- just apply things for the inverses
if (pA.isPredEdge() || child.isNominalNode() || child.equals(from)) {
if (applyUniversalNR(child, pA.getReverse(), dep, flags)) {
return true;
}
} else {
if (child.isDataNode()) {
checkDataNode = true;
if (hasDataClash(child)) {
return true;
}
} else {
// check if it is possible to use cache for new node
if (tryCacheNode(child).usageByState()) {
return true;
}
}
}
// all done
return false;
}
/**
* add necessary concepts to the head of the new EDGE
*
* @param node
* node
* @param R
* R
* @param dep
* dep
* @param reason
* reason
* @return true if clashing
*/
@PortedFrom(file = "Reasoner.h", name = "initHeadOfNewEdge")
private boolean initHeadOfNewEdge(DlCompletionTree node, Role R,
DepSet dep, String reason) {
// if R is functional, then add FR with given DEP-set to NODE
if (R.isFunctional()) {
List<Role> begin_topfunc = R.begin_topfunc();
int size = begin_topfunc.size();
for (int i = 0; i < size; i++) {
if (addToDoEntry(node, begin_topfunc.get(i).getFunctional(),
dep, "fr")) {
return true;
}
}
}
// setup Domain for R
if (addToDoEntry(node, R.getBPDomain(), dep, reason)) {
return true;
}
if (!options.isRKG_UPDATE_RND_FROM_SUPERROLES()) {
List<Role> list = R.getAncestor();
for (int i = 0; i < list.size(); i++) {
Role q = list.get(i);
if (addToDoEntry(node, q.getBPDomain(), dep, reason)) {
return true;
}
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyFunc")
private boolean commonTacticBodyFunc(DLVertex cur) {
assert curConceptConcept > 0 && isFunctionalVertex(cur);
if (cur.getRole().isTop()) {
return processTopRoleFunc(cur);
}
if (isNNApplicable(cur.getRole(), bpTOP, curConceptConcept + 1)) {
return commonTacticBodyNN(cur);
}
stats.getnFuncCalls().inc();
if (isQuickClashLE(cur)) {
return true;
}
findNeighbours(cur.getRole(), bpTOP, null);
if (EdgesToMerge.size() < 2) {
return false;
}
DlCompletionTreeArc q = EdgesToMerge.get(0);
DlCompletionTree sample = q.getArcEnd();
DepSet depF = DepSet.create(curConceptDepSet);
depF.add(q.getDep());
for (int i = 1; i < EdgesToMerge.size(); i++) {
q = EdgesToMerge.get(i);
if (!q.getArcEnd().isPBlocked()
&& merge(q.getArcEnd(), sample,
DepSet.plus(depF, q.getDep()))) {
return true;
}
}
return false;
}
@SuppressWarnings("unchecked")
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyLE")
private boolean commonTacticBodyLE(DLVertex cur) // for <=nR.C concepts
{
assert curConceptConcept > 0 && cur.getType() == dtLE;
stats.getnLeCalls().inc();
Role R = cur.getRole();
if (R.isTop()) {
return processTopRoleLE(cur);
}
int C = cur.getConceptIndex();
boolean needInit = true;
if (!isFirstBranchCall()) {
if (bContext instanceof BCNN) {
return commonTacticBodyNN(cur);
// after application <=-rule would be checked again
}
if (bContext instanceof BCLE) {
needInit = false;
// clash in LE-rule: skip the initial checks
} else {
assert bContext instanceof BCChoose;
}
} else {
// if we are here that it IS first LE call
if (isQuickClashLE(cur)) {
return true;
}
}
// initial phase: choose-rule, NN-rule
if (needInit) {
// check if we have Qualified NR
if (C != bpTOP && commonTacticBodyChoose(R, C)) {
return true;
}
// check whether we need to apply NN rule first
if (isNNApplicable(R, C, curConceptConcept + cur.getNumberLE())) {
return commonTacticBodyNN(cur);
// after application <=-rule would be checked again
}
}
// we need to repeat merge until there will be necessary amount of edges
while (true) {
if (isFirstBranchCall() && initLEProcessing(cur)) {
return false;
}
BCLE<DlCompletionTreeArc> bcLE = (BCLE<DlCompletionTreeArc>) bContext;
if (bcLE.noMoreLEOptions()) {
// set global clashset to cumulative
// one from previous branch failures
useBranchDep();
return true;
}
// get from- and to-arcs using corresponding indexes in Edges
DlCompletionTreeArc fromArc = bcLE.getFrom();
DlCompletionTreeArc toArc = bcLE.getTo();
DlCompletionTree from = fromArc.getArcEnd();
DlCompletionTree to = toArc.getArcEnd();
Reference<DepSet> dep = new Reference<DepSet>(DepSet.create());
// empty dep-set
// fast check for FROM =/= TO
if (cGraph.nonMergable(from, to, dep)) {
// need this for merging two nominal nodes
dep.getReference().add(fromArc.getDep());
dep.getReference().add(toArc.getDep());
// add dep-set from labels
if (C == bpTOP) {
setClashSet(dep.getReference());
} else {
// QCR: update dep-set wrt C
// here we know that C is in both labels; set a proper
// clash-set
DagTag tag = dlHeap.get(C).getType();
boolean test;
// here dep contains the clash-set
test = findConceptClash(from.label().getLabel(tag), C,
dep.getReference());
assert test;
// save new dep-set
dep.getReference().add(clashSet);
test = findConceptClash(to.label().getLabel(tag), C,
dep.getReference());
assert test;
// both clash-sets are now in common clash-set
}
updateBranchDep();
bContext.nextOption();
assert !isFirstBranchCall();
continue;
}
save();
// add depset from current level and FROM arc and to current dep.set
DepSet curDep = DepSet.create(getCurDepSet());
curDep.add(fromArc.getDep());
if (merge(from, to, curDep)) {
return true;
}
/**
* it might be the case (see bIssue28) that after the merge there is
* an R-neigbour that have neither C or ~C in its label (it was far
* in the nominal cloud)
*/
if (C != bpTOP && commonTacticBodyChoose(R, C)) {
return true;
}
}
}
@SuppressWarnings("unchecked")
@PortedFrom(file = "Reasoner.h", name = "initLEProcessing")
private boolean initLEProcessing(DLVertex cur) {
DepSet dep = DepSet.create();
// check the amount of neighbours we have
findNeighbours(cur.getRole(), cur.getConceptIndex(), dep);
// if the number of R-neighbours satisfies condition -- nothing to do
if (EdgesToMerge.size() <= cur.getNumberLE()) {
return true;
}
// init context
createBCLE();
bContext.branchDep.add(dep);
// setup BCLE
BCLE<DlCompletionTreeArc> bcLE = (BCLE<DlCompletionTreeArc>) bContext;
EdgesToMerge = bcLE.swap(EdgesToMerge);
bcLE.resetMCI();
return false;
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyGE")
private boolean commonTacticBodyGE(DLVertex cur) {
// for >=nR.C concepts
assert curConceptConcept < 0 && cur.getType() == dtLE;
// check blocking conditions
if (isCurNodeBlocked()) {
return false;
}
Role R = cur.getRole();
if (R.isTop()) {
return processTopRoleGE(cur);
}
stats.getnGeCalls().inc();
if (isQuickClashGE(cur)) {
return true;
}
// create N new different edges
return createDifferentNeighbours(cur.getRole(), cur.getConceptIndex(),
curConceptDepSet, cur.getNumberGE(),
DlCompletionTree.BLOCKABLE_LEVEL);
}
// Func/LE/GE with top role processing
@PortedFrom(file = "Reasoner.h", name = "processTopRoleFunc")
private boolean processTopRoleFunc(DLVertex cur) {
// for <=1 R concepts
assert curConceptConcept > 0 && isFunctionalVertex(cur);
stats.getnFuncCalls().inc();
if (isQuickClashLE(cur)) {
return true;
}
// locate all R-neighbours of curNode
// not used
DepSet dummy = DepSet.create();
findCLabelledNodes(bpTOP, dummy);
// check if we have nodes to merge
if (NodesToMerge.size() < 2) {
return false;
}
// merge all nodes to the first (the least wrt nominal hierarchy) found
// node
DlCompletionTree sample = NodesToMerge.get(0);
DepSet dep = DepSet.create(curConceptDepSet); // dep-set for merging
// merge all elements to sample (sample wouldn't be merge)
for (int i = 0; i < NodesToMerge.size(); i++) {
// during merge EdgesToMerge may became purged (see Nasty4) => check
// this
if (!NodesToMerge.get(i).isPBlocked()
&& merge(NodesToMerge.get(i), sample, dep)) {
return true;
}
}
return false;
}
@SuppressWarnings("unchecked")
@PortedFrom(file = "Reasoner.h", name = "processTopRoleLE")
private boolean processTopRoleLE(DLVertex cur) {
// for <=nR.C concepts
assert curConceptConcept > 0 && cur.getType() == dtLE;
int C = cur.getConceptIndex();
boolean needInit = true;
if (!isFirstBranchCall()) {
if (bContext instanceof BCLE) {
// clash in LE-rule: skip the initial checks
needInit = false;
} else {
assert bContext instanceof BCChoose;
}
} else {
// if we are here that it IS first LE call
if (isQuickClashLE(cur)) {
return true;
}
}
// initial phase: choose-rule, NN-rule
// check if we have Qualified NR
if (needInit && C != bpTOP && applyChooseRuleGlobally(C)) {
return true;
}
// we need to repeat merge until there will be necessary amount of edges
while (true) {
if (isFirstBranchCall() && initTopLEProcessing(cur)) {
return false;
}
BCLE<DlCompletionTree> bcLE = (BCLE<DlCompletionTree>) bContext;
if (bcLE.noMoreLEOptions()) {
// set global clashset to cumulative
// one from previous branch failures
useBranchDep();
return true;
}
// get from- and to-arcs using corresponding indexes in Edges
DlCompletionTree from = bcLE.getFrom();
DlCompletionTree to = bcLE.getTo();
Reference<DepSet> dep = new Reference<DepSet>(DepSet.create());
// fast check for FROM =/= TO
if (cGraph.nonMergable(from, to, dep)) {
// add dep-set from labels
if (C == bpTOP) {
setClashSet(dep.getReference());
} else {
// QCR: update dep-set wrt C
// here we know that C is in both labels; set a proper
// clash-set
DagTag tag = dlHeap.get(C).getType();
boolean test;
// here dep contains the clash-set
test = findConceptClash(from.label().getLabel(tag), C,
dep.getReference());
assert test;
// save new dep-set
dep.getReference().add(clashSet);
test = findConceptClash(to.label().getLabel(tag), C,
dep.getReference());
assert test;
// both clash-sets are now in common clash-set
}
updateBranchDep();
bContext.nextOption();
assert !isFirstBranchCall();
continue;
}
save();
// add depset from current level and FROM arc and to current dep.set
DepSet curDep = DepSet.create(getCurDepSet());
if (merge(from, to, curDep)) {
return true;
}
}
}
// for >=nR.C concepts
@PortedFrom(file = "Reasoner.h", name = "processTopRoleGE")
private boolean processTopRoleGE(DLVertex cur) {
assert curConceptConcept < 0 && cur.getType() == dtLE;
assert !isCurNodeBlocked();
stats.getnGeCalls().inc();
if (isQuickClashGE(cur)) {
return true;
}
// create N new different edges
// FIXME!! for now
return createDifferentNeighbours(cur.getRole(), cur.getConceptIndex(),
curConceptDepSet, cur.getNumberGE(),
DlCompletionTree.BLOCKABLE_LEVEL);
}
@SuppressWarnings("unchecked")
@PortedFrom(file = "Reasoner.h", name = "initTopLEProcessing")
private boolean initTopLEProcessing(DLVertex cur) {
DepSet dep = DepSet.create();
// check the amount of neighbours we have
findCLabelledNodes(cur.getConceptIndex(), dep);
// if the number of R-neighbours satisfies condition -- nothing to do
if (NodesToMerge.size() <= cur.getNumberLE()) {
return true;
}
// init context
createBCTopLE();
bContext.branchDep.add(dep);
// setup BCLE
BCLE<DlCompletionTree> bcLE = (BCLE<DlCompletionTree>) bContext;
NodesToMerge = bcLE.swap(NodesToMerge);
bcLE.resetMCI();
return false;
}
@PortedFrom(file = "Reasoner.h", name = "createDifferentNeighbours")
private boolean createDifferentNeighbours(Role R, int C, DepSet dep, int n,
int level) {
DlCompletionTreeArc pA = null;
cGraph.initIR();
for (int i = 0; i < n; ++i) {
pA = this.createOneNeighbour(R, dep, level);
DlCompletionTree child = pA.getArcEnd();
cGraph.setCurIR(child, dep);
// add necessary new node labels and setup new edge
if (initNewNode(child, dep, C)) {
return true;
}
if (setupEdge(pA, dep, redoForall.getValue())) {
return true;
}
}
cGraph.finiIR();
// re-apply all <= NR in curNode; do it only once for all created nodes;
// no need for Irr
return applyUniversalNR(curNode, pA, dep, redoFunc.getValue()
| redoAtMost.getValue());
}
@PortedFrom(file = "Reasoner.h", name = "isNRClash")
private boolean isNRClash(DLVertex atleast, DLVertex atmost,
ConceptWDep reason) {
if (atmost.getType() != DagTag.dtLE || atleast.getType() != DagTag.dtLE) {
return false;
}
if (!checkNRclash(atleast, atmost)) {
return false;
}
this.setClashSet(DepSet.plus(curConceptDepSet, reason.getDep()));
logNCEntry(curNode, reason.getConcept(), reason.getDep(), "x", dlHeap
.get(reason.getConcept()).getType().getName());
return true;
}
@PortedFrom(file = "Reasoner.h", name = "checkMergeClash")
private boolean checkMergeClash(CGLabel from, CGLabel to, DepSet dep,
int nodeId) {
DepSet clashDep = DepSet.create(dep);
boolean clash = false;
List<ConceptWDep> list = from.get_sc();
int size = list.size();
for (int i = 0; i < size; i++) {
ConceptWDep p = list.get(i);
int inverse = -p.getConcept();
if (used.contains(inverse)
&& findConceptClash(to.getLabel(dtPConcept), inverse,
p.getDep())) {
clash = true;
clashDep.add(clashSet);
options.getLog().printTemplate(Templates.CHECK_MERGE_CLASH,
nodeId, p.getConcept(), DepSet.plus(clashSet, dep));
}
}
list = from.get_cc();
int ccsize = list.size();
for (int i = 0; i < ccsize; i++) {
ConceptWDep p = list.get(i);
int inverse = -p.getConcept();
if (used.contains(inverse)
&& findConceptClash(to.getLabel(dtForall), inverse,
p.getDep())) {
clash = true;
clashDep.add(clashSet);
options.getLog().printTemplate(Templates.CHECK_MERGE_CLASH,
nodeId, p.getConcept(), DepSet.plus(clashSet, dep));
}
}
if (clash) {
this.setClashSet(clashDep);
}
return clash;
}
@PortedFrom(file = "Reasoner.h", name = "mergeLabels")
private boolean mergeLabels(CGLabel from, DlCompletionTree to, DepSet dep) {
CGLabel lab = to.label();
CWDArray sc = lab.getLabel(dtPConcept);
CWDArray cc = lab.getLabel(dtForall);
if (!dep.isEmpty()) {
cGraph.saveRareCond(sc.updateDepSet(dep));
cGraph.saveRareCond(cc.updateDepSet(dep));
}
List<ConceptWDep> list = from.get_sc();
for (int i = 0; i < list.size(); i++) {
ConceptWDep p = list.get(i);
int bp = p.getConcept();
stats.getnLookups().inc();
int index = sc.index(bp);
if (index > -1) {
if (!p.getDep().isEmpty()) {
cGraph.saveRareCond(sc.updateDepSet(index, p.getDep()));
}
} else {
if (insertToDoEntry(to, bp, DepSet.plus(dep, p.getDep()),
dlHeap.get(bp).getType(), "M")) {
return true;
}
}
}
list = from.get_cc();
for (int i = 0; i < list.size(); i++) {
ConceptWDep p = list.get(i);
int bp = p.getConcept();
stats.getnLookups().inc();
int index = cc.index(bp);
if (index > -1) {
if (!p.getDep().isEmpty()) {
cGraph.saveRareCond(cc.updateDepSet(index, p.getDep()));
}
} else {
if (insertToDoEntry(to, bp, DepSet.plus(dep, p.getDep()),
dlHeap.get(bp).getType(), "M")) {
return true;
}
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "merge")
private boolean merge(DlCompletionTree from, DlCompletionTree to,
DepSet depF) {
assert !from.isPBlocked();
assert !from.equals(to);
assert to.getNominalLevel() <= from.getNominalLevel();
options.getLog().printTemplate(Templates.MERGE, from.getId(),
to.getId());
stats.getnMergeCalls().inc();
DepSet dep = DepSet.create(depF);
Reference<DepSet> ref = new Reference<DepSet>(dep);
if (cGraph.nonMergable(from, to, ref)) {
this.setClashSet(ref.getReference());
return true;
}
if (checkMergeClash(from.label(), to.label(), depF, to.getId())) {
return true;
}
// copy all node labels
if (mergeLabels(from.label(), to, depF)) {
return true;
}
List<DlCompletionTreeArc> edges = new ArrayList<DlCompletionTreeArc>();
cGraph.merge(from, to, depF, edges);
int size = edges.size();
for (int i = 0; i < size; i++) {
DlCompletionTreeArc q = edges.get(i);
if (q.getRole().isDisjoint()
&& checkDisjointRoleClash(q.getReverse().getArcEnd(),
q.getArcEnd(), q.getRole(), depF)) {
// XXX dubious
return true;
}
}
if (to.isDataNode()) {
return hasDataClash(to);
}
for (DlCompletionTreeArc q : edges) {
if (applyUniversalNR(
to,
q,
depF,
redoForall.getValue() | redoFunc.getValue()
| redoAtMost.getValue() | redoIrr.getValue())) {
return true;
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "checkDisjointRoleClash")
protected boolean checkDisjointRoleClash(DlCompletionTree from,
DlCompletionTree to, Role R, DepSet dep) {
for (DlCompletionTreeArc p : from.getNeighbour()) {
if (checkDisjointRoleClash(p, to, R, dep)) {
return true;
}
}
return false;
}
@PortedFrom(file = "Tactic.cpp", name = "isNewEdge")
private static boolean isNewEdge(DlCompletionTree node,
List<DlCompletionTreeArc> e) {
int size = e.size();
for (int i = 0; i < size; i++) {
if (e.get(i).getArcEnd().equals(node)) {
return false;
}
}
return true;
}
@PortedFrom(file = "Reasoner.h", name = "findNeighbours")
private void findNeighbours(Role Role, int c, DepSet Dep) {
EdgesToMerge.clear();
DagTag tag = dlHeap.get(c).getType();
List<DlCompletionTreeArc> neighbour = curNode.getNeighbour();
int size = neighbour.size();
for (int i = 0; i < size; i++) {
DlCompletionTreeArc p = neighbour.get(i);
if (p.isNeighbour(Role)
&& isNewEdge(p.getArcEnd(), EdgesToMerge)
&& findChooseRuleConcept(p.getArcEnd().label()
.getLabel(tag), c, Dep)) {
EdgesToMerge.add(p);
}
}
Collections.sort(EdgesToMerge, new EdgeCompare());
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyChoose")
private boolean commonTacticBodyChoose(Role R, int C) {
List<DlCompletionTreeArc> neighbour = curNode.getNeighbour();
int size = neighbour.size();
for (int i = 0; i < size; i++) {
DlCompletionTreeArc p = neighbour.get(i);
if (p.isNeighbour(R) && applyChooseRule(p.getArcEnd(), C)) {
return true;
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "applyChooseRule")
private boolean applyChooseRule(DlCompletionTree node, int C) {
if (node.isLabelledBy(C) || node.isLabelledBy(-C)) {
return false;
}
if (isFirstBranchCall()) {
createBCCh();
save();
return addToDoEntry(node, -C, getCurDepSet(), "cr0");
} else {
prepareBranchDep();
DepSet dep = DepSet.create(getBranchDep());
determiniseBranchingOp();
return addToDoEntry(node, C, dep, "cr1");
}
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyNN")
private boolean commonTacticBodyNN(DLVertex cur) {
stats.getnNNCalls().inc();
if (isFirstBranchCall()) {
createBCNN();
}
BCNN bcNN = (BCNN) bContext;
if (bcNN.noMoreNNOptions(cur.getNumberLE())) {
useBranchDep();
return true;
}
int NN = bcNN.getBranchIndex();
save();
// new (just branched) dep-set
DepSet curDep = getCurDepSet();
// make a stopper to mark that NN-rule is applied
if (addToDoEntry(curNode, curConceptConcept + cur.getNumberLE(),
DepSet.create(), "NNs")) {
return true;
}
// create curNN new different edges
if (createDifferentNeighbours(cur.getRole(), cur.getConceptIndex(),
curDep, NN, curNode.getNominalLevel() + 1)) {
return true;
}
// now remember NR we just created: it is (<= curNN R), so have to find
// it
return addToDoEntry(curNode,
curConceptConcept + cur.getNumberLE() - NN, curDep, "NN");
}
@PortedFrom(file = "Reasoner.h", name = "isNNApplicable")
protected boolean isNNApplicable(Role r, int C, int stopper) {
// NN rule is only applicable to nominal nodes
if (!curNode.isNominalNode()) {
return false;
}
// check whether the NN-rule was already applied here for a given
// concept
if (used.contains(stopper) && curNode.isLabelledBy(stopper)) {
return false;
}
// check for the real applicability of the NN-rule here
for (DlCompletionTreeArc p : curNode.getNeighbour()) {
DlCompletionTree suspect = p.getArcEnd();
// if there is an edge that require to run the rule, then we need it
if (p.isPredEdge() && suspect.isBlockableNode() && p.isNeighbour(r)
&& suspect.isLabelledBy(C)) {
options.getLog().print(" NN(").print(suspect.getId())
.print(")");
return true;
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodySomeSelf")
private boolean commonTacticBodySomeSelf(Role R) {
if (isCurNodeBlocked()) {
return false;
}
for (DlCompletionTreeArc p : curNode.getNeighbour()) {
if (p.getArcEnd().equals(curNode) && p.isNeighbour(R)) {
return false;
}
}
DepSet dep = DepSet.create(curConceptDepSet);
DlCompletionTreeArc pA = cGraph.createLoop(curNode, R, dep);
return setupEdge(pA, dep, redoForall.getValue() | redoFunc.getValue()
| redoAtMost.getValue() | redoIrr.getValue());
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyIrrefl")
private boolean commonTacticBodyIrrefl(Role R) {
for (DlCompletionTreeArc p : curNode.getNeighbour()) {
if (this.checkIrreflexivity(p, R, curConceptDepSet)) {
return true;
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodyProj")
private boolean commonTacticBodyProj(Role R, int C, Role ProjR) {
if (curNode.isLabelledBy(-C)) {
return false;
}
// checkProjection() might change curNode's edge vector and thusly
// invalidate iterators
for (int i = 0; i < curNode.getNeighbour().size(); i++) {
if (curNode.getNeighbour().get(i).isNeighbour(R)
&& checkProjection(curNode.getNeighbour().get(i), C, ProjR)) {
return true;
}
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "checkProjection")
private boolean checkProjection(DlCompletionTreeArc pA, int C, Role ProjR) {
if (pA.isNeighbour(ProjR)) {
return false;
}
if (curNode.isLabelledBy(-C)) {
return false;
}
DepSet dep = DepSet.create(curConceptDepSet);
dep.add(pA.getDep());
if (!curNode.isLabelledBy(C)) {
if (isFirstBranchCall()) {
createBCCh();
save();
return addToDoEntry(curNode, -C, getCurDepSet(), "cr0");
} else {
prepareBranchDep();
dep.add(getBranchDep());
determiniseBranchingOp();
if (addToDoEntry(curNode, C, dep, "cr1")) {
return true;
}
}
}
DlCompletionTree child = pA.getArcEnd();
return setupEdge(cGraph.addRoleLabel(curNode, child, pA.isPredEdge(),
ProjR, dep), dep, redoForall.getValue() | redoFunc.getValue()
| redoAtMost.getValue() | redoIrr.getValue());
}
/** create BC for LE-rule */
@PortedFrom(file = "Reasoner.h", name = "createBCTopLE")
public void createBCTopLE() {
bContext = stack.pushTopLE();
initBC(bContext);
}
/**
* expansion rule for split
*
* @param cur
* cur
* @return true if clashing
*/
@PortedFrom(file = "Reasoner.h", name = "commonTacticBodySplit")
private boolean commonTacticBodySplit(DLVertex cur) {
if (tBox.isDuringClassification()
&& !ActiveSplits
.contains(curConceptConcept > 0 ? curConceptConcept
: -curConceptConcept)) {
return false;
}
DepSet dep = curConceptDepSet;
boolean pos = curConceptConcept > 0;
for (int q : cur.begin()) {
if (addToDoEntry(curNode, createBiPointer(q, pos), dep, null)) {
return true;
}
}
return false;
}
/**
* apply choose-rule for all vertices (necessary for Top role in QCR)
*
* @param C
* C
* @return true if clashing
*/
@PortedFrom(file = "Reasoner.h", name = "applyChooseRuleGlobally")
private boolean applyChooseRuleGlobally(int C) {
int i = 0;
DlCompletionTree p = cGraph.getNode(i++);
while (p != null) {
if (isObjectNodeUnblocked(p) && applyChooseRule(p, C)) {
return true;
}
p = cGraph.getNode(i++);
}
return false;
}
@PortedFrom(file = "Reasoner.h", name = "findCLabelledNodes")
private void findCLabelledNodes(int C, DepSet Dep) {
NodesToMerge.clear();
DagTag tag = dlHeap.get(C).getType();
// FIXME!! do we need this for d-blocked nodes?
int i = 0;
DlCompletionTree arc = cGraph.getNode(i++);
while (arc != null) {
if (isNodeGloballyUsed(arc)
&& findChooseRuleConcept(arc.label().getLabel(tag), C, Dep)) {
NodesToMerge.add(arc);
}
arc = cGraph.getNode(i++);
}
// sort EdgesToMerge: From named nominals to generated nominals
// to blockable nodes
Collections.sort(NodesToMerge, new NodeCompare());
}
}