Python/fuzzy_logic/fuzzy_operations.py
Maxim Smolskiy 79dc7c97ac
Enable ruff RUF001 rule (#11378)
* Enable ruff RUF001 rule

* Fix

* Fix
2024-04-22 21:45:24 +02:00

196 lines
5.9 KiB
Python

"""
By @Shreya123714
https://en.wikipedia.org/wiki/Fuzzy_set
"""
from __future__ import annotations
from dataclasses import dataclass
import matplotlib.pyplot as plt
import numpy as np
@dataclass
class FuzzySet:
"""
A class for representing and manipulating triangular fuzzy sets.
Attributes:
name: The name or label of the fuzzy set.
left_boundary: The left boundary of the fuzzy set.
peak: The peak (central) value of the fuzzy set.
right_boundary: The right boundary of the fuzzy set.
Methods:
membership(x): Calculate the membership value of an input 'x' in the fuzzy set.
union(other): Calculate the union of this fuzzy set with another fuzzy set.
intersection(other): Calculate the intersection of this fuzzy set with another.
complement(): Calculate the complement (negation) of this fuzzy set.
plot(): Plot the membership function of the fuzzy set.
>>> sheru = FuzzySet("Sheru", 0.4, 1, 0.6)
>>> sheru
FuzzySet(name='Sheru', left_boundary=0.4, peak=1, right_boundary=0.6)
>>> str(sheru)
'Sheru: [0.4, 1, 0.6]'
>>> siya = FuzzySet("Siya", 0.5, 1, 0.7)
>>> siya
FuzzySet(name='Siya', left_boundary=0.5, peak=1, right_boundary=0.7)
# Complement Operation
>>> sheru.complement()
FuzzySet(name='¬Sheru', left_boundary=0.4, peak=0.6, right_boundary=0)
>>> siya.complement() # doctest: +NORMALIZE_WHITESPACE
FuzzySet(name='¬Siya', left_boundary=0.30000000000000004, peak=0.5,
right_boundary=0)
# Intersection Operation
>>> siya.intersection(sheru)
FuzzySet(name='Siya ∩ Sheru', left_boundary=0.5, peak=0.6, right_boundary=1.0)
# Membership Operation
>>> sheru.membership(0.5)
0.16666666666666663
>>> sheru.membership(0.6)
0.0
# Union Operations
>>> siya.union(sheru)
FuzzySet(name='Siya U Sheru', left_boundary=0.4, peak=0.7, right_boundary=1.0)
"""
name: str
left_boundary: float
peak: float
right_boundary: float
def __str__(self) -> str:
"""
>>> FuzzySet("fuzzy_set", 0.1, 0.2, 0.3)
FuzzySet(name='fuzzy_set', left_boundary=0.1, peak=0.2, right_boundary=0.3)
"""
return (
f"{self.name}: [{self.left_boundary}, {self.peak}, {self.right_boundary}]"
)
def complement(self) -> FuzzySet:
"""
Calculate the complement (negation) of this fuzzy set.
Returns:
FuzzySet: A new fuzzy set representing the complement.
>>> FuzzySet("fuzzy_set", 0.1, 0.2, 0.3).complement()
FuzzySet(name='¬fuzzy_set', left_boundary=0.7, peak=0.9, right_boundary=0.8)
"""
return FuzzySet(
f"¬{self.name}",
1 - self.right_boundary,
1 - self.left_boundary,
1 - self.peak,
)
def intersection(self, other) -> FuzzySet:
"""
Calculate the intersection of this fuzzy set
with another fuzzy set.
Args:
other: Another fuzzy set to intersect with.
Returns:
A new fuzzy set representing the intersection.
>>> FuzzySet("a", 0.1, 0.2, 0.3).intersection(FuzzySet("b", 0.4, 0.5, 0.6))
FuzzySet(name='a ∩ b', left_boundary=0.4, peak=0.3, right_boundary=0.35)
"""
return FuzzySet(
f"{self.name}{other.name}",
max(self.left_boundary, other.left_boundary),
min(self.right_boundary, other.right_boundary),
(self.peak + other.peak) / 2,
)
def membership(self, x: float) -> float:
"""
Calculate the membership value of an input 'x' in the fuzzy set.
Returns:
The membership value of 'x' in the fuzzy set.
>>> a = FuzzySet("a", 0.1, 0.2, 0.3)
>>> a.membership(0.09)
0.0
>>> a.membership(0.1)
0.0
>>> a.membership(0.11)
0.09999999999999995
>>> a.membership(0.4)
0.0
>>> FuzzySet("A", 0, 0.5, 1).membership(0.1)
0.2
>>> FuzzySet("B", 0.2, 0.7, 1).membership(0.6)
0.8
"""
if x <= self.left_boundary or x >= self.right_boundary:
return 0.0
elif self.left_boundary < x <= self.peak:
return (x - self.left_boundary) / (self.peak - self.left_boundary)
elif self.peak < x < self.right_boundary:
return (self.right_boundary - x) / (self.right_boundary - self.peak)
msg = f"Invalid value {x} for fuzzy set {self}"
raise ValueError(msg)
def union(self, other) -> FuzzySet:
"""
Calculate the union of this fuzzy set with another fuzzy set.
Args:
other (FuzzySet): Another fuzzy set to union with.
Returns:
FuzzySet: A new fuzzy set representing the union.
>>> FuzzySet("a", 0.1, 0.2, 0.3).union(FuzzySet("b", 0.4, 0.5, 0.6))
FuzzySet(name='a U b', left_boundary=0.1, peak=0.6, right_boundary=0.35)
"""
return FuzzySet(
f"{self.name} U {other.name}",
min(self.left_boundary, other.left_boundary),
max(self.right_boundary, other.right_boundary),
(self.peak + other.peak) / 2,
)
def plot(self):
"""
Plot the membership function of the fuzzy set.
"""
x = np.linspace(0, 1, 1000)
y = [self.membership(xi) for xi in x]
plt.plot(x, y, label=self.name)
if __name__ == "__main__":
from doctest import testmod
testmod()
a = FuzzySet("A", 0, 0.5, 1)
b = FuzzySet("B", 0.2, 0.7, 1)
a.plot()
b.plot()
plt.xlabel("x")
plt.ylabel("Membership")
plt.legend()
plt.show()
union_ab = a.union(b)
intersection_ab = a.intersection(b)
complement_a = a.complement()
union_ab.plot()
intersection_ab.plot()
complement_a.plot()
plt.xlabel("x")
plt.ylabel("Membership")
plt.legend()
plt.show()