/**
* 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.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import com.app.utils.Utilities;
import spindle.core.dom.DomUtilities;
import spindle.core.dom.Literal;
import spindle.core.dom.Mode;
import spindle.core.dom.Rule;
import spindle.core.dom.RuleException;
import spindle.core.dom.RuleType;
import spindle.engine.TheoryNormalizer;
import spindle.engine.TheoryNormalizerException;
import spindle.sys.AppConst;
import spindle.sys.message.ErrorMessage;
/**
* MDL Theory Normalizer.
* <p>
* Provides methods that can be used to transform a defeasible theory into an equivalent theory without superiority
* relation or defeater using the algorithms described in:
* <ul>
* <li>G. Antoniou, D. Billington, G. Governatori and M.J. Maher (2001) Representation Results for Defeasible Logic,
* <i>ACM Transactions on Computational Logic</i>, Vol. 2 (2), pp. 255-287</li>
* </ul>
* </p>
* <p>
* Rule/literal modal conversions and conflict resolutions are based on description presented in:
* <ul>
* <li>G. Governatori and A. Rotolo (2008) BIO Logical Agents: Norms, Beliefs, Intentions in Defeasible Logic,
* <i>Journal of Autonomous Agents and Multi Agent Systems</i>, Vol. 17 (1), pp. 36--69</li>
* </ul>
* </p>
*
* @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 class MdlTheoryNormalizer extends TheoryNormalizer {
Map<String, Set<String>> ruleModesConversionsRules = null;
public MdlTheoryNormalizer() {
super();
}
/**
* expand defeasible rule with head more than one literal
*
* <pre>
* e.g. a => b,c
* will becomes
* a => b
* a, -b => c
* </pre>
*
* @param rule
* original defeasible rule
* @return list of expanded rules
* @throws RuleException
*/
protected List<Rule> expandDefeasibleRule(final Rule rule) throws RuleException {
if (rule.getRuleType() != RuleType.DEFEASIBLE) return null;
String originalRuleLabel = rule.getOriginalLabel();
List<Rule> newRules = new ArrayList<Rule>();
List<Literal> headLiterals = rule.getHeadLiterals();
try {
if (headLiterals.size() < 2) {
Rule newRule = rule.clone();
newRules.add(newRule);
} else {
List<Literal> bodyLiterals = rule.getBodyLiterals();
Literal lastLiteral = null;
int count = 1;
Mode ruleMode = rule.getMode();
for (Literal literal : headLiterals) {
if (null == lastLiteral) {
} else {
Literal lc = lastLiteral.getComplementClone();
bodyLiterals.add(lc);
}
String newRuleLabel = rule.getLabel() + "_" + count;
Rule newRule = DomUtilities.getRule(newRuleLabel, RuleType.DEFEASIBLE);
newRule.setOriginalLabel(originalRuleLabel);
newRule.setMode(ruleMode);
addBodyLiterals(newRule, bodyLiterals, "");
newRule.addHeadLiteral(literal);
newRules.add(newRule);
lastLiteral = literal;
count++;
}
}
return newRules;
} catch (Exception e) {
throw new RuleException("exception throw while expanding rule [" + rule.getLabel() + "]", e);
}
}
@Override
protected void transformTheoryToRegularFormImpl() throws TheoryNormalizerException {
ruleModesConversionsRules = theory.getAllModeConversionRules();
List<Rule> rulesToAdd = new ArrayList<Rule>();
Set<String> rulesToDelete = new TreeSet<String>();
Map<String, List<Rule>> oldNewRuleMapping = new Hashtable<String, List<Rule>>();
List<Literal> headLiterals = null;
List<Literal> origHeadLiterals = null;
Rule newRule1 = null;
Rule newRule2 = null;
Rule newRule3 = null;
List<Rule> newRules = null;
try {
for (Rule rule : factsAndRules.values()) {
logMessage(Level.FINER, 1, "transforming ", rule.getRuleType().getLabel(), " [", rule.getLabel(), "]");
newRule1 = null;
newRule2 = null;
newRule3 = null;
headLiterals = null;
String originalRuleLabel = rule.getOriginalLabel();
Mode ruleMode = rule.getMode();
if ("".equals(ruleMode.getName())) ruleMode = null;
switch (rule.getRuleType()) {
case STRICT:
origHeadLiterals = rule.getHeadLiterals();
headLiterals = rule.getHeadLiterals();
String profixStr = (factsAndRules.containsKey(rule.getLabel() + TRANSFORM_POSTFIX)) ? (Utilities
.getRandomString(AppConst.LOG_FILE_ID_LENGTH) + TRANSFORM_POSTFIX) : TRANSFORM_POSTFIX;
newRule1 = DomUtilities.getRule(rule.getLabel() + profixStr, RuleType.STRICT);
newRule1.setOriginalLabel(originalRuleLabel);
if (null != ruleMode) newRule1.setMode(ruleMode);
addBodyLiterals(newRule1, rule.getBodyLiterals(), TRANSFORM_POSTFIX);
addHeadLiterals(newRule1, headLiterals, TRANSFORM_POSTFIX);
newRule2 = DomUtilities.getRule(rule.getLabel() + profixStr + TRANSFORM_POSTFIX2, RuleType.STRICT);
newRule2.setOriginalLabel(originalRuleLabel);
if (null != ruleMode) newRule2.setMode(ruleMode);
addBodyLiterals(newRule2, headLiterals, TRANSFORM_POSTFIX);
addHeadLiterals(newRule2, origHeadLiterals, "");
if (null != ruleMode) newRule2.setHeadLiteralMode(ruleMode);
// change the strict rule to defeasible rule, and
// add the two new strict rules to the theory
newRule3 = rule.clone();
newRule3.setOriginalLabel(originalRuleLabel);
newRule3.setRuleType(RuleType.DEFEASIBLE);
rulesToAdd.add(newRule1);
rulesToAdd.add(newRule2);
rulesToAdd.add(newRule3);
rulesToDelete.add(rule.getLabel());
break;
case FACT:
origHeadLiterals = rule.getHeadLiterals();
headLiterals = rule.getHeadLiterals();
String newFactStrictRuleLabel = theory.getUniqueRuleLabel(FACT_RULE_TRANSFORM_PREFIX);
newRule1 = DomUtilities.getRule(newFactStrictRuleLabel, RuleType.STRICT);
newRule1.setOriginalLabel(originalRuleLabel);
if (null != ruleMode) newRule1.setMode(ruleMode);
addHeadLiterals(newRule1, headLiterals, TRANSFORM_POSTFIX);
newRule2 = DomUtilities.getRule(newFactStrictRuleLabel + TRANSFORM_POSTFIX, RuleType.STRICT);
newRule2.setOriginalLabel(originalRuleLabel);
if (null != ruleMode) newRule2.setMode(ruleMode);
addBodyLiterals(newRule2, headLiterals, TRANSFORM_POSTFIX);
addHeadLiterals(newRule2, origHeadLiterals, "");
if (null != ruleMode) newRule2.setHeadLiteralMode(ruleMode);
// delete the fact, and
// add the two new strict rules to the theory
rulesToDelete.add(rule.getLabel());
rulesToAdd.add(newRule1);
rulesToAdd.add(newRule2);
break;
case DEFEASIBLE:
// - modification start
List<Rule> expandedModeRules = convertRuleMode(rule);
if (!AppConst.isDeploy) {
for (Rule r : expandedModeRules) {
logMessage(Level.FINEST, 2, "[", rule.getLabel(), "] expandRuleWithModeConversion: ", r);
}
}
newRules = new ArrayList<Rule>();
// expand the defeasible rule if number of head literal is greater than 1
// do nothing otherwise
for (Rule expendedRule : expandedModeRules) {
headLiterals = expendedRule.getHeadLiterals();
if (headLiterals.size() > 1) {
logMessage(Level.FINEST, 1, "expending ", expendedRule.getRuleType().getLabel(), " [", expendedRule.getLabel(),
"]");
newRules.addAll(expandDefeasibleRule(expendedRule));
} else {
logMessage(Level.FINEST, 1, "no transform performed to ", rule.getRuleType().getLabel(), " [", rule.getLabel(),
"]");
newRules.add(expendedRule);
}
}
// - modification end
// delete the old rule and
// add the expanded rules to the theory
rulesToDelete.add(rule.getLabel());
rulesToAdd.addAll(newRules);
if (newRules.size() > 1) oldNewRuleMapping.put(rule.getLabel(), newRules);
break;
default:
logMessage(Level.FINEST, 2, "no transform performed to ", rule.getRuleType().getLabel(), " [", rule.getLabel(), "]");
}
}
theory.updateTheory(rulesToAdd, rulesToDelete, oldNewRuleMapping);
} catch (Exception e) {
throw new TheoryNormalizerException(getClass(), ErrorMessage.THEORY_UPDATE_ERROR, e);
} finally {
if (!AppConst.isDeploy) {
logMessage(Level.INFO, 0, "=== transformTheoryToRegularFormImpl - start ===");
logMessage(Level.INFO, 0, theory.toString());
logMessage(Level.INFO, 0, "=== transformTheoryToRegularFormImpl - end ===");
}
}
}
private List<Rule> convertRuleMode(Rule rule) throws TheoryNormalizerException {
List<Rule> expandedRules = new ArrayList<Rule>();
Mode ruleMode = rule.getMode();
String ruleModeName = ruleMode.getName();
if ("".equals(ruleModeName) && rule.getModeUsedInHead().size() > 1) {
expandedRules.add(rule);
return expandedRules;
}
Rule modifiedRule = null;
if ("".equals(ruleModeName)) {
modifiedRule = rule;
} else {
try {
modifiedRule = DomUtilities.getRule(rule.getLabel(), rule.getRuleType());
addBodyLiterals(modifiedRule, rule.getBodyLiterals(), "");
for (Literal literal : rule.getHeadLiterals()) {
Literal l = literal.clone();
l.setMode(ruleMode);
modifiedRule.addHeadLiteral(l);
}
} catch (RuleException e) {
throw new TheoryNormalizerException(getClass(), "exception throw while converting rule mode", e);
}
}
expandedRules.add(modifiedRule);
List<Mode> modeUsedInBody = modifiedRule.getModeUsedInBody();
if (!AppConst.isDeploy) {
logMessage(Level.INFO, 0, "convertRuleMode.rule=", modifiedRule);
logMessage(Level.INFO, 1, "convertRuleMode.rule.getBodyLiterals().size()=" + modifiedRule.getBodyLiterals().size());
logMessage(Level.INFO, 1, "convertRuleMode.modeUsedInBody.size()=" + modeUsedInBody.size());
logMessage(Level.INFO, 1, "convertRuleMode.modeUsedInBody=", modeUsedInBody);
}
if (modifiedRule.getBodyLiterals().size() == 0 || modeUsedInBody.size() == 0) {
// ruleModeName= modifiedRule.getHeadLiterals().get(0).getMode().getName();
// ruleModeName =headLiteralMode.getName();
// Set<String> conversionRule = theory.getModeConversionRules(ruleModeName);
Mode headLiteralMode = modifiedRule.getHeadLiterals().get(0).getMode();
Set<String> conversionRule = theory.getModeConversionRules(headLiteralMode.getName());
if (!AppConst.isDeploy)
logMessage(Level.INFO, 1, "convertRuleMode.1, ruleModeName=", ruleModeName, ",conversionRule =", conversionRule);
if (null != conversionRule) {
for (String cm : conversionRule) {
try {
Rule newRule = modifiedRule.cloneWithModeChange(new Mode(cm, headLiteralMode.isNegation()));
newRule.setLabel(modifiedRule.getLabel() + "_[" + cm + "]");
expandedRules.add(newRule);
logMessage(Level.FINEST, 3, "newRule=", newRule);
} catch (Exception e) {
logMessage(Level.SEVERE, 0, "[ERROR] ", e.getMessage());
throw new TheoryNormalizerException(getClass(), "exception throw while converting rule mode", e);
}
}
}
} else if (modeUsedInBody.size() == 1) {
String bodyMode = (modeUsedInBody.size() == 0) ? "" : modeUsedInBody.get(0).getName();
// ruleModeName = modifiedRule.getHeadLiterals().get(0).getMode().getName();
// Set<String> conversionRule = theory.getModeConversionRules(ruleModeName);
Mode headLiteralMode = modifiedRule.getHeadLiterals().get(0).getMode();
Set<String> conversionRule = theory.getModeConflictRules(headLiteralMode.getName());
if (!AppConst.isDeploy)
logMessage(Level.INFO, 1, "convertRuleMode.2, ruleModeName=", ruleModeName, ",conversionRule =", conversionRule);
if (null != conversionRule && conversionRule.contains(bodyMode)) {
try {
Rule newRule = modifiedRule.cloneWithModeChange(new Mode(bodyMode, headLiteralMode.isNegation()));
newRule.setLabel(modifiedRule.getLabel() + "_[" + bodyMode + "]");
expandedRules.add(newRule);
logMessage(Level.FINEST, 3, "newRule=", newRule);
} catch (Exception e) {
logMessage(Level.SEVERE, 0, "[ERROR] " + e.getMessage());
throw new TheoryNormalizerException(getClass(), "exception throw while converting rule mode", e);
}
}
}
return expandedRules;
}
}