All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.semanticweb.elk.reasoner.indexing.classes.DifferentialIndex Maven / Gradle / Ivy

There is a newer version: 0.29.0
Show newest version
/*
 * #%L
 * ELK Reasoner
 * 
 * $Id$
 * $HeadURL$
 * %%
 * Copyright (C) 2011 - 2012 Department of Computer Science, University of Oxford
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package org.semanticweb.elk.reasoner.indexing.classes;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

import org.semanticweb.elk.owl.interfaces.ElkAxiom;
import org.semanticweb.elk.owl.interfaces.ElkClass;
import org.semanticweb.elk.owl.interfaces.ElkNamedIndividual;
import org.semanticweb.elk.owl.interfaces.ElkObjectProperty;
import org.semanticweb.elk.owl.predefined.PredefinedElkEntityFactory;
import org.semanticweb.elk.reasoner.indexing.conversion.ElkUnexpectedIndexingException;
import org.semanticweb.elk.reasoner.indexing.model.IndexedClass;
import org.semanticweb.elk.reasoner.indexing.model.IndexedClassExpression;
import org.semanticweb.elk.reasoner.indexing.model.IndexedDefinedClass;
import org.semanticweb.elk.reasoner.indexing.model.IndexedEntity;
import org.semanticweb.elk.reasoner.indexing.model.IndexedIndividual;
import org.semanticweb.elk.reasoner.indexing.model.IndexedObjectProperty;
import org.semanticweb.elk.reasoner.indexing.model.IndexedPredefinedClass;
import org.semanticweb.elk.reasoner.indexing.model.ModifiableIndexedClassExpression;
import org.semanticweb.elk.reasoner.indexing.model.ModifiableIndexedDefinedClass;
import org.semanticweb.elk.reasoner.indexing.model.StructuralIndexedSubObject;
import org.semanticweb.elk.reasoner.saturation.rules.Rule;
import org.semanticweb.elk.reasoner.saturation.rules.contextinit.ChainableContextInitRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.ChainableSubsumerRule;
import org.semanticweb.elk.util.collections.ArrayHashMap;
import org.semanticweb.elk.util.collections.ArrayHashSet;
import org.semanticweb.elk.util.collections.Operations;
import org.semanticweb.elk.util.collections.chains.AbstractChain;
import org.semanticweb.elk.util.collections.chains.Chain;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * An object representing incremental changes in the index. The changes are
 * stored in two maps: additions and deletions. The map for additions assigns to
 * every {@link IndexedClassExpression} new rules to be added to the index;
 * likewise, the map of deletions assigns to every
 * {@link IndexedClassExpression} a new rules to be removed from the index.
 * 
 * @author "Yevgeny Kazakov"
 * @author Pavel Klinov
 * 
 */
public class DifferentialIndex extends DirectIndex {

	private static final Logger LOGGER_ = LoggerFactory
			.getLogger(DifferentialIndex.class);

	/**
	 * if {@code true} all changes will be applied incrementally; otherwise
	 * changes are applied directly
	 */
	boolean incrementalMode = false;

	/**
	 * added and removed {@link ElkClass}es during the last incremental session
	 */
	private Set addedClasses_, removedClasses_;

	/**
	 * added and removed {@link ElkNamedIndividual}s during the last incremental
	 * session
	 */
	private Set addedIndividuals_, removedIndividuals_;

	/**
	 * added and removed {@link ElkObjectProperty}ies during the last
	 * incremental session
	 */
	private Set addedObjectProperties_,
			removedObjectProperties_;

	private final IndexedEntity.Visitor entityInsertionListener_ = new EntityInsertionListener(),
			entityDeletionListener_ = new EntityDeletionListener();

	/**
	 * Pending deletions of {@link StructuralIndexedSubObject}s
	 */
	private Set> todoDeletions_;

	/**
	 * The added and removed initialization {@link Rule}s
	 */
	private ChainableContextInitRule addedContextInitRules_,
			removedContextInitRules_;

	/**
	 * The maps of added and removed {@link Rule}s for index class expressions;
	 */
	private Map addedContextRuleHeadByClassExpressions_,
			removedContextRuleHeadByClassExpressions_;

