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

import org.semanticweb.elk.reasoner.saturation.conclusions.model.BackwardLink;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.ClassConclusion;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.ContextInitialization;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.ClassInconsistency;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.DisjointSubsumer;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.ForwardLink;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.Propagation;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.SubClassInclusionComposed;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.SubClassInclusionDecomposed;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.SubContextInitialization;

/**
 * An object which can be used to count {@link ClassConclusion}s. The fields of
 * the counter correspond to the methods of {@link ClassConclusion.Visitor}.
 *
 * @author "Yevgeny Kazakov"
 */
public class ClassConclusionCounter {

	/**
	 * counter for {@link BackwardLink}
	 */
	long countBackwardLink;

	/**
	 * counter for {@link ContextInitialization}
	 */
	long countContextInitialization;

	/**
	 * counter for {@link ClassInconsistency}
	 */
	long countContradiction;

	/**
	 * counter for {@link DisjointSubsumer}
	 */
	long countDisjointSubsumer;

	/**
	 * counter for {@link ForwardLink}
	 */
	long countForwardLink;

	/**
	 * counter for {@link SubClassInclusionDecomposed}
	 */
	long countSubClassInclusionDecomposed;

	/**
	 * counter for {@link SubClassInclusionComposed}
	 */
	long countSubClassInclusionComposed;

	/**
	 * counter for {@link Propagation}
	 */
	long countPropagation;

	/**
	 * counter for {@link SubContextInitialization}
	 */
	long countSubContextInitialization;

	/**
	 * Adds all counters of the argument to the corresponding counters of this
	 * object. The counters should not be directly modified other than using
	 * this method during this operation. The counter in the argument will be
	 * reseted after this operation.
	 *
	 * @param counter
	 *            the object which counters should be added
	 */
	public synchronized void add(ClassConclusionCounter counter) {
		this.countSubClassInclusionDecomposed += counter.countSubClassInclusionDecomposed;
		this.countSubClassInclusionComposed += counter.countSubClassInclusionComposed;
		this.countBackwardLink += counter.countBackwardLink;
		this.countForwardLink += counter.countForwardLink;
		this.countContradiction += counter.countContradiction;
		this.countPropagation += counter.countPropagation;
		this.countDisjointSubsumer += counter.countDisjointSubsumer;
		this.countContextInitialization += counter.countContextInitialization;
		this.countSubContextInitialization += counter.countSubContextInitialization;
	}

	public long getCountBackwardLink() {
		return countBackwardLink;
	}

	public long getCountContradiction() {
		return countContradiction;
	}

	public long getCountContextInitialization() {
		return countContextInitialization;
	}

	public long getCountDisjointSubsumer() {
		return countDisjointSubsumer;
	}

	public long getCountForwardLink() {
		return countForwardLink;
	}

	public long getCountSubClassInclusionDecomposed() {
		return countSubClassInclusionDecomposed;
	}

	public long getCountSubClassInclusionComposed() {
		return countSubClassInclusionComposed;
	}

	public long getCountPropagation() {
		return countPropagation;
	}

	public long getCountSubContextInitialization() {
		return countSubContextInitialization;
	}

	public long getTotalCount() {
		return countSubClassInclusionDecomposed + countSubClassInclusionComposed
				+ countBackwardLink + countForwardLink + countContradiction
				+ countPropagation + countDisjointSubsumer
				+ countContextInitialization + countSubContextInitialization;
	}

	/**
	 * Reset all counters to zero.
	 */
	public void reset() {
		countSubClassInclusionDecomposed = 0;
		countSubClassInclusionComposed = 0;
		countBackwardLink = 0;
		countForwardLink = 0;
		countContradiction = 0;
		countPropagation = 0;
		countDisjointSubsumer = 0;
		countContextInitialization = 0;
		countSubContextInitialization = 0;
	}

}


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

import org.slf4j.Logger;

/**
 * Collection of several static methods that help in taking and logging
 * statistical information.
 *
 * @author Yevgeny Kazakov
 * @author Markus Kroetzsch
 */
public class Statistics {

	// Declare the size
	final static int megaBytes = 1024 * 1024;

	/**
	 * Log the start of a particular operation with INFO priority. This method
	 * should be used for long-running tasks and is mainly intended. Multiple
	 * threads can independently log operations of the same name, but
	 * (obviously) no single thread should use the same operation name to record
	 * the start and end of overlapping code.
	 *
	 * @param operationName
	 * @param logger
	 */
	public static void logOperationStart(String operationName, Logger logger) {
		logOperationStart(operationName, logger, LogLevel.INFO);
	}

	/**
	 * Log the start of a particular operation with the given priority. This
	 * method should be used for long-running tasks and is mainly intended.
	 * Multiple threads can independently log operations of the same name, but
	 * (obviously) no single thread should use the same operation name to record
	 * the start and end of overlapping code.
	 *
	 * @param operationName
	 * @param logger
	 * @param priority
	 */
	public static void logOperationStart(String operationName, Logger logger,
			LogLevel priority) {
		if (LoggerWrap.isEnabledFor(logger, priority)) {
			LoggerWrap.log(logger, priority, operationName + " started");
			ElkTimer timer = ElkTimer.getNamedTimer(operationName,
					ElkTimer.RECORD_WALLTIME);
			timer.reset(); // needed in case this was done before
			timer.start();
		}
	}

	/**
	 * Log the end of a particular operation the beginning of which has been
	 * logged using logOperationStart(), using INFO priority.
	 *
	 * @param operationName
	 * @param logger
	 */
	public static void logOperationFinish(String operationName, Logger logger) {
		logOperationFinish(operationName, logger, LogLevel.INFO);
	}

	/**
	 * Log the end of a particular operation the beginning of which has been
	 * logged using logOperationStart(), using the given logging priority.
	 *
	 * @param operationName
	 * @param logger
	 * @param priority
	 */
	public static void logOperationFinish(String operationName, Logger logger,
			LogLevel priority) {
		if (LoggerWrap.isEnabledFor(logger, priority)) {
			ElkTimer timer = ElkTimer.getNamedTimer(operationName,
					ElkTimer.RECORD_WALLTIME);
			timer.stop();
			LoggerWrap.log(logger, priority, operationName + " took "
					+ timer.getTotalWallTime() / 1000000 + " ms");
		}
	}

	/**
	 * Log the current total memory usage using DEBUG priority.
	 *
	 * @param logger
	 */
	public static void logMemoryUsage(Logger logger) {
		logMemoryUsage(logger, LogLevel.DEBUG);
	}

	/**
	 * Log the current total memory usage with the specified priority.
	 *
	 * @param logger
	 * @param priority
	 */
	public static void logMemoryUsage(Logger logger, LogLevel priority) {
		if (LoggerWrap.isEnabledFor(logger, priority)) {
			// Getting the runtime reference from system
			Runtime runtime = Runtime.getRuntime();

			LoggerWrap.log(logger, priority, "Memory (MB) Used/Total/Max: "
					+ (runtime.totalMemory() - runtime.freeMemory())
					/ megaBytes + "/" + runtime.totalMemory() / megaBytes + "/"
					+ runtime.maxMemory() / megaBytes);
		}
	}

}


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

import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.semanticweb.elk.exceptions.ElkException;
import org.semanticweb.elk.owl.interfaces.ElkAxiom;
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.interfaces.ElkObjectProperty;
import org.semanticweb.elk.reasoner.config.ReasonerConfiguration;
import org.semanticweb.elk.reasoner.indexing.model.OntologyIndex;
import org.semanticweb.elk.reasoner.stages.AbstractReasonerState;
import org.semanticweb.elk.reasoner.stages.ReasonerStageExecutor;
import org.semanticweb.elk.reasoner.taxonomy.FreshInstanceNode;
import org.semanticweb.elk.reasoner.taxonomy.FreshTaxonomyNode;
import org.semanticweb.elk.reasoner.taxonomy.FreshTypeNode;
import org.semanticweb.elk.reasoner.taxonomy.TaxonomyNodeUtils;
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.Operations;
import org.semanticweb.elk.util.concurrent.computation.ConcurrentExecutor;
import org.semanticweb.elk.util.concurrent.computation.ConcurrentExecutors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The class for querying the results of the reasoning tasks for a given
 * ontology. The input ontology is represented internally by the
 * {@link OntologyIndex} object, which is updated by adding or removing
 * {@link ElkAxiom}s (methods addAxiom() and removeAxiom()). When querying the
 * results of the reasoning tasks, the reasoner will ensure that all necessary
 * reasoning stages, such as consistency checking, are performed.
 *
 * Reasoners are created (and pre-configured) by the {@link ReasonerFactory}.
 */
public class Reasoner extends AbstractReasonerState {

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

	/**
	 * the executor used for concurrent tasks
	 */
	private final static ConcurrentExecutor EXECUTOR_ = ConcurrentExecutors
			.create("elk-reasoner");

	/**
	 * The progress monitor that is used for reporting progress.
	 */
	protected ProgressMonitor progressMonitor;
	/**
	 * The executor for various stages of the reasoner
	 */
	private final ReasonerStageExecutor stageExecutor_;
	/**
	 * The object that is notified and propagates the information about
	 * interruption.
	 */
	private final ReasonerInterrupter interrupter_;
	/**
	 * Number of workers for concurrent jobs.
	 */
	private int workerNo_;

	/**
	 * Should fresh entities in reasoner queries be accepted (configuration
	 * setting). If false, a {@link ElkFreshEntitiesException} will be thrown
	 * when encountering entities that did not occur in the ontology.
	 */
	protected boolean allowFreshEntities;

	/**
	 * Constructor. In most cases, Reasoners should be created by the
	 * {@link ReasonerFactory}.
	 */
	protected Reasoner(ElkObject.Factory elkFactory,
			final ReasonerInterrupter interrupter,
			ReasonerStageExecutor stageExecutor, ReasonerConfiguration config) {
		super(elkFactory, config);

		this.stageExecutor_ = stageExecutor;
		this.interrupter_ = interrupter;
		this.progressMonitor = new DummyProgressMonitor();
		this.allowFreshEntities = true;
		setConfigurationOptions(config);
		LOGGER_.info("ELK reasoner was created");
	}

	/**
	 * Set the progress monitor that will be used for reporting progress on all
	 * potentially long-running operations.
	 *
	 * @param progressMonitor
	 */
	public synchronized void setProgressMonitor(
			ProgressMonitor progressMonitor) {
		this.progressMonitor = progressMonitor;
	}

	/**
	 * Set if fresh entities should be allowed. Fresh entities are entities that
	 * occur as parameters of reasoner queries without occurring in the loaded
	 * ontology. If false, a {@link ElkFreshEntitiesException} will be thrown in
	 * such cases. If true, the reasoner will answer as if the entity had been
	 * declared (but not used in any axiom).
	 *
	 * @param allow
	 */
	public synchronized void setAllowFreshEntities(boolean allow) {
		allowFreshEntities = allow;
	}

