Performance¶
All numbers below come from benchmarks/benchmark.py, which ships with the
repository. Re-run it on your own machine rather than trusting the table:
python benchmarks/benchmark.py # every section
python benchmarks/benchmark.py type-reduction # just one
The reference run below is fuzzytool 0.7.0, NumPy 2.5, Python 3.14, arm64.
Rule bases reuse propositions, so inference memoizes them¶
A rule base repeats the same variable is term atoms across many rules. The
engines evaluate each one once per call and share the result across the
whole rule base.
For a 125-rule Mamdani system over 4 inputs × 5 terms:
| antecedent atoms in the rule base | 375 |
distinct (variable, term) pairs |
15 |
| membership evaluations performed | 15 |
Without the memo the same call performs 375 evaluations. On this system a scalar call went from ~4.3 ms to ~0.5 ms — roughly 8× faster, and the gain grows with the rule count. It is largest exactly where it matters: rule bases learned from data, which have hundreds of rules over a handful of terms.
predict is unaffected by this ratio because it is dominated by the
(n_samples × resolution) array arithmetic, not by membership evaluation.
predict chunks, so large batches do not exhaust memory¶
Mamdani inference materializes an (n_samples, resolution) aggregation buffer
per output. At the default resolution of 501 samples, a million-row batch would
allocate 4 GB. predict therefore processes the batch in blocks:
system.predict(score=score, dti=dti) # chunk_size=4096 default
system.predict(score=score, dti=dti, chunk_size=512) # tighter memory bound
system.predict(score=score, dti=dti, chunk_size=None) # off
For 20 000 samples through the 125-rule system:
chunk_size |
Time | Peak buffer |
|---|---|---|
None |
1340 ms | 80 MB |
| 4096 | 1431 ms | 16 MB |
| 512 | 1290 ms | 2 MB |
Chunking costs nothing measurable and bounds peak memory by a factor of 40. The results are identical either way.
Type reduction: pick the reducer that fits the job¶
Karnik-Mendel is the exact, canonical type reducer. EIASC computes the same interval by walking the sorted points once instead of re-averaging repeatedly; Nie-Tan is a closed-form approximation.
| Points | karnik_mendel |
eiasc |
nie_tan |
|---|---|---|---|
| 5 | 0.054 ms | 0.006 ms (9× faster, identical) | 0.002 ms (24× faster, approximate) |
| 20 | 0.077 ms | 0.011 ms (7× faster, identical) | 0.002 ms (34× faster) |
| 100 | 0.090 ms | 0.035 ms (2.6× faster, identical) | 0.002 ms (38× faster) |
Real rule bases sit at the top of that table, where EIASC wins most.
fz.type2.IT2Mamdani(reducer="eiasc") # same answers, less time
fz.type2.IT2Mamdani(reducer="nie-tan") # approximate, for control loops
EIASC is verified against Karnik-Mendel on random problems in the test suite, so switching is safe.
ANFIS: choose the partition before you choose the epochs¶
A grid partition needs n_mf ** n_inputs rules. At 5 inputs and 3 membership
functions each that is 243 rules and 1458 consequent parameters — more than the
600 training samples, which is why it reaches R² = 1.000 by interpolating.
| Model | Time (20 epochs) | Rules | R² |
|---|---|---|---|
| ANFIS, grid partition (3 MFs/input) | 1306 ms | 243 | 1.000 (overfit) |
| ANFIS, cluster partition (10 rules) | 31 ms | 10 | 0.995 |
| Chiu subtractive clustering → TSK | 21 ms | 25 | 0.954 |
The cluster partition is 42× faster with 24× fewer rules and essentially the same fit. Use the grid partition when you want a readable linguistic partition over two or three inputs; use the cluster partition for anything wider.
Cluster rules overlap by construction, which makes the consequent least-squares
solve ill-conditioned — so that partition defaults to a small ridge
(ridge=1e-6). Without it, the same fit on this problem collapses to R² ≈ 0.
The grid partition keeps Jang's original unregularized solve.
Auditing is cheap enough to run in CI¶
audit() on the 125-rule system takes ~3 ms, sweeping a lattice over the input
space. Add it to your test suite:
def test_rule_base_is_complete():
report = audit(build_system())
assert report.coverage == 1.0
assert not report.contradictions
See also: Batch, I/O & sklearn, Auditing a rule base, ANFIS.