Skip to content

Interpretation

kanforge.interpret.analysis

Tabulation, attribution and pruning of KAN models (PyTorch or MLX).

EdgeTable(x, values) dataclass

Edge functions phi_oi sampled on a per-input grid of points.

input_ranges(layer, x=None, margin=0.0)

Per-input (lo, hi): from samples x, else the basis grid, else [-1, 1].

tabulate(layer, x=None, n=201, margin=0.0)

Sample every edge of layer (any basis, any backend) on n points per input over the range of x (or of the grid).

layer_activations(model, x)

Inputs of every KAN layer of the model, in order (backend arrays).

tabulate_model(model, x, n=201)

Tabulate every KAN layer over the activations it receives for inputs x.

attribution(model, x, eps=1e-12)

Importance of edges and nodes, propagated from the outputs (pykan-style).

E_oi = std over the data of phi_oi(x_i); an output node passes its score to its inputs in proportion to E_oi; a product node passes its full score to each factor. Per layer: edge (out, in), input (in,), output (out,) scores; output nodes of the model score 1.

feature_importance(model, x)

Importance of every model input (first-layer input scores).

prune_edges(model, x, threshold=0.01)

Mask edges whose attribution score is below threshold; returns how many.

prune_nodes(model, x, threshold=0.01)

A smaller model without hidden nodes scoring below threshold.

Works for KAN and sequences of KANLinear; inputs and outputs stay.

prune(model, x, node_threshold=0.01, edge_threshold=0.01)

prune_nodes then prune_edges (pykan's prune).

kanforge.interpret.fit

Symbolic regression of one edge: fit c * f(a * x + b) + d and rank candidates.

For each library function a coarse grid over (a, b) followed by two zoom rounds is searched; for every (a, b) the outer c, d are the exact least-squares solution (variable projection), so the fit is deterministic and needs no gradient. Ranking follows pykan: score = weight_simple * complexity + (1 - weight_simple) * log2(1 + 1e-5 - R^2), lower is better, plus a penalty for cancelling fits: a function used far from where it bends, scaled up and offset back (38 cos(0.2 x) - 38 ~ x^2) also reaches R^2 ~ 1. Its size |c| * max|f| / (half range of y) is ~1 for a real match and large for a Taylor-like imitation.

Suggestion(name, r2, complexity, params, score) dataclass

expr(u)

SymPy expression of the edge for input expression u.

fit_affine(x, y, fn, a_max=10.0, b_max=10.0, grid=41)

Best (a, b, c, d) and R^2 of y ~ c * fn(a * x + b) + d.

suggest_symbolic(x, y, functions=None, weight_simple=0.8, topk=5)

Candidate formulas for samples (x, y) of one edge, best first.

kanforge.interpret.symbolic

Symbolic edges and closed-form formulas of whole models (SymPy).

suggest_edge(layer, o, i, x=None, functions=None, weight_simple=0.8, topk=5, n=201)

Candidate formulas for edge (o, i) of layer over the range of x.

fix_symbolic(layer, o, i, name, x=None, n=201)

Fit c * f(a * x + b) + d to edge (o, i), make it symbolic; returns R^2.

auto_symbolic(model, x, functions=None, weight_simple=0.8, r2_threshold=0.9, n=201)

Make every learned edge symbolic with its best candidate (pykan's auto_symbolic). Ranges come from the activations each layer receives for x. Edges whose best R^2 is below r2_threshold stay learned, so symbolic_formula reports them instead of returning a wrong formula.

The zero function is not a candidate by default — with its zero complexity it would win over every mediocre fit; remove negligible edges with prune_edges instead (or pass functions including "0").

symbolic_formula(model, names=None, digits=4, simplify=False, tol=0.0)

SymPy expressions of every output.

Every edge must be symbolic or pruned (spline and base weights zero up to tol count as zero); otherwise ValueError lists the remaining ones. Also handles MultKAN product nodes and plain Linear layers (models from from_mlp).

kanforge.interpret.kanpiler

kanpiler: compile SymPy formulas into MultKAN models (KAN 2.0).

The expression tree becomes a graph of nodes:

  • a sum (Add) is an addition node, numbers go to its bias;
  • a product of several factors is a binary multiplication node (Mul with more factors is split into nested binary products);
  • a function of an affine argument, c * f(a * u + b) + d with f from the symbolic library (powers, sqrt, exp, log, sin, ...), is an edge;
  • anything else reaching an edge goes through the identity edge.

Nodes are placed on layers by depth; edges that skip layers get identity nodes in between, and an input feeding the same node twice is routed once through an identity node. mode="symbolic" makes every edge symbolic (the model equals the formula); mode="fit" fits the layer's basis to every edge by least squares over the variable ranges (a learnable starting point, like TruKAN's compiler).

kanpile(exprs, variables, backend='torch', basis='bspline', mode='symbolic', ranges=None, samples=1000, seed=0)

Compile SymPy expression(s) of variables into a MultKAN.

Returns (model, outputs) where outputs[k] is the output column of exprs[k] (sum nodes come before product nodes in MultKAN layers). ranges ({variable: (lo, hi)}, default [-1, 1]) are used by mode="fit" to sample the edges and to place the per-input grids.

kanforge.interpret.library

Library of 1-D functions for symbolic edges: c * f(a * x + b) + d.

Every function is written with operations NumPy, PyTorch and MLX share, so the same entry evaluates symbolic edges on any backend; sympy gives its formula and complexity follows pykan's scale (used to prefer simpler candidates). Codes stored in layers are positions in NAMES: append new functions at the end to keep saved models valid.

kanforge.interpret.plot

Plots of edge functions (matplotlib, optional dependency).

plot_layer(layer, x=None, n=201, scores=None, ax_size=1.6)

Grid of every edge function phi_oi (rows: outputs, columns: inputs).

Pruned edges are blank, symbolic ones are titled with their function; with scores (attribution(...)[k]["edge"]) the line opacity shows edge importance. Returns the matplotlib figure.

plot_model(model, x, n=201)

plot_layer for every KAN layer, with attribution opacities; list of figures.

kanforge.interpret.contrastive

pykan's unsupervised mode: find dependent features with a contrastive task.

Real samples (label 1) are mixed with samples whose columns are shuffled independently (label 0), which destroys every dependence between features but keeps their marginals. A KAN trained to tell them apart can only use relations between features; pruning and feature_importance then show which features are related, and auto_symbolic how.

contrastive_samples(x, seed=0)

(inputs, labels) NumPy arrays: x with label 1 and a column-shuffled copy with label 0.