	/**
	 * Get whether fresh entities are allowed. See
	 * {@link #setAllowFreshEntities(boolean)} for details.
	 *
	 * @return {@code true} if fresh entities are allowed
	 */
	public synchronized boolean getAllowFreshEntities() {
		return allowFreshEntities;
	}

	@Override
	protected synchronized int getNumberOfWorkers() {
		return workerNo_;
	}

	/**
	 * Sets the number of working threads. Shouldn't be used during reasoning.
	 *
	 * @param workerNo
	 */
	public synchronized void setNumberOfWorkers(int workerNo) {
		workerNo_ = workerNo;
	}

	/**
	 * This supposed to be the central place where the reasoner gets its
	 * configuration options
	 *
	 * @param config
	 */
	public synchronized void setConfigurationOptions(
			ReasonerConfiguration config) {
		this.workerNo_ = config.getParameterAsInt(
				ReasonerConfiguration.NUM_OF_WORKING_THREADS);

		setAllowIncrementalMode(config.getParameterAsBoolean(
				ReasonerConfiguration.INCREMENTAL_MODE_ALLOWED));

	}

	@Override
	protected ConcurrentExecutor getProcessExecutor() {
		return EXECUTOR_;
	}

	@Override
	protected ReasonerStageExecutor getStageExecutor() {
		return stageExecutor_;
	}

	@Override
	protected ReasonerInterrupter getInterrupter() {
		return interrupter_;
	}

	@Override
	protected synchronized ProgressMonitor getProgressMonitor() {
		return progressMonitor;
	}

	/**
	 * Tries to shut down the reasoner within the specified time
	 *
	 * @param timeout
	 *            the maximum time to wait
	 * @param unit
	 *            the time unit of the timeout argument
	 * @return {@code true} if the operation was successful
	 * @throws InterruptedException
	 *             if the current thread was interrupted
	 */
	public synchronized boolean shutdown(long timeout, TimeUnit unit)
			throws InterruptedException {
		boolean success = true;
		if (success) {
			LOGGER_.info("ELK reasoner has shut down");
		} else {
			LOGGER_.error("ELK reasoner failed to shut down!");
		}
		return success;

	}

	/**
	 * Tries to shut down the reasoner within 1 minute
	 *
	 * @return {@code true} if the operation was successful
	 * @throws InterruptedException
	 *             if the current thread was interrupted
	 */
	public synchronized boolean shutdown() throws InterruptedException {
		return shutdown(1, TimeUnit.MINUTES);
	}

	/**
	 * Helper method to get a {@link TaxonomyNode} from the taxonomy.
	 *
	 * @param elkClass
	 *            an {@link ElkClass} for which to find a {@link TaxonomyNode}
	 * @return the {@link TaxonomyNode} for the given {@link ElkClass}
	 *
	 */
	protected TaxonomyNode<ElkClass> getTaxonomyNode(ElkClass elkClass)
			throws ElkException {
		final Taxonomy<ElkClass> taxonomy = getTaxonomy();
		final TaxonomyNode<ElkClass> node = taxonomy.getNode(elkClass);
		if (node != null)
			return node;
		// else
		if (allowFreshEntities)
			return new FreshTaxonomyNode<ElkClass>(elkClass, taxonomy);
		// else
		throw new ElkFreshEntitiesException(elkClass);
	}

	/**
	 * Helper method to get an {@link InstanceNode} from the taxonomy.
	 *
	 * @param elkNamedIndividual
	 * @return the {@link InstanceNode} for the given {@link ElkNamedIndividual}
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	protected InstanceNode<ElkClass, ElkNamedIndividual> getInstanceNode(
			ElkNamedIndividual elkNamedIndividual) throws ElkException {
		final InstanceTaxonomy<ElkClass, ElkNamedIndividual> instanceTaxonomy = getInstanceTaxonomy();
		final InstanceNode<ElkClass, ElkNamedIndividual> node = instanceTaxonomy
				.getInstanceNode(elkNamedIndividual);
		if (node != null)
			return node;
		// else
		if (allowFreshEntities)
			return new FreshInstanceNode<ElkClass, ElkNamedIndividual>(
					elkNamedIndividual, instanceTaxonomy);
		// else
		throw new ElkFreshEntitiesException(elkNamedIndividual);
	}

	/**
	 * Helper method to get a {@link TypeNode} from the taxonomy.
	 *
	 * @param elkClass
	 * @return the {@link TypeNode} for the given {@link ElkClass}
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	protected TypeNode<ElkClass, ElkNamedIndividual> getTypeNode(
			ElkClass elkClass) throws ElkException {
		final InstanceTaxonomy<ElkClass, ElkNamedIndividual> instanceTaxonomy = getInstanceTaxonomy();
		final TypeNode<ElkClass, ElkNamedIndividual> node = instanceTaxonomy
				.getNode(elkClass);
		if (node != null)
			return node;
		// else
		if (allowFreshEntities)
			return new FreshTypeNode<ElkClass, ElkNamedIndividual>(elkClass,
					instanceTaxonomy);
		// else
		throw new ElkFreshEntitiesException(elkClass);
	}

	/**
	 * Helper method to get a {@link TaxonomyNode} from the property taxonomy.
	 *
	 * @param elkProperty
	 *            an {@link ElkObjectProperty} for which to find a
	 *            {@link TaxonomyNode}
	 * @return the {@link TaxonomyNode} for the given {@link ElkObjectProperty}
	 *
	 */
	protected TaxonomyNode<ElkObjectProperty> getObjectPropertyTaxonomyNode(
			final ElkObjectProperty elkProperty) throws ElkException {
		final Taxonomy<ElkObjectProperty> propertyTaxonomy = getObjectPropertyTaxonomy();
		final TaxonomyNode<ElkObjectProperty> node = propertyTaxonomy
				.getNode(elkProperty);
		if (node != null) {
			return node;
		}
		// else
		if (allowFreshEntities) {
			return new FreshTaxonomyNode<ElkObjectProperty>(elkProperty,
					propertyTaxonomy);
		}
		// else
		throw new ElkFreshEntitiesException(elkProperty);
	}

