Skip to content

bulanik.type2

type2

Interval type-2 fuzzy sets, type reduction and inference.

An interval type-2 membership function (IT2MF) maps \(x\) to an interval \([\underline{\mu}(x), \overline{\mu}(x)]\) of membership degrees, written (lower, upper): the area between the two bounds is the footprint of uncertainty (FOU). The module has

Rules use bulanik.inference for parsing and share its options; a system built from IT2LinguisticVariable.from_type1 variables (no uncertainty) reproduces the type-1 result.

NoLowerFiringError

Bases: ValueError

bmm type reduction needs a positive lower weight and every one is 0.

A ValueError raised by type_reduce and by the interval type-2 systems' evaluate / evaluate_interval / explain when type_reduction="bmm" and no rule fires with certainty (every lower firing is 0). Use "km", "ekm" or "nie_tan" instead.

Examples:

>>> from bulanik.type2 import type_reduce
>>> type_reduce([1, 2], [0, 0], [1, 1], "bmm")
Traceback (most recent call last):
...
bulanik.type2.NoLowerFiringError: bmm needs a positive lower weight somewhere (every lower weight is 0); use 'km', 'ekm' or 'nie_tan' instead

IT2MF dataclass

IT2MF(upper: MembershipFunction, lower: MembershipFunction)

Interval type-2 membership function bounded by two type-1 functions.

Calling mf(x) returns the pair (lower, upper) of membership degrees at x, so \(\underline{\mu}(x) \le \overline{\mu}(x)\). The region between the two bounds is the footprint of uncertainty. A lower above the upper by more than \(10^{-12}\) at some x raises ValueError when that x is evaluated; float noise within that tolerance is clamped.

Parameters:

Name Type Description Default
upper MembershipFunction

The upper membership function \(\overline{\mu}\).

required
lower MembershipFunction

The lower membership function \(\underline{\mu}\).

required

Raises:

Type Description
TypeError

If upper or lower is not a MembershipFunction.

Attributes:

Name Type Description
upper MembershipFunction

The upper membership function.

lower MembershipFunction

The lower membership function.

Examples:

>>> from bulanik.sets import triangular
>>> from bulanik.type2 import IT2MF
>>> mf = IT2MF(upper=triangular(0, 5, 10), lower=triangular(2, 5, 8))
>>> mf(5), mf(3)
((1.0, 1.0), (0.3333333333333333, 0.6))
>>> IT2MF(upper=triangular(2, 5, 8), lower=triangular(0, 5, 10))(1)
Traceback (most recent call last):
...
ValueError: lower membership 0.2 exceeds upper membership 0 at x=1

IT2LinguisticVariable

IT2LinguisticVariable(name: str, universe: tuple[float, float], terms: Mapping[str, IT2MF])

A named variable on a universe (lo, hi) with interval type-2 terms.

The type-2 counterpart of LinguisticVariable; variable["term"] returns the IT2MF.

Parameters:

Name Type Description Default
name str

The variable name, used in rule text.

required
universe tuple[float, float]

The pair (lo, hi) with lo < hi.

required
terms Mapping[str, IT2MF]

Mapping from term name to IT2MF (at least one).

required

Raises:

Type Description
ValueError

If lo >= hi, an end is not finite, or terms is empty.

TypeError

If a term is not an IT2MF.

Attributes:

Name Type Description
name

The variable name.

universe

The domain as a tuple of floats.

term_names tuple[str, ...]

The term names, in insertion order.

Examples:

>>> from bulanik.type2 import IT2LinguisticVariable, scaled_triangle
>>> x = IT2LinguisticVariable("x", (0, 10), {
...     "lo": scaled_triangle(0, 0, 10, 0.5), "hi": scaled_triangle(0, 10, 10, 0.5)})
>>> x
IT2LinguisticVariable('x', (0.0, 10.0), terms=('lo', 'hi'))
>>> x.fuzzify(2)
{'lo': (0.4, 0.8), 'hi': (0.1, 0.2)}

