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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

import org.liveontologies.puli.Producer;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.ClassConclusion;
import org.semanticweb.elk.reasoner.saturation.inferences.ClassInference;
import org.semanticweb.elk.reasoner.tracing.ConclusionBaseFactory;
import org.semanticweb.elk.reasoner.tracing.DummyConclusionVisitor;
import org.semanticweb.elk.reasoner.tracing.ModifiableTracingProof;
import org.semanticweb.elk.reasoner.tracing.TracingInference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * An {@link Producer} that filters out the unnecessary {@link ClassInference}s
 * and saves the remaining ones into the provided
 * {@link ModifiableTracingProof}. A {@link ClassInference} is unnecessary if
 * one of the local premises of the inference is either its conclusion (cycle of
 * length one) or can only be a conclusion of inferences in the provided
 * {@link ModifiableTracingProof} which have this conclusion as one of the
 * premises (cycle of length two).
 *
 * @author Yevgeny Kazakov
 */
class ClassInferenceBlockingFilter implements Producer<ClassInference> {

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

	private final static ClassConclusion.Factory CONCLUSION_FACTORY_ = new ConclusionBaseFactory();

	private final static ClassInference.Visitor<ClassConclusion> CONCLUSION_GETTER_ = new ClassInferenceConclusionGettingVisitor(
			CONCLUSION_FACTORY_);

	private final ModifiableTracingProof<ClassInference> output_;

	/**
	 * inferences such that one of their local premises cannot be obtained as a
	 * conclusion of other inferences in {@link #output_} that do not use the
	 * conclusion of the inference as one of the premises; the key is one of
	 * such premises
	 */
	private final Map<ClassConclusion, List<ClassInference>> blocked_ = new HashMap<ClassConclusion, List<ClassInference>>();

	/**
	 * the inferences that are (no longer) blocked as a result of adding other
	 * (unblocked) inferences to {@link #output_}
	 */
	private final Queue<ClassInference> unblocked_ = new LinkedList<ClassInference>();

	ClassInferenceBlockingFilter(
			ModifiableTracingProof<ClassInference> output) {
		this.output_ = output;
	}

	@Override
	public void produce(ClassInference next) {
		checkBlocked(next);
		while ((next = unblocked_.poll()) != null) {
			output_.produce(next);
			List<ClassInference> blockedByNext = blocked_
					.remove(getConclusion(next));
			if (blockedByNext == null) {
				continue;
			}
			// else
			for (ClassInference inf : blockedByNext) {
				checkBlocked(inf);
			}
		}
	}

	private void checkBlocked(ClassInference inference) {
		if (hasPremise(inference, getConclusion(inference))) {
			LOGGER_.trace("{}: permanently blocked", inference);
			return;
		}
		ClassConclusion blockedPremise = getBlockedPremise(inference);
		if (blockedPremise == null) {
			LOGGER_.trace("{}: unblocked", inference);
			unblocked_.add(inference);
		} else {
			LOGGER_.trace("{}: blocked by {}", inference, blockedPremise);
			block(inference, blockedPremise);
		}
	}

	/**
	 * Records that the given {@link ClassInference} has the given premise
	 * {@code ClassConclusion} that is not a conclusion of any inference in
	 * {@link #output_} that do not use the conclusion of this
	 * {@link ClassInference} as one of the premises
	 *
	 * @param inference
	 * @param conclusion
	 */
	private void block(ClassInference inference, ClassConclusion conclusion) {
		List<ClassInference> blockedForConclusion = blocked_.get(conclusion);
		if (blockedForConclusion == null) {
			blockedForConclusion = new ArrayList<ClassInference>();
			blocked_.put(conclusion, blockedForConclusion);
		}
		blockedForConclusion.add(inference);
	}

	private static ClassConclusion getConclusion(ClassInference inference) {
		return inference.accept(CONCLUSION_GETTER_);
	}

	/**
	 * @param inference
	 * @param premise
	 * @return {@code true} if the given {@code ClassInference} has the given
	 *         {@code ClassConclusion} as one of the premises
	 */
	private static boolean hasPremise(ClassInference inference,
			ClassConclusion premise) {
		ConclusionEqualityChecker checker = new ConclusionEqualityChecker(
				premise);
		inference.accept(new ClassInferenceLocalPremiseVisitor<Void>(
				CONCLUSION_FACTORY_, checker));
		return checker.getResult();
	}

	/**
	 * @param inference
	 * @return a local premise of the given {@code ClassInference} that cannot
	 *         be derived by other inferences in {@link #output_} that do not
	 *         use the conclusion of this {@code ClassInference} as one of the
	 *         premises; returns {@code null} if such a premise does not exist
	 */
	private ClassConclusion getBlockedPremise(ClassInference inference) {
		DerivabilityChecker checker = new DerivabilityChecker(
				getConclusion(inference));
		inference.accept(new ClassInferenceLocalPremiseVisitor<Void>(
				CONCLUSION_FACTORY_, checker));
		return checker.getResult();
	}

	/**
	 * @param conclusion
	 * @param premise
	 * @return {@code true} if there exists an inference in {@link #output_}
	 *         with the given conclusion which does not use the given premise
	 */
	private boolean derivableWithoutPremise(ClassConclusion conclusion,
			ClassConclusion premise) {
		for (TracingInference inf : output_.getInferences(conclusion)) {
			if (!hasPremise((ClassInference) inf, premise)) {
				return true;
			}
		}
		// else
		return false;
	}

	/**
	 * A convenience class for checking if series of {@code ClassConclusion}s
	 * are derivable by inferences in {@link #output_} without using a given
	 * premise. For checking this, it is sufficient to visit these conclusions
	 * in any order by {@link DerivabilityChecker} and then take
	 * {@link DerivabilityChecker#getResult()}.
	 *
	 * @author Yevgeny Kazakov
	 */
	private class DerivabilityChecker extends DummyConclusionVisitor<Void> {

		private final ClassConclusion premise_;

		/**
		 * the first visited {@code ClassConclusion} that is not derivable
		 * without {@link #premise_}
		 */
		private ClassConclusion result_ = null;

		DerivabilityChecker(ClassConclusion premise) {
			this.premise_ = premise;
		}

		@Override
		protected Void defaultVisit(ClassConclusion candidate) {
			if (result_ == null
					&& !derivableWithoutPremise(candidate, premise_)) {
				result_ = candidate;
			}
			return null;
		}

		ClassConclusion getResult() {
			return result_;
		}

	}

}


/*
 * #%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.InstanceTaxonomy;
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
 */
public class InstanceTaxonomyHasher {

	/**
	 * Compute the hash code of a taxonomy.
	 *
	 * @param taxonomy
	 * @return hash
	 */
	public static int hash(InstanceTaxonomy<? extends ElkEntity, ? extends ElkEntity> taxonomy) {
		int typeHash = HashGenerator.combineMultisetHash(true, taxonomy.getNodes(), TypeNodeHasher.INSTANCE);
		int instanceHash = HashGenerator.combineMultisetHash(true, taxonomy.getInstanceNodes(), InstanceNodeHasher.INSTANCE);
		return HashGenerator.combineListHash(typeHash, instanceHash);
	}

}


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

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

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

import org.semanticweb.elk.reasoner.indexing.model.IndexedClassExpression;
import org.semanticweb.elk.reasoner.indexing.model.IndexedObjectProperty;
import org.semanticweb.elk.reasoner.indexing.model.IndexedObjectSomeValuesFrom;
import org.semanticweb.elk.reasoner.indexing.model.ModifiableIndexedObjectSomeValuesFrom;
import org.semanticweb.elk.reasoner.indexing.model.ModifiableOntologyIndex;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.BackwardLink;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.Propagation;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.SubClassInclusion;
import org.semanticweb.elk.reasoner.saturation.context.Context;
import org.semanticweb.elk.reasoner.saturation.context.ContextPremises;
import org.semanticweb.elk.reasoner.saturation.context.SubContextPremises;
import org.semanticweb.elk.reasoner.saturation.inferences.PropagationGenerated;
import org.semanticweb.elk.reasoner.saturation.properties.SaturatedPropertyChain;
import org.semanticweb.elk.reasoner.saturation.rules.ClassInferenceProducer;
import org.semanticweb.elk.util.collections.LazySetIntersection;
import org.semanticweb.elk.util.collections.LazySetUnion;
import org.semanticweb.elk.util.collections.chains.Chain;
import org.semanticweb.elk.util.collections.chains.Matcher;
import org.semanticweb.elk.util.collections.chains.ReferenceFactory;
import org.semanticweb.elk.util.collections.chains.SimpleTypeBasedMatcher;

/**
 * A {@link ChainableSubsumerRule} producing {@link Propagation} of a
 * {@link SubClassInclusion} {@link IndexedObjectSomeValuesFrom} over
 * {@link BackwardLink}s when the {@link IndexedClassExpression} filler of this
 * {@link IndexedObjectSomeValuesFrom} provided it can be used with at least one
 * {@link BackwardLink} in this {@link Context}
 *
 * @author "Yevgeny Kazakov"
 */