	/**
	 * Return the {@link TaxonomyNode} for the given {@link ElkObjectProperty}.
	 * Calling of this method may trigger the computation of the taxonomy, if it
	 * has not been done yet. If the input is an {@link ElkObjectProperty} that
	 * does not occur in the ontology and fresh entities are not allowed, a
	 * {@link ElkFreshEntitiesException} will be thrown.
	 *
	 * @param property
	 *            the {@link ElkObjectProperty} for which to return the
	 *            {@link Node}
	 * @return the {@link TaxonomyNode} for the given {@link ElkObjectProperty}
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized TaxonomyNode<ElkObjectProperty> getObjectPropertyNode(
			final ElkObjectProperty property) throws ElkException {
		return getObjectPropertyTaxonomyNode(property);
	}

	/**
	 * Return the {@code Node} containing equivalent classes of the given
	 * {@link ElkClassExpression}. Calling of this method may trigger the
	 * computation of the taxonomy, if it has not been done yet.
	 *
	 * @param classExpression
	 *            the {@link ElkClassExpression} for which to return the
	 *            {@link Node}
	 * @return the set of {@link Node} whose members are {@link ElkClass}es
	 *         equivalent to the given {@link ElkClassExpression}
	 * @throws ElkInconsistentOntologyException
	 *             if the ontology is inconsistent
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized Node<ElkClass> getEquivalentClasses(
			ElkClassExpression classExpression)
			throws ElkInconsistentOntologyException, ElkException {
		if (classExpression instanceof ElkClass) {
			return getTaxonomyNode((ElkClass) classExpression);
		}
		// else

		return queryEquivalentClasses(classExpression);
	}

	/**
	 * Return the {@code Node} containing equivalent classes of the given
	 * {@link ElkClassExpression}. Calling of this method may trigger the
	 * computation of the taxonomy, if it has not been done yet.
	 *
	 * @param classExpression
	 *            the {@link ElkClassExpression} for which to return the
	 *            {@link Node}
	 * @return the set of {@link Node} whose members are {@link ElkClass}es
	 *         equivalent to the given {@link ElkClassExpression}
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized Node<ElkClass> getEquivalentClassesQuietly(
			ElkClassExpression classExpression) throws ElkException {
		try {
			return getEquivalentClasses(classExpression);
		} catch (final ElkInconsistentOntologyException e) {
			// All classes are equivalent to each other, so also to owl:Nothing.
			return getTaxonomyQuietly().getBottomNode();
		}
	}

	/**
	 * Return the (direct or indirect) subclasses of the given
	 * {@link ElkClassExpression} as specified by the parameter. The method
	 * returns a set of {@link Node}s, each of which representing an equivalent
	 * class of subclasses. Calling of this method may trigger the computation
	 * of the taxonomy, if it has not been done yet.
	 *
	 * @param classExpression
	 *            the {@link ElkClassExpression} for which to return the
	 *            subclass {@link Node}s
	 * @param direct
	 *            if {@code true}, only direct subclasses should be returned
	 * @return the set of {@link Node}s for direct or indirect subclasses of the
	 *         given {@link ElkClassExpression} according to the specified
	 *         parameter
	 * @throws ElkInconsistentOntologyException
	 *             if the ontology is inconsistent
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized Set<? extends Node<ElkClass>> getSubClasses(
			ElkClassExpression classExpression, boolean direct)
			throws ElkInconsistentOntologyException, ElkException {
		if (classExpression instanceof ElkClass) {
			final TaxonomyNode<ElkClass> queryNode = getTaxonomyNode(
					(ElkClass) classExpression);
			return direct ? queryNode.getDirectSubNodes()
					: queryNode.getAllSubNodes();
		} else {

			final Set<? extends Node<ElkClass>> subNodes = queryDirectSubClasses(
					classExpression);
			if (direct) {
				return subNodes;
			}
			// else all nodes

			final Taxonomy<ElkClass> taxonomy = restoreTaxonomy();

			return TaxonomyNodeUtils.getAllReachable(Operations.map(subNodes,
					new Operations.Transformation<Node<ElkClass>, TaxonomyNode<ElkClass>>() {

						@Override
						public TaxonomyNode<ElkClass> transform(
								final Node<ElkClass> node) {
							return taxonomy.getNode(node.getCanonicalMember());
						}

					}),
					new Operations.Functor<TaxonomyNode<ElkClass>, Set<? extends TaxonomyNode<ElkClass>>>() {

						@Override
						public Set<? extends TaxonomyNode<ElkClass>> apply(
								final TaxonomyNode<ElkClass> node) {
							return node.getDirectSubNodes();
						}

					});
		}

	}

	/**
	 * Return the (direct or indirect) subclasses of the given
	 * {@link ElkClassExpression} as specified by the parameter. The method
	 * returns a set of {@link Node}s, each of which representing an equivalent
	 * class of subclasses. Calling of this method may trigger the computation
	 * of the taxonomy, if it has not been done yet.
	 *
	 * @param classExpression
	 *            the {@link ElkClassExpression} for which to return the
	 *            subclass {@link Node}s
	 * @param direct
	 *            if {@code true}, only direct subclasses should be returned
	 * @return the set of {@link Node}s for direct or indirect subclasses of the
	 *         given {@link ElkClassExpression} according to the specified
	 *         parameter
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized Set<? extends Node<ElkClass>> getSubClassesQuietly(
			final ElkClassExpression classExpression, final boolean direct)
			throws ElkException {
		try {
			return getSubClasses(classExpression, direct);
		} catch (final ElkInconsistentOntologyException e) {
			// All classes are equivalent to each other, so also to owl:Nothing.
			final TaxonomyNode<ElkClass> node = getTaxonomyQuietly()
					.getBottomNode();
			return direct ? node.getDirectSubNodes() : node.getAllSubNodes();
		}
	}

	/**
	 * Return the (direct or indirect) superclasses of the given
	 * {@link ElkClassExpression} as specified by the parameter. The method
	 * returns a set of {@link Node}s, each of which representing an equivalent
	 * class of superclasses. Calling of this method may trigger the computation
	 * of the taxonomy, if it has not been done yet.
	 *
	 * @param classExpression
	 *            the {@link ElkClassExpression} for which to return the
	 *            superclass {@link Node}s
	 * @param direct
	 *            if {@code true}, only direct superclasses are returned
	 * @return the set of {@link Node}s for direct or indirect superclasses of
	 *         the given {@link ElkClassExpression} according to the specified
	 *         parameter
	 * @throws ElkInconsistentOntologyException
	 *             if the ontology is inconsistent
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized Set<? extends Node<ElkClass>> getSuperClasses(
			ElkClassExpression classExpression, boolean direct)
			throws ElkInconsistentOntologyException, ElkException {
		if (classExpression instanceof ElkClass) {
			final TaxonomyNode<ElkClass> queryNode = getTaxonomyNode(
					(ElkClass) classExpression);
			return direct ? queryNode.getDirectSuperNodes()
					: queryNode.getAllSuperNodes();
		} else {

			final Set<? extends Node<ElkClass>> superNodes = queryDirectSuperClasses(
					classExpression);
			if (direct) {
				return superNodes;
			}
			// else all nodes

			final Taxonomy<ElkClass> taxonomy = restoreTaxonomy();

			return TaxonomyNodeUtils.getAllReachable(Operations.map(superNodes,
					new Operations.Transformation<Node<ElkClass>, TaxonomyNode<ElkClass>>() {

						@Override
						public TaxonomyNode<ElkClass> transform(
								final Node<ElkClass> node) {
							return taxonomy.getNode(node.getCanonicalMember());
						}

					}),
					new Operations.Functor<TaxonomyNode<ElkClass>, Set<? extends TaxonomyNode<ElkClass>>>() {

						@Override
						public Set<? extends TaxonomyNode<ElkClass>> apply(
								final TaxonomyNode<ElkClass> node) {
							return node.getDirectSuperNodes();
						}

					});
		}

	}

	/**
	 * Return the (direct or indirect) superclasses of the given
	 * {@link ElkClassExpression} as specified by the parameter. The method
	 * returns a set of {@link Node}s, each of which representing an equivalent
	 * class of superclasses. Calling of this method may trigger the computation
	 * of the taxonomy, if it has not been done yet.
	 *
	 * @param classExpression
	 *            the {@link ElkClassExpression} for which to return the
	 *            superclass {@link Node}s
	 * @param direct
	 *            if {@code true}, only direct superclasses are returned
	 * @return the set of {@link Node}s for direct or indirect superclasses of
	 *         the given {@link ElkClassExpression} according to the specified
	 *         parameter
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized Set<? extends Node<ElkClass>> getSuperClassesQuietly(
			ElkClassExpression classExpression, boolean direct)
			throws ElkException {
		try {
			return getSuperClasses(classExpression, direct);
		} catch (final ElkInconsistentOntologyException e) {
			// All classes are equivalent to each other, so also to owl:Nothing.
			final TaxonomyNode<ElkClass> node = getTaxonomyQuietly()
					.getBottomNode();
			return direct ? node.getDirectSuperNodes()
					: node.getAllSuperNodes();
		}
	}

	/**
	 * Return the (direct or indirect) sub-properties of the given
	 * {@link ElkObjectProperty} as specified by the parameter. The method
	 * returns a set of {@link Node}s, each of which representing an equivalence
	 * class of sub-properties. Calling of this method may trigger the
	 * computation of the taxonomy, if it has not been done yet.
	 *
	 * @param property
	 *            the {@link ElkObjectProperty} for which to return the
	 *            sub-property {@link Node}s
	 * @param direct
	 *            if {@code true}, only direct sub-properties should be returned
	 * @return the set of {@link Node}s for direct or indirect sub-properties of
	 *         the given {@link ElkObjectProperty} according to the specified
	 *         parameter
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized Set<? extends Node<ElkObjectProperty>> getSubObjectProperties(
			final ElkObjectProperty property, final boolean direct)
			throws ElkException {

		final TaxonomyNode<ElkObjectProperty> queryNode = getObjectPropertyNode(
				property);

		return (direct) ? queryNode.getDirectSubNodes()
				: queryNode.getAllSubNodes();
	}

	/**
	 * Return the (direct or indirect) super-properties of the given
	 * {@link ElkObjectProperty} as specified by the parameter. The method
	 * returns a set of {@link Node}s, each of which representing an equivalence
	 * class of super-properties. Calling of this method may trigger the
	 * computation of the taxonomy, if it has not been done yet.
	 *
	 * @param property
	 *            the {@link ElkObjectProperty} for which to return the
	 *            super-property {@link Node}s
	 * @param direct
	 *            if {@code true}, only direct super-properties are returned
	 * @return the set of {@link Node}s for direct or indirect super-properties
	 *         of the given {@link ElkObjectProperty} according to the specified
	 *         parameter
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized Set<? extends Node<ElkObjectProperty>> getSuperObjectProperties(
			final ElkObjectProperty property, final boolean direct)
			throws ElkException {

		TaxonomyNode<ElkObjectProperty> queryNode = getObjectPropertyNode(
				property);

		return (direct) ? queryNode.getDirectSuperNodes()
				: queryNode.getAllSuperNodes();
	}

	/**
	 * Return the (direct or indirect) instances of the given
	 * {@link ElkClassExpression} as specified by the parameter. The method
	 * returns a set of {@link Node}s, each of which representing an equivalent
	 * class of instances. Calling of this method may trigger the computation of
	 * the realization, if it has not been done yet.
	 *
	 * @param classExpression
	 *            the {@link ElkClassExpression} for which to return the
	 *            instances {@link Node}s
	 * @param direct
	 *            if {@code true}, only direct instances are returned
	 * @return the set of {@link Node}s for direct or indirect instances of the
	 *         given {@link ElkClassExpression} according to the specified
	 *         parameter
	 * @throws ElkInconsistentOntologyException
	 *             if the ontology is inconsistent
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized Set<? extends Node<ElkNamedIndividual>> getInstances(
			ElkClassExpression classExpression, boolean direct)
			throws ElkInconsistentOntologyException, ElkException {

		if (classExpression instanceof ElkClass) {
			final TypeNode<ElkClass, ElkNamedIndividual> queryNode = getTypeNode(
					(ElkClass) classExpression);
			return direct ? queryNode.getDirectInstanceNodes()
					: queryNode.getAllInstanceNodes();
		}

		final Set<? extends Node<ElkNamedIndividual>> instances = queryDirectInstances(
				classExpression);
		if (direct) {
			return instances;
		}
		// else all instances

		final Set<? extends Node<ElkClass>> subNodes = queryDirectSubClasses(
				classExpression);
		final InstanceTaxonomy<ElkClass, ElkNamedIndividual> taxonomy = restoreInstanceTaxonomy();

		return TaxonomyNodeUtils.collectFromAllReachable(Operations.map(
				subNodes,
				new Operations.Transformation<Node<ElkClass>, TypeNode<ElkClass, ElkNamedIndividual>>() {

					@Override
					public TypeNode<ElkClass, ElkNamedIndividual> transform(
							final Node<ElkClass> node) {
						return taxonomy.getNode(node.getCanonicalMember());
					}

				}), Operations.map(instances,
						new Operations.Transformation<Node<ElkNamedIndividual>, InstanceNode<ElkClass, ElkNamedIndividual>>() {

							@Override
							public InstanceNode<ElkClass, ElkNamedIndividual> transform(
									final Node<ElkNamedIndividual> node) {
								return taxonomy.getInstanceNode(
										node.getCanonicalMember());
							}

						}),
				new Operations.Functor<TypeNode<ElkClass, ElkNamedIndividual>, Set<? extends TypeNode<ElkClass, ElkNamedIndividual>>>() {

					@Override
					public Set<? extends TypeNode<ElkClass, ElkNamedIndividual>> apply(
							final TypeNode<ElkClass, ElkNamedIndividual> node) {
						return node.getDirectSubNodes();
					}

				},
				new Operations.Functor<TypeNode<ElkClass, ElkNamedIndividual>, Set<? extends InstanceNode<ElkClass, ElkNamedIndividual>>>() {

					@Override
					public Set<? extends InstanceNode<ElkClass, ElkNamedIndividual>> apply(
							final TypeNode<ElkClass, ElkNamedIndividual> node) {
						return node.getDirectInstanceNodes();
					}

				});
	}

	/**
	 * Return the (direct or indirect) instances of the given
	 * {@link ElkClassExpression} as specified by the parameter. The method
	 * returns a set of {@link Node}s, each of which representing an equivalent
	 * class of instances. Calling of this method may trigger the computation of
	 * the realization, if it has not been done yet.
	 *
	 * @param classExpression
	 *            the {@link ElkClassExpression} for which to return the
	 *            instances {@link Node}s
	 * @param direct
	 *            if {@code true}, only direct instances are returned
	 * @return the set of {@link Node}s for direct or indirect instances of the
	 *         given {@link ElkClassExpression} according to the specified
	 *         parameter
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized Set<? extends Node<ElkNamedIndividual>> getInstancesQuietly(
			ElkClassExpression classExpression, boolean direct)
			throws ElkException {
		try {
			return getInstances(classExpression, direct);
		} catch (final ElkInconsistentOntologyException e) {
			// All classes are equivalent to each other, so also to owl:Nothing.
			final TypeNode<ElkClass, ElkNamedIndividual> node = getInstanceTaxonomyQuietly()
					.getBottomNode();
			return direct ? node.getDirectInstanceNodes()
					: node.getAllInstanceNodes();
		}
	}

	/**
	 * Return the (direct or indirect) types of the given
	 * {@link ElkNamedIndividual}. The method returns a set of {@link Node}s,
	 * each of which representing an equivalent class of types. Calling of this
	 * method may trigger the computation of the realization, if it has not been
	 * done yet.
	 *
	 * @param elkNamedIndividual
	 *            the {@link ElkNamedIndividual} for which to return the types
	 *            {@link Node}s
	 * @param direct
	 *            if {@code true}, only direct types are returned
	 * @return the set of {@link Node}s for the direct or indirect types of the
	 *         given {@link ElkNamedIndividual} according to the specified
	 *         parameter
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized Set<? extends Node<ElkClass>> getTypes(
			ElkNamedIndividual elkNamedIndividual, boolean direct)
			throws ElkException {
		InstanceNode<ElkClass, ElkNamedIndividual> node = getInstanceNode(
				elkNamedIndividual);
		return direct ? node.getDirectTypeNodes() : node.getAllTypeNodes();
	}

	/**
	 * Check if the given {@link ElkClassExpression} is satisfiable, that is, if
	 * it can possibly have instances. {@link ElkClassExpression}s are not
	 * satisfiable if they are equivalent to {@code owl:Nothing}. A satisfiable
	 * {@link ElkClassExpression} is also called consistent or coherent. Calling
	 * of this method may trigger the computation of the taxonomy, if it has not
	 * been done yet.
	 *
	 * @param classExpression
	 *            the {@link ElkClassExpression} for which to check
	 *            satisfiability
	 * @return {@code true} if the given input is satisfiable
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized boolean isSatisfiable(
			ElkClassExpression classExpression) throws ElkException {

		if (classExpression instanceof ElkClass) {
			final TaxonomyNode<ElkClass> queryNode = getTaxonomyNode(
					(ElkClass) classExpression);
			return !queryNode.contains(getElkFactory().getOwlNothing());
		}

		return querySatisfiability(classExpression);
	}

	/**
	 * Check if the given {@link ElkClassExpression} is satisfiable, that is, if
	 * it can possibly have instances. {@link ElkClassExpression}s are not
	 * satisfiable if they are equivalent to {@code owl:Nothing}. A satisfiable
	 * {@link ElkClassExpression} is also called consistent or coherent. Calling
	 * of this method may trigger the computation of the taxonomy, if it has not
	 * been done yet.
	 *
	 * @param classExpression
	 *            the {@link ElkClassExpression} for which to check
	 *            satisfiability
	 * @return {@code true} if the given input is satisfiable
	 * @throws ElkException
	 *             if the result cannot be computed
	 */
	public synchronized boolean isSatisfiableQuietly(
			final ElkClassExpression classExpression) throws ElkException {
		try {
			return isSatisfiable(classExpression);
		} catch (final ElkInconsistentOntologyException e) {
			// Any class is unsatisfiable.
			return false;
		}
	}

}