	private Map addedDefinitions_,
			removedDefinitions_;

	private Map addedDefinitionReasons_,
			removedDefinitionReasons_;

	public DifferentialIndex(final PredefinedElkEntityFactory elkFactory) {
		super(elkFactory);
		init();
	}

	/**
	 * Initializes all data structures
	 */
	void init() {
		initClassChanges();
		initIndividualChanges();
		initObjectPropertyChanges();
		initAdditions();
		initDeletions();
	}

	public void initClassChanges() {
		this.addedClasses_ = new ArrayHashSet<>(32);
		this.removedClasses_ = new ArrayHashSet<>(32);
	}

	public void initIndividualChanges() {
		this.addedIndividuals_ = new ArrayHashSet<>(32);
		this.removedIndividuals_ = new ArrayHashSet<>(32);
	}

	public void initObjectPropertyChanges() {
		this.addedObjectProperties_ = new ArrayHashSet<>(32);
		this.removedObjectProperties_ = new ArrayHashSet<>(32);
	}

	public void initAdditions() {
		this.addedContextInitRules_ = null;
		this.addedContextRuleHeadByClassExpressions_ = new ArrayHashMap<>(32);
		this.addedDefinitions_ = new ArrayHashMap<>(32);
		this.addedDefinitionReasons_ = new ArrayHashMap<>(32);
	}

	public void initDeletions() {
		this.removedContextInitRules_ = null;
		this.todoDeletions_ = new ArrayHashSet>(
				1024);
		this.removedContextRuleHeadByClassExpressions_ = new ArrayHashMap<>(32);
		this.removedDefinitions_ = new ArrayHashMap<>(32);
		this.removedDefinitionReasons_ = new ArrayHashMap<>(32);
	}

	/* read-only methods */

	// nothing so far

	/* read-write methods */

	@Override
	public void add(StructuralIndexedSubObject input) {
		if (!incrementalMode) {
			super.add(input);
			return;
		}
		// else incrementalMode
		LOGGER_.trace("{}: to add", input);
		if (input instanceof IndexedEntity)
			((IndexedEntity) input).accept(entityInsertionListener_);
		if (todoDeletions_.remove(input))
			return;
		// else
		super.add(input);
	}

	@Override
	public void remove(StructuralIndexedSubObject input) {
		if (!incrementalMode) {
			super.remove(input);
			return;
		}
		// else incrementalMode
		LOGGER_.trace("{}: to remove", input);
		if (input instanceof IndexedEntity)
			((IndexedEntity) input).accept(entityDeletionListener_);
		todoDeletions_.add(input);
	}

	private class EntityInsertionListener implements IndexedEntity.Visitor {

		Void defaultVisit(IndexedClass element) {
			ElkClass entity = element.getElkEntity();
			if (!removedClasses_.remove(entity))
				addedClasses_.add(entity);
			return null;
		}
		
		@Override
		public Void visit(IndexedDefinedClass element) {
			return defaultVisit(element);
		}
		
		@Override
		public Void visit(IndexedPredefinedClass element) {
			return defaultVisit(element);
		}

		@Override
		public Void visit(IndexedIndividual element) {
			ElkNamedIndividual entity = element.getElkEntity();
			if (!removedIndividuals_.remove(entity))
				addedIndividuals_.add(entity);
			return null;
		}

		@Override
		public Void visit(IndexedObjectProperty element) {
			ElkObjectProperty entity = element.getElkEntity();
			if (!removedObjectProperties_.remove(entity))
				addedObjectProperties_.add(entity);
			return null;
		}

	}

	private class EntityDeletionListener implements IndexedEntity.Visitor {

		Void defaultVisit(IndexedClass element) {
			ElkClass entity = element.getElkEntity();
			if (!addedClasses_.remove(entity))
				removedClasses_.add(entity);
			return null;
		}
		
		@Override
		public Void visit(IndexedDefinedClass element) {
			return defaultVisit(element);
		}
		
		@Override
		public Void visit(IndexedPredefinedClass element) {
			return defaultVisit(element);
		}