public class PropagationFromExistentialFillerRule extends
		AbstractChainableSubsumerRule {

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

	public static final String NAME = "ObjectSomeValuesFrom Propagation Introduction";

	private final Collection<IndexedObjectSomeValuesFrom> negExistentials_;

	private PropagationFromExistentialFillerRule(ChainableSubsumerRule next) {
		super(next);
		this.negExistentials_ = new ArrayList<IndexedObjectSomeValuesFrom>(1);
	}

	private PropagationFromExistentialFillerRule(
			IndexedObjectSomeValuesFrom negExistential) {
		super(null);
		this.negExistentials_ = new ArrayList<IndexedObjectSomeValuesFrom>(1);
		this.negExistentials_.add(negExistential);
	}

	@Deprecated
	public Collection<IndexedObjectSomeValuesFrom> getNegativeExistentials() {
		return negExistentials_;
	}

	public static boolean addRuleFor(
			ModifiableIndexedObjectSomeValuesFrom existential,
			ModifiableOntologyIndex index) {
		return index.add(existential.getFiller(),
				new PropagationFromExistentialFillerRule(existential));
	}

	public static boolean removeRuleFor(
			ModifiableIndexedObjectSomeValuesFrom existential,
			ModifiableOntologyIndex index) {
		return index.remove(existential.getFiller(),
				new PropagationFromExistentialFillerRule(existential));
	}

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

	@Override
	public void apply(IndexedClassExpression premise, ContextPremises premises,
			ClassInferenceProducer producer) {

		final Map<IndexedObjectProperty, ? extends SubContextPremises> subContextMap = premises
				.getSubContextPremisesByObjectProperty();
		final Set<IndexedObjectProperty> candidatePropagationProperties = new LazySetUnion<IndexedObjectProperty>(
				premises.getLocalReflexiveObjectProperties(),
				subContextMap.keySet());

		if (candidatePropagationProperties.isEmpty()) {
			return;
		}

		for (IndexedObjectSomeValuesFrom e : negExistentials_) {
			IndexedObjectProperty relation = e.getProperty();
			/*
			 * creating propagations for relevant sub-properties of the relation
			 */
			SaturatedPropertyChain saturation = relation.getSaturated();
			for (IndexedObjectProperty property : new LazySetIntersection<IndexedObjectProperty>(
					candidatePropagationProperties,
					saturation.getSubProperties())) {
				if (subContextMap.get(property).isInitialized()) {
					producer.produce(new PropagationGenerated(premises
							.getRoot(), property, e));
				}
			}
		}
	}

	@Override
	public boolean isTracingRule() {
		return false;
	}

	@Override
	public boolean addTo(Chain<ChainableSubsumerRule> ruleChain) {
		if (isEmpty())
			return true;
		PropagationFromExistentialFillerRule rule = ruleChain.getCreate(
				MATCHER_, FACTORY_);
		rule.negExistentials_.addAll(this.negExistentials_);
		return true;
	}

	@Override
	public boolean removeFrom(Chain<ChainableSubsumerRule> ruleChain) {
		if (isEmpty())
			return true;
		PropagationFromExistentialFillerRule rule = ruleChain.find(MATCHER_);
		if (rule == null)
			return false;
		// else
		boolean success = true;
		int removed = 0;
		for (IndexedObjectSomeValuesFrom negExistential : this.negExistentials_) {
			if (rule.negExistentials_.remove(negExistential)) {
				removed++;
			} else {
				success = false;
				break;
			}
		}
		if (success) {
			if (rule.isEmpty())
				ruleChain.remove(MATCHER_);
			return true;
		}
		// else revert all changes
		for (IndexedObjectSomeValuesFrom negExistential : this.negExistentials_) {
			if (removed == 0)
				break;
			removed--;
			rule.negExistentials_.add(negExistential);
		}
		return false;
	}

	@Override
	public void accept(LinkedSubsumerRuleVisitor<?> visitor,
			IndexedClassExpression premise, ContextPremises premises,
			ClassInferenceProducer producer) {
		visitor.visit(this, premise, premises, producer);
	}

	/**
	 * @return {@code true} if this rule never does anything
	 */
	private boolean isEmpty() {
		return negExistentials_.isEmpty();
	}

	/**
	 * Produces propagations of {@link IndexedObjectSomeValuesFrom} over the
	 * given {@link IndexedObjectProperty} in the given {@link Context}
	 *
	 * @param property
	 * @param premises
	 * @param producer
	 */
	void applyForProperty(IndexedObjectProperty property,
			ContextPremises premises, ClassInferenceProducer producer) {

		for (IndexedObjectSomeValuesFrom e : negExistentials_) {
			if (e.getProperty().getSaturated().getSubPropertyChains()
					.contains(property)) {
				producer.produce(new PropagationGenerated(premises.getRoot(),
						property, e));
			}
		}

	}

	public static void applyForProperty(LinkedSubsumerRule rule,
			IndexedObjectProperty property, ContextPremises premises,
			ClassInferenceProducer producer) {
		for (;;) {
			if (rule == null)
				return;
			PropagationFromExistentialFillerRule matchedRule = MATCHER_
					.match(rule);
			if (matchedRule != null) {
				matchedRule.applyForProperty(property, premises, producer);
				return;
			}
			// else
			rule = rule.next();
		}
	}

	private static final Matcher<LinkedSubsumerRule, PropagationFromExistentialFillerRule> MATCHER_ = new SimpleTypeBasedMatcher<LinkedSubsumerRule, PropagationFromExistentialFillerRule>(
			PropagationFromExistentialFillerRule.class);

	private static final ReferenceFactory<ChainableSubsumerRule, PropagationFromExistentialFillerRule> FACTORY_ = new ReferenceFactory<ChainableSubsumerRule, PropagationFromExistentialFillerRule>() {
		@Override
		public PropagationFromExistentialFillerRule create(
				ChainableSubsumerRule next) {
			return new PropagationFromExistentialFillerRule(next);
		}
	};

}


/*
 * #%L
 * ELK Utilities for Concurrency
 *
 * $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.concurrent.computation;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * An class for concurrent processing of a number of tasks. The input for the
 * tasks are submitted, buffered, and processed by concurrent workers using the
 * the {@link InputProcessor} objects created by the supplied
 * {@link InputProcessorFactory}. The implementation is loosely based on a
 * producer-consumer framework with one producer and many consumers. The
 * processing of the input should start by calling the {@link #start()} method,
 * following by {@link #submit(Object)} method for submitting input to be
 * processed. The workers will always wait for new input, unless interrupted or
 * {@link #finish()} method is called. If {@link #finish()} is called then no
 * further input can be submitted and the workers will terminate when all input
 * has been processed or they are interrupted earlier, whichever is earlier.
 *
 * @author "Yevgeny Kazakov"
 *
 * @param <I>
 *            the type of the input to be processed.
 * @param <F>
 *            the type of the factory for the input processors
 */
public class ConcurrentComputationWithInputs<I, F extends InputProcessorFactory<I, ?>>
		extends ConcurrentComputation<F> {
	/**
	 * the internal buffer for queuing input
	 */
	private final BlockingQueue<I> buffer_;
	/**
	 * the capacity of the buffer
	 */
	private final int bufferCapacity_;
	/**
	 * a special object to "wake up" worker threads waiting for the input
	 */
	@SuppressWarnings("unchecked")
	private final I poison_pill_ = (I) new Object();

	/**
	 * Creating a {@link ConcurrentComputationWithInputs} instance.
	 *
	 * @param inputProcessorFactory
	 *            the factory for input processors
	 * @param executor
	 *            the executor used internally to run the jobs
	 * @param maxWorkers
	 *            the maximal number of concurrent workers processing the jobs
	 * @param bufferCapacity
	 *            the size of the buffer for scheduled jobs; if the buffer is
	 *            full, submitting new jobs will block until new space is
	 *            available
	 */
	public ConcurrentComputationWithInputs(F inputProcessorFactory,
			ConcurrentExecutor executor, int maxWorkers, int bufferCapacity) {
		super(inputProcessorFactory, executor, maxWorkers);
		if (bufferCapacity <= maxWorkers) {
			// we need poisons from the workers plus one input to fit in the
			// buffer
			bufferCapacity = maxWorkers + 1;
		}
		this.bufferCapacity_ = bufferCapacity;
		this.buffer_ = new ArrayBlockingQueue<I>(bufferCapacity);
	}

	/**
	 * Creating a {@link ConcurrentComputationWithInputs} instance.
	 *
	 * @param inputProcessorFactory
	 *            the factory for input processors
	 * @param executor
	 *            the executor used internally to run the jobs
	 * @param maxWorkers
	 *            the maximal number of concurrent workers processing the jobs
	 */
	public ConcurrentComputationWithInputs(F inputProcessorFactory,
			ConcurrentExecutor executor, int maxWorkers) {
		this(inputProcessorFactory, executor, maxWorkers, 512 + 32 * maxWorkers);
	}

	/**
	 * Submitting a new input for processing. Submitted input jobs are first
	 * buffered, and then concurrently processed by workers. If the buffer is
	 * full, the method blocks until new space is available.
	 *
	 * @param input
	 *            the input to be processed
	 * @return {@code true} if the input has been successfully submitted for
	 *         computation; the input cannot be submitted, e.g., if
	 *         {@link #finish()} has been called
	 * @throws InterruptedException
	 *             thrown if interrupted during waiting for space to be
	 *             available
	 */
	public synchronized boolean submit(I input) throws InterruptedException {
		if (termination || isInterrupted())
			return false;
		buffer_.put(input);
		return true;
	}

	@Override
	protected synchronized void waitWorkers() throws InterruptedException {
		if (buffer_.isEmpty())
			// wake up blocked workers if not done already
			buffer_.offer(poison_pill_);
		super.waitWorkers();
		// remove all poison pills
		while (buffer_.peek() == poison_pill_) {
			buffer_.remove();
		}
	}

	@Override
	Runnable getWorker() {
		return new Worker();
	}

	/**
	 * The {@link Runnable} for workers processing the input
	 *
	 * @author "Yevgeny Kazakov"
	 *
	 */
	private class Worker implements Runnable {

		/**
		 * Exceptions produced by worker
		 */
		private RuntimeException workerException_ = null;

		@Override
		public final void run() {
			// TODO: reuse the code from the superclass
			// we use one engine per worker run
			InputProcessor<I> inputProcessor = processorFactory.getEngine();

			try {
				boolean doneProcess = false;
				for (;;) {
					// make sure that all previously submitted inputs are
					// processed
					if (!doneProcess) {
						inputProcessor.process(); // can be interrupted
						doneProcess = true;
					}
					I nextInput = buffer_.take();
					if (nextInput != poison_pill_) {
						inputProcessor.submit(nextInput); // should not fail
						inputProcessor.process(); // can be interrupted
					}
					if (termination || isInterrupted()) {
						if (buffer_.isEmpty()) {
							// wake up blocked workers if not done already
							buffer_.put(poison_pill_);
							break;
						}
						if (isInterrupted()) {
							if (buffer_.size() == bufferCapacity_) {
								// buffer is full, producer may be blocked,
								// need to consume one more input
								continue;
							}
							// else
							break;
						}
					}
				}
			} catch (InterruptedException e) {
				/*
				 * we don't know what is causing this but we need to obey;
				 * consistency of the computation for such interrupt is not
				 * guaranteed; restore the interrupt status and exit
				 */
				Thread.currentThread().interrupt();
			} catch (Throwable e) {
				workerException_ = new RuntimeException(
						"Exception in worker thread: ", e);
			} finally {
				if (workerException_ != null)
					throw workerException_;
				inputProcessor.finish();
			}
		}
	}
}


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

import java.io.IOException;

import org.semanticweb.elk.owl.interfaces.ElkObject;

/**
 * Printing ELK Objects in OWL 2 functional style syntax.
 *
 * @author "Yevgeny Kazakov"
 *
 */
public class OwlFunctionalStylePrinter {

	/**
	 * Converting an ELK Object to string.
	 *
	 * @param elkObject
	 *            the input ELK object
	 * @return the string representation of the ELK object
	 */
	public static String toString(ElkObject elkObject) {
		return toString(elkObject, false);
	}

	public static String toString(ElkObject elkObject, boolean expandAbbreviatedIris) {
		StringBuilder writer = new StringBuilder();
		OwlFunctionalStylePrinterVisitor printer = new OwlFunctionalStylePrinterVisitor(
				writer, expandAbbreviatedIris);
		elkObject.accept(printer);
		return writer.toString();
	}

	/**
	 * Printing an ELK Object through an appender.
	 *
	 * @param appender
	 *            the appender used for printing
	 * @param elkObject
	 *            the ELK Object to print
	 * @throws IOException
	 *             if an I/O Error occurs
	 */
	public static void append(Appendable appender, ElkObject elkObject)
			throws IOException {
		append(appender, elkObject, false);
	}

	public static void append(Appendable appender, ElkObject elkObject, boolean expandAbbreviatedIris)
			throws IOException {
		OwlFunctionalStylePrinterVisitor printer = new OwlFunctionalStylePrinterVisitor(
				appender, expandAbbreviatedIris);
		try {
			elkObject.accept(printer);
		} catch (PrintingException e) {
			throw new IOException(e.getMessage(), e.getCause());
		}

	}

}


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

