new feature, filling with weights

This commit is contained in:
Hans Dembinski 2016-04-09 16:31:16 -04:00
parent 14c7a282dc
commit 103fa6cf0a
14 changed files with 645 additions and 355 deletions

View File

@ -9,28 +9,30 @@ find_package(Boost 1.55 REQUIRED
COMPONENTS python iostreams serialization unit_test_framework) COMPONENTS python iostreams serialization unit_test_framework)
find_package(PythonLibs) find_package(PythonLibs)
find_package(Numpy) # optional find_package(Numpy) # optional
find_package(ROOT) # only used in one of the tests
include_directories(include ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}) include_directories(include ${Boost_INCLUDE_DIRS})
add_definitions(-DBOOST_TEST_DYN_LINK) # for unit_test_framework add_definitions(-DBOOST_TEST_DYN_LINK) # for unit_test_framework
set(LIBRARIES stdc++ ${Boost_LIBRARIES}) set(LIBRARIES stdc++ ${Boost_LIBRARIES})
if(Boost_PYTHON_FOUND) if(Boost_PYTHON_FOUND AND PYTHONLIBS_FOUND)
set(USE_PYTHON True)
include_directories(${PYTHON_INCLUDE_DIRS})
LIST(APPEND LIBRARIES ${PYTHON_LIBRARIES}) LIST(APPEND LIBRARIES ${PYTHON_LIBRARIES})
add_definitions(-DUSE_PYTHON)
if(NUMPY_FOUND)
include_directories(${NUMPY_INCLUDE_DIR})
add_definitions(-DUSE_NUMPY)
endif()
endif() endif()
if(NUMPY_FOUND) # core library
include_directories(${NUMPY_INCLUDE_DIR})
add_definitions(-DUSE_NUMPY)
endif()
add_library(histogram SHARED add_library(histogram SHARED
src/axis.cpp src/axis.cpp
src/histogram_base.cpp src/histogram_base.cpp
src/nhistogram.cpp src/histogram.cpp
src/nstore.cpp src/nstore.cpp
src/zero_suppression.cpp src/zero_suppression.cpp
# src/whistogram.cpp
) )
target_link_libraries(histogram ${LIBRARIES}) target_link_libraries(histogram ${LIBRARIES})
@ -41,21 +43,24 @@ else()
target_compile_options(histogram PUBLIC "-O3 -fomit-frame-pointer -mtune=generic") target_compile_options(histogram PUBLIC "-O3 -fomit-frame-pointer -mtune=generic")
endif() endif()
if(Boost_PYTHON_FOUND) # python bindings
if(USE_PYTHON)
add_library(pyhistogram MODULE add_library(pyhistogram MODULE
src/python/module.cpp src/python/module.cpp
src/python/histogram_base.cpp src/python/histogram_base.cpp
src/python/nhistogram.cpp src/python/histogram.cpp
) )
target_link_libraries(pyhistogram histogram ${LIBRARIES}) target_link_libraries(pyhistogram histogram ${LIBRARIES})
set_target_properties(pyhistogram PROPERTIES OUTPUT_NAME "histogram" PREFIX "" SUFFIX ".so") set_target_properties(pyhistogram PROPERTIES OUTPUT_NAME "histogram" PREFIX "" SUFFIX ".so")
endif() endif()
# examples
add_executable(sizeof add_executable(sizeof
examples/sizeof.cpp examples/sizeof.cpp
) )
target_link_libraries(sizeof ${LIBRARIES}) target_link_libraries(sizeof ${LIBRARIES})
find_package(ROOT) # only used in speed comparison
if(ROOT_FOUND) if(ROOT_FOUND)
add_executable(nhistogram_speed add_executable(nhistogram_speed
examples/speed_vs_root.cpp) examples/speed_vs_root.cpp)

View File

