Solve the Bellman Expectation Equation Exactly
Problem Statement
Given a policy already folded into the MDP, compute exactly by solving a linear system — no iteration.
Background
Fix a policy and the MDP collapses into a Markov reward process: a transition matrix where , and a reward vector . The Bellman expectation equation is then one vector equation:
This is linear in , which people often miss because the recursive statement looks like something you have to unroll. Rearranged:
For gamma < 1 the matrix is always invertible, so the solution exists and is unique. The catch is cost: a direct solve is in the number of states, which is why iterative policy evaluation exists at all. Knowing the closed form still matters — it is the ground truth you check your iterative code against.
Your Task
Implement:
def solve_v_pi(P_pi, R_pi, gamma):
...
- P_pi — an n x n nested list, P_pi[s][s2] is the probability of moving from s to s2 under the policy.
- R_pi — a list of n floats, the expected immediate reward in each state under the policy.
- gamma — discount factor, 0.0 <= gamma < 1.0.
Return a list of n floats.
Input / Output Format
Nested lists of floats in, a list of floats out. The grader rounds to 4 decimals.
Sample
P = [[0.5, 0.5, 0.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0]]
R = [1.0, 2.0, 0.0]
print([round(x, 4) for x in solve_v_pi(P, R, 0.9)])
Output:
[3.4545, 2.0, 0.0]
State 2 is absorbing with zero reward so v(2) = 0. Then v(1) = 2 + 0.9*0 = 2. Finally v(0) = 1 + 0.9(0.5v(0) + 0.52)** gives **0.55v(0) = 1.9**, i.e. v(0) = 3.4545....
Example
solve_v_pi([[0.5, 0.5, 0.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0]], [1.0, 2.0, 0.0], 0.9)
[3.4545, 2.0, 0.0]
-
Identify the linear system: The Bellman equation is rearranged to . We construct the coefficient matrix and the reward vector .
-
Compute matrix : Subtract times the transition matrix from the identity matrix:
-
Solve for : The third row of the system corresponds to the absorbing state 2. The equation is , which yields .
-
Solve for : Substitute into the second row equation . This simplifies to .
-
Solve for : Substitute into the first row equation . This gives , so
-
Final Output: Rounding the values to 4 decimal places results in the list
[3.4545, 2.0, 0.0].
Constraints
1 <= n <= 200- Each row of
P_pisums to 1. 0.0 <= gamma < 1.0, soI - gamma*P_piis invertible.- Solve the system directly (
numpy.linalg.solveis available); do not iterate to convergence. - Do not round inside the function.