/*
 * #%L
 * ELK Reasoner
 * $Id:$
 * $HeadURL:$
 * %%
 * Copyright (C) 2011 - 2016 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.stages;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.semanticweb.elk.loading.AbstractClassQueryLoader;
import org.semanticweb.elk.loading.ClassQueryLoader;
import org.semanticweb.elk.loading.ElkLoadingException;
import org.semanticweb.elk.owl.interfaces.ElkClass;
import org.semanticweb.elk.owl.interfaces.ElkClassExpression;
import org.semanticweb.elk.owl.interfaces.ElkNamedIndividual;
import org.semanticweb.elk.owl.interfaces.ElkObject;
import org.semanticweb.elk.owl.predefined.PredefinedElkClassFactory;
import org.semanticweb.elk.owl.visitors.ElkClassExpressionProcessor;
import org.semanticweb.elk.reasoner.config.ReasonerConfiguration;
import org.semanticweb.elk.reasoner.indexing.conversion.ElkIndexingUnsupportedException;
import org.semanticweb.elk.reasoner.indexing.conversion.ElkPolarityExpressionConverter;
import org.semanticweb.elk.reasoner.indexing.conversion.ElkPolarityExpressionConverterImpl;
import org.semanticweb.elk.reasoner.indexing.model.IndexedClass;
import org.semanticweb.elk.reasoner.indexing.model.IndexedClassExpression;
import org.semanticweb.elk.reasoner.indexing.model.IndexedContextRoot;
import org.semanticweb.elk.reasoner.indexing.model.IndexedIndividual;
import org.semanticweb.elk.reasoner.indexing.model.IndexingListener;
import org.semanticweb.elk.reasoner.indexing.model.ModifiableOntologyIndex;
import org.semanticweb.elk.reasoner.indexing.model.Occurrence;
import org.semanticweb.elk.reasoner.indexing.model.OccurrenceStore;
import org.semanticweb.elk.reasoner.query.ElkQueryException;
import org.semanticweb.elk.reasoner.query.QueryNode;
import org.semanticweb.elk.reasoner.reduction.TransitiveReductionOutputEquivalent;
import org.semanticweb.elk.reasoner.reduction.TransitiveReductionOutputEquivalentDirect;
import org.semanticweb.elk.reasoner.reduction.TransitiveReductionOutputUnsatisfiable;
import org.semanticweb.elk.reasoner.reduction.TransitiveReductionOutputVisitor;
import org.semanticweb.elk.reasoner.saturation.SaturationState;
import org.semanticweb.elk.reasoner.saturation.SaturationStateDummyChangeListener;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.ClassInconsistency;
import org.semanticweb.elk.reasoner.saturation.context.Context;
import org.semanticweb.elk.reasoner.taxonomy.ElkClassKeyProvider;
import org.semanticweb.elk.reasoner.taxonomy.model.InstanceNode;
import org.semanticweb.elk.reasoner.taxonomy.model.InstanceTaxonomy;
import org.semanticweb.elk.reasoner.taxonomy.model.Node;
import org.semanticweb.elk.reasoner.taxonomy.model.Taxonomy;
import org.semanticweb.elk.reasoner.taxonomy.model.TaxonomyNode;
import org.semanticweb.elk.reasoner.taxonomy.model.TypeNode;
import org.semanticweb.elk.util.collections.ArrayHashMap;
import org.semanticweb.elk.util.collections.ArrayHashSet;
import org.semanticweb.elk.util.collections.Evictor;
import org.semanticweb.elk.util.collections.Operations;
import org.semanticweb.elk.util.concurrent.computation.InterruptMonitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Predicate;

/**
 * Keeps track of class expressions that were queried for satisfiability,
 * equivalent classes, super-classes or sub-classes.
 *
 * @author Peter Skocovsky
 */
public class ClassExpressionQueryState implements ClassQueryLoader.Factory {

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

	/**
	 * Maps class expressions that were queried to the states of their query.
	 * The values must be superset of values of {@link #indexed_}.
	 */
	private final Map<ElkClassExpression, QueryState> queried_ = new ConcurrentHashMap<ElkClassExpression, QueryState>();

	/**
	 * Contains class expressions that were queried but not loaded. This is an
	 * overestimation of class expressions that need to be loaded, because some
	 * of them may not have states.
	 */
	private final Queue<ElkClassExpression> toLoad_ = new ConcurrentLinkedQueue<ElkClassExpression>();

	/**
	 * Maps results of indexing of queried class expressions to the states of
	 * their query. The values must have {@link QueryState#indexed} set to the
	 * keys.
	 */
	private final Map<IndexedClassExpression, QueryState> indexed_ = new ConcurrentHashMap<IndexedClassExpression, QueryState>();

	/**
	 * Manages eviction from {@link #queried_}.
	 */
	private final Evictor<ElkClassExpression> queriedEvictor_;

	/**
	 * The class expressions that were registered by the last call.
	 */
	private final Set<ElkClassExpression> lastQueries_ = new ArrayHashSet<ElkClassExpression>();

	/**
	 * State of the query of a particular class expression. There are four
	 * forbidden states:
	 *

	 *
when a class expression does not have a state, it must not be loaded,
	 *
when {@link #isLoaded} is {@code false} and {@link #indexed} is not
	 * {@code null},
	 *
when {@link #indexed} is {@code null} and {@link #isComputed} is
	 * {@code true}, and
	 *
when {@link #isComputed} is {@code false} and {@link #node} is not
	 * {@code null}.
	 *

	 *
	 * @author Peter Skocovsky
	 */
	private static class QueryState {
		/**
		 * Whether the queried class expression was loaded (whether it was
		 * attempted to index it). If this is {@code false}, then
		 * {@link #indexed} must be {@code null}.
		 */
		boolean isLoaded = false;
		/**
		 * Results of indexing of the queried class expression. If this is
		 * {@code null}, then {@link #isComputed} must be {@code false}.
		 */
		IndexedClassExpression indexed = null;
		/**
		 * Whether the query was computed. If this is {@code false}, then
		 * {@link #node} must be {@code null}.
		 */
		boolean isComputed = false;
		/**
		 * The result of the query. If {@link #isComputed} is {@code true} and
		 * this field is {@code null}, the query is unsatisfiable.
		 */
		QueryNode<ElkClass> node = null;
		/**
		 * How many times an {@link Occurrence} occurs in the query.
		 * {@code null} means no occurrences.
		 */
		Map<Occurrence, Integer> occurrences = null;
	}

	/**
	 * Maps atomic classes to queried indexed class expressions to which they
	 * are related, i.e., the atomic classes are equivalent to them, or their
	 * direct super-classes.
	 */
	private final Map<ElkClass, Collection<IndexedClassExpression>> queriesByRelated_ = new ConcurrentHashMap<ElkClass, Collection<IndexedClassExpression>>();

	private final SaturationState<? extends Context> saturationState_;

	private final ElkPolarityExpressionConverter resolvingExpressionConverter_;

	private final ClassInconsistency.Factory conclusionFactory_;

	public <C extends Context> ClassExpressionQueryState(
			final ReasonerConfiguration config,
			final SaturationState<C> saturationState,
			final PredefinedElkClassFactory elkFactory,
			final ModifiableOntologyIndex ontologyIndex,
			final ClassInconsistency.Factory conclusionFactory) {
		this.saturationState_ = saturationState;
		this.resolvingExpressionConverter_ = new ElkPolarityExpressionConverterImpl(
				elkFactory, ontologyIndex);
		this.conclusionFactory_ = conclusionFactory;
		saturationState
				.addListener(new SaturationStateDummyChangeListener<C>() {

					@Override
					public void contextMarkNonSaturated(final C context) {
						/*
						 * Saturation and context clean should not happen at the
						 * same time, so this should be thread-safe.
						 */
						final IndexedContextRoot root = context.getRoot();
						synchronized (queriesByRelated_) {
							if (root instanceof IndexedClass) {
								final IndexedClass ic = (IndexedClass) root;

								final Collection<IndexedClassExpression> queryClasses = queriesByRelated_
										.remove(ic.getElkEntity());
								if (queryClasses != null) {
									for (final IndexedClassExpression queryClass : queryClasses) {
										markNotComputed(queryClass);
									}
								}

							} else if (root instanceof IndexedClassExpression) {
								final IndexedClassExpression ice = (IndexedClassExpression) root;
								markNotComputed(ice);
							}
						}
					}

					@Override
					public void contextsClear() {
						for (final QueryState state : queried_.values()) {
							state.isComputed = false;
							state.node = null;
						}
						queriesByRelated_.clear();
					}

				});

		final Object builder = config.getParameter(
				ReasonerConfiguration.CLASS_EXPRESSION_QUERY_EVICTOR);
		LOGGER_.info("{} = {}",
				ReasonerConfiguration.CLASS_EXPRESSION_QUERY_EVICTOR, builder);
		this.queriedEvictor_ = ((Evictor.Builder) builder).build();
	}

	/**
	 * If the specified query was added to the index, this method marks it as
	 * computed. Does not modify the cached query results.
	 *
	 * @param queryClass
	 * @return query state iff the parameter was queried, added to the index,
	 *         and the query was not-computed just before the call and was
	 *         marked computed by this call, otherwise {@code null}.
	 */
	private QueryState markComputed(final IndexedClassExpression queryClass) {
		final QueryState state = indexed_.get(queryClass);
		if (state == null || state.isComputed) {
			return null;
		}
		state.isComputed = true;
		LOGGER_.trace("query computed {}", queryClass);
		return state;
	}

	/**
	 * If the specified query was added to the index, this method marks it as
	 * not-computed and deletes the query results.
	 *
	 * @param queryClass
	 * @return query state iff the parameter was queried, added to the index,
	 *         and the query was computed just before the call and was marked
	 *         not-computed by this call, otherwise {@code null}.
	 */
	private QueryState markNotComputed(
			final IndexedClassExpression queryClass) {
		final QueryState state = indexed_.get(queryClass);
		if (state == null || !state.isComputed) {
			return null;
		}
		state.isComputed = false;
		if (state.node != null) {
			removeAllRelated(queryClass, state.node);
			state.node = null;
		}
		return state;
	}

	/**
	 * Registers the supplied class expression for querying. If the expression
	 * has already been registered, returns {@code false}. Otherwise, if this
	 * state did not keep track of the expression yet, returns {@code true}. If
	 * all necessary stages are run after doing this, the result retrieval
	 * methods, e.g., {@link #isSatisfiable(ElkClassExpression)}, will not throw
	 * {@link ElkQueryException}.
	 *
	 * @param classExpression
	 * @return {@code true} if this is a new query, {@code false} if this class
	 *         expression has already been registered.
	 */
	boolean registerQuery(final ElkClassExpression classExpression) {

		LOGGER_.trace("class expression query registered {}", classExpression);

		lastQueries_.clear();
		queriedEvictor_.add(classExpression);
		lastQueries_.add(classExpression);

		QueryState state = queried_.get(classExpression);
		if (state != null) {
			return false;
		}
		// Create query state.
		state = new QueryState();
		queried_.put(classExpression, state);
		toLoad_.offer(classExpression);

		return true;
	}

	public IndexingListener getIndexingListener() {
		return indexingListener_;
	}

