fysvm
Intrinsically interpretable fuzzy SVM-style classifiers built on scikit-learn.
fysvm trains linear max-margin classifiers over fuzzy rule activations instead
of raw feature coordinates. Every learned dimension is a human-readable
linguistic rule such as:
IF glucose is high AND bmi is high THEN positive
Two classifiers are provided:
FuzzyRuleSVM— trains in raw rule activation space; fast and interpretable.CSRQClassifier— trains in the canonical quotient space; solves the parameterisation-invariance problem described below.
Installation
uv pip install fysvm
CSRQClassifier requires sympy for exact rational arithmetic, which is
included in the default dependencies. The optional Variant B atomic norm
classifier (QuotientAtomicFuzzySVM) additionally requires osqp:
uv pip install "fysvm[csrq-atomic]"
Requires Python ≥ 3.14.
Quickstart: FuzzyRuleSVM
from fysvm import FuzzyRuleSVM
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
data.data, data.target, test_size=0.3, random_state=0
)
clf = FuzzyRuleSVM(
max_rule_length=2,
max_rules=128,
penalty="l1",
feature_names=data.feature_names,
random_state=0,
)
clf.fit(X_train, y_train)
print(clf.score(X_test, y_test))
How FuzzyRuleSVM works
The estimator has three stages:
1. Fuzzy concepts. Each numeric feature is summarized by three linguistic
terms — low, medium, high — defined by triangular membership functions
anchored at data quantiles. Every sample gets a membership score in [0, 1] for
each concept.
2. Rule generation. All conjunctions of up to max_rule_length concepts are
enumerated as candidate rules (e.g. glucose is high AND bmi is high).
Candidates are scored by discriminative power and coverage; the top max_rules
are kept.
3. Max-margin learning. Each sample is mapped to a firing-strength vector
φ(x) ∈ [0, 1]^K where entry k is the fuzzy AND of the concepts in rule k.
A sparse linear SVM is trained on this activation space:
f(x) = Σ_k β_k · φ_k(x) + b
Explaining FuzzyRuleSVM predictions
Because the decision function is a weighted sum of fuzzy rule firings, explanations are the model computation — no proxy, no approximation.
Per-sample explanation
explanation = clf.explain(X_test[:1])[0]
Returns the bias, the net margin, and the top-contributing rules sorted by absolute contribution. Each rule has:
rule— a human-readable string likeIF feature is low THEN class_Afiring— how strongly the sample matches the rule antecedent in [0, 1]weight— the learned SVM coefficientβ_kcontribution—firing × weight, the rule's impact on the margin
Contributions sum with the bias to the predicted margin:
assert abs(explanation["margin"]
- (explanation["bias"] + explanation["net_rule_contribution"])) < 1e-12
Global rule inspection
for item in clf.support_rules():
print(item["rule"], item["weight"])
Returns rules with non-zero coefficients, sorted by absolute weight.
Fuzzy concept membership
concepts = clf.concept_memberships(X_test[:1])[0]
# {"glucose": {"low": 0.0, "medium": 0.3, "high": 0.7}, ...}
Fuzzy margin violations
violations = clf.fuzzy_violations(X_test, y_test)
# Each item: {"slack": 0.42, "memberships": {"cleanly_classified": 0.58,
# "borderline": 0.42, "strong_violation": 0.0}}
The parameterisation problem
FuzzyRuleSVM trains in raw rule activation space with a coefficient-space
norm. This norm is not invariant to the algebraic structure of the rule basis.
When the product t-norm is used with strict triangular anchors, the partition satisfies two pointwise identities:
L_j(x) + M_j(x) + H_j(x) = 1 (Ruspini identity)
L_j(x) · H_j(x) = 0 (orthogonality)
These identities generate a polynomial ideal that makes many rule dictionaries
semantically equivalent: they span the same hypothesis space. Replacing a
medium atom with its equivalent low/high expansion, permuting the rule
ordering, or rescaling atom weights are all parameterisations of the same
function space. Yet the L2 penalty changes with each such reparameterisation,
and the trained model typically changes with it.
In practice: two analysts designing semantically equivalent rule grammars
independently — one using explicit medium atoms, the other using low/high
expansions — obtain different trained models under FuzzyRuleSVM, even though
their hypothesis spaces are identical. This is a reproducibility and
interpretability artefact.
CSRQClassifier eliminates this artefact.
Quickstart: CSRQClassifier
from fysvm import CSRQClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
data.data, data.target, test_size=0.3, random_state=0
)
clf = CSRQClassifier(
C=1.0,
max_rule_length=2,
feature_names=data.feature_names,
)
clf.fit(X_train, y_train)
print(clf.score(X_test, y_test))
How CSRQClassifier works
CSRQClassifier constructs the canonical quotient space Q_{d,r}
explicitly before training. Medium terms are eliminated by exact algebraic
substitution — M_j → 1 - L_j - H_j — so the canonical basis contains only
low and high monomials. Its dimension is:
D_{d,r} = Σ_{l=0}^{r} C(d,l) · 2^l
strictly smaller than the full grammar size N_{d,r} = Σ C(d,l) · 3^l.
A positive-definite degree-weighted metric G = diag(p_q²) on this basis
yields a unique ideal minimiser that is independent of the rule dictionary
used to construct the training data. Two training modes are available:
complete(default) — trains over allDcanonical coordinates. Fully dictionary-invariant: any rule dictionary produces the same solution.dictionary— trains over the exact RREF subspace of a supplied rule dictionary. Invariant across all dictionaries with the same semantic span.
Every fitted model is accompanied by an exact certificate A_D · γ = c
verified in rational arithmetic, enabling independent audit of semantic
consistency.
Explaining CSRQClassifier predictions
explanation = clf.explain(X_test[:1])[0]
print(explanation["prediction"])
print(explanation["margin"])
for rule in explanation["top_rules"]:
print(f"{rule['monomial']:40s} weight={rule['weight']:+.4f} firing={rule['firing']:.3f}")
Global support rules
for item in clf.support_rules():
print(item["rule"], item["weight"])
Decoding back to the original grammar
The canonical basis eliminates medium atoms for training invariance, but
you can decode the canonical coefficients back to original rule weights at
any time:
decoded = clf.decode(method="minimum_l2")
for atom, weight in zip(decoded["atoms"], decoded["weights"]):
print(f"{atom} → {weight:+.4f}")
Exporting a reproducibility artifact
artifact = clf.export_artifact(X_val=X_test)
# artifact.semantic_equality_certificate.max_abs_residual is the
# exact rational certificate residual (should be 0)
print(artifact.optimization_report.n_iter)
print(artifact.semantic_equality_certificate.is_certified)
Dictionary mode: preserving hand-crafted grammars
If you have domain-specific rules that you want to keep intact (including
medium atoms), supply them explicitly and use dictionary mode:
from fysvm import CSRQClassifier
from fysvm.quotient import RuleAtom
from fysvm.rule_svm import FuzzyRule, RuleCondition
atoms = (
RuleAtom(FuzzyRule((RuleCondition(0, "high"), RuleCondition(1, "high"))), scale=1.0, cost=1.0),
RuleAtom(FuzzyRule((RuleCondition(0, "low"),)), scale=1.0, cost=1.0),
RuleAtom(FuzzyRule((RuleCondition(1, "medium"),)), scale=1.0, cost=1.0),
)
clf = CSRQClassifier(
semantic_space="dictionary",
rule_dictionary=atoms,
)
clf.fit(X_train, y_train)
The training problem is invariant across any other dictionary that spans the same semantic subspace (same RREF row space).
API Reference
FuzzyRuleSVM (aliased as SparseMaxMarginFuzzyRuleMachine)
| Parameter | Default | Description |
|---|---|---|
C |
1.0 |
Inverse regularization strength |
penalty |
"l1" |
"l1" or "l2" SVM penalty |
max_rule_length |
2 |
Max conjuncts per rule (≤ n_features) |
max_rules |
256 |
Max candidate rules kept |
min_rule_coverage |
0.02 |
Minimum fuzzy support for a candidate |
and_operator |
"min" |
"min", "product", or "softmin" |
feature_names |
None |
Column names for readable rule strings |
class_weight |
None |
"balanced" or dict for imbalanced classes |
CSRQClassifier
| Parameter | Default | Description |
|---|---|---|
C |
1.0 |
SVM regularization strength |
max_rule_length |
2 |
Max degree of canonical monomials |
degree_penalty |
1.0 |
Weight increment per extra degree above 1 (η) |
intercept_penalty |
1.0 |
Regularization weight for the intercept (p₀ > 0) |
semantic_space |
"complete" |
"complete" or "dictionary" |
rule_dictionary |
None |
tuple[RuleAtom, ...] for dictionary mode |
partition_quantiles |
(0.25, 0.5, 0.75) |
Quantiles for fuzzy partition anchors |
feature_names |
None |
Column names for readable rule strings |
class_weight |
None |
"balanced" or dict for imbalanced classes |
See the docstrings for the full parameter list.
Example notebooks
See the examples/ directory:
basic_usage.py— fit, predict, evaluateexplain_predictions.py— detailed explanation walkthrough
Citations
If you use FuzzyRuleSVM in published work, please cite:
@misc{davidsen2026fuzzy,
author = {Davidsen, S. A. and Padmavathamma, M.},
title = {Faithful Regularised Classification over Linguistic Fuzzy Rule Activations},
year = {2026},
note = {Under review}
}
If you use CSRQClassifier, please also cite:
@misc{davidsen2026csrq,
author = {Davidsen, S. A. and Padmavathamma, M.},
title = {Quotient-Invariant Max-Margin Training for Product Fuzzy Rule Classifiers},
year = {2026},
note = {Under review}
}
Metadata
Release files for fysvm 0.0.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| fysvm-0.0.5.tar.gz | 3.7 MB | With provenance | Details for fysvm-0.0.5.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| fysvm-0.0.5-py3-none-any.whl | Python 3 | none | any | Details for fysvm-0.0.5-py3-none-any.whl |
Total release size: 3.8 MB
Release files / fysvm-0.0.5.tar.gz
| Download URL | fysvm-0.0.5.tar.gz |
|---|---|
| Size | 3.7 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
901e211a634eb1adda1f79471def4265913ff26d6a8ecdfee28b01d8c868e789
|
|
BLAKE2b-256 checksum How to use checksums |
46fb0174a66db41472ff6b2cf7bf08d825dec16edecfb054d73d91831e194168
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 9, 2026.
Transparency logRelease files / fysvm-0.0.5-py3-none-any.whl
| Download URL | fysvm-0.0.5-py3-none-any.whl |
|---|---|
| Size | 64.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b46cfcec65fa506dd3cd32e404b8dfc31093aff1f5cfdff435ee833a76937033
|
|
BLAKE2b-256 checksum How to use checksums |
361dd932a8e1134ccd652bb12aed7818e95154114e75d1b1341968df907e1453
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 9, 2026.
Transparency logSecurity for fysvm 0.0.5
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for fysvm-0.0.5.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 9, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.