MAXQ Value Function Decomposition
Instead of solving a massive problem all at once, MAXQ breaks it into a tree of smaller jobs that only look at the details they need to finish.
Why Does This Exist?
Flat reinforcement learning algorithms scale poorly in long-horizon problems with complex subgoal structures. When an agent must navigate across rooms, pick up objects, unlock doors, and deliver cargo, choosing from raw primitive motor commands at every single time step leads to exponential sample complexity and sluggish exploration.
While the Options framework (Sutton et al., 1999) introduced temporally extended actions, options treat subpolicies as black boxes without breaking down the value function itself. An option still evaluates values across the full global state space, offering no built-in mechanism to ignore irrelevant state dimensions.
MAXQ Value Function Decomposition (Dietterich, 2000) solves this limitation by decomposing the core Markov Decision Process into a directed acyclic graph of subtasks. Crucially, MAXQ splits the value function itself into:
- Child Execution Values : The reward earned while executing an immediate child subtask.
- Completion Functions : The expected future reward of completing the rest of the parent task after the child subtask terminates.
By explicitly formalizing completion functions and state abstraction, MAXQ enables subtasks to ignore irrelevant state variables, dramatically compressing the state space and facilitating modular subtask reuse across different parent routines.
Think of It Like This
A modular automotive assembly line in a car factory
Imagine a modern manufacturing plant tasked with building an automobile from raw parts (BuildCar).
- Flat RL: A single robot arm stands in the center of the warehouse. At every millisecond, it must choose which single bolt to turn among 30,000 components, tracking the temperature of the engine, the tire pressure, and the stitch count of the leather seats simultaneously. Learning this way would take centuries.
- The MAXQ Approach: The plant manager organizes production into a hierarchical task graph:
- Root task
BuildCardelegates work to three specialized workstations:AssembleEngine,MountChassis, andInstallInterior. - The technician inside
InstallInteriorfocuses entirely on their localized subtask. - State Abstraction: The interior technician only needs to know the seat anchor positions and upholstery color. They have zero need to know the engine cylinder displacement, camshaft timing, or brake fluid level. Those variables are abstracted away.
- Subtask Termination: The interior subtask terminates as soon as the seats and dashboard are bolted down.
- The Completion Function: Once the interior workstation finishes, the plant manager evaluates what remains to complete
BuildCar(InstallElectronicsandPaintJob).
- Root task
Where the analogy stops: A car factory runs a fixed, pre-scheduled assembly line. In reinforcement learning, the environment is stochastic and dynamic. The agent must dynamically decide which subtask to invoke based on real-time sensor observations () and recursively evaluate completion functions () to choose optimal subtask dispatching.
How It Actually Works
MAXQ Task Graph and Recursive Value Decomposition
The overall MDP is decomposed into a hierarchy of subtasks , where represents the root task. The hierarchy forms a Directed Acyclic Graph (DAG) called the MAXQ Task Graph.
1. Formal Subtask Definition
Each subtask node is defined by a tuple :
- Termination Predicate : A boolean condition that determines whether subtask has completed (e.g., when taxi coordinates match destination coordinates).
- Child Actions : The set of actions that can invoke. Children can be other subtasks or primitive actions.
- Pseudo-Reward Function : An optional intrinsic reward function used to shape subtask policies toward desirable terminal subgoals.
2. Value Function Decomposition
Let be the expected cumulative discounted reward of executing child action from state within parent subtask .
MAXQ decomposes this value function recursively:
where:
- (Child Value): The expected cumulative reward earned during the execution of child action until terminates:
- (Completion Function): The expected cumulative discounted reward of completing the rest of parent subtask after child action terminates: where is the probability that child subtask terminates in state after environment steps.
3. Recursive Policy Execution
At any subtask level , the agent selects the child action that maximizes the sum of child value and parent completion value:
Execution recurses down the task graph until a primitive motor action is dispatched to the environment.
4. State Abstraction
Each subtask is equipped with an abstraction mapping that filters out state dimensions irrelevant to . For example, a navigation subtask only requires the current coordinates and target coordinates , completely ignoring passenger status or final delivery destination. This shields lower-level subtasks from exponential state explosion.
Worked numerical example
Consider the classic Taxi environment where a taxi must pick up a passenger and drop them off at a destination.
Setup:
- Current state: .
- Step cost: per move. Illegal action penalty: .
- Parent subtask: (pickup passenger).
- Candidate child actions for :
- Subtask : Navigate to passenger.
- Primitive action
Pickup: Attempt pickup at current location.
Step 1: Evaluate Child Action 1 ()
- Child Value : Taxi is at and passenger is at . Manhattan distance is steps North.
- Completion Function :
Once completes, the taxi arrives at . To terminate parent subtask (passenger inside taxi), the agent must execute 1 legal
Pickupstep: - Total Q-value:
Step 2: Evaluate Child Action 2 (Immediate Pickup)
- Child Value : Taxi attempts to pick up at where no passenger is present. The environment incurs an illegal action penalty:
- Completion Function : Because the illegal pickup failed, the passenger remains at . Completing still requires navigating 2 steps and executing 1 legal pickup:
- Total Q-value:
Step 3: Action Selection
Evaluating the decision rule:
The hierarchical policy selects , correctly prioritizing navigation over an illegal premature pickup.
Code
from dataclasses import dataclassfrom typing import List, Tuple
@dataclassclass SubtaskOption: """Represents a candidate child subtask or primitive action."""
name: str is_primitive: bool child_value_v: float completion_value_c: float
@property def total_q_value(self) -> float: return self.child_value_v + self.completion_value_c
class MAXQTaskGraphEvaluator: """Demonstrates MAXQ Value Function Decomposition (Dietterich 2000):
Q(i, s, a) = V(a, s) + C(i, s, a) """
def __init__( self, step_cost: float = -1.0, illegal_penalty: float = -10.0 ) -> None: self.step_cost = step_cost self.illegal_penalty = illegal_penalty
def compute_nav_child_value( self, current_pos: Tuple[int, int], target_pos: Tuple[int, int], ) -> float: """Computes V(M_Nav, s) using Manhattan distance step costs.""" distance = abs(current_pos[0] - target_pos[0]) + abs( current_pos[1] - target_pos[1] ) return distance * self.step_cost
def compute_pickup_child_value( self, taxi_pos: Tuple[int, int], pass_pos: Tuple[int, int], ) -> float: """Computes V(Pickup, s): legal pickup cost or illegal penalty.""" if taxi_pos == pass_pos: return self.step_cost return self.illegal_penalty
def evaluate_m_get_subtask( self, taxi_pos: Tuple[int, int], pass_pos: Tuple[int, int], ) -> List[SubtaskOption]: """Evaluates child choices under parent subtask M_Get.""" # 1. Option: Call Navigation child M_Nav v_nav = self.compute_nav_child_value(taxi_pos, pass_pos) # Completing M_Get after arriving requires 1 pickup step c_nav = self.step_cost opt_nav = SubtaskOption( name="M_Nav", is_primitive=False, child_value_v=v_nav, completion_value_c=c_nav, )
# 2. Option: Call primitive Pickup immediately v_pickup = self.compute_pickup_child_value(taxi_pos, pass_pos) # Completing M_Get after illegal pickup requires 2 nav steps + 1 legal pickup dist = abs(taxi_pos[0] - pass_pos[0]) + abs(taxi_pos[1] - pass_pos[1]) c_pickup = (dist + 1) * self.step_cost opt_pickup = SubtaskOption( name="Pickup", is_primitive=True, child_value_v=v_pickup, completion_value_c=c_pickup, )
return [opt_nav, opt_pickup]
@staticmethod def select_best_subtask(options: List[SubtaskOption]) -> SubtaskOption: """Selects argmax_{a} [ V(a, s) + C(i, s, a) ].""" return max(options, key=lambda opt: opt.total_q_value)
# Test scenario matching the worked numerical exampleevaluator = MAXQTaskGraphEvaluator(step_cost=-1.0, illegal_penalty=-10.0)taxi_start = (1, 1)passenger_location = (1, 3)
options = evaluator.evaluate_m_get_subtask(taxi_start, passenger_location)
for opt in options: print( f"Child: {opt.name:<6} | V(a, s): {opt.child_value_v:5.1f} | " f"C(i, s, a): {opt.completion_value_c:5.1f} | Q(i, s, a): {opt.total_q_value:5.1f}" )# -> Child: M_Nav | V(a, s): -2.0 | C(i, s, a): -1.0 | Q(i, s, a): -3.0# -> Child: Pickup | V(a, s): -10.0 | C(i, s, a): -3.0 | Q(i, s, a): -13.0
best_choice = evaluator.select_best_subtask(options)print( f"Selected Subtask: {best_choice.name} (Q = {best_choice.total_q_value:.1f})")# -> Selected Subtask: M_Nav (Q = -3.0)
# Verification assertionsassert options[0].name == "M_Nav"assert options[0].child_value_v == -2.0assert options[0].completion_value_c == -1.0assert options[0].total_q_value == -3.0
assert options[1].name == "Pickup"assert options[1].child_value_v == -10.0assert options[1].completion_value_c == -3.0assert options[1].total_q_value == -13.0
assert best_choice.name == "M_Nav"Watch Out For
Recursive Optimality vs. Global Optimality in Subtask Hierarchies
A fundamental theoretical limitation of the MAXQ framework is that it guarantees recursive optimality, not global optimality.
In recursive optimality, each subtask policy is optimal given the fixed policies of its child subtasks. However, a child subtask is blind to the future goals of sibling or parent tasks.
- Example: In a navigation subtask , the agent may have two doors that both lead out of a room in 3 steps. The child subtask considers them equally optimal and arbitrarily picks Door 1. However, Door 2 would have placed the agent directly adjacent to the passenger for the next subtask, saving 10 steps overall. Because terminates locally, it produces a globally sub-optimal trajectory.
The Fix:
- Pseudo-Rewards : Carefully design intrinsic terminal pseudo-rewards that reward subtasks for terminating in specific states that maximize the parent completion function .
- Hierarchical Fine-Tuning: After pre-training modular subtasks under MAXQ decomposition, unfreeze the hierarchy and allow joint end-to-end fine-tuning across boundary states.
The Quick Version
- MAXQ decomposes complex Markov Decision Processes into a hierarchical Directed Acyclic Graph (DAG) of reusable subtasks with localized termination predicates .
- The core value decomposition splits action-values into child execution value and parent completion value : .
- State abstraction shields lower-level subtasks by filtering out state variables irrelevant to their local objectives, exponentially shrinking the effective state space.
- MAXQ achieves recursive optimality rather than global optimality; child subtasks optimize local subgoals independently of global parent contexts unless guided by pseudo-rewards.