// Lukasiewicz t-norm derived equivalence static public IFuzzy Equivalence(IFuzzy A, IFuzzy B) { // Take snapshots of A and B IFuzzy copy_A = (IFuzzy)A.Clone(); IFuzzy copy_B = (IFuzzy)B.Clone(); // We lose our bounds :( return(new DelegateFuzzy((x) => Mathf.Min( 1 - copy_A.Membership(x) + copy_B.Membership(x), 1 - copy_B.Membership(x) + copy_A.Membership(x)), Mathf.NegativeInfinity, Mathf.Infinity)); }
// COG public static float Defuzzify(IFuzzy A) { if (A.close_left == Mathf.NegativeInfinity || A.close_right == Mathf.Infinity) { Debug.LogWarning("Tried to defuzzify with infinite bounds!"); } // Defuzzy crisp is just the crisp if (A.close_left == A.close_right) { return(A.close_right); } // The ammount of points sampled for a numerical integral approximation of the value const int resolution = 32; float interval = (A.close_right - A.close_left) / resolution; // Use trapezoidal rule integration approximation float moment = 0.0f; float sum = 0.0f; for (int i = 0; i < resolution; ++i) { // Left bound of integration float left = i * interval + A.close_left; // Right bound of integration float right = left + interval; float integral = interval * (A.Membership(left) + A.Membership(right)) * 0.5f; Debug.Assert(integral >= 0.0f); moment += (left + interval * 0.5f) * integral; sum += integral; } // If this is a flat integral, then give up and give them the midpoint if (sum <= 0.0f) { // Debug.LogWarning("Tried to defuzzy an empty number:" + sum); return((A.close_right + A.close_left) * 0.5f); } return(moment / sum); }
static public IFuzzy Complement(IFuzzy A) { // Copy A so that later changes don't modify IFuzzy copy = (IFuzzy)A.Clone(); // We lose our bounds :( return(new DelegateFuzzy((x) => 1.0f - copy.Membership(x) , Mathf.NegativeInfinity, Mathf.Infinity)); }
public IFuzzy ApplyRule(float x) { // Get the membership of input float firingLevel = input.GetTerm(inputProperty).Membership(x); // Copy the second rule base so that changing the linguistic base won't affect this result IFuzzy outCopy = (IFuzzy)output.GetTerm(outputProperty).Clone(); // Return a delegate that clamps that value return(new DelegateFuzzy((y) => Mathf.Min(outCopy.Membership(y), firingLevel), outCopy.close_left, outCopy.close_right // Bounds are same as outputProperty )); }
static public IFuzzy Intersection(IFuzzy A, IFuzzy B) { // Copy A and B so that later changes don't modify this result IFuzzy copy_A = (IFuzzy)A.Clone(); IFuzzy copy_B = (IFuzzy)B.Clone(); // Compute the new bounds float left = Mathf.Max(A.close_left, B.close_left); float right = Mathf.Min(A.close_right, B.close_right); return(new DelegateFuzzy((x) => Mathf.Min(copy_A.Membership(x), copy_B.Membership(x)), left, right )); }
// Applies a set of rules to a given output private void ApplyRuleSet(Rule[] rules) { IFuzzy ruleResults = Fuzzy.Zero(); Debug.Assert(rules.Length > 0); LinguisticVariable output = rules[0].output; for (int i = 0; i < rules.Length; ++i) { Rule r = rules[i]; // Make sure everything in this rule exists if (!r.IsValid()) { Debug.LogWarning("Bad fuzzy rule: " + r.ToString()); continue; } // Make sure all of the rules have the same properties, we don't want to mix up our outputs Debug.Assert(r.output == output, r.output + "!=" + output); // Input to the fuzzy membership is the input's referenced field float input = r.input.value; // Apply the rule IFuzzy ruleStrength = r.ApplyRule(input); // Combine this input with the other inputs to the rule ruleResults = Fuzzy.Union(ruleResults, ruleStrength); // TODO maybe make this so I don't have ~n! copies of rules in memory } // Defuzzify them float crisp = Fuzzy.Defuzzify(ruleResults); if (ConfidenceLerp) { FuzzyOutput confidence = ruleResults.Membership(crisp); output.value = Mathf.Lerp(output.value, crisp, confidence); } else { output.value = crisp; } }