		@Override
		public Void visit(IndexedIndividual element) {
			ElkNamedIndividual entity = element.getElkEntity();
			if (!addedIndividuals_.remove(entity))
				removedIndividuals_.add(entity);
			return null;
		}

		@Override
		public Void visit(IndexedObjectProperty element) {
			ElkObjectProperty entity = element.getElkEntity();
			if (!addedObjectProperties_.remove(entity))
				removedObjectProperties_.add(entity);
			return null;
		}
	}

	@Override
	public boolean add(ModifiableIndexedClassExpression target,
			ChainableSubsumerRule newRule) {
		if (!incrementalMode) {
			return super.add(target, newRule);
		}
		// else incrementalMode
		if (newRule.removeFrom(getRemovedContextRuleChain(target))) {
			if (newRule.addTo(target.getCompositionRuleChain()))
				return true;
			// else revert
			newRule.addTo(getRemovedContextRuleChain(target));
		}
		// if above fails
		return newRule.addTo(getAddedContextRuleChain(target));
	}

	@Override
	public boolean remove(ModifiableIndexedClassExpression target,
			ChainableSubsumerRule oldRule) {
		if (!incrementalMode) {
			return super.remove(target, oldRule);
		}
		// else incrementalMode
		if (oldRule.removeFrom(getAddedContextRuleChain(target)))
			return true;
		// else
		if (oldRule.addTo(getRemovedContextRuleChain(target))) {
			if (oldRule.removeFrom(target.getCompositionRuleChain()))
				return true;
			// else revert
			oldRule.removeFrom(getRemovedContextRuleChain(target));
		}
		return false;
	}

	@Override
	public boolean tryAddDefinition(ModifiableIndexedDefinedClass target,
			ModifiableIndexedClassExpression definition, ElkAxiom reason) {
		if (!incrementalMode)
			return super.tryAddDefinition(target, definition, reason);
		// for incremental mode:
		IndexedClassExpression removedDefintion = removedDefinitions_
				.get(target);
		ElkAxiom removedDefinitionReason = removedDefinitionReasons_
				.get(target);
		if (target.getDefinition() != removedDefintion
				|| addedDefinitions_.get(target) != null) {
			// the existing definition was not removed or some definition has
			// been added
			return false;
		}
		// else removing
		if (removedDefintion == definition
				&& removedDefinitionReason.equals(reason)) {
			removedDefinitions_.remove(target);
			removedDefinitionReasons_.remove(target);
			target.setDefinition(definition, reason);
		} else {
			addedDefinitions_.put(target, definition);
			addedDefinitionReasons_.put(target, reason);
		}
		return true;
	}

	@Override
	public boolean tryRemoveDefinition(ModifiableIndexedDefinedClass target,
			ModifiableIndexedClassExpression definition, ElkAxiom reason) {
		if (!incrementalMode)
			return super.tryRemoveDefinition(target, definition, reason);
		// for incremental mode:
		IndexedClassExpression addedDefinition = addedDefinitions_.get(target);
		ElkAxiom addedDefinitionReason = addedDefinitionReasons_.get(target);
		if (addedDefinition == definition
				&& addedDefinitionReason.equals(reason)) {
			addedDefinitions_.remove(target);
			addedDefinitionReasons_.remove(target);
			return true;
		}
		// else
		if (addedDefinition != null || target.getDefinition() != definition
				|| !target.getDefinitionReason().equals(reason))
			return false;
		// else
		target.removeDefinition();
		removedDefinitions_.put(target, definition);
		removedDefinitionReasons_.put(target, reason);
		return true;
	}

	@Override
	public boolean addContextInitRule(ChainableContextInitRule newRule) {
		if (!incrementalMode) {
			return super.addContextInitRule(newRule);
		}
		// else incrementalMode
		if (newRule.removeFrom(getRemovedContextInitRuleChain())) {
			if (newRule.addTo(getContextInitRuleChain()))
				return true;
			// else revert
			newRule.addTo(getRemovedContextInitRuleChain());
		}
		// if above fails
		return newRule.addTo(getAddedContextInitRuleChain());
	}