package org.semanticweb.elk.util.logging.statistics;
/*
 * #%L
 * ELK Utilities for Logging
 * $Id:$
 * $HeadURL:$
 * %%
 * Copyright (C) 2011 - 2014 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.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;

public class StatisticsPrinter {
	/**
	 * the total width of the line to be printed
	 */
	private static final int FORMAT_WIDTH_ = 80;
	/**
	 * We are interested in substrings of the form "%***{***}*" the internal
	 * part in {***} will be the corresponding column heading parameter. The
	 * rest should be the formatter specifying how the values for this column
	 * are processed. Example: "%,{time}d"
	 */
	private static final Pattern REGEXP = Pattern
			.compile("(%[^\\{]*)\\{([^\\.\\}]*)\\}(.)");

	/**
	 * the logger used to print the statistics messages
	 */
	private final Logger logger_;

	/**
	 * specifies how the header will be formatted
	 */
	private final String headerFormat_;

	/**
	 * the header parameters used for formatting
	 */
	private final Object[] headerParams_;

	/**
	 * specifies how the values are formatted
	 */
	private final String valuesFormat_;

	/**
	 * how many symbols should be added to obtain the full width
	 * {@value #FORMAT_WIDTH_} assuming the value in the first column is empty;
	 * if it is not empty, the number of symbols added should be reduced by the
	 * value's length
	 */
	private final int maxPaddingWidth_;

	public StatisticsPrinter(Logger logger, String pattern,
			Object... sampleValues) {
		this.logger_ = logger;
		// used to find matches for regular expressions
		Matcher matcher = REGEXP.matcher(pattern);
		// used to use the found matches for the second time
		Matcher m = REGEXP.matcher(pattern);
		// header values to be extracted from the pattern
		List<String> headers = new LinkedList<String>();
		// used to build the formatting string for the headers
		StringBuffer headerFormatBuilder = new StringBuffer();
		// used to build the formatting string for the values
		StringBuffer lineFormatBuilder = new StringBuffer();
		// the formatted first sample value to be used in
		// the calculation of the padding
		String firstSampleValue = "";
		for (int i = 0; matcher.find(); i++) {
			m.find();
			// find the matching part in {}
			String header = matcher.group(2);
			headers.add(header);
			// formatting the corresponding sample value
			String formattedSample = String.format(
					matcher.group(1) + matcher.group(3), sampleValues[i]);
			if (i == 0) {
				firstSampleValue = formattedSample;
				// we do not need to set the width; it will be padded
				matcher.appendReplacement(lineFormatBuilder, matcher.group(1)
						+ matcher.group(3));
				m.appendReplacement(headerFormatBuilder, "%s");

			} else {
				// we set the width to the maximum of the width of the
				// column heading and the width of the formatted sample
				// so that all fits nicely
				int width = Math.max(header.length(), formattedSample.length());
				matcher.appendReplacement(lineFormatBuilder, matcher.group(1)
						+ width + matcher.group(3));
				m.appendReplacement(headerFormatBuilder, "%" + width + "s");
			}
		}
		matcher.appendTail(lineFormatBuilder);
		m.appendTail(headerFormatBuilder);

		this.headerFormat_ = headerFormatBuilder.toString();
		this.headerParams_ = headers.toArray();
		this.valuesFormat_ = lineFormatBuilder.toString();
		this.maxPaddingWidth_ = FORMAT_WIDTH_
				- String.format(valuesFormat_, sampleValues).length()
				+ firstSampleValue.length();
	}

	/**
	 * Prints a line separator
	 */
	public void printSeparator() {
		String separator = getString('-', FORMAT_WIDTH_);
		logger_.debug(separator);
	}

	/**
	 * Prints the heading together with the separators
	 */
	public void printHeader() {
		printSeparator();
		addPadding(' ', headerParams_);
		logger_.debug(String.format(headerFormat_, headerParams_));
		printSeparator();
	}

	/**
	 * Appends a string consisting of the given character to the first value so
	 * that when the values when formatted have in total {@value #FORMAT_WIDTH_}
	 * characters
	 *
	 * @param c
	 * @param values
	 * @return
	 */
	Object[] addPadding(char c, Object... values) {
		String firstValue = values[0].toString();
		int paddingLength = maxPaddingWidth_ - firstValue.length();
		if (paddingLength > 0) {
			String padding = getString(c, paddingLength);
			values[0] = firstValue + padding;
		}
		return values;
	}

	/**
	 * Formats and the given values, adding padding symbols if necessary. The
	 * given array may be modified, but the values themselves are not modified.
	 *
	 * @param values
	 */
	public void print(Object... values) {
		addPadding('.', values);
		logger_.debug(String.format(valuesFormat_, values));
	}

	/**
	 * Creates a string of the given length consisting of the given character
	 *
	 * @param c
	 * @param n
	 * @return
	 */
	static String getString(char c, int n) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < n; i++) {
			sb.append(c);
		}
		return sb.toString();
	}
}


/*
 * #%L
 * ELK OWL Object Interfaces
 *
 * $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.owl.predefined;

import org.semanticweb.elk.owl.iris.ElkFullIri;
import org.semanticweb.elk.owl.iris.ElkIri;

/**
 *
 * <a href= "http://www.w3.org/TR/owl2-syntax/#IRIs" >Reserved Vocabulary of OWL
 * 2 with Special Treatment<a> in OWL 2 (see Table 3 in the link).
 *
 * @author "Yevgeny Kazakov"
 *
 */
public class PredefinedElkIris {

	public static final ElkIri

	OWL_BACKWARD_COMPATIBLE_WITH = new ElkFullIri(PredefinedElkPrefix.OWL,
			"backwardCompatibleWith"),

			OWL_BOTTOM_DATA_PROPERTY = new ElkFullIri(PredefinedElkPrefix.OWL,
					"bottomDataProperty"),

			OWL_BOTTOM_OBJECT_PROPERTY = new ElkFullIri(
					PredefinedElkPrefix.OWL, "bottomObjectProperty"),

			OWL_DEPRECATED = new ElkFullIri(PredefinedElkPrefix.OWL,
					"deprecated"),

			OWL_INCOMPATIBLE_WITH = new ElkFullIri(PredefinedElkPrefix.OWL,
					"incompatibleWith"),

			OWL_NOTHING = new ElkFullIri(PredefinedElkPrefix.OWL, "Nothing"),

			OWL_PRIOR_VERSION = new ElkFullIri(PredefinedElkPrefix.OWL,
					"priorVersion"),

			OWL_RATIONAL = new ElkFullIri(PredefinedElkPrefix.OWL, "rational"),

			OWL_REAL = new ElkFullIri(PredefinedElkPrefix.OWL, "real"),

			OWL_VERSION_INFO = new ElkFullIri(PredefinedElkPrefix.OWL,
					"versionInfo"),

			OWL_THING = new ElkFullIri(PredefinedElkPrefix.OWL, "Thing"),

			OWL_TOP_DATA_PROPERTY = new ElkFullIri(PredefinedElkPrefix.OWL,
					"topDataProperty"),

			OWL_TOP_OBJECT_PROPERTY = new ElkFullIri(PredefinedElkPrefix.OWL,
					"topObjectProperty"),

			RDF_LANG_RANGE = new ElkFullIri(PredefinedElkPrefix.RDF,
					"langRange"),

			RDF_PLAIN_LITERAL = new ElkFullIri(PredefinedElkPrefix.RDF,
					"PlainLiteral"),

			RDF_XML_LITERAL = new ElkFullIri(PredefinedElkPrefix.RDF,
					"XMLLiteral"),

			RDFS_COMMENT = new ElkFullIri(PredefinedElkPrefix.RDFS, "comment"),