	@Override
	public ClassQueryLoader getQueryLoader(final InterruptMonitor interrupter) {
		return indexingListener_.new Loader(interrupter);
	}

	private final QueryIndexingListener indexingListener_ = new QueryIndexingListener();

	private class QueryIndexingListener implements IndexingListener {

		// Indexing state.
		private boolean isInsertion_;
		private QueryState beingIndexed_ = null;

		private void checkStateOnIndexing() throws IllegalStateException {
			if (beingIndexed_ == null) {
				throw new IllegalStateException(
						"Indexing listener notified while no query is being loaded!");
			}
		}

		public class Loader extends AbstractClassQueryLoader {
			public Loader(final InterruptMonitor interrupter) {
				super(interrupter);
			}

			@Override
			public void load(final ElkClassExpressionProcessor inserter,
					final ElkClassExpressionProcessor deleter)
					throws ElkLoadingException {

				// First evict and unload.
				isInsertion_ = false;
				final Iterator<ElkClassExpression> evicted = queriedEvictor_
						.evict(doNotEvict_);
				while (evicted.hasNext()) {
					final ElkClassExpression classExpression = evicted.next();
					final QueryState state = queried_.remove(classExpression);
					if (!state.isLoaded) {
						continue;
					}
					// else
					beingIndexed_ = state;
					deleter.visit(classExpression);
					if (state.indexed != null) {
						if (state.isComputed) {
							if (state.node != null) {
								removeAllRelated(state.indexed, state.node);
								state.node = null;
							}
						}
						indexed_.remove(state.indexed);
						state.indexed = null;
					}
				}

				/*
				 * Load all registered queries that are not loaded and assign
				 * state.indexed if successful.
				 */
				isInsertion_ = true;
				ElkClassExpression classExpression;
				while ((classExpression = toLoad_.poll()) != null) {
					final QueryState state = queried_.get(classExpression);
					if (state == null) {
						continue;
					}
					// else

					beingIndexed_ = state;
					inserter.visit(classExpression);
					state.isLoaded = true;

					try {
						final IndexedClassExpression ice = classExpression
								.accept(resolvingExpressionConverter_);
						state.indexed = ice;
						indexed_.put(state.indexed, state);
						LOGGER_.trace("query {} indexed as {}", classExpression,
								ice);

						// Check whether it is computed.
						final Context context = saturationState_
								.getContext(state.indexed);
						if (context != null && context.isInitialized()
								&& context.isSaturated()
								&& context.containsConclusion(conclusionFactory_
										.getContradiction(state.indexed))) {
							/*
							 * If the query is unsatisfiable, it is already
							 * computed ...
							 */
							state.isComputed = true;
							LOGGER_.trace("query computed {}", ice);
						} else {
							/*
							 * ... otherwise we need to compute the equivalent
							 * and super-classes
							 */
							state.isComputed = false;
						}
					} catch (final ElkIndexingUnsupportedException e) {
						state.indexed = null;
						LOGGER_.trace("query NOT indexed {}", classExpression);
					}

					if (isInterrupted()) {
						return;
					}
				}

			}

			@Override
			public boolean isLoadingFinished() {
				return toLoad_.isEmpty();
			}
		}

		@Override
		public void onIndexing(final Occurrence occurrence) {
			checkStateOnIndexing();
			if (isInsertion_) {
				if (beingIndexed_.occurrences == null) {
					beingIndexed_.occurrences = new ArrayHashMap<Occurrence, Integer>(
							4);
				}
				Integer noOccurrences = beingIndexed_.occurrences
						.get(occurrence);
				if (noOccurrences == null) {
					noOccurrences = 0;
				}
				noOccurrences++;
				beingIndexed_.occurrences.put(occurrence, noOccurrences);
			} else {
				if (beingIndexed_.occurrences == null) {
					return;
				}
				Integer noOccurrences = beingIndexed_.occurrences
						.get(occurrence);
				if (noOccurrences == null) {
					return;
				}
				noOccurrences--;
				if (noOccurrences <= 0) {
					beingIndexed_.occurrences.remove(occurrence);
					if (beingIndexed_.occurrences.isEmpty()) {
						beingIndexed_.occurrences = null;
					}
				} else {
					beingIndexed_.occurrences.put(occurrence, noOccurrences);
				}
			}
		}

	}

	private final Predicate<ElkClassExpression> doNotEvict_ = new Predicate<ElkClassExpression>() {
		@Override
		public boolean apply(final ElkClassExpression ce) {
			return lastQueries_.contains(ce);
		}
	};

	private final TransitiveReductionOutputVisitor<IndexedClassExpression> transitiveReductionOutputProcessor_ = new TransitiveReductionOutputVisitor<IndexedClassExpression>() {

		@Override
		public void visit(
				final TransitiveReductionOutputEquivalentDirect<IndexedClassExpression> output) {

			final IndexedClassExpression ice = output.getRoot();
			/*
			 * Saturation and "un-saturation" should not happen at the same
			 * time, so this should be thread-safe.
			 */
			final QueryState state = markComputed(ice);
			if (state == null) {
				return;
			}

			final List<ElkClass> equivalent = output.getEquivalent();
			final Collection<? extends List<ElkClass>> directSubsumers = output
					.getDirectSubsumers();

			final QueryNode<ElkClass> node = new QueryNode<ElkClass>(equivalent,
					equivalent.size(), ElkClassKeyProvider.INSTANCE);

			for (final List<ElkClass> directSubs : directSubsumers) {
				// direct subsumers should not be empty
				final QueryNode<ElkClass> directSuperNode = new QueryNode<ElkClass>(
						directSubs, directSubs.size(),
						ElkClassKeyProvider.INSTANCE);
				node.addDirectSuperNode(directSuperNode);
			}

			addAllRelated(ice, node);
			state.node = node;
		}

		@Override
		public void visit(
				final TransitiveReductionOutputUnsatisfiable<IndexedClassExpression> output) {

			final IndexedClassExpression ice = output.getRoot();
			/*
			 * Saturation and "un-saturation" should not happen at the same
			 * time, so this should be thread-safe.
			 */
			markComputed(ice);
		}

		@Override
		public void visit(
				final TransitiveReductionOutputEquivalent<IndexedClassExpression> output) {
			// transitive reduction computation should not produce these
			throw new IllegalArgumentException(
					"Unexpected output of transitive reduction!");
		}

	};

	private void addAllRelated(final IndexedClassExpression queryClass,
			final QueryNode<ElkClass> queryNode) {
		synchronized (queriesByRelated_) {
			// equivalent
			for (final ElkClass related : queryNode) {
				addRelated(queryClass, related);
			}
			// superclasses
			for (final Node<ElkClass> superNode : queryNode
					.getDirectSuperNodes()) {
				for (final ElkClass related : superNode) {
					addRelated(queryClass, related);
				}
			}
		}
	}

	private void addRelated(final IndexedClassExpression queryClass,
			final ElkClass related) {
		// Synchronized on queriesByRelated_ by caller.
		Collection<IndexedClassExpression> queryClasses = queriesByRelated_
				.get(related);
		if (queryClasses == null) {
			queryClasses = new ArrayHashSet<IndexedClassExpression>();
			queriesByRelated_.put(related, queryClasses);
		}
		queryClasses.add(queryClass);
	}

	private void removeAllRelated(final IndexedClassExpression queryClass,
			final QueryNode<ElkClass> queryNode) {
		synchronized (queriesByRelated_) {
			// equivalent
			for (final ElkClass related : queryNode) {
				removeRelated(queryClass, related);
			}
			// superclasses
			for (final Node<ElkClass> superNode : queryNode
					.getDirectSuperNodes()) {
				for (final ElkClass related : superNode) {
					removeRelated(queryClass, related);
				}
			}
		}
	}

	private void removeRelated(final IndexedClassExpression queryClass,
			final ElkClass related) {
		// Synchronized on queriesByRelated_ by caller.
		Collection<IndexedClassExpression> queryClasses = queriesByRelated_
				.get(related);
		if (queryClasses != null) {
			queryClasses.remove(queryClass);
			if (queryClasses.isEmpty()) {
				queriesByRelated_.remove(related);
			}
		}
	}

	/**
	 * @return processor of output of transitive reduction of the queried class
	 *         expressions.
	 */
	TransitiveReductionOutputVisitor<IndexedClassExpression> getTransitiveReductionOutputProcessor() {
		return transitiveReductionOutputProcessor_;
	}

	private final static Operations.Transformation<QueryState, IndexedClassExpression> notComputedIces_ = new Operations.Transformation<QueryState, IndexedClassExpression>() {
		@Override
		public IndexedClassExpression transform(final QueryState element) {
			if (element.isComputed) {
				return null;
			}
			return element.indexed;
		}
	};

	/**
	 * @return indexed class expressions that were queried and added to the
	 *         index, but not saturated.
	 */
	public Collection<IndexedClassExpression> getNotSaturatedQueriedClassExpressions() {
		return Operations.map(indexed_.values(), notComputedIces_);
	}

	/**
	 * @param classExpression
	 * @return whether the supplied class expression was indexed as a query.
	 */
	public boolean isIndexed(final ElkClassExpression classExpression) {
		final QueryState state = queried_.get(classExpression);
		return state != null && state.indexed != null;
	}

	/**
	 * @param classExpression
	 * @return whether the query result for the supplied class expression was
	 *         already computed.
	 */
	public boolean isComputed(final ElkClassExpression classExpression) {
		final QueryState state = queried_.get(classExpression);
		return state != null && state.isComputed;
	}

	private QueryState checkComputed(final ElkClassExpression classExpression)
			throws ElkQueryException {

		final QueryState state = queried_.get(classExpression);

		if (state != null && state.isComputed) {
			return state;
		}

		throw new ElkQueryException(
				"Query was not computed yet: " + classExpression);
	}

	OccurrenceStore getOccurrenceStore(
			final ElkClassExpression classExpression) {
		return new OccurrenceStore() {

			@Override
			public Collection<? extends ElkObject> occursIn(
					final Occurrence occurrence) {
				final QueryState state = queried_.get(classExpression);
				if (state == null || state.occurrences == null
						|| !state.occurrences.containsKey(occurrence)) {
					return Collections.emptySet();
				}
				// else
				return Collections.singleton(classExpression);
			}

		};
	}

	/**
	 * Checks whether the supplied class expression is satisfiable, if the
	 * result was already computed. If the class expression was not registered
	 * by {@link #registerQuery(ElkClassExpression)} or the appropriate stage
	 * was not completed yet, throws {@link ElkQueryException}.
	 *
	 * @param classExpression
	 * @return whether the supplied class expression is satisfiable.
	 * @throws ElkQueryException
	 *             if the result is not ready
	 */
	boolean isSatisfiable(final ElkClassExpression classExpression)
			throws ElkQueryException {
		final QueryState state = checkComputed(classExpression);
		return state.node != null;
	}

	/**
	 * Returns {@link Node} containing all {@link ElkClass}es equivalent to the
	 * supplied class expression, if it is satisfiable. Returns
	 * null otherwise. If the class expression was not registered
	 * by {@link #registerQuery(ElkClassExpression)} or the appropriate stage
	 * was not completed yet, throws {@link ElkQueryException}.
	 *
	 * @param classExpression
	 * @return atomic classes equivalent to the supplied class expression, if it
	 *         is satisfiable, otherwise null.
	 * @throws ElkQueryException
	 *             if the result is not ready
	 */
	Node<ElkClass> getEquivalentClasses(
			final ElkClassExpression classExpression) throws ElkQueryException {
		final QueryState state = checkComputed(classExpression);
		return state.node;
	}