	@Override
	public boolean removeContextInitRule(ChainableContextInitRule oldRule) {
		if (!incrementalMode) {
			return super.removeContextInitRule(oldRule);
		}
		// else incrementalMode
		if (oldRule.removeFrom(getAddedContextInitRuleChain()))
			return true;
		// else
		if (oldRule.addTo(getRemovedContextInitRuleChain())) {
			if (oldRule.removeFrom(getContextInitRuleChain()))
				return true;
			// else revert
			oldRule.removeFrom(getRemovedContextInitRuleChain());
		}
		return false;
	}

	/* incremental-specific methods */

	/**
	 * @return the context initialization rules added during the last
	 *         incremental session
	 */
	public ChainableContextInitRule getAddedContextInitRules() {
		return addedContextInitRules_;
	}

	/**
	 * @return the context initialization rules removed during the last
	 *         incremental session
	 */
	public ChainableContextInitRule getRemovedContextInitRules() {
		return removedContextInitRules_;
	}

	/**
	 * @return the map from indexed class expressions to the corresponding
	 *         objects containing index additions for these class expressions
	 */
	public Map getAddedContextRulesByClassExpressions() {
		return this.addedContextRuleHeadByClassExpressions_;
	}

	/**
	 * @return the map from indexed class expressions to the corresponding
	 *         objects containing index deletions for these class expressions
	 */
	public Map getRemovedContextRulesByClassExpressions() {
		return this.removedContextRuleHeadByClassExpressions_;
	}

	/**
	 * @return the added definitions for {@link IndexedClass}es
	 */
	public Map getAddedDefinitions() {
		return this.addedDefinitions_;
	}

	/**
	 * @return the {@link ElkAxiom}s from which the added definitions for the
	 *         corresponding {@link IndexedClass}es originate
	 */
	public Map getAddedDefinitionReasons() {
		return this.addedDefinitionReasons_;
	}

	/**
	 * @return the removed definitions for {@link IndexedClass}es
	 */
	public Map getRemovedDefinitions() {
		return this.removedDefinitions_;
	}

	/**
	 * @return the {@link ElkAxiom}s from which the removed definitions for the
	 *         corresponding {@link IndexedClass}es originate
	 */
	public Map getRemovedDefinitionReasons() {
		return this.removedDefinitionReasons_;
	}

	/**
	 * @return the {@link ElkClass} added during the last incremental session
	 */
	public Collection getAddedClasses() {
		return this.addedClasses_;
	}

	/**
	 * @return the collection of named individuals added to the signature
	 */
	public Collection getAddedIndividuals() {
		return this.addedIndividuals_;
	}

	/**
	 * @return the {@link IndexedClassExpression}s removed during the last
	 *         incremental session
	 */
	public Iterable getRemovedClassExpressions() {
		return Operations.filter(todoDeletions_, IndexedClassExpression.class);
	}

	/**
	 * Removes the deleted rules from this {@link DifferentialIndex}; these
	 * rules should be already applied in the main index during their
	 * registration
	 */
	public void clearDeletedRules() {
		for (StructuralIndexedSubObject deletion : todoDeletions_) {
			LOGGER_.trace("{}: comitting removal", deletion);
			super.remove(deletion);
		}
		initDeletions();
	}

	/**
	 * Commits the added rules to the main index and removes them from this
	 * {@link DifferentialIndex}.
	 */
	public void commitAddedRules() {
		// commit changes in the context initialization rules
		ChainableContextInitRule nextContextInitRule;
		Chain contextInitRuleChain;

		nextContextInitRule = addedContextInitRules_;
		contextInitRuleChain = getContextInitRuleChain();
		while (nextContextInitRule != null) {
			nextContextInitRule.addTo(contextInitRuleChain);
			nextContextInitRule = nextContextInitRule.next();
		}

		// commit changes in rules for IndexedClassExpression
		ChainableSubsumerRule nextClassExpressionRule;
		Chain classExpressionRuleChain;
		for (ModifiableIndexedClassExpression target : addedContextRuleHeadByClassExpressions_
				.keySet()) {
			LOGGER_.trace("{}: committing context rule additions", target);

			nextClassExpressionRule = addedContextRuleHeadByClassExpressions_
					.get(target);
			classExpressionRuleChain = target.getCompositionRuleChain();
			while (nextClassExpressionRule != null) {
				nextClassExpressionRule.addTo(classExpressionRuleChain);
				nextClassExpressionRule = nextClassExpressionRule.next();
			}
		}
		for (ModifiableIndexedDefinedClass target : addedDefinitions_.keySet()) {
			ModifiableIndexedClassExpression definition = addedDefinitions_
					.get(target);
			ElkAxiom reason = addedDefinitionReasons_.get(target);
			LOGGER_.trace("{}: committing definition addition {}", target,
					definition);
			if (!target.setDefinition(definition, reason))
				throw new ElkUnexpectedIndexingException(target);
		}
		initAdditions();
	}

