Fuzzy sets in Python

Python
Soft Computing
A python code for implementing Fuzzy sets.

1. Introduction
2. What is Fuzzy set?
3. Fuzzy Operations
4. References


Prerequisite: Basic understanding of classical set theory.

1. Introduction

I completed the course ME60353 – Knowledge Based Systems in Engineering at IIT Kharagpur, taught by Prof. D. K. Pratihar, where I learned about fuzzy set theory. I have implemented fuzzy sets in Python as part of personal mini project.

Classical (Crisp) Set:-

A classical set is an unordered collection of distinct elements—essentially, a collection of objects.

Examples: - Set of all positive integers
- Set of all months in a year

Mathematically, a set can be represented as:

\[A = \{~ a,e,i,o,u ~ \}\]

2. What is a Fuzzy set?

A fuzzy set is a collection of ordered pairs, where each element is associated with a membership value between 0 and 1.

Mathematically, a fuzzy set is represented as:

\[A =\{ (x,\mu_{S}(x)), x\in X\}\]

Where \(X\) is an Universal set and \(\mu_{S}\) is membership function value.

3. Fuzzy Operations

Here, we will look into traditiona fuzzy operations along with respective python implementation.

Let A and B be tow fuzzy sets defined on universal set X, then different Fuzzy set operations can be defined as follows,

  1. Subset:-

\[A\subset B \iff \mu_{A}(x)<\mu_{B}(x)\]

def subset(self, other):
    """Returns True if a fuzzy set is subset of another."""
    if not isinstance(other, FuzzySet):
        return NotImplemented
    if self._elements.keys() != other._elements.keys():
        return False
    return all(self._elements[k] < other._elements[k] for k in self._elements)
  1. Equal:-

\[A= B \iff \mu_{A}(x)=\mu_{B}(x)\]

def __eq__(self, other):
    """Returns True if two fuzzy sets have exactly the same elements and membership values."""
    if not isinstance(other, FuzzySet):
        return NotImplemented
    if self._elements.keys() != other._elements.keys():
        return False
    return all(self._elements[k] == other._elements[k] for k in self._elements)
  1. Complement:-

\[\bar A = \{ x, 1-\mu_{A}(x)\}\]

def complement(self):
    """Returns the complement of this fuzzy set as a new FuzzySet."""
    result = FuzzySet()
    for k, v in self._elements.items():
        result[k] = 1 - v
    return result
  1. Union:-

\[A\cup B = \{ x, max[\mu_{A}(x),\mu_{B}(x)] \}\]

def union(self, other):
    """Returns the union of two fuzzy sets as a new FuzzySet."""
    result = FuzzySet()
    keys = set(self._elements.keys()) | set(other._elements.keys())
    for k in keys:
        m1 = self._elements.get(k, 0)
        m2 = other._elements.get(k, 0)
        result[k] = max(m1, m2)
    return result
  1. Intersection:-

\[A\cup B = \{ x, min[\mu_{A}(x),\mu_{B}(x)] \}\]

def intersection(self, other):
    """Returns the intersection of two fuzzy sets as a new FuzzySet."""
    result = FuzzySet()
    keys = set(self._elements.keys()) & set(other._elements.keys())
    for k in keys:
        m1 = self._elements[k]
        m2 = other._elements[k]
        result[k] = min(m1, m2)
    return result
  1. Algebric Product:-

\[A\cdot B = \{ x,\mu_{A}(x)\cdot\mu_{B}(x) \}\]

 def __mul__(self, other):
    """Returns the multiplication of two fuzzy sets (product t-norm)
    or scalar multiplication with a crisp number."""
    result = FuzzySet()
    
    if isinstance(other, FuzzySet):
        # FuzzySet × FuzzySet
        keys = set(self._elements.keys()) | set(other._elements.keys())
        for k in keys:
            m1 = self._elements.get(k, 0)
            m2 = other._elements.get(k, 0)
            result[k] = m1 * m2
        return result
    ...
  1. Multiplication by crisp number:-

\[c\cdot A = \{ x, c\cdot\mu_{A}(x)\}\]

 def __mul__(self, other):
    """Returns the multiplication of two fuzzy sets (product t-norm)
    or scalar multiplication with a crisp number."""
    result = FuzzySet()
    ...
    elif isinstance(other, (int, float)):
        # FuzzySet × scalar
        for k, v in self._elements.items():
            val = v * other
            result[k] = min(max(val, 0), 1)  # clamp into [0, 1]
        return result
  1. pth power:-

\[A^p = \{ x, \mu_{A}(x)^p\}\]

def __pow__(self, p):
    """Returns a new FuzzySet with membership values raised to the power p."""
    if not isinstance(p, (int, float)):
        return NotImplemented
    if p < 0:
        raise ValueError("Exponent must be non-negative for fuzzy sets.")
    
    result = FuzzySet()
    for k, v in self._elements.items():
        result[k] = v ** p
    return result
  1. Algebraic sum:-

\[A+B = \{ x,\mu_{A}(x)+\mu_{B}(x) \}\]

def __add__(self, other):
    """Returns the algebraic addition of two fuzzy sets as a new FuzzySet."""
    result = FuzzySet()
    keys = set(self._elements.keys()) | set(other._elements.keys())
    for k in keys:
        m1 = self._elements.get(k, 0)
        m2 = other._elements.get(k, 0)
        result[k] = m1+m2-(m1*m2)
    return result
  1. Algebraic difference:-

\[A-B = \{ x,\mu_{A}(x)-\mu_{B}(x) \}\]

def __sub__(self, other):
    """Returns the algebraic subtraction of two fuzzy sets as a new FuzzySet."""
    result = FuzzySet()
    keys = set(self._elements.keys()) | set(other._elements.keys())
    for k in keys:
        m1 = self._elements.get(k, 0)
        m2 = other._elements.get(k, 0)
        result[k] = m1-m2
    return result
  1. Bounded sum:-

\[A\oplus B = \{ x,\mu_{A}(x)\oplus \mu_{B}(x) \}\]

\[\mu_{A}(x)\oplus \mu_{B}(x) =min[1,\mu_{A}(x)+\mu_{B}(x)]\]

def bdsum (self, other):
    """Returns the bounded sum of two fuzzy sets as a new FuzzySet."""
    result = FuzzySet()
    keys = set(self._elements.keys()) | set(other._elements.keys())
    for k in keys:
        m1 = self._elements.get(k, 0)
        m2 = other._elements.get(k, 0)
        result[k] = min(1,m1+m2)
    return result
  1. Bounded difference:-

\[A\ominus B = \{ x,\mu_{A \ominus B}(x)\}\]

\[\\mu_{A \ominus B}(x) =max[0,\mu_{A}(x)+\mu_{B}(x)-1]\]

def bddiff(self, other):
    """Returns the bounded difference of two fuzzy sets as a new FuzzySet."""
    result = FuzzySet()
    keys = set(self._elements.keys()) | set(other._elements.keys())
    for k in keys:
        m1 = self._elements.get(k, 0)
        m2 = other._elements.get(k, 0)
        result[k] = max(0,m1+m2-1)
    return result

To see the full code, please refer GitHub link here.

4. References

  1. D. K. Pratihar, Soft Computing, Narosa Publications, New Delhi, 2008
  2. Shridhar Rajendra Mankar, 5 Minute Engineering, YouTube Channel, 2019
  3. Pozo Ramos, L. (2024, July 1), Python’s built-in functions: A complete exploration, Real Python. https://realpython.com/python-built-in-functions