	/**
	 * Returns set of {@link Node}s containing all {@link ElkClass}es that are
	 * direct strict super-classes of the supplied class expression, if it is
	 * satisfiable. Returns null otherwise. If the class expression
	 * was not registered by {@link #registerQuery(ElkClassExpression)} or the
	 * appropriate stage was not completed yet, throws {@link ElkQueryException}
	 * .
	 *
	 * @param classExpression
	 * @return atomic direct strict super-classes of the supplied class
	 *         expression, if it is satisfiable, otherwise null.
	 * @throws ElkQueryException
	 *             if the result is not ready
	 */
	Set<? extends Node<ElkClass>> getDirectSuperClasses(
			final ElkClassExpression classExpression) throws ElkQueryException {
		final QueryState state = checkComputed(classExpression);
		if (state.node == null) {
			return null;
		} else {
			return state.node.getDirectSuperNodes();
		}
	}

	/**
	 * Returns set of {@link Node}s containing all {@link ElkClass}es that are
	 * direct strict sub-classes of the supplied class expression, if it is
	 * satisfiable. Returns null otherwise. If the class expression
	 * was not registered by {@link #registerQuery(ElkClassExpression)} or the
	 * appropriate stage was not completed yet, throws {@link ElkQueryException}
	 * .
	 *
	 * @param classExpression
	 * @param taxonomy
	 * @return atomic direct strict sub-classes of the supplied class
	 *         expression, if it is satisfiable, otherwise null.
	 * @throws ElkQueryException
	 *             if the result is not ready
	 */
	Set<? extends Node<ElkClass>> getDirectSubClasses(
			final ElkClassExpression classExpression,
			final Taxonomy<ElkClass> taxonomy) throws ElkQueryException {

		final QueryState state = checkComputed(classExpression);
		if (state.node == null) {
			return null;
		}
		// else

		final Iterator<ElkClass> iter = state.node.iterator();
		if (iter.hasNext()) {
			final ElkClass cls = iter.next();
			return taxonomy.getNode(cls).getDirectSubNodes();
		}
		/*
		 * Else, if classExpression is not equivalent to any atomic class,
		 * direct atomic sub-classes of classExpression are atomic classes that
		 * have classExpression among their subsumers, but no other of their
		 * strict subsumers have classExpression among its subsumers.
		 */

		final Collection<? extends IndexedClass> allClasses = saturationState_
				.getOntologyIndex().getClasses();
		final Set<IndexedClass> strictSubclasses = new ArrayHashSet<IndexedClass>(
				allClasses.size());

		for (final IndexedClass ic : allClasses) {
			final Set<IndexedClassExpression> subsumers = ic.getContext()
					.getComposedSubsumers();
			if (subsumers.contains(state.indexed) && state.indexed.getContext()
					.getComposedSubsumers().size() != subsumers.size()) {
				// is subclass, but not equivalent
				strictSubclasses.add(ic);
			}
		}

		final Set<TaxonomyNode<ElkClass>> result = new ArrayHashSet<TaxonomyNode<ElkClass>>();

		for (final IndexedClass strictSubclass : strictSubclasses) {
			/*
			 * If some strict superclass of strictSubclass is a strict subclass
			 * of classExpression, strictSubclass is not direct.
			 *
			 * It is sufficient to check only direct superclasses of
			 * strictSubclass.
			 */
			boolean isDirect = true;
			for (final TaxonomyNode<ElkClass> superNode : taxonomy
					.getNode(strictSubclass.getElkEntity())
					.getDirectSuperNodes()) {
				final IndexedClassExpression superClass = superNode
						.getCanonicalMember()
						.accept(resolvingExpressionConverter_);
				if (strictSubclasses.contains(superClass)) {
					isDirect = false;
					break;
				}
			}

			if (isDirect) {
				result.add(taxonomy.getNode(strictSubclass.getElkEntity()));
			}
		}

		if (result.isEmpty()) {
			/*
			 * No indexed class has classExpression among its subsumers and
			 * classExpression is not equivalent to any atomic class, so the
			 * only subclass of classExpression is Nothing and it is direct.
			 */
			result.add(taxonomy.getBottomNode());
		}
		return Collections.unmodifiableSet(result);
	}

	/**
	 * Returns set of {@link Node}s containing all {@link ElkNamedIndividual}s
	 * that are direct instances of the supplied class expression, if it is
	 * satisfiable. Returns null otherwise. If the class expression
	 * was not registered by {@link #registerQuery(ElkClassExpression)} or the
	 * appropriate stage was not completed yet, throws {@link ElkQueryException}
	 * .
	 *
	 * @param classExpression
	 * @param taxonomy
	 * @return direct instances of the supplied class expression, if it is
	 *         satisfiable, otherwise null.
	 * @throws ElkQueryException
	 *             if the result is not ready
	 */
	Set<? extends Node<ElkNamedIndividual>> getDirectInstances(
			final ElkClassExpression classExpression,
			final InstanceTaxonomy<ElkClass, ElkNamedIndividual> taxonomy)
			throws ElkQueryException {

		final QueryState state = checkComputed(classExpression);
		if (state.node == null) {
			return null;
		}
		// else

		final Iterator<ElkClass> iter = state.node.iterator();
		if (iter.hasNext()) {
			final ElkClass cls = iter.next();
			return taxonomy.getNode(cls).getDirectInstanceNodes();
		}
		/*
		 * Else, if classExpression is not equivalent to any atomic class,
		 * direct instances of classExpression are instances that have
		 * classExpression among their subsumers, but no other of their strict
		 * subsumers have classExpression among its subsumers.
		 */

		final Collection<? extends IndexedIndividual> allIndividuals = saturationState_
				.getOntologyIndex().getIndividuals();
		final Set<IndexedIndividual> instances = new ArrayHashSet<IndexedIndividual>(
				allIndividuals.size());

		for (final IndexedIndividual ii : allIndividuals) {
			final Set<IndexedClassExpression> subsumers = ii.getContext()
					.getComposedSubsumers();
			if (subsumers.contains(state.indexed)) {
				instances.add(ii);
			}
		}

		final Set<InstanceNode<ElkClass, ElkNamedIndividual>> result = new ArrayHashSet<InstanceNode<ElkClass, ElkNamedIndividual>>();

		for (final IndexedIndividual instance : instances) {
			/*
			 * If some type of instance is a strict subclass of classExpression,
			 * instance is not direct.
			 *
			 * It is sufficient to check only direct types of instance.
			 */
			boolean isDirect = true;
			for (final TypeNode<ElkClass, ElkNamedIndividual> typeNode : taxonomy
					.getInstanceNode(instance.getElkEntity())
					.getDirectTypeNodes()) {
				final IndexedClassExpression type = typeNode
						.getCanonicalMember()
						.accept(resolvingExpressionConverter_);
				final Set<IndexedClassExpression> subsumers = type.getContext()
						.getComposedSubsumers();
				if (subsumers.contains(state.indexed)
						&& state.indexed.getContext().getComposedSubsumers()
								.size() != subsumers.size()) {
					// is subclass, but not equivalent
					isDirect = false;
					break;
				}
			}

			if (isDirect) {
				result.add(taxonomy.getInstanceNode(instance.getElkEntity()));
			}
		}

		return Collections.unmodifiableSet(result);
	}

}


package org.semanticweb.elk.reasoner.saturation.conclusions.classes;

import org.semanticweb.elk.Reference;

/*
 * #%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%
 */

import org.semanticweb.elk.reasoner.saturation.SaturationStateWriter;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.ClassConclusion;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.ContextInitialization;
import org.semanticweb.elk.reasoner.saturation.context.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A {@link ClassConclusion.Visitor} that adds the visited
 * {@link ClassConclusion} to the {@link Context} value of the provided
 * {@link Reference}. The visit method returns {@link true} if the
 * {@link Context} was modified as the result of this operation, i.e., the
 * {@link ClassConclusion} was not contained in the {@link Context}.
 * Additionally, when inserting {@link ContextInitialization} the
 * {@link Context} is marked as non-saturated using the provided
 * {@link SaturationStateWriter}.
 *
 * @see ClassConclusionDeletionVisitor
 * @see ClassConclusionOccurrenceCheckingVisitor
 *
 * @author "Yevgeny Kazakov"
 */
public class ClassConclusionInsertionVisitor
		extends
			DummyClassConclusionVisitor<Boolean> implements Reference<Context> {

	// logger for events
	private static final Logger LOGGER_ = LoggerFactory
			.getLogger(ClassConclusionInsertionVisitor.class);

	private final Reference<Context> contextRef_;

	private final SaturationStateWriter<?> writer_;

	public ClassConclusionInsertionVisitor(Reference<Context> contextRef,
			SaturationStateWriter<?> writer) {
		this.contextRef_ = contextRef;
		this.writer_ = writer;
	}

	@Override
	public Context get() {
		return contextRef_.get();
	}

	// TODO: make this by combining the visitor in order to avoid overheads when
	// logging is switched off
	@Override
	protected Boolean defaultVisit(ClassConclusion conclusion) {
		Context context = get();
		boolean result = context.addConclusion(conclusion);
		if (LOGGER_.isTraceEnabled()) {
			LOGGER_.trace("{}: inserting {}: {}", context, conclusion,
					result ? "success" : "failure");
		}
		return result;
	}

	@Override
	public Boolean visit(ContextInitialization conclusion) {
		Context context = get();
		if (context.containsConclusion(conclusion))
			return false;
		// else
		// Mark context as non-saturated if conclusion was not already
		// initialized. It is important to mark before we insert, otherwise
		// the context can be found initialized and saturated when it is not.
		writer_.markAsNotSaturated(context.getRoot());
		return defaultVisit(conclusion);
	}

}


package org.semanticweb.elk.benchmark.reasoning;

/*
 * #%L
 * ELK Benchmarking Package
 * $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%
 */

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
import java.util.Set;

import org.semanticweb.elk.benchmark.BenchmarkUtils;
import org.semanticweb.elk.benchmark.Metrics;
import org.semanticweb.elk.benchmark.Task;
import org.semanticweb.elk.benchmark.TaskException;
import org.semanticweb.elk.io.IOUtils;
import org.semanticweb.elk.loading.AbstractAxiomLoader;
import org.semanticweb.elk.loading.AxiomLoader;
import org.semanticweb.elk.loading.ElkLoadingException;
import org.semanticweb.elk.loading.Owl2ParserLoader;
import org.semanticweb.elk.owl.exceptions.ElkException;
import org.semanticweb.elk.owl.interfaces.ElkAxiom;
import org.semanticweb.elk.owl.interfaces.ElkClassAxiom;
import org.semanticweb.elk.owl.iris.ElkPrefix;
import org.semanticweb.elk.owl.parsing.Owl2ParseException;
import org.semanticweb.elk.owl.parsing.Owl2Parser;
import org.semanticweb.elk.owl.parsing.Owl2ParserAxiomProcessor;
import org.semanticweb.elk.owl.parsing.javacc.Owl2FunctionalStyleParserFactory;
import org.semanticweb.elk.owl.visitors.ElkAxiomProcessor;
import org.semanticweb.elk.reasoner.Reasoner;
import org.semanticweb.elk.reasoner.ReasonerFactory;
import org.semanticweb.elk.reasoner.config.ReasonerConfiguration;
import org.semanticweb.elk.reasoner.incremental.TestChangesLoader;
import org.semanticweb.elk.reasoner.stages.LoggingStageExecutor;
import org.semanticweb.elk.util.collections.ArrayHashSet;

