/**
* 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.engine.mdl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import spindle.core.dom.Conclusion;
import spindle.core.dom.ConclusionType;
import spindle.core.dom.Literal;
import spindle.core.dom.Mode;
import spindle.core.dom.Rule;
import spindle.core.dom.RuleType;
import spindle.engine.ReasoningEngineException;
import spindle.engine.sdl.SdlReasoningEngine2;
import spindle.sys.AppConst;
import spindle.tools.explanation.RuleInferenceStatus;
/**
* MDL Reasoning Engine (version 2).
*
* @author H.-P. Lam (oleklam@gmail.com), National ICT Australia - Queensland Research Laboratory
* @since version 1.0.0
* @version Last modified 2012.09.29
*/
public class MdlReasoningEngine2 extends SdlReasoningEngine2 {
protected Map<String, Set<String>> strongerModeSet = null;
public MdlReasoningEngine2() {
super();
}
@Override
protected void initialize() throws ReasoningEngineException {
strongerModeSet = theory.getStrongModeSet();
super.initialize();
}
protected Set<Literal> getConflictLiteralListWithoutOperatorChange(final Literal literal) {
System.out.println("-- MdlReasoningEngine2.getConflictLiteralListWithoutOperatorChange("+literal+")");
Set<Literal> conflictLiteralList = new TreeSet<Literal>();
conflictLiteralList.add(literal.getComplementClone());
Mode literalMode = literal.getMode();
if (!"".equals(literalMode.getName())) {
Literal conflictLiteral = literal.clone();
conflictLiteral.setMode(literalMode.getComplementClone());
conflictLiteralList.add(conflictLiteral);
}
return conflictLiteralList;
}
// remove ambiguity caused by complementary literal
protected void removeComplementaryLiteralAmbiguity(int i) throws ReasoningEngineException {
System.out.println("-- MdlReasoningEngine2.removeComplementLiteralAmbiguity("+i+")");
logMessage(Level.FINE, 1, "=== removeComplementLiteralAmbiguity - start ===");
List<Conclusion> ambiguousConclusionsToRemove = new ArrayList<Conclusion>();
removeComplementaryLiteralAmbiguity(ambiguousConclusions[i],ambiguousConclusionsToRemove);
for (Conclusion conclusion : ambiguousConclusionsToRemove) {
removeAmbiguousConclusion(conclusion);
}
// TODO remove record??
logMessage(Level.FINE, 1, "=== removeComplementLiteralAmbiguity - end ===");
}
protected void removeComplementaryLiteralAmbiguity(Map<Conclusion,Set<String>>ambiguousConclusions,List<Conclusion>ambiguousConclusionsToRemove){
for (Entry<Conclusion,Set<String>>entry:ambiguousConclusions.entrySet()){
Conclusion conclusion=entry.getKey();
Set<String>ruleLabels=entry.getValue();
Literal literal=conclusion.getLiteral();
Set<Literal>conflictLiterals=getConflictLiteralListWithoutOperatorChange(literal);
switch (conclusion.getConclusionType()) {
case DEFINITE_PROVABLE:
logMessage(Level.FINEST, 2, "removeComplementLiteralAmbiguity, check literal (definite): ", literal);
if (!containsUnprovedRuleInTheory(conflictLiterals, RuleType.STRICT)) {
if (isAmbiguousConclusionExist(conflictLiterals, ConclusionType.DEFINITE_PROVABLE)) {
ambiguousConclusionsToRemove.add(conclusion);
if (isLogInferenceProcess) getInferenceLogger().updateRuleInferenceStatus(ruleLabels,
RuleType.STRICT, ConclusionType.DEFINITE_NOT_PROVABLE, literal,
RuleInferenceStatus.DEFEATED);
newLiteralFind_definiteNotProvable(literal, true);
}
}
break;
case DEFEASIBLY_PROVABLE:
logMessage(Level.FINEST, 2, "removeComplementLiteralAmbiguity, check literal (defeasible): ", literal);
if (!containsUnprovedRuleInTheory(conflictLiterals, RuleType.DEFEASIBLE)) {
if (isAmbiguousConclusionExist(conflictLiterals, ConclusionType.DEFEASIBLY_PROVABLE)) {
ambiguousConclusionsToRemove.add(conclusion);
if (isLogInferenceProcess) getInferenceLogger().updateRuleInferenceStatus(ruleLabels,
RuleType.DEFEASIBLE, ConclusionType.DEFEASIBLY_NOT_PROVABLE, literal,
RuleInferenceStatus.DEFEATED);
newLiteralFind_defeasiblyNotProvable(literal, true);
}
}
break;
default:
}
}
}
@Override
protected void updateAmbiguousConclusions(int i) throws ReasoningEngineException {
System.out.println("-- MdlReasoningEngine2.updateAmbiguousConclusions(" + i + ")");
if (ambiguousConclusions[i].size() == 0) return;
logMessage(Level.FINE, 0, "-- MdlReasoningEngine2.updateAmbiguousConclusions - start, i=", i);
if (!AppConst.isDeploy) printEngineStatus("updateAmbiguousConclusions-before");
// remove ambiguity due to complementary literals
removeComplementaryLiteralAmbiguity(i);
List<Conclusion> ambiguousConclusionToRemove = new ArrayList<Conclusion>();
List<Conclusion> recordsToRemove = new ArrayList<Conclusion>();
RuleType ruleType = null;
ConclusionType negativeConclusionType = null;
for (Entry<Conclusion, Set<String>> entry : ambiguousConclusions[i].entrySet()) {
Conclusion conclusion = entry.getKey();
Set<String> ruleLabels = entry.getValue();
Literal literal = conclusion.getLiteral();
ConclusionType conclusionType = conclusion.getConclusionType();
switch (conclusionType) {
case DEFINITE_PROVABLE:
ruleType = RuleType.STRICT;
negativeConclusionType = ConclusionType.DEFINITE_NOT_PROVABLE;
break;
case DEFEASIBLY_PROVABLE:
ruleType = RuleType.DEFEASIBLE;
negativeConclusionType = ConclusionType.DEFEASIBLY_NOT_PROVABLE;
break;
default:
}
Set<Rule> rulesWithLiteralAsHead = theory.getRulesWithHead(literal);
boolean keepLiteralInAmbiguousSet = false;
for (Rule r : rulesWithLiteralAsHead) {
if (!ruleType.equals(r.getRuleType())) continue;
for (Literal bodyLiteral : r.getBodyLiterals()) {
if (bodyLiteral.isPlaceHolder()) keepLiteralInAmbiguousSet = true;
}
}
Set<Literal> conflictLiterals = getConflictLiterals(literal);
boolean conflictLiteralInSccGroup = false;
for (Literal conflictLiteral : conflictLiterals) {
if (null != getSccGroup(conflictLiteral)) conflictLiteralInSccGroup = true;
}
boolean chk = isRecordExist(conflictLiterals, conclusionType);
if (keepLiteralInAmbiguousSet) {
// defer the removal of literal until all rules generated
// by the superiority removal process have been evaluated
logMessage(Level.FINER, 2, "keep literal in ambiguous set temporary");
conclusionType = null;
} else if (!containsUnprovedRuleInTheory(conflictLiterals, ruleType)) {
ambiguousConclusionToRemove.add(conclusion);
if (chk) {
// mdl modification - start
// remove ambiguity based on modal operator strength
conclusionType = evaluateAmbiguousConclusionsByModality(literal, conclusionType, conflictLiterals);
if (conclusionType.isPositiveConclusion()) {
// literal with strongest modal operator find
// positive conclusion => conclusion type unchanged
if (isLogInferenceProcess)
getInferenceLogger().updateRuleInferenceStatus(ruleLabels, conclusion, RuleInferenceStatus.APPICABLE);
} else {
// literal is not with strongest modal operator
// defeated conclusion => remove record from the records set
recordsToRemove.add(conclusion);
if (isLogInferenceProcess)
getInferenceLogger().updateRuleInferenceStatus(ruleLabels, ruleType, negativeConclusionType, literal,
RuleInferenceStatus.DEFEATED);
}
// mdl modification - end
} else {
if (isLogInferenceProcess)
getInferenceLogger().updateRuleInferenceStatus(ruleLabels, conclusion, RuleInferenceStatus.APPICABLE);
// literal with no ambiguous conclusion find
// positive conclusion => conclusion type unchanged
}
} else if (conflictLiteralInSccGroup && chk) {
ambiguousConclusionToRemove.add(conclusion);
recordsToRemove.add(conclusion);
if (isLogInferenceProcess)
getInferenceLogger().updateRuleInferenceStatus(ruleLabels, conclusion, RuleInferenceStatus.DISCARDED);
// literal with conflict that appear in the SCC set
// negative conclusion => change conclusion type to negative
conclusionType = negativeConclusionType;
}
if (null == conclusionType) continue;
// generate new conclusion based on the conclusion type derived above
generateConclusionsWithLiteral(conclusionType, literal, true);
// ============ commented on 2012.12.12 - start
// switch (conclusion.getConclusionType()) {
// case DEFINITE_PROVABLE:
// logMessage(Level.FINER, 1, "updateAmbiguousConclusion [MDL], check literal (definite): ", literal);
// for (Rule r:rulesWithLiteralAsHead){
// if (!RuleType.STRICT.equals(r.getRuleType()))continue;
// for (Literal bodyLiteral:r.getBodyLiterals()){
// if (bodyLiteral.isPlaceHolder())keepLiteralInAmbiguousSet=true;
// }
// }
//
// boolean chk2 = isRecordExist(conflictLiterals, ConclusionType.DEFINITE_PROVABLE);
//
// if (keepLiteralInAmbiguousSet){
// // defer the removal of literal until all rules generated
// // by the superiority removal process have been evaluated
// logMessage(Level.FINER, 2, "keep literal in ambiguous set temporary");
// } else if (!containsUnprovedRuleInTheory(conflictLiterals, RuleType.STRICT)) {
// if (chk2) {
// ambiguousConclusionToRemove.add(conclusion);
//
// int conflictLiteralExistCount = 0;
// int strongModeCount = 0;
// for (Literal conflictLiteral : conflictLiterals) {
// if (isRecordExist(conflictLiteral, ConclusionType.DEFINITE_PROVABLE)) {
// conflictLiteralExistCount++;
// if (hasStrongerMode(literal, conflictLiteral)) {
// logMessage(Level.FINEST, 2, null, literal, " hasStrongerMode: ", conflictLiteral);
// strongModeCount++;
// }
// }
// }
//
// // only conclusion with strongest modal operator is concluded
// if (strongModeCount == conflictLiteralExistCount) {
// if (isLogInferenceProcess) getInferenceLogger().updateRuleInferenceStatus(ruleLabels,
// conclusion, RuleInferenceStatus.APPICABLE);
// newLiteralFind_definiteProvable(literal,true);
// } else {
// recordsToRemove.add(conclusion);
// if (isLogInferenceProcess) getInferenceLogger().updateRuleInferenceStatus(ruleLabels,RuleType.STRICT,
// ConclusionType.DEFINITE_NOT_PROVABLE,literal, RuleInferenceStatus.DEFEATED);
// newLiteralFind_definiteNotProvable(literal,true);
// }
// } else {
// if (isLogInferenceProcess) getInferenceLogger().updateRuleInferenceStatus(ruleLabels,
// conclusion, RuleInferenceStatus.APPICABLE);
// newLiteralFind_definiteProvable(literal,true);
// }
// } else if (conflictLiteralInSccGroup && chk2){
// ambiguousConclusionToRemove.add(conclusion);
// recordsToRemove.add(conclusion);
// if (isLogInferenceProcess) getInferenceLogger().updateRuleInferenceStatus(ruleLabels,
// conclusion, RuleInferenceStatus.DISCARDED);
// newLiteralFind_defeasiblyNotProvable(literal,true);
// }
// break;
// case DEFEASIBLY_PROVABLE:
// logMessage(Level.FINER, 1, "updateAmbiguousConclusion [MDL], check literal (defeasible): ", literal);
// for (Rule r:rulesWithLiteralAsHead){
// if (!RuleType.DEFEASIBLE.equals(r.getRuleType()))continue;
// for (Literal bodyLiteral:r.getBodyLiterals()){
// if (bodyLiteral.isPlaceHolder())keepLiteralInAmbiguousSet=true;
// }
// }
// boolean dchk2 = isRecordExist(conflictLiterals, ConclusionType.DEFEASIBLY_PROVABLE);
//
// if (keepLiteralInAmbiguousSet){
// // defer the removal of literal until all rules generated
// // by the superiority removal process have been evaluated
// logMessage(Level.FINER, 2, "keep literal in ambiguous set temporary");
// } else if (!containsUnprovedRuleInTheory(conflictLiterals, RuleType.DEFEASIBLE)) {
// ambiguousConclusionToRemove.add(conclusion);
// if (dchk2) {
// int conflictLiteralExistCount = 0;
// int strongModeCount = 0;
// for (Literal conflictLiteral : conflictLiterals) {
// if (isRecordExist(conflictLiteral, ConclusionType.DEFEASIBLY_PROVABLE)) {
// conflictLiteralExistCount++;
// if (hasStrongerMode(literal, conflictLiteral)) {
// logMessage(Level.FINEST, 2, null, literal, " hasStrongerMode: ", conflictLiteral);
// strongModeCount++;
// }
// }
// }
//
// // only conclusion with strongest modal operator is concluded
// if (strongModeCount == conflictLiteralExistCount) {
// if (isLogInferenceProcess) getInferenceLogger().updateRuleInferenceStatus(ruleLabels,
// conclusion, RuleInferenceStatus.APPICABLE);
// newLiteralFind_defeasiblyProvable(literal,true);
// } else {
// recordsToRemove.add(conclusion);
// if (isLogInferenceProcess) getInferenceLogger().updateRuleInferenceStatus(ruleLabels,RuleType.DEFEASIBLE,
// ConclusionType.DEFEASIBLY_NOT_PROVABLE,literal, RuleInferenceStatus.DEFEATED);
// newLiteralFind_defeasiblyNotProvable(literal,true);
// }
// } else {
// if (isLogInferenceProcess) getInferenceLogger().updateRuleInferenceStatus(ruleLabels,
// conclusion, RuleInferenceStatus.APPICABLE);
// newLiteralFind_defeasiblyProvable(literal,true);
// }
// } else if (conflictLiteralInSccGroup && dchk2){
// ambiguousConclusionToRemove.add(conclusion);
// recordsToRemove.add(conclusion);
// if (isLogInferenceProcess) getInferenceLogger().updateRuleInferenceStatus(ruleLabels,
// conclusion, RuleInferenceStatus.DISCARDED);
// newLiteralFind_defeasiblyNotProvable(literal,true);
// }
// break;
// default:
// }
// ============ commented on 2012.12.12 - end
}
for (Conclusion conclusion : ambiguousConclusionToRemove) {
ambiguousConclusions[i].remove(conclusion);
}
for (Conclusion record : recordsToRemove) {
removeRecord(record);
}
if (!AppConst.isDeploy) printEngineStatus("updateAmbiguousConclusions-after");
logMessage(Level.FINE, 0, "-- MdlReasoningEngine2.updateAmbiguousConclusions - end, i=", i);
}
protected ConclusionType evaluateAmbiguousConclusionsByModality(Literal literal, ConclusionType conclusionType, //
Collection<Literal> conflictLiterals) throws ReasoningEngineException {
// no need to perform literal modal operators comparisons if the conclusion type is already negative
if (conclusionType.isNegativeConclusion()) return conclusionType;
// count the number of conflict modal literals that appear in the records
// and the number of literals weaker than the prescribed literal
int conflictLiteralExistCount = 0;
int strongModeCount = 0;
for (Literal conflictLiteral : conflictLiterals) {
if (isRecordExist(conflictLiteral, conclusionType)) {
conflictLiteralExistCount++;
if (hasStrongerMode(literal, conflictLiteral)) {
logMessage(Level.FINEST, 2, null, literal, " hasStrongerMode: ", conflictLiteral);
strongModeCount++;
}
}
}
// only conclusion with strongest modality is positively concluded
if (strongModeCount == conflictLiteralExistCount) {
// literal with strongest modal operator find
// positive conclusion => conclusion type unchanged
return conclusionType;
} else {
// literal does not with strongest modality
// defeated conclusion => change conclusion type to negative
switch (conclusionType) {
case DEFINITE_PROVABLE:
return ConclusionType.DEFINITE_NOT_PROVABLE;
case DEFEASIBLY_PROVABLE:
return ConclusionType.DEFEASIBLY_NOT_PROVABLE;
default:
throw new ReasoningEngineException(getClass(), "unknown conclusion type: " + conclusionType);
}
}
}
protected boolean hasStrongerMode(Literal literal, Literal conflictLiteral) {
//System.out.println("-- MdlReasoningEngine2.hasStrongerMode("+literal+","+conflictLiteral+")");
Mode m1 = literal.getMode();
Mode m2 = conflictLiteral.getMode();
if (m1.getName().equals(m2.getName())) return false;
Set<String> modeList = strongerModeSet.get(m1.getName());
if (null == modeList) return false;
String m2ModeName = m2.getName();
if (modeList.contains(m2ModeName)) return true;
return false;
}
}