org.semanticweb.elk.reasoner.saturation.AbstractSaturationState 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
package org.semanticweb.elk.reasoner.saturation;
/*
* #%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%
*/
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import org.semanticweb.elk.reasoner.indexing.model.IndexedContextRoot;
import org.semanticweb.elk.reasoner.indexing.model.OntologyIndex;
import org.semanticweb.elk.reasoner.saturation.conclusions.classes.DummyClassConclusionVisitor;
import org.semanticweb.elk.reasoner.saturation.conclusions.classes.SaturationClassConclusionChecker;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.ClassConclusion;
import org.semanticweb.elk.reasoner.saturation.conclusions.model.ContextInitialization;
import org.semanticweb.elk.reasoner.saturation.context.Context;
import org.semanticweb.elk.reasoner.saturation.inferences.ClassInference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A skeleton to simplify implementation of {@link SaturationState}s
*
* @author "Yevgeny Kazakov"
*
* @param
* the type of contexts maintained by this {@link SaturationState}
*/
public abstract class AbstractSaturationState
implements SaturationState {
// logger for events
private static final Logger LOGGER_ = LoggerFactory
.getLogger(AbstractSaturationState.class);
final OntologyIndex ontologyIndex;
/**
* The queue containing all activated contexts (whose todo queue is not
* empty). Every activated context occurs exactly once.
*/
private final Queue activeContexts_ = new ConcurrentLinkedQueue();
/**
* The queue containing all {@link Context}s of this {@link SaturationState}
* that are not saturated, i.e., for which {@link Context#isSaturated()}
* returns {@code false}. Each non-saturated context occurs exactly once.
*/
private final Queue notSaturatedContexts_ = new ConcurrentLinkedQueue();
/**
* increments before a {@link Context} is marked as non-saturated
*/
private final AtomicInteger contextSetNonSaturatedUpper_ = new AtomicInteger(
0);
/**
* increments after a {@link Context} is marked as non-saturated
*/
private final AtomicInteger contextSetNonSaturatedLower_ = new AtomicInteger(
0);
/**
* increments before a {@link Context} is marked as saturated
*/
private final AtomicInteger contextSetSaturatedUpper_ = new AtomicInteger(
0);
/**
* increments after a {@link Context} is marked as saturated
*/
private final AtomicInteger contextSetSaturatedLower_ = new AtomicInteger(
0);
private final ContextFactory contextFactory;
private final List> listeners_ = new ArrayList<>();
public AbstractSaturationState(OntologyIndex index,
ContextFactory factory) {
this.ontologyIndex = index;
this.contextFactory = factory;
}
@Override
public OntologyIndex getOntologyIndex() {
return ontologyIndex;
}
@Override
public Collection getNotSaturatedContexts() {
return Collections.unmodifiableCollection(new AbstractCollection() {
@Override
public Iterator iterator() {
return notSaturatedContexts_.iterator();
}
@Override
public int size() {
int nonSaturatedLower = contextSetNonSaturatedLower_.get();
int nonSaturatedUpper = contextSetNonSaturatedUpper_.get();
if (nonSaturatedLower != nonSaturatedUpper) {
LOGGER_.error("Some context are being marked non-saturated!");
}
int setSaturatedLower = contextSetSaturatedLower_.get();
int setSaturatedUpper = contextSetSaturatedUpper_.get();
if (setSaturatedLower != setSaturatedUpper) {
LOGGER_.error("Some context are being marked saturated!");
}
return nonSaturatedLower - setSaturatedUpper;
}
});
}
@Override
public int getContextMarkNonSaturatedCount() {
return contextSetNonSaturatedLower_.get();
}
@Override
public int getContextSetSaturatedCount() {
return contextSetSaturatedLower_.get();
}
@Override
public void setContextsSaturated(int saturatedContextLimit) {
for (;;) {
int contextSetSaturatedUpperSnapshot = contextSetSaturatedUpper_
.get();
if (contextSetSaturatedUpperSnapshot >= saturatedContextLimit) {
return;
}
if (contextSetSaturatedUpperSnapshot >= contextSetNonSaturatedLower_
.get()) {
int contextSetSaturatedLowerSnapshot = contextSetSaturatedLower_
.get();
EC next = notSaturatedContexts_.peek();
if (next != null
&& contextSetSaturatedLowerSnapshot >= contextSetNonSaturatedUpper_
.get()) {
LOGGER_.error("{}: was not marked as saturated", next);
}
return;
}
if (!contextSetSaturatedUpper_.compareAndSet(
contextSetSaturatedUpperSnapshot,
contextSetSaturatedUpperSnapshot + 1)) {
continue;
}
EC next = notSaturatedContexts_.poll();
if (next.setSaturated(true)) {
LOGGER_.error("{}: was marked as saturated already", next);
}
contextSetSaturatedLower_.incrementAndGet();
LOGGER_.trace("{}: marked as saturated", next);
notifyContextMarkedSaturated(next);
}
}
@Override
public SaturationStateWriter getContextModifyingWriter(
ContextModificationListener contextModificationListener) {
return new ContextModifyingWriter(contextModificationListener);
}
@Override
public SaturationStateWriter getContextModifyingWriter() {
return getContextModifyingWriter(ContextModificationListener.DUMMY);
}
@Override
public ContextCreatingSaturationStateWriter getContextCreatingWriter(
ContextCreationListener contextCreationListener,
ContextModificationListener contextModificationListener) {
return new ContextCreatingWriter(contextCreationListener,
contextModificationListener);
}
@Override
public ContextCreatingSaturationStateWriter getContextCreatingWriter() {
return getContextCreatingWriter(ContextCreationListener.DUMMY,
ContextModificationListener.DUMMY);
}
@Override
public boolean addListener(SaturationState.ChangeListener super EC> listener) {
return listeners_.add(listener);
}
@Override
public boolean removeListener(SaturationState.ChangeListener super EC> listener) {
return listeners_.remove(listener);
}
@Override
abstract public EC getContext(IndexedContextRoot root);
void notifyContextsClear() {
for (int i = 0; i < listeners_.size(); i++) {
listeners_.get(i).contextsClear();
}
}
void notifyContextAddition(EC context) {
for (int i = 0; i < listeners_.size(); i++) {
listeners_.get(i).contextAddition(context);
}
}
void notifyContextMarkedSaturated(EC context) {
for (int i = 0; i < listeners_.size(); i++) {
listeners_.get(i).contextMarkedSaturated(context);
}
}
void notifyContextMarkedNonSaturated(EC context) {
for (int i = 0; i < listeners_.size(); i++) {
listeners_.get(i).contextMarkedNonSaturated(context);
}
}
void notifySaturatedContextModified(EC context) {
for (int i = 0; i < listeners_.size(); i++) {
listeners_.get(i).saturatedContextModified(context);
}
}
abstract void resetContexts();
private void reset() {
resetContexts();
activeContexts_.clear();
notSaturatedContexts_.clear();
}
/**
* Adds the given {@link ExtendedContext} to this {@link SaturationState} if
* no {@link ExtendedContext} was assigned for its root
*
* @param context
* the {@link ExtendedContext} to be added to this
* {@link SaturationState}
* @return the {@link ExtendedContext} in this {@link SaturationState} that
* was assigned to the same root, or {@link null} if no such
* {@link Context} existed before this method is called
*
* @see ExtendedContext#getRoot()
*/
abstract EC setIfAbsent(EC context);
/**
*
*
*/
class ContextModifyingWriter implements SaturationStateWriter {
private final ContextModificationListener contextModificationListener_;
private ContextModifyingWriter(
ContextModificationListener contextSaturationListener) {
this.contextModificationListener_ = contextSaturationListener;
}
@Override
public Context pollForActiveContext() {
return activeContexts_.poll();
}
void produce(Context context, ClassInference inference) {
LOGGER_.trace("{}: new inference {}", context, inference);
if (context.addToDo(inference)) {
LOGGER_.trace("{}: activated", context);
// context was activated
activeContexts_.add(context);
}
}
@Override
public void produce(ClassInference inference) {
// TODO: what if NPE?
produce(getContext(inference.getDestination()), inference);
}
void addNotSaturated(EC context) {
contextSetNonSaturatedUpper_.incrementAndGet();
LOGGER_.trace("{}: marked as non-saturated", context);
notSaturatedContexts_.add(context);
contextSetNonSaturatedLower_.incrementAndGet();
contextModificationListener_.notifyContextModification(context);
notifyContextMarkedNonSaturated(context);
}
boolean markAsNotSaturated(EC context) {
if (context.setSaturated(false)) {
addNotSaturated(context);
return true;
}
// else
return false;
}
boolean markAsNotSaturated(IndexedContextRoot root) {
EC context = getContext(root);
return context == null ? false : markAsNotSaturated(context);
}
@Override
public void resetContexts() {
AbstractSaturationState.this.reset();
}
@Override
public SaturationState getSaturationState() {
return AbstractSaturationState.this;
}
@Override
public boolean addConclusion(ClassConclusion conclusion) {
EC context = getContext(conclusion.getDestination());
return conclusion
.accept(new DummyClassConclusionVisitor() {
@Override
protected Boolean defaultVisit(ClassConclusion c) {
return addConclusion(context, c);
}
@Override
public Boolean visit(ContextInitialization c) {
if (context.containsConclusion(c)) {
return false;
}
// Mark context as non-saturated before we
// insert, otherwise the context could be found
// initialized and non-saturated
markAsNotSaturated(context);
return addConclusion(context, c);
}
});
}
boolean addConclusion(EC context, ClassConclusion conclusion) {
if (!context.addConclusion(conclusion)) {
LOGGER_.trace("{}: inserting {}: already present", context,
conclusion);
return false;
}
// else
LOGGER_.trace("{}: inserting {}: success", context, conclusion);
checkSaturationFor(conclusion);
return true;
}
@Override
public boolean removeConclusion(ClassConclusion conclusion) {
EC context = getContext(conclusion.getDestination());
if (!context.removeConclusion(conclusion)) {
LOGGER_.trace("{}: deleting {}: already absent", context,
conclusion);
return false;
}
// else
LOGGER_.trace("{}: deleting {}: success", context, conclusion);
checkSaturationFor(conclusion);
return true;
}
/**
* Checks if adding or removing the given conclusion can make some
* context non-saturated.
*
* @param conclusion
*/
void checkSaturationFor(ClassConclusion conclusion) {
EC origin = getContext(conclusion.getTraceRoot());
if (!origin.isSaturated()) {
return;
}
if (SaturationClassConclusionChecker.check(conclusion)) {
markAsNotSaturated(origin);
} else {
notifySaturatedContextModified(origin);
}
}
}
/**
* @author Pavel Klinov
*
* [email protected]
* @author "Yevgeny Kazakov"
*/
protected class ContextCreatingWriter extends ContextModifyingWriter
implements ContextCreatingSaturationStateWriter {
private final ContextCreationListener contextCreationListener_;
protected ContextCreatingWriter(
ContextCreationListener contextCreationListener,
ContextModificationListener contextModificationListener) {
super(contextModificationListener);
this.contextCreationListener_ = contextCreationListener;
}
protected ContextCreatingWriter() {
super(ContextModificationListener.DUMMY);
this.contextCreationListener_ = ContextCreationListener.DUMMY;
}
@Override
public void produce(ClassInference inference) {
produce(getCreateContext(inference.getDestination()), inference);
}
@Override
public EC getCreateContext(IndexedContextRoot root) {
EC previous = getContext(root);
if (previous != null) {
return previous;
}
// else try to assign a new context
EC newContext = contextFactory.createContext(root);
previous = setIfAbsent(newContext);
if (previous != null) {
// the context is already assigned meanwhile
return previous;
}
// markAsNotSaturatedInternal(newContext);
contextCreationListener_.notifyContextCreation(newContext);
LOGGER_.trace("{}: context created", newContext);
return newContext;
}
}
}