/**
 * Used to evaluate effectiveness of incremental classification
 *
 * @author Pavel Klinov
 *
 *         pavel.klinov@uni-ulm.de
 */
public class IncrementalClassificationTask implements Task {

	protected final String ontologyFileName;
	protected final ReasonerConfiguration reasonerConfig;
	protected List<ElkAxiom> loadedAxioms = null;
	protected final int axiomsToChange;

	protected Reasoner incrementalReasoner = null;

	final static int REPEAT_NUMBER = 5;

	public IncrementalClassificationTask(String[] args) {
		ontologyFileName = args[0];
		axiomsToChange = args.length > 1 ? Integer.valueOf(args[1]) : -1;
		reasonerConfig = ReasonerConfiguration.getConfiguration();
	}

	@Override
	public String getName() {
		return "Incremental classification ["
				+ ontologyFileName.substring(ontologyFileName.lastIndexOf('/'))
				+ "]";
	}

	@Override
	public void postRun() throws TaskException {}

	@Override
	public void prepare() throws TaskException {
		File ontologyFile = BenchmarkUtils.getFile(ontologyFileName);

		loadedAxioms = new ArrayList<ElkAxiom>();
		incrementalReasoner = prepareReasoner(ontologyFile, true);
		incrementalReasoner.setAllowIncrementalMode(true);
	}

	protected Reasoner prepareReasoner(final File ontologyFile,
			final boolean saveAxioms) throws TaskException {
		InputStream stream = null;

		try {
			stream = new FileInputStream(ontologyFile);

			final Owl2Parser parser = new Owl2FunctionalStyleParserFactory()
					.getParser(stream);
			final AxiomLoader loader = new AbstractAxiomLoader() {

				@Override
				public void load(final ElkAxiomProcessor axiomInserter,
						ElkAxiomProcessor axiomDeleter)
						throws ElkLoadingException {

					ElkAxiomProcessor wrappedAxiomInserter = axiomInserter;
					if (saveAxioms) {
						wrappedAxiomInserter = new ElkAxiomProcessor() {

							@Override
							public void visit(ElkAxiom elkAxiom) {
								axiomInserter.visit(elkAxiom);

								if (passAxiom(elkAxiom)) {
									loadedAxioms.add(elkAxiom);
								}
							}
						};
					}
					new Owl2ParserLoader(parser).load(wrappedAxiomInserter,
							axiomDeleter);
				}

				@Override
				public boolean isLoadingFinished() {
					// TODO Auto-generated method stub
					return false;
				}
			};

			Reasoner reasoner = new ReasonerFactory().createReasoner(loader,
					new LoggingStageExecutor(), reasonerConfig);

			// reasoner.loadAxioms();

			return reasoner;
		} catch (Exception e) {
			throw new TaskException(e);
		} finally {
			IOUtils.closeQuietly(stream);
		}
	}

	protected List<ElkAxiom> loadAxioms(InputStream stream) throws IOException,
			Owl2ParseException {
		Owl2Parser parser = new Owl2FunctionalStyleParserFactory()
				.getParser(stream);
		final List<ElkAxiom> axioms = new ArrayList<ElkAxiom>();

		parser.accept(new Owl2ParserAxiomProcessor() {

			@Override
			public void visit(ElkPrefix elkPrefix) throws Owl2ParseException {
			}

			@Override
			public void visit(ElkAxiom elkAxiom) throws Owl2ParseException {
				axioms.add(elkAxiom);
			}

			@Override
			public void finish() throws Owl2ParseException {
			}
		});

		return axioms;
	}

	protected boolean passAxiom(ElkAxiom axiom) {
		return axiom instanceof ElkClassAxiom;
	}

	@Override
	public void run() throws TaskException {
		long seed = System.currentTimeMillis();
		Random rnd = new Random(seed);
		TestChangesLoader changeLoader = new TestChangesLoader();

		incrementalReasoner.registerAxiomLoader(changeLoader);

		for (int i = 0; i < REPEAT_NUMBER; i++) {
			try {
				// delete some axioms
				Set<ElkAxiom> deleted = getRandomSubset(loadedAxioms, rnd);

				// incremental changes
				remove(changeLoader, deleted);
				incrementalReasoner.getTaxonomyQuietly();
				// add the axioms back
				add(changeLoader, deleted);

				incrementalReasoner.getTaxonomyQuietly();
			} catch (ElkException e) {
				throw new TaskException(e);
			}
		}
	}

	/*
	 * can return a smaller subset than requested because one axiom can be
	 * randomly picked more than once
	 */
	protected Set<ElkAxiom> getRandomSubset(List<ElkAxiom> axioms, Random rnd) {
		int size = axiomsToChange > 0 ? axiomsToChange : Math.max(1,
				axioms.size() / 100);
		Set<ElkAxiom> subset = new ArrayHashSet<ElkAxiom>(size);

		if (size >= axioms.size()) {
			subset.addAll(axioms);
		} else {
			for (int i = 0; i < size; i++) {
				ElkAxiom axiom = axioms.get(rnd.nextInt(size));

				subset.add(axiom);
			}
		}

		return subset;
	}

	protected void add(TestChangesLoader loader, Collection<ElkAxiom> axiomList) {
		for (ElkAxiom axiom : axiomList) {
			loader.add(axiom);
		}
	}

	protected void remove(TestChangesLoader loader,
			Collection<ElkAxiom> axiomList) {
		for (ElkAxiom axiom : axiomList) {
			loader.remove(axiom);
		}
	}

	@Override
	public void dispose() {
		shutdown(incrementalReasoner);
	}

	protected void shutdown(Reasoner reasoner) {
		if (reasoner != null) {
			try {
				reasoner.shutdown();
			} catch (InterruptedException e) {
			}
		}
	}

	@Override
	public Metrics getMetrics() {
		// TODO Auto-generated method stub
		return null;
	}
}


/*
 * #%L
 * ELK Reasoner
 *
 * $Id$
 * $HeadURL$
 * %%
 * Copyright (C) 2011 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.taxonomy.hashing;

import org.semanticweb.elk.owl.interfaces.ElkEntity;
import org.semanticweb.elk.reasoner.taxonomy.model.Taxonomy;
import org.semanticweb.elk.util.hashing.HashGenerator;

/**
 * A class for computing the structural hash of a
 * Taxonomy. This is mainly useful during testing to check if the reasoner
 * produces the same taxonomy.
 *
 *
 * @author Frantisek Simancik
 * @author Markus Kroetzsch
 */
public class TaxonomyHasher {

	/**
	 * Compute the hash code of a taxonomy.
	 *
	 * @param taxonomy
	 * @return hash
	 */
	public static int hash(Taxonomy<? extends ElkEntity> taxonomy) {
		return HashGenerator.combineMultisetHash(true, taxonomy.getNodes(), TaxonomyNodeHasher.INSTANCE);
	}

}


/*
 * #%L
 * elk-reasoner
 *
 * $Id$
 * $HeadURL$
 * %%
 * Copyright (C) 2011 Oxford University Computing Laboratory
 * %%
 * 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%
 */
/**
 * @author Yevgeny Kazakov, May 15, 2011
 */
package org.semanticweb.elk.reasoner.taxonomy.impl;

import java.util.Collections;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.semanticweb.elk.owl.interfaces.ElkEntity;
import org.semanticweb.elk.reasoner.taxonomy.TaxonomyNodeUtils;
import org.semanticweb.elk.reasoner.taxonomy.model.GenericInstanceNode;
import org.semanticweb.elk.reasoner.taxonomy.model.GenericTypeNode;
import org.semanticweb.elk.reasoner.taxonomy.model.InstanceTaxonomy;
import org.semanticweb.elk.reasoner.taxonomy.model.Taxonomy;
import org.semanticweb.elk.util.collections.ArrayHashSet;
import org.semanticweb.elk.util.hashing.HashGenerator;

/**
 * Class for storing information about a class in the context of classification.
 * It is the main data container for {@link InstanceTaxonomy} objects. Like most
 * such data containers in ELK, it is read-only for public access but provides
 * package-private ways of modifying it. Modifications of this class happen in
 * implementations of {@link InstanceTaxonomy} only.
 *
 * @author Yevgeny Kazakov
 * @author Markus Kroetzsch
 * @author Peter Skocovsky
 *
 * @param <T>
 *            The type of members of associated type nodes.
 * @param <I>
 *            The type of members of this nodes.
 * @param <TN>
 *            The immutable type of type nodes with which this node may be
 *            associated.
 * @param <IN>
 *            The immutable type of instance nodes with which this node may be
 *            associated.
 * @param <UTN>
 *            The mutable type of type nodes with which this node may be
 *            associated.
 * @param <UIN>
 *            The mutable type of instance nodes with which this node may be
 *            associated.
 */
