/**
* SPINdle (version 2.2.2)
* Copyright (C) 2009-2012 NICTA Ltd.
*
* This file is part of SPINdle project.
*
* SPINdle is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SPINdle is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SPINdle. If not, see <http://www.gnu.org/licenses/>.
*
* @author H.-P. Lam (oleklam@gmail.com), National ICT Australia - Queensland Research Laboratory
*/
package spindle.core;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Map.Entry;
import java.util.logging.Level;
import com.app.utils.FileManager;
import com.app.utils.Utilities.ProcessStatus;
import spindle.core.dom.Conclusion;
import spindle.core.dom.ConclusionType;
import spindle.core.dom.Literal;
import spindle.core.dom.Theory;
import spindle.engine.ReasoningEngine;
import spindle.engine.ReasoningEngineFactory;
import spindle.engine.ReasoningEngineFactoryException;
import spindle.engine.ReasoningEngineListener;
import spindle.engine.TheoryNormalizer;
import spindle.engine.TheoryNormalizerListener;
import spindle.io.IOManager;
import spindle.io.OutputterException;
import spindle.io.outputter.XmlTheoryOutputter2;
import spindle.sys.AppConst;
import spindle.sys.AppFeatureConst;
import spindle.sys.AppLogger;
import spindle.sys.AppModuleBase;
import spindle.sys.AppModuleListener;
import spindle.sys.Conf;
import spindle.sys.Messages;
import spindle.sys.message.ErrorMessage;
import spindle.sys.message.SystemMessage;
import spindle.tools.evaluator.LiteralVariablesEvaluator;
import spindle.tools.evaluator.LiteralVariablesEvaluatorException;
import spindle.tools.evaluator.LiteralVariablesEvaluatorListener;
import spindle.tools.explanation.InferenceLogger;
/**
* Base class for SPINdle reasoner.
*
* @author H.-P. Lam (oleklam@gmail.com), National ICT Australia - Queensland Research Laboratory
* @since version 1.0.0
* @version Last modified 2012.07.21
*/
public abstract class ReasonerBase extends AppModuleBase //
implements AppLogger, LiteralVariablesEvaluatorListener, TheoryNormalizerListener, ReasoningEngineListener {
protected static String LINE_SEPARATOR = FileManager.LINE_SEPARATOR;
private LiteralVariablesEvaluator literalVariableEvaluator = null;
private TheoryNormalizer theoryNormalizer = null;
private ReasoningEngine reasoningEngine = null;
protected Theory origTheory = null;
protected Theory workingTheory = null;
protected Map<Literal, Map<ConclusionType, Conclusion>> conclusions = null;
protected List<Conclusion> conclusionsAsList = null;
protected Map<ConclusionType, Set<Literal>> inapplicableLiteralsBeforeInference = null;
protected InferenceLogger inferenceLogger = null;
private boolean isTheoryChanged = false;
public ReasonerBase() {
super();
if (!Conf.isInitialized()) {
System.out.println(ReasonerUtilities.getAppStartMessage());
Conf.initializeApplicationContext(null);
}
}
public ProcessStatus loadTheory(final Theory theory) throws ReasonerException {
if (null == theory) throw new ReasonerException(ErrorMessage.THEORY_NULL_THEORY);
if (theory.isEmpty()) throw new ReasonerException(ErrorMessage.THEORY_EMPTY_THEORY);
clear();
try {
origTheory = theory;
workingTheory = origTheory.clone();
isTheoryChanged = true;
conclusions = null;
fireOnReasonerMessage(MessageType.INFO, Messages.getSystemMessage(
SystemMessage.REASONER_THEORY_LOADED_SUCCESSFULLY, new Object[] { workingTheory.getTheoryType()
.name() }));
if (Conf.isShowProgress()) fireOnReasonerMessage(MessageType.INFO, "Theory read:\n", workingTheory);
return ProcessStatus.SUCCESS;
} catch (Exception e) {
clear();
throw new ReasonerException(e);
}
}
protected LiteralVariablesEvaluator getLiteralVariablesEvaluator() throws ReasonerException {
if (null == workingTheory) throw new ReasonerException(ErrorMessage.THEORY_NULL_THEORY);
if (null == literalVariableEvaluator) {
literalVariableEvaluator = ReasoningEngineFactory.getLiteralVariablesEvaluator();
literalVariableEvaluator.addLiteralVariablesEvaluatorListener(this);
literalVariableEvaluator.setAppLogger(this);
}
return literalVariableEvaluator;
}
/**
* get the theory normalizer according to the theory type
*
* @return theory normalizer
* @throws ReasonerException
* throw when theory is null or theory type is not defined
*/
protected TheoryNormalizer getTheoryNormalizer() throws ReasonerException {
if (null == workingTheory) throw new ReasonerException(ErrorMessage.THEORY_NULL_THEORY);
if (isTheoryChanged) {
if (null != theoryNormalizer) theoryNormalizer.removeTheoryNormalizerListener(this);
theoryNormalizer = null;
}
if (null == theoryNormalizer) {
try {
theoryNormalizer = ReasoningEngineFactory.getTheoryNormalizer(workingTheory.getTheoryType());
theoryNormalizer.addTheoryNormalizerListener(this);
theoryNormalizer.setAppLogger(this);
} catch (ReasoningEngineFactoryException e) {
fireOnReasonerMessage(MessageType.ERROR, e.getMessage());
throw new ReasonerException("getTheoryNormalizer exception", e);
}
isTheoryChanged = false;
}
theoryNormalizer.setTheory(workingTheory);
return theoryNormalizer;
}
/**
* Get the reasoning engine according to the theory type.
*
* @return an instance of reasoner
* @throws ReasonerException
*/
protected ReasoningEngine getReasoningEngine() throws ReasonerException {
if (null == workingTheory) throw new ReasonerException(ErrorMessage.THEORY_NULL_THEORY);
if (isTheoryChanged) {
if (null != reasoningEngine) reasoningEngine.removeReasoningEngineListener(this);
reasoningEngine = null;
}
if (null == reasoningEngine) {
try {
reasoningEngine = ReasoningEngineFactory.getReasoningEngine(workingTheory);
reasoningEngine.addReasoningEngineListener(this);
reasoningEngine.setAppLogger(this);
} catch (ReasoningEngineFactoryException e) {
fireOnReasonerMessage(MessageType.ERROR, e.getMessage());
throw new ReasonerException(e);
}
isTheoryChanged = false;
}
return reasoningEngine;
}
public ProcessStatus transformTheoryToRegularForm() throws ReasonerException {
if (workingTheory.getLiteralVariableCount() > 0 || workingTheory.getLiteralBooleanFunctionCount() > 0) {
fireOnReasonerMessage(MessageType.INFO, "remove literal variables in theory");
try {
workingTheory = getLiteralVariablesEvaluator().evaluateLiteralVariables(workingTheory);
if (Conf.isShowProgress()) fireOnReasonerMessage(MessageType.INFO, null, workingTheory);
} catch (LiteralVariablesEvaluatorException e) {
fireOnReasonerMessage(MessageType.ERROR, e.getMessage());
throw new ReasonerException(
"Literal variables evaluator exception throw while evaluating literal variable", e);
}
onLogMessage(Level.INFO, "=== literal variables removal:", workingTheory);
} else {
fireOnReasonerMessage(MessageType.INFO,
Messages.getSystemMessage(SystemMessage.THEORY_CONTAINS_NO_LITERAL_VARIABLES));
}
return doTransformTheoryToRegularForm();
}
/**
* set the conclusions and extract only conclusion with non-place holder literals
*
* @param tempConclusions
* @return Process status
* @throws ReasonerException
*/
protected ProcessStatus setConclusions(Map<Literal, Map<ConclusionType, Conclusion>> tempConclusions)
throws ReasonerException {
if (null == tempConclusions || tempConclusions.size() == 0) throw new ReasonerException(
ErrorMessage.CONCLUSION_NULL_CONCLUSIONS_SET);
conclusions = new TreeMap<Literal, Map<ConclusionType, Conclusion>>();
Set<Conclusion> tempConclusionList = new TreeSet<Conclusion>();
for (Entry<Literal, Map<ConclusionType, Conclusion>> entry : tempConclusions.entrySet()) {
Literal literal = entry.getKey();
if (!literal.isPlaceHolder()) {
conclusions.put(literal, entry.getValue());
for (Conclusion conclusion : entry.getValue().values()) {
tempConclusionList.add(conclusion);
}
}
}
conclusionsAsList = new ArrayList<Conclusion>(tempConclusionList);
return ProcessStatus.SUCCESS;
}
public List<Conclusion> getConclusionsAsList() throws ReasonerException {
fireOnReasonerMessage(MessageType.INFO, Messages.getSystemMessage(SystemMessage.REASONER_GET_CONCLUSION_AS_SET));
if (null == conclusions) getConclusions();
return conclusionsAsList;
}
public String getConclusionsAsXmlString() throws ReasonerException {
try {
return XmlTheoryOutputter2.getConclusionsAsXmlString(getConclusionsAsList());
} catch (OutputterException e) {
fireOnReasonerMessage(MessageType.ERROR, e.getMessage());
throw new ReasonerException("Exception throw while executing getConclusionsAsXmlString()", e);
}
}
public ProcessStatus saveTheoryAs(final File filename) throws ReasonerException {
if (null == workingTheory) throw new ReasonerException(ErrorMessage.THEORY_NULL_THEORY);
if (workingTheory.isEmpty()) throw new ReasonerException(ErrorMessage.THEORY_EMPTY_THEORY);
String msg = Messages.getSystemMessage(SystemMessage.IO_SAVE_THEORY, new Object[] { filename });
fireOnReasonerMessage(MessageType.INFO, msg);
onLogMessage(Level.INFO, msg);
try {
return IOManager.save(filename, workingTheory, this);
} catch (OutputterException e) {
fireOnReasonerMessage(MessageType.ERROR, e.getMessage());
throw new ReasonerException(Messages.getErrorMessage(ErrorMessage.IO_OUTPUTTER_THEORY_SAVE_EXCEPTION,
new Object[] { filename }), e);
}
}
public ProcessStatus saveConclusions(final File filename) throws ReasonerException {
if (null == conclusionsAsList || conclusionsAsList.size() == 0) throw new ReasonerException(
ErrorMessage.CONCLUSION_NULL_CONCLUSIONS_SET);
String filenameStr = filename.toString();
String msg = Messages.getSystemMessage(SystemMessage.IO_SAVE_CONCLUSIONS, new Object[] { filenameStr });
fireOnReasonerMessage(MessageType.INFO, msg);
onLogMessage(Level.INFO, msg);
try {
return IOManager.save(filename, conclusionsAsList, this);
} catch (OutputterException e) {
fireOnReasonerMessage(MessageType.ERROR, e.getMessage());
throw new ReasonerException("Theory exception throw while saving conclusions to [" + filenameStr + "]", e);
}
}
public Theory getTheory() {
return workingTheory;
}
public Theory getOriginalTheory() {
return origTheory;
}
public void printConclusions() {
if (null == conclusions || conclusions.size() == 0) {
fireOnReasonerMessage(MessageType.WARNING,
Messages.getErrorMessage(ErrorMessage.CONCLUSION_NULL_CONCLUSIONS_SET));
return;
}
StringBuilder sb = new StringBuilder();
sb.append(Messages.getSystemMessage(SystemMessage.REASONER_CONCLUSIONS_GENERATED));
if (AppFeatureConst.isPrintConclusionByType) {
List<Conclusion> cLst = conclusionsAsList;
for (Conclusion c : cLst) {
sb.append(LINE_SEPARATOR).append(AppConst.IDENTATOR).append(c.toString());
}
} else {
for (Entry<Literal, Map<ConclusionType, Conclusion>> entry : conclusions.entrySet()) {
sb.append(LINE_SEPARATOR).append(AppConst.IDENTATOR).append("literal [").append(entry.getKey())
.append("]");
for (Conclusion conclusion : entry.getValue().values()) {
sb.append(LINE_SEPARATOR).append(AppConst.IDENTATOR).append(conclusion.toString());
}
}
}
onLogMessage(Level.INFO, sb.toString());
fireOnReasonerMessage(MessageType.INFO, sb.toString());
}
public void onLogMessage(Level logLevel, String message, Object... objects) {
onLogMessage(logLevel, 0, message, objects);
}
@Override
public void onLogMessage(Level logLevel, int indentLevel, String message, Object... objects) {
logMessage(logLevel, indentLevel, message, objects);
}
@Override
public void onReasoningEngineMessage(MessageType messageType, String message) {
fireOnReasonerMessage(messageType, message);
}
public Map<ConclusionType, Set<Literal>> getInapplicableLiteralsBeforeInference() {
return inapplicableLiteralsBeforeInference;
}
@Override
public void setInapplicableLiteralsBeforeInference(
Map<ConclusionType, Set<Literal>> inapplicableLiteralsBeforeInference) {
this.inapplicableLiteralsBeforeInference = inapplicableLiteralsBeforeInference;
}
public InferenceLogger getInferenceLogger() {
return inferenceLogger;
}
@Override
public void setInferenceLogger(InferenceLogger inferenceLogger) {
this.inferenceLogger = inferenceLogger;
}
@Override
public void onTheoryNormalizerMessage(MessageType messageType, String message) {
fireOnReasonerMessage(messageType, message);
}
@Override
public void onLiteralVariablesEvaluatorMesage(MessageType messageType, String message) {
fireOnReasonerMessage(messageType, message);
}
protected ProcessStatus clear() {
if (null != origTheory) {
origTheory.clear();
origTheory = null;
}
if (null != workingTheory) {
workingTheory.clear();
workingTheory = null;
}
theoryNormalizer = null;
reasoningEngine = null;
isTheoryChanged = false;
return ProcessStatus.SUCCESS;
}
public Map<Literal, Map<ConclusionType, Conclusion>> generateConclusionsWithTransformations()
throws ReasonerException {
if (conclusions == null) {
transformTheoryToRegularForm();
if (workingTheory.getDefeatersCount() > 0) removeDefeater();
switch (Conf.getReasonerVersion()) {
case 1:
if (workingTheory.getSuperiorityCount() > 0) removeSuperiority();
break;
default:
}
getConclusions();
}
if (Conf.isShowResult() || Conf.isShowProgress()) printConclusions();
return conclusions;
}
// =========================
// Reasoner Listener - start
// =========================
public void addReasonerMessageListener(ReasonerMessageListener listener) {
addAppModuleListener(listener);
}
public void removeReasonerMessageListener(ReasonerMessageListener listener) {
removeAppModuleListener(listener);
}
protected void fireOnReasonerMessage(final MessageType messageType, final String message, Object... objects) {
for (AppModuleListener listener : getAppModuleListeners()) {
if (listener instanceof ReasonerMessageListener) {
((ReasonerMessageListener) listener).onReasonerMessage(messageType, message, objects);
}
}
}
// =======================
// Reasoner Listener - end
// =======================
protected abstract ProcessStatus doTransformTheoryToRegularForm() throws ReasonerException;
public abstract ProcessStatus removeDefeater() throws ReasonerException;
public abstract ProcessStatus removeSuperiority() throws ReasonerException;
public abstract Map<Literal, Map<ConclusionType, Conclusion>> getConclusions() throws ReasonerException;
}