| # Copyright (c) 2021 The Regents of The University of California | |
| # All rights reserved. | |
| # | |
| # Redistribution and use in source and binary forms, with or without | |
| # modification, are permitted provided that the following conditions are | |
| # met: redistributions of source code must retain the above copyright | |
| # notice, this list of conditions and the following disclaimer; | |
| # redistributions in binary form must reproduce the above copyright | |
| # notice, this list of conditions and the following disclaimer in the | |
| # documentation and/or other materials provided with the distribution; | |
| # neither the name of the copyright holders nor the names of its | |
| # contributors may be used to endorse or promote products derived from | |
| # this software without specific prior written permission. | |
| # | |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| from abc import ABC | |
| from typing import Any, Iterable, Optional, Union, List | |
| from .jsonserializable import JsonSerializable | |
| from .storagetype import StorageType | |
| class Statistic(ABC, JsonSerializable): | |
| """ | |
| The abstract base class for all Python statistics. | |
| """ | |
| value: Any | |
| type: Optional[str] | |
| unit: Optional[str] | |
| description: Optional[str] | |
| datatype: Optional[StorageType] | |
| def __init__(self, value: Any, type: Optional[str] = None, | |
| unit: Optional[str] = None, | |
| description: Optional[str] = None, | |
| datatype: Optional[StorageType] = None): | |
| self.value = value | |
| self.type = type | |
| self.unit = unit | |
| self.description = description | |
| self.datatype = datatype | |
| class Scalar(Statistic): | |
| """ | |
| A scalar Python statistic type. | |
| """ | |
| value: Union[float, int] | |
| def __init__(self, value: Any, | |
| unit: Optional[str] = None, | |
| description: Optional[str] = None, | |
| datatype: Optional[StorageType] = None): | |
| super().__init__(value=value, type="Scalar", unit=unit, | |
| description=description, datatype=datatype) | |
| class BaseScalarVector(Statistic): | |
| """ | |
| An abstract base class for classes containing a vector of Scalar values. | |
| """ | |
| value: List[Union[int,float]] | |
| def __init__(self, value: Iterable[Union[int,float]], | |
| type: Optional[str] = None, | |
| unit: Optional[str] = None, | |
| description: Optional[str] = None, | |
| datatype: Optional[StorageType] = None): | |
| super().__init__(value=list(value), type=type, unit=unit, | |
| description=description, datatype=datatype) | |
| def mean(self) -> float: | |
| """ | |
| Returns the mean of the value vector. | |
| Returns | |
| ------- | |
| float | |
| The mean value across all bins. | |
| """ | |
| assert(self.value != None) | |
| assert(isinstance(self.value, List)) | |
| from statistics import mean as statistics_mean | |
| return statistics_mean(self.value) | |
| def count(self) -> float: | |
| """ | |
| Returns the count across all the bins. | |
| Returns | |
| ------- | |
| float | |
| The sum of all bin values. | |
| """ | |
| assert(self.value != None) | |
| return sum(self.value) | |
| class Distribution(BaseScalarVector): | |
| """ | |
| A statistic type that stores information relating to distributions. Each | |
| distribution has a number of bins (>=1) | |
| between this range. The values correspond to the value of each bin. | |
| E.g., value[3]` is the value of the 4th bin. | |
| It is assumed each bucket is of equal size. | |
| """ | |
| min: Union[float, int] | |
| max: Union[float, int] | |
| num_bins: int | |
| bin_size: Union[float, int] | |
| sum: Optional[int] | |
| sum_squared: Optional[int] | |
| underflow: Optional[int] | |
| overflow: Optional[int] | |
| logs: Optional[float] | |
| def __init__(self, value: Iterable[int], | |
| min: Union[float, int], | |
| max: Union[float, int], | |
| num_bins: int, | |
| bin_size: Union[float, int], | |
| sum: Optional[int] = None, | |
| sum_squared: Optional[int] = None, | |
| underflow: Optional[int] = None, | |
| overflow: Optional[int] = None, | |
| logs: Optional[float] = None, | |
| unit: Optional[str] = None, | |
| description: Optional[str] = None, | |
| datatype: Optional[StorageType] = None): | |
| super().__init__(value=value, type="Distribution", unit=unit, | |
| description=description, datatype=datatype) | |
| self.min = min | |
| self.max = max | |
| self.num_bins = num_bins | |
| self.bin_size = bin_size | |
| self.sum = sum | |
| self.underflow = underflow | |
| self.overflow = overflow | |
| self.logs = logs | |
| self.sum_squared = sum_squared | |
| # These check some basic conditions of a distribution. | |
| assert(self.bin_size >= 0) | |
| assert(self.num_bins >= 1) | |
| class Accumulator(BaseScalarVector): | |
| """ | |
| A statistical type representing an accumulator. | |
| """ | |
| _count: int | |
| min: Union[int, float] | |
| max: Union[int, float] | |
| sum_squared: Optional[int] | |
| def __init__(self, value: Iterable[Union[int,float]], | |
| count: int, | |
| min: Union[int, float], | |
| max: Union[int, float], | |
| sum_squared: Optional[int] = None, | |
| unit: Optional[str] = None, | |
| description: Optional[str] = None, | |
| datatype: Optional[StorageType] = None): | |
| super().__init__(value=value, type="Accumulator", unit=unit, | |
| description=description, datatype=datatype) | |
| self._count = count | |
| self.min = min | |
| self.max = max | |
| self.sum_squared = sum_squared | |
| def count(self) -> int: | |
| return self._count |