FuzzyVariable.java
package libai.fuzzy;
import libai.common.Pair;
import libai.fuzzy.defuzzifiers.Defuzzifier;
import libai.fuzzy.operators.accumulation.Accumulation;
import libai.fuzzy.operators.activation.ActivationMethod;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Created by kronenthaler on 23/04/2017.
*/
public class FuzzyVariable implements XMLSerializer {
protected List<FuzzyTerm> terms; // group of fuzzy terms that this variable can take.
protected String name; //name of the linguistic variable that represents
protected double domainLeft;
protected double domainRight;
protected String scale; //label
protected Type type = Type.INPUT;
// for output variables
protected double defaultValue = 0;
protected Accumulation accumulation = Accumulation.MAX;
protected Defuzzifier defuzzifier = Defuzzifier.COG; //defuzzifier interface?
public FuzzyVariable(Node xmlNode) {
load(xmlNode);
}
public FuzzyVariable(String name, double domainLeft, double domainRight, String scale, FuzzyTerm... terms) {
this.name = name;
this.domainLeft = domainLeft;
this.domainRight = domainRight;
this.scale = scale;
this.terms = Arrays.asList(terms);
}
public FuzzyVariable(String name, double domainLeft, double domainRight, double defaultValue, String scale, Accumulation accumulation, Defuzzifier defuzzifier, FuzzyTerm... terms) {
this(name, domainLeft, domainRight, scale, terms);
this.type = Type.OUTPUT;
this.defaultValue = defaultValue;
this.accumulation = accumulation;
this.defuzzifier = defuzzifier;
}
@Override
public String toXMLString(String indent) {
StringBuilder str = new StringBuilder();
str.append(String.format("%s<FuzzyVariable name=\"%s\" domainLeft=\"%f\" domainRight=\"%f\" scale=\"%s\" type=\"%s\"", indent, name, domainLeft, domainRight, scale, type.getText()));
if (type == Type.OUTPUT) {
str.append(String.format(" defaultValue=\"%f\" defuzzifier=\"%s\" accumulation=\"%s\"", defaultValue, defuzzifier, accumulation));
}
str.append(">\n"); // close tag
for (FuzzyTerm t : terms) {
str.append(String.format("%s%n", t.toXMLString(indent + "\t")));
}
//FIXME Why are there two parameters here?
str.append(String.format("%s</FuzzyVariable>", indent, name));
return str.toString();
}
@Override
public void load(Node xmlNode) {
NamedNodeMap attributes = xmlNode.getAttributes();
name = attributes.getNamedItem("name").getTextContent();
domainLeft = Double.parseDouble(attributes.getNamedItem("domainLeft").getTextContent());
domainRight = Double.parseDouble(attributes.getNamedItem("domainRight").getTextContent());
// load optional parameters
if (attributes.getNamedItem("defaultValue") != null) {
defaultValue = Double.parseDouble(attributes.getNamedItem("defaultValue").getTextContent());
}
if (attributes.getNamedItem("scale") != null) {
scale = attributes.getNamedItem("scale").getTextContent();
}
if (attributes.getNamedItem("type") != null) {
type = Type.fromString(attributes.getNamedItem("type").getTextContent());
}
if (attributes.getNamedItem("accumulation") != null) {
accumulation = Accumulation.fromString(attributes.getNamedItem("accumulation").getTextContent());
}
if (attributes.getNamedItem("defuzzifier") != null) {
defuzzifier = Defuzzifier.fromString(attributes.getNamedItem("defuzzifier").getTextContent());
}
terms = new ArrayList<>();
NodeList children = ((Element) xmlNode).getElementsByTagName("FuzzyTerm");
for (int i = 0; i < children.getLength(); i++) {
terms.add(new FuzzyTerm(children.item(i)));
}
}
public FuzzyTerm getTerm(String name) {
for (FuzzyTerm term : terms) {
if (term.getName().equals(name)) {
return term;
}
}
return null;
}
public double defuzzify(ActivationMethod activationMethod, KnowledgeBase knowledgeBase, double delta, List<Pair<Double, Clause>> terms) {
List<Point.Double> function = new ArrayList<>();
for (double x = domainLeft; x <= domainRight; x += delta) {
Point.Double p = new Point.Double(x, 0);
for (Pair<Double, Clause> term : terms) {
double y = term.second.eval(x, knowledgeBase); //evaluate the term in the x
y = activationMethod.eval(term.first, y); // result after calculate the activation of the rule.
p.y = accumulation.eval(p.y, y); // accumulate the result of this term.
}
function.add(p);
}
return defuzzifier.getValue(function);
}
enum Type {
INPUT("input"), OUTPUT("output");
private String text;
Type(String text) {
this.text = text;
}
public static Type fromString(String text) {
Type result = null;
for (Type b : Type.values()) {
if (b.text.equalsIgnoreCase(text)) {
result = b;
break;
}
}
return result;
}
public String getText() {
return this.text;
}
}
}