term_names property

term_names: tuple[str, ...]

The term names, in insertion order.

fuzzify

fuzzify(x: float) -> dict[str, Interval]

(lower, upper) 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, Interval]

A dict from term name to the pair (lower, upper), in term order.

Raises:

Type Description
ValueError

If x is not finite or lies outside the universe.

Examples:

>>> from bulanik.type2 import IT2LinguisticVariable, scaled_triangle
>>> x = IT2LinguisticVariable("x", (0, 10), {"mid": scaled_triangle(0, 5, 10, 0.8)})
>>> x.fuzzify(5)
{'mid': (0.8, 1.0)}
>>> x.fuzzify(11)
Traceback (most recent call last):
...
ValueError: 'x' input 11 is outside its universe [0, 10]

from_type1 classmethod

from_type1(lv: LinguisticVariable) -> IT2LinguisticVariable

The type-1 variable as a type-2 one with no uncertainty (lower = upper).

Parameters:

Name Type Description Default
lv LinguisticVariable required

Returns:

Type Description
IT2LinguisticVariable

An IT2LinguisticVariable with the same name, universe and terms,

IT2LinguisticVariable

each term's lower and upper bound being the type-1 function.

Raises:

Type Description
TypeError

If lv is not a LinguisticVariable.

Examples:

>>> from bulanik.sets import LinguisticVariable, linear_decreasing
>>> from bulanik.type2 import IT2LinguisticVariable
>>> lv = LinguisticVariable("x", (0, 10), {"lo": linear_decreasing(0, 10)})
>>> IT2LinguisticVariable.from_type1(lv).fuzzify(2.5)
{'lo': (0.75, 0.75)}

TypeReduced dataclass

TypeReduced(left: float, right: float, output: float, left_switch: int | None, right_switch: int | None)

Type-reduced interval [left, right] and the crisp output.

Returned by type_reduce and, per output variable, by evaluate_interval of the interval type-2 systems.

Parameters:

Name Type Description Default
left float

Left end \(y_l\) of the interval.

required
right float

Right end \(y_r\).

required
output float

The crisp output, the interval midpoint (for bmm, the weighted combination of its two averages).

required
left_switch int | None

KM / EKM switch point of the left end, or None.

required
right_switch int | None

KM / EKM switch point of the right end, or None.

required

Attributes:

Name Type Description
left float

Left end of the interval.

right float

Right end of the interval.

output float

The crisp output.

left_switch int | None

The 1-based position in the y-sorted samples where the left end switches from upper to lower weights, or None for the closed-form reducers (nie_tan, bmm).

right_switch int | None

The same for the right end, where the weights switch from lower to upper instead.

Examples:

>>> from bulanik.type2 import type_reduce
>>> r = type_reduce([1, 2, 3], [0.2, 0.3, 0.1], [0.6, 0.8, 0.5])
>>> (r.left, r.right, r.output, r.left_switch, r.right_switch)
(1.5, 2.3, 1.9, 1, 2)

IT2MamdaniFIS

IT2MamdaniFIS(inputs: Sequence[IT2LinguisticVariable], outputs: Sequence[IT2LinguisticVariable], rules: Sequence[Rule | str], *, and_method: str = 'min', or_method: str = 'max', implication: str = 'min', aggregation: str = 'max', type_reduction: str = 'km', resolution: int = 1001, default: Mapping[str, float | tuple[float, float]] | None = None)

Bases: _IT2Base

Interval type-2 Mamdani system with the centroid type reducer.

Each rule fires with an interval \([\underline{f}_k, \overline{f}_k]\) (the rule weight times the antecedent firing, computed with the lower and upper membership bounds separately; NOT maps \([a, b]\) to \([1 - b, 1 - a]\)). Each output universe is sampled at resolution points \(x_i\). At each sample the upper and lower aggregated sets are

