/** * 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.dom; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import spindle.sys.AppFeatureConst; import spindle.sys.message.ErrorMessage; /** * DOM for representing a rule in theory. * * @author H.-P. Lam (oleklam@gmail.com), National ICT Australia - Queensland Research Laboratory * @version Last modified 2012.08.09 */ public class Rule implements Comparable<Object>, Cloneable, Serializable { private static final long serialVersionUID = 1L; protected String label; protected String originalLabel; protected RuleType ruleType; protected Mode mode; protected Temporal temporal; protected Set<Literal> body = null; protected List<Literal> head = null; public Rule(final String label, final RuleType ruleType) { this.label = label.trim(); this.originalLabel = this.label; setRuleType(ruleType); body = new TreeSet<Literal>(); head = new ArrayList<Literal>(); setMode(null); setTemporal(null); } public Rule(Rule rule) { this(rule.label, rule.ruleType); setMode(rule.mode); setTemporal(rule.temporal); try { for (spindle.core.dom.Literal literal : rule.getBodyLiterals()) { addBodyLiteral(literal.clone()); } for (spindle.core.dom.Literal literal : rule.getHeadLiterals()) { addHeadLiteral(literal.clone()); } } catch (Exception e) { } } public void setHeadLiteralMode(final Mode headLiteralMode) { for (Literal literal : head) { literal.setMode(headLiteralMode.clone()); } } public void addHeadLiteral(final Literal literal) throws RuleException { // addHeadLiteral(literal,true); // } // public void addHeadLiteral(final Literal literal,boolean checkLiteralVariable) throws RuleException { if (null == literal || "".equals(literal.getName())) throw new RuleException(ErrorMessage.LITERAL_NAME_MISSING); if ((ruleType != RuleType.DEFEASIBLE) && head.size() > 0) { // only defeasible rule is allowed to have // more than one head literal throw new RuleException(ErrorMessage.RULE_NON_DEFEASIBLE_RULE_WITH_MULTIPLE_HEADS, new Object[] { label }); } else if (literal instanceof LiteralVariable) { throw new RuleException(ErrorMessage.RULE_THEORY_VARIABLE_IN_HEAD, new Object[] { literal }); } else { head.add(literal); } } public void removeHeadLiteral(final Literal literal) { for (int i = 0; i < head.size(); i++) { if (head.get(i).equals(literal)) { head.remove(i); return; } } } public boolean isHeadLiteral(final Literal literal) { return head.contains(literal); } public List<Literal> getHeadLiterals() { List<Literal> literalList = new ArrayList<Literal>(); for (Literal literal : head) { literalList.add(literal.clone()); } return literalList; } public void addBodyLiteral(final Literal literal) throws RuleException { if (null == literal || "".equals(literal.getName())) throw new RuleException(ErrorMessage.LITERAL_NAME_MISSING); body.add(literal); } public void removeBodyLiteral(final Literal literal) { body.remove(literal); } public boolean isBodyLiteral(final Literal literal) { return body.contains(literal); } public List<Literal> getBodyLiterals() { List<Literal> literalList = new ArrayList<Literal>(); if (AppFeatureConst.isCloneRuleBodyLiterals) { for (Literal bodyLiteral : body) { literalList.add(bodyLiteral.clone()); } } else { for (Literal bodyLiteral : body) { literalList.add(bodyLiteral); } } return literalList; } public boolean isEmptyBody() { return body.size() == 0; } public String getLabel() { return label; } public void setLabel(final String label) { this.label = label.trim(); } public String getOriginalLabel() { return originalLabel; } public void setOriginalLabel(String originalLabel) { this.originalLabel = originalLabel.trim(); } public Mode getMode() { return mode; } public void setMode(final Mode mode) { this.mode = (mode == null) ? new Mode("", false) : mode.clone(); } public Temporal getTemporal() { return temporal; } public void setTemporal(Temporal temporal) { if (null == temporal || !temporal.hasTemporalInfo()) this.temporal = null; else this.temporal = temporal.clone(); } private boolean isLiteralsContainsTemporalInfo() { for (Literal literal : head) { if (literal.hasTemporalInfo()) return true; } for (Literal literal : body) { if (literal.hasTemporalInfo()) return true; } return false; } public boolean hasTemporalInfo() { return null != temporal && temporal.hasTemporalInfo() || isLiteralsContainsTemporalInfo(); } private boolean isLiteralsContainsModalInfo() { for (Literal literal : head) { if (!"".equals(literal.getMode().getName())) return true; } for (Literal literal : body) { if (!"".equals(literal.getMode().getName())) return true; } return false; } public boolean hasModalInfo() { return !"".equals(mode.getName()) || isLiteralsContainsModalInfo(); } public RuleType getRuleType() { return ruleType; } public void setRuleType(final RuleType ruleType) { this.ruleType = ruleType; } public boolean isConflictRule(Rule rule) { List<Literal> ruleHeadLiteral = rule.getHeadLiterals(); for (Literal literal : head) { for (Literal literalX : ruleHeadLiteral) { if (literal.isComplementTo(literalX)) { return true; } } } return false; } public Set<Literal> getLiteralList() { Set<Literal> literalSet = new TreeSet<Literal>(); literalSet.addAll(getBodyLiterals()); literalSet.addAll(getHeadLiterals()); return literalSet; } public Rule clone() { Rule r = DomUtilities.getRule(label, ruleType); r.setMode(mode.clone()); try { for (Literal literal : body) { r.addBodyLiteral(literal.clone()); } for (Literal literal : head) { r.addHeadLiteral(literal.clone()); } } catch (Exception e) { } return r; } public List<Mode> getModeUsedInBody() { List<Mode> modeList = new ArrayList<Mode>(); for (Literal literal : body) { if (!"".equals(literal.getMode().getName())) { if (!modeList.contains(literal.getMode())) modeList.add(literal.getMode().clone()); } } return modeList; } public List<Mode> getModeUsedInHead() { List<Mode> modeList = new ArrayList<Mode>(); for (Literal literal : head) { if (!"".equals(literal.getMode().getName())) { if (!modeList.contains(literal.getMode())) modeList.add(literal.getMode().clone()); } } return modeList; } public Rule cloneWithModeChange(final Mode toMode) throws RuleException { if ("".equals(toMode)) throw new RuleException("invalid mode [" + toMode + "] to convert"); boolean isModified = false; Rule newRule = clone(); List<Mode> modeUsedInBody = getModeUsedInBody(); if (modeUsedInBody.size() == 0) { } else { for (Literal literal : newRule.body) { if (!toMode.equals(literal.getMode())) throw new RuleModeConversionException("inconsistent mode found in rule body"); } } if (!toMode.equals(newRule.getMode())) { newRule.setMode(mode.clone()); isModified = true; } for (Literal literal : newRule.head) { if (!"".equals(literal.getMode().toString()) && !toMode.equals(literal.getMode())) { literal.setMode(toMode.clone()); isModified = true; } } if (!isModified) throw new RuleModeConversionException("no mode is modified"); return newRule; } public void updateLiteralPredicatesValues(Map<String, String> predicateValues) { if (body.size() > 0) { for (Literal literal : body) { literal.updatePredicatesValues(predicateValues); } } if (head.size() > 0) { for (Literal literal : head) { literal.updatePredicatesValues(predicateValues); } } } public Rule cloneWithUpdatePredicatesValues(Map<String, String> predicateValues) { Rule r = DomUtilities.getRule(label, ruleType); r.setMode(mode.clone()); try { for (Literal literal : body) r.body.add(literal.cloneWithUpdatePredicatesValues(predicateValues)); for (Literal literal : head) r.addHeadLiteral(literal.cloneWithUpdatePredicatesValues(predicateValues)); } catch (Exception e) { } return r; } public String getRuleAsString() { char LITERAL_SEPARATOR = DomConst.Literal.LITERAL_SEPARATOR; int c = 0; StringBuilder sb = new StringBuilder(); if (ruleType == RuleType.FACT) { // do nothing for the body part } else { if (body.size() > 0) { c = 0; for (Literal literal : body) { if (c > 0) sb.append(LITERAL_SEPARATOR); sb.append(literal.toString()); c++; } sb.append(" "); } } sb.append(ruleType.getSymbol()); if (head.size() > 0) { sb.append(" "); c = 0; for (Literal literal : head) { if (c > 0) sb.append(LITERAL_SEPARATOR); sb.append(literal.toString()); c++; } } return sb.toString(); } protected String getRuleLabelInfo() { return label + mode + (null == temporal ? "" : temporal.toString()); } public String toString() { return "[" + getRuleLabelInfo() + "]\t" + getRuleAsString(); } @Override public int compareTo(Object o) { if (this == o) return 0; if (!(o instanceof Rule)) return getClass().getName().compareTo(o.getClass().getName()); Rule r = (Rule) o; int c = mode.compareTo(r.mode); if (c != 0) return c; c = body.size() - r.body.size(); if (c != 0) return c; Iterator<Literal> it = body.iterator(); Iterator<Literal> itr = r.body.iterator(); Literal l, lr; while (it.hasNext()) { l = it.next(); lr = itr.next(); c = l.compareTo(lr); if (c != 0) return c; } c = head.size() - r.head.size(); if (c != 0) return c; for (int i = 0; i < head.size(); i++) { c = head.get(i).compareTo(r.head.get(i)); if (c != 0) return c; } return 0; } @Override public int hashCode() { return label.hashCode(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null) return false; if (!(o instanceof Rule)) return false; Rule r = (Rule) o; if (!ruleType.equals(r.ruleType)) return false; if (!mode.equals(r.mode)) return false; if (body.size() != r.body.size()) return false; if (head.size() != r.head.size()) return false; if (body.size() > 0) { for (Literal literal : body) { if (!r.body.contains(literal)) return false; } } for (int i = 0; i < head.size(); i++) { if (!head.get(i).equals(r.head.get(i))) return false; } return true; } }