@ -1,4 +1,4 @@
#include <boost/histogram/nhistogram.hpp> #include <boost/histogram/histogram.hpp>
#include <boost/histogram/axis.hpp> #include <boost/histogram/axis.hpp>
#include <boost/random.hpp> #include <boost/random.hpp>
#include <boost/array.hpp> #include <boost/array.hpp>
@ -51,7 +51,7 @@ void compare_1d(unsigned n)
t = clock() - t; t = clock() - t;
best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC); best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC);
nhistogram h(regular_axis(100, 0, 1)); histogram h(regular_axis(100, 0, 1));
t = clock(); t = clock();
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i)
h.fill(r[i]); h.fill(r[i]);
@ -80,7 +80,7 @@ void compare_3d(unsigned n)
t = clock() - t; t = clock() - t;
best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC); best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC);
nhistogram h(regular_axis(100, 0, 1), histogram h(regular_axis(100, 0, 1),
regular_axis(100, 0, 1), regular_axis(100, 0, 1),
regular_axis(100, 0, 1)); regular_axis(100, 0, 1));
t = clock(); t = clock();
@ -118,7 +118,7 @@ void compare_6d(unsigned n)
t = clock() - t; t = clock() - t;
best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC); best_root = std::min(best_root, double(t) / CLOCKS_PER_SEC);
nhistogram h(regular_axis(10, 0, 1), histogram h(regular_axis(10, 0, 1),
regular_axis(10, 0, 1), regular_axis(10, 0, 1),
regular_axis(10, 0, 1), regular_axis(10, 0, 1),
regular_axis(10, 0, 1), regular_axis(10, 0, 1),

View File

@ -1,10 +1,12 @@
#ifndef _BOOST_HISTOGRAM_NSTORE_HPP_ #ifndef _BOOST_HISTOGRAM_DETAIL_NSTORE_HPP_
#define _BOOST_HISTOGRAM_NSTORE_HPP_ #define _BOOST_HISTOGRAM_DETAIL_NSTORE_HPP_
#include <boost/histogram/detail/wtype.hpp>
#include <boost/histogram/detail/zero_suppression.hpp>
#include <boost/serialization/access.hpp> #include <boost/serialization/access.hpp>
#include <boost/serialization/array.hpp> #include <boost/serialization/array.hpp>
#include <boost/histogram/detail/zero_suppression.hpp>
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include <boost/assert.hpp>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <limits> #include <limits>
@ -20,7 +22,6 @@ class nstore {
public: public:
typedef uintptr_t size_type; typedef uintptr_t size_type;
public:
nstore(); nstore();
nstore(const nstore&); nstore(const nstore&);
nstore(size_type, unsigned d = sizeof(uint8_t)); nstore(size_type, unsigned d = sizeof(uint8_t));
@ -30,11 +31,12 @@ public:
nstore& operator+=(const nstore&); nstore& operator+=(const nstore&);
bool operator==(const nstore&) const; bool operator==(const nstore&) const;
uint64_t read(size_type) const;
void write(size_type, uint64_t);
inline void increase(size_type i) { inline void increase(size_type i) {
switch (depth_) { switch (depth_) {
case sizeof(wtype): {
wtype& b = ((wtype*)buffer_)[i];
b += 1.0;
}
#define BOOST_HISTOGRAM_NSTORE_INC(T) \ #define BOOST_HISTOGRAM_NSTORE_INC(T) \
case sizeof(T): { \ case sizeof(T): { \
T& b = ((T*)buffer_)[i]; \ T& b = ((T*)buffer_)[i]; \
@ -51,6 +53,14 @@ public:
} }
} }
inline void increase(size_type i, double w) {
assert(depth_ == sizeof(wtype));
((wtype*)buffer_)[i] += w;
}
double value(size_type) const;
double variance(size_type) const;
const void* buffer() const { return buffer_; } const void* buffer() const { return buffer_; }
unsigned depth() const { return depth_; } unsigned depth() const { return depth_; }
@ -62,8 +72,24 @@ private:
void create(); void create();
void destroy(); void destroy();
void grow(); void grow();
void wconvert();
uint64_t max_count() const; uint64_t max_count() const
{
switch (depth_) {
#define BOOST_HISTOGRAM_NSTORE_CASE(T) \
case sizeof(T): return std::numeric_limits<T>::max()
BOOST_HISTOGRAM_NSTORE_CASE(uint8_t);
BOOST_HISTOGRAM_NSTORE_CASE(uint16_t);
BOOST_HISTOGRAM_NSTORE_CASE(uint32_t);
BOOST_HISTOGRAM_NSTORE_CASE(uint64_t);
#undef BOOST_HISTOGRAM_NSTORE_CASE
default: assert(!"invalid depth");
}
return 0;
}
uint64_t ivalue(size_type) const;
friend class serialization::access; friend class serialization::access;
template <class Archive> template <class Archive>
@ -81,26 +107,50 @@ private:
throw std::bad_alloc(); throw std::bad_alloc();
if (Archive::is_saving::value) { if (Archive::is_saving::value) {
std::vector<char> buf; switch (depth_) {
if (zero_suppression_encode(buf, size_ * depth_, #define BOOST_HISTOGRAM_NSTORE_SAVE(T) \
(char*)buffer_, size_ * depth_)) { case sizeof(T): { \
bool is_zero_suppressed = true; std::vector<T> buf; \
ar & is_zero_suppressed; if (zero_suppression_encode<T>(buf, (T*)buffer_, size_)) { \
ar & buf; bool is_zero_suppressed = true; \
} else { ar & is_zero_suppressed; \
bool is_zero_suppressed = false; ar & buf; \
ar & is_zero_suppressed; } else { \
ar & serialization::make_array((char*)buffer_, size_ * depth_); bool is_zero_suppressed = false; \
ar & is_zero_suppressed; \
ar & serialization::make_array((T*)buffer_, size_); \
} \
} break
BOOST_HISTOGRAM_NSTORE_SAVE(uint8_t);
BOOST_HISTOGRAM_NSTORE_SAVE(uint16_t);
BOOST_HISTOGRAM_NSTORE_SAVE(uint32_t);
BOOST_HISTOGRAM_NSTORE_SAVE(uint64_t);
BOOST_HISTOGRAM_NSTORE_SAVE(wtype);
#undef BOOST_HISTOGRAM_NSTORE_SAVE
default: assert(!"invalid depth");
} }
} else { }
if (Archive::is_loading::value) {
bool is_zero_suppressed = false; bool is_zero_suppressed = false;
ar & is_zero_suppressed; ar & is_zero_suppressed;
if (is_zero_suppressed) { switch (depth_) {
std::vector<char> buf; #define BOOST_HISTOGRAM_NSTORE_LOAD(T) \
ar & buf; case sizeof(T): \
zero_suppression_decode((char*)buffer_, size_ * depth_, buf); if (is_zero_suppressed) { \
} else { std::vector<T> buf; \
ar & serialization::make_array((char*)buffer_, size_ * depth_); ar & buf; \
zero_suppression_decode<T>((T*)buffer_, size_, buf); \
} else { \
ar & serialization::make_array((T*)buffer_, size_); \
} break
BOOST_HISTOGRAM_NSTORE_LOAD(uint8_t);
BOOST_HISTOGRAM_NSTORE_LOAD(uint16_t);
BOOST_HISTOGRAM_NSTORE_LOAD(uint32_t);
BOOST_HISTOGRAM_NSTORE_LOAD(uint64_t);
BOOST_HISTOGRAM_NSTORE_LOAD(wtype);
#undef BOOST_HISTOGRAM_NSTORE_LOAD
default: assert(!"invalid depth");
} }
} }
} }

View File

@ -0,0 +1,47 @@
#ifndef _BOOST_HISTOGRAM_DETAIL_WTYPE_HPP_
#define _BOOST_HISTOGRAM_DETAIL_WTYPE_HPP_
#include <boost/cstdint.hpp>
#include <ostream>
namespace boost {
namespace histogram {
namespace detail {
struct wtype {
double w, w2;
wtype() : w(0), w2(0) {}
wtype(const wtype& o) : w(o.w), w2(o.w2) {}
wtype(uint64_t i) : w(i), w2(i) {}
wtype& operator+=(const wtype& o)
{ w += o.w; w2 += o.w2; return *this; }
wtype& operator+=(double v)
{ w += v; w2 += v*v; return *this; }
wtype& operator=(uint64_t i)
{ w = i; w2 = i; return *this; }
bool operator==(uint64_t i) const
{ return w == i; }
bool operator!=(uint64_t i) const
{ return w != i; }
bool operator==(const wtype& o) const
{ return w == o.w && w2 == o.w2; }
bool operator!=(const wtype& o) const
{ return w != o.w || w2 != o.w2; }
template <class Archive>
void serialize(Archive& ar, unsigned version)
{ ar & w; ar & w2; }
};
static
inline
std::ostream& operator<<(std::ostream& os, const wtype& w)
{
os << '(' << w.w << ',' << w.w2 << ')';
return os;
}
}
}
}
#endif

View File

@ -1,20 +1,80 @@
#ifndef _BOOST_HISTOGRAM_DETAIL_ZERO_SUPPRESSION_HPP_ #ifndef _BOOST_HISTOGRAM_DETAIL_ZERO_SUPPRESSION_HPP_
#define _BOOST_HISTOGRAM_DETAIL_ZERO_SUPPRESSION_HPP_ #define _BOOST_HISTOGRAM_DETAIL_ZERO_SUPPRESSION_HPP_
#include <cstddef> #include <boost/cstdint.hpp>
#include <boost/histogram/detail/wtype.hpp>
#include <limits>
#include <vector> #include <vector>
namespace boost { namespace boost {
namespace histogram { namespace histogram {
namespace detail { namespace detail {
template <typename T>
bool bool
zero_suppression_encode(std::vector<char>& output, std::size_t output_max, zero_suppression_encode(std::vector<T>& output, const T* input,
const char* input, std::size_t input_len); uintptr_t size)
{
#define BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL { \
if ((size - output.size()) < 2) \
return false; \
output.push_back(0); \
output.push_back(nzero); \
nzero = 0; \
}
const T* input_end = input + size;
T nzero = 0;
for (; input != input_end; ++input) {
if (*input != 0) {
if (nzero)
BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL
if (output.size() == size)
return false;
output.push_back(*input);
}
else {
++nzero;
if (nzero == 0) // overflowed to zero
BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL
}
}
if (nzero)
BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL
return true;
}
template <typename T>
void void
zero_suppression_decode(char* output, std::size_t output_len, zero_suppression_decode(T* output, uintptr_t size,
const std::vector<char>& input); const std::vector<T>& input)
{
const T* inp = &input[0];
const T* output_end = output + size;
while (output != output_end) {
*output = *inp;
if (*inp == 0) {
const uintptr_t nzero = *(++inp);
for (T j = 1; j != nzero; ++j) {
*(++output) = 0;
if (output == output_end)
return;
}
}
++inp;
++output;
}
}
template <>
void
zero_suppression_decode(wtype* output, uintptr_t size,
const std::vector<wtype>& input);
template <>
bool
zero_suppression_encode(std::vector<wtype>& output, const wtype* input,
uintptr_t size);
} }
} }

View File

@ -1,5 +1,5 @@
#ifndef _BOOST_HISTOGRAM_NHISTOGRAM_HPP_ #ifndef _BOOST_HISTOGRAM_HISTOGRAM_HPP_
#define _BOOST_HISTOGRAM_NHISTOGRAM_HPP_ #define _BOOST_HISTOGRAM_HISTOGRAM_HPP_
#include <boost/histogram/axis.hpp> #include <boost/histogram/axis.hpp>
#include <boost/histogram/histogram_base.hpp> #include <boost/histogram/histogram_base.hpp>
@ -9,28 +9,27 @@
#include <boost/serialization/base_object.hpp> #include <boost/serialization/base_object.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/python/dict.hpp>
namespace boost { namespace boost {
namespace histogram { namespace histogram {
class nhistogram : public histogram_base { class histogram : public histogram_base {
public: public:
nhistogram() {} histogram() {}
nhistogram(const nhistogram& o) : histogram(const histogram& o) :
histogram_base(o), histogram_base(o),
data_(o.data_) data_(o.data_)
{} {}
explicit explicit
nhistogram(const axes_type& axes) : histogram(const axes_type& axes) :
histogram_base(axes), histogram_base(axes),
data_(field_count()) data_(field_count())
{} {}
#define BOOST_NHISTOGRAM_CTOR(z, n, unused) \ #define BOOST_NHISTOGRAM_CTOR(z, n, unused) \
nhistogram( BOOST_PP_ENUM_PARAMS_Z(z, n, const axis_type& a) ) : \ histogram( BOOST_PP_ENUM_PARAMS_Z(z, n, const axis_type& a) ) : \
histogram_base( BOOST_PP_ENUM_PARAMS_Z(z, n, a) ), \ histogram_base( BOOST_PP_ENUM_PARAMS_Z(z, n, a) ), \
data_(field_count()) \ data_(field_count()) \
{} {}
@ -73,12 +72,43 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_CTOR, ni
// generates fill functions taking 1 to AXIS_LIMT arguments // generates fill functions taking 1 to AXIS_LIMT arguments
BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_FILL, nil) BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_FILL, nil)
template <typename Container>
inline
void wfill(const Container& v, double w)
{
BOOST_ASSERT(v.size() == dim());
const size_type k = pos(v);
if (k != uintmax_t(-1))
data_.increase(k, w);
}
// C-style call
inline
void wfill(unsigned n, const double* v, double w)
{
BOOST_ASSERT(n == dim());
const size_type k = pos(v);
if (k != uintmax_t(-1))
data_.increase(k, w);
}
#define BOOST_NHISTOGRAM_WFILL(z, n, unused) \
inline \
void wfill( BOOST_PP_ENUM_PARAMS_Z(z, n, double x), double w ) \
{ \
const double buffer[n] = { BOOST_PP_ENUM_PARAMS(n, x) }; \
wfill(n, buffer, w); /* size is checked here */ \
}
// generates wfill functions taking 1 to AXIS_LIMT arguments
BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_WFILL, nil)
template <typename Container> template <typename Container>
double value(const Container& idx) double value(const Container& idx)
const const
{ {
BOOST_ASSERT(idx.size() == dim()); BOOST_ASSERT(idx.size() == dim());
return data_.read(linearize(idx)); return data_.value(linearize(idx));
} }
// C-style call // C-style call
@ -86,7 +116,7 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_FILL, ni
const const
{ {
BOOST_ASSERT(n == dim()); BOOST_ASSERT(n == dim());
return data_.read(linearize(idx)); return data_.value(linearize(idx));
} }
#define BOOST_NHISTOGRAM_VALUE(z, n, unused) \ #define BOOST_NHISTOGRAM_VALUE(z, n, unused) \
@ -100,11 +130,38 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_FILL, ni
// generates value functions taking 1 to AXIS_LIMT arguments // generates value functions taking 1 to AXIS_LIMT arguments
BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_VALUE, nil) BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_VALUE, nil)
bool operator==(const nhistogram& o) const template <typename Container>
double variance(const Container& idx)
const
{
BOOST_ASSERT(idx.size() == dim());
return data_.variance(linearize(idx));
}
// C-style call
double variance(unsigned n, const int* idx)
const
{
BOOST_ASSERT(n == dim());
return data_.variance(linearize(idx));
}
#define BOOST_NHISTOGRAM_VARIANCE(z, n, unused) \
double variance( BOOST_PP_ENUM_PARAMS_Z(z, n, int i) ) \
const \
{ \
const int idx[n] = { BOOST_PP_ENUM_PARAMS_Z(z, n, i) }; \
return variance(n, idx); /* size is checked here */ \
}
// generates variance functions taking 1 to AXIS_LIMT arguments
BOOST_PP_REPEAT_FROM_TO(1, BOOST_HISTOGRAM_AXIS_LIMIT, BOOST_NHISTOGRAM_VARIANCE, nil)
bool operator==(const histogram& o) const
{ return histogram_base::operator==(o) && { return histogram_base::operator==(o) &&
data_ == o.data_; } data_ == o.data_; }
nhistogram& operator+=(const nhistogram& o) histogram& operator+=(const histogram& o)
{ data_ += o.data_; return *this; } { data_ += o.data_; return *this; }
private: private:
@ -118,11 +175,11 @@ private:
ar & data_; ar & data_;
} }
friend python::dict nhistogram_array_interface(nhistogram&); friend class buffer_access;
}; };
nhistogram operator+(const nhistogram& a, const nhistogram& b) { histogram operator+(const histogram& a, const histogram& b) {
nhistogram result(a); histogram result(a);
return result += b; return result += b;
} }

View File

@ -1,110 +0,0 @@
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <boost/serialization/array.hpp>
class wstore {
public:
typedef boost::uintmax_t size_type;
struct wcount { double w_, w2_; };
private:
size_type size_;
double* buffer_;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive & ar, unsigned version) {
using boost::serialization::make_array;
size_type s = size_;
ar & make_nvp("size", size_);
if (s != size_) {
destroy();
create();
}
ar & make_nvp("data", \
make_array(buffer_, size_ * 2));
}
void
create() {
buffer_ = (double*)std::calloc(size_, sizeof(wcount));
}
void
destroy() {
free(buffer_);
buffer_ = 0;
}
public:
wstore()
: size_(0), buffer_(0)
{}
wstore(size_type n)
: size_(n)
{
create();
}
wstore(const wstore& other)
: size_(other.size_)
{
create();
*this = other;
}
~wstore() { destroy(); }
wstore&
operator=(const wstore& other)
{
if (size_ != other.size_) {
destroy();
size_ = other.size_;
create();
}
std::memcpy(buffer_, other.buffer_, size_ * sizeof(wcount));
return *this;
}
inline
wcount&
operator[](size_type i)
{
return *((wcount*)buffer_ + i);
}
inline
const wcount&
operator[](size_type i) const
{
return *((wcount*)buffer_ + i);
}
wstore&
operator+=(const wstore& other) {
if (size_ != other.size_)
throw std::logic_error("sizes do not match");
for (size_type i = 0; i < (size_ * 2); ++i)
buffer_[i] += other.buffer_[i];
return *this;
}
bool
operator==(const wstore& other) const {
if (size_ != other.size_)
return false;
for (size_type i = 0; i < (size_ * 2); ++i)
if (buffer_[i] != other.buffer_[i])
return false;
return true;
}
inline size_type size() const { return size_; }
inline const double* buffer() const { return buffer_; }
};