\[\overline{\mu}(x_i) = \operatorname{agg}_k \operatorname{imp}\bigl(\overline{f}_k, \overline{\mu}_{B_k}(x_i)\bigr), \qquad \underline{\mu}(x_i) = \operatorname{agg}_k \operatorname{imp}\bigl(\underline{f}_k, \underline{\mu}_{B_k}(x_i)\bigr),\]

and type_reduce turns the pair into the interval \([y_l, y_r]\) whose midpoint is the output. With lower = upper everywhere it gives exactly the type-1 centroid. If the upper set is zero everywhere no rule fired, and the default is returned or NoRuleFiredError is raised. A default value is a number or a (left, right) pair (the type-reduced interval to report; the output is its midpoint). type_reduction="bmm" additionally needs some rule with a positive lower firing; without one, evaluation raises NoLowerFiringError naming the output.

Parameters:

Name Type Description Default
inputs Sequence[IT2LinguisticVariable] required
outputs Sequence[IT2LinguisticVariable]

Output interval type-2 variables (at least one; names distinct from the inputs).

required
rules Sequence[Rule | str]

Rule objects and/or rule text.

required
and_method str

"min" or "prod".

'min'
or_method str

"max" or "probor".

'max'
implication str

"min" or "prod".

'min'
aggregation str

"max", "sum" or "probor".

'max'
type_reduction str

"km", "ekm", "nie_tan" or "bmm".

'km'
resolution int

Samples per output universe, an integer of at least 2.

1001
default Mapping[str, float | tuple[float, float]] | None

Output value, or (left, right) interval, per output variable, used when no rule fires.

None

Raises:

Type Description
TypeError

If a variable is not an IT2LinguisticVariable or a rule is neither a Rule nor a string.

ValueError

If an option name is unknown, resolution is not an integer of at least 2, there are no inputs, outputs or rules, a variable name is duplicated, a rule names an unknown variable or term, an output term used by a rule has upper membership 0 at every sample, or default is malformed.

Attributes:

Name Type Description
inputs

The input variables (read-only).

outputs

The output variables (read-only).

rules

The parsed rules (read-only).

and_method

The t-norm name.

or_method

The t-conorm name.

implication

The implication name.

aggregation

The aggregation name.

type_reduction

The type reduction method.

resolution

Samples per output universe.

default

A copy of the no-fire defaults, or None.

Examples:

>>> from bulanik.type2 import IT2LinguisticVariable, IT2MamdaniFIS, scaled_triangle
>>> x = IT2LinguisticVariable("x", (0, 10), {
...     "lo": scaled_triangle(0, 0, 10, 0.5), "hi": scaled_triangle(0, 10, 10, 0.5)})
>>> tip = IT2LinguisticVariable("tip", (0, 20), {
...     "low": scaled_triangle(0, 0, 10, 0.6), "high": scaled_triangle(10, 20, 20, 0.6)})
>>> fis = IT2MamdaniFIS([x], [tip], [
...     "IF x IS lo THEN tip IS low", "IF x IS hi THEN tip IS high"], resolution=201)
>>> fis.evaluate({"x": 7})
{'tip': 12.01...}
>>> r = fis.evaluate_interval({"x": 7})["tip"]
>>> round(r.left, 2), round(r.right, 2)
(10.2, 13.83)

Without uncertainty the system gives the type-1 answer:

>>> from bulanik.sets import LinguisticVariable, triangular
>>> from bulanik.inference import MamdaniFIS
>>> t1x = LinguisticVariable("x", (0, 10), {"lo": triangular(0, 0, 10), "hi": triangular(0, 10, 10)})
>>> t1y = LinguisticVariable("tip", (0, 20), {"low": triangular(0, 0, 10), "high": triangular(10, 20, 20)})
>>> rules = ["IF x IS lo THEN tip IS low", "IF x IS hi THEN tip IS high"]
>>> type1 = MamdaniFIS([t1x], [t1y], rules, resolution=201).evaluate({"x": 7})
>>> type2 = IT2MamdaniFIS([IT2LinguisticVariable.from_type1(t1x)],
...                       [IT2LinguisticVariable.from_type1(t1y)], rules,
...                       resolution=201).evaluate({"x": 7})
>>> abs(type1["tip"] - type2["tip"]) < 1e-9
True
References

