Add shared reward
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
from random import random
|
||||
from typing import Any, Iterable, Mapping
|
||||
|
||||
|
||||
def simulate_trial(p_of_success: float) -> bool:
|
||||
@@ -14,3 +15,81 @@ def simulate_trial(p_of_success: float) -> bool:
|
||||
:returns: True if the trial is successful (with probability 'p_of_success'); otherwise, False.
|
||||
"""
|
||||
return random() < p_of_success
|
||||
|
||||
|
||||
def graph_has_cycle(graph: Mapping[Any, Iterable[Any]]) -> bool:
|
||||
"""Detect cycles in a directed graph.
|
||||
|
||||
Provide the graph as a dictionary that describes which nodes are linked. For example:
|
||||
{0: {1,2}, 1:{2,3}, 3:{0}} here there's a cycle 0 -> 1 -> 3 -> 0
|
||||
{'a': ('b','c'), c:('b')} here there is no cycle
|
||||
|
||||
:param graph: a mapping from node to a set of nodes to which it is connected.
|
||||
:type graph: Mapping[Any, Iterable[Any]]
|
||||
:return: Whether the graph has any cycles
|
||||
:rtype: bool
|
||||
"""
|
||||
visited = set()
|
||||
currently_visiting = set()
|
||||
|
||||
def depth_first_search(node: Any) -> bool:
|
||||
"""Perform depth-first search (DFS) traversal to detect cycles starting from a given node."""
|
||||
if node in currently_visiting:
|
||||
return True # Cycle detected
|
||||
if node in visited:
|
||||
return False # Already visited, no need to explore further
|
||||
|
||||
visited.add(node)
|
||||
currently_visiting.add(node)
|
||||
|
||||
for neighbour in graph.get(node, []):
|
||||
if depth_first_search(neighbour):
|
||||
return True # Cycle detected
|
||||
|
||||
currently_visiting.remove(node)
|
||||
return False
|
||||
|
||||
# Start DFS traversal from each node
|
||||
for node in graph:
|
||||
if depth_first_search(node):
|
||||
return True # Cycle detected
|
||||
|
||||
return False # No cycles found
|
||||
|
||||
|
||||
def topological_sort(graph: Mapping[Any, Iterable[Any]]) -> Iterable[Any]:
|
||||
"""
|
||||
Perform topological sorting on a directed graph.
|
||||
|
||||
This guarantees that if there's a directed edge from node A to node B, then A appears before B.
|
||||
|
||||
:param graph: A dictionary representing the directed graph, where keys are node identifiers
|
||||
and values are lists of outgoing edges from each node.
|
||||
:type graph: dict[int, list[Any]]
|
||||
|
||||
:return: A topologically sorted list of node identifiers.
|
||||
:rtype: list[Any]
|
||||
"""
|
||||
visited: set[Any] = set()
|
||||
stack: list[Any] = []
|
||||
|
||||
def dfs(node: Any) -> None:
|
||||
"""
|
||||
Depth-first search traversal to visit nodes and their neighbors.
|
||||
|
||||
:param node: The current node to visit.
|
||||
:type node: Any
|
||||
"""
|
||||
if node in visited:
|
||||
return
|
||||
visited.add(node)
|
||||
for neighbour in graph.get(node, []):
|
||||
dfs(neighbour)
|
||||
stack.append(node)
|
||||
|
||||
# Perform DFS traversal from each node
|
||||
for node in graph:
|
||||
dfs(node)
|
||||
|
||||
# Reverse the stack and return it.
|
||||
return stack[::-1]
|
||||
|
||||
Reference in New Issue
Block a user