RuleBase.java

package libai.fuzzy;

import libai.common.Pair;
import libai.fuzzy.operators.activation.ActivationMethod;
import libai.fuzzy.operators.AndMethod;
import libai.fuzzy.operators.Operator;
import libai.fuzzy.operators.OrMethod;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.*;

/**
 * Created by kronenthaler on 30/04/2017.
 */
public class RuleBase implements XMLSerializer {

    private String name;
    private ActivationMethod activationMethod = ActivationMethod.MIN; // implication method
    private Operator andMethod = AndMethod.MIN; //operator to be used as default (mostly for systems that edit the files)
    private Operator orMethod = OrMethod.MAX; //operator to be used as default (mostly for systems that edit the files)
    private List<Rule> rules = new ArrayList<>();

    public RuleBase(Node xmlNode) {
        load(xmlNode);
    }

    public RuleBase(String name, Rule... rules) {
        this.name = name;
        this.rules = Arrays.asList(rules);
    }

    public RuleBase(String name, ActivationMethod activationMethod, Rule... rules) {
        this(name, rules);
        this.activationMethod = activationMethod;
    }

    public RuleBase(String name, ActivationMethod activationMethod, Operator andMethod, Operator orMethod, Rule... rules) {
        this(name, activationMethod, rules);
        this.andMethod = andMethod;
        this.orMethod = orMethod;
    }

    @Override
    public String toXMLString(String indent) {
        StringBuilder str = new StringBuilder();
        str.append(String.format("%s<RuleBase name=\"%s\" type=\"mamdani\" activationMethod=\"%s\" andMethod=\"%s\" orMethod=\"%s\">%n", indent, getName(), activationMethod, andMethod, orMethod));
        for (Rule r : rules) {
            str.append(String.format("%s%n", r.toXMLString(indent + "\t")));
        }
        str.append(String.format("%s</RuleBase>", indent));
        return str.toString();
    }

    @Override
    public void load(Node xmlNode) {
        //throw unsupported exception if type is not mamdani
        NamedNodeMap attributes = xmlNode.getAttributes();
        name = attributes.getNamedItem("name").getTextContent();
        String type = attributes.getNamedItem("type").getTextContent();
        if ("tsk".equalsIgnoreCase(type)) {
            throw new UnsupportedOperationException("TSK is not supported yet");
        }

        if (attributes.getNamedItem("activationMethod") != null) {
            activationMethod = ActivationMethod.fromString(attributes.getNamedItem("activationMethod").getTextContent());
        }

        if (attributes.getNamedItem("andMethod") != null) {
            andMethod = AndMethod.fromString(attributes.getNamedItem("andMethod").getTextContent());
        }

        if (attributes.getNamedItem("orMethod") != null) {
            orMethod = OrMethod.fromString(attributes.getNamedItem("orMethod").getTextContent());
        }

        NodeList children = ((Element) xmlNode).getElementsByTagName("Rule");
        for (int i = 0; i < children.getLength(); i++) {
            rules.add(new Rule(children.item(i)));
        }
    }

    public Map<String, Double> fire(Map<String, Double> variables, KnowledgeBase knowledgeBase, double delta) {
        Map<String, List<Pair<Double, Clause>>> outputVariables = new HashMap<>();

        for (Rule r : rules) {
            double tau = r.getActivationValue(variables, knowledgeBase);

            for (Clause clause : r.getConsequentClauses()) {
                String variableName = clause.getVariableName();
                if (outputVariables.get(variableName) == null) {
                    outputVariables.put(variableName, new ArrayList<>());
                }
                outputVariables.get(variableName).add(new Pair<>(tau, clause));
            }
        }

        Map<String, Double> result = new HashMap<>();
        for (String variableName : outputVariables.keySet()) {
            FuzzyVariable variable = knowledgeBase.getVariable(variableName);
            double value = variable.defuzzify(activationMethod, knowledgeBase, delta, outputVariables.get(variableName));
            result.put(variableName, value);
        }

        return result;
    }

    public String getName() {
        return name;
    }
}