Mendel (2001): Uncertain Rule-Based Fuzzy Logic Systems: Introduction and New Directions.

evaluate_interval

evaluate_interval(inputs: Mapping[str, float]) -> dict[str, TypeReduced]

Type-reduced interval and crisp output of every output variable.

Parameters:

Name Type Description Default
inputs Mapping[str, float]

Crisp value of every input variable, by name. The keys must be exactly the input names and each value inside its universe.

required

Returns:

Type Description
dict[str, TypeReduced]

A dict from output variable name to its

dict[str, TypeReduced]

Raises:

Type Description
TypeError

If a value is a bool or a string.

ValueError

If an input is missing, unexpected, not finite or outside its universe.

NoRuleFiredError

If no rule fires for an output and there is no default.

NoLowerFiringError

If type_reduction="bmm" and no rule has a positive lower firing.

Examples:

>>> from bulanik.type2 import IT2LinguisticVariable, IT2SugenoFIS, scaled_triangle
>>> from bulanik.inference import SugenoOutput
>>> x = IT2LinguisticVariable("x", (0, 10), {
...     "lo": scaled_triangle(0, 0, 10, 0.5), "hi": scaled_triangle(0, 10, 10, 0.5)})
>>> y = SugenoOutput("y", {"a": 0.0, "b": 10.0})
>>> fis = IT2SugenoFIS([x], [y], ["IF x IS lo THEN y IS a", "IF x IS hi THEN y IS b"])
>>> r = fis.evaluate_interval({"x": 7})["y"]
>>> round(r.left, 3), round(r.right, 3), round(r.output, 3)
(5.385, 8.235, 6.81)

evaluate

evaluate(inputs: Mapping[str, float]) -> dict[str, float]

Crisp outputs (the type-reduced output) for crisp inputs.

Parameters:

Name Type Description Default
inputs Mapping[str, float]

Crisp value of every input variable, by name.

required

Returns:

Type Description
dict[str, float]

A dict from output variable name to its crisp value.

Raises:

Type Description
TypeError

If a value is a bool or a string.

ValueError

If an input is missing, unexpected, not finite or outside its universe.

NoRuleFiredError

If no rule fires for an output and there is no default.

NoLowerFiringError

If type_reduction="bmm" and no rule has a positive lower firing.

Examples:

>>> from bulanik.type2 import IT2LinguisticVariable, IT2SugenoFIS, scaled_triangle
>>> from bulanik.inference import SugenoOutput
>>> x = IT2LinguisticVariable("x", (0, 10), {
...     "lo": scaled_triangle(0, 0, 10, 0.5), "hi": scaled_triangle(0, 10, 10, 0.5)})
>>> y = SugenoOutput("y", {"a": 0.0, "b": 10.0})
>>> rules = ["IF x IS lo THEN y IS a", "IF x IS hi THEN y IS b"]
>>> IT2SugenoFIS([x], [y], rules, type_reduction="nie_tan").evaluate({"x": 7})
{'y': 7.0}

explain

explain(inputs: Mapping[str, float]) -> Explanation

Degrees (lower, upper), rule firing intervals and crisp outputs.

Parameters:

Name Type Description Default
inputs Mapping[str, float]

Crisp value of every input variable, by name.

required

Returns:

Type Description
Explanation

An Explanation whose

Explanation

degrees and rule activations hold (lower, upper) pairs and

Explanation

whose outputs are the crisp (type-reduced) outputs.

Raises:

Type Description
TypeError