public abstract class IndividualNode<
				T extends ElkEntity,
				I extends ElkEntity,
				TN extends GenericTypeNode<T, I, TN, IN>,
				IN extends GenericInstanceNode<T, I, TN, IN>,
				UTN extends UpdateableTypeNode<T, I, TN, IN, UTN, UIN>,
				UIN extends UpdateableInstanceNode<T, I, TN, IN, UTN, UIN>
		>
		extends SimpleUpdateableNode<I>
		implements UpdateableInstanceNode<T, I, TN, IN, UTN, UIN> {

	// logger for events
	private static final Logger LOGGER_ = LoggerFactory
			.getLogger(IndividualNode.class);

	/** The taxonomy of this node. */
	final InstanceTaxonomy<T, I> taxonomy_;

	/**
	 * ElkClass nodes whose members are direct types of the members of this
	 * node.
	 */
	private final Set<UTN> directTypeNodes_;

	/**
	 * Constructs the node for the supplied equivalent members.
	 *
	 * @param taxonomy
	 *            The taxonomy to which this node belongs.
	 * @param members
	 *            Non-empty sequence of equivalent members.
	 * @param size
	 *            The number of equivalent members.
	 */
	protected IndividualNode(final InstanceTaxonomy<T, I> taxonomy,
			final Iterable<? extends I> members, final int size) {
		super(members, size, taxonomy.getInstanceKeyProvider());
		this.taxonomy_ = taxonomy;
		this.directTypeNodes_ = new ArrayHashSet<UTN>();
	}

	/**
	 * Add a direct super-class node. This method is not thread safe.
	 *
	 * @param typeNode
	 *            node to add
	 */
	@Override
	public synchronized void addDirectTypeNode(final UTN typeNode) {
		LOGGER_.trace("{}: new direct type-node {}", this, typeNode);

		directTypeNodes_.add(typeNode);
	}

	@Override
	public Set<? extends TN> getDirectTypeNodes() {
		return Collections.unmodifiableSet(toTypeNodes(directTypeNodes_));
	}

	@Override
	public Set<? extends TN> getAllTypeNodes() {
		return TaxonomyNodeUtils.getAllSuperNodes(getDirectTypeNodes());
	}

	@Override
	public Taxonomy<T> getTaxonomy() {
		return taxonomy_;
	}

	/**
	 * Returns the supplied set of mutable nodes as a set of immutable nodes.
	 *
	 * @param nodes
	 *            The set of mutable nodes that should be returned.
	 * @return The supplied set of mutable nodes as a set of immutable nodes.
	 */
	protected abstract Set<? extends TN> toTypeNodes(Set<? extends UTN> nodes);

	private final int hashCode_ = HashGenerator.generateNextHashCode();

	@Override
	public final int hashCode() {
		return hashCode_;
	}

	@Override
	public String toString() {
		return getCanonicalMember().getIri().getFullIriAsString();
	}

	@Override
	public synchronized void removeDirectTypeNode(final UTN typeNode) {
		LOGGER_.trace("{}: removing direct type node: {}", this, typeNode);

		directTypeNodes_.remove(typeNode);
	}

	@Override
	public Set<? extends UTN> getDirectNonBottomTypeNodes() {
		return directTypeNodes_;
	}

	/**
	 * A subclass with fixed type parameters so that this node may be associated
	 * with {@link UpdateableTypeNode}s.
	 *
	 * @author Peter Skocovsky
	 *
	 * @param <T>
	 *            The type of members of associated type nodes.
	 * @param <I>
	 *            The type of members of this nodes.
	 */
	public static class Projection<T extends ElkEntity, I extends ElkEntity>
			extends IndividualNode<
					T,
					I,
					GenericTypeNode.Projection<T, I>,
					GenericInstanceNode.Projection<T, I>,
					UpdateableTypeNode.Projection<T, I>,
					UpdateableInstanceNode.Projection<T, I>
			> implements UpdateableInstanceNode.Projection<T, I> {

		/**
		 * Constructs the node for the supplied equivalent members.
		 *
		 * @param taxonomy
		 *            The taxonomy to which this node belongs.
		 * @param members
		 *            Non-empty sequence of equivalent members.
		 * @param size
		 *            The number of equivalent members.
		 */
		public Projection(final InstanceTaxonomy<T, I> taxonomy,
				final Iterable<? extends I> members, final int size) {
			super(taxonomy, members, size);
		}

		@Override
		protected Set<? extends GenericTypeNode.Projection<T, I>> toTypeNodes(
				final Set<? extends UpdateableTypeNode.Projection<T, I>> nodes) {
			return nodes;
		}

	}

	/**
	 * A subclass with fixed type parameters so that this node may be associated
	 * with simple {@link NonBottomGenericTypeNode}s.
	 *
	 * @author Peter Skocovsky
	 *
	 * @param <T>
	 *            The type of members of associated type nodes.
	 * @param <I>
	 *            The type of members of this nodes.
	 */
	public static class Projection2<T extends ElkEntity, I extends ElkEntity>
			extends IndividualNode<
					T,
					I,
					GenericTypeNode.Projection<T, I>,
					GenericInstanceNode.Projection<T, I>,
					NonBottomGenericTypeNode.Projection<T, I>,
					Projection2<T, I>
			> implements GenericInstanceNode.Projection<T, I> {

		/**
		 * Constructs the node for the supplied equivalent members.
		 *
		 * @param taxonomy
		 *            The taxonomy to which this node belongs.
		 * @param members
		 *            Non-empty sequence of equivalent members.
		 * @param size
		 *            The number of equivalent members.
		 */
		public Projection2(final InstanceTaxonomy<T, I> taxonomy,
				final Iterable<? extends I> members, final int size) {
			super(taxonomy, members, size);
		}

		@Override
		protected Set<? extends GenericTypeNode.Projection<T, I>> toTypeNodes(
				final Set<? extends NonBottomGenericTypeNode.Projection<T, I>> nodes) {
			return nodes;
		}

	}

}


/*
 * #%L
 * ELK Reasoner
 *
 * $Id$
 * $HeadURL$
 * %%
 * Copyright (C) 2011 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.saturation.rules.factories;

import org.semanticweb.elk.ModifiableReference;
import org.semanticweb.elk.Reference;
import org.semanticweb.elk.ReferenceImpl;
import org.semanticweb.elk.reasoner.indexing.model.IndexedClassExpression;
import org.semanticweb.elk.reasoner.saturation.ContextCreationListener;
import org.semanticweb.elk.reasoner.saturation.ContextModificationListener;
import org.semanticweb.elk.reasoner.saturation.SaturationState;
import org.semanticweb.elk.reasoner.saturation.SaturationStateWriter;
import org.semanticweb.elk.reasoner.saturation.SaturationStatistics;
import org.semanticweb.elk.reasoner.saturation.SaturationUtils;
import org.semanticweb.elk.reasoner.saturation.context.Context;
import org.semanticweb.elk.reasoner.saturation.inferences.ClassInference;
import org.semanticweb.elk.reasoner.saturation.rules.RuleStatistics;
import org.semanticweb.elk.reasoner.saturation.rules.RuleVisitor;
import org.semanticweb.elk.util.concurrent.computation.InputProcessor;
import org.semanticweb.elk.util.concurrent.computation.InterruptMonitor;
import org.semanticweb.elk.util.concurrent.computation.DelegateInterruptMonitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A skeleton for implementing {@link RuleApplicationFactory}
 *
 * @author "Yevgeny Kazakov"
 *
 * @param <C>
 *            the type of the context used by this factory
 * @param <I>
 *            the type of the input processed by this factory
 */
public abstract class AbstractRuleApplicationFactory<C extends Context, I extends RuleApplicationInput>
		extends
			DelegateInterruptMonitor
		implements RuleApplicationFactory<C, I> {

	// logger for this class
	protected static final Logger LOGGER_ = LoggerFactory
			.getLogger(AbstractRuleApplicationFactory.class);

	/**
	 * The main {@link SaturationState} this factory works with
	 */
	private final SaturationState<? extends C> saturationState_;

	/**
	 * The {@link SaturationStatistics} aggregated for all workers
	 */
	private final SaturationStatistics aggregatedStats_;

	public AbstractRuleApplicationFactory(final InterruptMonitor interrupter,
			final SaturationState<? extends C> saturationState) {
		super(interrupter);
		this.saturationState_ = saturationState;
		this.aggregatedStats_ = new SaturationStatistics();
	}

	/**
	 * @param activeContext
	 * @param inferenceProcessor
	 * @param saturationStateWriter
	 * @param localStatistics
	 * @return an {@link InputProcessor} that processes {@link ClassInference}s
	 *         in {@link Context}s within an individual worker thread for the
	 *         input root {@link IndexedClassExpression} using the supplied
	 *         {@link SaturationStateWriter} and updates the supplied local
	 *         {@link SaturationStatistics} accordingly
	 */
	protected InputProcessor<I> getEngine(
			ModifiableReference<Context> activeContext,
			ClassInference.Visitor<Boolean> inferenceProcessor,
			SaturationStateWriter<? extends C> saturationStateWriter,
			WorkerLocalTodo localTodo, SaturationStatistics localStatistics) {
		return new BasicRuleEngine<I>(activeContext, inferenceProcessor,
				localTodo, this, saturationStateWriter, aggregatedStats_,
				localStatistics);
	}

	/**
	 * Creates a new primary {@link SaturationStateWriter} for the
	 * {@link SaturationState} to be used by an engine of this
	 * {@link RuleApplicationFactory}. This {@link SaturationStateWriter} can be
	 * further extended and optimized.
	 *
	 * @param creationListener
	 * @param modificationListener
	 * @return a new writer for the main {@link SaturationState} to be used by
	 *         engine.
	 */
	SaturationStateWriter<? extends C> getBaseWriter(
			ContextCreationListener creationListener,
			ContextModificationListener modificationListener) {
		// by default the writer can create new contexts
		return saturationState_.getContextCreatingWriter(creationListener,
				modificationListener);
	}

	/**
	 * Produces the final {@link SaturationStateWriter} to be used by an engine
	 * of this {@link RuleApplicationFactory} using the given candidate.
	 *
	 * @param writer
	 *            the {@link SaturationStateWriter} intended to be used by this
	 *            {@link RuleApplicationFactory}
	 * @return the actual {@link SaturationStateWriter} that will be used
	 */
	SaturationStateWriter<? extends C> getFinalWriter(
			SaturationStateWriter<? extends C> writer) {
		return writer;
	}

	/**
	 * An instance of {@link ClassInference.Visitor} that processes
	 * {@link ClassInference}s within {@link Context} by an individual worker.
	 *
	 * @param activeContext
	 * @param ruleVisitor
	 * @param writer
	 * @param localStatistics
	 * @return
	 */
	protected abstract ClassInference.Visitor<Boolean> getInferenceProcessor(
			Reference<Context> activeContext, RuleVisitor<?> ruleVisitor,
			SaturationStateWriter<? extends C> writer,
			SaturationStatistics localStatistics);

	/**
	 * Creates a {@link RuleVisitor} that specifies how the rules are applied
	 *
	 * @param statistics
	 * @return the {@link RuleVisitor} used by this
	 */
	@SuppressWarnings("static-method")
	protected RuleVisitor<?> getRuleVisitor(RuleStatistics statistics) {
		return SaturationUtils.getStatsAwareRuleVisitor(statistics);
	}

	@Override
	public final InputProcessor<I> getEngine(
			ContextCreationListener creationListener,
			ContextModificationListener modificationListener) {
		SaturationStatistics localStatistics = new SaturationStatistics();
		localStatistics.startMeasurements();
		creationListener = SaturationUtils.addStatsToContextCreationListener(
				creationListener, localStatistics.getContextStatistics());
		modificationListener = SaturationUtils
				.addStatsToContextModificationListener(modificationListener,
						localStatistics.getContextStatistics());
		SaturationStateWriter<? extends C> writer = getBaseWriter(
				creationListener, modificationListener);
		WorkerLocalTodo localTodo = new WorkerLocalTodoImpl();
		writer = new WorkerLocalizedSaturationStateWriter<C>(writer, localTodo);
		writer = getFinalWriter(writer);
		RuleVisitor<?> ruleVisitor = getRuleVisitor(localStatistics.getRuleStatistics());
		ModifiableReference<Context> activeContext = new ReferenceImpl<Context>();
		return getEngine(
				activeContext, getInferenceProcessor(activeContext, ruleVisitor,
						writer, localStatistics),
				writer, localTodo, localStatistics);
	}

	@Override
	public void dispose() {
		// aggregatedStats_.check(LOGGER_);
	}

	@Override
	public SaturationStatistics getSaturationStatistics() {
		return aggregatedStats_;
	}

	@Override
	public final SaturationState<? extends C> getSaturationState() {
		return saturationState_;
	}

}


package org.semanticweb.elk.matching;

/*
 * #%L
 * ELK Proofs Package
 * $Id:$
 * $HeadURL:$
 * %%
 * Copyright (C) 2011 - 2016 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%
 */

import org.semanticweb.elk.owl.interfaces.ElkObjectIntersectionOf;
import org.semanticweb.elk.owl.interfaces.ElkObjectInverseOf;
import org.semanticweb.elk.owl.interfaces.ElkObjectProperty;
import org.semanticweb.elk.owl.interfaces.ElkObjectPropertyChain;
import org.semanticweb.elk.owl.interfaces.ElkObjectPropertyExpression;
import org.semanticweb.elk.owl.interfaces.ElkSubObjectPropertyExpression;
import org.semanticweb.elk.owl.visitors.ElkSubObjectPropertyExpressionVisitor;

