#!/usr/bin/env python
# Created by "Thieu" at 22:53, 29/12/2024 ----------%
# Email: nguyenthieu2102@gmail.com %
# Github: https://github.com/thieu1995 %
# --------------------------------------------------%
from typing import Optional, Type, Dict, Any
import torch
import torch.nn as nn
[docs]class BaseMembership(nn.Module):
"""Base class for membership functions.
This class defines the interface for all membership functions. Subclasses
must implement the `forward` method to calculate membership values.
"""
def __init__(self) -> None:
super(BaseMembership, self).__init__()
[docs] def forward(self, X: torch.Tensor) -> torch.Tensor:
"""
Calculate membership values for the given input tensor.
Args:
X (torch.Tensor): Input tensor of shape (batch_size, input_dim).
Returns:
torch.Tensor: Tensor of membership values of shape (batch_size,).
Raises:
NotImplementedError: If not implemented by subclass.
"""
raise NotImplementedError("Subclasses must implement the forward method.")
[docs] def get_parameters(self) -> Dict[str, torch.Tensor]:
"""
Retrieve the current parameters of the membership function.
Returns:
Dict[str, torch.Tensor]: Dictionary containing parameter names and values.
"""
return {name: param.data for name, param in self.named_parameters()}
def __str__(self):
return self.__class__.__name__
[docs] def name(self):
return self.__class__.__name__
[docs]class GaussianMembership(BaseMembership):
"""Gaussian membership function implementation."""
def __init__(self, input_dim: int) -> None:
"""
Initialize the Gaussian membership function.
Args:
input_dim (int): Number of input features.
"""
super(GaussianMembership, self).__init__()
self.centers = nn.Parameter(torch.randn(input_dim)) # Centers
self.widths = nn.Parameter(torch.abs(torch.randn(input_dim))) # Widths
[docs] def forward(self, X: torch.Tensor) -> torch.Tensor:
"""
Calculate Gaussian membership values.
Args:
X (torch.Tensor): Input tensor of shape (batch_size, input_dim).
Returns:
torch.Tensor: Tensor of membership values of shape (batch_size,).
"""
return torch.exp(-((X - self.centers) ** 2) / (2 * torch.clamp(self.widths, min=1e-8) ** 2))
[docs]class TrapezoidalMembership(BaseMembership):
"""Trapezoidal membership function implementation."""
def __init__(self, input_dim: int) -> None:
"""
Initialize the Trapezoidal membership function.
Args:
input_dim (int): Number of input features.
"""
super().__init__()
# Ta khởi tạo theo thứ tự rồi dùng sigmoid để đảm bảo đúng thứ tự a < b < c < d
self.raw_params = nn.Parameter(torch.rand(4, input_dim)) # [a, b, c, d]
[docs] def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Calculate Trapezoidal membership values.
Args:
x (torch.Tensor): Input tensor of shape (batch_size, input_dim).
Returns:
torch.Tensor: Tensor of membership values of shape (batch_size,).
"""
# Sort theo chiều tăng để đảm bảo thứ tự đúng
abcd = torch.sort(self.raw_params, dim=0).values
a, b, c, d = abcd[0], abcd[1], abcd[2], abcd[3]
ramp_up = torch.clamp((x - a) / (b - a + 1e-6), 0.0, 1.0)
plateau = torch.ones_like(x)
ramp_down = torch.clamp((d - x) / (d - c + 1e-6), 0.0, 1.0)
membership = torch.where(x <= a, 0.0,
torch.where(x < b, ramp_up,
torch.where(x <= c, plateau,
torch.where(x < d, ramp_down, 0.0))))
return membership
[docs]class TriangularMembership(BaseMembership):
"""Triangular membership function implementation."""
def __init__(self, input_dim: int) -> None:
"""
Initialize the Triangular membership function.
Args:
input_dim (int): Number of input features.
"""
super(TriangularMembership, self).__init__()
# Khởi tạo centers trong khoảng [0, 1] vì data của chúng ta cũng nằm trong khoảng này
self.centers = nn.Parameter(torch.rand(input_dim))
# Khởi tạo spread với giá trị dương và không quá nhỏ
self.left_spread = nn.Parameter(torch.ones(input_dim) * 0.5)
self.right_spread = nn.Parameter(torch.ones(input_dim) * 0.5)
[docs] def forward(self, X: torch.Tensor) -> torch.Tensor:
"""
Calculate Triangular membership values.
Args:
X (torch.Tensor): Input tensor of shape (batch_size, input_dim).
Returns:
torch.Tensor: Tensor of membership values of shape (batch_size,).
"""
left_spread = torch.abs(self.left_spread) + 1e-4
right_spread = torch.abs(self.right_spread) + 1e-4
# Tính toán membership values
left_side = (X - (self.centers - left_spread)) / left_spread
right_side = ((self.centers + right_spread) - X) / right_spread
# Sử dụng torch.relu thay vì torch.maximum để đảm bảo gradient flow tốt hơn
return torch.minimum(torch.relu(left_side), torch.relu(right_side))
[docs]class SigmoidMembership(BaseMembership):
"""Sigmoid membership function implementation."""
def __init__(self, input_dim: int) -> None:
"""
Initialize the Sigmoid membership function.
Args:
input_dim (int): Number of input features.
"""
super(SigmoidMembership, self).__init__()
self.a = nn.Parameter(torch.randn(input_dim)) # Slope
self.b = nn.Parameter(torch.randn(input_dim)) # Offset
[docs] def forward(self, X: torch.Tensor) -> torch.Tensor:
"""
Calculate Sigmoid membership values.
Args:
X (torch.Tensor): Input tensor of shape (batch_size, input_dim).
Returns:
torch.Tensor: Tensor of membership values of shape (batch_size,).
"""
return 1 / (1 + torch.exp(-self.a * (X - self.b)))
[docs]class PiShapedMembership(BaseMembership):
"""
Pi-shaped membership function implementation.
This membership function is characterized by a rising edge, a plateau, and a falling edge,
forming a shape similar to the Greek letter Pi (π).
Args:
input_dim (int): Number of input features.
Attributes:
a (nn.Parameter): Start of the rising edge.
b (nn.Parameter): Start of the plateau.
c (nn.Parameter): End of the plateau.
d (nn.Parameter): End of the falling edge.
"""
def __init__(self, input_dim):
super().__init__()
self.a = nn.Parameter(torch.rand(input_dim)) # Start of the ramp
self.b = nn.Parameter(torch.rand(input_dim)) # Peak start
self.c = nn.Parameter(torch.rand(input_dim)) # Peak end
self.d = nn.Parameter(torch.rand(input_dim)) # End of the ramp
[docs] def forward(self, x):
ramp_up = (x - self.a) / (self.b - self.a + 1e-6)
ramp_down = (self.d - x) / (self.d - self.c + 1e-6)
rising_edge = torch.clamp(ramp_up, min=0.0, max=1.0)
falling_edge = torch.clamp(ramp_down, min=0.0, max=1.0)
return torch.min(rising_edge, falling_edge)
[docs]class GBellMembership(BaseMembership):
"""
Generalized Bell-shaped membership function implementation.
This membership function is defined by a smooth, symmetric bell curve.
Args:
input_dim (int): Number of input features.
Attributes:
a (nn.Parameter): Width of the bell curve.
b (nn.Parameter): Slope of the bell curve.
c (nn.Parameter): Center of the bell curve.
"""
def __init__(self, input_dim):
super().__init__()
self.a = nn.Parameter(torch.rand(input_dim)) # Width
self.b = nn.Parameter(torch.ones(input_dim)) # Slope
self.c = nn.Parameter(torch.rand(input_dim)) # Center
[docs] def forward(self, x):
return 1.0 / (1.0 + torch.abs((x - self.c) / (self.a + 1e-6)) ** (2 * self.b))
[docs]class ZShapedMembership(BaseMembership):
"""
Z-shaped membership function implementation.
This membership function is characterized by a smooth transition from 1 to 0,
forming a Z-like shape.
Args:
input_dim (int): Number of input features.
Attributes:
a (nn.Parameter): Start of the transition.
b (nn.Parameter): End of the transition.
"""
def __init__(self, input_dim):
super().__init__()
self.a = nn.Parameter(torch.rand(input_dim)) # Start
self.b = nn.Parameter(torch.rand(input_dim)) # End
[docs] def forward(self, x):
mid = (self.a + self.b) / 2
left = (x <= self.a).float()
middle1 = ((x > self.a) & (x <= mid)).float()
middle2 = ((x > mid) & (x <= self.b)).float()
right = (x > self.b).float()
term1 = 1 - 2 * ((x - self.a) / (self.b - self.a + 1e-6))**2
term2 = 2 * ((self.b - x) / (self.b - self.a + 1e-6))**2
return left + middle1 * term1 + middle2 * term2
[docs]class SShapedMembership(BaseMembership):
"""
S-shaped membership function implementation.
This membership function is characterized by a smooth transition from 0 to 1,
forming an S-like shape.
Args:
input_dim (int): Number of input features.
Attributes:
a (nn.Parameter): Start of the transition.
b (nn.Parameter): End of the transition.
"""
def __init__(self, input_dim):
super().__init__()
self.a = nn.Parameter(torch.rand(input_dim))
self.b = nn.Parameter(torch.rand(input_dim))
[docs] def forward(self, x):
mid = (self.a + self.b) / 2
left = (x <= self.a).float()
middle1 = ((x > self.a) & (x <= mid)).float()
middle2 = ((x > mid) & (x <= self.b)).float()
right = (x > self.b).float()
term1 = 2 * ((x - self.a) / (self.b - self.a + 1e-6))**2
term2 = 1 - 2 * ((self.b - x) / (self.b - self.a + 1e-6))**2
return left * 0 + middle1 * term1 + middle2 * term2 + right
[docs]class LinearMembership(BaseMembership):
"""
Linear membership function implementation.
This membership function is defined by a linear ramp between two points.
Args:
input_dim (int): Number of input features.
Attributes:
a (nn.Parameter): Start of the ramp.
b (nn.Parameter): End of the ramp.
"""
def __init__(self, input_dim):
super().__init__()
self.a = nn.Parameter(torch.rand(input_dim))
self.b = nn.Parameter(torch.rand(input_dim))
[docs] def forward(self, x):
slope = (x - self.a) / (self.b - self.a + 1e-6)
return torch.clamp(slope, 0.0, 1.0)