If a value is a bool or a string.

ValueError

If an input is missing, unexpected, not finite or outside its universe.

NoRuleFiredError

If no rule fires for an output and there is no default.

NoLowerFiringError

If type_reduction="bmm" and no rule has a positive lower firing.

Examples:

>>> from bulanik.type2 import IT2LinguisticVariable, IT2SugenoFIS, scaled_triangle
>>> from bulanik.inference import SugenoOutput
>>> x = IT2LinguisticVariable("x", (0, 10), {
...     "lo": scaled_triangle(0, 0, 10, 0.5), "hi": scaled_triangle(0, 10, 10, 0.5)})
>>> y = SugenoOutput("y", {"a": 0.0, "b": 10.0})
>>> fis = IT2SugenoFIS([x], [y], ["IF x IS lo THEN y IS a", "IF x IS hi THEN y IS b"])
>>> info = fis.explain({"x": 7})
>>> info.degrees["x"]
{'lo': (0.15, 0.3), 'hi': (0.35, 0.7)}
>>> info.activations[1].strength
(0.35, 0.7)

IT2SugenoFIS

IT2SugenoFIS(inputs: Sequence[IT2LinguisticVariable], outputs: Sequence[SugenoOutput], rules: Sequence[Rule | str], *, and_method: str = 'min', or_method: str = 'max', type_reduction: str = 'km', default: Mapping[str, float | tuple[float, float]] | None = None)

Bases: _IT2Base

Interval type-2 Sugeno system with the centre-of-sets type reducer.

Each fired rule \(k\) gives \(z_k\) (a constant or a Linear of the inputs) with firing interval \([\underline{f}_k, \overline{f}_k]\); the type-reduced interval is type_reduce([z_k], [f_lower_k], [f_upper_k]) and the output its midpoint. When no rule fires for an output (all upper firings are 0) the default (a number or a (left, right) pair) is returned or NoRuleFiredError is raised. type_reduction="bmm" needs some positive lower firing, else NoLowerFiringError is raised.

Parameters:

Name Type Description Default
inputs Sequence[IT2LinguisticVariable] required
outputs Sequence[SugenoOutput]

SugenoOutputs (at least one; names distinct from the inputs).

required
rules Sequence[Rule | str]

Rule objects and/or rule text.

required
and_method str

"min" or "prod".

'min'
or_method str

"max" or "probor".

'max'
type_reduction str

"km", "ekm", "nie_tan" or "bmm".

'km'
default Mapping[str, float | tuple[float, float]] | None

Output value, or (left, right) interval, per output variable, used when no rule fires.

None

Raises:

Type Description
TypeError

If a variable has the wrong class or a rule is neither a Rule nor a string.

ValueError

If an option name is unknown, there are no inputs, outputs or rules, a variable name is duplicated, a rule names an unknown variable or term, a Linear names an unknown input, or default is malformed.

Attributes:

Name Type Description
inputs

The input variables (read-only).

outputs

The output variables (read-only).

rules

The parsed rules (read-only).

and_method

The t-norm name.

or_method

The t-conorm name.

type_reduction

The type reduction method.

default

A copy of the no-fire defaults, or None.

Examples:

>>> from bulanik.type2 import IT2LinguisticVariable, IT2SugenoFIS, scaled_triangle
>>> from bulanik.inference import SugenoOutput
>>> x = IT2LinguisticVariable("x", (0, 10), {
...     "lo": scaled_triangle(0, 0, 10, 0.5), "hi": scaled_triangle(0, 10, 10, 0.5)})
>>> y = SugenoOutput("y", {"a": 0.0, "b": 10.0})
>>> fis = IT2SugenoFIS([x], [y], ["IF x IS lo THEN y IS a", "IF x IS hi THEN y IS b"])
>>> fis.evaluate({"x": 7})
{'y': 6.809...}
>>> fis.evaluate_interval({"x": 7})["y"].left_switch
1

