Polynomials and Fourier Basis in RL
Instead of struggling to fit complex value landscapes with unstable polynomial curves, the Fourier basis decomposes continuous states into harmonious, orthogonal cosine waves of increasing frequency.
Why Does This Exist?
When reinforcement learning moves from discrete gridworlds to continuous physical systems—such as controlling a robot arm, balancing a cart-pole, or piloting a spacecraft—tabular Q-learning breaks down because the number of distinct states is infinite. The agent must approximate value functions using function approximation:
Where is a feature vector that transforms raw continuous state coordinates into a higher-dimensional space where linear methods can represent non-linear value surfaces.
The most naive feature transformation is the polynomial basis, constructing features from powers and cross-products (). While mathematically straightforward, polynomials suffer from fatal pathologies in reinforcement learning:
- Global interference: A temporal difference error observed in one corner of the state space modifies polynomial weights that warp value predictions everywhere else, causing catastrophic forgetting.
- Runge's phenomenon and unbounded divergence: Higher-order polynomial features shoot toward near the boundaries of the state space, making gradient updates violently unstable.
- Ill-conditioned Hessians: Polynomial features are non-orthogonal, causing gradient descent to oscillate erratically across narrow error valleys.
To overcome these structural flaws, George Konidaris, Sarah Osentoski, and Philip Thomas (2011) introduced the Fourier basis for reinforcement learning. By using orthogonal cosine harmonics over a normalized hypercube , the Fourier basis guarantees bounded feature outputs in , eliminates destructive global interference, and provides a mathematically grounded frequency-dependent learning rate rule that outperforms polynomials and radial basis functions across continuous control benchmarks.
Think of It Like This
Musical Synthesizers: Taylor Series Polynomials vs. Fourier Harmonic Overtones
Imagine trying to synthesize the warm acoustic resonance of a concert cello on an electronic keyboard:
- The Polynomial Approach (Brute-Force Taylor Approximation): You try to craft the cello's sound wave by superimposing steep algebraic powers: . Because high powers shoot off to infinity at the edges, turning up the volume on to fix a tiny buzzing artifact at the end of the note completely destroys the pitch in the middle of the wave. The entire keyboard screeches with wild, unpredictable distortion.
- The Fourier Basis Approach (Harmonic Synthesis): You synthesize the cello using pure sinusoidal harmonics. You start with the fundamental pitch (the low-frequency base tone, ), and then add subtle second, third, and fourth harmonic overtones of increasing frequency () at decreasing volumes. Because each harmonic is mathematically orthogonal, adjusting a high-frequency overtone adds fine musical texture without altering the fundamental pitch. The sound remains rich, stable, and perfectly bounded within the speaker's dynamic range.
Where the analogy stops: In sound synthesis, harmonics travel across continuous time. In reinforcement learning, the Fourier basis projects continuous spatial state vectors onto multi-dimensional frequency vectors to approximate state values and action-value surfaces.
How It Actually Works
Polynomial Limitations and Konidaris' Fourier Cosine Basis
Consider a continuous state space of dimension , where the state vector is .
1. The Polynomial Basis
For an order- polynomial basis, each feature is formed by integer exponents :
For a 2D state space with order , the complete basis consists of features:
Because these features are not orthogonal over the state domain, their inner products are heavily coupled. Updating weight for alters values across the entire state space, making semi-gradient TD updates sluggish and prone to divergence.
2. The Fourier Cosine Basis
Konidaris et al. demonstrated that using only the cosine functions of a multidimensional Fourier series provides an exceptional basis for linear value approximation. Cosine functions are symmetric about the origin, naturally representing boundary conditions where derivative fluxes approach zero.
Before feature evaluation, continuous state coordinates must be normalized into the unit hypercube:
For an order- Fourier basis, each basis feature is defined by an integer coefficient vector with each :
The total number of basis features for an order- expansion in dimensions is .
3. Why the Fourier Basis Excels in RL
The Fourier basis possesses three mathematical properties that make it uniquely suited for temporal difference learning:
-
Strict Boundedness: Features cannot explode, preventing numerical overflow and gradient spikes.
-
Orthogonality: The basis functions form an orthogonal set under the inner product over : This near-zero cross-correlation keeps the gradient covariance matrix well-conditioned, drastically reducing destructive interference between coarse and fine features.
-
The Natural Frequency-Scaled Step Size Rule: In Fourier analysis, the norm of the gradient scales with frequency . Konidaris et al. proved that applying a uniform learning rate causes high-frequency features to update too aggressively, producing severe high-frequency oscillations ("ringing").
To maintain uniform parameter convergence rates across all spatial scales, learning rates must be scaled inversely with the Euclidean norm of the coefficient vector: Where .
This rule automatically lets low-frequency features capture broad value topography quickly, while high-frequency features gently refine localized details without instability.
Worked numerical example
Consider a 2D continuous state space (e.g., Mountain Car position and velocity) with order .
Let:
- Continuous state
- Base learning rate
- Order basis vectors
Let us compute the features and scaled learning rates step by step:
1. Feature 0: Bias Term ()
- Frequency norm:
- Inner product:
- Feature value:
- Learning rate:
2. Feature 1: Variation along Dimension 2 ()
- Frequency norm:
- Inner product:
- Feature value:
- Learning rate:
3. Feature 2: Variation along Dimension 1 ()
- Frequency norm:
- Inner product:
- Feature value:
- Learning rate:
4. Feature 3: Coupled Diagonal Variation ()
- Frequency norm:
- Inner product:
- Feature value:
- Scaled learning rate:
Summary Table
| Index | Frequency Vector | Frequency Norm | Feature | Scaled Step Size | Spatial Role |
|---|---|---|---|---|---|
| Baseline DC bias | |||||
| Pure vertical axis mode | |||||
| Pure horizontal axis mode | |||||
| Coupled diagonal interaction |
Notice how is automatically damped by to ensure high-frequency cross-terms do not oscillate during value updates.
Code
The following complete, type-hinted Python implementation constructs a multi-dimensional Fourier basis encoder, precomputes frequency-scaled learning rates, and updates a linear value approximator with assertion checks.
import itertoolsimport mathfrom typing import List, Tuple
class FourierBasis: """Fourier Cosine Basis linear feature encoder for continuous RL states.
References: Konidaris, Osentoski, and Thomas (AAAI 2011). 'Value Function Approximation in Reinforcement Learning using the Fourier Basis' """
def __init__( self, state_dim: int, order: int, state_bounds: List[Tuple[float, float]], base_alpha: float = 0.01, ) -> None: self.state_dim: int = state_dim self.order: int = order self.state_bounds: List[Tuple[float, float]] = state_bounds self.base_alpha: float = base_alpha
# Generate all multi-frequency coefficient vectors c in {0, ..., order}^k coord_ranges = [range(order + 1) for _ in range(state_dim)] self.c_vectors: List[List[int]] = [ list(c) for c in itertools.product(*coord_ranges) ] self.num_features: int = len(self.c_vectors)
# Precompute frequency-scaled step sizes: alpha_i = alpha / ||c_i||_2 self.alphas: List[float] = [] for c in self.c_vectors: norm = math.sqrt(sum(ci**2 for ci in c)) self.alphas.append(base_alpha if norm == 0 else base_alpha / norm)
# Initialize linear weights vector to zero self.weights: List[float] = [0.0] * self.num_features
def normalize_state(self, state: List[float]) -> List[float]: """Linearly projects continuous state into unit hypercube [0, 1]^k.""" normalized: List[float] = [] for s_val, (s_min, s_max) in zip(state, self.state_bounds): clamped = max(s_min, min(s_max, s_val)) norm_val = ( (clamped - s_min) / (s_max - s_min) if s_max > s_min else 0.0 ) normalized.append(norm_val) return normalized
def encode(self, state: List[float]) -> List[float]: """Computes basis features phi_i(s) = cos(pi * c_i^T s).""" s_norm = self.normalize_state(state) features: List[float] = [] for c in self.c_vectors: dot_product = sum(ci * si for ci, si in zip(c, s_norm)) features.append(math.cos(math.pi * dot_product)) return features
def predict(self, state: List[float]) -> float: """Computes linear approximation V(s) = w^T phi(s).""" features = self.encode(state) return sum(w * phi for w, phi in zip(self.weights, features))
def update(self, state: List[float], target: float) -> float: """Applies semi-gradient TD update with frequency-scaled learning rates.""" features = self.encode(state) prediction = sum(w * phi for w, phi in zip(self.weights, features)) td_error = target - prediction
# w_i <- w_i + alpha_i * td_error * phi_i(s) for i in range(self.num_features): self.weights[i] += self.alphas[i] * td_error * features[i]
return td_error
# Define 2D continuous state space with raw domain boundariesstate_boundaries = [(0.0, 10.0), (-5.0, 5.0)]fourier_encoder = FourierBasis( state_dim=2, order=1, state_bounds=state_boundaries, base_alpha=0.01)
# Raw state that maps exactly to normalized coords [0.2, 0.8]# s_0 = 2.0 -> (2.0 - 0) / 10 = 0.2# s_1 = 3.0 -> (3.0 - (-5)) / 10 = 0.8query_state = [2.0, 3.0]phi_features = fourier_encoder.encode(query_state)
print("Computed Fourier Features phi(s):")for i, (c, phi, a) in enumerate( zip(fourier_encoder.c_vectors, phi_features, fourier_encoder.alphas)): print(f" Feature {i} (c={c}): phi = {phi:+.4f}, alpha = {a:.6f}")
# Verification assertionsassert len(phi_features) == 4, "Incorrect feature dimension"assert round(phi_features[0], 4) == 1.0000, "Bias term incorrect"assert round(phi_features[1], 4) == -0.8090, "Dim 2 feature incorrect"assert round(phi_features[2], 4) == 0.8090, "Dim 1 feature incorrect"assert round(phi_features[3], 4) == -1.0000, "Coupled diagonal incorrect"assert round(fourier_encoder.alphas[3], 6) == round( 0.01 / math.sqrt(2), 6), "Scaled alpha incorrect"
# Verify semi-gradient value updateinitial_prediction = fourier_encoder.predict(query_state)fourier_encoder.update(query_state, target=5.0)updated_prediction = fourier_encoder.predict(query_state)
print(f"\nInitial V(s): {initial_prediction:.4f}")print(f"Updated V(s): {updated_prediction:.4f}")assert ( updated_prediction > initial_prediction), "Value failed to increase toward target!"print("All assertions passed: Fourier basis correctly encoded and updated!")
# -> Expected output:# -> Computed Fourier Features phi(s):# -> Feature 0 (c=[0, 0]): phi = +1.0000, alpha = 0.010000# -> Feature 1 (c=[0, 1]): phi = -0.8090, alpha = 0.010000# -> Feature 2 (c=[1, 0]): phi = +0.8090, alpha = 0.010000# -> Feature 3 (c=[1, 1]): phi = -1.0000, alpha = 0.007071# -> # -> Initial V(s): 0.0000# -> Updated V(s): 0.1508# -> All assertions passed: Fourier basis correctly encoded and updated!Watch Out For
Skipping [0, 1] State Normalization or Using Uniform Learning Rates
Two primary traps degrade Fourier basis performance in continuous reinforcement learning:
Trap 1: Passing Unnormalized States: The Fourier cosine basis strictly assumes that inputs live on the normalized interval . If you pass raw physical coordinates (such as position and velocity ), the cosine argument wraps through dozens of arbitrary cycles, destroying spatial coherence and causing value predictions to resemble random noise.
- The Fix: Always clip and normalize state variables linearly into using known environmental domain bounds.
Trap 2: Omitting the Frequency-Scaled Learning Rate: Setting a constant step size across all frequencies causes high-order features to update too quickly relative to low-order features. Because high-frequency waves oscillate rapidly over small spatial intervals, uniform updates cause severe "ringing" artifacts and gradient overshoot.
- The Fix: Always scale learning rates inversely by the coefficient norm (retaining for the zero-frequency vector).
The Quick Version
- Polynomial limitations: Polynomial basis functions () suffer from severe global interference, non-orthogonal collinearity, and boundary divergence.
- Fourier cosine basis: Projects continuous normalized states onto orthogonal cosine harmonics .
- Strict boundedness: Every Fourier basis feature is guaranteed to remain inside , preventing gradient blowups and numerical instability.
- Frequency-scaled step sizes: Scaling learning rates by stabilizes high-frequency updates, allowing smooth value landscapes to form without ringing artifacts.