			RDFS_IS_DEFINED_BY = new ElkFullIri(PredefinedElkPrefix.RDFS,
					"isDefinedBy"),

			RDFS_LABEL = new ElkFullIri(PredefinedElkPrefix.RDFS, "label"),

			RDFS_LITERAL = new ElkFullIri(PredefinedElkPrefix.RDFS, "Literal"),

			RDFS_SEE_ALSO = new ElkFullIri(PredefinedElkPrefix.RDFS, "seeAlso"),

			XSD_ANY_URI = new ElkFullIri(PredefinedElkPrefix.XSD, "anyURI"),

			XSD_BASE_64_BINARY = new ElkFullIri(PredefinedElkPrefix.XSD,
					"base64Binary"),

			XSD_BOOLEAN = new ElkFullIri(PredefinedElkPrefix.XSD, "boolean"),

			XSD_BYTE = new ElkFullIri(PredefinedElkPrefix.XSD, "boolean"),

			XSD_DATE_TIME = new ElkFullIri(PredefinedElkPrefix.XSD, "dateTime"),

			XSD_DATE_TIME_STAMP = new ElkFullIri(PredefinedElkPrefix.XSD,
					"dateTimeStamp"),

			XSD_DECIMAL = new ElkFullIri(PredefinedElkPrefix.XSD, "decimal"),

			XSD_DOUBLE = new ElkFullIri(PredefinedElkPrefix.XSD, "double"),

			XSD_FLOAT = new ElkFullIri(PredefinedElkPrefix.XSD, "float"),

			XSD_HEX_BINARY = new ElkFullIri(PredefinedElkPrefix.XSD,
					"hexBinary"),

			XSD_INT = new ElkFullIri(PredefinedElkPrefix.XSD, "int"),

			XSD_INTEGER = new ElkFullIri(PredefinedElkPrefix.XSD, "integer"),

			XSD_LANGUAGE = new ElkFullIri(PredefinedElkPrefix.XSD, "language"),

			XSD_LENGTH = new ElkFullIri(PredefinedElkPrefix.XSD, "length"),

			XSD_LONG = new ElkFullIri(PredefinedElkPrefix.XSD, "long"),

			XSD_MAX_EXCLUSIVE = new ElkFullIri(PredefinedElkPrefix.XSD,
					"maxExclusive"),

			XSD_MAX_INCLUSIVE = new ElkFullIri(PredefinedElkPrefix.XSD,
					"maxInclusive"),

			XSD_MAX_LENGTH = new ElkFullIri(PredefinedElkPrefix.XSD,
					"maxLength"),

			XSD_MIN_EXCLUSIVE = new ElkFullIri(PredefinedElkPrefix.XSD,
					"minExclusive"),

			XSD_MIN_INCLUSIVE = new ElkFullIri(PredefinedElkPrefix.XSD,
					"minInclusive"),

			XSD_MIN_LENGTH = new ElkFullIri(PredefinedElkPrefix.XSD,
					"minLength"),

			XSD_NAME = new ElkFullIri(PredefinedElkPrefix.XSD, "Name"),

			XSD_NC_NAME = new ElkFullIri(PredefinedElkPrefix.XSD, "NCName"),

			XSD_NEGATIVE_INTEGER = new ElkFullIri(PredefinedElkPrefix.XSD,
					"negativeInteger"),

			XSD_NM_TOKEN = new ElkFullIri(PredefinedElkPrefix.XSD, "NMTOKEN"),

			XSD_NON_NEGATIVE_INTEGER = new ElkFullIri(PredefinedElkPrefix.XSD,
					"nonNegativeInteger"),

			XSD_NON_POSITIVE_INTEGER = new ElkFullIri(PredefinedElkPrefix.XSD,
					"nonPositiveInteger"),

			XSD_NORMALIZED_STRING = new ElkFullIri(PredefinedElkPrefix.XSD,
					"normalizedString"),

			XSD_PATTERN = new ElkFullIri(PredefinedElkPrefix.XSD, "pattern"),

			XSD_POSITIVE_INTEGER = new ElkFullIri(PredefinedElkPrefix.XSD,
					"positiveInteger"),

			XSD_SHORT = new ElkFullIri(PredefinedElkPrefix.XSD, "short"),

			XSD_STRING = new ElkFullIri(PredefinedElkPrefix.XSD, "string"),

			XSD_TOKEN = new ElkFullIri(PredefinedElkPrefix.XSD, "token"),

			XSD_UNSIGNED_BYTE = new ElkFullIri(PredefinedElkPrefix.XSD,
					"unsignedByte"),

			XSD_UNSIGNED_INT = new ElkFullIri(PredefinedElkPrefix.XSD,
					"unsignedInt"),

			XSD_UNSIGNED_LONG = new ElkFullIri(PredefinedElkPrefix.XSD,
					"unsignedLong"),

			XSD_UNSIGNED_SHORT = new ElkFullIri(PredefinedElkPrefix.XSD,
					"unsignedShort")

			;

	/**
	 * Defines an ordering on IRIs starting with {@link #OWL_NOTHING},
	 * {@link #OWL_THING}, followed by the remaining IRIs in alphabetical order.
	 *
	 * @param firstIri
	 *            the fist {@link ElkIri} to compare with the second
	 * @param secondIri
	 *            the second {@link ElkIri} to compare with the first
	 * @return a negative integer, zero, or a positive integer as the first IRI
	 *         is less, equal, or greater than the second IRI in the specified
	 *         order
	 */
	public static int compare(ElkIri firstIri, ElkIri secondIri) {
		boolean isOwl0 = firstIri.equals(OWL_THING)
				|| firstIri.equals(OWL_NOTHING);
		boolean isOwl1 = secondIri.equals(OWL_THING)
				|| secondIri.equals(OWL_NOTHING);

		if (isOwl0 == isOwl1)
			return firstIri.compareTo(secondIri);
		// else
		return isOwl0 ? -1 : 1;
	}
}


/*
 * #%L
 * ELK Command Line Interface
 * $Id:$
 * $HeadURL:$
 * %%
 * Copyright (C) 2011 - 2013 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.ore;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import org.semanticweb.elk.exceptions.ElkException;
import org.semanticweb.elk.loading.AxiomLoader;
import org.semanticweb.elk.loading.Owl2StreamLoader;
import org.semanticweb.elk.owl.interfaces.ElkClass;
import org.semanticweb.elk.owl.interfaces.ElkNamedIndividual;
import org.semanticweb.elk.owl.parsing.Owl2ParserFactory;
import org.semanticweb.elk.owl.parsing.javacc.Owl2FunctionalStyleParserFactory;
import org.semanticweb.elk.reasoner.ElkInconsistentOntologyException;
import org.semanticweb.elk.reasoner.Reasoner;
import org.semanticweb.elk.reasoner.ReasonerFactory;
import org.semanticweb.elk.reasoner.taxonomy.model.InstanceTaxonomy;
import org.semanticweb.elk.reasoner.taxonomy.model.Taxonomy;

/**
 * The CLI tool for the ORE 2013 contest which uses the ELK's native OWL FSS
 * parser and includes the parsing/loading/indexing time in the total wall time.
 *
 * @author Pavel Klinov
 *
 *         pavel.klinov@uni-ulm.de
 */
public class NativeRunner {

	enum Task {
		CLASSIFICATION {

			@Override
			public String toString() {
				return "classification";
			}
		},

		CONSISTENCY {

			@Override
			public String toString() {
				return "consistency";
			}
		},

		REALISATION {

			@Override
			public String toString() {
				return "realisation";
			}
		},
	};

