Source code for gameanalysis.collect

from collections import abc

import numpy as np


[docs]class WeightedSimilaritySet(object): """A set of non-similar elements prioritized by weight Allows adding a bunch of weighted elements, and when iterated, only iterates over dissimilar elements with the lowest weights. Adding new elements that are similar to the existing set, but with higher weights won't change the set returned.""" def __init__(self, is_similar): self._is_similar = is_similar self._i = 0 # Tie breaking self._items = [] self._set = [] self._computed = True
[docs] def add(self, item, weight): self._computed = False self._set.clear() self._items.append((weight, self._i, item)) self._i += 1 return self
def _satisfy(self): if not self._computed: self._items.sort() for w, _, i in self._items: if all(not self._is_similar(i, j) for j, _ in self._set): self._set.append((i, w)) def __len__(self): self._satisfy() return len(self._set) def __iter__(self): self._satisfy() return iter(self._set) def __repr__(self): self._satisfy() suffix = ('.add(' + ').add('.join('{}, {}'.format(i, w) for w, _, i in self._items) + ')' if self._items else '') return '{}({}){}'.format(self.__class__.__name__, self._is_similar.__name__, suffix)
[docs]class DynamicArray(object): """A object with a backed array that also allows adding data""" def __init__(self, item_shape, dtype=None, initial_room=8, grow_fraction=2): assert grow_fraction > 1 if not isinstance(item_shape, abc.Sized): item_shape = (item_shape,) self._data = np.empty((initial_room,) + item_shape, dtype) self._length = 0 self._grow_fraction = 2
[docs] def append(self, array): """Append an array""" array = np.asarray(array, self._data.dtype) if array.shape[1:] == self._data.shape[1:]: # Adding multiple num = array.shape[0] self.ensure_capacity(self._length + num) self._data[self._length:self._length+num] = array self._length += num elif array.shape == self._data.shape[1:]: # Adding one self.ensure_capacity(self._length + 1) self._data[self._length] = array self._length += 1 else: raise ValueError("Invalid shape for append")
[docs] def pop(self, num=None): """Pop one or several arrays""" if num is None: assert self._length > 0, "can't pop from an empty array" self._length -= 1 return self._data[self._length].copy() else: assert num >= 0 and self._length >= num self._length -= num return self._data[self._length:self._length+num].copy()
@property def data(self): """A view of all of the data""" return self._data[:self._length]
[docs] def ensure_capacity(self, new_capacity): """Make sure the array has a least new_capacity""" if new_capacity > self._data.shape[0]: growth = round(self._data.shape[0] * self._grow_fraction) + 1 new_size = max(growth, new_capacity) new_data = np.empty((new_size,) + self._data.shape[1:], self._data.dtype) new_data[:self._length] = self._data[:self._length] self._data = new_data
[docs] def compact(self): """Trim underlying storage to hold only valid data""" self._data = self.data.copy() self._length = self._data.shape[0]
def __len__(self): return self._length def __str__(self): return str(self.data) def __repr__(self): return repr(self.data)