evaluate_interval

evaluate_interval(inputs: Mapping[str, float]) -> dict[str, TypeReduced]

Type-reduced interval and crisp output of every output variable.

Parameters:

Name Type Description Default
inputs Mapping[str, float]

Crisp value of every input variable, by name. The keys must be exactly the input names and each value inside its universe.

required

Returns:

Type Description
dict[str, TypeReduced]

A dict from output variable name to its

dict[str, TypeReduced]

Raises:

Type Description
TypeError

If a value is a bool or a string.

ValueError

If an input is missing, unexpected, not finite or outside its universe.

NoRuleFiredError

If no rule fires for an output and there is no default.

NoLowerFiringError

If type_reduction="bmm" and no rule has a positive lower firing.

Examples:

>>> from bulanik.type2 import IT2LinguisticVariable, IT2SugenoFIS, scaled_triangle
>>> from bulanik.inference import SugenoOutput
>>> x = IT2LinguisticVariable("x", (0, 10), {
...     "lo": scaled_triangle(0, 0, 10, 0.5), "hi": scaled_triangle(0, 10, 10, 0.5)})
>>> y = SugenoOutput("y", {"a": 0.0, "b": 10.0})
>>> fis = IT2SugenoFIS([x], [y], ["IF x IS lo THEN y IS a", "IF x IS hi THEN y IS b"])
>>> r = fis.evaluate_interval({"x": 7})["y"]
>>> round(r.left, 3), round(r.right, 3), round(r.output, 3)
(5.385, 8.235, 6.81)

evaluate

evaluate(inputs: Mapping[str, float]) -> dict[str, float]

Crisp outputs (the type-reduced output) for crisp inputs.

Parameters:

Name Type Description Default
inputs Mapping[str, float]

Crisp value of every input variable, by name.

required

Returns:

Type Description
dict[str, float]

A dict from output variable name to its crisp value.

Raises:

Type Description
TypeError

If a value is a bool or a string.

ValueError

If an input is missing, unexpected, not finite or outside its universe.

NoRuleFiredError

If no rule fires for an output and there is no default.

NoLowerFiringError

If type_reduction="bmm" and no rule has a positive lower firing.

Examples:

>>> from bulanik.type2 import IT2LinguisticVariable, IT2SugenoFIS, scaled_triangle
>>> from bulanik.inference import SugenoOutput
>>> x = IT2LinguisticVariable("x", (0, 10), {
...     "lo": scaled_triangle(0, 0, 10, 0.5), "hi": scaled_triangle(0, 10, 10, 0.5)})
>>> y = SugenoOutput("y", {"a": 0.0, "b": 10.0})
>>> rules = ["IF x IS lo THEN y IS a", "IF x IS hi THEN y IS b"]
>>> IT2SugenoFIS([x], [y], rules, type_reduction="nie_tan").evaluate({"x": 7})
{'y': 7.0}

explain

explain(inputs: Mapping[str, float]) -> Explanation

Degrees (lower, upper), rule firing intervals and crisp outputs.

Parameters:

Name Type Description Default
inputs Mapping[str, float]

Crisp value of every input variable, by name.

required

Returns:

Type Description
Explanation

An Explanation whose

Explanation

degrees and rule activations hold (lower, upper) pairs and

Explanation

whose outputs are the crisp (type-reduced) outputs.

Raises:

Type Description
TypeError

If a value is a bool or a string.

ValueError

If an input is missing, unexpected, not finite or outside its universe.

NoRuleFiredError

If no rule fires for an output and there is no default.

NoLowerFiringError

If type_reduction="bmm" and no rule has a positive lower firing.

Examples:

