// Testing basic functionality of fuzzy sets private void runFuzzySetTestButton_Click(object sender, EventArgs e) { ClearDataSeries(); // create 2 fuzzy sets to represent the Cool and Warm temperatures FuzzySet fsCool = new FuzzySet("Cool", new TrapezoidalFunction(13, 18, 23, 28)); FuzzySet fsWarm = new FuzzySet("Warm", new TrapezoidalFunction(23, 28, 33, 38)); // get membership of some points to the cool fuzzy set double[,] coolValues = new double[20, 2]; for (int i = 10; i < 30; i++) { coolValues[i - 10, 0] = i; coolValues[i - 10, 1] = fsCool.GetMembership(i); } // getting memberships of some points to the warm fuzzy set double[,] warmValues = new double[20, 2]; for (int i = 20; i < 40; i++) { warmValues[i - 20, 0] = i; warmValues[i - 20, 1] = fsWarm.GetMembership(i); } // plot membership to a chart chart.UpdateDataSeries("COOL", coolValues); chart.UpdateDataSeries("WARM", warmValues); }
// Testing basic functionality of linguistic variables private void runLingVarTestButton_Click(object sender, EventArgs e) { ClearDataSeries(); // create a linguistic variable to represent temperature LinguisticVariable lvTemperature = new LinguisticVariable("Temperature", 0, 80); // create the linguistic labels (fuzzy sets) that compose the temperature FuzzySet fsCold = new FuzzySet("Cold", new TrapezoidalFunction(10, 15, TrapezoidalFunction.EdgeType.Right)); FuzzySet fsCool = new FuzzySet("Cool", new TrapezoidalFunction(10, 15, 20, 25)); FuzzySet fsWarm = new FuzzySet("Warm", new TrapezoidalFunction(20, 25, 30, 35)); FuzzySet fsHot = new FuzzySet("Hot", new TrapezoidalFunction(30, 35, TrapezoidalFunction.EdgeType.Left)); // adding labels to the variable lvTemperature.AddLabel(fsCold); lvTemperature.AddLabel(fsCool); lvTemperature.AddLabel(fsWarm); lvTemperature.AddLabel(fsHot); // get membership of some points to the cool fuzzy set double[][,] chartValues = new double[4][,]; for (int i = 0; i < 4; i++) chartValues[i] = new double[160, 2]; // showing the shape of the linguistic variable - the shape of its labels memberships from start to end int j = 0; for (float x = 0; x < 80; x += 0.5f, j++) { double y1 = lvTemperature.GetLabelMembership("Cold", x); double y2 = lvTemperature.GetLabelMembership("Cool", x); double y3 = lvTemperature.GetLabelMembership("Warm", x); double y4 = lvTemperature.GetLabelMembership("Hot", x); chartValues[0][j, 0] = x; chartValues[0][j, 1] = y1; chartValues[1][j, 0] = x; chartValues[1][j, 1] = y2; chartValues[2][j, 0] = x; chartValues[2][j, 1] = y3; chartValues[3][j, 0] = x; chartValues[3][j, 1] = y4; } // plot membership to a chart chart.UpdateDataSeries("COLD", chartValues[0]); chart.UpdateDataSeries("COOL", chartValues[1]); chart.UpdateDataSeries("WARM", chartValues[2]); chart.UpdateDataSeries("HOT", chartValues[3]); }
/// <summary> /// Adds a linguistic label to the variable. /// </summary> /// /// <param name="label">A <see cref="FuzzySet"/> that will be a linguistic label of the linguistic variable.</param> /// /// <remarks>Linguistic labels are fuzzy sets (<see cref="FuzzySet"/>). Each /// label of the variable must have a unique name. The range of the label /// (left and right limits) cannot be greater than /// the linguistic variable range (start/end).</remarks> /// /// <exception cref="NullReferenceException">The fuzzy set was not initialized.</exception> /// <exception cref="ArgumentException">The linguistic label name already exists in the linguistic variable.</exception> /// <exception cref="ArgumentException">The left limit of the fuzzy set can not be lower than the linguistic variable's starting point.</exception> /// <exception cref="ArgumentException">"The right limit of the fuzzy set can not be greater than the linguistic variable's ending point."</exception> /// public void AddLabel(FuzzySet label) { // checking for existing name if (this.labels.ContainsKey(label.Name)) { throw new ArgumentException("The linguistic label name already exists in the linguistic variable."); } // checking ranges if (label.LeftLimit < this.start) { throw new ArgumentException("The left limit of the fuzzy set can not be lower than the linguistic variable's starting point."); } if (label.RightLimit > this.end) { throw new ArgumentException("The right limit of the fuzzy set can not be greater than the linguistic variable's ending point."); } // adding label this.labels.Add(label.Name, label); }
/// <summary> /// Adds a linguistic label to the variable. /// </summary> /// /// <param name="label">A <see cref="FuzzySet"/> that will be a linguistic label of the linguistic variable.</param> /// /// <remarks>Linguistic labels are fuzzy sets (<see cref="FuzzySet"/>). Each /// label of the variable must have a unique name. The range of the label /// (left and right limits) cannot be greater than /// the linguistic variable range (start/end).</remarks> /// /// <exception cref="NullReferenceException">The fuzzy set was not initialized.</exception> /// <exception cref="ArgumentException">The linguistic label name already exists in the linguistic variable.</exception> /// <exception cref="ArgumentException">The left limit of the fuzzy set can not be lower than the linguistic variable's starting point.</exception> /// <exception cref="ArgumentException">"The right limit of the fuzzy set can not be greater than the linguistic variable's ending point."</exception> /// public void AddLabel( FuzzySet label ) { // checking for existing name if ( this.labels.ContainsKey( label.Name ) ) throw new ArgumentException( "The linguistic label name already exists in the linguistic variable." ); // checking ranges if ( label.LeftLimit < this.start ) throw new ArgumentException( "The left limit of the fuzzy set can not be lower than the linguistic variable's starting point." ); if ( label.RightLimit > this.end ) throw new ArgumentException( "The right limit of the fuzzy set can not be greater than the linguistic variable's ending point." ); // adding label this.labels.Add( label.Name, label ); }
/// <summary> /// Converts the Fuzzy Rule to RPN (Reverse Polish Notation). For debug proposes, the string representation of the /// RPN expression can be acessed by calling <see cref="GetRPNExpression"/> method. /// </summary> /// private void ParseRule( ) { // flag to incicate we are on consequent state bool consequent = false; // tokens like IF and THEN will be searched always in upper case string upRule = rule.ToUpper( ); // the rule must start with IF, and must have a THEN somewhere if (!upRule.StartsWith("IF")) { throw new ArgumentException("A Fuzzy Rule must start with an IF statement."); } if (upRule.IndexOf("THEN") < 0) { throw new ArgumentException("Missing the consequent (THEN) statement."); } // building a list with all the expression (rule) string tokens string spacedRule = rule.Replace("(", " ( ").Replace(")", " ) "); // getting the tokens list string[] tokensList = GetRuleTokens(spacedRule); // stack to convert to RPN Stack <string> s = new Stack <string>( ); // storing the last token string lastToken = "IF"; // linguistic var read, used to build clause LinguisticVariable lingVar = null; // verifying each token for (int i = 0; i < tokensList.Length; i++) { // removing spaces string token = tokensList[i].Trim( ); // getting upper case string upToken = token.ToUpper( ); // ignoring these tokens if (upToken == "" || upToken == "IF") { continue; } // if the THEN is found, the rule is now on consequent if (upToken == "THEN") { lastToken = upToken; consequent = true; continue; } // if we got a linguistic variable, an IS statement and a label is needed if (lastToken == "VAR") { if (upToken == "IS") { lastToken = upToken; } else { throw new ArgumentException("An IS statement is expected after a linguistic variable."); } } // if we got an IS statement, a label must follow it else if (lastToken == "IS") { try { FuzzySet fs = lingVar.GetLabel(token); Clause c = new Clause(lingVar, fs); if (consequent) { output = c; } else { rpnTokenList.Add(c); } lastToken = "LAB"; } catch (KeyNotFoundException) { throw new ArgumentException("Linguistic label " + token + " was not found on the variable " + lingVar.Name + "."); } } // not VAR and not IS statement else { // openning new scope if (upToken == "(") { // if we are on consequent, only variables can be found if (consequent) { throw new ArgumentException("Linguistic variable expected after a THEN statement."); } // if its a (, just push it s.Push(upToken); lastToken = upToken; } // operators else if (upToken == "AND" || upToken == "OR" || unaryOperators.IndexOf(upToken) >= 0) { // if we are on consequent, only variables can be found if (consequent) { throw new ArgumentException("Linguistic variable expected after a THEN statement."); } // pop all the higher priority operators until the stack is empty while ((s.Count > 0) && (Priority(s.Peek( )) > Priority(upToken))) { rpnTokenList.Add(s.Pop( )); } // pushing the operator s.Push(upToken); lastToken = upToken; } // closing the scope else if (upToken == ")") { // if we are on consequent, only variables can be found if (consequent) { throw new ArgumentException("Linguistic variable expected after a THEN statement."); } // if there is nothing on the stack, an oppening parenthesis is missing. if (s.Count == 0) { throw new ArgumentException("Openning parenthesis missing."); } // pop the tokens and copy to output until openning is found while (s.Peek( ) != "(") { rpnTokenList.Add(s.Pop( )); if (s.Count == 0) { throw new ArgumentException("Openning parenthesis missing."); } } s.Pop( ); // saving last token... lastToken = upToken; } // finally, the token is a variable else { // find the variable try { lingVar = database.GetVariable(token); lastToken = "VAR"; } catch (KeyNotFoundException) { throw new ArgumentException("Linguistic variable " + token + " was not found on the database."); } } } } // popping all operators left in stack while (s.Count > 0) { rpnTokenList.Add(s.Pop( )); } }
// Hardcode initializing the Fuzzy Inference System void InitFuzzyEngine() { // Linguistic labels (fuzzy sets) that compose the distances FuzzySet fsNear = new FuzzySet("Near", new TrapezoidalFunction(15, 50, TrapezoidalFunction.EdgeType.Right)); FuzzySet fsMedium = new FuzzySet("Medium", new TrapezoidalFunction(15, 50, 60, 100)); FuzzySet fsFar = new FuzzySet("Far", new TrapezoidalFunction(60, 100, TrapezoidalFunction.EdgeType.Left)); // Right Distance (Input) LinguisticVariable lvRight = new LinguisticVariable("RightDistance", 0, 120); lvRight.AddLabel(fsNear); lvRight.AddLabel(fsMedium); lvRight.AddLabel(fsFar); // Left Distance (Input) LinguisticVariable lvLeft = new LinguisticVariable("LeftDistance", 0, 120); lvLeft.AddLabel(fsNear); lvLeft.AddLabel(fsMedium); lvLeft.AddLabel(fsFar); // Front Distance (Input) LinguisticVariable lvFront = new LinguisticVariable("FrontalDistance", 0, 120); lvFront.AddLabel(fsNear); lvFront.AddLabel(fsMedium); lvFront.AddLabel(fsFar); // Linguistic labels (fuzzy sets) that compose the angle FuzzySet fsVN = new FuzzySet("VeryNegative", new TrapezoidalFunction(-40, -35, TrapezoidalFunction.EdgeType.Right)); FuzzySet fsN = new FuzzySet("Negative", new TrapezoidalFunction(-40, -35, -25, -20)); FuzzySet fsLN = new FuzzySet("LittleNegative", new TrapezoidalFunction(-25, -20, -10, -5)); FuzzySet fsZero = new FuzzySet("Zero", new TrapezoidalFunction(-10, 5, 5, 10)); FuzzySet fsLP = new FuzzySet("LittlePositive", new TrapezoidalFunction(5, 10, 20, 25)); FuzzySet fsP = new FuzzySet("Positive", new TrapezoidalFunction(20, 25, 35, 40)); FuzzySet fsVP = new FuzzySet("VeryPositive", new TrapezoidalFunction(35, 40, TrapezoidalFunction.EdgeType.Left)); // Angle LinguisticVariable lvAngle = new LinguisticVariable("Angle", -50, 50); lvAngle.AddLabel(fsVN); lvAngle.AddLabel(fsN); lvAngle.AddLabel(fsLN); lvAngle.AddLabel(fsZero); lvAngle.AddLabel(fsLP); lvAngle.AddLabel(fsP); lvAngle.AddLabel(fsVP); // The database Database fuzzyDB = new Database(); fuzzyDB.AddVariable(lvFront); fuzzyDB.AddVariable(lvLeft); fuzzyDB.AddVariable(lvRight); fuzzyDB.AddVariable(lvAngle); // Creating the inference system IS = new InferenceSystem(fuzzyDB, new CentroidDefuzzifier(1000)); // Going Straight IS.NewRule("Rule 1", "IF FrontalDistance IS Far THEN Angle IS Zero"); // Going Straight (if can go anywhere) IS.NewRule("Rule 2", "IF FrontalDistance IS Far AND RightDistance IS Far AND LeftDistance IS Far THEN Angle IS Zero"); // Near right wall IS.NewRule("Rule 3", "IF RightDistance IS Near AND LeftDistance IS Not Near THEN Angle IS LittleNegative"); // Near left wall IS.NewRule("Rule 4", "IF RightDistance IS Not Near AND LeftDistance IS Near THEN Angle IS LittlePositive"); // Near front wall - room at right IS.NewRule("Rule 5", "IF RightDistance IS Far AND FrontalDistance IS Near THEN Angle IS Positive"); // Near front wall - room at left IS.NewRule("Rule 6", "IF LeftDistance IS Far AND FrontalDistance IS Near THEN Angle IS Negative"); // Near front wall - room at both sides - go right IS.NewRule("Rule 7", "IF RightDistance IS Far AND LeftDistance IS Far AND FrontalDistance IS Near THEN Angle IS Positive"); }
/// <summary> /// Initializes a new instance of the <see cref="Clause"/> class. /// </summary> /// /// <param name="variable">Linguistic variable of the clause. </param> /// /// <param name="label">Label of the linguistic variable, a fuzzy set used as label into the linguistic variable.</param> /// /// <exception cref="KeyNotFoundException">The label indicated was not found in the linguistic variable.</exception> /// public Clause( LinguisticVariable variable, FuzzySet label ) { // check if label belongs to var. variable.GetLabel( label.Name ); // initializing attributes this.label = label; this.variable = variable; }
/// <summary> /// Calculate the membership of a given value to a given label. Used to evaluate linguistics clauses like /// "X IS A", where X is a value and A is a linguistic label. /// </summary> /// /// <param name="labelName">Label (fuzzy set) to evaluate value's membership.</param> /// <param name="value">Value which label's membership will to be calculated.</param> /// /// <returns>Degree of membership [0..1] of the value to the label (fuzzy set).</returns> /// /// <exception cref="KeyNotFoundException">The label indicated in labelName was not found in the linguistic variable.</exception> /// public float GetLabelMembership(string labelName, float value) { FuzzySet fs = labels[labelName]; return(fs.GetMembership(value)); }