import java.io.IOException;
import java.io.Writer;
import java.util.Collections;
import java.util.Set;

import org.semanticweb.elk.reasoner.indexing.model.IndexedClassExpression;
import org.semanticweb.elk.reasoner.indexing.model.IndexedComplexPropertyChain;
import org.semanticweb.elk.reasoner.indexing.model.IndexedObjectProperty;
import org.semanticweb.elk.reasoner.indexing.model.IndexedPropertyChain;
import org.semanticweb.elk.util.collections.AbstractHashMultimap;
import org.semanticweb.elk.util.collections.Multimap;
import org.semanticweb.elk.util.collections.Operations;

/**
 *
 * This object is used for fast retrieval of property inclusions and
 * compositions which are needed during saturation of class expressions.
 *
 * @author Frantisek Simancik
 * @author "Yevgeny Kazakov"
 *
 */
public class SaturatedPropertyChain {

	/**
	 * the {@code IndexedPropertyChain} for which this saturation is computed
	 */
	final IndexedPropertyChain root;

	/**
	 * the {@code IndexedObjectProperty}s which are subsumed by {@link #root}
	 */
	Set<IndexedObjectProperty> derivedSubProperties;

	/**
	 * the {@code IndexedPropertyChain}s which are subsumed by {@link #root}
	 */
	Set<IndexedPropertyChain> derivedSubProperyChains;

	/**
	 * {@code true} if {@link #derivedSubProperties} and
	 * {@link #derivedSubProperyChains} are not {@code null} and fully computed
	 */
	volatile boolean derivedSubPropertiesComputed = false;

	/**
	 * the {@code IndexedClassExpression}s that are ranges of the
	 * {@code IndexedObjectProperty}s that subsume {@link #root}
	 */
	Set<IndexedClassExpression> derivedRanges;

	/**
	 * {@code true} if {@link #derivedRanges} is not {@code null} and fully
	 * computed
	 */
	volatile boolean derivedRangesComputed = false;

	/**
	 * a multimap T -> {S} such that both S and ObjectPropertyChain(S, T) imply
	 * {@link #root}
	 */
	Multimap<IndexedObjectProperty, IndexedObjectProperty> leftSubComposableSubPropertiesByRightProperties;

	/**
	 * {@code true} if {@link #leftSubComposableSubPropertiesByRightProperties}
	 * is not {@code null} and was fully computed
	 */
	volatile boolean leftSubComposableSubPropertiesByRightPropertiesComputed = false;

	/**
	 * A {@link Multimap} from R to S such that ObjectPropertyChain(R, root) is
	 * a subrole of S
	 */
	AbstractHashMultimap<IndexedObjectProperty, IndexedComplexPropertyChain> nonRedundantCompositionsByLeftSubProperty;

	/**
	 * A {@link Multimap} from R to S such that ObjectPropertyChain(R, root) is
	 * a subrole of S, which is considered to be redundant
	 */
	AbstractHashMultimap<IndexedObjectProperty, IndexedComplexPropertyChain> redundantCompositionsByLeftSubProperty;

	/**
	 * A {@link Multimap} from R to S such that ObjectPropertyChain(root, R) is
	 * a subrole of S
	 */
	AbstractHashMultimap<IndexedPropertyChain, IndexedComplexPropertyChain> nonRedundantCompositionsByRightSubProperty;

	/**
	 * A {@link Multimap} from R to S such that ObjectPropertyChain(root, R) is
	 * a subrole of S, which is considered to be redundant
	 */
	AbstractHashMultimap<IndexedPropertyChain, IndexedComplexPropertyChain> redundantCompositionsByRightSubProperty;

	public SaturatedPropertyChain(IndexedPropertyChain ipc) {
		this.root = ipc;
	}

	/**
	 * Clear all derived information for this {@link SaturatedPropertyChain}
	 */
	public void clear() {
		derivedSubProperties = null;
		derivedSubProperyChains = null;
		derivedSubPropertiesComputed = false;
		derivedRanges = null;
		derivedRangesComputed = false;
		leftSubComposableSubPropertiesByRightProperties = null;
		leftSubComposableSubPropertiesByRightPropertiesComputed = false;
		nonRedundantCompositionsByLeftSubProperty = null;
		redundantCompositionsByLeftSubProperty = null;
		nonRedundantCompositionsByRightSubProperty = null;
		redundantCompositionsByRightSubProperty = null;
	}

	/**
	 * @return {@code true} if there is no derived information in this
	 *         {@link SaturatedPropertyChain}, that is, its state is the same as
	 *         after applying {@link #clear()}
	 */
	public boolean isClear() {
		return derivedSubProperties == null && derivedSubProperyChains == null
				&& leftSubComposableSubPropertiesByRightProperties == null
				&& nonRedundantCompositionsByLeftSubProperty == null
				&& redundantCompositionsByLeftSubProperty == null
				&& nonRedundantCompositionsByRightSubProperty == null
				&& redundantCompositionsByRightSubProperty == null;
	}

	/**
	 * @return All sub-{@link IndexedObjectProperty} of root including root, if
	 *         it is an {@link IndexedObjectProperty} itself.
	 */
	public Set<IndexedObjectProperty> getSubProperties() {
		if (derivedSubProperties != null)
			return derivedSubProperties;
		// else
		if (root instanceof IndexedObjectProperty)
			return Collections
					.<IndexedObjectProperty> singleton((IndexedObjectProperty) root);
		// else
		return Collections.emptySet();
	}

	/**
	 * @return All sub-{@link IndexedPropertyChain} of root including root
	 *         itself.
	 */
	public Set<IndexedPropertyChain> getSubPropertyChains() {
		return derivedSubProperyChains == null ? Collections
				.<IndexedPropertyChain> singleton(root)
				: derivedSubProperyChains;
	}

	/**
	 * @return All ranges of super-{@link IndexedObjectProperty} of root.
	 */
	public Set<IndexedClassExpression> getRanges() {
		if (derivedRanges == null)
			return Collections.emptySet();
		// else
		return derivedRanges;
	}

	/**
	 * @return A {@link Multimap} from R to S such that ObjectPropertyChain(R,
	 *         root) is a subrole of S, non-redundant ones
	 */
	public Multimap<IndexedObjectProperty, IndexedComplexPropertyChain> getNonRedundantCompositionsByLeftSubProperty() {
		return nonRedundantCompositionsByLeftSubProperty == null ? Operations
				.<IndexedObjectProperty, IndexedComplexPropertyChain> emptyMultimap()
				: nonRedundantCompositionsByLeftSubProperty;
	}

	/**
	 * @return A {@link Multimap} from R to S such that ObjectPropertyChain(R,
	 *         root) is a subrole of S, redundant ones
	 */
	public Multimap<IndexedObjectProperty, IndexedComplexPropertyChain> getRedundantCompositionsByLeftSubProperty() {
		return redundantCompositionsByLeftSubProperty == null ? Operations
				.<IndexedObjectProperty, IndexedComplexPropertyChain> emptyMultimap()
				: redundantCompositionsByLeftSubProperty;
	}

	/**
	 * @return A {@link Multimap} from R to S such that
	 *         ObjectPropertyChain(root, R) is a subrole of S, non-redundant ones
	 */
	public Multimap<IndexedPropertyChain, IndexedComplexPropertyChain> getNonRedundantCompositionsByRightSubProperty() {
		return nonRedundantCompositionsByRightSubProperty == null ? Operations
				.<IndexedPropertyChain, IndexedComplexPropertyChain> emptyMultimap()
				: nonRedundantCompositionsByRightSubProperty;
	}

	/**
	 * @return A {@link Multimap} from R to S such that
	 *         ObjectPropertyChain(root, R) is a subrole of S, including the redundant ones
	 */
	public Multimap<IndexedPropertyChain, IndexedComplexPropertyChain> getRedundantCompositionsByRightSubProperty() {
		return redundantCompositionsByRightSubProperty == null ? Operations
				.<IndexedPropertyChain, IndexedComplexPropertyChain> emptyMultimap()
				: redundantCompositionsByRightSubProperty;
	}

	/* Functions that modify the saturation */

	/**
	 * Prints differences with other {@link SaturatedPropertyChain}
	 *
	 * @param other
	 *            the {@link SaturatedPropertyChain} with which to compare this
	 *            {@link SaturatedPropertyChain}
	 * @throws IOException
	 */
	public void dumpDiff(SaturatedPropertyChain other, Writer writer)
			throws IOException {

		// comparing roots
		if (this.root != other.root)
			writer.append("this root: " + root + "; other root: " + other.root
					+ "\n");
		// comparing derived sub-properties
		Operations.dumpDiff(this.getSubPropertyChains(),
				other.getSubPropertyChains(), writer, root
						+ ": this sub-property not in other: ");
		Operations.dumpDiff(other.getSubPropertyChains(),
				this.getSubPropertyChains(), writer, root
						+ ": other sub-property not in this: ");
		// comparing derived compositions
		Operations.dumpDiff(this.getNonRedundantCompositionsByLeftSubProperty(),
				other.getNonRedundantCompositionsByLeftSubProperty(), writer, root
						+ ": this non-redundant left composition not in other: ");
		Operations.dumpDiff(this.getRedundantCompositionsByLeftSubProperty(),
				other.getRedundantCompositionsByLeftSubProperty(), writer, root
						+ ": this redundant left composition not in other: ");
		Operations.dumpDiff(other.getNonRedundantCompositionsByLeftSubProperty(),
				this.getNonRedundantCompositionsByLeftSubProperty(), writer, root
						+ ": other non-redundant left composition not in this: ");
		Operations.dumpDiff(other.getRedundantCompositionsByLeftSubProperty(),
				this.getRedundantCompositionsByLeftSubProperty(), writer, root
						+ ": other redundant left composition not in this: ");
		Operations.dumpDiff(this.getNonRedundantCompositionsByRightSubProperty(),
				other.getNonRedundantCompositionsByRightSubProperty(), writer, root
						+ ": this non-redundant right composition not in other: ");
		Operations.dumpDiff(this.getRedundantCompositionsByRightSubProperty(),
				other.getRedundantCompositionsByRightSubProperty(), writer, root
						+ ": this redundant right composition not in other: ");
		Operations.dumpDiff(other.getNonRedundantCompositionsByRightSubProperty(),
				this.getNonRedundantCompositionsByRightSubProperty(), writer, root
						+ ": other non-redundant right composition not in this: ");
		Operations.dumpDiff(other.getRedundantCompositionsByRightSubProperty(),
				this.getRedundantCompositionsByRightSubProperty(), writer, root
						+ ": other redundant right composition not in this: ");
	}
}


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

/**
 * hash sets using array and linear probing for resolving hash collision see [1]
 * p.526. Reuses some code from 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 this set
 *
 */
