Skip to content

bulanik.aggregate

aggregate

Weighted aggregation: weighted average (WA), weighted geometric (WG), experts.

wa and wg combine fuzzy numbers of one type with non-negative weights summing to 1, using the type's own operators (scale / add for the average, power / mul for the geometric mean). aggregate_experts applies one of them to a stack of expert rating matrices, cell by cell.

All functions require the inputs to be of one class (and rung, for orthopair numbers); mixing types raises TypeError.

wa

wa(values: Sequence[FuzzyNumber], weights: Sequence[float] | None = None, *, ops: str = 'algebraic', normalize: bool = False) -> FuzzyNumber

Weighted average \(\sum_i w_i A_i\) with the type's own operators.

Computed as scale of each number by its weight, folded with add. For triangular numbers this is the componentwise weighted mean of the points; for intuitionistic numbers it is the classic IFWA operator \(\left(1 - \prod_i (1 - \mu_i)^{w_i},\; \prod_i \nu_i^{w_i}\right)\). Picture numbers use the closed form \(\left(1 - \prod_i (1 - \mu_i)^{w_i},\; \prod_i \eta_i^{w_i},\; \prod_i \nu_i^{w_i}\right)\), because scaling by a weight below 1 is not closed for them.

weights=None means equal weights \(1/n\). Weights must be non-negative and sum to 1 unless normalize=True (then they are divided by their sum); weights that sum to 1 only within \(10^{-9}\) are accepted and silently rescaled to sum to exactly 1. Inputs with a weight of 0 are ignored.

Parameters:

Name Type Description Default
values Sequence[FuzzyNumber]

Fuzzy numbers of one type (and rung).

required
weights Sequence[float] | None

One weight per value, or None for equal weights.

None
ops str

Operator set of the type, "algebraic" or (orthopair) "einstein".

'algebraic'
normalize bool

Divide the weights by their sum instead of requiring sum 1.

False

Returns:

Type Description
FuzzyNumber

The aggregated number, of the type of the inputs.

Raises:

Type Description
ValueError

If values is empty, the number of weights differs, a weight is negative or not finite, the weights do not sum to 1 (and normalize is false) or are all zero (with normalize), or ops is unsupported.

TypeError

If the values are not fuzzy numbers or differ in type.

References

Xu (2007), IEEE Transactions on Fuzzy Systems 15(6): intuitionistic fuzzy aggregation operators. Wei (2017) for the picture closed forms (retracted by the publisher in 2025; the closed forms are tested against the code, not the paper).

Examples:

>>> from bulanik import TFN, IFN
>>> from bulanik.aggregate import wa
>>> wa([TFN(1, 2, 4), TFN(2, 3, 5)])
TFN(l=1.5, m=2.5, u=4.5)
>>> r = wa([IFN(0.6, 0.3), IFN(0.5, 0.4)], [2, 1], normalize=True)
>>> round(r.mu, 4), round(r.nu, 4)
(0.5691, 0.3302)
>>> wa([TFN(1, 2, 4), TFN(2, 3, 5)], [0.5, 0.2])
Traceback (most recent call last):
...
ValueError: weights must sum to 1, got 0.7

wg

wg(values: Sequence[FuzzyNumber], weights: Sequence[float] | None = None, *, ops: str = 'algebraic', normalize: bool = False) -> FuzzyNumber

Weighted geometric mean \(\prod_i A_i^{w_i}\) with the type's own operators.

Computed as power of each number by its weight, folded with mul. For positive triangular numbers this is the componentwise weighted geometric mean of the points. Weights, normalize and ops behave as in wa. Picture numbers use closed forms \(\left(\prod_i (\mu_i + \eta_i)^{w_i} - \prod_i \eta_i^{w_i},\; \prod_i \eta_i^{w_i},\; 1 - \prod_i (1 - \nu_i)^{w_i}\right)\).

Parameters:

Name Type Description Default
values Sequence[FuzzyNumber]

Fuzzy numbers of one type (and rung).

required
weights Sequence[float] | None

One weight per value, or None for equal weights.

None
ops str

Operator set of the type, "algebraic" or (orthopair) "einstein".

'algebraic'
normalize bool

Divide the weights by their sum instead of requiring sum 1.

False

Returns:

Type Description
FuzzyNumber

The aggregated number, of the type of the inputs.

Raises:

Type Description
ValueError

As for wa; additionally, for triangular numbers with a negative lowest point.

TypeError

If the values are not fuzzy numbers or differ in type.

References

Xu and Yager (2006), International Journal of General Systems 35(4): intuitionistic fuzzy geometric aggregation operators.

Examples:

>>> from bulanik import TFN
>>> from bulanik.aggregate import wg
>>> r = wg([TFN(1, 2, 4), TFN(2, 3, 5)])
>>> round(r.l, 4), round(r.m, 4), round(r.u, 4)
(1.4142, 2.4495, 4.4721)

aggregate_experts

aggregate_experts(ratings: Sequence[Sequence[Sequence[FuzzyNumber]]], weights: Sequence[float] | None = None, *, method: str = 'wa', ops: str = 'algebraic', normalize: bool = False) -> list[list[FuzzyNumber]]

Aggregate expert ratings indexed [expert][alternative][criterion].

For every alternative-criterion cell the experts' numbers are combined with wa or wg using the expert weights.

Parameters:

Name Type Description Default
ratings Sequence[Sequence[Sequence[FuzzyNumber]]]

One matrix per expert; each is a list (alternatives) of lists (criteria) of fuzzy numbers, all of the same shape and type.

required
weights Sequence[float] | None

One weight per expert, or None for equal weights.

None
method str

"wa" (default) or "wg".

'wa'
ops str

Operator set of the number type.

'algebraic'
normalize bool

Divide the expert weights by their sum instead of requiring sum 1.

False

Returns:

Type Description
list[list[FuzzyNumber]]

The [alternative][criterion] matrix of aggregated numbers.

Raises:

Type Description
ValueError

If method is unknown, there are no experts, the matrices differ in shape, or the weights are invalid (see wa).

TypeError

If the numbers differ in type.

Examples:

>>> from bulanik import TFN
>>> from bulanik.aggregate import aggregate_experts
>>> a, b = TFN(1, 2, 4), TFN(2, 3, 5)
>>> experts = [[[a, b]], [[b, a]]]  # 2 experts, 1 alternative, 2 criteria
>>> aggregate_experts(experts)
[[TFN(l=1.5, m=2.5, u=4.5), TFN(l=1.5, m=2.5, u=4.5)]]