From b2d571de1f8e6997e9263e460d7af25de04a8265 Mon Sep 17 00:00:00 2001 From: Tapajyoti Bose Date: Tue, 23 Jun 2020 11:32:03 +0530 Subject: [PATCH 1/2] Added Markov Chain --- other/markov_chain.py | 80 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 other/markov_chain.py diff --git a/other/markov_chain.py b/other/markov_chain.py new file mode 100644 index 000000000000..f410fcfab449 --- /dev/null +++ b/other/markov_chain.py @@ -0,0 +1,80 @@ +from random import random +from typing import Dict, List, Tuple + + +class MarkovChainGraphUndirectedUnweighted: + ''' + Undirected Unweighted Graph for running Markov Chain Algorithm + ''' + + def __init__(self): + self.connections = {} + + def add_node(self, node: str) -> None: + self.connections[node] = {} + + def add_transition_probability(self, node1: str, + node2: str, + probability: float) -> None: + if node1 not in self.connections: + self.add_node(node1) + if node2 not in self.connections: + self.add_node(node2) + self.connections[node1][node2] = probability + + def get_nodes(self) -> List[str]: + return list(self.connections.keys()) + + def transition(self, node: str) -> str: + current_probability = 0 + random_value = random() + + for dest in self.connections[node]: + current_probability += self.connections[node][dest] + if current_probability > random_value: + return dest + + +def get_transitions(start: str, + transitions: List[Tuple[str, str, float]], + steps: int) -> Dict[str, int]: + ''' + Running Markov Chain algorithm and calculating the number of times each node is + visited + + >>> transitions = [ + ... ('a', 'a', 0.9), + ... ('a', 'b', 0.075), + ... ('a', 'c', 0.025), + ... ('b', 'a', 0.15), + ... ('b', 'b', 0.8), + ... ('b', 'c', 0.05), + ... ('c', 'a', 0.25), + ... ('c', 'b', 0.25), + ... ('c', 'c', 0.5) + ... ] + + >>> result = get_transitions('a', transitions, 5000) + + >>> assert result['a'] > result['b'] > result['c'] + ''' + + graph = MarkovChainGraphUndirectedUnweighted() + + for node1, node2, probability in transitions: + graph.add_transition_probability(node1, node2, probability) + + visited = {node: 0 for node in graph.get_nodes()} + node = start + + for _ in range(steps): + node = graph.transition(node) + visited[node] += 1 + + return visited + + +if __name__ == "__main__": + import doctest + + doctest.testmod() From 865cfe7155fdde6ef46e2fa47f97444928b1c1bf Mon Sep 17 00:00:00 2001 From: Tapajyoti Bose Date: Tue, 23 Jun 2020 15:50:33 +0530 Subject: [PATCH 2/2] Implemented suggestions --- other/markov_chain.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/other/markov_chain.py b/other/markov_chain.py index f410fcfab449..d5893d849471 100644 --- a/other/markov_chain.py +++ b/other/markov_chain.py @@ -1,3 +1,4 @@ +from collections import Counter from random import random from typing import Dict, List, Tuple @@ -23,7 +24,7 @@ def add_transition_probability(self, node1: str, self.connections[node1][node2] = probability def get_nodes(self) -> List[str]: - return list(self.connections.keys()) + return list(self.connections) def transition(self, node: str) -> str: current_probability = 0 @@ -56,7 +57,8 @@ def get_transitions(start: str, >>> result = get_transitions('a', transitions, 5000) - >>> assert result['a'] > result['b'] > result['c'] + >>> result['a'] > result['b'] > result['c'] + True ''' graph = MarkovChainGraphUndirectedUnweighted() @@ -64,7 +66,7 @@ def get_transitions(start: str, for node1, node2, probability in transitions: graph.add_transition_probability(node1, node2, probability) - visited = {node: 0 for node in graph.get_nodes()} + visited = Counter(graph.get_nodes()) node = start for _ in range(steps):