def minimal_steps_number_to(mdp: MDP, T: List[int]) -> List[float]: """ Compute the shortest path in term of edges in the underlying graph of the MDP to T (i.e., the minimal number of steps to reach T in the underlying graph). The function connected_to (a breadth first serach algorithm) is adapted to number the states instead of mark them. :param mdp: a MDP. :param T: a list of target states of the MDP. :return: a list 'steps' such that, for each state s of the MDP, steps[s] = n where n is the minimal number of steps to reach T in the underlying graph of the MDP. """ steps = [float('inf')] * mdp.number_of_states for t in T: steps[t] = 0 next = deque([]) for t in T: next.extend(mdp.pred(t)) i = 1 while len(next) > 0: predecessors = next next = deque([]) while len(predecessors) > 0: pred = predecessors.pop() if steps[pred] > i: steps[pred] = i next.extend(mdp.pred(pred)) i += 1 return steps
def connected_to(mdp: MDP, T: List[int]) -> List[bool]: """ Compute the states connected to T. For this purpose, a backward breadth-first search algorithm on the underlying graph of the MDP is used. :param mdp: a MDP. :param T: a list of target states of the MDP. :return: a list 'marked' such that, for each state s of the MDP, marked[s] = True if s is connected to T in the underlying graph of the MDP. """ marked = [False] * mdp.number_of_states for t in T: marked[t] = True next = deque([]) for t in T: next.extend(mdp.pred(t)) while len(next) > 0: pred = next.pop() if not marked[pred]: marked[pred] = True for predecessor in mdp.pred(pred): next.appendleft(predecessor) return marked