public class AbstractMatch<P> extends AbstractChild<P> {

	public AbstractMatch(P parent) {
		super(parent);
	}

	// some methods for checking correctness of arguments

	protected static void checkChainMatch(
			final ElkSubObjectPropertyExpression fullChain,
			final int startPos) {
		// verifies that start position exists in full chain
		fullChain.accept(new ElkSubObjectPropertyExpressionVisitor<Void>() {

			void fail() {
				throw new IllegalArgumentException(fullChain + ", " + startPos);
			}

			Void defaultVisit(ElkObjectPropertyExpression expression) {
				if (startPos != 0) {
					fail();
				}
				return null;
			}

			@Override
			public Void visit(ElkObjectPropertyChain expression) {
				if (startPos < 0 || startPos >= expression
						.getObjectPropertyExpressions().size())
					fail();
				return null;
			}

			@Override
			public Void visit(ElkObjectInverseOf expression) {
				return defaultVisit(expression);
			}

			@Override
			public Void visit(ElkObjectProperty expression) {
				return defaultVisit(expression);
			}
		});

	}

	protected static void checkConjunctionMatch(
			ElkObjectIntersectionOf conjunction, int prefixLength) {
		if (prefixLength < 1
				|| prefixLength >= conjunction.getClassExpressions().size()) {
			throw new IllegalArgumentException(
					conjunction + ", " + prefixLength);
		}

	}

}


/*
 * #%L
 * ELK Reasoner
 *
 * $Id$
 * $HeadURL$
 * %%
 * Copyright (C) 2011 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.util.collections;

import java.io.IOException;
import java.io.Writer;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;

/**
 * Some useful static methods for collections
 *
 * @author "Yevgeny Kazakov"
 * @author Peter Skocovsky
 */
public class Operations {

	public static final Multimap<?, ?> EMPTY_MULTIMAP = new Multimap<Object, Object>() {

		@Override
		public boolean contains(Object key, Object value) {
			return false;
		}

		@Override
		public boolean add(Object key, Object value) {
			throw new UnsupportedOperationException(
					"The Empty multimap cannot be modified!");
		}

		@Override
		public Collection<Object> get(Object key) {
			return Collections.emptySet();
		}

		@Override
		public boolean remove(Object key, Object value) {
			return false;
		}

		@Override
		public boolean isEmpty() {
			return true;
		}

		@Override
		public Set<Object> keySet() {
			return Collections.emptySet();
		}

		@Override
		public void clear() {
		}

		@Override
		public Collection<Object> remove(Object key) {
			return Collections.emptySet();
		}

	};

	@SuppressWarnings("unchecked")
	public static <S, T> Multimap<S, T> emptyMultimap() {
		return (Multimap<S, T>) EMPTY_MULTIMAP;
	}

	public static <T> Iterable<T> concat(final Iterable<? extends T>... inputs) {
		return concat(Arrays.asList(inputs));
	}

	public static <T> Iterator<T> singletonIterator(final T element) {
		return new Iterator<T>() {
			boolean hasNext = true;

			@Override
			public boolean hasNext() {
				return hasNext;
			}

			@Override
			public T next() {
				hasNext = false;
				return element;
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}
		};
	}

	public static <T> Iterable<T> singleton(final T element) {
		return new Iterable<T>() {
			@Override
			public Iterator<T> iterator() {
				return singletonIterator(element);
			}
		};
	}

	/**
	 * Concatenates several {@link Iterable}s into one
	 *
	 * @param inputs
	 *            the {@link Iterable} of {@link Iterable}s to be concatenated
	 * @return {@link Iterable} consisting of all elements found in input
	 *         {@link Iterable}s
	 */
	public static <T> Iterable<T> concat(
			final Iterable<? extends Iterable<? extends T>> inputs) {
		assert inputs != null;

		return new Iterable<T>() {

			@Override
			public Iterator<T> iterator() {

				return new Iterator<T>() {
					Iterator<? extends Iterable<? extends T>> outer = inputs
							.iterator();

					Iterator<? extends T> inner;
					boolean hasNext = advance();

					@Override
					public boolean hasNext() {
						return hasNext;
					}

					@Override
					public T next() {
						if (hasNext) {
							T result = inner.next();
							hasNext = advance();
							return result;
						}
						throw new NoSuchElementException();
					}

					@Override
					public void remove() {
						throw new UnsupportedOperationException();
					}

					boolean advance() {
						while (true) {
							if (inner != null && inner.hasNext())
								return true;

							if (outer.hasNext())
								inner = outer.next().iterator();
							else
								return false;
						}
					}
				};
			}
		};
	}

	/**
	 * Splits the input {@link Iterable} on batches with at most given number of
	 * elements.
	 *
	 * @param elements
	 *            the {@link Iterable} to be split
	 * @param batchSize
	 *            the maximal number of elements in batches
	 * @return a {@link Iterable} of batches containing elements from the input
	 *         collection
	 * @see #concat(Iterable)
	 */
	public static <T> Iterable<ArrayList<T>> split(
			final Iterable<? extends T> elements, final int batchSize) {
		return new Iterable<ArrayList<T>>() {

			@Override
			public Iterator<ArrayList<T>> iterator() {
				return new Iterator<ArrayList<T>>() {

					final Iterator<? extends T> elementsIterator = elements
							.iterator();

					@Override
					public boolean hasNext() {
						return elementsIterator.hasNext();
					}

					@Override
					public ArrayList<T> next() {
						final ArrayList<T> nextBatch = new ArrayList<T>(
								batchSize);
						int count = 0;
						while (count++ < batchSize
								&& elementsIterator.hasNext()) {
							nextBatch.add(elementsIterator.next());
						}
						return nextBatch;
					}

					@Override
					public void remove() {
						throw new UnsupportedOperationException(
								"Deletion is not supported");
					}
				};
			}
		};
	}

	/**
	 * Splits the input {@link Collection} on batches with at most given number
	 * of elements.
	 *
	 * @param elements
	 *            the {@link Collection} to be split
	 * @param batchSize
	 *            the maximal number of elements in batches
	 * @return a {@link Collection} of batches containing elements from the
	 *         input collection
	 */
	public static <T> Collection<ArrayList<T>> split(
			final Collection<? extends T> elements, final int batchSize) {
		return new AbstractCollection<ArrayList<T>>() {

			@Override
			public Iterator<ArrayList<T>> iterator() {
				return split((Iterable<? extends T>) elements, batchSize)
						.iterator();
			}

			@Override
			public int size() {
				// rounding up
				return (elements.size() + batchSize - 1) / batchSize;
			}
		};
	}

	public static <T> Collection<T> getCollection(final Iterable<T> iterable,
			final int size) {
		return new AbstractCollection<T>() {

			@Override
			public Iterator<T> iterator() {
				return iterable.iterator();
			}

			@Override
			public int size() {
				return size;
			}
		};
	}

	/**
	 *
	 * @param input
	 *            the input iterator
	 * @param condition
	 *            the condition used for filtering
	 * @return the filtered iterator
	 *
	 */
	public static <T> Iterable<T> filter(final Iterable<? extends T> input,
			final Condition<? super T> condition) {
		assert input != null;

		return new Iterable<T>() {

			@Override
			public Iterator<T> iterator() {

				return new Iterator<T>() {
					Iterator<? extends T> i = input.iterator();
					T next;
					boolean hasNext = advance();

					@Override
					public boolean hasNext() {
						return hasNext;
					}

					@Override
					public T next() {
						if (hasNext) {
							T result = next;
							hasNext = advance();
							return result;
						}
						throw new NoSuchElementException();
					}

					@Override
					public void remove() {
						i.remove();
					}

					boolean advance() {
						while (i.hasNext()) {
							next = i.next();
							if (condition.holds(next))
								return true;
						}
						return false;
					}
				};
			}
		};
	}

	@SuppressWarnings("unchecked")
	public static <T, S> Iterable<T> filter(final Iterable<S> input,
			final Class<T> type) {

		return (Iterable<T>) filter(input, new Condition<S>() {
			@Override
			public boolean holds(S element) {
				return type.isInstance(element);
			}
		});
	}

	/**
	 * Returns read-only view of the given set consisting of the elements
	 * satisfying a given condition, if the number of such elements is known
	 *
	 * @param input
	 *            the given set to be filtered
	 * @param condition
	 *            the condition used for filtering the set. Must be consistent
	 *            with equals() for T, that is: a.equals(b) must imply that
	 *            holds(a) == holds(b)
	 * @param size
	 *            the number of elements in the filtered set
	 * @return the set consisting of the elements of the input set satisfying
	 *         the given condition
	 */
	public static <T> Set<T> filter(final Set<? extends T> input,
			final Condition<? super T> condition, final int size) {
		return new Set<T>() {

			@Override
			public int size() {
				return size;
			}

			@Override
			public boolean isEmpty() {
				return size == 0;
			}

			@Override
			@SuppressWarnings("unchecked")
			public boolean contains(Object o) {

				if (!input.contains(o))
					return false;

				T elem = null;

				try {
					elem = (T) o;
				} catch (ClassCastException cce) {
					return false;
				}
				/*
				 * here's why the condition must be consistent with equals(): we
				 * check it on the passed element while we really need to check
				 * it on the element which is in the underlying set (and is
				 * equal to o according to equals()). However, as long as the
				 * condition is consistent, the result will be the same.
				 */
				return condition.holds(elem);
			}

			@Override
			public Iterator<T> iterator() {
				return filter(input, condition).iterator();
			}

			@Override
			public Object[] toArray() {
				Object[] result = new Object[size];
				int i = 0;
				for (Object o : filter(input, condition)) {
					result[i++] = o;
				}
				return result;
			}

			@Override
			public <S> S[] toArray(S[] a) {
				throw new UnsupportedOperationException();
			}

			@Override
			public boolean add(T e) {
				throw new UnsupportedOperationException();
			}

			@Override
			public boolean remove(Object o) {
				throw new UnsupportedOperationException();
			}

			@Override
			public boolean containsAll(Collection<?> c) {
				for (Object o : c) {
					if (contains(o))
						return false;
				}
				return true;
			}

			@Override
			public boolean addAll(Collection<? extends T> c) {
				throw new UnsupportedOperationException();
			}

			@Override
			public boolean retainAll(Collection<?> c) {
				throw new UnsupportedOperationException();
			}

			@Override
			public boolean removeAll(Collection<?> c) {
				throw new UnsupportedOperationException();
			}

			@Override
			public void clear() {
				throw new UnsupportedOperationException();
			}

		};

	}

	/**
	 * Transformations of input values to output values
	 *
	 * @param <I>
	 *            the type of the input of the transformation
	 * @param <O>
	 *            the type of the output of the transformation
	 */
	public interface Transformation<I, O> {
		/**
		 * Transforms the input element
		 *
		 * @param element
		 *            the element to be transformed
		 * @return the result of the transformation
		 */
		public O transform(I element);
	}

	// TODO: get rid of Conditions in favour of transformations

