Radial Basis Functions in RL
Radial basis functions tile a continuous state space with smooth overlapping bells instead of sharp boxes, so the value surface stays differentiable and a small step in any direction gives a small sensible change.
Why Does This Exist?
Robot joints, velocities, and torques vary continuously, but the classic linear features are binary: a state is either inside a tile or outside it. Cross a tile coding boundary and the value estimate jumps like a staircase, flat plates separated by cliffs. On the plates the spatial gradient is exactly zero, so an actor-critic gets no direction to follow; at the edges the gradient does not exist at all.
Radial basis functions fix the representation, not the algorithm. Each feature is a smooth bell, usually Gaussian, centered at a prototype state. A state near the center activates the feature strongly, a far state barely at all, and everything in between varies continuously. The value surface becomes infinitely differentiable, the spatial gradient exists everywhere, and policy methods can climb it. Sutton and Barto present RBFs as the continuous generalization of coarse coding, and the formula below is theirs.
This page covers the Gaussian form, the update, the bandwidth trade-off, and one fully traced state. For the binary tiling it replaces, see tile coding. For the linear methods both plug into, see value function approximation.
Think of It Like This
Stage lights with soft lenses
Three spotlights hang over a dark stage, aimed at the left mark, center mark, and right mark. Each carries a soft diffusion lens instead of a sharp shutter: full brightness at its own mark, fading smoothly outward in a bell curve.
Stand just right of center. The center beam hits you at 95 percent, the right beam's halo reaches you at 41 percent, and the far left beam barely brushes you at 14 percent. Your total light is the blend of all three, and every step you take changes it gradually. Nothing flickers, nothing jumps, because there are no edges to cross.
Map it point for point: marks are basis centers, brightness percentages are feature activations, the blend is the weighted sum with learned weights, and the absence of shutters is differentiability.
Where it stops: stage light only adds, while learned weights can be negative. Dips and penalty valleys in a value surface need those negative weights, which have no lighting equivalent.
How It Actually Works
A continuous state becomes a feature vector through one Gaussian per center with width :
In words: exponentiate the negative squared distance, scaled by the width. At the center the activation is ; far away it decays toward zero. The value estimate is a plain weighted sum, , and because the Gaussian is smooth, the spatial gradient exists in closed form:
Learning is the semi-gradient update: observe a target for the visited state, form the error , and move each weight in proportion to its activation, . The nearest center absorbs most of the update, neighbors get a smooth share, and nobody gets a cliff.
Worked example: state 0.60 under three bells
Centers at with shared width , so . Weights start at , step size , observed target .
First the activations at :
Then the value, term by term:
The error is , and each weight moves by :
The nearest center takes the largest step () while the far one barely moves (), with no boundary deciding who learns. The diagram above draws these same three bells and the they produce.
The one knob: bandwidth
Width sets how far each bell reaches, and both extremes hurt. Too wide and every bell sees everything: sharp reward peaks wash out into a bland average. Too narrow and bells stop overlapping: states between centers activate nothing, predictions collapse toward zero, and gradients vanish in the dead zones. The working rule is to space centers evenly and set near the center spacing, so neighbors cross around activation. Against binary tilings, the summary is short: RBFs cost a transcendental exponential per basis per step and go dense everywhere, while tile coding costs a few integer lookups and stays sparse, which is why tilings survive in high dimensions and RBFs own the low-dimensional smooth jobs.
Code
Plain standard library, matching the hand trace exactly:
import math
def rbf_features(state: float, centers: list[float], sigma: float) -> list[float]: denom = 2.0 * sigma * sigma return [math.exp(-((state - c) ** 2) / denom) for c in centers]
centers = [0.0, 0.5, 1.0]weights = [2.0, 5.0, 8.0]state, target, alpha = 0.60, 10.0, 0.1
phi = rbf_features(state, centers, 0.3)value = sum(w * p for w, p in zip(weights, phi))delta = target - valueweights = [w + alpha * delta * p for w, p in zip(weights, phi)]
print([round(p, 4) for p in phi]) # -> [0.1353, 0.946, 0.4111]print(round(value, 4)) # -> 8.2894print(round(delta, 4)) # -> 1.7106print([round(w, 4) for w in weights]) # -> [2.0232, 5.1618, 8.0703]Four prints, four matches with the worked example: features, value, error, and updated weights.
Watch Out For
Gridding centers in high dimensions
Even spacing sounds principled until you count. Five centers per dimension across an 8-dimensional arm needs bells, every one evaluated densely on every step, each costing distance math plus an exponential. Tile coding answers the same space with a handful of active tiles. The fix is to stop gridding: place centers on states the agent actually visits, cluster replay observations and plant bells there, and switch to tilings or neural features once dimensions outgrow a dozen.
Dead zones between narrow bells
When centers sit far apart relative to , the gaps between them activate nothing: every rounds to zero, the value reads as zero, and the update moves nothing, so the zone never learns its way out. The symptom is a value surface with confident predictions near centers and flat zero deserts between them. The fix is normalized activations that always sum to one, , which guarantees every state belongs somewhere.
The Quick Version
- Gaussian bells turn a continuous state into smooth features in , replacing sharp tile memberships.
- State under centers gives features and value under weights .
- Target gives error and new weights , shared smoothly by distance.
- The value surface is differentiable everywhere, so actor methods get usable spatial gradients.
- Set width near center spacing; normalize activations or cluster centers to avoid dead zones and dimensional blowup.