Java tutorial
/** * (c) 2009-2014 Otto-Friedrich-University Bamberg * * $Id$ * * Use, modification and restribution of this file are covered by the * terms of the Artistic License 2.0. * * You should have received a copy of the license terms in a file named * "LICENSE" together with this software package. * * Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT * HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR * A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE * EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO * COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT * OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. **/ package de.uniba.wiai.kinf.pw.projects.lillytab.reasoner.tbox; import de.dhke.projects.cutil.collections.factories.EnumSetFactory; import de.dhke.projects.cutil.collections.factories.ICollectionFactory; import de.dhke.projects.cutil.collections.factories.SortedListSetFactory; import de.dhke.projects.cutil.collections.iterator.MultiMapEntryIterable; import de.dhke.projects.cutil.collections.map.GenericMultiHashMap; import de.dhke.projects.cutil.collections.set.Flat3Set; import de.uniba.wiai.kinf.pw.projects.lillytab.abox.EInconsistentRBoxException; import de.uniba.wiai.kinf.pw.projects.lillytab.tbox.IAssertedRBox; import de.uniba.wiai.kinf.pw.projects.lillytab.tbox.IRBox; import de.uniba.wiai.kinf.pw.projects.lillytab.tbox.ITBox; import de.uniba.wiai.kinf.pw.projects.lillytab.tbox.RoleProperty; import de.uniba.wiai.kinf.pw.projects.lillytab.tbox.RoleType; import de.uniba.wiai.kinf.pw.projects.lillytab.terms.IDLClassExpression; import de.uniba.wiai.kinf.pw.projects.lillytab.terms.IDLNodeTerm; import java.lang.ref.WeakReference; import java.util.*; import org.apache.commons.collections15.MultiMap; import org.apache.commons.collections15.keyvalue.DefaultMapEntry; /** * * @param <I> The type for individuals/nominals * @param <L> The type for literals * @param <K> The type for DL classes * @param <R> The type for properties (roles) * * @author Peter Wullinger <peter.wullinger@uni-bamberg.de> */ public class RBox<I extends Comparable<? super I>, L extends Comparable<? super L>, K extends Comparable<? super K>, R extends Comparable<? super R>> implements IRBox<I, L, K, R> { private final AssertedRBox<I, L, K, R> _assertedRBox; private final MultiMap<R, R> _inverseRoles; private final MultiMap<R, R> _equivalentRoles; private final MultiMap<R, R> _subRoles; private final MultiMap<R, R> _superRoles; private final MultiMap<RoleProperty, R> _propertyRoleMap; private final MultiMap<R, RoleProperty> _rolePropertyMap; private WeakReference<IRBox<I, L, K, R>> _immutable; protected RBox(final AssertedRBox<I, L, K, R> assertedRBox) { _assertedRBox = assertedRBox; final ICollectionFactory<R, ? extends Collection<R>> roleSetFactory = new SortedListSetFactory<>(); _rolePropertyMap = new GenericMultiHashMap<>(new EnumSetFactory<>(RoleProperty.class)); _propertyRoleMap = new GenericMultiHashMap<>(roleSetFactory); _inverseRoles = new GenericMultiHashMap<>(roleSetFactory); _equivalentRoles = new GenericMultiHashMap<>(roleSetFactory); _subRoles = new GenericMultiHashMap<>(roleSetFactory); _superRoles = new GenericMultiHashMap<>(roleSetFactory); } @Override public ITBox<I, L, K, R> getTBox() { return _assertedRBox.getTBox(); } @Override public String toString() { return toString(""); } @Override public String toString(String prefix) { /* ": Properties: [], Domains: [], Ranges: []".length() = 41 */ StringBuilder sb = new StringBuilder(_assertedRBox.getRoles().size() * (prefix.length() + 41)); for (R role : _assertedRBox.getRoles()) { sb.append(role); sb.append(": Properties: "); sb.append(getRoleProperties(role)); sb.append(", Domains: "); sb.append(getRoleDomains(role)); sb.append(", Ranges: "); sb.append(getRoleRanges(role)); sb.append("\n"); sb.append(prefix); } return sb.toString(); } @Override public Collection<R> getEquivalentRoles(R role) { if (!hasRole(role)) { throw new IllegalArgumentException(String.format("Unknown role `%s'", role)); } final Collection<R> roles = _equivalentRoles.get(role); if (roles != null) { return Collections.unmodifiableCollection(roles); } else { return null; } } @Override public Collection<R> getInverseRoles(R role) { if (!hasRole(role)) { throw new IllegalArgumentException(String.format("Unknown role `%s'", role)); } final Collection<R> roles = _inverseRoles.get(role); if (roles != null) { return Collections.unmodifiableCollection(roles); } else { return null; } } @Override public Collection<IDLClassExpression<I, L, K, R>> getRoleDomains(final R role) { final Set<IDLClassExpression<I, L, K, R>> domains = new Flat3Set<>(); for (R superRole : getSuperRoles(role)) { final Collection<IDLClassExpression<I, L, K, R>> assertedDomains = _assertedRBox .getRoleDomains(superRole); if (assertedDomains != null) { domains.addAll(assertedDomains); } } return domains; } @Override public Collection<IDLNodeTerm<I, L, K, R>> getRoleRanges(final R role) { final Set<IDLNodeTerm<I, L, K, R>> ranges = new Flat3Set<>(); for (R superRole : getSuperRoles(role)) { final Collection<IDLNodeTerm<I, L, K, R>> assertedRanges = _assertedRBox.getRoleRanges(superRole); if (assertedRanges != null) { ranges.addAll(assertedRanges); } } return ranges; } @Override public Collection<RoleProperty> getRoleProperties(R role) { final Collection<RoleProperty> properties = _rolePropertyMap.get(role); if (properties != null) { return Collections.unmodifiableCollection(properties); } else { return null; } } @Override public RoleType getRoleType(R role) { return _assertedRBox.getRoleType(role); } @Override public boolean hasRole(R role) { return (getRoleType(role) != null); } @Override public Collection<R> getRoles() { return _assertedRBox.getRoles(); } @Override public Collection<R> getRoles(RoleProperty property) { final Collection<R> roles = _propertyRoleMap.get(property); if (roles != null) { return Collections.unmodifiableCollection(roles); } else { return null; } } @Override public Collection<R> getRoles(RoleType type) { return _assertedRBox.getRoles(type); } @Override public Collection<R> getSubRoles(R role) { if (!hasRole(role)) { throw new IllegalArgumentException(String.format("Unknown role `%s'", role)); } final Collection<R> subRoles = _subRoles.get(role); if (subRoles != null) { return Collections.unmodifiableCollection(subRoles); } else { return null; } } @Override public Collection<R> getSuperRoles(R role) { if (!hasRole(role)) { throw new IllegalArgumentException(String.format("Unknown role `%s'", role)); } final Collection<R> superRoles = _superRoles.get(role); if (superRoles != null) { return Collections.unmodifiableCollection(superRoles); } else { return null; } } @Override public boolean hasRoleProperty(R role, RoleProperty property) { return _rolePropertyMap.containsValue(role, property); } @Override public boolean hasRoleType(R role, RoleType roleType) { return getAssertedRBox().hasRoleType(role, roleType); } @Override public boolean isEquivalentRole(R first, R second) { return _equivalentRoles.containsValue(first, second); } @Override public boolean isInverseRole(R first, R second) { return _inverseRoles.containsValue(first, second); } @Override public boolean hasInverseRoles() { return !_inverseRoles.isEmpty(); } @Override public boolean isSubRole(R sup, R sub) { return _subRoles.containsValue(sup, sub); } @Override public boolean isSuperRole(R sub, R sup) { return _superRoles.containsValue(sub, sup); } @Override public IAssertedRBox<I, L, K, R> getAssertedRBox() { return _assertedRBox; } @Override public IRBox<I, L, K, R> clone() { return this; } @Override public synchronized IRBox<I, L, K, R> getImmutable() { IRBox<I, L, K, R> immutable = null; if (_immutable != null) { immutable = _immutable.get(); } if (immutable == null) { immutable = new ImmutableRBox<>(getTBox().getImmutable(), this); _immutable = new WeakReference<>(immutable); } return immutable; } protected void recalculate() throws EInconsistentRBoxException { /* * clear local collections, initialize from asserted RBox */ _propertyRoleMap.clear(); _propertyRoleMap.putAll(_assertedRBox.getPropertyRoles()); _rolePropertyMap.clear(); _rolePropertyMap.putAll(_assertedRBox.getRoleProperties()); _inverseRoles.clear(); _inverseRoles.putAll(_assertedRBox.getInverseRoles()); _subRoles.clear(); _subRoles.putAll(_assertedRBox.getSubRoles()); _superRoles.clear(); _superRoles.putAll(_assertedRBox.getSuperRoles()); _equivalentRoles.clear(); _equivalentRoles.putAll(_assertedRBox.getEquivalentRoles()); addCommutativeInverses(); addCommutativeEqualities(); addSubSuper(); /** * Perform a fixed point iteration to update the role box. */ boolean isChanged = true; while (isChanged) { isChanged = false; isChanged |= updateInverseEqualities(); isChanged |= updateEqualitiesSubSuper(); isChanged |= updateTopEqualities(); isChanged |= updateSubSuperEqualities(); isChanged |= updateTopSubSuper(); isChanged |= propagateRoleProperties(); } } private boolean propagateRoleProperties() { boolean isChanged = false; isChanged |= propagateDown(RoleProperty.FUNCTIONAL); isChanged |= propagateDown(RoleProperty.INVERSE_FUNCTIONAL); isChanged |= propagateUp(RoleProperty.TRANSITIVE); isChanged |= propagateDown(RoleProperty.SYMMETRIC); return isChanged; } private boolean updateTopSubSuper() { boolean isChanged = false; final Collection<R> topRoles = getRoles(RoleProperty.TOP); if (topRoles != null) { for (R topRole : topRoles) { final RoleType topRoleType = getRoleType(topRole); if (getRoles(topRoleType) != null) { for (R otherRole : getRoles(topRoleType)) { if (!isSubRole(topRole, otherRole)) { _subRoles.put(topRole, otherRole); _superRoles.put(otherRole, topRole); isChanged = true; } } } } } return isChanged; } private boolean updateEqualitiesSubSuper() throws EInconsistentRBoxException { boolean isChanged = false; for (Map.Entry<R, R> subRoleEntry : MultiMapEntryIterable.decorate(_subRoles.entrySet())) { final R sup = subRoleEntry.getKey(); final R sub = subRoleEntry.getValue(); if (getRoleType(sub) != getRoleType(sup)) { throw new EInconsistentRBoxException(_assertedRBox, String.format("Roles `%s' and `%s' are subroles, but not of the same type", sub, sup)); } if ((isSubRole(sub, sup)) && (!isEquivalentRole(sub, sup))) { _equivalentRoles.put(sub, sup); _equivalentRoles.put(sup, sub); isChanged = true; } } return isChanged; } private boolean updateTopEqualities() { boolean isChanged = false; final Collection<R> topAdds = new TreeSet<>(); if (getRoles(RoleProperty.TOP) != null) { for (R topRole : getRoles(RoleProperty.TOP)) { for (R topEq : getEquivalentRoles(topRole)) { if (!hasRoleProperty(topEq, RoleProperty.TOP)) { topAdds.add(topEq); isChanged = true; } } } } if (!topAdds.isEmpty()) { for (R topAdd : topAdds) { _propertyRoleMap.put(RoleProperty.TOP, topAdd); _rolePropertyMap.put(topAdd, RoleProperty.TOP); } isChanged = true; } return isChanged; } private boolean updateSubSuperEqualities() throws EInconsistentRBoxException { boolean isChanged = false; for (Map.Entry<R, R> eq : MultiMapEntryIterable.decorate(_equivalentRoles)) { if (getRoleType(eq.getKey()) != getRoleType(eq.getValue())) { throw new EInconsistentRBoxException(_assertedRBox, String.format( "Roles `%s' and `%s' are equal, but of different type", eq.getKey(), eq.getValue())); } if (isInverseRole(eq.getKey(), eq.getValue())) { throw new EInconsistentRBoxException(_assertedRBox, String.format( "Roles `%s' and `%s' are inverses and cannot be equal", eq.getKey(), eq.getValue())); } if (!isSubRole(eq.getKey(), eq.getValue())) { _subRoles.put(eq.getKey(), eq.getValue()); isChanged = true; } if (!isSuperRole(eq.getKey(), eq.getValue())) { _superRoles.put(eq.getKey(), eq.getValue()); isChanged = true; } } return isChanged; } private boolean updateInverseEqualities() throws EInconsistentRBoxException { final Collection<Map.Entry<R, R>> addList = new HashSet<>(); boolean isChanged = false; /** * Iterate through all inverses * */ for (Map.Entry<R, R> invEntry : MultiMapEntryIterable.decorate(_inverseRoles.entrySet())) { final R first = invEntry.getValue(); final R second = invEntry.getKey(); if (!hasRoleType(first, RoleType.OBJECT_PROPERTY)) { throw new EInconsistentRBoxException(_assertedRBox, String.format("Role `%s' has an inverse, but is not an object property", first)); } if (isEquivalentRole(first, second)) { throw new EInconsistentRBoxException(_assertedRBox, String.format("Roles `%s' and `%s' are both inverses and equal", first, second)); } /** * All roles equal to the second role are inverses to the first role, too. * */ final Collection<R> secondEqs = getEquivalentRoles(second); for (R secondEq : secondEqs) { if (!isInverseRole(first, secondEq)) { if (isEquivalentRole(first, secondEq)) { if (isInverseRole(first, secondEq)) { throw new EInconsistentRBoxException(_assertedRBox, String.format( "Roles `%s' and `%s' are equal and cannot be inverses", first, secondEq)); } } addList.add(new DefaultMapEntry<>(first, secondEq)); } } /** * Inverses of the second (= inverses of the inverses of the first role) are equal to the first role. */ final Collection<R> invInvs = getInverseRoles(second); if (invInvs != null) { for (R invInv : invInvs) { final Collection<R> invInvEqs = getEquivalentRoles(invInv); for (R invInvEq : invInvEqs) { if (isInverseRole(first, invInvEq)) { throw new EInconsistentRBoxException(_assertedRBox, String.format( "Roles `%s' and `%s' are inverses and cannot be equal", first, invInvEq)); } if (!isEquivalentRole(first, invInvEq)) { _equivalentRoles.put(first, invInvEq); isChanged = true; } } } } } if (!addList.isEmpty()) { for (Map.Entry<R, R> invAddEntry : addList) { _inverseRoles.put(invAddEntry.getKey(), invAddEntry.getValue()); _inverseRoles.put(invAddEntry.getValue(), invAddEntry.getKey()); } isChanged = true; } return isChanged; } private void addCommutativeInverses() { final Collection<Map.Entry<R, R>> addList = new HashSet<>(); for (Map.Entry<R, R> invEntry : MultiMapEntryIterable.decorate(_inverseRoles.entrySet())) { if (!_inverseRoles.containsValue(invEntry.getValue(), invEntry.getKey())) { addList.add(invEntry); } } for (Map.Entry<R, R> addItem : addList) { _inverseRoles.put(addItem.getKey(), addItem.getValue()); } } private void addCommutativeEqualities() { final Collection<Map.Entry<R, R>> addList = new HashSet<>(); for (Map.Entry<R, R> invEntry : MultiMapEntryIterable.decorate(_equivalentRoles.entrySet())) { if (!_equivalentRoles.containsValue(invEntry.getValue(), invEntry.getKey())) { addList.add(invEntry); } } for (Map.Entry<R, R> addItem : addList) { _equivalentRoles.put(addItem.getKey(), addItem.getValue()); } } private void addSubSuper() { final Collection<Map.Entry<R, R>> addList = new HashSet<>(); for (Map.Entry<R, R> invEntry : MultiMapEntryIterable.decorate(_subRoles.entrySet())) { if (!_superRoles.containsValue(invEntry.getValue(), invEntry.getKey())) { addList.add(invEntry); } } for (Map.Entry<R, R> addItem : addList) { _superRoles.put(addItem.getKey(), addItem.getValue()); } addList.clear(); for (Map.Entry<R, R> invEntry : MultiMapEntryIterable.decorate(_superRoles.entrySet())) { if (!_subRoles.containsValue(invEntry.getValue(), invEntry.getKey())) { addList.add(invEntry); } } for (Map.Entry<R, R> addItem : addList) { _subRoles.put(addItem.getKey(), addItem.getValue()); } } private boolean propagateDown(final RoleProperty prop) { boolean isChanged = false; for (R superRole : _subRoles.keySet()) { if (hasRoleProperty(superRole, prop)) { for (R subRole : _subRoles.get(superRole)) { if (!hasRoleProperty(subRole, prop)) { _rolePropertyMap.put(subRole, prop); _propertyRoleMap.put(prop, subRole); isChanged = true; } } } } return isChanged; } private boolean propagateUp(final RoleProperty prop) { boolean isChanged = false; for (R subRole : _superRoles.keySet()) { if (hasRoleProperty(subRole, prop)) { for (R superRole : _superRoles.get(subRole)) { if (!hasRoleProperty(superRole, prop)) { _rolePropertyMap.put(superRole, prop); _propertyRoleMap.put(prop, superRole); isChanged = true; } } } } return isChanged; } }