	/**
	 * Transforms elements using a given {@link Transformation} the output
	 * elements consist of the result of the transformation in the same order;
	 * if the transformation returns {@code null}, it is not included in the
	 * output
	 *
	 * @param input
	 *            the input elements
	 * @param transformation
	 *            the transformation for elements
	 * @return the transformed output elements
	 *
	 */
	public static <I, O> Iterable<O> map(final Iterable<I> input,
			final Transformation<? super I, O> transformation) {
		assert input != null;

		return new Iterable<O>() {

			@Override
			public Iterator<O> iterator() {

				return new Iterator<O>() {
					Iterator<I> i = input.iterator();
					O next;
					boolean hasNext = advance();

					@Override
					public boolean hasNext() {
						return hasNext;
					}

					@Override
					public O next() {
						if (hasNext) {
							O result = next;
							hasNext = advance();
							return result;
						}
						throw new NoSuchElementException();
					}

					@Override
					public void remove() {
						i.remove();
					}

					boolean advance() {
						while (i.hasNext()) {
							next = transformation.transform(i.next());
							if (next != null)
								return true;
						}
						return false;
					}
				};
			}
		};
	}

	public static <I, O> Iterable<O> mapConcat(final Iterable<I> input,
			final Transformation<? super I, Iterable<O>> transformation) {
		assert input != null;

		return new Iterable<O>() {

			@Override
			public Iterator<O> iterator() {
				return mapConcat(input.iterator(), transformation);
			}
		};
	}

	public static <I, O> Collection<O> map(final Collection<I> input,
			final Transformation<? super I, O> transformation) {
		assert input != null;

		return new AbstractCollection<O>() {

			@Override
			public Iterator<O> iterator() {
				return map(input.iterator(), transformation);
			}

			@Override
			public int size() {
				// this is an upper bound
				return input.size();
			}

		};
	}

	public static <I, O> Iterator<O> map(final Iterator<I> input, final Transformation<? super I, O> transformation) {
		return new Iterator<O>() {
			O next;
			boolean hasNext = advance();

			@Override
			public boolean hasNext() {
				return hasNext;
			}

			@Override
			public O next() {
				if (hasNext) {
					O result = next;
					hasNext = advance();
					return result;
				}
				throw new NoSuchElementException();
			}

			@Override
			public void remove() {
				input.remove();
			}

			boolean advance() {
				while (input.hasNext()) {
					next = transformation.transform(input.next());
					if (next != null)
						return true;
				}
				return false;
			}
		};
	}

	public static <I, O> Iterator<O> mapConcat(final Iterator<I> input, final Transformation<? super I, Iterable<O>> transformation) {
		return new Iterator<O>() {
			Iterator<O> nextIter = Collections.<O>emptyList().iterator();

			O next;

			@Override
			public boolean hasNext() {
				for (;;) {
					if (next != null) {
						return true;
					}

					if (nextIter.hasNext()) {
						next = nextIter.next();
						return true;
					}

					if (input.hasNext()) {
						nextIter = transformation.transform(input.next()).iterator();
					}
					else {
						return false;
					}
				}
			}

			@Override
			public O next() {
				if (!hasNext()) {
					throw new NoSuchElementException();
				}

				O result = next;

				next = null;

				return result;
			}

			@Override
			public void remove() {
				input.remove();
			}

		};
	}

	/**
	 * Prints key-value entries present in the first {@link Multimap} but not in
	 * the second {@link Multimap} using the given {@link Writer} and prefixing
	 * all messages with a given prefix.
	 *
	 * @param first
	 * @param second
	 * @param writer
	 * @param prefix
	 * @throws IOException
	 */
	public static <K, V> void dumpDiff(Multimap<K, V> first,
			Multimap<K, V> second, Writer writer, String prefix)
			throws IOException {
		for (K key : first.keySet()) {
			Collection<V> firstValues = first.get(key);
			Collection<V> secondValues = second.get(key);
			dumpDiff(firstValues, secondValues, writer, prefix + key + "->");
		}

	}

	/**
	 * Prints the elements present in the first {@link Collection} but not in
	 * the second {@link Collection} using the given {@link Writer} and
	 * prefixing all messages with a given prefix.
	 *
	 * @param first
	 * @param second
	 * @param writer
	 * @param prefix
	 * @throws IOException
	 */
	public static <T> void dumpDiff(Collection<T> first, Collection<T> second,
			Writer writer, String prefix) throws IOException {
		for (T element : first)
			if (!second.contains(element))
				writer.append(prefix + element + "\n");
	}

	/**
	 * A simple object that transforms objects of type I to objects of type O
	 *
	 * @author Pavel Klinov
	 *
	 *         pavel.klinov@uni-ulm.de
	 */
	public interface Functor<I, O> {

		public O apply(I element);
	}

	/**
	 * An extension of {@link Functor} which can do the reverse transformation
	 *
	 * @author Pavel Klinov
	 *
	 *         pavel.klinov@uni-ulm.de
	 */
	public interface FunctorEx<I, O> extends Functor<I, O> {

		/**
		 * The reason this method takes Objects rather than instances of O is
		 * because it's primarily used for an efficient implementation of
		 * {@link Set#contains(Object)}, which takes an Object
		 *
		 * @return Can return null if the transformation is not possible
		 */
		public I deapply(Object element);
	}

	/**
	 *
	 * @author Pavel Klinov
	 *
	 *         pavel.klinov@uni-ulm.de
	 */
	private static class MapIterator<I, O> implements Iterator<O> {

		private final Iterator<? extends I> iter_;
		private final Functor<I, O> functor_;

		MapIterator(Iterator<? extends I> iter, Functor<I, O> functor) {
			iter_ = iter;
			functor_ = functor;
		}

		@Override
		public boolean hasNext() {
			return iter_.hasNext();
		}

		@Override
		public O next() {
			return functor_.apply(iter_.next());
		}

		@Override
		public void remove() {
			iter_.remove();
		}

	}

	/**
	 * A simple second-order map function for sets
	 *
	 * @param input
	 * @param functor
	 * @return a set which contains the results of applying the functor to the
	 *         elements in the input set
	 */
	public static <I, O> Set<O> map(final Set<? extends I> input,
			final FunctorEx<I, O> functor) {
		return new AbstractSet<O>() {

			@Override
			public Iterator<O> iterator() {
				return new MapIterator<I, O>(input.iterator(), functor);
			}

			@Override
			public boolean contains(Object o) {
				I element = functor.deapply(o);

				return element == null ? false : input.contains(element);
			}

			@Override
			public int size() {
				return input.size();
			}

		};
	}

	public static <T> String toString(Iterable<T> iterable) {
		StringBuilder builder = new StringBuilder();
		boolean first = true;

		for (T elem : iterable) {
			String elemStr = elem.toString();

			if (!first && !elemStr.isEmpty()) {
				builder.append(' ');
			}

			if (!elemStr.isEmpty()) {
				builder.append(elemStr);
			}

			first = false;
		}

		return builder.toString();
	}

	/**
	 * @param elementComparator
	 * @return {@link Comparator} that compares iterables according to lexical
	 *         order w.r.t. element ordering defined by the provided element
	 *         {@link Comparator}.
	 */
	public static final <T> Comparator<? super Iterable<T>> lexicalOrder(
			final Comparator<? super T> elementComparator) {
		return new Comparator<Iterable<T>>() {
			@Override
			public int compare(final Iterable<T> o1, final Iterable<T> o2) {

				final Iterator<T> list1 = o1 == null
						? Collections.<T> emptyList().iterator()
						: o1.iterator();
				final Iterator<T> list2 = o2 == null
						? Collections.<T> emptyList().iterator()
						: o2.iterator();

				while (list1.hasNext() || list2.hasNext()) {

					// index did not exceed the size of at least one list.
					if (!list1.hasNext()) {
						// list1 is shorter and coincides on its elements.
						return -1;
					}
					if (!list2.hasNext()) {
						// list2 is shorter and coincides on its elements.
						return 1;
					}
					// index exceeded the size of none of the lists.

					final int cmp = elementComparator.compare(list1.next(),
							list2.next());
					if (cmp != 0) {
						return cmp;
					}

				}
				/*
				 * index exceeded size of both lists and no difference was
				 * found, so the lists are the same.
				 */
				return 0;
			}
		};
	}

}


/*
 * #%L
 * elk-reasoner
 *
 * $Id$
 * $HeadURL$
 * %%
 * Copyright (C) 2011 Oxford University Computing Laboratory
 * %%
 * 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%
 */
/**
 * @author Yevgeny Kazakov, May 17, 2011
 */
package org.semanticweb.elk.util.collections;

import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Set;

/**
 * A compact representation of several sets (called "slices") that can share
 * many elements. The representation is backed by arrays that store the elements
 * and numerical masks that encode to which sets those elements belong to. The
 * membership is checked using hash values of elements with linear probing to
 * resolve hash collisions: see [1] p.526. Parts of the code are inspired by the
 * implementation of {@link java.util.HashMap}.
 *
 * [1] Donald E. Knuth, The Art of Computer Programming, Volume 3, Sorting and
 * Searching, Second Edition
 *
 * @author Yevgeny Kazakov
 * @param <E>
 *            the type of the elements in the sets
 *
 */
public class ArraySlicedSet<E> {

	/**
	 * the maximal number of slices that can be stored in a
	 * {@link ArraySlicedSet}
	 */
	public static int MAX_SLICES = 32;

	/**
	 * The table for the elements; the length MUST always be a power of two.
	 */
	transient E[] data;

	/**
	 * The table of masks that encode the membership of elements in slices; the
	 * length MUST be a power of two.
	 */
	transient int[] masks;

	/**
	 * The number of elements contained in the respective slice
	 */
	transient int[] sizes;

	/**
	 * The number of non-{@code null} elements in {@link #data}
	 */
	transient int occupied = 0;

	/**
	 * The upper rounded logarithm for the number of slices; it is used to
	 * efficiently compute membership of elements
	 */
	private final byte logs;

	/**
	 * Bitwise masks consisting of binary exponential number of 1s.
	 */
	private static int[] MSK_ = { 1, (1 << 2) - 1, (1 << 4) - 1, (1 << 8) - 1,
			(1 << 16) - 1, ~0 };

	@SuppressWarnings("unchecked")
	public ArraySlicedSet(int slices, int initialCapacity) {
		if (slices <= 0 || slices > MAX_SLICES)
			throw new IllegalArgumentException(
					"The nuber of slices should be between 1 and " + MAX_SLICES
							+ ": " + slices);
		int capacity = LinearProbing.getInitialCapacity(initialCapacity);
		this.data = (E[]) new Object[capacity];
		this.logs = (byte) upperLog(slices);
		this.masks = new int[getMaskCapacity(logs, capacity)];
		this.sizes = new int[slices];
		initSizes();
	}

	public ArraySlicedSet(int slices) {
		this(slices, LinearProbing.DEFAULT_INITIAL_CAPACITY);
	}

	static int upperLog(int n) {
		int log = 0;
		int exp = 1;
		while (exp < n) {
			log++;
			exp <<= 1;
		}
		return log;
	}

	void initSizes() {
		for (int i = 0; i < sizes.length; i++)
			this.sizes[i] = 0;
	}

