-
Notifications
You must be signed in to change notification settings - Fork 25
Direct memory access to accumulators #194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 14 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
ea2c381
Allow direct memory access, no longer throws error/segfault
henryiii c1227ac
Internalize accumulators
henryiii 3c9b2af
First working version of conversion
henryiii 8dc503c
Fix several bugs, and change the meaning of np.asarray() slightly
henryiii f1e6c89
Fix view not returning an editable view
henryiii 3e55a80
Normalize names
henryiii f1dd6a6
Nicer repr and str for views
henryiii b1f154b
Cleanup views with a decorator
henryiii d61118a
Some small polish
henryiii e198e25
Fix #195, unlimited and atomic single access
henryiii 29808b0
Adding tests for storages
henryiii eab4378
README update
henryiii 09c6ec0
CHANGELOG and renable a test
henryiii c88b1a2
Fix unneeded change
henryiii f0ca2e7
Address review comments
henryiii 7fc7f6b
Move ostream, remove some extra headers
henryiii 164f66e
Fix reprs, add missing tests
henryiii 91c033d
Adding accum[key] access
henryiii 7f41e94
Addressing second review
henryiii bcd53cb
Rename wsum and wsum2
henryiii File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| from __future__ import absolute_import, division, print_function | ||
|
|
||
| from ..accumulators import Mean, WeightedMean, WeightedSum | ||
|
|
||
| import numpy as np | ||
|
|
||
|
|
||
| class View(np.ndarray): | ||
| __slots__ = () | ||
|
|
||
| def __getitem__(self, ind): | ||
| sliced = super(View, self).__getitem__(ind) | ||
|
|
||
| # If the shape is empty, return the parent type | ||
| if not sliced.shape: | ||
| return self._PARENT._make(*sliced) | ||
| # If the dtype has changed, return a normal array (no longer a record) | ||
| elif sliced.dtype != self.dtype: | ||
| return np.asarray(sliced) | ||
| # Otherwise, no change, return the same View type | ||
| else: | ||
| return sliced | ||
|
|
||
| def __repr__(self): | ||
| # Numpy starts the ndarray class name with "array", so we replace it | ||
| # with our class name | ||
| return ( | ||
| "{self.__class__.__name__}(\n ".format(self=self) | ||
| + repr(self.view(np.ndarray))[6:] | ||
| ) | ||
|
|
||
| def __str__(self): | ||
| fields = ", ".join(self._FIELDS) | ||
| return "{self.__class__.__name__}: ({fields})\n{arr}".format( | ||
| self=self, fields=fields, arr=self.view(np.ndarray) | ||
| ) | ||
|
|
||
|
|
||
| def fields(*names): | ||
| """ | ||
| This decorator adds the name to the _FIELDS | ||
| class property (for printing in reprs), and | ||
| adds a property that looks like this: | ||
|
|
||
| @property | ||
| def name(self): | ||
| return self["name"] | ||
| @name.setter | ||
| def name(self, value): | ||
| self["name"] = value | ||
| """ | ||
|
|
||
| def injector(cls): | ||
| if hasattr(cls, "_FIELDS"): | ||
| raise RuntimeError( | ||
| "{0} already has had a fields decorator applied".format( | ||
| self.__class__.__name__ | ||
| ) | ||
| ) | ||
| fields = [] | ||
| for name in names: | ||
| fields.append(name) | ||
|
|
||
| def fget(self): | ||
| return self[name] | ||
|
|
||
| def fset(self, value): | ||
| self[name] = value | ||
|
|
||
| setattr(cls, name, property(fget, fset)) | ||
| cls._FIELDS = tuple(fields) | ||
| return cls | ||
|
|
||
| return injector | ||
|
|
||
|
|
||
| @fields("value", "variance") | ||
| class WeightedSumView(View): | ||
| __slots__ = () | ||
| _PARENT = WeightedSum | ||
|
|
||
|
|
||
| @fields( | ||
| "sum_of_weights", | ||
| "sum_of_weights_squared", | ||
| "value", | ||
| "sum_of_weighted_deltas_squared", | ||
| ) | ||
| class WeightedMeanView(View): | ||
| __slots__ = () | ||
| _PARENT = WeightedMean | ||
|
|
||
| @property | ||
| def variance(self): | ||
| return self["sum_of_weighted_deltas_squared"] / ( | ||
| self["sum_of_weights"] | ||
| - self["sum_of_weights_squared"] / self["sum_of_weights"] | ||
| ) | ||
|
|
||
|
|
||
| @fields("count", "value", "sum_of_deltas_squared") | ||
| class MeanView(View): | ||
| __slots__ = () | ||
| _PARENT = Mean | ||
|
|
||
| # Variance is a computation | ||
| @property | ||
| def variance(self): | ||
| return self["sum_of_deltas_squared"] / (self["count"] - 1) | ||
|
|
||
|
|
||
| def _to_view(item, value=False): | ||
| for cls in View.__subclasses__(): | ||
| if cls._FIELDS == item.dtype.names: | ||
| ret = item.view(cls) | ||
| if value and ret.shape: | ||
| return ret.value | ||
| else: | ||
| return ret | ||
| return item |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| // Copyright 2015-2019 Hans Dembinski and Henry Schreiner | ||
| // | ||
| // Distributed under the Boost Software License, version 1.0. | ||
| // (See accompanying file LICENSE_1_0.txt | ||
| // or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| // | ||
| // Based on boost/histogram/accumulators/mean.hpp | ||
| // Changes: | ||
| // * Internal values are public for access from Python | ||
| // * A special constructor added for construction from Python | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <boost/assert.hpp> | ||
| #include <boost/core/nvp.hpp> | ||
| #include <boost/histogram/fwd.hpp> // for mean<> | ||
henryiii marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| #include <boost/throw_exception.hpp> | ||
| #include <stdexcept> | ||
| #include <type_traits> | ||
|
|
||
| namespace boost { | ||
henryiii marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| namespace histogram { | ||
| namespace python { | ||
|
|
||
| /** Calculates mean and variance of sample. | ||
| Uses Welfords's incremental algorithm to improve the numerical | ||
henryiii marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| stability of mean and variance computation. | ||
| */ | ||
| template <class RealType> | ||
| struct mean { | ||
| public: | ||
henryiii marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| mean() = default; | ||
| mean(const RealType &n, const RealType &mean, const RealType &variance) noexcept | ||
| : sum_(n) | ||
| , mean_(mean) | ||
| , sum_of_deltas_squared_(variance * (n - 1)) {} | ||
|
|
||
| mean(const RealType &sum, | ||
| const RealType &mean, | ||
| const RealType &sum_of_deltas_squared, | ||
| bool /* Tag to trigger python internal constructor */) | ||
henryiii marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| : sum_(sum) | ||
| , mean_(mean) | ||
| , sum_of_deltas_squared_(sum_of_deltas_squared) {} | ||
|
|
||
| void operator()(const RealType &x) noexcept { | ||
| sum_ += static_cast<RealType>(1); | ||
| const auto delta = x - mean_; | ||
| mean_ += delta / sum_; | ||
| sum_of_deltas_squared_ += delta * (x - mean_); | ||
| } | ||
|
|
||
| void operator()(const weight_type<RealType> &w, const RealType &x) noexcept { | ||
| sum_ += w.value; | ||
| const auto delta = x - mean_; | ||
| mean_ += w.value * delta / sum_; | ||
| sum_of_deltas_squared_ += w.value * delta * (x - mean_); | ||
| } | ||
|
|
||
| template <class T> | ||
| mean &operator+=(const mean<T> &rhs) noexcept { | ||
| if(sum_ != 0 || rhs.sum_ != 0) { | ||
| const auto tmp = mean_ * sum_ + static_cast<RealType>(rhs.mean_ * rhs.sum_); | ||
| sum_ += rhs.sum_; | ||
| mean_ = tmp / sum_; | ||
| } | ||
| sum_of_deltas_squared_ += static_cast<RealType>(rhs.sum_of_deltas_squared_); | ||
| return *this; | ||
| } | ||
|
|
||
| mean &operator*=(const RealType &s) noexcept { | ||
| mean_ *= s; | ||
| sum_of_deltas_squared_ *= s * s; | ||
| return *this; | ||
| } | ||
|
|
||
| template <class T> | ||
| bool operator==(const mean<T> &rhs) const noexcept { | ||
| return sum_ == rhs.sum_ && mean_ == rhs.mean_ | ||
| && sum_of_deltas_squared_ == rhs.sum_of_deltas_squared_; | ||
| } | ||
|
|
||
| template <class T> | ||
| bool operator!=(const mean<T> &rhs) const noexcept { | ||
| return !operator==(rhs); | ||
| } | ||
|
|
||
| const RealType &count() const noexcept { return sum_; } | ||
henryiii marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| const RealType &value() const noexcept { return mean_; } | ||
| RealType variance() const noexcept { return sum_of_deltas_squared_ / (sum_ - 1); } | ||
|
|
||
| template <class Archive> | ||
| void serialize(Archive &ar, unsigned version) { | ||
henryiii marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if(version == 0) { | ||
| // read only | ||
| std::size_t sum; | ||
| ar &make_nvp("sum", sum); | ||
| sum_ = static_cast<RealType>(sum); | ||
| } else { | ||
| ar &make_nvp("sum", sum_); | ||
| } | ||
| ar &make_nvp("mean", mean_); | ||
| ar &make_nvp("sum_of_deltas_squared", sum_of_deltas_squared_); | ||
| } | ||
|
|
||
| RealType sum_ = 0, mean_ = 0, sum_of_deltas_squared_ = 0; | ||
| }; | ||
|
|
||
| } // namespace python | ||
| } // namespace histogram | ||
| } // namespace boost | ||
|
|
||
| #ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED | ||
|
|
||
| namespace boost { | ||
| namespace serialization { | ||
|
|
||
| template <class T> | ||
| struct version; | ||
|
|
||
| // version 1 for boost::histogram::accumulators::mean<RealType> | ||
| template <class RealType> | ||
| struct version<histogram::python::mean<RealType>> : std::integral_constant<int, 1> {}; | ||
henryiii marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| } // namespace serialization | ||
| } // namespace boost | ||
|
|
||
| namespace std { | ||
| template <class T, class U> | ||
| /// Specialization for boost::histogram::accumulators::mean. | ||
| struct common_type<boost::histogram::accumulators::mean<T>, | ||
henryiii marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| boost::histogram::accumulators::mean<U>> { | ||
| using type = boost::histogram::accumulators::mean<common_type_t<T, U>>; | ||
| }; | ||
| } // namespace std | ||
|
|
||
| #endif | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.