>>> from bulanik.type2 import IT2LinguisticVariable, IT2SugenoFIS, scaled_triangle
>>> from bulanik.inference import SugenoOutput
>>> x = IT2LinguisticVariable("x", (0, 10), {
...     "lo": scaled_triangle(0, 0, 10, 0.5), "hi": scaled_triangle(0, 10, 10, 0.5)})
>>> y = SugenoOutput("y", {"a": 0.0, "b": 10.0})
>>> fis = IT2SugenoFIS([x], [y], ["IF x IS lo THEN y IS a", "IF x IS hi THEN y IS b"])
>>> info = fis.explain({"x": 7})
>>> info.degrees["x"]
{'lo': (0.15, 0.3), 'hi': (0.35, 0.7)}
>>> info.activations[1].strength
(0.35, 0.7)

gaussian_uncertain_mean

gaussian_uncertain_mean(mean_low: float, mean_high: float, sigma: float) -> IT2MF

Gaussian with a mean anywhere in \([m_1, m_2]\) (Mendel 2001).

With \(g(x; m) = \exp\bigl(-(x - m)^2 / (2\sigma^2)\bigr)\), the upper bound is 1 on \([m_1, m_2]\) and the Gaussian of the nearer mean outside it; the lower bound is \(\min\bigl(g(x; m_1), g(x; m_2)\bigr)\).

Parameters:

Name Type Description Default
mean_low float

Left end \(m_1\) of the mean interval.

required
mean_high float

Right end \(m_2\), with \(m_1 \le m_2\).

required
sigma float

Common standard deviation, positive.

required

Returns:

Type Description
IT2MF

The interval type-2 membership function.

Raises:

Type Description
ValueError

If mean_low > mean_high, sigma <= 0 or a value is not finite.

Examples:

>>> from bulanik.type2 import gaussian_uncertain_mean
>>> mf = gaussian_uncertain_mean(4, 6, 1.5)
>>> mf(5)
(0.800..., 1.0)
>>> mf(8)
(0.0285..., 0.411...)
References

Mendel (2001): Uncertain Rule-Based Fuzzy Logic Systems: Introduction and New Directions.

gaussian_uncertain_sigma

gaussian_uncertain_sigma(mean: float, sigma_low: float, sigma_high: float) -> IT2MF

Gaussian with a width anywhere in \([\sigma_1, \sigma_2]\).

The upper bound is the Gaussian with \(\sigma_2\) and the lower bound the Gaussian with \(\sigma_1\), both with the same mean.

Parameters:

Name Type Description Default
mean float

The centre.

required
sigma_low float

Smallest width \(\sigma_1\), positive.

required
sigma_high float

Largest width \(\sigma_2\), with \(\sigma_1 \le \sigma_2\).

required

Returns:

Type Description
IT2MF

The interval type-2 membership function.

Raises:

Type Description
ValueError

If 0 < sigma_low <= sigma_high does not hold, or a value is not finite.

Examples:

>>> from bulanik.type2 import gaussian_uncertain_sigma
>>> mf = gaussian_uncertain_sigma(5, 1, 2)
>>> mf(6)
(0.606..., 0.882...)
>>> gaussian_uncertain_sigma(5, 2, 1)
Traceback (most recent call last):
...
ValueError: gaussian_uncertain_sigma needs 0 < sigma_low <= sigma_high, got 2, 1

scaled_triangle

scaled_triangle(a: float, b: float, c: float, height: float) -> IT2MF

Triangle \(\operatorname{tri}(a, b, c)\) over a lower triangle \(h \cdot \operatorname{tri}(a, b, c)\).

The upper bound is the triangular function with feet a, c and peak b; the lower bound is the same triangle scaled to height \(h\), \(0 < h \le 1\).

Parameters:

Name Type Description Default
a float

Left foot.

required
b float

Peak.

required
c float

Right foot, with a <= b <= c and a < c.

required
height float

Height \(h\) of the lower triangle, in \((0, 1]\).

required

Returns:

Type Description
IT2MF

The interval type-2 membership function.

Raises:

Type Description
ValueError

If the points are not ordered or height is outside \((0, 1]\).

