Skip to content

Commit

Permalink
adding MaxAccumulator, MinAccumulator, and HistogramCounter, some sim…
Browse files Browse the repository at this point in the history
…ple but very useful primitives.
  • Loading branch information
mahmoud committed Apr 5, 2016
1 parent fbd1e13 commit 58f4a1c
Showing 1 changed file with 78 additions and 0 deletions.
78 changes: 78 additions & 0 deletions lithoxyl/accumulators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

import math
from bisect import bisect_right, insort

# TODO: trivial to implement reset on these, but recreation might be better practice?

class MaxAccumulator(object):
# max_list is sorted in ascending order
def __init__(self, count=10):
self.max_list = []
self.max_len = count

def add(self, val):
max_list, max_len = self.max_list, self.max_len
if max_list and val <= max_list[0]:
return
if len(max_list) < max_len:
insort(max_list, val)
return

idx = bisect_right(max_list, val)
if idx == max_len:
max_list.append(val)
max_list.pop(0)
else:
max_list[idx] = val
return


class MinAccumulator(object):
# min_list is sorted in ascending order
def __init__(self, count=10):
self.min_list = []
self.max_len = count

def add(self, val):
min_list, max_len = self.min_list, self.max_len
if min_list and val >= min_list[-1]:
return
if len(min_list) < max_len:
insort(min_list, val)
return

idx = bisect_right(min_list, val)
if idx == 0:
min_list.insert(0, val)
min_list.pop()
else:
min_list[idx] = val
return


class HistogramCounter(object):
def __init__(self, bounds):
try:
bounds_float = [float(b) for b in bounds]
except ValueError:
raise TypeError('expected iterable of numeric ranges, not %r'
% (bounds,))
if any([math.isnan(b) for b in bounds_float]):
raise ValueError('expected non-NaN floats, not %r' % (bounds,))
bounds_set = set(bounds_float)

bounds_set.add(float('inf'))
bounds_set.add(float('-inf'))
bounds_sorted = sorted(bounds_set)
self.bounds = bounds_sorted
self.ranges = [(b1, b2) for b1, b2 in
zip(bounds_sorted, bounds_sorted[1:])]
self.buckets = [0] * len(self.ranges)

def add(self, val):
bucket_idx = bisect_right(self.bounds, val) - 1
self.buckets[bucket_idx] += 1
return

def get_results(self):
return zip(self.ranges, self.buckets)

0 comments on commit 58f4a1c

Please sign in to comment.