View File

@ -1,16 +1,16 @@
#include <boost/histogram/nhistogram.hpp> #include <boost/histogram/histogram.hpp>
#include <ostream> #include <ostream>
namespace boost { namespace boost {
namespace histogram { namespace histogram {
double double
nhistogram::sum() histogram::sum()
const const
{ {
double result = 0.0; double result = 0.0;
for (size_type i = 0, n = field_count(); i < n; ++i) for (size_type i = 0, n = field_count(); i < n; ++i)
result += data_.read(i); result += data_.value(i);
return result; return result;
} }

View File

@ -50,8 +50,42 @@ nstore::operator+=(const nstore& o)
{ {
if (size_ != o.size_) if (size_ != o.size_)
throw std::logic_error("sizes do not match"); throw std::logic_error("sizes do not match");
for (size_type i = 0; i < size_; ++i)
write(i, read(i) + o.read(i)); if (depth_ != o.depth_) {
if (o.depth_ == sizeof(wtype))
wconvert();
else
while (depth_ < o.depth_)
grow();
}
if (depth_ == sizeof(wtype)) {
for (size_type i = 0; i < size_; ++i)
((wtype*)buffer_)[i] += ((wtype*)o.buffer_)[i];
}
else {
size_type i = 0;
while (i < size_) {
const uint64_t oi = o.ivalue(i);
switch (depth_) {
#define BOOST_HISTOGRAM_NSTORE_ADD(T) \
case sizeof(T): { \
T& b = ((T*)buffer_)[i]; \
if ((std::numeric_limits<T>::max() - b) >= oi) { \
b += oi; \
++i; \
break; \
} else grow(); /* add fall through */ \
}
BOOST_HISTOGRAM_NSTORE_ADD(uint8_t);
BOOST_HISTOGRAM_NSTORE_ADD(uint16_t);
BOOST_HISTOGRAM_NSTORE_ADD(uint32_t);
BOOST_HISTOGRAM_NSTORE_ADD(uint64_t);
#undef BOOST_HISTOGRAM_NSTORE_ADD
default: assert(!"invalid depth");
}
}
}
return *this; return *this;
} }
@ -64,42 +98,31 @@ nstore::operator==(const nstore& o)
return std::memcmp(buffer_, o.buffer_, size_ * depth_) == 0; return std::memcmp(buffer_, o.buffer_, size_ * depth_) == 0;
} }
uint64_t double
nstore::read(size_type i) nstore::value(size_type i)
const
{
if (depth_ == sizeof(wtype))
return ((wtype*)buffer_)[i].w;
return ivalue(i);
}
double
nstore::variance(size_type i)
const const
{ {
switch (depth_) { switch (depth_) {
#define BOOST_HISTOGRAM_NSTORE_READ(T) \ case sizeof(wtype): return ((wtype*)buffer_)[i].w2;
#define BOOST_HISTOGRAM_NSTORE_VARIANCE(T) \
case sizeof(T): return ((T*)buffer_)[i] case sizeof(T): return ((T*)buffer_)[i]
BOOST_HISTOGRAM_NSTORE_READ(uint8_t); BOOST_HISTOGRAM_NSTORE_VARIANCE(uint8_t);
BOOST_HISTOGRAM_NSTORE_READ(uint16_t); BOOST_HISTOGRAM_NSTORE_VARIANCE(uint16_t);
BOOST_HISTOGRAM_NSTORE_READ(uint32_t); BOOST_HISTOGRAM_NSTORE_VARIANCE(uint32_t);
BOOST_HISTOGRAM_NSTORE_READ(uint64_t); BOOST_HISTOGRAM_NSTORE_VARIANCE(uint64_t);
#undef BOOST_HISTOGRAM_NSTORE_READ #undef BOOST_HISTOGRAM_NSTORE_VARIANCE
default: assert(!"invalid depth");
}
return 0;
}
void
nstore::write(size_type i, uint64_t v)
{
const uint64_t vmax = max_count();
while (vmax < v) grow();
switch (depth_) {
#define BOOST_HISTOGRAM_NSTORE_WRITE(T) \
case sizeof(T): { \
((T*)buffer_)[i] = v; \
break; \
}
BOOST_HISTOGRAM_NSTORE_WRITE(uint8_t);
BOOST_HISTOGRAM_NSTORE_WRITE(uint16_t);
BOOST_HISTOGRAM_NSTORE_WRITE(uint32_t);
BOOST_HISTOGRAM_NSTORE_WRITE(uint64_t);
#undef BOOST_HISTOGRAM_NSTORE_WRITE
default: assert(!"invalid depth"); default: assert(!"invalid depth");
} }
return 0.0;
} }
void void
@ -118,17 +141,17 @@ nstore::destroy()
void void
nstore::grow() nstore::grow()
{ {
if (depth_ == sizeof(uint64_t)) assert(depth_ > 0);
throw std::overflow_error("depth > 64 bit is not supported"); assert(depth_ < sizeof(uint64_t));
if (depth_ == 0 || buffer_ == 0) assert(buffer_ != 0);
throw std::logic_error("cannot call grow on null buffer");
buffer_ = std::realloc(buffer_, size_ * 2 * depth_); buffer_ = std::realloc(buffer_, size_ * 2 * depth_);
if (!buffer_) throw std::bad_alloc(); if (!buffer_) throw std::bad_alloc();
size_type i = size_;
switch (depth_) { switch (depth_) {
#define BOOST_HISTOGRAM_NSTORE_GROW(T0, T1) \ #define BOOST_HISTOGRAM_NSTORE_GROW(T0, T1) \
case sizeof(T0): \ case sizeof(T0): \
for (size_type i = size_ - 1; i != size_type(-1); --i) \ while (i--) \
((T1*)buffer_)[i] = ((T0*)buffer_)[i]; \ ((T1*)buffer_)[i] = ((T0*)buffer_)[i]; \
break break
BOOST_HISTOGRAM_NSTORE_GROW(uint8_t, uint16_t); BOOST_HISTOGRAM_NSTORE_GROW(uint8_t, uint16_t);
BOOST_HISTOGRAM_NSTORE_GROW(uint16_t, uint32_t); BOOST_HISTOGRAM_NSTORE_GROW(uint16_t, uint32_t);
@ -138,17 +161,41 @@ nstore::grow()
depth_ *= 2; depth_ *= 2;
} }
void
nstore::wconvert()
{
assert(depth_ < sizeof(wtype));
buffer_ = std::realloc(buffer_, size_ * sizeof(wtype));
if (!buffer_) throw std::bad_alloc();
size_type i = size_;
switch (depth_) {
#define BOOST_HISTOGRAM_NSTORE_CONVERT(T) \
case sizeof(T): \
while (i--) \
((wtype*)buffer_)[i] = ((T*)buffer_)[i]; \
break
BOOST_HISTOGRAM_NSTORE_CONVERT(uint8_t);
BOOST_HISTOGRAM_NSTORE_CONVERT(uint16_t);
BOOST_HISTOGRAM_NSTORE_CONVERT(uint32_t);
BOOST_HISTOGRAM_NSTORE_CONVERT(uint64_t);
#undef BOOST_HISTOGRAM_NSTORE_CONVERT
default: break; // no nuthin'
}
depth_ = sizeof(wtype);
}
uint64_t uint64_t
nstore::max_count() nstore::ivalue(size_type i)
const const
{ {
switch (depth_) { switch (depth_) {
#define BOOST_HISTOGRAM_NSTORE_CASE(T) \ #define BOOST_HISTOGRAM_NSTORE_IVALUE(T) \
case sizeof(T): return std::numeric_limits<T>::max() case sizeof(T): return ((T*)buffer_)[i]
BOOST_HISTOGRAM_NSTORE_CASE(uint8_t); BOOST_HISTOGRAM_NSTORE_IVALUE(uint8_t);
BOOST_HISTOGRAM_NSTORE_CASE(uint16_t); BOOST_HISTOGRAM_NSTORE_IVALUE(uint16_t);
BOOST_HISTOGRAM_NSTORE_CASE(uint32_t); BOOST_HISTOGRAM_NSTORE_IVALUE(uint32_t);
BOOST_HISTOGRAM_NSTORE_CASE(uint64_t); BOOST_HISTOGRAM_NSTORE_IVALUE(uint64_t);
#undef BOOST_HISTOGRAM_NSTORE_IVALUE
default: assert(!"invalid depth"); default: assert(!"invalid depth");
} }
return 0; return 0;

View File

@ -1,10 +1,10 @@
#include "serialization_suite.hpp"
#include <boost/histogram/axis.hpp> #include <boost/histogram/axis.hpp>
#include <boost/histogram/nhistogram.hpp> #include <boost/histogram/histogram.hpp>
#include <boost/python.hpp> #include <boost/python.hpp>
#include <boost/python/raw_function.hpp> #include <boost/python/raw_function.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include "serialization_suite.hpp"
#ifdef USE_NUMPY #ifdef USE_NUMPY
# define NO_IMPORT_ARRAY # define NO_IMPORT_ARRAY
# define PY_ARRAY_UNIQUE_SYMBOL boost_histogram_ARRAY_API # define PY_ARRAY_UNIQUE_SYMBOL boost_histogram_ARRAY_API
@ -16,7 +16,7 @@ namespace boost {
namespace histogram { namespace histogram {
python::object python::object
nhistogram_init(python::tuple args, python::dict kwargs) { histogram_init(python::tuple args, python::dict kwargs) {
using namespace python; using namespace python;
using python::tuple; using python::tuple;
@ -48,24 +48,12 @@ nhistogram_init(python::tuple args, python::dict kwargs) {
return pyinit(axes); return pyinit(axes);
} }
python::dict
nhistogram_array_interface(nhistogram& self) {
python::list shape;
for (unsigned i = 0; i < self.dim(); ++i)
shape.append(self.shape(i));
python::dict d;
d["shape"] = python::tuple(shape);
d["typestr"] = python::str("<u") + python::str(self.depth());
d["data"] = python::make_tuple((long long)(self.data_.buffer()), false);
return d;
}
python::object python::object
nhistogram_fill(python::tuple args, python::dict kwargs) { histogram_fill(python::tuple args, python::dict kwargs) {
using namespace python; using namespace python;
const unsigned nargs = len(args); const unsigned nargs = len(args);
nhistogram& self = extract<nhistogram&>(args[0]); histogram& self = extract<histogram&>(args[0]);
#ifdef USE_NUMPY #ifdef USE_NUMPY
if (nargs == 2) { if (nargs == 2) {
@ -128,7 +116,7 @@ nhistogram_fill(python::tuple args, python::dict kwargs) {
} }
uint64_t uint64_t
nhistogram_getitem(const nhistogram& self, python::object oidx) { histogram_getitem(const histogram& self, python::object oidx) {
using namespace python; using namespace python;
if (self.dim() == 1) if (self.dim() == 1)
@ -147,26 +135,42 @@ nhistogram_getitem(const nhistogram& self, python::object oidx) {
return self.value(self.dim(), idx); return self.value(self.dim(), idx);
} }
void register_nhistogram() class buffer_access {
public:
static
python::dict
histogram_array_interface(histogram& self) {
python::list shape;
for (unsigned i = 0; i < self.dim(); ++i)
shape.append(self.shape(i));
python::dict d;
d["shape"] = python::tuple(shape);
d["typestr"] = python::str("<u") + python::str(self.data_.depth());
d["data"] = python::make_tuple((long long)(self.data_.buffer()), false);
return d;
}
};
void register_histogram()
{ {
using namespace python; using namespace python;
class_< class_<
nhistogram, bases<histogram_base>, histogram, bases<histogram_base>,
shared_ptr<nhistogram> shared_ptr<histogram>
>("nhistogram", no_init) >("histogram", no_init)
.def("__init__", raw_function(nhistogram_init)) .def("__init__", raw_function(histogram_init))
// shadowed C++ ctors // shadowed C++ ctors
.def(init<const axes_type&>()) .def(init<const axes_type&>())
.add_property("__array_interface__", nhistogram_array_interface) .add_property("__array_interface__", &buffer_access::histogram_array_interface)
.def("fill", raw_function(nhistogram_fill)) .def("fill", raw_function(histogram_fill))
.add_property("depth", &nhistogram::depth) .add_property("depth", &histogram::depth)
.add_property("sum", &nhistogram::sum) .add_property("sum", &histogram::sum)
.def("__getitem__", nhistogram_getitem) .def("__getitem__", histogram_getitem)
.def(self == self) .def(self == self)
.def(self += self) .def(self += self)
.def(self + self) .def(self + self)
.def_pickle(serialization_suite<nhistogram>()) .def_pickle(serialization_suite<histogram>())
; ;
} }

View File

@ -8,7 +8,7 @@
namespace boost { namespace boost {
namespace histogram { namespace histogram {
void register_histogram_base(); void register_histogram_base();
void register_nhistogram(); void register_histogram();
} }
} }
@ -18,5 +18,5 @@ BOOST_PYTHON_MODULE(histogram)
import_array(); import_array();
#endif #endif
boost::histogram::register_histogram_base(); boost::histogram::register_histogram_base();
boost::histogram::register_nhistogram(); boost::histogram::register_histogram();
} }

View File

@ -4,50 +4,52 @@ namespace boost {
namespace histogram { namespace histogram {
namespace detail { namespace detail {
template <>
bool bool
zero_suppression_encode(std::vector<char>& output, std::size_t output_max, zero_suppression_encode(std::vector<wtype>& output, const wtype* input,
const char* input, std::size_t input_len) uintptr_t size)
{ {
#define FILL_OUTPUT { \ #define BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL { \
if ((output_max - output.size()) < 2) \ if ((size - output.size()) < 2) \
return false; \ return false; \
output.push_back(0); \ output.push_back(0); \
output.push_back(nzero); \ output.push_back(nzero); \
nzero = 0; \ nzero = 0; \
} }
const char* input_end = input + input_len; const wtype* input_end = input + size;
unsigned nzero = 0; uint32_t nzero = 0;
for (; input != input_end; ++input) { for (; input != input_end; ++input) {
if (*input != 0) { if (*input != 0) {
if (nzero) if (nzero)
FILL_OUTPUT BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL
if (output.size() == output_max) if (output.size() == size)
return false; return false;
output.push_back(*input); output.push_back(*input);
} }
else { else {
++nzero; ++nzero;
if (nzero == 256) if (nzero == 0) // overflowed to zero
FILL_OUTPUT BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL
} }
} }
if (nzero) if (nzero)
FILL_OUTPUT BOOST_HISTOGRAM_ZERO_SUPPRESSION_FILL
return true; return true;
} }
template <>
void void
zero_suppression_decode(char* output, std::size_t output_len, zero_suppression_decode(wtype* output, uintptr_t size,
const std::vector<char>& input) const std::vector<wtype>& input)
{ {
const char* inp = &input[0]; const wtype* inp = &input[0];
const char* output_end = output + output_len; const wtype* output_end = output + size;
while (output != output_end) { while (output != output_end) {
*output = *inp; *output = *inp;
if (*inp == 0) { if (*inp == 0) {
const char nzero = *(++inp); const uintptr_t nzero = (++inp)->w;
for (char j = 1; j != nzero; ++j) { for (uintptr_t j = 1; j != nzero; ++j) {
*(++output) = 0; *(++output) = 0;
if (output == output_end) if (output == output_end)
return; return;

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
import unittest import unittest
from math import pi from math import pi
from histogram import nhistogram, regular_axis, polar_axis, \ from histogram import histogram, regular_axis, polar_axis, \
variable_axis, category_axis, integer_axis variable_axis, category_axis, integer_axis
import cPickle import cPickle
import StringIO import StringIO
@ -299,39 +299,39 @@ class test_integer_axis(unittest.TestCase):
self.assertEqual(a.index(3), 4) self.assertEqual(a.index(3), 4)
self.assertEqual(a.index(4), 4) self.assertEqual(a.index(4), 4)
class nhistogram_test(unittest.TestCase): class histogram_test(unittest.TestCase):
def test_init(self): def test_init(self):
nhistogram(integer_axis(-1, 1)) histogram(integer_axis(-1, 1))
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
nhistogram(1) histogram(1)
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
nhistogram("bla") histogram("bla")
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
nhistogram([]) histogram([])
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
nhistogram(regular_axis) histogram(regular_axis)
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
nhistogram(regular_axis()) histogram(regular_axis())
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
nhistogram([integer_axis(-1, 1)]) histogram([integer_axis(-1, 1)])
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
nhistogram(integer_axis(-1, 1), unknown_keyword="nh") histogram(integer_axis(-1, 1), unknown_keyword="nh")
h = nhistogram(integer_axis(-1, 1)) h = histogram(integer_axis(-1, 1))
self.assertEqual(h.dim, 1) self.assertEqual(h.dim, 1)
self.assertEqual(h.axis(0), integer_axis(-1, 1)) self.assertEqual(h.axis(0), integer_axis(-1, 1))
self.assertEqual(h.shape(0), 5) self.assertEqual(h.shape(0), 5)
self.assertEqual(h.depth, 1) self.assertEqual(h.depth, 1)
self.assertEqual(nhistogram(integer_axis(-1, 1, uoflow=False)).shape(0), 3) self.assertEqual(histogram(integer_axis(-1, 1, uoflow=False)).shape(0), 3)
self.assertNotEqual(h, nhistogram(regular_axis(1, -1, 1))) self.assertNotEqual(h, histogram(regular_axis(1, -1, 1)))
self.assertNotEqual(h, nhistogram(integer_axis(-1, 2))) self.assertNotEqual(h, histogram(integer_axis(-1, 2)))
self.assertNotEqual(h, nhistogram(integer_axis(-1, 1, label="ia"))) self.assertNotEqual(h, histogram(integer_axis(-1, 1, label="ia")))
self.assertNotEqual(h, nhistogram(integer_axis(-1, 1, uoflow=True))) self.assertNotEqual(h, histogram(integer_axis(-1, 1, uoflow=True)))
def test_fill_1d(self): def test_fill_1d(self):
h0 = nhistogram(integer_axis(-1, 1, uoflow=False)) h0 = histogram(integer_axis(-1, 1, uoflow=False))
h1 = nhistogram(integer_axis(-1, 1, uoflow=True)) h1 = histogram(integer_axis(-1, 1, uoflow=True))
for h in (h0, h1): for h in (h0, h1):
with self.assertRaises(StandardError): with self.assertRaises(StandardError):
h.fill() h.fill()
@ -363,7 +363,7 @@ class nhistogram_test(unittest.TestCase):
self.assertEqual(h1[3], 1) self.assertEqual(h1[3], 1)
def test_growth(self): def test_growth(self):
h = nhistogram(integer_axis(-1, 1)) h = histogram(integer_axis(-1, 1))
h.fill(-1) h.fill(-1)
h.fill(1) h.fill(1)
h.fill(1) h.fill(1)
@ -382,7 +382,7 @@ class nhistogram_test(unittest.TestCase):
def test_fill_2d(self): def test_fill_2d(self):
for uoflow in (False, True): for uoflow in (False, True):
h = nhistogram(integer_axis(-1, 1, uoflow=uoflow), h = histogram(integer_axis(-1, 1, uoflow=uoflow),
regular_axis(4, -2, 2, uoflow=uoflow)) regular_axis(4, -2, 2, uoflow=uoflow))
h.fill(-1, -2) h.fill(-1, -2)
h.fill(-1, -1) h.fill(-1, -1)
@ -407,7 +407,7 @@ class nhistogram_test(unittest.TestCase):
def test_add_2d(self): def test_add_2d(self):
for uoflow in (False, True): for uoflow in (False, True):
h = nhistogram(integer_axis(-1, 1, uoflow=uoflow), h = histogram(integer_axis(-1, 1, uoflow=uoflow),
regular_axis(4, -2, 2, uoflow=uoflow)) regular_axis(4, -2, 2, uoflow=uoflow))
h.fill(-1, -2) h.fill(-1, -2)
h.fill(-1, -1) h.fill(-1, -1)
@ -432,7 +432,7 @@ class nhistogram_test(unittest.TestCase):
self.assertEqual(h[i, j], 2 * m[i][j]) self.assertEqual(h[i, j], 2 * m[i][j])
def test_pickle(self): def test_pickle(self):
a = nhistogram(category_axis('A', 'B', 'C'), a = histogram(category_axis('A', 'B', 'C'),
integer_axis(0, 3, label='ia'), integer_axis(0, 3, label='ia'),
regular_axis(4, 0.0, 4.0, uoflow=False), regular_axis(4, 0.0, 4.0, uoflow=False),
variable_axis(0.0, 1.0, 2.0)) variable_axis(0.0, 1.0, 2.0))
@ -460,7 +460,7 @@ class nhistogram_test(unittest.TestCase):
@unittest.skipUnless("numpy" in globals(), "requires numpy") @unittest.skipUnless("numpy" in globals(), "requires numpy")
def test_numpy_conversion(self): def test_numpy_conversion(self):
a = nhistogram(integer_axis(0, 2, uoflow=False)) a = histogram(integer_axis(0, 2, uoflow=False))
for i in xrange(100): for i in xrange(100):
a.fill(1) a.fill(1)
b = numpy.array(a) # a copy b = numpy.array(a) # a copy
@ -481,19 +481,19 @@ class nhistogram_test(unittest.TestCase):
@unittest.skipUnless("numpy" in globals(), "requires numpy") @unittest.skipUnless("numpy" in globals(), "requires numpy")
def test_fill_with_numpy_array(self): def test_fill_with_numpy_array(self):
a = nhistogram(integer_axis(0, 2, uoflow=False)) a = histogram(integer_axis(0, 2, uoflow=False))
a.fill(numpy.array([-1, 0, 1, 2, 1, 4])) a.fill(numpy.array([-1, 0, 1, 2, 1, 4]))
self.assertEqual(a[0], 1) self.assertEqual(a[0], 1)
self.assertEqual(a[1], 2) self.assertEqual(a[1], 2)
self.assertEqual(a[2], 1) self.assertEqual(a[2], 1)
a = nhistogram(integer_axis(0, 1, uoflow=False), a = histogram(integer_axis(0, 1, uoflow=False),
regular_axis(2, 0, 2, uoflow=False)) regular_axis(2, 0, 2, uoflow=False))
a.fill(numpy.array([[-1., -1.], [0., 1.], [1., 0.1]])) a.fill(numpy.array([[-1., -1.], [0., 1.], [1., 0.1]]))
self.assertEqual(a[0, 0], 0) self.assertEqual(a[0, 0], 0)
self.assertEqual(a[0, 1], 1) self.assertEqual(a[0, 1], 1)
self.assertEqual(a[1, 0], 1) self.assertEqual(a[1, 0], 1)
self.assertEqual(a[1, 1], 0) self.assertEqual(a[1, 1], 0)
a = nhistogram(integer_axis(0, 2, uoflow=False)) a = histogram(integer_axis(0, 2, uoflow=False))
a.fill([0, 0, 1, 2]) a.fill([0, 0, 1, 2])
a.fill((1, 0, 2, 2)) a.fill((1, 0, 2, 2))
self.assertEqual(a[0], 3) self.assertEqual(a[0], 3)

View File

@ -5,150 +5,278 @@
#include <boost/assign/std/vector.hpp> #include <boost/assign/std/vector.hpp>
#include <iostream> #include <iostream>
using namespace boost::assign; using namespace boost::assign;
using boost::histogram::detail::zero_suppression_encode; using namespace boost::histogram::detail;
using boost::histogram::detail::zero_suppression_decode;
namespace tt = boost::test_tools; namespace tt = boost::test_tools;
template <typename T>
void void
print(const std::vector<char>& v) { print(const std::vector<T>& v) {
std::cerr << "["; std::cerr << "[";
for (unsigned i = 0; i < v.size(); ++i) { for (unsigned i = 0; i < v.size(); ++i) {
std::cerr << unsigned(v[i]) << (i < v.size() - 1 ? ", " : "]"); std::cerr << v[i] << (i < v.size() - 1 ? ", " : "]");
} }
std::cerr << "\n"; std::cerr << "\n";
} }
#define EQUAL_VECTORS(a, b) \ #define EQUAL_VECTORS(a, b) BOOST_CHECK_EQUAL_COLLECTIONS(a.begin(), a.end(), b.begin(), b.end())
BOOST_CHECK_EQUAL_COLLECTIONS(a.begin(), a.end(), b.begin(), b.end())
BOOST_AUTO_TEST_CASE( codec_no_zero ) BOOST_AUTO_TEST_CASE( codec_no_zero )
{ {
std::vector<char> a, b, c(3, 0); std::vector<unsigned> a, b, c(3, 0);
a += 1, 1, 1; a += 1, 1, 1;
BOOST_CHECK(zero_suppression_encode(b, 3, &a[0], a.size())); BOOST_CHECK(zero_suppression_encode<unsigned>(b, &a[0], a.size()));
EQUAL_VECTORS(a, b); EQUAL_VECTORS(a, b);
zero_suppression_decode(&c[0], c.size(), b); zero_suppression_decode<unsigned>(&c[0], c.size(), b);
EQUAL_VECTORS(a, c); EQUAL_VECTORS(a, c);
} }
BOOST_AUTO_TEST_CASE( codec_fail )
{
std::vector<char> a, b;
a += 1, 1, 1;
BOOST_CHECK(zero_suppression_encode(b, 2, &a[0], a.size()) == false);
}
BOOST_AUTO_TEST_CASE( codec_empty ) BOOST_AUTO_TEST_CASE( codec_empty )
{ {
std::vector<char> a, b, c; std::vector<unsigned> a, b, c;
BOOST_CHECK(zero_suppression_encode(b, 3, &a[0], a.size())); BOOST_CHECK(zero_suppression_encode<unsigned>(b, &a[0], a.size()));
EQUAL_VECTORS(a, b); EQUAL_VECTORS(a, b);
zero_suppression_decode(&c[0], c.size(), b); zero_suppression_decode<unsigned>(&c[0], c.size(), b);
EQUAL_VECTORS(a, c); EQUAL_VECTORS(a, c);
} }
BOOST_AUTO_TEST_CASE( codec_zero_0 ) BOOST_AUTO_TEST_CASE( codec_zero_0a )
{ {
std::vector<char> a, b, c, d(2, 0); std::vector<uint8_t> a, b;
a += 0, 1; a += 0;
c += 0, 1, 1; BOOST_CHECK(zero_suppression_encode<uint8_t>(b, &a[0], a.size()) == false);
BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); }
BOOST_AUTO_TEST_CASE( codec_zero_1a )
{
std::vector<uint8_t> a, b, c, d(3, 0);
a += 1, 0, 0;
c += 1, 0, 2;
BOOST_CHECK(zero_suppression_encode<uint8_t>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c); EQUAL_VECTORS(b, c);
zero_suppression_decode(&d[0], d.size(), b); zero_suppression_decode<uint8_t>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d); EQUAL_VECTORS(a, d);
} }
BOOST_AUTO_TEST_CASE( codec_zero_1 ) BOOST_AUTO_TEST_CASE( codec_zero_2a )
{ {
std::vector<char> a, b, c, d(3, 0); std::vector<uint8_t> a, b, c, d(3, 0);
a += 0, 0, 1; a += 0, 0, 1;
c += 0, 2, 1; c += 0, 2, 1;
BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); BOOST_CHECK(zero_suppression_encode<uint8_t>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c); EQUAL_VECTORS(b, c);
zero_suppression_decode(&d[0], d.size(), b); zero_suppression_decode<uint8_t>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d); EQUAL_VECTORS(a, d);
} }
BOOST_AUTO_TEST_CASE( codec_zero_2 ) BOOST_AUTO_TEST_CASE( codec_zero_3a )
{ {
std::vector<char> a, b, c, d(2, 0); std::vector<uint8_t> a, b, c, d(2, 0);
a += 0, 0; a += 0, 0;
c += 0, 2; c += 0, 2;
BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); BOOST_CHECK(zero_suppression_encode<uint8_t>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c); EQUAL_VECTORS(b, c);
zero_suppression_decode(&d[0], d.size(), b); zero_suppression_decode<uint8_t>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d); EQUAL_VECTORS(a, d);
} }
BOOST_AUTO_TEST_CASE( codec_zero_3 ) BOOST_AUTO_TEST_CASE( codec_zero_0b )
{ {
std::vector<char> a, b, c, d(1, 0); std::vector<unsigned> a, b;
a += 0; a += 0;
c += 0, 1; BOOST_CHECK(zero_suppression_encode<unsigned>(b, &a[0], a.size()) == false);
BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); }
BOOST_AUTO_TEST_CASE( codec_zero_1b )
{
std::vector<unsigned> a, b, c, d(3, 0);
a += 1, 0, 0;
c += 1, 0, 2;
BOOST_CHECK(zero_suppression_encode<unsigned>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c); EQUAL_VECTORS(b, c);
zero_suppression_decode(&d[0], d.size(), b); zero_suppression_decode<unsigned>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d);
}
BOOST_AUTO_TEST_CASE( codec_zero_2b )
{
std::vector<unsigned> a, b, c, d(3, 0);
a += 0, 0, 1;
c += 0, 2, 1;
BOOST_CHECK(zero_suppression_encode<unsigned>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c);
zero_suppression_decode<unsigned>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d);
}
BOOST_AUTO_TEST_CASE( codec_zero_3b )
{
std::vector<unsigned> a, b, c, d(2, 0);
a += 0, 0;
c += 0, 2;
BOOST_CHECK(zero_suppression_encode<unsigned>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c);
zero_suppression_decode<unsigned>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d);
}
BOOST_AUTO_TEST_CASE( codec_zero_0c )
{
std::vector<uint64_t> a, b;
a += 0;
BOOST_CHECK(zero_suppression_encode<uint64_t>(b, &a[0], a.size()) == false);
}
BOOST_AUTO_TEST_CASE( codec_zero_1c )
{
std::vector<uint64_t> a, b, c, d(3, 0);
a += 1, 0, 0;
c += 1, 0, 2;
BOOST_CHECK(zero_suppression_encode<uint64_t>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c);
zero_suppression_decode<uint64_t>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d);
}
BOOST_AUTO_TEST_CASE( codec_zero_2c )
{
std::vector<uint64_t> a, b, c, d(3, 0);
a += 0, 0, 1;
c += 0, 2, 1;
BOOST_CHECK(zero_suppression_encode<uint64_t>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c);
zero_suppression_decode<uint64_t>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d);
}
BOOST_AUTO_TEST_CASE( codec_zero_3c )
{
std::vector<uint64_t> a, b, c, d(2, 0);
a += 0, 0;
c += 0, 2;
BOOST_CHECK(zero_suppression_encode<uint64_t>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c);
zero_suppression_decode<uint64_t>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d);
}
BOOST_AUTO_TEST_CASE( codec_zero_0d )
{
std::vector<wtype> a, b;
a += 0;
BOOST_CHECK(zero_suppression_encode<wtype>(b, &a[0], a.size()) == false);
}
BOOST_AUTO_TEST_CASE( codec_zero_1d )
{
std::vector<wtype> a, b, c, d(3, 0);
a += 1, 0, 0;
c += 1, 0, 2;
BOOST_CHECK(zero_suppression_encode<wtype>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c);
zero_suppression_decode<wtype>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d);
}
BOOST_AUTO_TEST_CASE( codec_zero_2d )
{
std::vector<wtype> a, b, c, d(3, 0);
a += 0, 0, 1;
c += 0, 2, 1;
BOOST_CHECK(zero_suppression_encode<wtype>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c);
zero_suppression_decode<wtype>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d);
}
BOOST_AUTO_TEST_CASE( codec_zero_3d )
{
std::vector<wtype> a, b, c, d(2, 0);
a += 0, 0;
c += 0, 2;
BOOST_CHECK(zero_suppression_encode<wtype>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c);
zero_suppression_decode<wtype>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d); EQUAL_VECTORS(a, d);
} }
BOOST_AUTO_TEST_CASE( codec_zero_4 ) BOOST_AUTO_TEST_CASE( codec_zero_4 )
{ {
std::vector<char> a, b, c, d(3, 0); std::vector<unsigned> a, b, c, d(5, 0);
a += 0, 1, 0; a += 0, 0, 0, 1, 0;
c += 0, 1, 1, 0, 1; c += 0, 3, 1, 0, 1;
BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); BOOST_CHECK(zero_suppression_encode<unsigned>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c); EQUAL_VECTORS(b, c);
zero_suppression_decode(&d[0], d.size(), b); zero_suppression_decode<unsigned>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d); EQUAL_VECTORS(a, d);
} }
BOOST_AUTO_TEST_CASE( codec_zero_5 ) BOOST_AUTO_TEST_CASE( codec_zero_5 )
{ {
std::vector<char> a, b, c, d(4, 0); std::vector<unsigned> a, b, c, d(5, 0);
a += 0, 1, 0, 0; a += 0, 1, 0, 0, 0;
c += 0, 1, 1, 0, 2; c += 0, 1, 1, 0, 3;
BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); BOOST_CHECK(zero_suppression_encode<unsigned>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c); EQUAL_VECTORS(b, c);
zero_suppression_decode(&d[0], d.size(), b); zero_suppression_decode<unsigned>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d); EQUAL_VECTORS(a, d);
} }
BOOST_AUTO_TEST_CASE( codec_zero_6 ) BOOST_AUTO_TEST_CASE( codec_zero_6 )
{ {
std::vector<char> a(255, 0), b, c, d(255, 0); std::vector<uint8_t> a(255, 0), b, c, d(255, 0);
c += 0, 255; c += 0, 255;
BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); BOOST_CHECK(zero_suppression_encode<uint8_t>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c); EQUAL_VECTORS(b, c);
zero_suppression_decode(&d[0], d.size(), b); zero_suppression_decode<uint8_t>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d); EQUAL_VECTORS(a, d);
} }
BOOST_AUTO_TEST_CASE( codec_zero_7 ) BOOST_AUTO_TEST_CASE( codec_zero_7 )
{ {
std::vector<char> a(256, 0), b, c, d(256, 0); std::vector<uint8_t> a(256, 0), b, c, d(256, 0);
c += 0, 0; c += 0, 0;
BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); BOOST_CHECK(zero_suppression_encode<uint8_t>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c); EQUAL_VECTORS(b, c);
zero_suppression_decode(&d[0], d.size(), b); zero_suppression_decode<uint8_t>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d); EQUAL_VECTORS(a, d);
} }
BOOST_AUTO_TEST_CASE( codec_zero_8 ) BOOST_AUTO_TEST_CASE( codec_zero_8 )
{ {
std::vector<char> a(257, 0), b, c, d(257, 0); std::vector<uint8_t> a(257, 0), b, c, d(257, 0);
c += 0, 0, 0, 1; c += 0, 0, 0, 1;
BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); BOOST_CHECK(zero_suppression_encode<uint8_t>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c); EQUAL_VECTORS(b, c);
zero_suppression_decode(&d[0], d.size(), b); zero_suppression_decode<uint8_t>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d); EQUAL_VECTORS(a, d);
} }
BOOST_AUTO_TEST_CASE( codec_zero_9 ) BOOST_AUTO_TEST_CASE( codec_zero_9 )
{ {
std::vector<char> a(1000, 0), b, c, d(1000, 0); std::vector<uint8_t> a(1000, 0), b, c, d(1000, 0);
c += 0, 0, 0, 0, 0, 0, 0, 232; c += 0, 0, 0, 0, 0, 0, 0, 232;
BOOST_CHECK(zero_suppression_encode(b, c.size(), &a[0], a.size())); BOOST_CHECK(zero_suppression_encode<uint8_t>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c); EQUAL_VECTORS(b, c);
zero_suppression_decode(&d[0], d.size(), b); zero_suppression_decode<uint8_t>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d);
}
BOOST_AUTO_TEST_CASE( codec_zero_10 )
{
std::vector<uint16_t> a(1000, 0), b, c, d(1000, 0);
c += 0, 1000;
BOOST_CHECK(zero_suppression_encode<uint16_t>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c);
zero_suppression_decode<uint16_t>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d);
}
BOOST_AUTO_TEST_CASE( codec_zero_11 )
{
std::vector<uint16_t> a(65536, 0), b, c, d(65536, 0);
c += 0, 0;
BOOST_CHECK(zero_suppression_encode<uint16_t>(b, &a[0], a.size()));
EQUAL_VECTORS(b, c);
zero_suppression_decode<uint16_t>(&d[0], d.size(), b);
EQUAL_VECTORS(a, d); EQUAL_VECTORS(a, d);
} }