API reference¶
Generated from docstrings with mkdocstrings.
Membership functions¶
fuzzytool.membership ¶
Membership functions.
Every membership function (MF) is a callable mapping a crisp value (scalar or
NumPy array) to a membership degree in [0, 1]. The :class:MembershipFunction
Protocol is the only contract the rest of the library relies on: the inference
engine never inspects a concrete MF type, so a new shape = a new callable, with
no changes to the core (mirroring the "one variant = one impl" design of the
sibling project turboswarm).
The lowercase factory functions (:func:tri, :func:trap, :func:gauss,
:func:gbell, :func:sigmoid) are the public API; they return small classes so
the parameters stay introspectable for visualization and serialization.
MembershipFunction ¶
Bases: Protocol
A callable x -> degree with membership degrees in [0, 1].
Triangular ¶
Triangular MF with feet at a/c and peak at b.
Trapezoidal ¶
Trapezoidal MF; flat top between b and c.
Gaussian ¶
Gaussian MF centered at c with spread sigma.
GeneralizedBell ¶
Generalized bell MF: 1 / (1 + |(x - c) / a|^(2b)).
Sigmoid ¶
Sigmoidal MF: 1 / (1 + exp(-a (x - c))). Monotonic (invertible).
RampUp ¶
Monotonically increasing ramp: 0 below a, 1 above b.
RampDown ¶
Monotonically decreasing ramp: 1 below a, 0 above b.
trap ¶
Trapezoidal MF: shoulders a/d, flat top b..c.
gbell ¶
Generalized bell MF: width a, slope b, center c.
ramp_up ¶
Increasing ramp MF from 0 at a to 1 at b (monotonic).
ramp_down ¶
Decreasing ramp MF from 1 at a to 0 at b (monotonic).
Connectives (t-norms / s-norms)¶
fuzzytool.norms ¶
Fuzzy connectives: t-norms (AND) and s-norms / t-conorms (OR).
Connectives are plain vectorized callables (a, b) -> result operating
elementwise on membership degrees. They are pluggable: the inference engines
look them up by name through :func:get_tnorm / :func:get_snorm, so adding a
connective means registering one function — the engine never changes.
Sets, variables, and rule antecedents¶
fuzzytool.sets ¶
Fuzzy sets, linguistic variables, and the rule-antecedent expression tree.
A :class:Variable is a linguistic variable: a named universe of discourse plus
a dictionary of terms (named membership functions). Indexing a variable with a
term name (score["good"]) returns a :class:Proposition, the atom of a
rule antecedent. Propositions compose with Python operators:
score["poor"] | dti["high"] # OR (s-norm)
score["good"] & dti["low"] # AND (t-norm)
~dti["high"] # NOT (complement)
The result is a small expression tree that the inference engine evaluates
against crisp inputs to get a firing strength. The same atom doubles as a rule
consequent (premium["high"]), so there is a single concept to learn.
Antecedent ¶
Base node of a rule-antecedent expression tree.
Proposition ¶
Variable ¶
A linguistic variable: a named universe with named fuzzy-set terms.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
identifier; rule inputs are matched to variables by this name. |
required |
universe
|
tuple[float, float]
|
|
required |
terms
|
Iterable[str] | Mapping[str, MembershipFunction] | None
|
optional list of term names to auto-generate evenly across the
universe, or a mapping |
None
|
kind
|
str
|
shape used by auto-generation ( |
'triangular'
|
resolution
|
int
|
number of samples used to discretize the universe for Mamdani defuzzification. |
501
|
auto_terms ¶
Generate evenly-spaced terms named names across the universe.
to_dict ¶
Serialize this variable (universe + terms) to a JSON-ready dict.
Only built-in membership functions can be serialized (see
:func:fuzzytool.membership.to_dict).
from_dict
classmethod
¶
Rebuild a variable from :meth:to_dict output.
antecedent_from_dict ¶
Rebuild an antecedent tree from :meth:Antecedent.to_dict output.
variables maps variable names to the :class:Variable instances the
propositions should reference.
Rules¶
fuzzytool.rules ¶
Fuzzy rules shared by the inference engines.
A :class:Rule pairs an antecedent expression with a consequent and an optional
weight. The consequent is interpreted by the engine: Mamdani expects a
:class:~fuzzytool.sets.Proposition (output is term); TSK expects a
constant or a linear coefficient vector.
Rule
dataclass
¶
IF antecedent THEN consequent with an optional firing weight.
Defuzzification¶
fuzzytool.defuzz ¶
Defuzzification: collapse an aggregated output set into a crisp value.
Each defuzzifier takes the discretized universe x and the aggregated
membership y (same shape) and returns a scalar. They are looked up by name
through :func:get_defuzzifier, so adding a method = registering a function.
centroid ¶
Center of gravity of the area under y (the most common choice).
bisector ¶
Abscissa that splits the area under y into two equal halves.
centroid_batch ¶
Vectorized :func:centroid over the rows of Y.
bisector_batch ¶
Vectorized :func:bisector over the rows of Y.
get_batch_defuzzifier ¶
Return the vectorized form of a defuzzifier, or None if it has none.
get_defuzzifier ¶
Resolve a defuzzifier by name (or pass a callable through unchanged).
Inference — Mamdani¶
fuzzytool.inference.mamdani ¶
Mamdani fuzzy inference.
The engine knows nothing about specific membership functions, connectives, or
defuzzifiers: t-norm, s-norm, implication, aggregation and defuzzification are
all resolved by name (or supplied as callables) and applied uniformly. Adding a
behavior means registering a function in :mod:fuzzytool.norms or
:mod:fuzzytool.defuzz, never editing this loop.
Pipeline per call: evaluate each rule's antecedent to a firing strength → shape its consequent term over the output universe via the implication operator → aggregate the shaped sets per output variable → defuzzify.
Mamdani ¶
A Mamdani inference system.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tnorm
|
str | Callable
|
t-norm for AND in antecedents (default |
'min'
|
snorm
|
str | Callable
|
s-norm for OR in antecedents (default |
'max'
|
implication
|
str
|
how a firing strength shapes its consequent set —
|
'min'
|
aggregation
|
str | Callable
|
s-norm combining shaped sets per output (default |
'max'
|
defuzz
|
str | Callable
|
defuzzification method (default |
'centroid'
|
on_no_rule
|
str
|
crisp value for an output when no rule fires — |
'mid'
|
rule ¶
Add IF antecedent THEN output is term and return self.
__call__ ¶
Run inference. Returns a float for one output, else a dict by name.
predict ¶
Vectorized inference over array-valued inputs.
Each keyword is an array of n samples. Returns an array of length
n for a single output, else a dict of arrays. Equivalent to calling
the system once per sample, but evaluated in batch.
Inference — Takagi-Sugeno (TSK)¶
fuzzytool.inference.tsk ¶
Takagi-Sugeno-Kang (TSK) fuzzy inference.
Consequents are crisp functions of the inputs rather than fuzzy sets, so there is no defuzzification: the output is the firing-weighted average of the rule consequents. A consequent may be
- a number — zero-order (Sugeno constant), e.g.
5.0; - a mapping
{"const": b0, "x": b1, ...}— first-order linear in the inputs; - any callable
f(**inputs) -> float— arbitrary.
TSK ¶
A (zero- or first-order) Takagi-Sugeno inference system.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tnorm
|
str | Callable
|
t-norm for AND in antecedents (default |
'min'
|
snorm
|
str | Callable
|
s-norm for OR in antecedents (default |
'max'
|
on_no_rule
|
str
|
what to return when no rule fires — |
'nan'
|
rule ¶
Add IF antecedent THEN output = consequent and return self.
__call__ ¶
Run inference, returning the firing-weighted average output.
predict ¶
Vectorized inference over array-valued inputs (n per keyword).
Returns an array of length n. Samples where no rule fires follow
on_no_rule: nan (default) or a raised ValueError.
Inference — Tsukamoto¶
fuzzytool.inference.tsukamoto ¶
Tsukamoto fuzzy inference.
In a Tsukamoto system every rule's consequent is a monotonic membership
function. A rule firing with strength w produces the crisp value at which
its consequent reaches w (the inverse of the monotonic MF). The system
output is the firing-weighted average of those crisp values — so, like TSK,
there is no defuzzification step.
Consequents must expose inverse(degree) -> value; the built-in
:func:~fuzzytool.membership.ramp_up, :func:~fuzzytool.membership.ramp_down
and :func:~fuzzytool.membership.sigmoid do.
Tsukamoto ¶
A Tsukamoto inference system (monotonic consequents).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tnorm
|
str | Callable
|
t-norm for AND in antecedents (default |
'min'
|
snorm
|
str | Callable
|
s-norm for OR in antecedents (default |
'max'
|
on_no_rule
|
str
|
what to return when no rule fires — |
'nan'
|
Rule learning (Wang-Mendel)¶
fuzzytool.learn ¶
Learning fuzzy rule bases from data.
:func:wang_mendel implements the classic Wang-Mendel (1992) method: it turns
each training sample into one fuzzy rule (picking, per variable, the term with
the highest membership), assigns the rule a degree equal to the product of those
memberships, and resolves antecedent conflicts by keeping the highest-degree
consequent. The result is a ready-to-use :class:~fuzzytool.inference.Mamdani.
wang_mendel ¶
Generate a Mamdani rule base from data with the Wang-Mendel method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
inputs, shape |
required |
y
|
ndarray
|
targets, shape |
required |
inputs
|
list[Variable]
|
the input linguistic variables (each pre-populated with terms);
column |
required |
output
|
Variable
|
the output linguistic variable (pre-populated with terms). |
required |
Returns:
| Name | Type | Description |
|---|---|---|
A |
Mamdani
|
class: |
Mamdani
|
antecedent (conflicts resolved by rule degree). |
Fuzzy numbers¶
fuzzytool.fuzzynum ¶
Fuzzy numbers and their arithmetic.
A fuzzy number is a convex, normal fuzzy set on the reals. This module provides
the two most used shapes — triangular (TFN) and trapezoidal (TrFN) — with
standard fuzzy arithmetic (+ - * / and scalar scaling), alpha-cuts, a crisp
(centroid) value, and a vertex distance used by fuzzy MCDM (see
:mod:fuzzytool.mcdm).
Multiplication and division use the common positive-support approximation
(operate on the ordered defining points), which is exact for +/- and a
good approximation for *// when supports are positive.
FuzzyNumber ¶
Base class for fuzzy numbers defined by ordered points p.
distance ¶
Vertex distance to another fuzzy number of the same shape.
TriangularFuzzyNumber ¶
TrapezoidalFuzzyNumber ¶
tfn ¶
Shortcut for :class:TriangularFuzzyNumber.
trfn ¶
Shortcut for :class:TrapezoidalFuzzyNumber.
rank ¶
Indices that sort numbers from largest to smallest by centroid.
Fuzzy MCDM¶
fuzzytool.mcdm ¶
Fuzzy multi-criteria decision making (MCDM).
- :func:
fuzzy_topsis— Chen's (2000) fuzzy TOPSIS: rank alternatives by their closeness to the fuzzy positive-ideal solution. - :func:
fuzzy_ahp— Chang's (1996) extent-analysis AHP: derive crisp criterion weights from a triangular-fuzzy pairwise-comparison matrix.
Inputs are triangular fuzzy numbers (:class:~fuzzytool.fuzzynum.TriangularFuzzyNumber).
TopsisResult
dataclass
¶
Result of :func:fuzzy_topsis.
Attributes:
| Name | Type | Description |
|---|---|---|
closeness |
ndarray
|
closeness coefficient |
ranking |
list[int]
|
alternative indices ordered best-to-worst. |
d_plus |
ndarray
|
distance to the fuzzy positive-ideal solution per alternative. |
d_minus |
ndarray
|
distance to the fuzzy negative-ideal solution per alternative. |
fuzzy_topsis ¶
Rank alternatives with Chen's fuzzy TOPSIS.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
matrix
|
list
|
|
required |
weights
|
list
|
|
required |
benefit
|
list
|
length- |
required |
Returns:
| Name | Type | Description |
|---|---|---|
A |
TopsisResult
|
class: |
fuzzy_ahp ¶
Crisp criterion weights from a fuzzy pairwise matrix (Chang's method).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
matrix
|
list
|
|
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
A length- |
Serialization¶
fuzzytool.serialize ¶
Save and load fuzzy inference systems as JSON.
Supports :class:~fuzzytool.inference.Mamdani and
:class:~fuzzytool.inference.TSK systems whose connectives/defuzzifier were
given by name and whose variables use built-in membership functions.
TSK consequents must be numbers or coefficient mappings (callable consequents
cannot be serialized).
fz.save(system, "system.json")
system = fz.load("system.json")
Interval type-2 — sets¶
fuzzytool.type2.sets ¶
Interval type-2 (IT2) membership functions.
An :class:IntervalType2MF carries a lower (LMF) and an upper (UMF) type-1
membership function. Calling it returns the membership interval
(lower, upper); the engines also call .lower(x) / .upper(x) directly.
The constructors cover the standard ways of building an FOU from a type-1 set:
- :func:
it2— explicit LMF/UMF; - :func:
it2_scale— height uncertainty (LMF is a scaled-down UMF); - :func:
it2_gauss_uncertain_mean— a Gaussian with mean in[c1, c2]; - :func:
it2_gauss_uncertain_std— a Gaussian with uncertain spread.
IntervalType2MF ¶
An IT2 set defined by a lower (LMF) and an upper (UMF) type-1 MF.
The UMF must dominate the LMF everywhere (LMF(x) <= UMF(x)); this is not
enforced at construction (it would require sampling the universe) but holds
for every set built through the constructors below.
it2 ¶
An IT2 set from explicit lower and upper type-1 membership functions.
it2_scale ¶
Height-uncertainty FOU: UMF is mf, LMF is scale * mf (0 < scale ≤ 1).
it2_gauss_uncertain_mean ¶
Gaussian with an uncertain mean spanning [c1, c2] (c1 < c2).
The UMF is the upper envelope of all Gaussians with mean in [c1, c2]
(flat-topped at 1 between the means); the LMF is their lower envelope.
it2_gauss_uncertain_std ¶
Gaussian with an uncertain spread: UMF uses the wider σ, LMF the narrower.
Interval type-2 — inference¶
fuzzytool.type2.inference ¶
Interval type-2 inference engines.
Both engines evaluate each rule's antecedent to a firing interval
[f_low, f_high] (via :meth:Antecedent.eval_interval) and then collapse the
rule base with Karnik-Mendel type reduction, returning the midpoint of the
type-reduced interval [y_l, y_r].
- :class:
IT2Mamdaniuses center-of-sets type reduction: each consequent IT2 set is summarized by its centroid interval (computed once and cached), and KM combines those centroids weighted by the firing intervals. - :class:
IT2TSKhas crisp consequents (numbers, coefficient mappings, or callables) and applies KM directly to them.
IT2Mamdani ¶
Interval type-2 Mamdani inference (center-of-sets type reduction).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tnorm
|
str | Callable
|
t-norm for AND in antecedents (default |
'min'
|
snorm
|
str | Callable
|
s-norm for OR in antecedents (default |
'max'
|
IT2TSK ¶
Interval type-2 Takagi-Sugeno inference (KM over crisp consequents).
Consequents follow the same convention as the type-1 :class:~fuzzytool.inference.tsk.TSK
engine: a number, a coefficient mapping {"const": b0, "x": b1, ...}, or a
callable f(**inputs) -> float.
Interval type-2 — type reduction¶
fuzzytool.type2.reduction ¶
Karnik-Mendel type reduction.
Type reduction turns the interval-valued output of an IT2 system into a crisp
interval [y_l, y_r] (typically defuzzified as its midpoint). The
Karnik-Mendel (KM) algorithm finds each endpoint by locating the switch point
where the per-point weight flips between its lower and upper bound.
The single primitive :func:km_endpoint is reused everywhere: for an IT2 set's
centroid (points = universe samples, weights = the FOU) and for an IT2 rule base
(points = consequent centroids, weights = rule firing intervals).
km_endpoint ¶
km_endpoint(points: ndarray, lower: ndarray, upper: ndarray, side: str = 'l', max_iter: int = 100) -> float
One endpoint of the type-reduced interval via Karnik-Mendel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
ndarray
|
the y-values (e.g. consequent centroids or universe samples). |
required |
lower
|
ndarray
|
per-point weight lower bounds (same shape as |
required |
upper
|
ndarray
|
per-point weight upper bounds (same shape as |
required |
side
|
str
|
|
'l'
|
max_iter
|
int
|
safeguard on the Karnik-Mendel iteration count. |
100
|
Left endpoint uses the upper weights to the left of the switch and the lower weights to its right; the right endpoint mirrors this.
karnik_mendel ¶
Type-reduce to the interval (y_l, y_r) over a shared set of points.
centroid_it2 ¶
Centroid interval (c_l, c_r) of an IT2 set over universe.
General type-2 (zSlices)¶
fuzzytool.type2.general ¶
General type-2 (GT2) fuzzy sets via the zSlices / alpha-plane representation.
An interval type-2 set treats every point inside its footprint of uncertainty (FOU) as equally possible. A general type-2 set adds a secondary membership that weights those possibilities — the third dimension IT2 throws away.
A practical, exact way to handle that third dimension is the zSlices (alpha
-plane) decomposition (Wagner & Hagras): slice the secondary domain at levels
z and, at each level, the GT2 set reduces to an ordinary IT2 set whose FOU is
the z-cut. Inference and type reduction then run the existing IT2 machinery
on each slice and combine the results, weighted by z.
Here a GT2 set is built from an IT2 footprint plus a triangular secondary
peaking at the FOU's principal (mid) MF: at z -> 0 a slice is the full FOU,
at z = 1 it collapses to the principal MF.
- :class:
GeneralType2MF— a stack of IT2 z-slices (also exposes the overall FOU vialower/upper, so it degrades gracefully to IT2). - :func:
gt2_from_it2, :func:gt2_gauss_uncertain_mean, :func:gt2_scale— constructors. - :class:
GeneralType2Mamdani— z-weighted stack of IT2 Mamdani inferences. - :func:
centroid_gt2— zSlices centroid of a single GT2 set.
GeneralType2MF ¶
A general type-2 set represented as a stack of IT2 z-slices.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
slices
|
list[IntervalType2MF]
|
IT2 sets, one per |
required |
zlevels
|
ndarray
|
the secondary levels (in |
required |
footprint
|
IntervalType2MF
|
the overall FOU as an IT2 set (used for |
required |
GeneralType2Mamdani ¶
General type-2 Mamdani inference via the zSlices decomposition.
At each z level the GT2 terms collapse to their IT2 z-slice and the
existing :class:~fuzzytool.type2.inference.IT2Mamdani engine
(center-of-sets type reduction) produces a crisp output y(z). The final
result is the z-weighted average Σ z·y(z) / Σ z — the centroid of the
type-reduced general type-2 output.
Variables may mix GT2 and IT2/type-1 terms; only the GT2 terms are sliced.
All GT2 terms must share the same z levels (same n_slices).
gt2_from_it2 ¶
Build a GT2 set from an IT2 FOU with a triangular secondary MF.
The secondary membership peaks at the principal MF (the midline of the FOU)
and falls linearly to 0 at the LMF/UMF. The z-slice at level z is the
IT2 set whose FOU is narrowed from the full footprint toward that midline by
a factor (1 - z).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
footprint
|
IntervalType2MF
|
the IT2 set describing the full footprint of uncertainty. |
required |
n_slices
|
int
|
number of |
5
|
gt2_gauss_uncertain_mean ¶
GT2 Gaussian with an uncertain mean in [c1, c2] (triangular secondary).
gt2_scale ¶
GT2 set from a height-uncertainty FOU (UMF mf, LMF scale * mf).
centroid_gt2 ¶
zSlices centroid of a GT2 set: z-weighted mean of per-slice IT2 centroids.
Fuzzy clustering¶
fuzzytool.cluster ¶
Fuzzy clustering.
Unlike crisp k-means, fuzzy clustering lets each sample belong to several
clusters with graded membership. This module provides three algorithms and a
small set of validity metrics, all on plain NumPy arrays of shape
(n_samples, n_features):
- :func:
fuzzy_cmeans— Bezdek's FCM (spherical clusters, Euclidean norm). - :func:
gustafson_kessel— GK, an adaptive norm per cluster that captures ellipsoidal shapes. - :func:
possibilistic_cmeans— PCM, which drops the "memberships sum to 1" constraint so outliers get low typicality in every cluster.
Each returns a :class:ClusterResult. Every algorithm accepts a seed for
reproducibility.
ClusterResult
dataclass
¶
Outcome of a fuzzy clustering run.
Attributes:
| Name | Type | Description |
|---|---|---|
centers |
ndarray
|
cluster prototypes, shape |
u |
ndarray
|
membership/typicality matrix, shape |
n_iter |
int
|
iterations run until convergence. |
objective |
float
|
final value of the algorithm's objective function. |
labels |
ndarray
|
hard assignment |
fuzzy_cmeans ¶
fuzzy_cmeans(X: ndarray, c: int, m: float = 2.0, max_iter: int = 150, tol: float = 1e-05, seed: int | None = None) -> ClusterResult
Bezdek's fuzzy c-means.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
data, shape |
required |
c
|
int
|
number of clusters. |
required |
m
|
float
|
fuzziness exponent ( |
2.0
|
max_iter
|
int
|
maximum iterations. |
150
|
tol
|
float
|
stop when the membership matrix changes by less than this (max-norm). |
1e-05
|
seed
|
int | None
|
RNG seed for the membership initialization. |
None
|
gustafson_kessel ¶
gustafson_kessel(X: ndarray, c: int, m: float = 2.0, max_iter: int = 150, tol: float = 1e-05, seed: int | None = None, reg: float = 1e-10) -> ClusterResult
Gustafson-Kessel clustering (adaptive per-cluster Mahalanobis norm).
Each cluster learns a covariance-shaped, unit-determinant norm, so GK fits ellipsoidal clusters that FCM (fixed spherical norm) cannot.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
data, shape |
required |
c
|
int
|
number of clusters. |
required |
m
|
float
|
fuzziness exponent ( |
2.0
|
max_iter
|
int
|
maximum iterations. |
150
|
tol
|
float
|
convergence threshold on the membership matrix (max-norm). |
1e-05
|
seed
|
int | None
|
RNG seed for initialization. |
None
|
reg
|
float
|
ridge added to each fuzzy covariance for numerical stability. |
1e-10
|
possibilistic_cmeans ¶
possibilistic_cmeans(X: ndarray, c: int, m: float = 2.0, max_iter: int = 150, tol: float = 1e-05, seed: int | None = None, k: float = 1.0) -> ClusterResult
Possibilistic c-means (Krishnapuram-Keller).
PCM drops the probabilistic constraint that memberships sum to 1: each value
is a typicality in [0, 1], so noise points score low everywhere. It is
initialized from an FCM run, which also fixes each cluster's scale eta.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
data, shape |
required |
c
|
int
|
number of clusters. |
required |
m
|
float
|
fuzziness exponent ( |
2.0
|
max_iter
|
int
|
maximum iterations. |
150
|
tol
|
float
|
convergence threshold on the typicality matrix (max-norm). |
1e-05
|
seed
|
int | None
|
RNG seed (passed to the initializing FCM). |
None
|
k
|
float
|
scale multiplier for the bandwidth |
1.0
|
partition_coefficient ¶
Bezdek's partition coefficient in (1/c, 1]; higher = crisper.
partition_entropy ¶
Partition entropy in [0, log c); lower = crisper.
xie_beni ¶
Xie-Beni index (compactness / separation); lower is better.
ANFIS¶
fuzzytool.anfis ¶
ANFIS — an adaptive network-based fuzzy inference system (Jang, 1993).
ANFIS is a first-order Takagi-Sugeno system whose parameters are learned from
data. With a grid partition, each of the p inputs carries n_mf Gaussian
membership functions, giving n_mf ** p rules; rule i fires with the
product of its inputs' memberships and emits an affine function of the inputs.
Training uses Jang's hybrid scheme, one pass per epoch:
- with the premise (Gaussian) parameters fixed, the consequent (affine) parameters are solved in closed form by least squares — the output is linear in them;
- with the consequents fixed, the premise centers and widths take a gradient-descent step on the mean squared error.
Pure NumPy; intended for low-dimensional problems (the rule count grows as
n_mf ** p).
ANFIS ¶
A trainable first-order Sugeno system over a grid partition.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_inputs
|
int
|
number of input features |
required |
n_mf
|
int
|
Gaussian membership functions per input (rules = |
3
|
learning_rate
|
float
|
step size for the premise gradient updates. |
0.05
|
F-transform¶
fuzzytool.ftransform ¶
F-transform — the fuzzy transform of Perfilieva.
The F-transform projects a function onto a fuzzy partition of its domain. Over
a uniform partition by triangular basis functions A_1..A_n that satisfy the
Ruspini condition (they sum to 1 everywhere on [a, b]):
- the direct transform reduces the data to
ncomponents, each a membership-weighted average of the samples falling under one basis function; - the inverse transform reconstructs an approximation
f̂(x) = Σ_k F_k · A_k(x).
With few components the round trip smooths/denoises a signal; with many it approximates it closely. Pure NumPy.
FTransform ¶
A triangular F-transform over a uniform fuzzy partition of [a, b].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
float
|
left end of the domain. |
required |
b
|
float
|
right end of the domain ( |
required |
n_basis
|
int
|
number of basis functions / components ( |
required |
Visualization¶
fuzzytool.viz ¶
Matplotlib visualization helpers.
Importing this module requires matplotlib (an optional dependency; install
with pip install fuzzytool[viz]). Visualization is a first-class priority of
the project, mirroring its sibling turboswarm.
plot_variable ¶
Plot every term's membership function over the variable's universe.
plot_it2_variable ¶
Plot an IT2 variable: each term's lower/upper MF with a shaded FOU.
Type-1 terms (if any are mixed in) are drawn as a single line.
control_surface ¶
Plot a system's output as a surface over two input variables.
system must be callable as system(**{x_var.name: x, y_var.name: y})
and return a scalar (single-output Mamdani or TSK).
plot_clusters ¶
Scatter 2-D data colored by hard label, with cluster centers marked.
result is a :class:~fuzzytool.cluster.ClusterResult. Point opacity
encodes the top membership, so fuzzy/boundary points appear fainter.
Integrations — pandas¶
fuzzytool.integrations.pandas ¶
pandas integration: DataFrame in/out and tabular views of fuzzy objects.
Install with pip install fuzzytool[pandas]. Nothing here imports pandas at
module load beyond a guarded check, so the rest of the toolkit stays dependency
-free.
- :func:
predict_df— batch inference straight from a DataFrame. - :func:
rules_dataframe— a readable table of a system's rule base. - :func:
memberships_dataframe— a clustering result's membership matrix. - :func:
components_dataframe— an F-transform's components.
predict_df ¶
predict_df(system: Mamdani | TSK, df: DataFrame, columns: list[str] | None = None) -> pd.Series | pd.DataFrame
Run vectorized inference over a DataFrame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
system
|
Mamdani | TSK
|
a :class: |
required |
df
|
DataFrame
|
a DataFrame whose columns include the system's input variables. |
required |
columns
|
list[str] | None
|
input column names to use, in order. Defaults to the variables
the system's rules reference (see
:func: |
None
|
Returns:
| Type | Description |
|---|---|
Series | DataFrame
|
A |
Series | DataFrame
|
|
rules_dataframe ¶
Return the system's rule base as a DataFrame (one row per rule).
Columns: antecedent (the IF part as text), consequent (the
THEN part) and weight.
memberships_dataframe ¶
Return a clustering result's membership matrix as a DataFrame.
One row per sample, one column {prefix}_{k} per cluster, plus a label
column holding the hard (argmax) assignment.
components_dataframe ¶
Return an :class:~fuzzytool.ftransform.FTransform's components as a DataFrame.
Columns: node (the basis-function center) and component (its value).
Integrations — scikit-learn¶
fuzzytool.integrations.sklearn ¶
scikit-learn integration: fuzzy systems as estimators and transformers.
These objects follow the scikit-learn estimator protocol (fit returns
self, plus predict/transform, get_params/set_params and a
score/fit_transform), so they slot into a Pipeline, GridSearchCV
or cross_val_score — yet, like :class:~fuzzytool.anfis.ANFIS, they do not
import scikit-learn. The [sklearn] extra simply installs scikit-learn so
you have those tools available:
pip install fuzzytool[sklearn]
- :class:
Fuzzifier— a transformer turning crisp features into fuzzy membership-degree features (one column per term). - :class:
WangMendelRegressor— learns a Mamdani rule base from data (Wang-Mendel) and predicts with it. - :class:
FuzzySystemRegressor— wraps an already-built Mamdani/TSK system so it can be scored or pipelined.
Fuzzifier ¶
Bases: _Estimator
Expand crisp features into fuzzy membership-degree features.
Column j of X is interpreted through variables[j]: each of that
variable's terms becomes one output column holding the membership degree.
The result is a soft, interpretable encoding that downstream linear or tree
models can consume.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
variables
|
list[Variable]
|
one :class: |
required |
WangMendelRegressor ¶
Bases: _Estimator
A regressor that learns a Mamdani rule base from data (Wang-Mendel).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
inputs
|
list[Variable]
|
input linguistic variables (pre-populated with terms), one per
column of |
required |
output
|
Variable
|
the output linguistic variable (pre-populated with terms). |
required |
FuzzySystemRegressor ¶
Bases: _Estimator
Wrap an already-built single-output fuzzy system as an sklearn regressor.
fit does not change the system (it is already defined); it only records
the input column order. Use this to cross-validate, score, or pipeline a
hand-written Mamdani/TSK system.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
system
|
Mamdani | TSK
|
a single-output Mamdani or TSK system. |
required |
columns
|
list[str] | None
|
input variable names matching |
None
|
Integrations — SciPy¶
fuzzytool.integrations.scipy ¶
SciPy integration: tune a fuzzy system's membership functions to data.
Install with pip install fuzzytool[scipy]. :func:tune adjusts the
parameters of a system's built-in membership functions so its output fits a
dataset, using :func:scipy.optimize.least_squares. It mutates the system in
place and returns SciPy's OptimizeResult (.x, .cost, .nfev,
.success …) — a drop-in way to refine a hand-written Mamdani/TSK system.
Only built-in membership shapes (tri, trap, gauss, gbell,
sigmoid, ramp_up, ramp_down) are tunable; custom callables are left
untouched. Shape validity is preserved every iteration (breakpoints are kept
ordered, widths kept positive), so the optimizer explores freely without
producing degenerate sets.
tune ¶
tune(system: Mamdani | TSK, X: ndarray, y: ndarray, columns: list[str] | None = None, tune_outputs: bool = True, **least_squares_kwargs) -> OptimizeResult
Fit a system's membership-function parameters to data.
Any extra keyword arguments are forwarded to
:func:scipy.optimize.least_squares (e.g. max_nfev).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
system
|
Mamdani | TSK
|
a Mamdani or TSK system (mutated in place with the best params). |
required |
X
|
ndarray
|
inputs, shape |
required |
y
|
ndarray
|
targets, shape |
required |
columns
|
list[str] | None
|
input variable names matching |
None
|
tune_outputs
|
bool
|
also tune the output variables' MFs (Mamdani only). |
True
|
Returns:
| Type | Description |
|---|---|
OptimizeResult
|
The SciPy |
Integrations — turboswarm (PSO)¶
fuzzytool.integrations.turboswarm ¶
turboswarm integration: tune a fuzzy system with Particle Swarm Optimization.
Install with pip install fuzzytool[turboswarm]. :func:tune fits the
parameters of a system's built-in membership functions to data with
turboswarm <https://pypi.org/project/turboswarm/>_'s PSO — a gradient-free,
global optimizer. It is the metaheuristic sibling of
:func:fuzzytool.integrations.scipy.tune (local least-squares): slower, but it
escapes poor local optima and needs no derivatives, which suits the rugged,
non-smooth error surfaces fuzzy rule bases often produce.
Each parameter is searched within a box of ±margin × universe around its
current value; shape validity (ordered breakpoints, positive widths) is enforced
every evaluation, so the swarm explores freely. The system is mutated in place
with the best parameters found and the turboswarm PsoResult is returned.
tune ¶
tune(system: Mamdani | TSK, X: ndarray, y: ndarray, columns: list[str] | None = None, tune_outputs: bool = True, margin: float = 0.5, n_particles: int = 30, max_iter: int = 100, seed: int | None = None, **minimize_kwargs) -> PsoResult
Fit a system's membership-function parameters to data with PSO.
Extra keyword arguments are forwarded to :func:turboswarm.minimize
(e.g. topology, patience, max_time).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
system
|
Mamdani | TSK
|
a Mamdani or TSK system (mutated in place with the best params). |
required |
X
|
ndarray
|
inputs, shape |
required |
y
|
ndarray
|
targets, shape |
required |
columns
|
list[str] | None
|
input variable names matching |
None
|
tune_outputs
|
bool
|
also tune the output variables' MFs (Mamdani only). |
True
|
margin
|
float
|
search half-width per parameter as a fraction of its variable's
universe span ( |
0.5
|
n_particles
|
int
|
swarm size. |
30
|
max_iter
|
int
|
PSO iterations. |
100
|
seed
|
int | None
|
PSO seed for reproducibility. |
None
|
Returns:
| Type | Description |
|---|---|
PsoResult
|
The turboswarm |
Integrations — Optuna¶
fuzzytool.integrations.optuna ¶
Optuna integration: search fuzzy-system structure and hyperparameters.
Install with pip install fuzzytool[optuna]. Fuzzy systems have plenty of
discrete/continuous knobs — which t-norm, which defuzzifier, how many membership
functions, what learning rate — that are awkward to grid-search by hand. These
helpers turn an Optuna trial into a configured system, plus a ready-made
:func:tune_anfis study.
- :func:
suggest_inference_spec— sample the connectives/implication/defuzz of a Mamdani system from a trial. - :func:
suggest_anfis— build an :class:~fuzzytool.anfis.ANFISwith a trial-suggestedn_mfandlearning_rate. - :func:
tune_anfis— run a full study that minimizes training RMSE and returns the best (refit) model.
suggest_inference_spec ¶
Sample a Mamdani spec {tnorm, snorm, implication, defuzz} from a trial.
prefix namespaces the parameter names so several specs can coexist in one
study. Pass the result straight to :class:~fuzzytool.inference.Mamdani.
suggest_anfis ¶
suggest_anfis(trial, n_inputs: int, n_mf_range: tuple[int, int] = (2, 5), lr_range: tuple[float, float] = (0.001, 0.2)) -> ANFIS
Build an ANFIS with a trial-suggested n_mf and learning_rate.
tune_anfis ¶
tune_anfis(X: ndarray, y: ndarray, n_trials: int = 20, n_mf_range: tuple[int, int] = (2, 5), lr_range: tuple[float, float] = (0.001, 0.2), epochs: int = 100, seed: int | None = None) -> tuple
Tune an ANFIS's n_mf/learning_rate with an Optuna study.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
inputs, shape |
required |
y
|
ndarray
|
targets, shape |
required |
n_trials
|
int
|
number of Optuna trials. |
20
|
n_mf_range
|
tuple[int, int]
|
|
(2, 5)
|
lr_range
|
tuple[float, float]
|
|
(0.001, 0.2)
|
epochs
|
int
|
training epochs per trial. |
100
|
seed
|
int | None
|
seed for Optuna's sampler (reproducible search). |
None
|
Returns:
| Type | Description |
|---|---|
tuple
|
A |
tuple
|
hyperparameters, and the Optuna study. |
Integrations — Joblib / Dask¶
fuzzytool.integrations.parallel ¶
Parallel execution helpers (Joblib and Dask).
Install with pip install fuzzytool[parallel] (Joblib) or
fuzzytool[dask] (Dask). These spread embarrassingly-parallel fuzzy workloads
across cores or a Dask cluster:
- :func:
parallel_predict— chunked batch inference with Joblib. - :func:
multi_start_cmeans— run fuzzy c-means from many seeds in parallel and keep the best (FCM is sensitive to initialization). - :func:
dask_predict— the same chunked inference on a Dask scheduler.
.. note::
The process backends pickle the system. A hand-written Mamdani/TSK built from
the built-in shapes pickles fine; a TSK with lambda consequents does not —
pass backend="threading" for those.
parallel_predict ¶
parallel_predict(system: Mamdani | TSK, X: ndarray, columns: list[str] | None = None, n_jobs: int = -1, n_chunks: int | None = None, backend: str = 'loky') -> np.ndarray | dict
Run batch inference over X in parallel chunks with Joblib.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
system
|
Mamdani | TSK
|
a Mamdani or TSK system. |
required |
X
|
ndarray
|
inputs, shape |
required |
columns
|
list[str] | None
|
input variable names matching |
None
|
n_jobs
|
int
|
Joblib worker count ( |
-1
|
n_chunks
|
int | None
|
number of row chunks (defaults to |
None
|
backend
|
str
|
Joblib backend ( |
'loky'
|
Returns:
| Type | Description |
|---|---|
ndarray | dict
|
The stacked predictions — an array (single output) or a dict of arrays. |
multi_start_cmeans ¶
multi_start_cmeans(X: ndarray, c: int, n_starts: int = 8, n_jobs: int = -1, backend: str = 'loky', **kwargs) -> ClusterResult
Run :func:~fuzzytool.cluster.fuzzy_cmeans from many seeds; keep the best.
Fuzzy c-means converges to a local optimum that depends on initialization;
running several seeds and keeping the lowest-objective result is a standard
safeguard. The runs are independent, so they parallelize cleanly. Extra
keyword arguments are forwarded to :func:~fuzzytool.cluster.fuzzy_cmeans.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
data, shape |
required |
c
|
int
|
number of clusters. |
required |
n_starts
|
int
|
number of random restarts (seeds |
8
|
n_jobs
|
int
|
Joblib worker count ( |
-1
|
backend
|
str
|
Joblib backend. |
'loky'
|
Returns:
| Type | Description |
|---|---|
ClusterResult
|
The best :class: |
dask_predict ¶
dask_predict(system: Mamdani | TSK, X: ndarray, columns: list[str] | None = None, n_chunks: int | None = None) -> np.ndarray | dict
Run chunked batch inference on a Dask scheduler.
Mirrors :func:parallel_predict but builds a Dask graph (dask.delayed)
and computes it, so it scales to a distributed cluster.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
system
|
Mamdani | TSK
|
a Mamdani or TSK system. |
required |
X
|
ndarray
|
inputs, shape |
required |
columns
|
list[str] | None
|
input variable names matching |
None
|
n_chunks
|
int | None
|
number of row chunks (default 8). |
None
|
Returns:
| Type | Description |
|---|---|
ndarray | dict
|
The stacked predictions — an array or a dict of arrays. |
Integrations — LLM agents¶
fuzzytool.integrations.agents ¶
LLM-agent integration: expose a fuzzy system as an explainable tool.
Install with pip install fuzzytool[agents]. A fuzzy inference system is an
unusually good citizen for tool-using LLMs: it is deterministic, bounded, and —
unlike a black-box model — it can say why it produced an answer by reporting
which rules fired and how strongly.
- :func:
explain— run a system and return its crisp output plus the fired rules (no third-party dependency; useful on its own). - :func:
inference_tool— wrap a system as a LangChainStructuredToolan agent can call.
explain ¶
Run system on inputs and explain the result.
Returns a dict with the crisp output (a float, or a dict for a
multi-output Mamdani) and fired_rules: the rules whose firing strength is
positive, each {"rule", "firing"}, sorted strongest-first. This is the
payload an agent (or a human) needs to trust the answer.
inference_tool ¶
inference_tool(system: Mamdani | TSK, columns: list[str] | None = None, name: str = 'fuzzy_inference', description: str | None = None) -> StructuredTool
Wrap a fuzzy system as a LangChain StructuredTool.
The tool takes one float argument per input variable and returns the crisp output together with the rules that fired — so the agent can both use and explain the system.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
system
|
Mamdani | TSK
|
a Mamdani or TSK system. |
required |
columns
|
list[str] | None
|
input variable names (the tool's arguments). Defaults to the variables the rules reference. |
None
|
name
|
str
|
tool name exposed to the agent. |
'fuzzy_inference'
|
description
|
str | None
|
tool description; a sensible default is generated. |
None
|
Returns:
| Type | Description |
|---|---|
StructuredTool
|
A |
Datasets¶
fuzzytool.datasets ¶
Ready-made example systems.
credit_risk ¶
A credit-risk-premium Mamdani system.
Given a borrower's credit score (300-850) and dti (debt-to-income
ratio, 0-50%), recommend the premium (risk points, 0-12) a lender should
add on top of its base interest rate. Returns (system, score, dti,
premium) so callers can inspect the variables (e.g. for plotting).
sys, score, dti, premium = credit_risk() safe = sys(score=800, dti=10) # great score, low leverage risky = sys(score=520, dti=42) # poor score, high leverage safe < risky True
credit_risk_it2 ¶
An interval type-2 version of :func:credit_risk.
The score and premium terms carry a footprint of uncertainty (uncertain
Gaussian means), modeling vagueness in how a "good" score or a "low" premium
is defined. Returns (system, score, dti, premium).
sys, score, dti, premium = credit_risk_it2() sys(score=800, dti=10) < sys(score=520, dti=42) True
make_blobs ¶
make_blobs(centers=((0.0, 0.0), (6.0, 6.0), (0.0, 6.0)), n_per: int = 60, spread: float = 0.7, seed: int | None = 0) -> np.ndarray
Synthetic isotropic Gaussian blobs for clustering demos and tests.
Returns the stacked data X of shape (len(centers) * n_per, n_features).
X = make_blobs(seed=0) X.shape (180, 2)