diff --git a/src/rewriting_hw_1/walker_scheme.py b/src/rewriting_hw_1/walker_scheme.py new file mode 100644 index 0000000..26ee8b4 --- /dev/null +++ b/src/rewriting_hw_1/walker_scheme.py @@ -0,0 +1,76 @@ +from math import floor + + +class WalkerScheme: + def __init__(self, events_and_probabilities: list[tuple[str, int]]): + if sum(probability[1] for probability in events_and_probabilities) != 1: + raise Exception("Сумма вероятностей не равна 1.") + self.table = self._get_table(events_and_probabilities) + + def _get_table(self, events_and_probabilities): + """Генерирует таблицу Уолкера.""" + equal_probability = ( + 1 / len(events_and_probabilities) + ) # Переменная с вероятностью события, если бы все события были равновероятными. + probabilities = { + event: equal_probability for event, _ in events_and_probabilities + } # Словарь, где изначально все вероятности эквивалентны и меняются после донорства кого-то кому-то. + how_many_added_for_event = { + event: 0 for event, _ in events_and_probabilities + } # Для заполнения нерозданных отрезков в конце + table = [] + global_barrier = 0 + + for i in range(len(events_and_probabilities)): + break_flag = False + for donor_event, donor_probability in events_and_probabilities: + if donor_probability < probabilities[donor_event]: + for ( + recipient_event, + recipient_probability, + ) in events_and_probabilities: + if recipient_probability > probabilities[recipient_event]: + table.append( + ( + donor_event, + recipient_event, + global_barrier + + equal_probability + - probabilities[donor_event] + + donor_probability, # Подсчёт барьера, где к глобальному барьеру прибавляется остаток вероятности донора по модулю эквивалентной вероятности + ) + ) + global_barrier += equal_probability + + how_many_added_for_event[recipient_event] += ( + equal_probability + - probabilities[donor_event] + + donor_probability + ) + how_many_added_for_event[donor_event] += ( + probabilities[donor_event] - donor_probability + ) + + probabilities[recipient_event] += ( + probabilities[donor_event] - donor_probability + ) + probabilities[donor_event] = donor_probability + + break_flag = True + break + if break_flag: + break + else: # Для оставшихся + for event, probability in how_many_added_for_event.items(): + print(how_many_added_for_event) + if probability < probabilities[event]: + global_barrier += equal_probability + table.append((event, event, global_barrier)) + break + + return table + + def get_random(self, probability): + if self.table[floor(probability * len(self.table))][2] > probability: + return self.table[floor(probability * len(self.table))][0] + return self.table[floor(probability * len(self.table))][1] diff --git a/tests/walker_scheme_test.py b/tests/walker_scheme_test.py new file mode 100644 index 0000000..41ab194 --- /dev/null +++ b/tests/walker_scheme_test.py @@ -0,0 +1,9 @@ +from rewriting_hw_1.walker_scheme import WalkerScheme + + +def test_exception(): + try: + scheme = WalkerScheme([("A", 0.1), ("B", 1)]) + print(scheme) + except Exception as e: + assert str(e) == "Сумма вероятностей не равна 1."