bulanik.sets
sets ¶
Membership functions, linguistic variables and t-norms / t-conorms.
The building blocks of fuzzy inference:
MembershipFunctionand the factoriestriangular,trapezoidal,gaussian,bell,sigmoid,linear_increasingandlinear_decreasingbuild functions \(\mu: \mathbb{R} \to [0, 1]\).LinguisticVariablenames a variable on a universe and its fuzzy terms (for examplecold,warm,hot).t_normandt_conormare the fuzzy AND and OR used to combine rule antecedents.
SIGMOID_EPS
module-attribute
¶
SIGMOID_EPS = 1e-09
Sigmoid memberships never reach exactly 0 or 1, so inverse of a sigmoid clamps
alpha into \([\varepsilon, 1 - \varepsilon]\) with \(\varepsilon = 10^{-9}\) instead of returning
\(\pm\infty\).
MembershipFunction
dataclass
¶
MembershipFunction(kind: str, params: tuple[float, ...])
A membership function \(\mu: \mathbb{R} \to [0, 1]\) of a named kind.
Build one with the factories (triangular,
gaussian, ...). Calling the object evaluates it:
mf(x) returns the membership degree, always inside \([0, 1]\), also for huge
or infinite arguments. The supported kinds and their parameters are:
| kind | parameters | \(\mu(x)\) |
|---|---|---|
triangular |
a, b, c |
rises linearly from 0 at \(a\) to 1 at \(b\), falls to 0 at \(c\) |
trapezoidal |
a, b, c, d |
rises from \(a\) to 1 at \(b\), 1 on \([b, c]\), falls to 0 at \(d\) |
gaussian |
mean, sigma |
\(\exp(-(x - \text{mean})^2 / (2\sigma^2))\) |
bell |
a, b, c |
\(1 / (1 + \lvert (x - c)/a \rvert^{2b})\) |
sigmoid |
slope, center |
\(1 / (1 + e^{-\text{slope}\,(x - \text{center})})\) |
linear_increasing |
a, b |
0 for \(x \le a\), 1 for \(x \ge b\), linear between |
linear_decreasing |
a, b |
1 for \(x \le a\), 0 for \(x \ge b\), linear between |
Three more kinds are the building blocks of interval type-2 sets
(see bulanik.type2): gaussian_flat_top (m1, m2, sigma:
1 on \([m_1, m_2]\), else the Gaussian of the nearer mean), gaussian_min_pair
(m1, m2, sigma: the minimum of the two Gaussians) and scaled_triangular
(a, b, c, height: height times the triangle).
Direct construction validates the parameters as the factories do.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kind
|
str
|
One of the kinds above. |
required |
params
|
tuple[float, ...]
|
The numeric parameters of the kind, in the order shown. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
TypeError
|
If |
Attributes:
| Name | Type | Description |
|---|---|---|
kind |
str
|
The kind name. |
params |
tuple[float, ...]
|
The validated parameters, as a tuple of floats. |
Examples:
>>> from bulanik.sets import triangular, gaussian
>>> mf = triangular(0, 5, 10)
>>> mf(2.5)
0.5
>>> round(gaussian(5, 1)(6), 4)
0.6065
>>> mf.kind, mf.params
('triangular', (0.0, 5.0, 10.0))
is_monotonic
property
¶
is_monotonic: bool
True for the kinds linear_increasing, linear_decreasing and sigmoid.
Only monotonic functions have an inverse.
Examples:
>>> from bulanik.sets import sigmoid, triangular
>>> sigmoid(1, 0).is_monotonic, triangular(0, 1, 2).is_monotonic
(True, False)
inverse ¶
inverse(alpha: float) -> float
The \(x\) with \(\mu(x) = \alpha\) (monotonic kinds only).
For linear_increasing this is \(a (1 - \alpha) + b\alpha\) and for
linear_decreasing \(b (1 - \alpha) + a\alpha\), exact at the ends. For
sigmoid it is \(\text{center} - \ln(1/\alpha - 1)/\text{slope}\) with
\(\alpha\) clamped into \([\varepsilon, 1 - \varepsilon]\), where
\(\varepsilon\) is SIGMOID_EPS.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
alpha
|
float
|
Membership level in \([0, 1]\). |
required |
Returns:
| Type | Description |
|---|---|
float
|
The point |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the function is not monotonic, or |
Examples:
>>> from bulanik.sets import linear_increasing, sigmoid, triangular
>>> linear_increasing(0, 10).inverse(0.25)
2.5
>>> sigmoid(1, 0).inverse(0.5)
0.0
>>> triangular(0, 1, 2).inverse(0.5)
Traceback (most recent call last):
...
ValueError: inverse needs a monotonic membership function; triangular is not monotonic
LinguisticVariable ¶
LinguisticVariable(name: str, universe: tuple[float, float], terms: Mapping[str, MembershipFunction])
A named variable on a universe (lo, hi) with named fuzzy terms.
Terms are looked up with variable["term"], which returns the
MembershipFunction; the term order is
the insertion order of terms.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The variable name, used in error messages and rule text. |
required |
universe
|
tuple[float, float]
|
The pair |
required |
terms
|
Mapping[str, MembershipFunction]
|
Mapping from term name to membership function (at least one). |
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
ValueError
|
If |
Attributes:
| Name | Type | Description |
|---|---|---|
name |
The variable name. |
|
universe |
The domain as a tuple of floats |
Examples:
>>> from bulanik.sets import LinguisticVariable, linear_decreasing, triangular, linear_increasing
>>> temp = LinguisticVariable("temp", (0, 40), {
... "cold": linear_decreasing(10, 20),
... "warm": triangular(10, 20, 30),
... "hot": linear_increasing(20, 30),
... })
>>> temp
LinguisticVariable('temp', (0.0, 40.0), terms=('cold', 'warm', 'hot'))
>>> temp.fuzzify(15)
{'cold': 0.5, 'warm': 0.5, 'hot': 0.0}
term_names
property
¶
term_names: tuple[str, ...]
The term names, in insertion order.
Examples:
>>> from bulanik.sets import LinguisticVariable, triangular
>>> LinguisticVariable("x", (0, 1), {"lo": triangular(0, 0, 1)}).term_names
('lo',)
fuzzify ¶
fuzzify(x: float) -> dict[str, float]
Membership of x in every term.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
float
|
A crisp input inside the universe. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
A dict from term name to membership degree, in term order. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
>>> from bulanik.sets import LinguisticVariable, triangular
>>> v = LinguisticVariable("service", (0, 10), {"good": triangular(5, 10, 10)})
>>> v.fuzzify(7.5)
{'good': 0.5}
>>> v.fuzzify(11)
Traceback (most recent call last):
...
ValueError: 'service' input 11 is outside its universe [0, 10]
triangular ¶
triangular(a: float, b: float, c: float) -> MembershipFunction
Triangle with feet a, c and peak b (a <= b <= c, a < c).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
float
|
Left foot (membership 0). |
required |
b
|
float
|
Peak (membership 1). |
required |
c
|
float
|
Right foot (membership 0). |
required |
Returns:
| Type | Description |
|---|---|
MembershipFunction
|
A |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the parameters are not finite or violate |
Examples:
>>> from bulanik.sets import triangular
>>> tri = triangular(0, 5, 10)
>>> tri(5), tri(7.5), tri(11)
(1.0, 0.5, 0.0)
>>> triangular(3, 2, 1)
Traceback (most recent call last):
...
ValueError: triangular needs a <= b <= c and a < c, got (3.0, 2.0, 1.0)
trapezoidal ¶
trapezoidal(a: float, b: float, c: float, d: float) -> MembershipFunction
Trapezoid with plateau [b, c] (a <= b <= c <= d, a < d).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
float
|
Left foot (membership 0). |
required |
b
|
float
|
Start of the plateau. |
required |
c
|
float
|
End of the plateau. |
required |
d
|
float
|
Right foot (membership 0). |
required |
Returns:
| Type | Description |
|---|---|
MembershipFunction
|
A |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the parameters are not finite or violate |
Examples:
>>> from bulanik.sets import trapezoidal
>>> trapezoidal(0, 1, 2, 3)(0.5), trapezoidal(0, 1, 2, 3)(1.5)
(0.5, 1.0)
gaussian ¶
gaussian(mean: float, sigma: float) -> MembershipFunction
Gaussian \(\exp\!\left(-\frac{(x - \text{mean})^2}{2\sigma^2}\right)\) with \(\sigma > 0\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mean
|
float
|
Centre of the bell (membership 1). |
required |
sigma
|
float
|
Standard deviation, strictly positive. |
required |
Returns:
| Type | Description |
|---|---|
MembershipFunction
|
A |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a parameter is not finite or |
Examples:
>>> from bulanik.sets import gaussian
>>> g = gaussian(5, 1)
>>> g(5), round(g(6), 4)
(1.0, 0.6065)
bell ¶
bell(a: float, b: float, c: float) -> MembershipFunction
Generalized bell \(\dfrac{1}{1 + \lvert (x - c)/a \rvert^{2b}}\) with \(a > 0\), \(b > 0\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
float
|
Width, strictly positive. |
required |
b
|
float
|
Slope of the shoulders, strictly positive. |
required |
c
|
float
|
Centre (membership 1). |
required |
Returns:
| Type | Description |
|---|---|
MembershipFunction
|
A |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a parameter is not finite or |
Examples:
>>> from bulanik.sets import bell
>>> bell(2, 4, 6)(6), round(bell(2, 4, 6)(7), 4)
(1.0, 0.9961)
sigmoid ¶
sigmoid(slope: float, center: float) -> MembershipFunction
Sigmoid \(\dfrac{1}{1 + e^{-\text{slope}\,(x - \text{center})}}\) with \(\text{slope} \ne 0\).
Increasing for a positive slope and decreasing for a negative one;
membership 0.5 at center. It is monotonic, so it has an
inverse.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
slope
|
float
|
Steepness and direction, non-zero. |
required |
center
|
float
|
The point where the membership is 0.5. |
required |
Returns:
| Type | Description |
|---|---|
MembershipFunction
|
A |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a parameter is not finite or |
Examples:
>>> from bulanik.sets import sigmoid
>>> sigmoid(1, 0)(0)
0.5
linear_increasing ¶
linear_increasing(a: float, b: float) -> MembershipFunction
Ramp up: 0 for x <= a, 1 for x >= b, linear in between (a < b).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
float
|
Last point with membership 0. |
required |
b
|
float
|
First point with membership 1. |
required |
Returns:
| Type | Description |
|---|---|
MembershipFunction
|
A |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a parameter is not finite or |
Examples:
>>> from bulanik.sets import linear_increasing
>>> [linear_increasing(0, 10)(x) for x in (-1, 2.5, 12)]
[0.0, 0.25, 1.0]
linear_decreasing ¶
linear_decreasing(a: float, b: float) -> MembershipFunction
Ramp down: 1 for x <= a, 0 for x >= b, linear in between (a < b).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
float
|
Last point with membership 1. |
required |
b
|
float
|
First point with membership 0. |
required |
Returns:
| Type | Description |
|---|---|
MembershipFunction
|
A |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a parameter is not finite or |
Examples:
>>> from bulanik.sets import linear_decreasing
>>> [linear_decreasing(0, 10)(x) for x in (-1, 2.5, 12)]
[1.0, 0.75, 0.0]
t_norm ¶
t_norm(a: float, b: float, kind: str = 'min') -> float
Fuzzy AND (t-norm): "min" \(\min(a, b)\) or "prod" \(a\,b\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
float
|
Membership degree in \([0, 1]\). |
required |
b
|
float
|
Membership degree in \([0, 1]\). |
required |
kind
|
str
|
|
'min'
|
Returns:
| Type | Description |
|---|---|
float
|
The combined degree. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
>>> from bulanik.sets import t_norm
>>> t_norm(0.3, 0.6), round(t_norm(0.3, 0.6, "prod"), 4)
(0.3, 0.18)
t_conorm ¶
t_conorm(a: float, b: float, kind: str = 'max') -> float
Fuzzy OR (t-conorm): "max" \(\max(a, b)\) or "probor" \(a + b - ab\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
float
|
Membership degree in \([0, 1]\). |
required |
b
|
float
|
Membership degree in \([0, 1]\). |
required |
kind
|
str
|
|
'max'
|
Returns:
| Type | Description |
|---|---|
float
|
The combined degree. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
>>> from bulanik.sets import t_conorm
>>> t_conorm(0.3, 0.6), round(t_conorm(0.3, 0.6, "probor"), 4)
(0.6, 0.72)