Skip to main content

fysvm

GitHub Release Build Status codecov

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 like IF feature is low THEN class_A
  • firing — how strongly the sample matches the rule antecedent in [0, 1]
  • weight — the learned SVM coefficient β_k
  • contribution — 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 all D canonical 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:

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)

Source distribution for fysvm 0.0.5
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)

Table of built distributions (wheels) for fysvm 0.0.5
File Interpreter ABI Platform Actions
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 log

Release 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 log

Security 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.

Select from 2 files

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 log

A 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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page