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.Token.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.vocab.OWLRDFVocabulary;
import uk.ac.manchester.cs.jfact.helpers.DLTree;
import uk.ac.manchester.cs.jfact.helpers.DLTreeFactory;
import uk.ac.manchester.cs.jfact.helpers.FastSet;
import uk.ac.manchester.cs.jfact.helpers.FastSetFactory;
import uk.ac.manchester.cs.jfact.helpers.UnreachableSituationException;
import conformance.Original;
import conformance.PortedFrom;
/** concept */
@PortedFrom(file = "ConceptWithDep.h", name = "Concept")
public class Concept extends ClassifiableEntry {
private static final long serialVersionUID = 11000L;
/** temp concept iri */
public static final IRI temp = IRI.create("urn:jfact#", "temp");
/** query concept iri */
public static final IRI query = IRI.create("FaCT++.default");
/** nothing concept iri */
public static final IRI nothing = OWLRDFVocabulary.OWL_NOTHING.getIRI();
/** thing concept iri */
public static final IRI thing = OWLRDFVocabulary.OWL_THING.getIRI();
/** @return bottom concept */
@Original
public static Concept getBOTTOM() {
Concept toReturn = new Concept(nothing);
toReturn.setBottom();
toReturn.setId(-1);
toReturn.setpName(bpBOTTOM);
toReturn.setpBody(bpBOTTOM);
return toReturn;
}
/** @return top concept */
@Original
public static Concept getTOP() {
Concept toReturn = new Concept(thing);
toReturn.setTop();
toReturn.setId(-1);
toReturn.setpName(bpTOP);
toReturn.setpBody(bpTOP);
toReturn.setTsDepth(1);
toReturn.setClassTag(CTTag.cttTrueCompletelyDefined);
return toReturn;
}
/** @return temporary concept */
@Original
public static Concept getTEMP() {
Concept TEMP = new Concept(temp);
TEMP.setId(-1);
TEMP.setTsDepth(1);
TEMP.setClassTag(CTTag.cttTrueCompletelyDefined);
return TEMP;
}
/** @return query concept */
public static Concept getQuery() {
Concept p = new Concept(query);
p.setSystem();
return p;
}
/** type of concept wrt classifiability */
public enum CTTag {
/** not specified */
cttUnspecified('u'),
/** concept with all parents -- TCD */
cttTrueCompletelyDefined('T'),
/** concept w/o any told subsumers */
cttOrphan('O'),
/** concept with all parents -- LCD, TCD or Orptans */
cttLikeCompletelyDefined('L'),
/** concept with non-primitive TS */
cttHasNonPrimitiveTS('N'),
/** any other primitive concept */
cttRegular('r'),
/** any non-primitive concept (except synonyms) */
cttNonPrimitive('n');
private final char c;
private CTTag(char c) {
this.c = c;
}
protected char getCTTagName() {
return c;
}
}
/** label to use in relevant-only checks */
@PortedFrom(file = "tConcept.h", name = "rel")
private long rel;
/**
* classification type of concept: completely defined (true- or like-), no
* TS, other
*/
@PortedFrom(file = "tConcept.h", name = "classTag")
private CTTag classTag;
/** depth of the concept wrt told subsumers */
@PortedFrom(file = "tConcept.h", name = "tsDepth")
private int tsDepth;
/** pointer to the entry in DAG with concept name */
@PortedFrom(file = "tConcept.h", name = "pName")
private int pName;
/** pointer to the entry in DAG with concept definition */
@PortedFrom(file = "tConcept.h", name = "pBody")
private int pBody;
/** features for C */
@PortedFrom(file = "tConcept.h", name = "posFeatures")
private final LogicFeatures posFeatures = new LogicFeatures();
/** features for ~C */
@PortedFrom(file = "tConcept.h", name = "negFeatures")
private final LogicFeatures negFeatures = new LogicFeatures();
/** all extra rules for a given concept */
@PortedFrom(file = "tConcept.h", name = "erSet")
private final FastSet extraRules = FastSetFactory.create();
@PortedFrom(file = "tConcept.h", name = "Description")
protected DLTree description;
/**
* adds concept as a told subsumer of current one;
*
* @param concept
* concept
* @return value for CDC analisys
*/
@PortedFrom(file = "tConcept.h", name = "addToldSubsumer")
private boolean addToldSubsumer(Concept concept) {
if (concept != this) {
addParentIfNew(concept);
if (concept.isSingleton() || concept.isHasSP()) {
setHasSP(true);
// this has singleton parent
}
}
// if non-primitive concept was found in a description, it's not CD
return concept.isPrimitive();
}
/**
* @param name
* name
*/
public Concept(IRI name) {
super(name);
rel = 0;
classTag = CTTag.cttUnspecified;
tsDepth = 0;
pName = bpINVALID;
pBody = bpINVALID;
setPrimitive(true);
}
/**
* add index of a simple rule in TBox to the ER set
*
* @param ruleIndex
* ruleIndex
*/
@PortedFrom(file = "tConcept.h", name = "addExtraRule")
public void addExtraRule(int ruleIndex) {
extraRules.add(ruleIndex);
setCompletelyDefined(false);
}
/** @return if a concept is in a disjoint relation with anything */
@PortedFrom(file = "tConcept.h", name = "hasExtraRules")
public boolean hasExtraRules() {
return !extraRules.isEmpty();
}
/** @return accessing DJ elements */
@PortedFrom(file = "tConcept.h", name = "er_begin")
public FastSet getExtraRules() {
return extraRules;
}
/** @return class tag */
@Original
public CTTag getClassTagPlain() {
return classTag;
}
/** @return value of a tag; determine it if unset */
@PortedFrom(file = "tConcept.h", name = "getClassTag")
public CTTag getClassTag() {
if (classTag == CTTag.cttUnspecified) {
classTag = determineClassTag();
}
return classTag;
}
/** remove concept from its own definition (like in case C [= (or C ...) */
@PortedFrom(file = "tConcept.h", name = "removeSelfFromDescription")
public void removeSelfFromDescription() {
if (hasSelfInDesc()) {
description = replaceWithConstOld(description);
}
this.initToldSubsumers();
}
/** remove concept description (to save space) */
@PortedFrom(file = "tConcept.h", name = "removeDescription")
public void removeDescription() {
description = null;
}
/**
* @param desc
* desc
* @return whether it is possible to init this as a non-primitive concept
* with DESC
*/
@PortedFrom(file = "tConcept.h", name = "canInitNonPrim")
public boolean canInitNonPrim(DLTree desc) {
if (description == null) {
return true;
}
if (!isPrimitive() && description.equals(desc)) {
return true;
}
return false;
}
/**
* switch primitive concept to non-primitive with new definition;
*
* @param desc
* desc
* @return old definition
*/
@PortedFrom(file = "tConcept.h", name = "makeNonPrimitive")
public DLTree makeNonPrimitive(DLTree desc) {
DLTree ret = description;
removeDescription();
addDesc(desc);
setPrimitive(false);
return ret;
}
@Override
public String toString() {
return extName.toString();
}
/** init told subsumers of the concept by it's description */
@PortedFrom(file = "tConcept.h", name = "initToldSubsumers")
public void initToldSubsumers() {
toldSubsumers.clear();
setHasSP(false);
// normalise description if the only parent is TOP
if (isPrimitive() && description != null && description.isTOP()) {
removeDescription();
}
boolean CD = !hasExtraRules() && isPrimitive();
// not a completely defined if there are extra rules
if (description != null) {
CD &= this.initToldSubsumers(description, new HashSet<Role>());
}
setCompletelyDefined(CD);
}
/**
* init TOP told subsumer if necessary
*
* @param top
* top
*/
@PortedFrom(file = "tConcept.h", name = "setToldTop")
public void setToldTop(Concept top) {
if (description == null && !hasToldSubsumers()) {
addParent(top);
}
}
/** @return resolve synonym id */
@PortedFrom(file = "tConcept.h", name = "resolveId")
public int resolveId() {
if (pName == bpINVALID) {
return pBody;
}
if (isSynonym()) {
Concept r = resolveSynonym(this);
if (r != this) {
return r.resolveId();
}
}
// return concept's name
return pName;
}
/**
* @param Desc
* Desc
*/
@PortedFrom(file = "tConcept.h", name = "addDesc")
public void addDesc(DLTree Desc) {
if (Desc == null) {
return;
}
// assert this.isPrimitive();
if (description == null) {
description = Desc.copy();
return;
}
if (Desc.isAND()) {
if (description.isAND()) {
description.addFirstChildren(Desc.getChildren());
} else {
// if it's not an AND then a new AND must be created
DLTree t = description;
description = Desc.copy();
description.addChild(t);
}
} else {
if (description.isAND()) {
description.addFirstChild(Desc);
} else {
description = DLTreeFactory.createSNFAnd(Desc, description);
}
}
}
/**
* @param Desc
* Desc
*/
@Original
public void addLeaves(Collection<DLTree> Desc) {
// assert isPrimitive();
if (description == null) {
description = DLTreeFactory.createSNFAnd(Desc);
} else {
if (description.isAND()) {
for (DLTree d : Desc) {
description.addChild(d);
}
} else {
List<DLTree> l = new ArrayList<DLTree>(Desc);
l.add(description);
description = DLTreeFactory.createSNFAnd(l);
}
}
}
@PortedFrom(file = "tConcept.h", name = "determineClassTag")
private CTTag determineClassTag() {
if (isSynonym()) {
return resolveSynonym(this).getClassTag();
}
if (!isPrimitive()) {
return CTTag.cttNonPrimitive;
}
if (!hasToldSubsumers()) {
return CTTag.cttOrphan;
}
boolean hasLCD = false;
boolean hasOther = false;
boolean hasNP = false;
for (ClassifiableEntry p : toldSubsumers) {
switch (((Concept) p).getClassTag()) {
case cttTrueCompletelyDefined:
break;
case cttOrphan:
case cttLikeCompletelyDefined:
hasLCD = true;
break;
case cttRegular:
hasOther = true;
break;
case cttHasNonPrimitiveTS:
case cttNonPrimitive:
hasNP = true;
break;
default:
throw new UnreachableSituationException();
}
}
// there are non-primitive TS
if (hasNP) {
return CTTag.cttHasNonPrimitiveTS;
}
// has something different from CD-like ones (and not CD)
if (hasOther || !isCompletelyDefined()) {
return CTTag.cttRegular;
}
// no more 'other' concepts here, and the CD-like structure
if (hasLCD) {
return CTTag.cttLikeCompletelyDefined;
}
return CTTag.cttTrueCompletelyDefined;
}
@Original
private static final EnumSet<Token> replacements = EnumSet.of(CNAME, INAME,
RNAME, DNAME);
/**
* @param stack
* stack
* @param current
* current
*/
@Original
public void push(LinkedList<DLTree> stack, DLTree current) {
// push subtrees: stack size increases by one or two, or current is a
// leaf
for (DLTree t : current.getChildren()) {
if (t != null) {
stack.push(t);
}
}
}
@PortedFrom(file = "tConcept.h", name = "replaceSelfWithConst")
private DLTree replaceWithConstOld(DLTree t) {
if (t == null) {
return null;
}
Token token = t.token();
// the three ifs are actually exclusive
if (replacements.contains(token)
&& resolveSynonym((ClassifiableEntry) t.elem().getNE()).equals(
this)) {
return DLTreeFactory.createTop();
}
if (token == AND) {
List<DLTree> l = new ArrayList<DLTree>();
for (DLTree d : t.getChildren()) {
l.add(replaceWithConstOld(d));
}
return DLTreeFactory.createSNFAnd(l, t);
}
if (token == NOT
&& (t.getChild().isAND() || replacements.contains(t.getChild()
.token()))) {
return DLTreeFactory
.createSNFNot(replaceWithConstOld(t.getChild()));
}
return t;
}
@PortedFrom(file = "tConcept.h", name = "hasSelfInDesc")
private boolean hasSelfInDesc(DLTree t) {
if (t == null) {
return false;
}
Token token = t.token();
// the three ifs are actually exclusive
if (replacements.contains(token)) {
return resolveSynonym((ClassifiableEntry) t.elem().getNE()).equals(
this);
}
if (token == AND) {
for (DLTree d : t.getChildren()) {
if (hasSelfInDesc(d)) {
return true;
}
}
return false;
}
if (token == NOT
&& (t.getChild().isAND() || replacements.contains(t.getChild()
.token()))) {
return hasSelfInDesc(t.getChild());
}
return false;
}
/**
* init told subsumers of the concept by given DESCription;
*
* @param _desc
* _desc
* @param RolesProcessed
* RolesProcessed
* @return TRUE iff concept is CD
*/
@PortedFrom(file = "tConcept.h", name = "initToldSubsumers")
public boolean initToldSubsumers(DLTree _desc, Set<Role> RolesProcessed) {
if (_desc == null || _desc.isTOP()) {
return true;
}
DLTree desc = _desc;
Token token = desc.token();
if (replacements.contains(token)) {
return addToldSubsumer((Concept) desc.elem().getNE());
}
if (token == NOT) {
if (desc.getChild().token() == FORALL
|| desc.getChild().token() == LE) {
searchTSbyRoleAndSupers(
Role.resolveRole(desc.getChild().getLeft()),
RolesProcessed);
}
return false;
}
if (token == SELF) {
Role R = Role.resolveRole(desc.getChild());
searchTSbyRoleAndSupers(R, RolesProcessed);
searchTSbyRoleAndSupers(R.inverse(), RolesProcessed);
return false;
}
if (token == AND) {
// push all AND children on the list and traverse the list removing
// n-th level ANDs and pushing their children in turn; ends up with
// the leaves of the AND subtree
boolean toReturn = true;
for (DLTree t : desc.getChildren()) {
toReturn &= this.initToldSubsumers(t, RolesProcessed);
}
return toReturn;
}
return false;
}
@PortedFrom(file = "tConcept.h", name = "SearchTSbyRole")
private void searchTSbyRole(Role R, Set<Role> rolesProcessed) {
if (rolesProcessed.contains(R)) {
return;
}
DLTree Domain = R.getTDomain();
if (Domain == null || Domain.isConst()) {
return;
}
rolesProcessed.add(R);
this.initToldSubsumers(Domain, rolesProcessed);
}
/**
* @param r
* r
* @param RolesProcessed
* RolesProcessed
*/
@PortedFrom(file = "tConcept.h", name = "SearchTSbyRoleAndSupers")
public void searchTSbyRoleAndSupers(Role r, Set<Role> RolesProcessed) {
searchTSbyRole(r, RolesProcessed);
List<Role> list = r.getAncestor();
for (int i = 0; i < list.size(); i++) {
Role q = list.get(i);
searchTSbyRole(q, RolesProcessed);
}
}
/** @return told subsumers depth */
@PortedFrom(file = "tConcept.h", name = "calculateTSDepth")
public int calculateTSDepth() {
if (tsDepth > 0) {
return tsDepth;
}
int max = 0;
for (ClassifiableEntry p : toldSubsumers) {
// XXX should not be needed
if (!p.getToldSubsumers().contains(this)) {
int cur = ((Concept) p).calculateTSDepth();
if (max < cur) {
max = cur;
}
}
// else both nodes are each other subsumers: same depth?
}
tsDepth = max + 1;
return tsDepth;
}
/** clear concept */
@PortedFrom(file = "tConcept.h", name = "clear")
public void clear() {
// TNamedEntry clean
setId(0);
// ClassifiableEntry clean
taxVertex = null;
toldSubsumers.clear();
setCompletelyDefined(false);
pSynonym = null;
// TConcept clean
removeDescription();
setPrimitive(true);
pBody = bpINVALID;
pName = bpINVALID;
}
/**
* @return true iff description contains top-level references to THIS
* concept
*/
@PortedFrom(file = "tConcept.h", name = "hasSelfInDesc")
boolean hasSelfInDesc() {
return hasSelfInDesc(description);
}
/** @return p name */
@Original
public int getpName() {
return pName;
}
/**
* @param pName
* pName
*/
@Original
public void setpName(int pName) {
this.pName = pName;
}
/** @return p body */
@Original
public int getpBody() {
return pBody;
}
/**
* @param pBody
* pBody
*/
@Original
public void setpBody(int pBody) {
this.pBody = pBody;
}
/** @return description */
@Original
public DLTree getDescription() {
return description;
}
/** @return told subsumers depth */
@Original
public int getTsDepth() {
return tsDepth;
}
@Original
private void setTsDepth(int tsDepth) {
this.tsDepth = tsDepth;
}
/** @return neg features */
@Original
public LogicFeatures getNegFeatures() {
return negFeatures;
}
/** @return pos features */
@Original
public LogicFeatures getPosFeatures() {
return posFeatures;
}
@Original
@PortedFrom(file = "tConcept.h", name = "classTag")
private void setClassTag(CTTag classTag) {
this.classTag = classTag;
}
@Original
private boolean primitive;
/** @return true if primitive */
@Original
public boolean isPrimitive() {
return primitive;
}
/** @return false if primitive */
@Original
public boolean isNonPrimitive() {
return !isPrimitive();
}
/**
* @param action
* action
*/
@Original
public void setPrimitive(boolean action) {
primitive = action;
}
@Original
private boolean hasSP;
/** @return HasSingletonParent flag */
@Original
public boolean isHasSP() {
return hasSP;
}
/**
* @param action
* action
*/
@Original
public void setHasSP(boolean action) {
hasSP = action;
}
@Original
private boolean nominal;
/** @return nominal */
@Original
public boolean isNominal() {
return nominal;
}
/**
* @param action
* action
*/
@Original
public void setNominal(boolean action) {
nominal = action;
}
@Original
private boolean singleton;
/** @return singleton */
@Original
public boolean isSingleton() {
return singleton;
}
/**
* @param action
* action
*/
@Original
public void setSingleton(boolean action) {
singleton = action;
}
// relevance part
/**
* @param lab
* lab
* @return is given concept relevant to given Labeller's state
*/
@PortedFrom(file = "tConcept.h", name = "isRelevant")
public boolean isRelevant(long lab) {
return lab == rel;
}
/**
* make given concept relevant to given Labeller's state
*
* @param lab
* lab
*/
@PortedFrom(file = "tConcept.h", name = "setRelevant")
public void setRelevant(long lab) {
rel = lab;
}
/** make given concept irrelevant to given Labeller's state */
@PortedFrom(file = "tConcept.h", name = "dropRelevant")
public void dropRelevant() {
rel = 0;
}
}