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.DLTree.equalTrees; import static uk.ac.manchester.cs.jfact.helpers.Helper.bpINVALID; import static uk.ac.manchester.cs.jfact.kernel.Token.RCOMPOSITION; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.semanticweb.owlapi.model.IRI; import org.semanticweb.owlapi.reasoner.ReasonerInternalException; 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.LogAdapter; import uk.ac.manchester.cs.jfact.kernel.actors.AddRoleActor; import conformance.Original; import conformance.PortedFrom; /** Role */ @PortedFrom(file = "tRole.h", name = "Role") public class Role extends ClassifiableEntry { private static final long serialVersionUID = 11000L; static class KnownValue implements Serializable { private static final long serialVersionUID = 11000L; /** flag value */ protected boolean value; /** whether flag set or not */ protected boolean known; public KnownValue(boolean val) { value = val; known = false; } public KnownValue() { this(false); } /** @return true iff the value is known to be set */ protected boolean isKnown() { return known; } /** @return the value */ protected boolean getValue() { return value; } /** * set the value; it is now known * * @param val * val */ protected void setValue(boolean val) { value = val; known = true; } } /** role that are inverse of given one */ @PortedFrom(file = "tRole.h", name = "Inverse") private Role inverse = null; /** Domain of role as a concept description; default null */ @PortedFrom(file = "tRole.h", name = "pDomain") private DLTree pDomain = null; /** Domain of role as a concept description; default NULL */ @PortedFrom(file = "tRole.h", name = "pSpecialDomain") private DLTree pSpecialDomain = null; /** domain in the form AR.Range for the complex roles */ @PortedFrom(file = "tRole.h", name = "bpSpecialDomain") private int bpSpecialDomain = bpINVALID; /** Domain of role as a pointer to DAG entry */ @PortedFrom(file = "tRole.h", name = "bpDomain") private int bpDomain = bpINVALID; /** pointer to role's functional definition DAG entry (or just TOP) */ @PortedFrom(file = "tRole.h", name = "Functional") private int functional = bpINVALID; /** is role relevant to current query */ @PortedFrom(file = "tRole.h", name = "rel") private long rel = 0; /** label of a domain (inverse role is used for a range label) */ @PortedFrom(file = "tRole.h", name = "domLabel") private final MergableLabel domLabel = new MergableLabel(); // for later filling @PortedFrom(file = "tRole.h", name = "Ancestor") private final List<Role> ancestorRoles = new ArrayList<Role>(); @PortedFrom(file = "tRole.h", name = "Descendant") private final List<Role> descendantRoles = new ArrayList<Role>(); /** set of the most functional super-roles */ @PortedFrom(file = "tRole.h", name = "TopFunc") private final List<Role> topFunctionalRoles = new ArrayList<Role>(); /** set of the roles that are disjoint with a given one */ @PortedFrom(file = "tRole.h", name = "Disjoint") private final Set<Role> disjointRoles = new HashSet<Role>(); /** all compositions in the form R1*R2*\ldots*Rn [= R */ @PortedFrom(file = "tRole.h", name = "subCompositions") private final LinkedHashSet<List<Role>> subCompositions = new LinkedHashSet<List<Role>>(); /** bit-vector of all parents */ @PortedFrom(file = "tRole.h", name = "AncMap") private final FastSet ancestorMap = FastSetFactory.create(); /** bit-vector of all roles disjoint with current */ @PortedFrom(file = "tRole.h", name = "DJRoles") private final FastSet disjointRolesIndex = FastSetFactory.create(); /** automaton for role */ @PortedFrom(file = "tRole.h", name = "automaton") private final RoleAutomaton automaton = new RoleAutomaton(); /** value for functionality */ @PortedFrom(file = "tRole.h", name = "Functionality") private final KnownValue functionality = new KnownValue(); /** value for symmetry */ @PortedFrom(file = "tRole.h", name = "Symmetry") private final KnownValue symmetry = new KnownValue(); /** value for asymmetricity */ @PortedFrom(file = "tRole.h", name = "Asymmetry") private final KnownValue asymmetry = new KnownValue(); /** value for transitivity */ @PortedFrom(file = "tRole.h", name = "Transitivity") private final KnownValue transitivity = new KnownValue(); /** value for reflexivity */ @PortedFrom(file = "tRole.h", name = "Reflexivity") private final KnownValue reflexivity = new KnownValue(); /** value for reflexivity */ @PortedFrom(file = "tRole.h", name = "Irreflexivity") private final KnownValue irreflexivity = new KnownValue(); /** flag to show that this role needs special R and D processing */ @PortedFrom(file = "tRole.h", name = "SpecialDomain") private boolean specialDomain = false; /** * add automaton of a sub-role to a given one * * @param R * R */ @PortedFrom(file = "tRole.h", name = "addSubRoleAutomaton") private void addSubRoleAutomaton(Role R) { if (!equals(R)) { automaton.addRA(R.getAutomaton()); } } @PortedFrom(file = "tRole.h", name = "addTrivialTransition") private void addTrivialTransition(Role r) { automaton.addTransitionSafe(RoleAutomaton.initial, new RATransition( RoleAutomaton.final_state, r)); } /** * @return get an automaton by a (possibly synonymical) role * @param R * R * @param RInProcess * RInProcess */ @PortedFrom(file = "tRole.h", name = "completeAutomatonByRole") private RoleAutomaton completeAutomatonByRole(Role R, Set<Role> RInProcess) { // no synonyms here assert !R.isSynonym(); // no case ...*S*... [= S assert R != this; R.completeAutomaton(RInProcess); return R.automaton; } /** merge domains */ @PortedFrom(file = "tRole.h", name = "mergeSupersDomain") public void mergeSupersDomain() { for (int i = 0; i < ancestorRoles.size(); i++) { domLabel.merge(ancestorRoles.get(i).domLabel); } // for reflexive role -- merge domain and range labels if (isReflexive()) { domLabel.merge(getRangeLabel()); } // for R1*R2*...*Rn [= R, merge dom(R) with dom(R1) and ran(R) with // ran(Rn) for (List<Role> q : subCompositions) { if (!q.isEmpty()) { domLabel.merge(q.get(0).domLabel); getRangeLabel().merge(q.get(q.size() - 1).getRangeLabel()); } } } /** @return inverse of given role (non- version) */ @PortedFrom(file = "tRole.h", name = "inverse") public Role inverse() { assert inverse != null; return resolveSynonym(inverse); } /** @return real inverse of a role (RO) */ @PortedFrom(file = "tRole.h", name = "realInverse") public Role realInverse() { assert inverse != null; return inverse; } /** * set inverse to given role * * @param p * p */ @PortedFrom(file = "tRole.h", name = "setInverse") public void setInverse(Role p) { assert inverse == null; assert p != null; inverse = p; } /** * @return Simple flag (not simple if role or any of its sub-roles is * transitive) */ @PortedFrom(file = "tRole.h", name = "isSimple") public boolean isSimple() { return automaton.isSimple(); } /** @return special domain */ @PortedFrom(file = "tRole.h", name = "getTSpecialDomain") public DLTree getTSpecialDomain() { return pSpecialDomain; } /** @return true iff role has a special domain */ @PortedFrom(file = "tRole.h", name = "hasSpecialDomain") public boolean hasSpecialDomain() { return specialDomain; } /** init special domain; call this only after *ALL* the domains are known */ @PortedFrom(file = "tRole.h", name = "initSpecialDomain") public void initSpecialDomain() { if (!hasSpecialDomain() || getTRange() == null) { pSpecialDomain = DLTreeFactory.createTop(); } else { pSpecialDomain = DLTreeFactory.createSNFForall( DLTreeFactory.createRole(this), getTRange().copy()); pSpecialDomain = DLTreeFactory.createSNFForall( DLTreeFactory.buildTree(new Lexeme(Token.RNAME, this)), getTRange().copy()); } } /** * set the special domain value * * @param bp * bp */ @PortedFrom(file = "tRole.h", name = "setSpecialDomain") public void setSpecialDomain(int bp) { bpSpecialDomain = bp; } @Original private boolean dataRole; /** @return distinguish data- and non-data role */ @Original public boolean isDataRole() { return dataRole; } /** * @param action * action */ @Original public void setDataRole(boolean action) { dataRole = action; } /** @return test if role is functional (ie, have some functional ancestors) */ @PortedFrom(file = "tRole.h", name = "isFunctional") public boolean isFunctional() { return functionality.getValue(); } /** @return check whether the functionality of a role is known */ @PortedFrom(file = "tRole.h", name = "isFunctionalityKnown") public boolean isFunctionalityKnown() { return functionality.isKnown(); } /** * set role functionality value * * @param value * value */ @PortedFrom(file = "tRole.h", name = "setFunctional") public void setFunctional(boolean value) { functionality.setValue(value); } /** mark role (topmost) functional */ @PortedFrom(file = "tRole.h", name = "setFunctional") public void setFunctional() { if (topFunctionalRoles.isEmpty()) { topFunctionalRoles.add(this); } this.setFunctional(true); } // transitivity /** @return check whether the role is transitive */ @PortedFrom(file = "tRole.h", name = "isTransitive") public boolean isTransitive() { return transitivity.getValue(); } /** @return check whether the transitivity of a role is known */ @PortedFrom(file = "tRole.h", name = "isTransitivityKnown") public boolean isTransitivityKnown() { return transitivity.isKnown(); } /** * set the transitivity of both role and it's inverse * * @param value * value */ @PortedFrom(file = "tRole.h", name = "setTransitive") public void setTransitive(boolean value) { transitivity.setValue(value); inverse().transitivity.setValue(value); } // symmetry /** @return check whether the role is symmetric */ @PortedFrom(file = "tRole.h", name = "isSymmetric") public boolean isSymmetric() { return symmetry.getValue(); } /** @return check whether the symmetry of a role is known */ @PortedFrom(file = "tRole.h", name = "isSymmetryKnown") public boolean isSymmetryKnown() { return symmetry.isKnown(); } /** * set the symmetry of both role and it's inverse * * @param value * value */ @PortedFrom(file = "tRole.h", name = "setSymmetric") public void setSymmetric(boolean value) { symmetry.setValue(value); inverse().symmetry.setValue(value); } // asymmetry /** @return check whether the role is asymmetric */ @PortedFrom(file = "tRole.h", name = "isAsymmetric") public boolean isAsymmetric() { return asymmetry.getValue(); } /** @return check whether the asymmetry of a role is known */ @PortedFrom(file = "tRole.h", name = "isAsymmetryKnown") public boolean isAsymmetryKnown() { return asymmetry.isKnown(); } /** * set the asymmetry of both role and it's inverse * * @param value * value */ @PortedFrom(file = "tRole.h", name = "setAsymmetric") public void setAsymmetric(boolean value) { asymmetry.setValue(value); inverse().asymmetry.setValue(value); } /** @return check whether the role is reflexive */ @PortedFrom(file = "tRole.h", name = "isReflexive") public boolean isReflexive() { return reflexivity.getValue(); } /** @return check whether the reflexivity of a role is known */ @PortedFrom(file = "tRole.h", name = "isReflexivityKnown") public boolean isReflexivityKnown() { return reflexivity.isKnown(); } /** * set the reflexivity of both role and it's inverse * * @param value * value */ @PortedFrom(file = "tRole.h", name = "setReflexive") public void setReflexive(boolean value) { reflexivity.setValue(value); inverse().reflexivity.setValue(value); } // irreflexivity /** @return check whether the role is irreflexive */ @PortedFrom(file = "tRole.h", name = "isIrreflexive") public boolean isIrreflexive() { return irreflexivity.getValue(); } /** @return check whether the irreflexivity of a role is known */ @PortedFrom(file = "tRole.h", name = "isIrreflexivityKnown") public boolean isIrreflexivityKnown() { return irreflexivity.isKnown(); } /** * set the irreflexivity of both role and it's inverse * * @param value * value */ @PortedFrom(file = "tRole.h", name = "setIrreflexive") public void setIrreflexive(boolean value) { irreflexivity.setValue(value); inverse().irreflexivity.setValue(value); } /** * @return check if the role is topmost-functional (ie, has no functional * ancestors) */ @PortedFrom(file = "tRole.h", name = "isTopFunc") public boolean isTopFunc() { // check for emptyness is here due to case where a role is determined to // be a functional return !topFunctionalRoles.isEmpty() && topFunctionalRoles.get(0).equals(this); } /** * set functional attribute to given value (functional DAG vertex) * * @param fNode * fNode */ @PortedFrom(file = "tRole.h", name = "setFunctional") public void setFunctional(int fNode) { functional = fNode; } /** @return get the Functional DAG vertex */ @PortedFrom(file = "tRole.h", name = "getFunctional") public int getFunctional() { return functional; } // relevance /** * @param lab * lab * @return is given role relevant to given Labeller's state */ @PortedFrom(file = "tRole.h", name = "isRelevant") public boolean isRelevant(long lab) { return lab == rel; } /** * make given role relevant to given Labeller's state * * @param lab * lab */ @PortedFrom(file = "tRole.h", name = "setRelevant") public void setRelevant(long lab) { rel = lab; } // Sorted reasoning interface /** @return label of the role's domain */ @PortedFrom(file = "tRole.h", name = "getDomainLabel") public MergableLabel getDomainLabel() { return domLabel; } /** @return label of the role's range */ @PortedFrom(file = "tRole.h", name = "getRangeLabel") public MergableLabel getRangeLabel() { return inverse().domLabel; } /** * add p to domain of the role * * @param p * p */ @PortedFrom(file = "tRole.h", name = "setDomain") public void setDomain(DLTree p) { if (equalTrees(pDomain, p)) { // usual case when you have a name for inverse role } else if (DLTreeFactory.isFunctionalExpr(p, this)) { this.setFunctional(); // functional restriction in the role domain means the role is // functional } else { pDomain = DLTreeFactory.createSNFAnd(Arrays.asList(pDomain, p)); } } /** * add p to range of the role * * @param p * p */ @PortedFrom(file = "tRole.h", name = "setRange") public void setRange(DLTree p) { inverse().setDomain(p); } /** @return domain-as-a-tree of the role */ @PortedFrom(file = "tRole.h", name = "getTDomain") public DLTree getTDomain() { return pDomain; } /** @return range-as-a-tree of the role */ @PortedFrom(file = "tRole.h", name = "getTRange") private DLTree getTRange() { return inverse().pDomain; } /** merge to Domain all domains from super-roles */ @PortedFrom(file = "tRole.h", name = "collectDomainFromSupers") public void collectDomainFromSupers() { for (int i = 0; i < ancestorRoles.size(); i++) { setDomain(ancestorRoles.get(i).pDomain.copy()); } } /** * set domain-as-a-bipointer to a role * * @param p * p */ @PortedFrom(file = "tRole.h", name = "setBPDomain") public void setBPDomain(int p) { bpDomain = p; } /** @return domain-as-a-bipointer of the role */ @PortedFrom(file = "tRole.h", name = "getBPDomain") public int getBPDomain() { return bpDomain; } /** @return range-as-a-bipointer of the role */ @PortedFrom(file = "tRole.h", name = "getBPRange") public int getBPRange() { return inverse().bpDomain; } // disjoint roles /** * set R and THIS as a disjoint; use it after Anc/Desc are determined * * @param R * R */ @PortedFrom(file = "tRole.h", name = "addDisjointRole") public void addDisjointRole(Role R) { disjointRoles.add(R); for (Role p : R.descendantRoles) { disjointRoles.add(p); p.disjointRoles.add(this); } } /** check (and correct) case whether R != S for R [= S */ @PortedFrom(file = "tRole.h", name = "checkHierarchicalDisjoint") public void checkHierarchicalDisjoint() { this.checkHierarchicalDisjoint(this); if (isReflexive()) { this.checkHierarchicalDisjoint(inverse()); } } /** @return check whether a role is disjoint with anything */ @PortedFrom(file = "tRole.h", name = "isDisjoint") public boolean isDisjoint() { return !disjointRoles.isEmpty(); } /** * @param r * r * @return check whether a role is disjoint with R */ @PortedFrom(file = "tRole.h", name = "isDisjoint") public boolean isDisjoint(Role r) { return disjointRolesIndex.contains(r.getAbsoluteIndex()); } /** * @return check if role is a non-strict sub-role of R * @param r * r */ @PortedFrom(file = "tRole.h", name = "<") private boolean lesser(Role r) { return isDataRole() == r.isDataRole() && ancestorMap.contains(r.getAbsoluteIndex()); } /** * @param r * r * @return true if lesser or equal to r */ @PortedFrom(file = "tRole.h", name = "<=") public boolean lesserequal(Role r) { return equals(r) || lesser(r); } /** @return list of ancestor roles */ @PortedFrom(file = "tRole.h", name = "begin_anc") public List<Role> getAncestor() { return ancestorRoles; } /** @return func super-roles w/o func parents via iterator */ @PortedFrom(file = "tRole.h", name = "begin_topfunc") public List<Role> begin_topfunc() { return topFunctionalRoles; } /** * fills BITMAP with the role's ancestors * * @param bitmap * bitmap */ @PortedFrom(file = "tRole.h", name = "addAncestorsToBitMap") private void addAncestorsToBitMap(FastSet bitmap) { for (int i = 0; i < ancestorRoles.size(); i++) { bitmap.add(ancestorRoles.get(i).getAbsoluteIndex()); } } /** * add composition to a role * * @param tree * tree */ @PortedFrom(file = "tRole.h", name = "addComposition") public void addComposition(DLTree tree) { List<Role> RS = new ArrayList<Role>(); fillsComposition(RS, tree); subCompositions.add(RS); } /** @return RA for the role */ @PortedFrom(file = "tRole.h", name = "getAutomaton") public RoleAutomaton getAutomaton() { return automaton; } // completing internal constructions /** * eliminate told role cycle * * @return rewritten role */ @PortedFrom(file = "tRole.h", name = "eliminateToldCycles") public Role eliminateToldCycles() { Set<Role> RInProcess = new HashSet<Role>(); List<Role> ToldSynonyms = new ArrayList<Role>(); return this.eliminateToldCycles(RInProcess, ToldSynonyms); } /** * complete role automaton * * @param nRoles * nRoles */ @PortedFrom(file = "tRole.h", name = "completeAutomaton") public void completeAutomaton(int nRoles) { Set<Role> RInProcess = new HashSet<Role>(); this.completeAutomaton(RInProcess); automaton.setup(nRoles, isDataRole()); } /** check whether role description is consistent */ @PortedFrom(file = "tRole.h", name = "consistent") public void consistent() { if (isSimple()) { return; } if (isFunctional()) { throw new ReasonerInternalException( "Non simple role used as simple: " + getName()); } if (isDataRole()) { throw new ReasonerInternalException( "Non simple role used as simple: " + getName()); } if (this.isDisjoint()) { throw new ReasonerInternalException( "Non simple role used as simple: " + getName()); } } @Original private static Role resolveRoleHelper(DLTree t, String r) { if (t == null) { throw new ReasonerInternalException("Role expression expected: " + r); } switch (t.token()) { case RNAME: // role name case DNAME: // data role name return (Role) t.elem().getNE(); case INV: // inversion return resolveRoleHelper(t.getChild(), r).inverse(); default: // error throw new ReasonerInternalException("Invalid role expression: " + r + " but got: " + t); } } /** * @param t * t * @param r * r reason * @return R or -R for T in the form (inv ... (inv R)...); remove synonyms */ @PortedFrom(file = "tRole.h", name = "resolveRole") public static Role resolveRole(DLTree t, String r) { return resolveSynonym(resolveRoleHelper(t, r)); } /** * @param t * t * @return R or -R for T in the form (inv ... (inv R)...); remove synonyms */ @PortedFrom(file = "tRole.h", name = "resolveRole") public static Role resolveRole(DLTree t) { return resolveSynonym(resolveRoleHelper(t, "")); } protected Role(IRI name) { super(name); setCompletelyDefined(true); // role hierarchy is completely defined by its parents addTrivialTransition(this); } /** @return (unsigned) unique index of the role */ @PortedFrom(file = "tRole.h", name = "getIndex") public int getAbsoluteIndex() { int i = 2 * extId; return i > 0 ? i : 1 - i; } @Original private int buildIndex() { int i = 2 * extId; return i > 0 ? i : 1 - i; } @PortedFrom(file = "tRole.h", name = "fillsComposition") private void fillsComposition(List<Role> Composition, DLTree tree) { if (tree.token() == RCOMPOSITION) { fillsComposition(Composition, tree.getLeft()); fillsComposition(Composition, tree.getRight()); } else { Composition.add(resolveRole(tree)); } } /** add features */ @PortedFrom(file = "tRole.h", name = "addFeaturesToSynonym") public void addFeaturesToSynonym() { if (!isSynonym()) { return; } Role syn = resolveSynonym(this); if (isFunctional() && !syn.isFunctional()) { syn.setFunctional(); } if (isTransitive()) { syn.setTransitive(true); } if (isReflexive()) { syn.setReflexive(true); } if (isDataRole()) { syn.setDataRole(true); } if (pDomain != null) { syn.setDomain(pDomain.copy()); } if (this.isDisjoint()) { syn.disjointRoles.addAll(disjointRoles); } syn.subCompositions.addAll(subCompositions); toldSubsumers.clear(); addParent(syn); } @PortedFrom(file = "tRole.h", name = "eliminateToldCycles") private Role eliminateToldCycles(Set<Role> RInProcess, List<Role> ToldSynonyms) { if (isSynonym()) { return null; } if (RInProcess.contains(this)) { ToldSynonyms.add(this); return this; } Role ret = null; RInProcess.add(this); removeSynonymsFromParents(); for (ClassifiableEntry r : toldSubsumers) { if ((ret = ((Role) r).eliminateToldCycles(RInProcess, ToldSynonyms)) != null) { if (ret.equals(this)) { Collections.sort(ToldSynonyms, new RoleCompare()); ret = ToldSynonyms.get(0); for (int i = 1; i < ToldSynonyms.size(); i++) { Role p = ToldSynonyms.get(i); p.setSynonym(ret); ret.addParents(p.getToldSubsumers()); } ToldSynonyms.clear(); RInProcess.remove(this); return ret.eliminateToldCycles(RInProcess, ToldSynonyms); } else { ToldSynonyms.add(this); break; } } } RInProcess.remove(this); return ret; } @Override public String toString() { return extName.toString(); } /** * @param o * o */ @PortedFrom(file = "tRole.h", name = "print") public void print(LogAdapter o) { o.print("Role \"", getName(), "\"(") .print(getId()) .print(")", isTransitive() ? "T" : "", isReflexive() ? "R" : "", isTopFunc() ? "t" : "", isFunctional() ? "F" : "", isDataRole() ? "D" : ""); if (isSynonym()) { o.print(" = \"", getSynonym().getName(), "\"\n"); return; } if (!toldSubsumers.isEmpty()) { o.print(" parents={\""); List<ClassifiableEntry> l = new ArrayList<ClassifiableEntry>( toldSubsumers); for (int i = 0; i < l.size(); i++) { if (i > 0) { o.print("\", \""); } o.print(l.get(i).getName()); } o.print("\"}"); } if (!disjointRoles.isEmpty()) { o.print(" disjoint with {\""); List<Role> l = new ArrayList<Role>(disjointRoles); for (int i = 0; i < disjointRoles.size(); i++) { if (i > 0) { o.print("\", \""); } o.print(l.get(i).getName()); } o.print("\"}"); } if (pDomain != null) { o.print(" Domain=(").print(bpDomain).print(")=", pDomain); } if (getTRange() != null) { o.print(" Range=(").print(getBPRange()).print(")=", getTRange()); } o.print("\nAutomaton (size ") .print(automaton.size()) .print("): ", automaton.isISafe() ? "I" : "i", automaton.isOSafe() ? "O" : "o"); automaton.print(o); o.print("\n"); } /** * @param pTax * pTax * @param nRoles * nRoles */ @PortedFrom(file = "tRole.h", name = "initADbyTaxonomy") public void initADbyTaxonomy(Taxonomy pTax, int nRoles) { assert isClassified(); assert ancestorRoles.isEmpty() && descendantRoles.isEmpty(); // Note that Top/Bottom are not connected to taxonomy yet. // fills ancestors by the taxonomy AddRoleActor anc = new AddRoleActor(ancestorRoles); pTax.getRelativesInfo(getTaxVertex(), anc, false, false, true); // fills descendants by the taxonomy AddRoleActor desc = new AddRoleActor(descendantRoles); pTax.getRelativesInfo(getTaxVertex(), desc, false, false, false); // init map for fast Anc/Desc access addAncestorsToBitMap(ancestorMap); } /** post process */ @PortedFrom(file = "tRole.h", name = "postProcess") public void postProcess() { initTopFunc(); if (this.isDisjoint()) { initDJMap(); } } @PortedFrom(file = "tRole.h", name = "isRealTopFunc") private boolean isRealTopFunc() { if (!isFunctional()) { return false; } for (int i = 0; i < ancestorRoles.size(); i++) { if (ancestorRoles.get(i).isTopFunc()) { return false; } } return true; } @PortedFrom(file = "tRole.h", name = "initTopFunc") private void initTopFunc() { if (isRealTopFunc()) { return; } if (isTopFunc()) { topFunctionalRoles.clear(); } for (int i = 0; i < ancestorRoles.size(); i++) { Role p = ancestorRoles.get(i); if (p.isRealTopFunc()) { topFunctionalRoles.add(p); } } if (!topFunctionalRoles.isEmpty()) { functionality.setValue(true); } } @PortedFrom(file = "tRole.h", name = "checkHierarchicalDisjoint") private void checkHierarchicalDisjoint(Role R) { if (disjointRoles.contains(R)) { setDomain(DLTreeFactory.createBottom()); disjointRoles.clear(); return; } for (Role p : R.descendantRoles) { if (disjointRoles.contains(p)) { p.setDomain(DLTreeFactory.createBottom()); disjointRoles.remove(p); p.disjointRoles.clear(); } } } @PortedFrom(file = "tRole.h", name = "initDJMap") private void initDJMap() { for (Role q : disjointRoles) { disjointRolesIndex.add(q.getAbsoluteIndex()); } } @PortedFrom(file = "tRole.h", name = "preprocessComposition") private void preprocessComposition(List<Role> RS) { boolean same = false; int last = RS.size() - 1; // TODO doublecheck, strange assignments to what is in the list for (int i = 0; i < RS.size(); i++) { Role p = RS.get(i); Role R = resolveSynonym(p); if (R.isBottom()) { RS.clear(); return; } if (R.equals(this)) { if (i != 0 && i != last) { throw new ReasonerInternalException("Cycle in RIA " + getName()); } if (same) { if (last == 1) { RS.clear(); setTransitive(true); return; } else { throw new ReasonerInternalException("Cycle in RIA " + getName()); } } else { same = true; } } RS.set(i, R); } } @PortedFrom(file = "tRole.h", name = "completeAutomaton") private void completeAutomaton(Set<Role> RInProcess) { if (automaton.isCompleted()) { return; // if we found a cycle... } if (RInProcess.contains(this)) { throw new ReasonerInternalException("Cycle in RIA " + getName()); } // start processing role RInProcess.add(this); // make sure that all sub-roles already have completed automata for (Role p : descendantRoles) { p.completeAutomaton(RInProcess); } // add automata for complex role inclusions for (List<Role> q : subCompositions) { addSubCompositionAutomaton(q, RInProcess); } // check for the transitivity if (isTransitive()) { automaton.addTransitionSafe(RoleAutomaton.final_state, new RATransition(RoleAutomaton.initial)); } // here automaton is complete automaton.setCompleted(true); if (!isBottom()) { for (ClassifiableEntry p : toldSubsumers) { Role R = (Role) resolveSynonym(p); R.addSubRoleAutomaton(this); if (hasSpecialDomain()) { R.specialDomain = true; } } } // finish processing role RInProcess.remove(this); } /** * add automaton for a role composition * * @param RS * RS * @param RInProcess * RInProcess */ @PortedFrom(file = "tRole.h", name = "addSubCompositionAutomaton") private void addSubCompositionAutomaton(List<Role> RS, Set<Role> RInProcess) { // first preprocess the role chain preprocessComposition(RS); if (RS.isEmpty()) { return; } // here we need a special treatment for R&D specialDomain = true; // tune iterators and states int p = 0; int p_last = RS.size() - 1; int from = RoleAutomaton.initial, to = RoleAutomaton.final_state; if (RS.get(0).equals(this)) { ++p; from = RoleAutomaton.final_state; } else if (RS.get(p_last).equals(this)) { --p_last; to = RoleAutomaton.initial; } // make sure the role chain contain at least one element assert p <= p_last; // create a chain boolean oSafe = false; // we couldn't assume that the current role // automaton is i- or o-safe automaton.initChain(from); for (; p != p_last; ++p) { oSafe = automaton.addToChain( completeAutomatonByRole(RS.get(p), RInProcess), oSafe); } // add the last automaton to chain automaton.addToChain(completeAutomatonByRole(RS.get(p), RInProcess), oSafe, to); } /** @return inverse */ @Original public Role getInverse() { return inverse; } }