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.kernel.Token.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLRuntimeException;
import org.semanticweb.owlapi.reasoner.InconsistentOntologyException;
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.Helper;
import uk.ac.manchester.cs.jfact.helpers.LogAdapter;
import uk.ac.manchester.cs.jfact.kernel.options.JFactReasonerConfiguration;
import conformance.Original;
import conformance.PortedFrom;
/** role master */
@PortedFrom(file = "RoleMaster.h", name = "RoleMaster")
public class RoleMaster implements Serializable {
private static final long serialVersionUID = 11000L;
protected static class RoleCreator implements NameCreator<Role, IRI>,
Serializable {
private static final long serialVersionUID = 11000L;
@Override
public Role makeEntry(IRI name) {
return new Role(name);
}
}
/** number of the last registered role */
@PortedFrom(file = "RoleMaster.h", name = "newRoleId")
private int newRoleId;
/** all registered roles */
@PortedFrom(file = "RoleMaster.h", name = "Roles")
private final List<Role> roles = new ArrayList<Role>();
/** internal empty role (bottom in the taxonomy) */
@PortedFrom(file = "RoleMaster.h", name = "emptyRole")
private final Role emptyRole;
/** internal universal role (top in the taxonomy) */
@PortedFrom(file = "RoleMaster.h", name = "universalRole")
private final Role universalRole;
/** roles nameset */
@PortedFrom(file = "RoleMaster.h", name = "roleNS")
private final NameSet<Role, IRI> roleNS;
/** Taxonomy of roles */
@PortedFrom(file = "RoleMaster.h", name = "pTax")
private final Taxonomy pTax;
/** two halves of disjoint roles axioms */
@PortedFrom(file = "RoleMaster.h", name = "DJRolesA")
private final List<Role> disjointRolesA = new ArrayList<Role>();
@PortedFrom(file = "RoleMaster.h", name = "DJRolesB")
private final List<Role> disjointRolesB = new ArrayList<Role>();
/** flag whether to create data roles or not */
@PortedFrom(file = "RoleMaster.h", name = "DataRoles")
private final boolean dataRoles;
/** flag if it is possible to introduce new names */
@PortedFrom(file = "RoleMaster.h", name = "useUndefinedNames")
private boolean useUndefinedNames;
@Original
private static final int firstRoleIndex = 2;
/**
* TRole and its inverse in RoleBox
*
* @param r
* r
*/
@PortedFrom(file = "RoleMaster.h", name = "registerRole")
private void registerRole(Role r) {
assert r != null && r.getInverse() == null; // sanity check
assert r.getId() == 0; // only call it for the new roles
if (dataRoles) {
r.setDataRole(true);
}
roles.add(r);
r.setId(newRoleId);
// create new role which would be inverse of R
Role ri = new Role(IRI.create("-" + r.getName()));
// set up inverse
r.setInverse(ri);
ri.setInverse(r);
roles.add(ri);
ri.setId(-newRoleId);
++newRoleId;
}
/**
* @param p
* p
* @return true if P is a role that is registered in the RM
*/
@PortedFrom(file = "RoleMaster.h", name = "isRegisteredRole")
private boolean isRegisteredRole(NamedEntry p) {
if (!(p instanceof Role)) {
return false;
}
Role R = (Role) p;
int ind = R.getAbsoluteIndex();
return ind >= firstRoleIndex && ind < roles.size()
&& roles.get(ind).equals(p);
}
/** @return number of roles */
@PortedFrom(file = "RoleMaster.h", name = "size")
public int size() {
return roles.size() / 2 - 1;
}
/**
* @param d
* d
* @param TopRoleName
* TopRoleName
* @param BotRoleName
* BotRoleName
* @param c
* c
*/
public RoleMaster(boolean d, IRI TopRoleName, IRI BotRoleName,
JFactReasonerConfiguration c) {
newRoleId = 1;
emptyRole = new Role(BotRoleName);
universalRole = new Role(TopRoleName);
roleNS = new NameSet<Role, IRI>(new RoleCreator());
dataRoles = d;
useUndefinedNames = true;
// no zero-named roles allowed
roles.add(null);
roles.add(null);
// setup empty role
emptyRole.setId(0);
emptyRole.setInverse(emptyRole);
emptyRole.setDataRole(dataRoles);
emptyRole.setBPDomain(Helper.bpBOTTOM);
emptyRole.setBottom();
// setup universal role
universalRole.setId(0);
universalRole.setInverse(universalRole);
universalRole.setDataRole(dataRoles);
universalRole.setBPDomain(Helper.bpTOP);
universalRole.setTop();
// FIXME!! now it is not transitive => simple
universalRole.getAutomaton().setCompleted();
// create roles taxonomy
pTax = new Taxonomy(universalRole, emptyRole, c);
}
/**
* @param name
* name
* @return role entry with given name
*/
@PortedFrom(file = "RoleMaster.h", name = "ensureRoleName")
public NamedEntry ensureRoleName(IRI name) {
// check for the Top/Bottom names
if (name.equals(emptyRole.getName())) {
return emptyRole;
}
if (name.equals(universalRole.getName())) {
return universalRole;
}
// new name from NS
Role p = roleNS.insert(name);
// check what happens
if (p == null) {
throw new OWLRuntimeException("Unable to register '" + name
+ "' as a " + (dataRoles ? "data role" : "role"));
}
if (isRegisteredRole(p)) {
return p;
}
if (p.getId() != 0 || // not registered but has non-null ID
!useUndefinedNames) {
throw new OWLRuntimeException("Unable to register '" + name
+ "' as a " + (dataRoles ? "data role" : "role"));
}
registerRole(p);
return p;
}
/**
* add synonym to existing role
*
* @param role
* role
* @param syn
* syn
*/
@PortedFrom(file = "RoleMaster.h", name = "addRoleSynonym")
public void addRoleSynonym(Role role, Role syn) {
// no synonyms
// FIXME!! 1st call can make one of them a synonym of a const
addRoleParentProper(ClassifiableEntry.resolveSynonym(role),
ClassifiableEntry.resolveSynonym(syn));
addRoleParentProper(ClassifiableEntry.resolveSynonym(syn),
ClassifiableEntry.resolveSynonym(role));
}
/**
* add parent for the input role
*
* @param role
* role
* @param parent
* parent
*/
@PortedFrom(file = "RoleMaster.h", name = "addRoleParentProper")
public void addRoleParentProper(Role role, Role parent) {
assert !role.isSynonym() && !parent.isSynonym();
if (role.equals(parent)) {
return;
}
if (role.isDataRole() != parent.isDataRole()) {
throw new ReasonerInternalException(
"Mixed object and data roles in role subsumption axiom");
}
// check the inconsistency case *UROLE* [= *EROLE*
if (role.isTop() && parent.isBottom()) {
throw new InconsistentOntologyException();
}
// *UROLE* [= R means R (and R-) are synonym of *UROLE*
if (role.isTop()) {
parent.setSynonym(role);
parent.inverse().setSynonym(role);
return;
}
// R [= *EROLE* means R (and R-) are synonyms of *EROLE*
if (parent.isBottom()) {
role.setSynonym(parent);
role.inverse().setSynonym(parent);
return;
}
role.addParent(parent);
role.inverse().addParent(parent.inverse());
}
/**
* a pair of disjoint roles
*
* @param R
* R
* @param S
* S
*/
@PortedFrom(file = "RoleMaster.h", name = "addDisjointRoles")
public void addDisjointRoles(Role R, Role S) {
// object- and data roles are always disjoint
if (R.isDataRole() != S.isDataRole()) {
return;
}
disjointRolesA.add(R);
disjointRolesB.add(S);
}
/**
* change the undefined names usage policy
*
* @param val
* val
*/
@PortedFrom(file = "RoleMaster.h", name = "setUndefinedNames")
public void setUndefinedNames(boolean val) {
useUndefinedNames = val;
}
/** @return list of roles */
@PortedFrom(file = "RoleMaster.h", name = "begin")
public List<Role> getRoles() {
return roles.subList(firstRoleIndex, roles.size());
}
/** @return taxonomy */
@PortedFrom(file = "RoleMaster.h", name = "getTaxonomy")
public Taxonomy getTaxonomy() {
return pTax;
}
/**
* @param o
* o
* @param type
* type
*/
@PortedFrom(file = "RoleMaster.h", name = "Print")
public void print(LogAdapter o, String type) {
if (size() == 0) {
return;
}
o.print(type, " Roles (").print(size()).print("):\n");
o.print(emptyRole);
for (int i = firstRoleIndex; i < roles.size(); i++) {
Role p = roles.get(i);
p.print(o);
}
}
/** @return true if there are reflexive roles */
@PortedFrom(file = "RoleMaster.h", name = "hasReflexiveRoles")
public boolean hasReflexiveRoles() {
for (int i = firstRoleIndex; i < roles.size(); i++) {
Role p = roles.get(i);
if (p.isReflexive()) {
return true;
}
}
return false;
}
/**
* @param RR
* RR
*/
@PortedFrom(file = "RoleMaster.h", name = "fillReflexiveRoles")
public void fillReflexiveRoles(List<Role> RR) {
RR.clear();
for (int i = firstRoleIndex; i < roles.size(); i++) {
Role p = roles.get(i);
if (!p.isSynonym() && p.isReflexive()) {
RR.add(p);
}
}
}
/**
* @param tree
* tree
* @param parent
* parent
*/
@PortedFrom(file = "RoleMaster.h", name = "addRoleParent")
public void addRoleParent(DLTree tree, Role parent) {
if (tree == null) {
return;
}
if (tree.token() == RCOMPOSITION) {
parent.addComposition(tree);
DLTree inv = DLTreeFactory.inverseComposition(tree);
parent.inverse().addComposition(inv);
} else if (tree.token() == PROJINTO) {
Role R = Role.resolveRole(tree.getLeft());
if (R.isDataRole()) {
throw new ReasonerInternalException(
"Projection into not implemented for the data role");
}
DLTree C = tree.getRight().copy();
DLTree InvP = DLTreeFactory.buildTree(new Lexeme(RNAME, parent
.inverse()));
DLTree InvR = DLTreeFactory
.buildTree(new Lexeme(RNAME, R.inverse()));
// C = PROJINTO(PARENT-,C)
C = DLTreeFactory.buildTree(new Lexeme(PROJINTO), InvP, C);
// C = PROJFROM(R-,PROJINTO(PARENT-,C))
C = DLTreeFactory.buildTree(new Lexeme(PROJFROM), InvR, C);
R.setRange(C);
} else if (tree.token() == PROJFROM) {
Role R = Role.resolveRole(tree.getLeft());
DLTree C = tree.getRight().copy();
DLTree P = DLTreeFactory.buildTree(new Lexeme(RNAME, parent));
// C = PROJINTO(PARENT,C)
C = DLTreeFactory.buildTree(new Lexeme(PROJINTO), P, C);
// C = PROJFROM(R,PROJINTO(PARENT,C))
C = DLTreeFactory.buildTree(new Lexeme(PROJFROM), tree.getLeft()
.copy(), C);
R.setDomain(C);
} else {
addRoleParentProper(Role.resolveRole(tree), parent);
}
}
/** init ancestor description */
@PortedFrom(file = "RoleMaster.h", name = "initAncDesc")
public void initAncDesc() {
int nRoles = roles.size();
for (int i = firstRoleIndex; i < roles.size(); i++) {
Role p = roles.get(i);
p.eliminateToldCycles();
}
for (int i = firstRoleIndex; i < roles.size(); i++) {
Role p = roles.get(i);
if (p.isSynonym()) {
p.canonicaliseSynonym();
p.addFeaturesToSynonym();
}
}
for (int i = firstRoleIndex; i < roles.size(); i++) {
Role p = roles.get(i);
if (!p.isSynonym()) {
p.removeSynonymsFromParents();
}
}
// here TOP-role has no children yet, so it's safe to complete the
// automaton
universalRole.completeAutomaton(nRoles);
for (int i = firstRoleIndex; i < roles.size(); i++) {
Role p = roles.get(i);
if (!p.isSynonym() && !p.hasToldSubsumers()) {
p.addParent(universalRole);
}
}
TaxonomyCreator taxCreator = new TaxonomyCreator(pTax);
taxCreator.setCompletelyDefined(true);
for (int i = firstRoleIndex; i < roles.size(); i++) {
Role p = roles.get(i);
if (!p.isClassified()) {
taxCreator.classifyEntry(p);
}
}
for (int i = firstRoleIndex; i < roles.size(); i++) {
Role p = roles.get(i);
if (!p.isSynonym()) {
p.initADbyTaxonomy(pTax, nRoles);
}
}
for (int i = firstRoleIndex; i < roles.size(); i++) {
Role p = roles.get(i);
if (!p.isSynonym()) {
p.completeAutomaton(nRoles);
}
}
pTax.finalise();
if (!disjointRolesA.isEmpty()) {
for (int i = 0; i < disjointRolesA.size(); i++) {
Role q = disjointRolesA.get(i);
Role r = disjointRolesB.get(i);
Role R = ClassifiableEntry.resolveSynonym(q);
Role S = ClassifiableEntry.resolveSynonym(r);
R.addDisjointRole(S);
S.addDisjointRole(R);
R.inverse().addDisjointRole(S.inverse());
S.inverse().addDisjointRole(R.inverse());
}
for (int i = firstRoleIndex; i < roles.size(); i++) {
Role p = roles.get(i);
if (!p.isSynonym() && p.isDisjoint()) {
p.checkHierarchicalDisjoint();
}
}
}
for (int i = firstRoleIndex; i < roles.size(); i++) {
Role p = roles.get(i);
if (!p.isSynonym()) {
p.postProcess();
}
}
for (int i = firstRoleIndex; i < roles.size(); i++) {
Role p = roles.get(i);
if (!p.isSynonym()) {
p.consistent();
}
}
}
/** @return pointer to a TOP role */
@PortedFrom(file = "RoleMaster.h", name = "getTopRole")
public Role getTopRole() {
return universalRole;
}
/** @return pointer to a BOTTOM role */
@PortedFrom(file = "RoleMaster.h", name = "getBotRole")
public Role getBotRole() {
return emptyRole;
}
}