	/**
	 * Computes the capacity of the mask table given the capacity of the table
	 * using the property that one integer can represent 32 set membership flags
	 * (as bits).
	 *
	 * @param sl
	 *            the logarithm of the number of slices
	 * @param capacity
	 * @return
	 */
	static int getMaskCapacity(byte sl, int capacity) {
		int result = capacity >> (5 - sl);
		if (result == 0)
			result = 1;
		return result;
	}

	/**
	 * Returns the bit fragment that encodes the membership of an element for
	 * the given position in slices. The returned fragment is an integer whose
	 * lower bits correspond to whether an element occurs in the slice or not
	 * (the lowest bit corresponds to the membership in slice = 0, next bit in
	 * slice = 1, etc)
	 *
	 * @param sl
	 *            the logarithm of the number of slices
	 * @param masks
	 *            the table storing all masks encoding the membership of
	 *            elements in slices
	 * @param pos
	 *            the position of an element in the table for which the fragment
	 *            should be returned
	 * @return the integer whose bits encode membership of the element at the
	 *         given position in slices
	 */
	static int getFragment(byte sl, int[] masks, int pos) {
		/*
		 * one element of the masks table stores fragments for 32/(2^sl)
		 * elements; since it is a power of 2, we can divide on this value and
		 * compute the remainder efficiently
		 */
		int shift = (5 - sl);
		int p = pos >> shift; // = pos / (32/(2^sl))
		int r = (p << shift) ^ pos; // the remainder after the devision
		// extract the r-th fragment of the length 2^sl
		return (masks[p] >> (r << sl)) & MSK_[sl];
	}

	/**
	 * Changes the fragment that corresponds to the encoding of membership of an
	 * element at the given position. The change is specified by the bits of the
	 * last parameter: bit 1 means the corresponding value of the fragment
	 * should flip, bit 0 means it should stay the same.
	 *
	 * @param sl
	 *            the logarithm of the number of slices
	 * @param masks
	 *            the table storing all masks encoding the membership of
	 *            elements in slices
	 * @param pos
	 *            the position of an element in the table for which the fragment
	 *            should be changed
	 * @param diff
	 *            the sequence of bits that describes the change; the new
	 *            fragment is obtained by applying bitwise XOR operation
	 */
	static void changeFragment(byte sl, int[] masks, int pos, int diff) {
		int shift = (5 - sl);
		int p = pos >> shift;
		int r = (p << shift) ^ pos;
		masks[p] ^= diff << (r << sl);
	}

	/**
	 * @param s
	 *            the slice id
	 * @return the number of elements currently stored in the provided slice
	 */
	public int size(int s) {
		return sizes[s];
	}

	/**
	 * @param s
	 *            the slice id
	 * @return {@code true} if the given slice does not contain any elements and
	 *         {@code false} otherwise
	 */
	public boolean isEmpty(int s) {
		return sizes[s] == 0;
	}

	private static <E> int addMask(byte sl, E[] data, int[] masks, E e, int mask) {
		int pos = LinearProbing.getPosition(data, e);
		int oldMask = getFragment(sl, masks, pos);
		if (data[pos] == null) {
			data[pos] = e;
			changeFragment(sl, masks, pos, oldMask ^ mask);
			return 0;
		}
		// else
		int newMask = (oldMask | mask);
		if (newMask != oldMask)
			changeFragment(sl, masks, pos, oldMask ^ newMask);
		return oldMask;
	}

	private static <E> void remove(byte sl, E[] data, int[] masks, int pos) {
		int oldFragment = getFragment(sl, masks, pos);
		for (;;) {
			int next = LinearProbing.getMovedPosition(data, pos);
			E moved = data[pos] = data[next];
			int newFragment = getFragment(sl, masks, next);
			changeFragment(sl, masks, pos, oldFragment ^ newFragment);
			if (moved == null)
				return;
			// else
			pos = next;
			oldFragment = newFragment;
		}
	}

	private static <E> int removeMask(byte sl, E[] data, int[] masks, Object o,
			int mask) {
		int pos = LinearProbing.getPosition(data, o);
		if (data[pos] == null)
			return 0;
		// else
		int oldFragment = getFragment(sl, masks, pos);
		int newFragment = oldFragment & (~mask);
		if (newFragment == 0)
			remove(sl, data, masks, pos);
		else
			changeFragment(sl, masks, pos, oldFragment ^ newFragment);
		return oldFragment;
	}

	/**
	 * Increasing the capacity of the table
	 */
	private void enlarge() {
		int oldCapacity = data.length;
		if (oldCapacity == LinearProbing.MAXIMUM_CAPACITY)
			throw new IllegalArgumentException(
					"The set cannot grow beyond the capacity: "
							+ LinearProbing.MAXIMUM_CAPACITY);
		E[] oldData = data;
		int[] oldMasks = masks;
		int newCapacity = oldCapacity << 1;
		@SuppressWarnings("unchecked")
		E[] newData = (E[]) new Object[newCapacity];
		int[] newMasks = new int[getMaskCapacity(logs, newCapacity)];
		for (int i = 0; i < oldCapacity; i++) {
			E e = oldData[i];
			if (e != null)
				addMask(logs, newData, newMasks, e,
						getFragment(logs, oldMasks, i));
		}
		this.data = newData;
		this.masks = newMasks;
	}

	/**
	 * Decreasing the capacity of the table
	 */
	private void shrink() {
		int oldCapacity = data.length;
		if (oldCapacity == 1)
			return;
		E[] oldData = data;
		int[] oldMasks = masks;
		int newCapacity = oldCapacity >> 1;
		@SuppressWarnings("unchecked")
		E[] newData = (E[]) new Object[newCapacity];
		int[] newMasks = new int[getMaskCapacity(logs, newCapacity)];
		for (int i = 0; i < oldCapacity; i++) {
			E e = oldData[i];
			if (e != null)
				addMask(logs, newData, newMasks, e,
						getFragment(logs, oldMasks, i));
		}
		this.data = newData;
		this.masks = newMasks;
	}

	public boolean contains(int s, Object o) {
		if (o == null)
			throw new NullPointerException();
		// to avoid problems in the middle of resizing, we copy data and masks
		// when they have the same size
		E[] d;
		int[] m;
		for (;;) {
			d = this.data;
			m = this.masks;
			if (m.length == getMaskCapacity(logs, d.length))
				break;
		}
		int pos = LinearProbing.getPosition(d, o);
		if (d[pos] == null)
			return false;
		// else
		int mask = 1 << s;
		return ((getFragment(logs, m, pos) & mask) == mask);
	}

	/**
	 * Inserts a given element into the given slice
	 *
	 * @param s
	 *            the slice id
	 * @param e
	 *            the elements to be inserted in to the given slice
	 * @return {@code true} if the given element did not occur in the given
	 *         slice and thus was inserted. Otherwise {@code false} is returned
	 *         and nothing is modified.
	 */
	public boolean add(int s, E e) {
		if (e == null)
			throw new NullPointerException();
		int mask = (1 << s);
		int oldMask = addMask(logs, data, masks, e, mask);
		int newMask = oldMask | mask;
		if (newMask == oldMask)
			return false;
		else if (oldMask == 0
				&& ++occupied == LinearProbing.getUpperSize(data.length))
			enlarge();
		sizes[s]++;
		return true;
	}

	/**
	 * Removes the given object from the given slice
	 *
	 * @param s
	 *            the slice id
	 * @param o
	 *            the object that should be removed from the given slice
	 * @return {@code true} if the given object is equal to some element of the
	 *         given slice; this element will be removed from the slice. If
	 *         there is no such an object, {@code false} is returned and nothing
	 *         is modified
	 */
	public boolean remove(int s, Object o) {
		if (o == null)
			throw new NullPointerException();
		int mask = 1 << s;
		int oldMask = removeMask(logs, data, masks, o, mask);
		int newMask = oldMask & ~mask;
		if (newMask == oldMask)
			return false;
		// else
		if (newMask == 0
				&& --occupied == LinearProbing.getLowerSize(data.length))
			shrink();
		sizes[s]--;
		return true;
	}

	/**
	 * Removes all element of the given {@link Collection} from the given slice
	 *
	 * @param s
	 *            the slice id
	 * @param c
	 *            the collection whose elements should be removed
	 * @return {@code true} if at least one element is removed from the slice.
	 *         An element is removed if an equal element is present in the given
	 *         collection. If no elements are removed, {@code false} is returned
	 *         and nothing is modified.
	 */
	public boolean removeAll(int s, Collection<?> c) {
		boolean modified = false;
		for (Object o : c) {
			modified |= remove(s, o);
		}
		return modified;
	}

	/**
	 * Clears all slices of this {@link ArraySlicedSet}. After calling this
	 * methods, all slices are empty.
	 */
	@SuppressWarnings("unchecked")
	public void clear() {
		int capacity = data.length >> 2;
		if (capacity == 0)
			capacity = 1;
		initSizes();
		this.data = (E[]) new Object[capacity];
		this.masks = new int[getMaskCapacity(logs, capacity)];
	}

	/**
	 * @param s
	 *            the slice id
	 * @return the set corresponding to this slice backed by this
	 *         {@link ArraySlicedSet}; it can be modified
	 */
	public Set<E> getSlice(int s) {
		return new Slice(s);
	}

	private class Slice extends AbstractSet<E> implements Set<E> {

		/**
		 * the slice which is viewed by this set
		 */
		final byte s;

		Slice(int s) {
			if (s > sizes.length || s < 0)
				throw new IllegalArgumentException("Slice should be in [0;"
						+ sizes.length + "]: " + s);
			this.s = (byte) s;
		}

		@Override
		public int size() {
			return ArraySlicedSet.this.size(s);
		}

		@Override
		public boolean isEmpty() {
			return ArraySlicedSet.this.isEmpty(s);
		}

		@Override
		public boolean contains(Object o) {
			return ArraySlicedSet.this.contains(s, o);
		}

		@Override
		public boolean add(E e) {
			return ArraySlicedSet.this.add(s, e);
		}

		@Override
		public boolean remove(Object o) {
			return ArraySlicedSet.this.remove(s, o);
		}

		@Override
		public boolean removeAll(Collection<?> c) {
			return ArraySlicedSet.this.removeAll(s, c);
		}

		@Override
		public Iterator<E> iterator() {
			return new ElementIterator(s);
		}

		@Override
		public String toString() {
			return Arrays.toString(toArray());
		}

	}

	private class ElementIterator extends LinearProbingIterator<E, E> {

		final int s;
		final int mask;

		ElementIterator(int s) {
			super(data, sizes[s]);
			this.s = s;
			mask = (1 << s);
			init();
		}

		@Override
		void checkSize(int expectedSize) {
			if (expectedSize != sizes[s])
				throw new ConcurrentModificationException();
		}

		@Override
		boolean isOccupied(int pos) {
			return (dataSnapshot[pos] != null && (getFragment(logs, masks, pos) & mask) == mask);
		}

		@Override
		void remove(int pos) {
			int oldMask = getFragment(logs, masks, pos);
			int newMask = oldMask & (~mask);
			if (newMask == 0) {
				ArraySlicedSet.remove(logs, data, masks, pos);
				occupied--;
			} else
				changeFragment(logs, masks, pos, oldMask ^ newMask);
			sizes[s]--;
		}

		@Override
		E getValue(E element, int pos) {
			return element;
		}
	}
}