Greedy Policy Improvement
Problem Statement
Given a value function and the model, produce the greedy policy with respect to it, and report whether the policy changed.
Background
The policy improvement theorem is the engine of every control algorithm here. If you have and you build a new deterministic policy that acts greedily with respect to it,
then for every state. Not on average, not eventually — every state, guaranteed. One greedy step can never make the policy worse.
The second half of the theorem is what gives you a stopping rule: if the greedy policy is identical to the one you started from, then already satisfies the Bellman optimality equation, so is optimal and you are done. That equality check is the policy_stable flag in policy iteration.
Because floating-point ties do occur (symmetric actions in a gridworld, for instance), you need a deterministic tie-break or the "did it change?" test will flip-flop forever between equally good policies. Here: break ties toward the lowest action index.
Your Task
Implement:
def policy_improvement(policy, v, P, R, gamma):
...
- policy — a list of n_states ints, the current deterministic policy.
- v — a list of n_states floats.
- P[s][a][s2], R[s][a], gamma as usual.
Return a tuple (new_policy, stable) where new_policy is a list of ints and stable is a bool that is True exactly when new_policy == policy.
Input / Output Format
Lists in; a (list, bool) tuple out.
Sample
P = [[[0.0, 1.0], [1.0, 0.0]], [[1.0, 0.0], [0.0, 1.0]]]
R = [[0.0, 1.0], [2.0, 0.0]]
v = [1.0, 5.0]
new_policy, stable = policy_improvement([0, 1], v, P, R, 0.9)
print(new_policy, stable)
Output:
[0, 1] True
State 0: action 0 gives 0.0 + 0.9*5.0 = 4.5 and action 1 gives 1.0 + 0.9*1.0 = 1.9, so action 0 wins. State 1: action 0 gives 2.0 + 0.9*1.0 = 2.9 and action 1 gives 0.0 + 0.9*5.0 = 4.5, so action 1 wins. The greedy policy [0, 1] equals the policy passed in, so stable is True and policy iteration would halt here.
Example
policy_improvement([0, 1], [1.0, 5.0], [[[0.0, 1.0], [1.0, 0.0]], [[1.0, 0.0], [0.0, 1.0]]], [[0.0, 1.0], [2.0, 0.0]], 0.9)
[0, 1] True
State 0: q(0,0)=0.0+0.95.0=4.5 beats q(0,1)=1.0+0.91.0=1.9, so the greedy action is 0. State 1: q(1,0)=2.0+0.91.0=2.9 versus q(1,1)=0.0+0.95.0=4.5, so the greedy action is 1. The greedy policy [0, 1] matches the input policy, so stable is True.
Constraints
1 <= n_states <= 200,1 <= n_actions <= 20- Ties for the maximum must be broken toward the lowest action index.
stablemust beTrueonly when the new policy equals the input policy in every state.0.0 <= gamma <= 1.0- Return
(new_policy, stable)in that order.