public class ArrayHashSet<E> extends AbstractSet<E> implements Set<E>,
		DirectAccess<E> {

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

	/**
	 * The number of elements contained in this set.
	 */
	transient int size;

	@SuppressWarnings("unchecked")
	public ArrayHashSet(int initialCapacity) {
		int capacity = LinearProbing.getInitialCapacity(initialCapacity);
		this.data = (E[]) new Object[capacity];
		this.size = 0;
	}

	@SuppressWarnings("unchecked")
	public ArrayHashSet() {
		int capacity = LinearProbing.DEFAULT_INITIAL_CAPACITY;
		this.data = (E[]) new Object[capacity];
		this.size = 0;
	}

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

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

	/**
	 * 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 newCapacity = oldCapacity << 1;
		@SuppressWarnings("unchecked")
		E[] newData = (E[]) new Object[newCapacity];
		for (int i = 0; i < oldCapacity; i++) {
			E e = oldData[i];
			if (e != null)
				LinearProbing.add(newData, e);
		}
		this.data = newData;
	}

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

	@Override
	public boolean contains(Object o) {
		if (o == null)
			throw new NullPointerException();
		return LinearProbing.contains(data, o);
	}

	@Override
	public boolean add(E e) {
		if (e == null)
			throw new NullPointerException();
		boolean added = LinearProbing.add(data, e);
		if (added && ++size == LinearProbing.getUpperSize(data.length))
			enlarge();
		return added;
	}

	@Override
	public boolean remove(Object o) {
		if (o == null)
			throw new NullPointerException();
		boolean removed = LinearProbing.remove(data, o);
		if (removed && --size == LinearProbing.getLowerSize(data.length))
			shrink();
		return removed;
	}

	@Override
	public boolean removeAll(Collection<?> c) {
		boolean modified = false;
		for (Object o : c) {
			modified |= remove(o);
		}
		return modified;
	}

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

	@SuppressWarnings("unchecked")
	@Override
	public void clear() {
		int capacity = data.length >> 2;
		if (capacity == 0)
			capacity = 1;
		size = 0;
		this.data = (E[]) new Object[capacity];
	}

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

	@Override
	public E[] getRawData() {
		return data;
	}

	private class ElementIterator extends LinearProbingIterator<E, E> {

		ElementIterator() {
			super(data, size);
			init();
		}

		@Override
		void checkSize(int expectedSize) {
			if (expectedSize != size)
				throw new ConcurrentModificationException();
		}

		@Override
		void remove(int pos) {
			LinearProbing.remove(dataSnapshot, pos);
			size--;
		}

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

}


/*
 * #%L
 * ELK Bencharking 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%
 */
/**
 *
 */
package org.semanticweb.elk.benchmark;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import org.semanticweb.elk.reasoner.config.ReasonerConfiguration;

/**
 * A bunch of utility methods for benchmarking, e.g., instantiating tasks, etc.
 *
 * @author Pavel Klinov
 *
 *         pavel.klinov@uni-ulm.de
 */
public class BenchmarkUtils {

	/*
	 * Checks that all System properties are set. We use System properties
	 * (other than cmd args) because they're easier to pass parameters into
	 * maven tests (via Surefire or Failsafe plugins)
	 */
	public static Map<String, String> getSystemProperties(String... names) {
		Map<String, String> propMap = new HashMap<String, String>();

		for (String name : names) {
			checkIfSet(name, propMap);
		}

		return propMap;
	}

	public static String[] getCommaSeparatedParameter(String propName) {
		String propValue = System.getProperty(propName);

		if (propValue != null) {
			return propValue.split(",");
		} else {
			return new String[] {};
		}
	}

	public static void checkIfSet(String propName, Map<String, String> propMap) {
		String propValue = System.getProperty(propName);

		if (propValue == null) {
			System.err.println(propName + " property is not set, re-run with "
					+ "-D" + propName + "=<value>?");
		} else {
			propMap.put(propName, propValue);
		}
	}

	/*
	 * A macro method, reads system properties, instantiates the task and runs
	 * it
	 */
	public static void runTask() throws Exception {
		Map<String, String> propMap = BenchmarkUtils
				.getSystemProperties(new String[] { Constants.TASK_CLASS_NAME,
						Constants.WARM_UPS, Constants.RUNS,
						Constants.TASK_PARAMS });
		// First, need to instantiate the task
		Task task = TaskFactory.createTask(propMap
				.get(Constants.TASK_CLASS_NAME), BenchmarkUtils
				.getCommaSeparatedParameter(Constants.TASK_PARAMS));
		TaskRunner runner = new TaskRunner(Integer.valueOf(propMap
				.get(Constants.WARM_UPS)), Integer.valueOf(propMap
				.get(Constants.RUNS)));

		runner.run(task);
	}

	public static void runTask(String taskClass, int warmups, int runs, String[] params) throws Exception {
		Task task = TaskFactory.createTask(taskClass, params);
		TaskRunner runner = new TaskRunner(warmups, runs);

		try {
			runner.run(task);
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}

	/*
	 * A macro method, reads system properties, instantiates the task collection
	 * and runs it
	 */
	public static void runTaskCollection() throws Exception {
		Map<String, String> propMap = BenchmarkUtils
				.getSystemProperties(new String[] { Constants.TASK_CLASS_NAME,
						Constants.WARM_UPS, Constants.RUNS,
						Constants.TASK_PARAMS });

		TaskCollection collection = TaskFactory.createTaskCollection(propMap
				.get(Constants.TASK_CLASS_NAME), BenchmarkUtils
				.getCommaSeparatedParameter(Constants.TASK_PARAMS));
		RepeatEachTaskRunner runner = new RepeatEachTaskRunner(Integer.valueOf(propMap
				.get(Constants.WARM_UPS)), Integer.valueOf(propMap
				.get(Constants.RUNS)));

		runner.run(collection);
	}

	public static void runTaskCollection(String taskClass, int warmups, int runs, String[] params) throws Exception {
		TaskCollection collection = TaskFactory.createTaskCollection(taskClass, params);
		RepeatEachTaskRunner runner = new RepeatEachTaskRunner(warmups, runs);

		try {
			runner.run(collection);
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}

	//TODO need a better name
	public static void runTaskCollection2(String taskClass, int warmups, int runs, String[] params) throws Exception {
		VisitorTaskCollection collection = TaskFactory.createTaskCollection2(taskClass, params);
		RunAllOnceThenRepeatRunner runner = new RunAllOnceThenRepeatRunner(warmups, runs);

		try {
			runner.run(collection);
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}

	public static File getFile(String path) {
		if (path.startsWith("~" + File.separator)) {
			// replace with the user.home path
			path = System.getProperty("user.home") + path.substring(1);
			// TODO Invoke shell to handle stuff like ~username correctly?
		}

		return new File(path);
	}

	public static ReasonerConfiguration getReasonerConfiguration(String[] args) {
		return getReasonerConfiguration(args, 1);
	}

	public static ReasonerConfiguration getReasonerConfiguration(String[] args, int firstArgIndex) {
		ReasonerConfiguration config = ReasonerConfiguration.getConfiguration();

		if (args.length > firstArgIndex) {
			config.setParameter(ReasonerConfiguration.NUM_OF_WORKING_THREADS, args[firstArgIndex]);
		}

		return config;
	}
}


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

/*
 * #%L
 * ELK Reasoner
 * $Id:$
 * $HeadURL:$
 * %%
 * Copyright (C) 2011 - 2015 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.indexing.model.IndexedContextRoot;
import org.semanticweb.elk.reasoner.indexing.model.IndexedPropertyChain;
import org.semanticweb.elk.reasoner.saturation.conclusions.classes.ForwardLinkImpl;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.ForwardLink;

abstract class AbstractForwardLinkInference<R extends IndexedPropertyChain>
		extends AbstractClassInference implements ForwardLinkInference {

	/**
	 * the {@link IndexedPropertyChain} in the existential restriction
	 * corresponding to this {@link ForwardLinkImpl}
	 */
	private final R forwardChain_;

	/**
	 * the {@link IndexedContextRoot} corresponding to the filler of the
	 * existential restriction corresponding to this {@link ForwardLinkImpl}
	 */
	private final IndexedContextRoot target_;

	public AbstractForwardLinkInference(IndexedContextRoot destination,
			R forwardChain, IndexedContextRoot target) {
		super(destination);
		this.forwardChain_ = forwardChain;
		this.target_ = target;
	}

	public R getChain() {
		return forwardChain_;
	}

	public IndexedContextRoot getTarget() {
		return target_;
	}

	/**
	 * @param factory
	 *            the factory for creating conclusions
	 *
	 * @return the conclusion produced by this inference
	 */
	public final ForwardLink getConclusion(ForwardLink.Factory factory) {
		return factory.getForwardLink(getDestination(), getChain(),
				getTarget());
	}

	@Override
	public final <O> O accept(ClassInference.Visitor<O> visitor) {
		return accept((ForwardLinkInference.Visitor<O>) visitor);
	}

}


package org.semanticweb.elk.reasoner.saturation.properties.inferences;

/*-
 * #%L
 * ELK Reasoner Core
 * $Id:$
 * $HeadURL:$
 * %%
 * Copyright (C) 2011 - 2017 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.conclusions.model.ObjectPropertyConclusion;
import org.semanticweb.elk.reasoner.saturation.inferences.ClassInference;
import org.semanticweb.elk.reasoner.saturation.inferences.SaturationInference;
import org.semanticweb.elk.reasoner.tracing.AbstractTracingInference;
import org.semanticweb.elk.reasoner.tracing.Conclusion;
import org.semanticweb.elk.reasoner.tracing.TracingInference;

/**
 * A skeleton implementation of {@link ClassInference}
 *
 * @author Yevgeny Kazakov
 *
 */
abstract class AbstractObjectPropertyInference extends AbstractTracingInference
		implements ObjectPropertyInference {

	/**
	 * @param factory
	 *            the factory for creating conclusions
	 *
	 * @return the conclusion produced by this inference
	 */
	abstract <F extends ObjectPropertyConclusion.Factory> Conclusion getConclusion(
			F factory);

//	@Override
//	public final Conclusion getConclusion(Conclusion.Factory factory) {
//		return getConclusion((ObjectPropertyConclusion.Factory) factory);
//	}

	@Override
	public final <O> O accept(TracingInference.Visitor<O> visitor) {
		return accept((ObjectPropertyInference.Visitor<O>) visitor);
	}

	@Override
	public final <O> O accept(SaturationInference.Visitor<O> visitor) {
		return accept((ObjectPropertyInference.Visitor<O>) visitor);
	}

}


/*
 * #%L
 * ELK OWL API Binding
 *
 * $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.owlapi.wrapper;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.semanticweb.elk.owl.interfaces.ElkAnnotationAxiom;
import org.semanticweb.elk.owl.interfaces.ElkAnnotationProperty;
import org.semanticweb.elk.owl.interfaces.ElkAnnotationSubject;
import org.semanticweb.elk.owl.interfaces.ElkAnnotationValue;
import org.semanticweb.elk.owl.interfaces.ElkAnonymousIndividual;
import org.semanticweb.elk.owl.interfaces.ElkAssertionAxiom;
import org.semanticweb.elk.owl.interfaces.ElkAsymmetricObjectPropertyAxiom;
import org.semanticweb.elk.owl.interfaces.ElkAxiom;
import org.semanticweb.elk.owl.interfaces.ElkClass;
import org.semanticweb.elk.owl.interfaces.ElkClassAssertionAxiom;
import org.semanticweb.elk.owl.interfaces.ElkClassAxiom;
import org.semanticweb.elk.owl.interfaces.ElkClassExpression;
import org.semanticweb.elk.owl.interfaces.ElkDataAllValuesFrom;
import org.semanticweb.elk.owl.interfaces.ElkDataComplementOf;
import org.semanticweb.elk.owl.interfaces.ElkDataExactCardinality;
import org.semanticweb.elk.owl.interfaces.ElkDataHasValue;
import org.semanticweb.elk.owl.interfaces.ElkDataIntersectionOf;
import org.semanticweb.elk.owl.interfaces.ElkDataMaxCardinality;
import org.semanticweb.elk.owl.interfaces.ElkDataMinCardinality;
import org.semanticweb.elk.owl.interfaces.ElkDataOneOf;
import org.semanticweb.elk.owl.interfaces.ElkDataProperty;
import org.semanticweb.elk.owl.interfaces.ElkDataPropertyAssertionAxiom;
import org.semanticweb.elk.owl.interfaces.ElkDataPropertyAxiom;
import org.semanticweb.elk.owl.interfaces.ElkDataPropertyDomainAxiom;
import org.semanticweb.elk.owl.interfaces.ElkDataPropertyExpression;
import org.semanticweb.elk.owl.interfaces.ElkDataPropertyRangeAxiom;
import org.semanticweb.elk.owl.interfaces.ElkDataRange;
import org.semanticweb.elk.owl.interfaces.ElkDataSomeValuesFrom;
import org.semanticweb.elk.owl.interfaces.ElkDataUnionOf;
import org.semanticweb.elk.owl.interfaces.ElkDatatype;
import org.semanticweb.elk.owl.interfaces.ElkDatatypeDefinitionAxiom;
import org.semanticweb.elk.owl.interfaces.ElkDatatypeRestriction;
import org.semanticweb.elk.owl.interfaces.ElkDeclarationAxiom;
import org.semanticweb.elk.owl.interfaces.ElkDifferentIndividualsAxiom;
import org.semanticweb.elk.owl.interfaces.ElkDisjointClassesAxiom;
import org.semanticweb.elk.owl.interfaces.ElkDisjointDataPropertiesAxiom;
import org.semanticweb.elk.owl.interfaces.ElkDisjointObjectPropertiesAxiom;
import org.semanticweb.elk.owl.interfaces.ElkDisjointUnionAxiom;
import org.semanticweb.elk.owl.interfaces.ElkEntity;
import org.semanticweb.elk.owl.interfaces.ElkEquivalentClassesAxiom;
import org.semanticweb.elk.owl.interfaces.ElkEquivalentDataPropertiesAxiom;
import org.semanticweb.elk.owl.interfaces.ElkEquivalentObjectPropertiesAxiom;
import org.semanticweb.elk.owl.interfaces.ElkFacetRestriction;
import org.semanticweb.elk.owl.interfaces.ElkFunctionalDataPropertyAxiom;
import org.semanticweb.elk.owl.interfaces.ElkFunctionalObjectPropertyAxiom;
import org.semanticweb.elk.owl.interfaces.ElkHasKeyAxiom;
import org.semanticweb.elk.owl.interfaces.ElkIndividual;
import org.semanticweb.elk.owl.interfaces.ElkInverseFunctionalObjectPropertyAxiom;
import org.semanticweb.elk.owl.interfaces.ElkInverseObjectPropertiesAxiom;
import org.semanticweb.elk.owl.interfaces.ElkIrreflexiveObjectPropertyAxiom;
import org.semanticweb.elk.owl.interfaces.ElkLiteral;
import org.semanticweb.elk.owl.interfaces.ElkNamedIndividual;
import org.semanticweb.elk.owl.interfaces.ElkNegativeDataPropertyAssertionAxiom;
import org.semanticweb.elk.owl.interfaces.ElkNegativeObjectPropertyAssertionAxiom;
import org.semanticweb.elk.owl.interfaces.ElkObject;
import org.semanticweb.elk.owl.interfaces.ElkObjectAllValuesFrom;
import org.semanticweb.elk.owl.interfaces.ElkObjectComplementOf;
import org.semanticweb.elk.owl.interfaces.ElkObjectExactCardinality;
import org.semanticweb.elk.owl.interfaces.ElkObjectHasSelf;
import org.semanticweb.elk.owl.interfaces.ElkObjectHasValue;
import org.semanticweb.elk.owl.interfaces.ElkObjectIntersectionOf;
import org.semanticweb.elk.owl.interfaces.ElkObjectMaxCardinality;
import org.semanticweb.elk.owl.interfaces.ElkObjectMinCardinality;
import org.semanticweb.elk.owl.interfaces.ElkObjectOneOf;
import org.semanticweb.elk.owl.interfaces.ElkObjectProperty;
import org.semanticweb.elk.owl.interfaces.ElkObjectPropertyAssertionAxiom;
import org.semanticweb.elk.owl.interfaces.ElkObjectPropertyAxiom;
import org.semanticweb.elk.owl.interfaces.ElkObjectPropertyChain;
import org.semanticweb.elk.owl.interfaces.ElkObjectPropertyDomainAxiom;
import org.semanticweb.elk.owl.interfaces.ElkObjectPropertyExpression;
import org.semanticweb.elk.owl.interfaces.ElkObjectPropertyRangeAxiom;
import org.semanticweb.elk.owl.interfaces.ElkObjectSomeValuesFrom;
import org.semanticweb.elk.owl.interfaces.ElkObjectUnionOf;
import org.semanticweb.elk.owl.interfaces.ElkReflexiveObjectPropertyAxiom;
import org.semanticweb.elk.owl.interfaces.ElkSWRLRule;
import org.semanticweb.elk.owl.interfaces.ElkSameIndividualAxiom;
import org.semanticweb.elk.owl.interfaces.ElkSubClassOfAxiom;
import org.semanticweb.elk.owl.interfaces.ElkSubDataPropertyOfAxiom;
import org.semanticweb.elk.owl.interfaces.ElkSubObjectPropertyOfAxiom;
import org.semanticweb.elk.owl.interfaces.ElkSymmetricObjectPropertyAxiom;
import org.semanticweb.elk.owl.interfaces.ElkTransitiveObjectPropertyAxiom;
import org.semanticweb.elk.owl.iris.ElkFullIri;
import org.semanticweb.elk.owl.iris.ElkIri;
import org.semanticweb.owlapi.model.AxiomType;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotationAxiom;
import org.semanticweb.owlapi.model.OWLAnnotationProperty;
import org.semanticweb.owlapi.model.OWLAnnotationSubject;
import org.semanticweb.owlapi.model.OWLAnnotationValue;
import org.semanticweb.owlapi.model.OWLAnonymousIndividual;
import org.semanticweb.owlapi.model.OWLAsymmetricObjectPropertyAxiom;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassAssertionAxiom;
import org.semanticweb.owlapi.model.OWLClassAxiom;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDataAllValuesFrom;
import org.semanticweb.owlapi.model.OWLDataComplementOf;
import org.semanticweb.owlapi.model.OWLDataExactCardinality;
import org.semanticweb.owlapi.model.OWLDataHasValue;
import org.semanticweb.owlapi.model.OWLDataIntersectionOf;
import org.semanticweb.owlapi.model.OWLDataMaxCardinality;
import org.semanticweb.owlapi.model.OWLDataMinCardinality;
import org.semanticweb.owlapi.model.OWLDataOneOf;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLDataPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLDataPropertyAxiom;
import org.semanticweb.owlapi.model.OWLDataPropertyDomainAxiom;
import org.semanticweb.owlapi.model.OWLDataPropertyExpression;
import org.semanticweb.owlapi.model.OWLDataPropertyRangeAxiom;
import org.semanticweb.owlapi.model.OWLDataRange;
import org.semanticweb.owlapi.model.OWLDataSomeValuesFrom;
import org.semanticweb.owlapi.model.OWLDataUnionOf;
import org.semanticweb.owlapi.model.OWLDatatype;
import org.semanticweb.owlapi.model.OWLDatatypeDefinitionAxiom;
import org.semanticweb.owlapi.model.OWLDatatypeRestriction;
import org.semanticweb.owlapi.model.OWLDeclarationAxiom;
import org.semanticweb.owlapi.model.OWLDifferentIndividualsAxiom;
import org.semanticweb.owlapi.model.OWLDisjointClassesAxiom;
import org.semanticweb.owlapi.model.OWLDisjointDataPropertiesAxiom;
import org.semanticweb.owlapi.model.OWLDisjointObjectPropertiesAxiom;
import org.semanticweb.owlapi.model.OWLDisjointUnionAxiom;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLEquivalentClassesAxiom;
import org.semanticweb.owlapi.model.OWLEquivalentDataPropertiesAxiom;
import org.semanticweb.owlapi.model.OWLEquivalentObjectPropertiesAxiom;
import org.semanticweb.owlapi.model.OWLFacetRestriction;
import org.semanticweb.owlapi.model.OWLFunctionalDataPropertyAxiom;
import org.semanticweb.owlapi.model.OWLFunctionalObjectPropertyAxiom;
import org.semanticweb.owlapi.model.OWLHasKeyAxiom;
import org.semanticweb.owlapi.model.OWLIndividual;
import org.semanticweb.owlapi.model.OWLIndividualAxiom;
import org.semanticweb.owlapi.model.OWLInverseFunctionalObjectPropertyAxiom;
import org.semanticweb.owlapi.model.OWLInverseObjectPropertiesAxiom;
import org.semanticweb.owlapi.model.OWLIrreflexiveObjectPropertyAxiom;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLNegativeDataPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLNegativeObjectPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLObject;
import org.semanticweb.owlapi.model.OWLObjectAllValuesFrom;
import org.semanticweb.owlapi.model.OWLObjectComplementOf;
import org.semanticweb.owlapi.model.OWLObjectExactCardinality;
import org.semanticweb.owlapi.model.OWLObjectHasSelf;
import org.semanticweb.owlapi.model.OWLObjectHasValue;
import org.semanticweb.owlapi.model.OWLObjectIntersectionOf;
import org.semanticweb.owlapi.model.OWLObjectMaxCardinality;
import org.semanticweb.owlapi.model.OWLObjectMinCardinality;
import org.semanticweb.owlapi.model.OWLObjectOneOf;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLObjectPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLObjectPropertyAxiom;
import org.semanticweb.owlapi.model.OWLObjectPropertyDomainAxiom;
import org.semanticweb.owlapi.model.OWLObjectPropertyExpression;
import org.semanticweb.owlapi.model.OWLObjectPropertyRangeAxiom;
import org.semanticweb.owlapi.model.OWLObjectSomeValuesFrom;
import org.semanticweb.owlapi.model.OWLObjectUnionOf;
import org.semanticweb.owlapi.model.OWLReflexiveObjectPropertyAxiom;
import org.semanticweb.owlapi.model.OWLSameIndividualAxiom;
import org.semanticweb.owlapi.model.OWLSubClassOfAxiom;
import org.semanticweb.owlapi.model.OWLSubDataPropertyOfAxiom;
import org.semanticweb.owlapi.model.OWLSubObjectPropertyOfAxiom;
import org.semanticweb.owlapi.model.OWLSubPropertyChainOfAxiom;
import org.semanticweb.owlapi.model.OWLSymmetricObjectPropertyAxiom;
import org.semanticweb.owlapi.model.OWLTransitiveObjectPropertyAxiom;
import org.semanticweb.owlapi.model.SWRLRule;

/**
 *
 * @author Yevgeny Kazakov
 * @author Pavel Klinov
 *
 *         pavel.klinov@uni-ulm.de
 */
public class OwlConverter {

	private static OwlConverter INSTANCE_ = new OwlConverter();

	private OwlConverter() {
	}

	public static OwlConverter getInstance() {
		return INSTANCE_;
	}

	protected static OwlAxiomConverterVisitor OWL_AXIOM_CONVERTER = OwlAxiomConverterVisitor
			.getInstance();

	protected static OwlAnnotationAxiomConverterVisitor OWL_ANNOTATION_AXIOM_CONVERTER = OwlAnnotationAxiomConverterVisitor
			.getInstance();

	protected static OwlClassAxiomConverterVisitor OWL_CLASS_AXIOM_CONVERTER = OwlClassAxiomConverterVisitor
			.getInstance();

	protected static OwlObjectPropertyAxiomConverterVisitor OWL_OBJECT_PROPERTY_AXIOM_CONVERTER = OwlObjectPropertyAxiomConverterVisitor
			.getInstance();

	protected static OwlDataPropertyAxiomConverterVisitor OWL_DATA_PROPERTY_AXIOM_CONVERTER = OwlDataPropertyAxiomConverterVisitor
			.getInstance();

	protected static OwlIndividualAxiomConverterVisitor OWL_INDIVIDUAL_AXIOM_CONVERTER = OwlIndividualAxiomConverterVisitor
			.getInstance();

	protected static OwlClassExpressionConverterVisitor OWL_CLASS_EXPRESSION_CONVERTER = OwlClassExpressionConverterVisitor
			.getInstance();

	protected static OwlDataRangeConverterVisitor OWL_DATA_RANGE_CONVERTER = OwlDataRangeConverterVisitor
			.getInstance();

	protected static OwlObjectPropertyExpressionConverterVisitor OWL_OBJECT_PROPERTY_EXPRESSION_CONVERTER = OwlObjectPropertyExpressionConverterVisitor
			.getInstance();

	protected static OwlIndividualConverterVisitor OWL_INDIVIDUAL_CONVERTER = OwlIndividualConverterVisitor
			.getInstance();

	protected static OwlAnnotationSubjectValueVisitor OWL_ANNOTATION_CONVERTER = OwlAnnotationSubjectValueVisitor
			.getInstance();

	protected static OwlEntityConverterVisitor OWL_ENTITY_CONVERTER = OwlEntityConverterVisitor
			.getInstance();

	@SuppressWarnings("static-method")
	public ElkAnnotationProperty convert(
			OWLAnnotationProperty owlAnnotationProperty) {
		return new ElkAnnotationPropertyWrap<OWLAnnotationProperty>(
				owlAnnotationProperty);
	}

	@SuppressWarnings("static-method")
	public ElkAnonymousIndividual convert(
			OWLAnonymousIndividual owlAnonymousIndividual) {
		return new ElkAnonymousIndividualWrap<OWLAnonymousIndividual>(
				owlAnonymousIndividual);
	}

	@SuppressWarnings("static-method")
	public ElkAnnotationAxiom convert(OWLAnnotationAxiom owlAnnotationAxiom) {
		return owlAnnotationAxiom.accept(OWL_ANNOTATION_AXIOM_CONVERTER);
	}

	@SuppressWarnings("static-method")
	public ElkAssertionAxiom convert(OWLIndividualAxiom owlIndividualAxiom) {
		return owlIndividualAxiom.accept(OWL_INDIVIDUAL_AXIOM_CONVERTER);
	}

	@SuppressWarnings("static-method")
	public ElkAsymmetricObjectPropertyAxiom convert(
			OWLAsymmetricObjectPropertyAxiom owlAsymmetricObjectPropertyAxiom) {
		return new ElkAsymmetricObjectPropertyAxiomWrap<OWLAsymmetricObjectPropertyAxiom>(
				owlAsymmetricObjectPropertyAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkAxiom convert(OWLAxiom owlAxiom) {
		return owlAxiom.accept(OWL_AXIOM_CONVERTER);
	}

	@SuppressWarnings("static-method")
	public ElkClassAssertionAxiom convert(
			OWLClassAssertionAxiom owlClassAssertionAxiom) {
		return new ElkClassAssertionAxiomWrap<OWLClassAssertionAxiom>(
				owlClassAssertionAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkClassAxiom convert(OWLClassAxiom owlClassAxiom) {
		return owlClassAxiom.accept(OWL_CLASS_AXIOM_CONVERTER);
	}

	@SuppressWarnings("static-method")
	public ElkClassExpression convert(OWLClassExpression owlClassExpression) {
		return owlClassExpression.accept(OWL_CLASS_EXPRESSION_CONVERTER);
	}

	@SuppressWarnings("static-method")
	public ElkClass convert(OWLClass owlClass) {
		return new ElkClassWrap<OWLClass>(owlClass);
	}

	@SuppressWarnings("static-method")
	public ElkDataAllValuesFrom convert(
			OWLDataAllValuesFrom owlDataAllValuesFrom) {
		return new ElkDataAllValuesFromWrap<OWLDataAllValuesFrom>(
				owlDataAllValuesFrom);
	}

	@SuppressWarnings("static-method")
	public ElkDataComplementOf convert(
			OWLDataComplementOf owlDataComplementOf) {
		return new ElkDataComplementOfWrap<OWLDataComplementOf>(
				owlDataComplementOf);
	}

	@SuppressWarnings("static-method")
	public ElkDataExactCardinality convert(
			OWLDataExactCardinality owlDataExactCardinality) {
		if (owlDataExactCardinality.isQualified())
			return new ElkDataExactCardinalityQualifiedWrap<OWLDataExactCardinality>(
					owlDataExactCardinality);
		// else
		return new ElkDataExactCardinalityUnqualifiedWrap<OWLDataExactCardinality>(
				owlDataExactCardinality);
	}

	@SuppressWarnings("static-method")
	public ElkDataHasValue convert(OWLDataHasValue owlDataHasValue) {
		return new ElkDataHasValueWrap<OWLDataHasValue>(owlDataHasValue);
	}

	@SuppressWarnings("static-method")
	public ElkDataIntersectionOf convert(
			OWLDataIntersectionOf owlDataIntersectionOf) {
		return new ElkDataIntersectionOfWrap<OWLDataIntersectionOf>(
				owlDataIntersectionOf);
	}

	@SuppressWarnings("static-method")
	public ElkDataMaxCardinality convert(
			OWLDataMaxCardinality owlDataMaxCardinality) {
		if (owlDataMaxCardinality.isQualified())
			return new ElkDataMaxCardinalityQualifiedWrap<OWLDataMaxCardinality>(
					owlDataMaxCardinality);
		// else
		return new ElkDataMaxCardinalityUnqualifiedWrap<OWLDataMaxCardinality>(
				owlDataMaxCardinality);
	}

	@SuppressWarnings("static-method")
	public ElkDataMinCardinality convert(
			OWLDataMinCardinality owlDataMinCardinality) {
		if (owlDataMinCardinality.isQualified())
			return new ElkDataMinCardinalityQualifiedWrap<OWLDataMinCardinality>(
					owlDataMinCardinality);
		// else
		return new ElkDataMinCardinalityUnqualifiedWrap<OWLDataMinCardinality>(
				owlDataMinCardinality);
	}

	@SuppressWarnings("static-method")
	public ElkDataOneOf convert(OWLDataOneOf owlDataOneOf) {
		return new ElkDataOneOfWrap<OWLDataOneOf>(owlDataOneOf);
	}

	@SuppressWarnings("static-method")
	public ElkDataPropertyAssertionAxiom convert(
			OWLDataPropertyAssertionAxiom owlDataPropertyAssertionAxiom) {
		return new ElkDataPropertyAssertionAxiomWrap<OWLDataPropertyAssertionAxiom>(
				owlDataPropertyAssertionAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkDataPropertyAxiom convert(
			OWLDataPropertyAxiom owlDataPropertyAxiom) {
		return owlDataPropertyAxiom.accept(OWL_DATA_PROPERTY_AXIOM_CONVERTER);
	}

	@SuppressWarnings("static-method")
	public ElkDataPropertyDomainAxiom convert(
			OWLDataPropertyDomainAxiom owlDataPropertyDomainAxiom) {
		return new ElkDataPropertyDomainAxiomWrap<OWLDataPropertyDomainAxiom>(
				owlDataPropertyDomainAxiom);
	}

	public ElkDataPropertyExpression convert(
			OWLDataPropertyExpression owlDataPropertyExpression) {
		return this.convert(owlDataPropertyExpression.asOWLDataProperty());
	}

	@SuppressWarnings("static-method")
	public ElkDataPropertyRangeAxiom convert(
			OWLDataPropertyRangeAxiom owlDataPropertyRangeAxiom) {
		return new ElkDataPropertyRangeAxiomWrap<OWLDataPropertyRangeAxiom>(
				owlDataPropertyRangeAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkDataProperty convert(OWLDataProperty owlDataProperty) {
		return new ElkDataPropertyWrap<OWLDataProperty>(owlDataProperty);
	}

	@SuppressWarnings("static-method")
	public ElkDataRange convert(OWLDataRange owlDataRange) {
		return owlDataRange.accept(OWL_DATA_RANGE_CONVERTER);
	}

	@SuppressWarnings("static-method")
	public ElkDataSomeValuesFrom convert(
			OWLDataSomeValuesFrom owlDataSomeValuesFrom) {
		return new ElkDataSomeValuesFromWrap<OWLDataSomeValuesFrom>(
				owlDataSomeValuesFrom);
	}

	@SuppressWarnings("static-method")
	public ElkDatatypeRestriction convert(
			OWLDatatypeRestriction owlDatatypeRestriction) {
		return new ElkDatatypeRestrictionWrap<OWLDatatypeRestriction>(
				owlDatatypeRestriction);
	}

	@SuppressWarnings("static-method")
	public ElkDatatypeDefinitionAxiom convert(
			OWLDatatypeDefinitionAxiom owlDatatypeDefinition) {
		return new ElkDatatypeDefinitionAxiomWrap<OWLDatatypeDefinitionAxiom>(
				owlDatatypeDefinition);
	}

	@SuppressWarnings("static-method")
	public ElkDatatype convert(OWLDatatype owlDatatype) {
		return new ElkDatatypeWrap<OWLDatatype>(owlDatatype);
	}

	@SuppressWarnings("static-method")
	public ElkDataUnionOf convert(OWLDataUnionOf owlDataUnionOf) {
		return new ElkDataUnionOfWrap<OWLDataUnionOf>(owlDataUnionOf);
	}

	@SuppressWarnings("static-method")
	public ElkDeclarationAxiom convert(
			OWLDeclarationAxiom owlDeclarationAxiom) {
		return new ElkDeclarationAxiomWrap<OWLDeclarationAxiom>(
				owlDeclarationAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkDifferentIndividualsAxiom convert(
			OWLDifferentIndividualsAxiom owlDifferentIndividualsAxiom) {
		return new ElkDifferentIndividualsAxiomWrap<OWLDifferentIndividualsAxiom>(
				owlDifferentIndividualsAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkDisjointClassesAxiom convert(
			OWLDisjointClassesAxiom owlDisjointClassesAxiom) {
		return new ElkDisjointClassesAxiomWrap<OWLDisjointClassesAxiom>(
				owlDisjointClassesAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkDisjointDataPropertiesAxiom convert(
			OWLDisjointDataPropertiesAxiom owlDisjointDataPropertiesAxiom) {
		return new ElkDisjointDataPropertiesAxiomWrap<OWLDisjointDataPropertiesAxiom>(
				owlDisjointDataPropertiesAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkDisjointObjectPropertiesAxiom convert(
			OWLDisjointObjectPropertiesAxiom owlDisjointObjectPropertiesAxiom) {
		return new ElkDisjointObjectPropertiesAxiomWrap<OWLDisjointObjectPropertiesAxiom>(
				owlDisjointObjectPropertiesAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkDisjointUnionAxiom convert(
			OWLDisjointUnionAxiom owlDisjointUnionAxiom) {
		return new ElkDisjointUnionAxiomWrap<OWLDisjointUnionAxiom>(
				owlDisjointUnionAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkEntity convert(OWLEntity owlEntity) {
		return owlEntity.accept(OWL_ENTITY_CONVERTER);
	}

	@SuppressWarnings("static-method")
	public ElkEquivalentClassesAxiom convert(
			OWLEquivalentClassesAxiom owlEquivalentClassesAxiom) {
		return new ElkEquivalentClassesAxiomWrap<OWLEquivalentClassesAxiom>(
				owlEquivalentClassesAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkEquivalentDataPropertiesAxiom convert(
			OWLEquivalentDataPropertiesAxiom owlEquivalentDataPropertiesAxiom) {
		return new ElkEquivalentDataPropertiesAxiomWrap<OWLEquivalentDataPropertiesAxiom>(
				owlEquivalentDataPropertiesAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkEquivalentObjectPropertiesAxiom convert(
			OWLEquivalentObjectPropertiesAxiom owlEquivalentObjectPropertiesAxiom) {
		return new ElkEquivalentObjectPropertiesAxiomWrap<OWLEquivalentObjectPropertiesAxiom>(
				owlEquivalentObjectPropertiesAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkFacetRestriction convert(
			OWLFacetRestriction owlFacetRestriction) {
		return new ElkFacetRestrictionWrap<OWLFacetRestriction>(
				owlFacetRestriction);
	}

	@SuppressWarnings("static-method")
	public ElkFunctionalDataPropertyAxiom convert(
			OWLFunctionalDataPropertyAxiom owlFunctionalDataPropertyAxiom) {
		return new ElkFunctionalDataPropertyAxiomWrap<OWLFunctionalDataPropertyAxiom>(
				owlFunctionalDataPropertyAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkFunctionalObjectPropertyAxiom convert(
			OWLFunctionalObjectPropertyAxiom owlFunctionalObjectPropertyAxiom) {
		return new ElkFunctionalObjectPropertyAxiomWrap<OWLFunctionalObjectPropertyAxiom>(
				owlFunctionalObjectPropertyAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkIndividual convert(OWLIndividual owlIndividual) {
		return owlIndividual.accept(OWL_INDIVIDUAL_CONVERTER);
	}

	@SuppressWarnings("static-method")
	public ElkInverseFunctionalObjectPropertyAxiom convert(
			OWLInverseFunctionalObjectPropertyAxiom owlInverseFunctionalObjectPropertyAxiom) {
		return new ElkInverseFunctionalObjectPropertyAxiomWrap<OWLInverseFunctionalObjectPropertyAxiom>(
				owlInverseFunctionalObjectPropertyAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkInverseObjectPropertiesAxiom convert(
			OWLInverseObjectPropertiesAxiom owlInverseObjectPropertiesAxiom) {
		return new ElkInverseObjectPropertiesAxiomWrap<OWLInverseObjectPropertiesAxiom>(
				owlInverseObjectPropertiesAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkIrreflexiveObjectPropertyAxiom convert(
			OWLIrreflexiveObjectPropertyAxiom owlIrreflexiveObjectPropertyAxiom) {
		return new ElkIrreflexiveObjectPropertyAxiomWrap<OWLIrreflexiveObjectPropertyAxiom>(
				owlIrreflexiveObjectPropertyAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkLiteral convert(OWLLiteral owlLiteral) {
		return new ElkLiteralWrap<OWLLiteral>(owlLiteral);
	}

	@SuppressWarnings("static-method")
	public ElkNamedIndividual convert(OWLNamedIndividual owlNamedIndividual) {
		return new ElkNamedIndividualWrap<OWLNamedIndividual>(
				owlNamedIndividual);
	}

	@SuppressWarnings("static-method")
	public ElkNegativeDataPropertyAssertionAxiom convert(
			OWLNegativeDataPropertyAssertionAxiom owlNegativeDataPropertyAssertionAxiom) {
		return new ElkNegativeDataPropertyAssertionAxiomWrap<OWLNegativeDataPropertyAssertionAxiom>(
				owlNegativeDataPropertyAssertionAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkNegativeObjectPropertyAssertionAxiom convert(
			OWLNegativeObjectPropertyAssertionAxiom owlNegativeObjectPropertyAssertionAxiom) {
		return new ElkNegativeObjectPropertyAssertionAxiomWrap<OWLNegativeObjectPropertyAssertionAxiom>(
				owlNegativeObjectPropertyAssertionAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkObjectAllValuesFrom convert(
			OWLObjectAllValuesFrom owlObjectAllValuesFrom) {
		return new ElkObjectAllValuesFromWrap<OWLObjectAllValuesFrom>(
				owlObjectAllValuesFrom);
	}

	@SuppressWarnings("static-method")
	public ElkObjectComplementOf convert(
			OWLObjectComplementOf owlObjectComplementOf) {
		return new ElkObjectComplementOfWrap<OWLObjectComplementOf>(
				owlObjectComplementOf);
	}

	@SuppressWarnings("static-method")
	public ElkObjectExactCardinality convert(
			OWLObjectExactCardinality owlObjectExactCardinality) {
		if (owlObjectExactCardinality.isQualified())
			return new ElkObjectExactCardinalityQualifiedWrap<OWLObjectExactCardinality>(
					owlObjectExactCardinality);
		// else
		return new ElkObjectExactCardinalityUnqualifiedWrap<OWLObjectExactCardinality>(
				owlObjectExactCardinality);
	}

	@SuppressWarnings("static-method")
	public ElkObjectHasSelf convert(OWLObjectHasSelf owlObjectHasSelf) {
		return new ElkObjectHasSelfWrap<OWLObjectHasSelf>(owlObjectHasSelf);
	}

	@SuppressWarnings("static-method")
	public ElkObjectHasValue convert(OWLObjectHasValue owlObjectHasValue) {
		return new ElkObjectHasValueWrap<OWLObjectHasValue>(owlObjectHasValue);
	}

	@SuppressWarnings("static-method")
	public ElkObjectIntersectionOf convert(
			OWLObjectIntersectionOf owlObjectIntersectionOf) {
		return new ElkObjectIntersectionOfWrap<OWLObjectIntersectionOf>(
				owlObjectIntersectionOf);
	}

	@SuppressWarnings("static-method")
	public ElkObjectMaxCardinality convert(
			OWLObjectMaxCardinality owlObjectMaxCardinality) {
		if (owlObjectMaxCardinality.isQualified())
			return new ElkObjectMaxCardinalityQualifiedWrap<OWLObjectMaxCardinality>(
					owlObjectMaxCardinality);
		// else
		return new ElkObjectMaxCardinalityUnqualifiedWrap<OWLObjectMaxCardinality>(
				owlObjectMaxCardinality);
	}

	@SuppressWarnings("static-method")
	public ElkObjectMinCardinality convert(
			OWLObjectMinCardinality owlObjectMaxCardinality) {
		if (owlObjectMaxCardinality.isQualified())
			return new ElkObjectMinCardinalityQualifiedWrap<OWLObjectMinCardinality>(
					owlObjectMaxCardinality);
		// else
		return new ElkObjectMinCardinalityUnqualifiedWrap<OWLObjectMinCardinality>(
				owlObjectMaxCardinality);
	}

	@SuppressWarnings("static-method")
	public ElkObjectOneOf convert(OWLObjectOneOf owlObjectOneOf) {
		return new ElkObjectOneOfWrap<OWLObjectOneOf>(owlObjectOneOf);
	}

	@SuppressWarnings("static-method")
	public ElkObjectPropertyAssertionAxiom convert(
			OWLObjectPropertyAssertionAxiom owlObjectPropertyAssertionAxiom) {
		return new ElkObjectPropertyAssertionAxiomWrap<OWLObjectPropertyAssertionAxiom>(
				owlObjectPropertyAssertionAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkObjectPropertyAxiom convert(
			OWLObjectPropertyAxiom owlObjectPropertyAxiom) {
		return owlObjectPropertyAxiom
				.accept(OWL_OBJECT_PROPERTY_AXIOM_CONVERTER);
	}

	@SuppressWarnings("static-method")
	public ElkObjectPropertyChain convert(
			OWLSubPropertyChainOfAxiom owlSubPropertyChainOfAxiom) {
		return new ElkObjectPropertyChainWrap<List<? extends OWLObjectPropertyExpression>>(
				owlSubPropertyChainOfAxiom.getPropertyChain());
	}

	@SuppressWarnings("static-method")
	public ElkObjectPropertyDomainAxiom convert(
			OWLObjectPropertyDomainAxiom owlObjectPropertyDomainAxiom) {
		return new ElkObjectPropertyDomainAxiomWrap<OWLObjectPropertyDomainAxiom>(
				owlObjectPropertyDomainAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkObjectPropertyExpression convert(
			OWLObjectPropertyExpression objectPropertyExpression) {
		return objectPropertyExpression
				.accept(OWL_OBJECT_PROPERTY_EXPRESSION_CONVERTER);
	}

	@SuppressWarnings("static-method")
	public ElkObjectPropertyRangeAxiom convert(
			OWLObjectPropertyRangeAxiom owlObjectPropertyRangeAxiom) {
		return new ElkObjectPropertyRangeAxiomWrap<OWLObjectPropertyRangeAxiom>(
				owlObjectPropertyRangeAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkObjectProperty convert(OWLObjectProperty owlObjectProperty) {
		return new ElkObjectPropertyWrap<OWLObjectProperty>(owlObjectProperty);
	}

	@SuppressWarnings("static-method")
	public ElkObjectSomeValuesFrom convert(
			OWLObjectSomeValuesFrom owlObjectSomeValuesFrom) {
		return new ElkObjectSomeValuesFromWrap<OWLObjectSomeValuesFrom>(
				owlObjectSomeValuesFrom);
	}

	@SuppressWarnings("static-method")
	public ElkObjectUnionOf convert(OWLObjectUnionOf owlObjectUnionOf) {
		return new ElkObjectUnionOfWrap<OWLObjectUnionOf>(owlObjectUnionOf);
	}

	@SuppressWarnings("static-method")
	public ElkReflexiveObjectPropertyAxiom convert(
			OWLReflexiveObjectPropertyAxiom owlReflexiveObjectPropertyAxiom) {
		return new ElkReflexiveObjectPropertyAxiomWrap<OWLReflexiveObjectPropertyAxiom>(
				owlReflexiveObjectPropertyAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkSameIndividualAxiom convert(
			OWLSameIndividualAxiom owlSameIndividualAxiom) {
		return new ElkSameIndividualAxiomWrap<OWLSameIndividualAxiom>(
				owlSameIndividualAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkSubClassOfAxiom convert(OWLSubClassOfAxiom owlSubClassOfAxiom) {
		return new ElkSubClassOfAxiomWrap<OWLSubClassOfAxiom>(
				owlSubClassOfAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkSubDataPropertyOfAxiom convert(
			OWLSubDataPropertyOfAxiom owlSubDataPropertyOfAxiom) {
		return new ElkSubDataPropertyOfAxiomWrap<OWLSubDataPropertyOfAxiom>(
				owlSubDataPropertyOfAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkSubObjectPropertyOfAxiom convert(
			OWLSubObjectPropertyOfAxiom owlSubObjectPropertyOfAxiom) {
		return new ElkSubObjectPropertyOfAxiomWrap<OWLSubObjectPropertyOfAxiom>(
				owlSubObjectPropertyOfAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkSymmetricObjectPropertyAxiom convert(
			OWLSymmetricObjectPropertyAxiom owlSymmetricObjectPropertyAxiom) {
		return new ElkSymmetricObjectPropertyAxiomWrap<OWLSymmetricObjectPropertyAxiom>(
				owlSymmetricObjectPropertyAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkTransitiveObjectPropertyAxiom convert(
			OWLTransitiveObjectPropertyAxiom owlTransitiveObjectPropertyAxiom) {
		return new ElkTransitiveObjectPropertyAxiomWrap<OWLTransitiveObjectPropertyAxiom>(
				owlTransitiveObjectPropertyAxiom);
	}

	@SuppressWarnings("static-method")
	public ElkHasKeyAxiom convert(OWLHasKeyAxiom owlHasKey) {
		return new ElkHasKeyAxiomWrap<OWLHasKeyAxiom>(owlHasKey);
	}

	@SuppressWarnings("static-method")
	public ElkAnnotationSubject convert(OWLAnnotationSubject subject) {
		return OWL_ANNOTATION_CONVERTER.visit(subject);
	}

	@SuppressWarnings("static-method")
	public ElkAnnotationValue convert(OWLAnnotationValue value) {
		return OWL_ANNOTATION_CONVERTER.visit(value);
	}

	@SuppressWarnings("static-method")
	public ElkIri convert(IRI iri) {
		return new ElkFullIri(iri.toString());
	}

	/**
	 * @param axiom
	 *            the owl axiom to test
	 * @return {@code true} if the owl axiom can be converted to ELK axiom
	 */
	@SuppressWarnings("static-method")
	public boolean isRelevantAxiom(OWLAxiom axiom) {
		return axiom.isLogicalAxiom() || axiom.isOfType(AxiomType.DECLARATION);
	}

	@SuppressWarnings("static-method")
	public ElkSWRLRule convert(SWRLRule rule) {
		return new ElkSWRLRuleWrap<SWRLRule>(rule);
	}

	public Set<? extends ElkAxiom> convertAxiomSet(
			final Set<? extends OWLAxiom> owlAxioms) {
		final Set<ElkAxiom> result = new HashSet<ElkAxiom>(owlAxioms.size());
		for (final OWLAxiom owlAxiom : owlAxioms) {
			result.add(convert(owlAxiom));
		}
		return result;
	}

	/**
	 * One-parameter, public, non-static methods called "convert" and declared
	 * in this class specify mapping between {@link OWLObject} subclasses
	 * (parameter) and {@link ElkObject} subclasses (return type). This method
	 * returns a subclass of {@link ElkObject} to which the subclass of
	 * {@link OWLObject} specified as the parameter is mapped, or {@code null}
	 * if it is not mapped.
	 *
	 * @param owlClass
	 * @return
	 */
	public static Class<? extends ElkObject> convertType(
			final Class<?> owlClass) {

		if (!OWLObject.class.isAssignableFrom(owlClass)) {
			return null;
		}

		for (final Method declaredMethod : OwlConverter.class
				.getDeclaredMethods()) {

			final int mod = declaredMethod.getModifiers();
			final Class<?>[] parameterTypes = declaredMethod
					.getParameterTypes();
			final Class<?> returnType = declaredMethod.getReturnType();
			if ("convert".equals(declaredMethod.getName())
					&& Modifier.isPublic(mod) && !Modifier.isStatic(mod)
					&& parameterTypes.length == 1
					&& parameterTypes[0].equals(owlClass)
					&& ElkObject.class.isAssignableFrom(returnType)) {
				return returnType.asSubclass(ElkObject.class);
			}

		}

		return null;
	}

}


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

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

/**
 * A collection of static methods for {@link RuleVisitor}s.
 *
 * @author "Yevgeny Kazakov"
 *
 */
public class RuleVisitors {

	private static RuleVisitor<Boolean> LOCALITY_CHECKER_ = new RuleTracingCheckingVisitor();

	/**
	 * @param visitor
	 * @return A {@link RuleVisitor} that delegates the calls to the provided
	 *         {@link RuleVisitor} when for the {@link Rule} which accepts this
	 *         visitor, {@link Rule#isTracingRule()} returns {@code true}. Otherwise
	 *         the {@link RuleVisitor} returns {@code null}.
	 *
	 * @see Rule#isTracingRule()
	 */
	public static <O> RuleVisitor<O> getTracingVisitor(RuleVisitor<O> visitor) {
		return new ConditionalRuleVisitor<O>(visitor, LOCALITY_CHECKER_);
	}

	/**
	 * @param visitor
	 *            the {@link SubsumerDecompositionVisitor} used to execute the
	 *            methods
	 * @param counter
	 *            the {@link RuleCounter} used to count the number of method
	 *            invocations
	 * @return a new {@link RuleVisitor} that delegates all methods to the given
	 *         {@link RuleVisitor} and counts the number of invocations of the
	 *         corresponding methods using the given {@link RuleCounter}.
	 */
	public static <O> RuleVisitor<O> getCountingVisitor(RuleVisitor<O> visitor,
			RuleCounter counter) {
		return new RuleCounterVisitor<O>(visitor, counter);
	}

	/**
	 * @param visitor
	 *            the {@link SubsumerDecompositionVisitor} used to execute the
	 *            methods
	 * @param timer
	 *            the {@link RuleApplicationTimer} used to mesure the time spent
	 *            within the methods
	 *
	 * @return a new {@link SubsumerDecompositionVisitor} that executes the
	 *         corresponding methods of the given
	 *         {@link SubsumerDecompositionVisitor} and measures the time spent
	 *         within the corresponding methods using the given
	 *         {@link RuleApplicationTimer}.
	 */
	public static <O> RuleVisitor<O> getTimedVisitor(RuleVisitor<O> visitor,
			RuleApplicationTimer timer) {
		return new RuleApplicationTimerVisitor<O>(visitor, timer);
	}
}


/*
 * #%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.saturation.rules.factories;

import org.semanticweb.elk.ModifiableReference;
import org.semanticweb.elk.reasoner.saturation.context.Context;
import org.semanticweb.elk.reasoner.saturation.inferences.ClassInference;
import org.semanticweb.elk.util.concurrent.computation.DelegateInterruptMonitor;
import org.semanticweb.elk.util.concurrent.computation.InputProcessor;
import org.semanticweb.elk.util.concurrent.computation.InterruptMonitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * An engine to concurrently processing pending {@link ClassInference}s within
 * the corresponding {@link Context}s using a supplied
 * {@link ClassInference.Visitor}. The {@link ClassInference}s are retrieved
 * by {@link Context#takeToDo()}.
 *
 * @author "Yevgeny Kazakov"
 *
 */
public abstract class AbstractRuleEngine<I extends RuleApplicationInput>
		extends DelegateInterruptMonitor
		implements
			InputProcessor<I> {

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

	/**
	 * A reference to the current {@link Context} processed by the worker
	 */
	private final ModifiableReference<Context> activeContext_;

	/**
	 * Specifies how {@link ClassInference}s in the {@link Context} should be
	 * processed
	 */
	private final ClassInference.Visitor<?> inferenceProcessor_;

	/**
	 * Accumulates the produced {@link ClassInference}s that should be
	 * processed within the same {@link Context} in which they were produced;
	 * this should always be emptied before continuing to the next
	 * {@link Context}
	 */
	private final WorkerLocalTodo workerLocalTodo_;

	public AbstractRuleEngine(
			ModifiableReference<Context> activeContext,
			ClassInference.Visitor<?> inferenceProcessor,
			WorkerLocalTodo localizedProducer, InterruptMonitor interrupter) {
		super(interrupter);
		this.activeContext_ = activeContext;
		this.inferenceProcessor_ = inferenceProcessor;
		this.workerLocalTodo_ = localizedProducer;
	}

	@Override
	public void process() throws InterruptedException {
		try {
			for (;;) {
				if (isInterrupted()) {
					LOGGER_.trace("Rule application interrupted");

					break;
				}
				Context nextContext = getNextActiveContext();
				if (nextContext == null) {
					break;
				}
				process(nextContext);
			}
		} finally {
			workerLocalTodo_.deactivate();
		}
	}

	/**
	 * Process all pending {@link ClassInference}s of the given {@link Context}
	 *
	 * @param context
	 *            the active {@link Context} with unprocessed
	 *            {@link ClassInference}s
	 */
	void process(Context context) {
		activeContext_.set(context);
		// at this point workerLocalTodo_ must be empty
		workerLocalTodo_.setActiveRoot(context.getRoot());
		for (;;) {
			ClassInference inference = workerLocalTodo_.poll();
			if (inference == null) {
				inference = context.takeToDo();
				if (inference == null)
					return;
			}
			LOGGER_.trace("{}: processing inference {}", context, inference);
			inference.accept(inferenceProcessor_);
		}
	}

	/**
	 * Removes and returns the next active {@link Context} that has unprocessed
	 * {@link ClassInference}s.
	 *
	 * @return the next active {@link Context} to be processed by this
	 *         {@link BasicRuleEngine}
	 */
	abstract protected Context getNextActiveContext();

}