Files
carkov/carkov/utils.py
T

130 lines
3.4 KiB
Python

#
# carkov markov chain library
# © Copyright 2021 by Aldercone Studio <alderconestudio@gmail.com>
# This is free software, see the included LICENSE for terms and conditions.
#
"""
Various utilities the chainers and analyzers use.
"""
import string
from bisect import bisect
from typing import Dict, Callable, List, Sequence
from random import Random
def merge_dict(into: Dict, outof: Dict, mergefunction: Callable = lambda x, y: x + y) -> Dict:
"""
Given two dictionries of dictionaries, merge them together by applying the mergefunction to the
values of the second level dictionary.
Arguments:
into: The dictionary that is being operated on which gets modified.
outof: The dictionary to merge into into.
mergefunction: A function applied to every value in the second level dictionries, defaults to
adding the two values together.
Returns:
into dictionary after modification.
"""
for key in outof.keys():
if key in into:
for innerkey in outof[key].keys():
if innerkey in into[key]:
into[key][innerkey] = mergefunction(into[key][innerkey], outof[key][innerkey])
else:
into[key][innerkey] = outof[key][innerkey]
else:
into[key] = outof[key]
return into
def convert_counts(ind: Dict) -> Dict:
"""
Convert counts produced by analyzers into the statistics counts used by chainers.
Arguments:
ind (dict): The second level dictionary of a counts dictionary
Returns:
dict: A copy of ind with the values updated for chainer use.
"""
out = {}
for k in ind:
out[k] = [ind[k], 0]
return out
def merge_stats(into: Dict, outof: Dict) -> Dict:
"""
Perform a merge_dict in a way safe for the statistics dictionaries used by chainers.
Arguments:
into: The dictionary to modify
outof: The dictionary to merge into into.
Returns:
into (after modification)
"""
def stats_merge_function(i, o):
out = [0, 0]
out[0] = i[0] + o[0]
out[1] = 0
return out
return merge_dict(into, outof, stats_merge_function)
def weighted_choice(random_state: Random, values: Sequence, weights: Sequence):
"""
Choose a random value in a weighted manner.
Arguments:
random_state: A random.Random instance
values: A list of values to choose from
weights: The weights that corrospond to each value
Returns:
The selected value
"""
total: float = 0
cum_weights: List[float] = []
for w in weights:
total += w
cum_weights.append(total)
x = random_state.random() * total
i = bisect(cum_weights, x)
return values[i]
def weighted_stat_choice(random_state: Random, stats: Dict):
"""
Perform a weighted choice on a stat dictionary as used in chainers.
Arguments:
random_state: A random.Random instance
stats: A stats dictionary from a chainer
"""
values = tuple(stats.keys())
weights = tuple(stats[x][1] for x in values)
return weighted_choice(random_state, values, weights)
def make_word(seq: Sequence[str]):
return "".join(seq)
def make_sent(seq: Sequence[str]) -> str:
output = ""
for item in seq:
if item in string.punctuation:
output += item
else:
output += (" " + item) if output else (item)
return output