	/**
	 * @return {@code true} if there are no uncommitted changes in this
	 *         {@link DifferentialIndex}
	 */
	public boolean isFullyCommitted() {
		return addedContextInitRules_ == null
				&& removedContextInitRules_ == null
				&& (addedContextRuleHeadByClassExpressions_ == null || addedContextRuleHeadByClassExpressions_
						.isEmpty())
				&& (removedContextRuleHeadByClassExpressions_ == null || removedContextRuleHeadByClassExpressions_
						.isEmpty());
	}

	/**
	 * Sets the incremental mode for this {@code DifferentialIndex}.
	 * 
	 * @param incremental
	 *            if {@code true}, deletions and additions to this indexed are
	 *            stored separately; if {@code false} all changes are
	 *            immediately applied to the index.
	 */
	public void setIncrementalMode(boolean incremental) {
		if (this.incrementalMode == incremental)
			// already set
			return;
		LOGGER_.trace("set incremental mode: " + incremental);
		this.incrementalMode = incremental;
		if (!incremental) {
			clearDeletedRules();
			commitAddedRules();
			initClassChanges();
			initIndividualChanges();
		}
	}

	/**
	 * @return the current value of the incremental mode for this
	 *         {@code DifferentialIndex}
	 * @see #setIncrementalMode(boolean)
	 */
	public boolean isIncrementalMode() {
		return incrementalMode;
	}

	/**
	 * @return the chain of added context initialization rules suitable for
	 *         modifications (addition or deletions) of rules
	 */
	private Chain getAddedContextInitRuleChain() {
		return new AbstractChain() {

			@Override
			public ChainableContextInitRule next() {
				return addedContextInitRules_;
			}

			@Override
			public void setNext(ChainableContextInitRule tail) {
				addedContextInitRules_ = tail;
			}
		};
	}

	/**
	 * @return the chain of removed context initialization rules suitable for
	 *         modifications (addition or deletions) of rules
	 */
	private Chain getRemovedContextInitRuleChain() {
		return new AbstractChain() {

			@Override
			public ChainableContextInitRule next() {
				return removedContextInitRules_;
			}

			@Override
			public void setNext(ChainableContextInitRule tail) {
				removedContextInitRules_ = tail;
			}
		};
	}

	/**
	 * @param target
	 *            the {@link IndexedClassExpression} for which to return the
	 *            chain of added context rules
	 * 
	 * @return the chain of added context rules for the given
	 *         {@link IndexedClassExpression} that is suitable for modifications
	 *         (addition or deletions) of rules
	 */
	private Chain getAddedContextRuleChain(
			final ModifiableIndexedClassExpression target) {
		return AbstractChain.getMapBackedChain(
				addedContextRuleHeadByClassExpressions_, target);
	}

	/**
	 * @param target
	 *            the {@link IndexedClassExpression} for which to return the
	 *            chain of removed context rules
	 * 
	 * @return the chain of removed context rules for the given
	 *         {@link IndexedClassExpression} that is suitable for modifications
	 *         (addition or deletions) of rules
	 */
	private Chain getRemovedContextRuleChain(
			final ModifiableIndexedClassExpression target) {
		return AbstractChain.getMapBackedChain(
				removedContextRuleHeadByClassExpressions_, target);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy