org.semanticweb.elk.reasoner.incremental.ContextInitializationFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elk-reasoner Show documentation
Show all versions of elk-reasoner Show documentation
The core ELK Reasoner package
/*
* #%L
* ELK Reasoner
* $Id:$
* $HeadURL:$
* %%
* Copyright (C) 2011 - 2014 Department of Computer Science, University of Oxford
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.semanticweb.elk.reasoner.incremental;
import java.util.ArrayList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import org.semanticweb.elk.owl.interfaces.ElkAxiom;
import org.semanticweb.elk.reasoner.indexing.model.IndexedClassExpression;
import org.semanticweb.elk.reasoner.indexing.model.IndexedDefinedClass;
import org.semanticweb.elk.reasoner.saturation.SaturationState;
import org.semanticweb.elk.reasoner.saturation.SaturationStateWriter;
import org.semanticweb.elk.reasoner.saturation.SaturationStatistics;
import org.semanticweb.elk.reasoner.saturation.SaturationUtils;
import org.semanticweb.elk.reasoner.saturation.conclusions.classes.SaturationConclusionBaseFactory;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.ContextInitialization;
import org.semanticweb.elk.reasoner.saturation.context.Context;
import org.semanticweb.elk.reasoner.saturation.rules.RuleVisitor;
import org.semanticweb.elk.reasoner.saturation.rules.contextinit.LinkedContextInitRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.IndexedClassDecompositionRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.LinkedSubsumerRule;
import org.semanticweb.elk.reasoner.saturation.rules.subsumers.SubsumerDecompositionRule;
import org.semanticweb.elk.util.concurrent.computation.DelegateInterruptMonitor;
import org.semanticweb.elk.util.concurrent.computation.InputProcessor;
import org.semanticweb.elk.util.concurrent.computation.InputProcessorFactory;
import org.semanticweb.elk.util.concurrent.computation.InputProcessorListenerNotifyFinishedJob;
import org.semanticweb.elk.util.concurrent.computation.InterruptMonitor;
import org.semanticweb.elk.util.logging.CachedTimeThread;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Pavel Klinov
*
* [email protected]
* @author Peter Skocovsky
*/
class ContextInitializationFactory extends DelegateInterruptMonitor
implements
InputProcessorFactory, InputProcessor>> {
private static final Logger LOGGER_ = LoggerFactory
.getLogger(ContextInitializationFactory.class);
/**
* The buffer for jobs that need to be processed, i.e., those for which the
* method {@link BaseInputProcessor#submit(ArrayList)} was executed but
* processing of jobs has not been started yet.
*/
private final Queue> jobsToDo_ = new ConcurrentLinkedQueue>();
private final SaturationState> saturationState_;
private final ContextInitialization.Factory contextInitFactory_;
private final IndexedClassExpression[] changedComposedSubsumers_;
private final IndexedDefinedClass[] changedDecomposedSubsumers_;
private final LinkedContextInitRule changedContextInitRuleHead_;
private final Map extends IndexedClassExpression, ? extends LinkedSubsumerRule> changedCompositionRules_;
private AtomicInteger compositionRuleHits_ = new AtomicInteger(0);
private AtomicInteger decompositionRuleHits_ = new AtomicInteger(0);
private final SaturationStatistics stageStatistics_;
private final SubsumerDecompositionRule classDecomposition_;
public ContextInitializationFactory(final InterruptMonitor interrupter,
SaturationState> state,
LinkedContextInitRule changedContextInitRuleHead,
Map extends IndexedClassExpression, ? extends LinkedSubsumerRule> changedCompositionRules,
final Map extends IndexedDefinedClass, ? extends IndexedClassExpression> changedDefinitions,
final Map extends IndexedDefinedClass, ? extends ElkAxiom> changedDefinitionReasons,
SaturationStatistics stageStats) {
super(interrupter);
saturationState_ = state;
contextInitFactory_ = new SaturationConclusionBaseFactory();
changedCompositionRules_ = changedCompositionRules;
changedComposedSubsumers_ = new IndexedClassExpression[changedCompositionRules
.keySet().size()];
changedCompositionRules.keySet().toArray(changedComposedSubsumers_);
changedDecomposedSubsumers_ = new IndexedDefinedClass[changedDefinitions
.keySet().size()];
changedDefinitions.keySet().toArray(changedDecomposedSubsumers_);
changedContextInitRuleHead_ = changedContextInitRuleHead;
stageStatistics_ = stageStats;
classDecomposition_ = new IndexedClassDecompositionRule() {
private final Map extends IndexedDefinedClass, ? extends IndexedClassExpression> changedDefinitions_ = changedDefinitions;
private final Map extends IndexedDefinedClass, ? extends ElkAxiom> changedDefinitionReasons_ = changedDefinitionReasons;
@Override
protected IndexedClassExpression getDefinition(
IndexedDefinedClass premise) {
return changedDefinitions_.get(premise);
}
@Override
protected ElkAxiom getDefinitionReason(IndexedDefinedClass premise) {
return changedDefinitionReasons_.get(premise);
}
};
}
@Override
public InputProcessor> getEngine() {
return getEngine(getBaseContextProcessor());
}
private ContextProcessor getBaseContextProcessor() {
final SaturationStatistics localStatistics = new SaturationStatistics();
final RuleVisitor> ruleAppVisitor = SaturationUtils
.getStatsAwareRuleVisitor(localStatistics.getRuleStatistics());
final SaturationStateWriter> saturationStateWriter = saturationState_
.getContextModifyingWriter();
localStatistics.getConclusionStatistics().startMeasurements();
return new ContextProcessor() {
private int localCompsitionRuleHits_ = 0;
private int localDecompositionRuleHits_ = 0;
@Override
public void process(Context context) {
// apply all changed context initialization rules
ContextInitialization contextInit = contextInitFactory_
.getContextInitialization(context.getRoot());
LinkedContextInitRule nextContextInitRule = changedContextInitRuleHead_;
while (nextContextInitRule != null) {
LOGGER_.trace("{}: applying rule {}", context,
nextContextInitRule);
nextContextInitRule.accept(ruleAppVisitor, contextInit, context,
saturationStateWriter);
nextContextInitRule = nextContextInitRule.next();
}
// apply all changed composition rules for composed subsumers
Set composedSubsumers = context
.getComposedSubsumers();
if (composedSubsumers
.size() > changedComposedSubsumers_.length >> 2) {
// iterate over changes, check subsumers
for (int j = 0; j < changedComposedSubsumers_.length; j++) {
IndexedClassExpression changedICE = changedComposedSubsumers_[j];
if (composedSubsumers.contains(changedICE)) {
applyCompositionRules(context, changedICE);
}
}
} else {
// iterate over subsumers, check changes
for (IndexedClassExpression changedICE : composedSubsumers) {
applyCompositionRules(context, changedICE);
}
}
// apply all definition expansion rules for decomposed subsumers
Set decomposedSubsumers = context
.getDecomposedSubsumers();
if (decomposedSubsumers
.size() > changedDecomposedSubsumers_.length >> 2) {
// iterate over changes, check subsumers
for (int j = 0; j < changedDecomposedSubsumers_.length; j++) {
IndexedDefinedClass changedIC = changedDecomposedSubsumers_[j];
if (decomposedSubsumers.contains(changedIC)) {
applyDecompositionRules(context, changedIC);
}
}
} else {
// iterate over subsumers, check changes
for (IndexedClassExpression changedICE : decomposedSubsumers) {
if (changedICE instanceof IndexedDefinedClass)
applyDecompositionRules(context,
(IndexedDefinedClass) changedICE);
}
}
}
@Override
public void finish() {
stageStatistics_.add(localStatistics);
compositionRuleHits_.addAndGet(localCompsitionRuleHits_);
decompositionRuleHits_.addAndGet(localDecompositionRuleHits_);
}
private void applyCompositionRules(Context context,
IndexedClassExpression changedICE) {
LinkedSubsumerRule nextLocalRule = changedCompositionRules_
.get(changedICE);
if (nextLocalRule != null) {
localCompsitionRuleHits_++;
LOGGER_.trace("{}: applying composition rules for {}",
context, changedICE);
}
while (nextLocalRule != null) {
nextLocalRule.accept(ruleAppVisitor, changedICE, context,
saturationStateWriter);
nextLocalRule = nextLocalRule.next();
}
}
private void applyDecompositionRules(Context context,
IndexedDefinedClass changedICE) {
localDecompositionRuleHits_++;
LOGGER_.trace("{}: applying decomposition rules for {}",
context, changedICE);
classDecomposition_.accept(ruleAppVisitor, changedICE, context,
saturationStateWriter);
}
};
}
private InputProcessor> getEngine(
final ContextProcessor baseProcessor) {
if (SaturationUtils.COLLECT_PROCESSING_TIMES) {
return new TimedContextCollectionProcessor(baseProcessor,
stageStatistics_.getIncrementalProcessingStatistics(),
this);
}
// else
return new ContextCollectionProcessor(baseProcessor);
}
@Override
public void finish() {
if (LOGGER_.isDebugEnabled()) {
LOGGER_.debug(
"Composition rule hits: " + compositionRuleHits_.get());
LOGGER_.debug(
"Decomposition rule hits: " + decompositionRuleHits_.get());
}
}
/**
* Implements basic job queueing and lets subclasses focus on processing
* single jobs
*
* @author Pavel Klinov
*
* [email protected]
* @author Peter Skocovsky
*/
private abstract class BaseInputProcessor
implements InputProcessor> {
private final InputProcessorListenerNotifyFinishedJob> listener_;
public BaseInputProcessor() {
this(null);
}
public BaseInputProcessor(
final InputProcessorListenerNotifyFinishedJob> listener) {
listener_ = listener;
}
@Override
public void submit(ArrayList job) {
jobsToDo_.add(job);
}
@Override
public void process() throws InterruptedException {
for (;;) {
if (isInterrupted()) {
break;
}
ArrayList nextJob = jobsToDo_.poll();
if (nextJob == null) {
break;
}
process(nextJob);
if (listener_ != null) {
listener_.notifyFinished(nextJob);
}
}
}
@Override
public void finish() {
// no-op
}
protected abstract boolean isInterrupted();
protected abstract void process(ArrayList job);
}
/**
* @author Pavel Klinov
*
* [email protected]
*/
private class TimedContextCollectionProcessor extends BaseInputProcessor {
private final ContextProcessor contextProcessor_;
private final IncrementalProcessingStatistics stageStats_;
private final IncrementalProcessingStatistics localStats_ = new IncrementalProcessingStatistics();
private final InterruptMonitor interrupter_;
private int procNumber_ = 0;
public TimedContextCollectionProcessor(ContextProcessor baseProcessor,
IncrementalProcessingStatistics stageStats,
InterruptMonitor interrupter) {
contextProcessor_ = new TimedContextProcessor(baseProcessor,
localStats_);
stageStats_ = stageStats;
interrupter_ = interrupter;
localStats_.startMeasurements();
}
@Override
protected void process(ArrayList contexts) {
long ts = CachedTimeThread.getCurrentTimeMillis();
int contextCount = 0;
int subsumerCount = 0;
procNumber_++;
for (Context context : contexts) {
contextProcessor_.process(context);
contextCount++;
subsumerCount += context.getComposedSubsumers().size();
}
localStats_.changeInitContextCollectionProcessingTime += (CachedTimeThread
.getCurrentTimeMillis() - ts);
localStats_.countContexts += contextCount;
if (contextCount > 0) {
localStats_.countContextSubsumers += (subsumerCount
/ contextCount);
}
}
@Override
public void finish() {
super.finish();
contextProcessor_.finish();
if (procNumber_ > 0) {
localStats_.countContextSubsumers /= procNumber_;
}
stageStats_.add(localStats_);
}
@Override
protected boolean isInterrupted() {
return interrupter_.isInterrupted();
}
}
/**
*
* @author Pavel Klinov
*
* [email protected]
*/
private class ContextCollectionProcessor extends BaseInputProcessor {
private final ContextProcessor contextProcessor_;
ContextCollectionProcessor(ContextProcessor contextProcessor) {
contextProcessor_ = contextProcessor;
}
@Override
protected void process(ArrayList contexts) {
for (Context context : contexts) {
contextProcessor_.process(context);
}
}
@Override
public void finish() {
super.finish();
contextProcessor_.finish();
}
@Override
protected boolean isInterrupted() {
return ContextInitializationFactory.this.isInterrupted();
}
}
/**
*
* @author Pavel Klinov
*
* [email protected]
*/
static interface ContextProcessor {
public void process(Context context);
public void finish();
}
/**
* Measures time it takes to init changes for a context
*
* @author Pavel Klinov
*
* [email protected]
*/
static class TimedContextProcessor implements ContextProcessor {
private final IncrementalProcessingStatistics localStats_;
private final ContextProcessor processor_;
TimedContextProcessor(ContextProcessor p,
IncrementalProcessingStatistics localStats) {
processor_ = p;
localStats_ = localStats;
localStats_.startMeasurements();
}
@Override
public void process(Context context) {
long ts = CachedTimeThread.getCurrentTimeMillis();
processor_.process(context);
localStats_.changeInitContextProcessingTime += (CachedTimeThread
.getCurrentTimeMillis() - ts);
}
@Override
public void finish() {
processor_.finish();
// no need to add the local stats to the stage-level stats, as it's
// done by the caller
}
}
}