Examples:

>>> from bulanik.type2 import scaled_triangle
>>> mf = scaled_triangle(0, 5, 10, 0.6)
>>> mf(5), mf(2.5)
((0.6, 1.0), (0.3, 0.5))

type_reduce

type_reduce(ys: Sequence[float], lower: Sequence[float], upper: Sequence[float], method: str = 'km', *, bmm_m: float = 0.5, bmm_n: float = 0.5) -> TypeReduced

Reduce points ys with interval weights [lower, upper] to a crisp value.

Each point \(y_i\) may carry any weight \(w_i \in [\underline{w}_i, \overline{w}_i]\). The centroid interval is

\[[y_l, y_r], \qquad y_l = \min_{w} \frac{\sum_i y_i w_i}{\sum_i w_i}, \quad y_r = \max_{w} \frac{\sum_i y_i w_i}{\sum_i w_i},\]

and the methods are

  • "km" (Karnik and Mendel 2001) and "ekm" (enhanced KM, Wu and Mendel 2009) find the exact \([y_l, y_r]\); the output is its midpoint. Both converge to the same endpoints, but only up to rounding (about 1 ulp), and on plateaus (equal ys or equal weights) they may stop at different, equally optimal switch indices.
  • "nie_tan" (Nie and Tan 2008) is the closed form \(\sum_i y_i (\underline{w}_i + \overline{w}_i) / \sum_i (\underline{w}_i + \overline{w}_i)\), with left == right == output.
  • "bmm" (Begian, Melek and Mendel 2008) is \(m\,\bar y_{\text{lower}} + n\,\bar y_{\text{upper}}\), the combination of the weighted averages with the lower and with the upper weights; left / right are the two averages, sorted. bmm_m and bmm_n only have to be finite: they are deliberately unconstrained (the usual choice is \(m = n = 0.5\), but neither sign nor \(m + n = 1\) is enforced, so the output may fall outside [left, right]). It needs some positive lower weight.

Parameters:

Name Type Description Default
ys Sequence[float]

The points.

required
lower Sequence[float]

Lower weight of each point.

required
upper Sequence[float]

Upper weight of each point.

required
method str

"km", "ekm", "nie_tan" or "bmm".

'km'
bmm_m float

Factor \(m\) of the lower average ("bmm" only).

0.5
bmm_n float

Factor \(n\) of the upper average ("bmm" only).

0.5

Returns:

Type Description
TypeReduced

A TypeReduced with the interval and the

TypeReduced

crisp output.

Raises:

Type Description
TypeError

If a point or weight is a bool or a string.

ValueError

If method is unknown, the lengths differ, a value is not finite, a weight is negative, a lower weight exceeds its upper weight (by more than \(10^{-12}\)), or all upper weights are zero.

NoLowerFiringError

If method="bmm" and every lower weight is zero (a ValueError).

Examples:

>>> from bulanik.type2 import type_reduce
>>> ys, lo, hi = [1, 2, 3], [0.2, 0.3, 0.1], [0.6, 0.8, 0.5]
>>> r = type_reduce(ys, lo, hi)
>>> (r.left, r.right, r.output)
(1.5, 2.3, 1.9)
>>> type_reduce(ys, lo, hi, "nie_tan").output
1.92
>>> type_reduce(ys, [0.5] * 3, [0.5] * 3).output
2.0
References

Karnik and Mendel (2001): "Centroid of a type-2 fuzzy set", Information Sciences. Wu and Mendel (2009): "Enhanced Karnik-Mendel algorithms", IEEE Transactions on Fuzzy Systems. Nie and Tan (2008): "Towards an efficient type-reduction method for interval type-2 fuzzy logic systems", FUZZ-IEEE. Begian, Melek and Mendel (2008): "Stability analysis of type-2 fuzzy systems", IEEE International Conference on Fuzzy Systems (FUZZ-IEEE), 947-953 (the BMM reducer).