	/**
	 * Arguments are as follows: 0 - name of the reasoning task (SAT, query,
	 * classification, consistency) 1 - ontology path 2 - output path 3 -
	 * concept URI, in case of SAT
	 *
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		Task task = validateArgs(args);
		// help
		if (task == null) {
			printHelp();
			return;
		}

		NativeRunner runner = new NativeRunner();

		runner.run(args, task);
	}

	void run(String[] args, Task task) throws Exception {
		File input = getOutputFile(args[1]);
		File output = getOutputFile(args[2]);
		// create reasoner
		ReasonerFactory reasoningFactory = new ReasonerFactory();
		Owl2ParserFactory parserFactory = new Owl2FunctionalStyleParserFactory();
		AxiomLoader.Factory loaderFactory = new Owl2StreamLoader.Factory(
				parserFactory, input);
		Reasoner reasoner = reasoningFactory.createReasoner(loaderFactory);

		boolean printedStarted = false, printedTime = false;

		long ts = System.currentTimeMillis();

		try {
			loadOntology(reasoner);

			ts = System.currentTimeMillis();

			System.out.println("Started " + task.toString() + " on " + input);
			printedStarted = true;

			switch (task) {
			case CLASSIFICATION:
				Taxonomy<ElkClass> taxonomy = reasoner.getTaxonomyQuietly();

				printTime(ts);
				printedTime = true;

				writeClassTaxonomyToFile(output, taxonomy);

				break;
			case REALISATION:
				InstanceTaxonomy<ElkClass, ElkNamedIndividual> instanceTaxonomy = reasoner.getInstanceTaxonomyQuietly();

				printTime(ts);
				printedTime = true;

				writeInstanceTaxonomyToFile(output, instanceTaxonomy);

				break;
			case CONSISTENCY:
				boolean isConsistent = reasoner.isInconsistent();

				printTime(ts);
				printedTime = true;

				writeStringToFile(output, String.valueOf(!isConsistent), false);

				break;
			default:
			}
		} catch (ElkException e) {
			System.err.println("ELK error: " + e);
			if (!printedStarted) {
				ts = System.currentTimeMillis();
				System.out.println("Started " + task.toString() + " on " + input);
			}
			if (!printedTime) {
				printTime(ts);
			}
		} finally {
			printCompleted(task, input);
			reasoner.shutdown();
		}
	}

	protected void loadOntology(Reasoner reasoner) throws ElkException {
		// no eager loading so it will be done later and included in measurements
	}

	private File getOutputFile(String path) {
		File file = new File(path);

		try {
			if (!file.isAbsolute()) {
				file = new File(new File(".").getCanonicalPath() + "/" + path);
			}

			file.getParentFile().mkdirs();

			if (!file.exists()) {
				if (!file.createNewFile()) {
					throw new IOException(
							"Output file does not exist and cannot be created");
				}
			}
		} catch (IOException e) {
			System.err.println("Error: " + e.getMessage());
		}

		return file;
	}

	private void printTime(long ts) {
		System.out.println("Operation time: "
				+ (System.currentTimeMillis() - ts));

	}

	private void printCompleted(Task task, File input) {
		System.out.println("Completed " + task.toString() + " on " + input);
	}

	static Task validateArgs(String[] args) {
		Task task = null;

		if (args.length < 3) {
			return null;// not enough arguments
		}

		for (Task t : Task.values()) {
			if (t.name().equalsIgnoreCase(args[0])) {
				task = t;
				break;
			}
		}

		// strip possible quotes
		args[1] = stripQuotes(args[1]);
		args[2] = stripQuotes(args[2]);

		return task;
	}

	private static String stripQuotes(String arg) {
		return arg.replaceAll("^\"|\"$", "");
	}

	static void printHelp() {
		System.out
				.println("The system requires the following command line arguments:\n"
						+ "* name of the reasoning task, one of: CONSISTENCY, CLASSIFICATION, REALISATION case insensitive\n"
						+ "* path to the ontology file\n"
						+ "* path to the output file\n");
	}

	void writeStringToFile(File file, String string, boolean append)
			throws IOException, ElkException {
		FileWriter fstream = new FileWriter(file, append);
		BufferedWriter writer = new BufferedWriter(fstream);

		writer.write(string);
		writer.flush();
		writer.close();
	}

	void writeClassTaxonomyToFile(File file, Taxonomy<ElkClass> taxonomy)
			throws IOException, ElkInconsistentOntologyException, ElkException {
		OreTaxonomyPrinter.printClassTaxonomy(taxonomy, file);
	}

	void writeInstanceTaxonomyToFile(File file,
			InstanceTaxonomy<ElkClass, ElkNamedIndividual> taxonomy)
			throws IOException, ElkInconsistentOntologyException, ElkException {
		OreTaxonomyPrinter.printInstanceTaxonomy(taxonomy, file);
	}

}


package org.semanticweb.elk.protege.proof;

/*-
 * #%L
 * ELK OWL API Binding
 * $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 java.util.AbstractList;
import java.util.Collection;
import java.util.List;

import org.liveontologies.puli.Inference;
import org.liveontologies.puli.ProofNode;
import org.liveontologies.puli.ProofStep;
import org.semanticweb.elk.owl.inferences.ElkClassInclusionExistentialComposition;
import org.semanticweb.elk.owl.inferences.ElkClassInclusionExistentialTransitivity;
import org.semanticweb.elk.owl.inferences.ElkPropertyInclusionOfTransitiveObjectProperty;
import org.semanticweb.elk.owl.interfaces.ElkClassExpression;
import org.semanticweb.elk.owl.interfaces.ElkObjectSomeValuesFrom;
import org.semanticweb.elk.owl.interfaces.ElkSubClassOfAxiom;
import org.semanticweb.elk.owlapi.proofs.ElkOwlInference;
import org.semanticweb.owlapi.model.OWLAxiom;

/**
 * An {@link ProofStep} resulting from rewriting nested
 * {@link ElkClassInclusionExistentialComposition} inferences into one
 * {@link ElkClassInclusionExistentialTransitivity} inference.
 *
 * For example the sequence of inferences
 *
 *

 *
 *       B ⊑ ∃T.C   C ⊑ ∃T.D   T∘T ⊑ T
 *       ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
 * A ⊑ ∃T.B   B ⊑ ∃T.D   T∘T ⊑ T
 * ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
 *         A ⊑ ∃T.D
 *

 *
 * with T∘T ⊑ T derived only by
 * {@link ElkPropertyInclusionOfTransitiveObjectProperty}
 *
 *

 * TransitiveObjectProperty(T)
 * ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
 *         T∘T ⊑ T
 *

 *
 * is replaced with one inference
 *
 *

 * A ⊑ ∃T.B   B ⊑ ∃T.C   C ⊑ ∃T.D   TransitiveObjectProperty(T)
 * ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
 *                   A ⊑ ∃T.D
 *

 *
 * The replacement is done provided there is only one inference deriving each
 * premise of the inference and these premises are derived by either a similar
 * {@link ElkClassInclusionExistentialComposition} inference or
 * {@link ElkPropertyInclusionOfTransitiveObjectProperty} (in case of the last
 * premise).
 *
 * @author Yevgeny Kazakov
 */
public class InlinedClassInclusionExistentialPropertyExpansionStep
		extends AbstractInlinedStep {

	public final static String NAME = ElkClassInclusionExistentialTransitivity.NAME;

	private InlinedClassInclusionExistentialPropertyExpansionStep(
			ProofStep<OWLAxiom> step, ProofNode<OWLAxiom> transitivityNode) {
		super(step);
		addPremise(transitivityNode);
	}

	@Override
	public String getName() {
		return NAME;
	}

	static ProofStep<OWLAxiom> convert(ProofStep<OWLAxiom> step) {
		ProofNode<OWLAxiom> transitivityNode = canConvertStep(step);
		if (transitivityNode == null) {
			return null;
		}
		// else
		return new InlinedClassInclusionExistentialPropertyExpansionStep(step,
				transitivityNode);
	}

	/**
	 * Checks if {@link ProofStep} is derived by
	 * {@link ElkClassInclusionExistentialComposition} inference where the last
	 * premise is derived from
	 * {@link ElkPropertyInclusionOfTransitiveObjectProperty}
	 *
	 * @param step
	 * @return the transitivity axiom node that is the premise of the inference
	 *         for the last premise
	 */
	static ProofNode<OWLAxiom> canConvertStep(ProofStep<OWLAxiom> step) {
		if (step.getName() != ElkClassInclusionExistentialComposition.NAME) {
			return null;
		}
		List<? extends ProofNode<OWLAxiom>> premises = step.getPremises();
		ProofNode<OWLAxiom> lastPremise = premises.get(premises.size() - 1);
		Collection<? extends ProofStep<OWLAxiom>> lastPremiseSteps = lastPremise
				.getInferences();
		if (lastPremiseSteps.size() != 1) {
			return null;
		}
		// else
		for (ProofStep<OWLAxiom> lastPremiseStep : lastPremiseSteps) {
			if (lastPremiseStep
					.getName() == ElkPropertyInclusionOfTransitiveObjectProperty.NAME) {
				return lastPremiseStep.getPremises().get(0);
			}
		}
		// else
		return null;
	}

	@Override
	void process(ProofStep<OWLAxiom> step) {
		List<? extends ProofNode<OWLAxiom>> premises = step.getPremises();
		for (int i = 0; i < premises.size() - 1; i++) {
			ProofNode<OWLAxiom> premise = premises.get(i);
			if (!process(premise)) {
				// inferences for the premise cannot be flattened
				addPremise(premise);
			}
		}
	}

	private boolean process(ProofNode<OWLAxiom> node) {
		Collection<? extends ProofStep<OWLAxiom>> steps = node.getInferences();
		if (steps.size() > 1) {
			// don't expand multiple inferences
			return false;
		}
		for (ProofStep<OWLAxiom> step : steps) {
			// just one step
			if (canConvertStep(step) != null) {
				process(step);
				return true;
			}
		}
		// else
		return false;
	}

	@Override
	public Inference<OWLAxiom> getInference() {
		return new ElkOwlInference(
				FACTORY.getElkClassInclusionExistentialTransitivity(
						getElkSuperClassExistential(getPremises().get(0))
								.getProperty(),
						new AbstractList<ElkClassExpression>() {

							@Override
							public ElkClassExpression get(int index) {
								switch (index) {
								case 0:
									return getElkSubClassOfAxiom(
											getPremises().get(0))
													.getSubClassExpression();
								default:
									return getElkSuperClassExistential(
											getPremises().get(index - 1))
													.getFiller();
								}
							}

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

	private ElkSubClassOfAxiom getElkSubClassOfAxiom(ProofNode<OWLAxiom> node) {
		return (ElkSubClassOfAxiom) convertNodeMember(node);
	}

	private ElkObjectSomeValuesFrom getElkSuperClassExistential(
			ProofNode<OWLAxiom> node) {
		return (ElkObjectSomeValuesFrom) getElkSubClassOfAxiom(node)
				.getSuperClassExpression();
	}

}


/*
 * #%L
 * ELK Reasoner
 * $Id:$
 * $HeadURL:$
 * %%
 * Copyright (C) 2011 - 2013 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.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.semanticweb.elk.owl.interfaces.ElkClass;
import org.semanticweb.elk.owl.interfaces.ElkObject;
import org.semanticweb.elk.reasoner.indexing.classes.DifferentialIndex;
import org.semanticweb.elk.reasoner.indexing.classes.OntologyIndexDummyChangeListener;
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.IndexedContextRoot;
import org.semanticweb.elk.reasoner.indexing.model.ModifiableIndexedClassExpression;
import org.semanticweb.elk.reasoner.indexing.model.OntologyIndex;
import org.semanticweb.elk.reasoner.saturation.SaturationState;
import org.semanticweb.elk.reasoner.saturation.SaturationStateDummyChangeListener;
import org.semanticweb.elk.reasoner.saturation.context.Context;
import org.semanticweb.elk.reasoner.taxonomy.ConcurrentClassTaxonomy;
import org.semanticweb.elk.reasoner.taxonomy.DummyNodeStoreListener;
import org.semanticweb.elk.reasoner.taxonomy.DummyTaxonomyListener;
import org.semanticweb.elk.reasoner.taxonomy.ElkClassKeyProvider;
import org.semanticweb.elk.reasoner.taxonomy.model.Node;
import org.semanticweb.elk.reasoner.taxonomy.model.NodeStore;
import org.semanticweb.elk.reasoner.taxonomy.model.Taxonomy;
import org.semanticweb.elk.reasoner.taxonomy.model.TaxonomyNode;
import org.semanticweb.elk.reasoner.taxonomy.model.UpdateableTaxonomy;
import org.semanticweb.elk.util.collections.Operations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Stores information about the state of the class taxonomy
 *
 * @author Pavel Klinov
 *
 *         pavel.klinov@uni-ulm.de
 * @author Peter Skocovsky
 */
public class ClassTaxonomyState {

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

	private UpdateableTaxonomy<ElkClass> taxonomy_ = null;

	/**
	 * Contains at least all classes that are in ontology, but either were
	 * removed from taxonomy or their super-nodes in taxonomy were removed since
	 * the last completed construction of the taxonomy.
	 */
	private final Queue<IndexedClass> toAdd_ = new ConcurrentLinkedQueue<IndexedClass>();

	/**
	 * Contains at least all classes that are in taxonomy, but either were
	 * removed from ontology or their context became not saturated since the
	 * last completed construction of the taxonomy.
	 */
	private final Queue<IndexedClass> toRemove_ = new ConcurrentLinkedQueue<IndexedClass>();

	private final ElkObject.Factory elkFactory_;

	private final OntologyIndex ontologyIndex_;

	private final SaturationState<?> saturationState_;

	private final ElkPolarityExpressionConverter converter_;

	private final List<Listener> listeners_ = new ArrayList<Listener>();

	<C extends Context> ClassTaxonomyState(
			final SaturationState<C> saturationState,
			final DifferentialIndex ontologyIndex,
			final ElkObject.Factory elkFactory,
			final Collection<Listener> listeners) {

		this.elkFactory_ = elkFactory;
		this.ontologyIndex_ = ontologyIndex;
		this.saturationState_ = saturationState;
		this.converter_ = new ElkPolarityExpressionConverterImpl(elkFactory,
				ontologyIndex);
		this.listeners_.addAll(listeners);

		resetTaxonomy();

		ontologyIndex.addListener(new OntologyIndexDummyChangeListener() {

			@Override
			public void classAddition(final IndexedClass cls) {
				toAdd_.add(cls);
			}

			@Override
			public void classRemoval(final IndexedClass cls) {
				toRemove_.add(cls);
			}

		});

		saturationState
				.addListener(new SaturationStateDummyChangeListener<C>() {

					@Override
					public void contextMarkNonSaturated(final C context) {
						final IndexedContextRoot root = context.getRoot();
						if (root instanceof IndexedClass) {
							final IndexedClass cls = (IndexedClass) root;
							toRemove_.add(cls);
						}
					}

					@Override
					public void contextsClear() {
						// The whole taxonomy must be computed from scratch.
						resetTaxonomy();
					}

				});

	}

	public <C extends Context> ClassTaxonomyState(
			final SaturationState<C> saturationState,
			final DifferentialIndex ontologyIndex,
			final ElkObject.Factory elkFactory) {
		this(saturationState, ontologyIndex, elkFactory,
				Collections.<Listener> emptyList());
	}

	private final NodeStore.Listener<ElkClass> nodeStoreListener_ = new DummyNodeStoreListener<ElkClass>() {

		@Override
		public void memberForNodeDisappeared(final ElkClass member,
				final Node<ElkClass> node) {
			addToAdd(member);
		}

	};

	private final Taxonomy.Listener<ElkClass> taxonomyListener_ = new DummyTaxonomyListener<ElkClass>() {

		@Override
		public void directSuperNodesDisappeared(
				final TaxonomyNode<ElkClass> subNode) {
			for (final ElkClass elkClass : subNode) {
				addToAdd(elkClass);
			}
		}

	};

	public UpdateableTaxonomy<ElkClass> getTaxonomy() {
		return taxonomy_;
	}

	private void addToAdd(final ElkClass elkClass) {
		final ModifiableIndexedClassExpression converted = elkClass
				.accept(converter_);
		if (converted != null && (converted instanceof IndexedClass)) {
			final IndexedClass cls = (IndexedClass) converted;
			toAdd_.add(cls);
		}
	}

	/**
	 * Prunes {@link #toAdd_}.
	 *

	 * {@code taxonomy_} must not be {@code null}!
	 *
	 * @return The resulting size of {@link #toAdd_}.
	 */
	private int pruneToAdd() {
		final Iterator<IndexedClass> iter = toAdd_.iterator();
		int size = 0;
		while (iter.hasNext()) {
			final IndexedClass cls = iter.next();
			/* @formatter:off
			 *
			 * Should be pruned when:
			 * it is not in ontology, or
			 * it is in the top node, or
			 * it has super-nodes in taxonomy.
			 *
			 * @formatter:on
			 */
			if (!cls.occurs()) {
				iter.remove();
				continue;
			}
			// else
			final Context context = saturationState_.getContext(cls);
			if (context == null || !context.isInitialized()
					|| !context.isSaturated()) {
				// it is not saturated.
				size++;
				continue;
			}
			// else
			final TaxonomyNode<ElkClass> node = taxonomy_
					.getNode(cls.getElkEntity());
			if (node == null) {
				// it is not in taxonomy
				size++;
				continue;
			}
			// else
			if (node.equals(taxonomy_.getTopNode())) {
				iter.remove();
				continue;
			}
			// else
			if (!node.getDirectSuperNodes().isEmpty()) {
				iter.remove();
				continue;
			}
			// else
			size++;
		}
		return size;
	}

	/**
	 * Returns collection that contains at least all classes that are in
	 * ontology, but either are removed from taxonomy or their super-nodes in
	 * taxonomy were removed.
	 *
	 * @return collection that contains at least all classes that are in
	 *         ontology, but either are removed from taxonomy or their
	 *         super-nodes in taxonomy were removed.
	 */
	Collection<IndexedClass> getToAdd() {
		final int size = pruneToAdd();
		/*
		 * since getting the size of the queue is a linear operation, use the
		 * computed size
		 */
		return Operations.getCollection(toAdd_, size);
	}

	/**
	 * Prunes {@link #toRemove_}.
	 *

	 * {@code taxonomy_} must not be {@code null}!
	 *
	 * @return The resulting size of {@link #toRemove_}.
	 */
	private int pruneToRemove() {
		final Iterator<IndexedClass> iter = toRemove_.iterator();
		int size = 0;
		while (iter.hasNext()) {
			final IndexedClass cls = iter.next();
			/* @formatter:off
			 *
			 * Should be pruned when
			 * it is not in taxonomy, or
			 * it is in the bottom class.
			 *
			 * @formatter:on
			 */
			final TaxonomyNode<ElkClass> node = taxonomy_
					.getNode(cls.getElkEntity());
			if (node == null) {
				iter.remove();
				continue;
			}
			// else
			if (cls == ontologyIndex_.getOwlNothing()) {
				iter.remove();
				continue;
			}
			size++;
		}
		return size;
	}

	/**
	 * Returns collection that contains at least all classes that are in
	 * taxonomy, but either are removed from ontology or their context became
	 * not saturated.
	 *
	 * @return collection that contains at least all classes that are in
	 *         taxonomy, but either are removed from ontology or their context
	 *         became not saturated.
	 */
	Collection<IndexedClass> getToRemove() {
		final int size = pruneToRemove();
		/*
		 * since getting the size of the queue is a linear operation, use the
		 * computed size
		 */
		return Operations.getCollection(toRemove_, size);
	}

	void resetTaxonomy() {
		LOGGER_.trace("Reset class taxonomy");

		final UpdateableTaxonomy<ElkClass> old = taxonomy_;
		if (taxonomy_ != null) {
			taxonomy_.removeListener(nodeStoreListener_);
			taxonomy_.removeListener(taxonomyListener_);
		}
		taxonomy_ = new ConcurrentClassTaxonomy(elkFactory_,
				ElkClassKeyProvider.INSTANCE);
		for (final Listener listener : listeners_) {
			listener.taxonomyReset(old, taxonomy_);
		}
		taxonomy_.addListener(nodeStoreListener_);
		taxonomy_.addListener(taxonomyListener_);

		// All classes need to be added to the taxonomy
		toRemove_.clear();
		toAdd_.clear();
		toAdd_.addAll(ontologyIndex_.getClasses());

	}

	/**
	 * Notifies this {@link ClassTaxonomyState} that the taxonomy has just been
	 * completely construction.
	 */
	void taxonomyComplete() {
		// Clear pending classes.
		toRemove_.clear();
		toAdd_.clear();
	}

	void addListener(final Listener listener) {
		listeners_.add(listener);
	}

	void removeListener(final Listener listener) {
		listeners_.remove(listener);
	}

	static interface Listener {

		/**
		 * Called immediately after the result of calling
		 * {@link ClassTaxonomyState#getTaxonomy()} changes.
		 *
		 * @param oldTaxonomy
		 *            value of {@link ClassTaxonomyState#getTaxonomy()} before
		 *            the change
		 * @param newTaxonomy
		 *            value of {@link ClassTaxonomyState#getTaxonomy()} after
		 *            the change
		 */
		void taxonomyReset(UpdateableTaxonomy<ElkClass> oldTaxonomy,
				UpdateableTaxonomy<ElkClass> newTaxonomy);

	}

}


package org.semanticweb.elk.reasoner.saturation.rules;

/*
 * #%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.rules.backwardlinks.BackwardLinkChainFromBackwardLinkRule;
import org.semanticweb.elk.reasoner.saturation.rules.backwardlinks.ContradictionOverBackwardLinkRule;
import org.semanticweb.elk.reasoner.saturation.rules.backwardlinks.SubsumerBackwardLinkRule;
import org.semanticweb.elk.reasoner.saturation.rules.contextinit.OwlThingContextInitRule;
import org.semanticweb.elk.reasoner.saturation.rules.contextinit.RootContextInitializationRule;
import org.semanticweb.elk.reasoner.saturation.rules.contradiction.ContradictionPropagationRule;
import org.semanticweb.elk.reasoner.saturation.rules.disjointsubsumer.ContradictionCompositionRule;
import org.semanticweb.elk.reasoner.saturation.rules.forwardlink.BackwardLinkFromForwardLinkRule;
import org.semanticweb.elk.reasoner.saturation.rules.forwardlink.NonReflexiveBackwardLinkCompositionRule;
import org.semanticweb.elk.reasoner.saturation.rules.forwardlink.ReflexiveBackwardLinkCompositionRule;
import org.semanticweb.elk.reasoner.saturation.rules.propagations.SubsumerPropagationRule;
import org.semanticweb.elk.reasoner.saturation.rules.subcontextinit.PropagationInitializationRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.ComposedFromDecomposedSubsumerRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.ContradictionFromNegationRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.ContradictionFromOwlNothingRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.DisjointSubsumerFromMemberRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.EquivalentClassFirstFromSecondRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.EquivalentClassSecondFromFirstRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.IndexedClassDecompositionRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.IndexedClassFromDefinitionRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.IndexedObjectComplementOfDecomposition;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.IndexedObjectHasSelfDecomposition;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.IndexedObjectIntersectionOfDecomposition;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.IndexedObjectSomeValuesFromDecomposition;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.ObjectIntersectionFromFirstConjunctRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.ObjectIntersectionFromSecondConjunctRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.ObjectUnionFromDisjunctRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.PropagationFromExistentialFillerRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.SuperClassFromSubClassRule;

/**
 * An object which can be used to measure the methods invocations of a
 * {@link RuleVisitor}. The fields of the counter correspond to the methods of
 * {@link RuleVisitor}.
 *
 * @author "Yevgeny Kazakov"
 */
public class RuleCounter {

	/**
	 * counter for {@link BackwardLinkChainFromBackwardLinkRule}
	 */
	long countBackwardLinkChainFromBackwardLinkRule;

	/**
	 * counter for {@link BackwardLinkFromForwardLinkRule}
	 */
	long countBackwardLinkFromForwardLinkRule;

	/**
	 * counter for {@link ComposedFromDecomposedSubsumerRule}
	 */
	long countComposedFromDecomposedSubsumerRule;

	/**
	 * counter for {@link ContradictionCompositionRule}
	 */
	long countContradictionCompositionRule;

	/**
	 * counter for {@link ContradictionFromNegationRule}
	 */
	long countContradictionFromNegationRule;

	/**
	 * counter for {@link ContradictionFromOwlNothingRule}
	 */
	long countContradictionFromOwlNothingRule;

	/**
	 * counter for {@link ContradictionOverBackwardLinkRule}
	 */
	long countContradictionOverBackwardLinkRule;

	/**
	 * counter for {@link ContradictionPropagationRule}
	 */
	long countContradictionPropagationRule;

	/**
	 * counter for {@link DisjointSubsumerFromMemberRule}
	 */
	long countDisjointSubsumerFromMemberRule;

	/**
	 * counter for {@link IndexedClassDecompositionRule}
	 */
	long countIndexedClassDecompositionRule;

	/**
	 * counter for {@link IndexedClassFromDefinitionRule}
	 */
	long countIndexedClassFromDefinitionRule;

	/**
	 * counter for {@link IndexedObjectComplementOfDecomposition}
	 */
	long countIndexedObjectComplementOfDecomposition;

	/**
	 * counter for {@link IndexedObjectHasSelfDecomposition}
	 */
	long countIndexedObjectHasSelfDecomposition;

	/**
	 * counter for {@link IndexedObjectIntersectionOfDecomposition}
	 */
	long countIndexedObjectIntersectionOfDecomposition;

	/**
	 * counter for {@link IndexedObjectSomeValuesFromDecomposition}
	 */
	long countIndexedObjectSomeValuesFromDecomposition;

	/**
	 * counter for {@link NonReflexiveBackwardLinkCompositionRule}
	 */
	long countNonReflexiveBackwardLinkCompositionRule;

	/**
	 * counter for {@link ObjectIntersectionFromFirstConjunctRule}
	 */
	long countObjectIntersectionFromFirstConjunctRule;

	/**
	 * counter for {@link ObjectIntersectionFromSecondConjunctRule}
	 */
	long countObjectIntersectionFromSecondConjunctRule;

	/**
	 * counter for {@link ObjectUnionFromDisjunctRule}
	 */
	long countObjectUnionFromDisjunctRule;

	/**
	 * counter for {@link OwlThingContextInitRule}
	 */
	long countOwlThingContextInitRule;

	/**
	 * counter for {@link PropagationFromExistentialFillerRule}
	 */
	long countPropagationFromExistentialFillerRule;

	/**
	 * counter for {@link PropagationInitializationRule}
	 */
	long countPropagationInitializationRule;

	/**
	 * counter for {@link ReflexiveBackwardLinkCompositionRule}
	 */
	long countReflexiveBackwardLinkCompositionRule;

	/**
	 * counter for {@link RootContextInitializationRule}
	 */
	long countRootContextInitializationRule;

	/**
	 * counter for {@link SubsumerBackwardLinkRule}
	 */
	long countSubsumerBackwardLinkRule;

	/**
	 * counter for {@link SubsumerPropagationRule}
	 */
	long countSubsumerPropagationRule;

	/**
	 * counter for {@link SuperClassFromSubClassRule}
	 */
	long countSuperClassFromSubClassRule;

	/**
	 * counter for {@link EquivalentClassFirstFromSecondRule}
	 */
	long countEquivalentClassFirstFromSecondRule;

	/**
	 * counter for {@link EquivalentClassSecondFromFirstRule}
	 */
	long countEquivalentClassSecondFromFirstRule;

	/**
	 * Add the values the corresponding values of the given counter
	 *
	 * @param counter
	 */
	public synchronized void add(RuleCounter counter) {
		countOwlThingContextInitRule += counter.countOwlThingContextInitRule;
		countRootContextInitializationRule += counter.countRootContextInitializationRule;
		countDisjointSubsumerFromMemberRule += counter.countDisjointSubsumerFromMemberRule;
		countContradictionFromNegationRule += counter.countContradictionFromNegationRule;
		countObjectIntersectionFromFirstConjunctRule += counter.countObjectIntersectionFromFirstConjunctRule;
		countObjectIntersectionFromSecondConjunctRule += counter.countObjectIntersectionFromSecondConjunctRule;
		countSuperClassFromSubClassRule += counter.countSuperClassFromSubClassRule;
		countPropagationFromExistentialFillerRule += counter.countPropagationFromExistentialFillerRule;
		countObjectUnionFromDisjunctRule += counter.countObjectUnionFromDisjunctRule;
		countBackwardLinkChainFromBackwardLinkRule += counter.countBackwardLinkChainFromBackwardLinkRule;
		countSubsumerBackwardLinkRule += counter.countSubsumerBackwardLinkRule;
		countContradictionOverBackwardLinkRule += counter.countContradictionOverBackwardLinkRule;
		countContradictionPropagationRule += counter.countContradictionPropagationRule;
		countContradictionCompositionRule += counter.countContradictionCompositionRule;
		countNonReflexiveBackwardLinkCompositionRule += counter.countNonReflexiveBackwardLinkCompositionRule;
		countIndexedObjectIntersectionOfDecomposition += counter.countIndexedObjectIntersectionOfDecomposition;
		countIndexedObjectSomeValuesFromDecomposition += counter.countIndexedObjectSomeValuesFromDecomposition;
		countIndexedObjectComplementOfDecomposition += counter.countIndexedObjectComplementOfDecomposition;
		countIndexedObjectHasSelfDecomposition += counter.countIndexedObjectHasSelfDecomposition;
		countContradictionFromOwlNothingRule += counter.countContradictionFromOwlNothingRule;
		countSubsumerPropagationRule += counter.countSubsumerPropagationRule;
		countReflexiveBackwardLinkCompositionRule += counter.countReflexiveBackwardLinkCompositionRule;
		countPropagationInitializationRule += counter.countPropagationInitializationRule;
		countBackwardLinkFromForwardLinkRule += counter.countBackwardLinkFromForwardLinkRule;
		countComposedFromDecomposedSubsumerRule += counter.countComposedFromDecomposedSubsumerRule;
		countIndexedClassDecompositionRule += counter.countIndexedClassDecompositionRule;
		countIndexedClassFromDefinitionRule += counter.countIndexedClassFromDefinitionRule;
		countEquivalentClassFirstFromSecondRule += counter.countEquivalentClassFirstFromSecondRule;
		countEquivalentClassSecondFromFirstRule += counter.countEquivalentClassSecondFromFirstRule;
	}

	public long getTotalRuleAppCount() {
		return countOwlThingContextInitRule + countRootContextInitializationRule
				+ countDisjointSubsumerFromMemberRule
				+ countContradictionFromNegationRule
				+ countObjectIntersectionFromFirstConjunctRule
				+ countObjectIntersectionFromSecondConjunctRule
				+ countSuperClassFromSubClassRule
				+ countPropagationFromExistentialFillerRule
				+ countObjectUnionFromDisjunctRule
				+ countBackwardLinkChainFromBackwardLinkRule
				+ countSubsumerBackwardLinkRule
				+ countContradictionOverBackwardLinkRule
				+ countContradictionPropagationRule
				+ countContradictionCompositionRule
				+ countNonReflexiveBackwardLinkCompositionRule
				+ countReflexiveBackwardLinkCompositionRule
				+ countIndexedObjectIntersectionOfDecomposition
				+ countIndexedObjectSomeValuesFromDecomposition
				+ countIndexedObjectComplementOfDecomposition
				+ countIndexedObjectHasSelfDecomposition
				+ countContradictionFromOwlNothingRule
				+ countSubsumerPropagationRule
				+ countPropagationInitializationRule
				+ countBackwardLinkFromForwardLinkRule
				+ countComposedFromDecomposedSubsumerRule
				+ countIndexedClassDecompositionRule
				+ countIndexedClassFromDefinitionRule
				+ countEquivalentClassFirstFromSecondRule
				+ countEquivalentClassSecondFromFirstRule;
	}

	/**
	 * Reset all counters to zero.
	 */
	public void reset() {
		countOwlThingContextInitRule = 0;
		countRootContextInitializationRule = 0;
		countDisjointSubsumerFromMemberRule = 0;
		countContradictionFromNegationRule = 0;
		countObjectIntersectionFromFirstConjunctRule = 0;
		countObjectIntersectionFromSecondConjunctRule = 0;
		countSuperClassFromSubClassRule = 0;
		countPropagationFromExistentialFillerRule = 0;
		countObjectUnionFromDisjunctRule = 0;
		countBackwardLinkChainFromBackwardLinkRule = 0;
		countSubsumerBackwardLinkRule = 0;
		countContradictionOverBackwardLinkRule = 0;
		countContradictionPropagationRule = 0;
		countContradictionCompositionRule = 0;
		countNonReflexiveBackwardLinkCompositionRule = 0;
		countReflexiveBackwardLinkCompositionRule = 0;
		countIndexedObjectIntersectionOfDecomposition = 0;
		countIndexedObjectSomeValuesFromDecomposition = 0;
		countIndexedObjectComplementOfDecomposition = 0;
		countIndexedObjectHasSelfDecomposition = 0;
		countContradictionFromOwlNothingRule = 0;
		countSubsumerPropagationRule = 0;
		countPropagationInitializationRule = 0;
		countBackwardLinkFromForwardLinkRule = 0;
		countComposedFromDecomposedSubsumerRule = 0;
		countIndexedClassDecompositionRule = 0;
		countIndexedClassFromDefinitionRule = 0;
		countEquivalentClassFirstFromSecondRule = 0;
		countEquivalentClassSecondFromFirstRule = 0;
	}
}


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

import org.semanticweb.elk.exceptions.ElkRuntimeException;
import org.semanticweb.elk.util.concurrent.computation.ConcurrentComputation;
import org.semanticweb.elk.util.concurrent.computation.ConcurrentExecutor;
import org.semanticweb.elk.util.concurrent.computation.ProcessorFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A {@link ConcurrentComputation} used for executing of reasoner stages
 *
 * @author "Yevgeny Kazakov"
 *
 * @param <F>
 *            the type of the factory for the input processors
 */
public class ReasonerComputation<F extends ProcessorFactory<?>> extends
		ConcurrentComputation<F> {

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

	public ReasonerComputation(F inputProcessorFactory,
			ConcurrentExecutor executor, int maxWorkers) {
		super(inputProcessorFactory, executor, maxWorkers);
	}

	/**
	 * Process the given input concurrently using the provided input processor.
	 * If the process has been interrupted, this method can be called again to
	 * continue the computation.
	 */
	public void process() {

		if (!start()) {
			String message = "Could not start workers required for reasoner computation!";
			LOGGER_.error(message);
			throw new ElkRuntimeException(message);
		}

		try {
			finish();
		} catch (InterruptedException e) {
			// restore interrupt status
			Thread.currentThread().interrupt();
			throw new ElkRuntimeException(
					"Reasoner computation interrupted externally!");
		}
	}

}