mirror of
https://github.com/boostorg/histogram.git
synced 2026-01-30 20:02:13 +00:00
back to histogram master template
This commit is contained in:
@@ -25,152 +25,147 @@ namespace np = boost::python::numpy;
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace bp = boost::python;
|
||||
namespace bh = boost::histogram;
|
||||
namespace bha = boost::histogram::axis;
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T> python::str generic_repr(const T &t) {
|
||||
template <typename T> bp::str generic_repr(const T &t) {
|
||||
std::ostringstream os;
|
||||
os << t;
|
||||
return os.str().c_str();
|
||||
}
|
||||
|
||||
struct generic_iterator {
|
||||
generic_iterator(python::object o) : iterable(o), size(python::len(iterable)) {}
|
||||
python::object next() {
|
||||
generic_iterator(bp::object o) : iterable(o), size(bp::len(iterable)) {}
|
||||
bp::object next() {
|
||||
if (idx == size) {
|
||||
PyErr_SetString(PyExc_StopIteration, "No more items.");
|
||||
python::throw_error_already_set();
|
||||
bp::throw_error_already_set();
|
||||
}
|
||||
return iterable[idx++];
|
||||
}
|
||||
python::object self() { return python::object(*this); }
|
||||
python::object iterable;
|
||||
bp::object self() { return bp::object(*this); }
|
||||
bp::object iterable;
|
||||
unsigned idx = 0;
|
||||
unsigned size = 0;
|
||||
};
|
||||
|
||||
generic_iterator make_generic_iterator(python::object self) {
|
||||
generic_iterator make_generic_iterator(bp::object self) {
|
||||
return generic_iterator(self);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct axis_interval_to_python
|
||||
{
|
||||
static PyObject* convert(const axis::interval<T> &i)
|
||||
static PyObject* convert(const bha::interval<T> &i)
|
||||
{
|
||||
return python::incref(python::make_tuple(i.lower(), i.upper()).ptr());
|
||||
return bp::incref(bp::make_tuple(i.lower(), i.upper()).ptr());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct pair_int_axis_interval_to_python
|
||||
{
|
||||
static PyObject* convert(const std::pair<int, axis::interval<T>> &p)
|
||||
static PyObject* convert(const std::pair<int, bha::interval<T>> &p)
|
||||
{
|
||||
return python::incref(python::make_tuple(
|
||||
p.first, python::make_tuple(p.second.lower(), p.second.upper())
|
||||
return bp::incref(bp::make_tuple(
|
||||
p.first, bp::make_tuple(p.second.lower(), p.second.upper())
|
||||
).ptr());
|
||||
}
|
||||
};
|
||||
|
||||
python::object variable_init(python::tuple args, python::dict kwargs) {
|
||||
using namespace python;
|
||||
|
||||
object self = args[0];
|
||||
bp::object variable_init(bp::tuple args, bp::dict kwargs) {
|
||||
bp::object self = args[0];
|
||||
|
||||
if (len(args) < 2) {
|
||||
PyErr_SetString(PyExc_TypeError, "require at least two arguments");
|
||||
throw_error_already_set();
|
||||
bp::throw_error_already_set();
|
||||
}
|
||||
|
||||
std::vector<double> v;
|
||||
for (int i = 1, n = len(args); i < n; ++i) {
|
||||
v.push_back(extract<double>(args[i]));
|
||||
v.push_back(bp::extract<double>(args[i]));
|
||||
}
|
||||
|
||||
string_view label;
|
||||
auto uo = axis::uoflow::on;
|
||||
boost::string_view label;
|
||||
auto uo = bha::uoflow::on;
|
||||
while (len(kwargs) > 0) {
|
||||
python::tuple kv = kwargs.popitem();
|
||||
string_view k = extract<const char*>(kv[0])();
|
||||
object v = kv[1];
|
||||
bp::tuple kv = kwargs.popitem();
|
||||
boost::string_view k = bp::extract<const char*>(kv[0])();
|
||||
bp::object v = kv[1];
|
||||
if (k == "label")
|
||||
label = extract<const char*>(v)();
|
||||
label = bp::extract<const char*>(v)();
|
||||
else if (k == "uoflow") {
|
||||
if (!extract<bool>(v))
|
||||
uo = axis::uoflow::off;
|
||||
if (!bp::extract<bool>(v))
|
||||
uo = bha::uoflow::off;
|
||||
}
|
||||
else {
|
||||
std::stringstream s;
|
||||
s << "keyword " << k << " not recognized";
|
||||
PyErr_SetString(PyExc_KeyError, s.str().c_str());
|
||||
throw_error_already_set();
|
||||
bp::throw_error_already_set();
|
||||
}
|
||||
}
|
||||
|
||||
return self.attr("__init__")(
|
||||
axis::variable<>(v.begin(), v.end(), label, uo));
|
||||
bha::variable<>(v.begin(), v.end(), label, uo));
|
||||
}
|
||||
|
||||
python::object category_init(python::tuple args, python::dict kwargs) {
|
||||
using namespace python;
|
||||
bp::object category_init(bp::tuple args, bp::dict kwargs) {
|
||||
bp::object self = args[0];
|
||||
|
||||
object self = args[0];
|
||||
|
||||
if (len(args) == 1) {
|
||||
if (bp::len(args) == 1) {
|
||||
PyErr_SetString(PyExc_TypeError, "require at least one argument");
|
||||
throw_error_already_set();
|
||||
bp::throw_error_already_set();
|
||||
}
|
||||
|
||||
string_view label;
|
||||
while (len(kwargs) > 0) {
|
||||
python::tuple kv = kwargs.popitem();
|
||||
string_view k = extract<const char*>(kv[0])();
|
||||
object v = kv[1];
|
||||
boost::string_view label;
|
||||
while (bp::len(kwargs) > 0) {
|
||||
bp::tuple kv = kwargs.popitem();
|
||||
boost::string_view k = bp::extract<const char*>(kv[0])();
|
||||
bp::object v = kv[1];
|
||||
if (k == "label")
|
||||
label = extract<const char*>(v)();
|
||||
label = bp::extract<const char*>(v)();
|
||||
else {
|
||||
std::stringstream s;
|
||||
s << "keyword " << k << " not recognized";
|
||||
PyErr_SetString(PyExc_KeyError, s.str().c_str());
|
||||
throw_error_already_set();
|
||||
bp::throw_error_already_set();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> c;
|
||||
for (int i = 1, n = len(args); i < n; ++i)
|
||||
c.push_back(extract<int>(args[i]));
|
||||
for (int i = 1, n = bp::len(args); i < n; ++i)
|
||||
c.push_back(bp::extract<int>(args[i]));
|
||||
|
||||
return self.attr("__init__")(axis::category<>(c.begin(), c.end(), label));
|
||||
return self.attr("__init__")(bha::category<>(c.begin(), c.end(), label));
|
||||
}
|
||||
|
||||
template <typename A> python::object axis_getitem(const A &a, int i) {
|
||||
template <typename A> bp::object axis_getitem(const A &a, int i) {
|
||||
if (i < -1 * a.uoflow() || i >= a.size() + 1 * a.uoflow()) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of bounds");
|
||||
python::throw_error_already_set();
|
||||
bp::throw_error_already_set();
|
||||
}
|
||||
return python::object(a[i]);
|
||||
return bp::object(a[i]);
|
||||
}
|
||||
|
||||
template <typename T> void axis_set_label(T& t, python::str s) {
|
||||
t.label({python::extract<const char*>(s)(),
|
||||
static_cast<std::size_t>(python::len(s))});
|
||||
template <typename T> void axis_set_label(T& t, bp::str s) {
|
||||
t.label({bp::extract<const char*>(s)(),
|
||||
static_cast<std::size_t>(bp::len(s))});
|
||||
}
|
||||
|
||||
template <typename T> python::str axis_get_label(const T& t) {
|
||||
template <typename T> bp::str axis_get_label(const T& t) {
|
||||
auto s = t.label();
|
||||
return {s.data(), s.size()};
|
||||
}
|
||||
|
||||
#ifdef HAVE_NUMPY
|
||||
template <typename Axis> python::object axis_array_interface(const Axis& axis) {
|
||||
template <typename Axis> bp::object axis_array_interface(const Axis& axis) {
|
||||
using T = typename std::decay<decltype(axis[0].lower())>::type;
|
||||
python::dict d;
|
||||
auto shape = python::make_tuple(axis.size()+1);
|
||||
bp::dict d;
|
||||
auto shape = bp::make_tuple(axis.size()+1);
|
||||
d["shape"] = shape;
|
||||
d["typestr"] = python::dtype_typestr<T>();
|
||||
d["typestr"] = bp::dtype_typestr<T>();
|
||||
// make new array, and pass it to Python
|
||||
auto a = np::empty(shape, np::dtype::get_builtin<T>());
|
||||
auto buf = reinterpret_cast<T*>(a.get_data());
|
||||
@@ -181,11 +176,11 @@ template <typename Axis> python::object axis_array_interface(const Axis& axis) {
|
||||
return d;
|
||||
}
|
||||
|
||||
template <> python::object axis_array_interface<axis::category<>>(const axis::category<>& axis) {
|
||||
python::dict d;
|
||||
auto shape = python::make_tuple(axis.size());
|
||||
template <> bp::object axis_array_interface<bha::category<>>(const bha::category<>& axis) {
|
||||
bp::dict d;
|
||||
auto shape = bp::make_tuple(axis.size());
|
||||
d["shape"] = shape;
|
||||
d["typestr"] = python::dtype_typestr<int>();
|
||||
d["typestr"] = bp::dtype_typestr<int>();
|
||||
// make new array, and pass it to Python
|
||||
auto a = np::empty(shape, np::dtype::get_builtin<int>());
|
||||
auto buf = reinterpret_cast<int*>(a.get_data());
|
||||
@@ -198,7 +193,7 @@ template <> python::object axis_array_interface<axis::category<>>(const axis::ca
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
struct axis_suite : public python::def_visitor<axis_suite<T>> {
|
||||
struct axis_suite : public bp::def_visitor<axis_suite<T>> {
|
||||
template <class Class> static void visit(Class &cl) {
|
||||
cl.add_property(
|
||||
"shape", &T::shape,
|
||||
@@ -208,18 +203,18 @@ struct axis_suite : public python::def_visitor<axis_suite<T>> {
|
||||
"Name or description for the axis.");
|
||||
cl.def("index", &T::index, ":param float x: value"
|
||||
"\n:returns: bin index for the passed value",
|
||||
python::args("self", "x"));
|
||||
bp::args("self", "x"));
|
||||
cl.def("__len__", &T::size,
|
||||
":returns: number of bins, excluding over-/underflow bins.",
|
||||
python::arg("self"));
|
||||
bp::arg("self"));
|
||||
cl.def("__getitem__", axis_getitem<T>,
|
||||
":param integer i: bin index"
|
||||
"\n:returns: bin corresponding to index",
|
||||
python::args("self", "i"));
|
||||
bp::args("self", "i"));
|
||||
cl.def("__iter__", make_generic_iterator);
|
||||
cl.def("__repr__", generic_repr<T>,
|
||||
":returns: string representation of this axis", python::arg("self"));
|
||||
cl.def(python::self == python::self);
|
||||
":returns: string representation of this axis", bp::arg("self"));
|
||||
cl.def(bp::self == bp::self);
|
||||
#ifdef HAVE_NUMPY
|
||||
cl.add_property("__array_interface__", &axis_array_interface<T>);
|
||||
#endif
|
||||
@@ -227,67 +222,63 @@ struct axis_suite : public python::def_visitor<axis_suite<T>> {
|
||||
};
|
||||
|
||||
template <typename Transform>
|
||||
axis::regular<double, Transform>* regular_init(
|
||||
bha::regular<double, Transform>* regular_init(
|
||||
unsigned bin, double lower, double upper,
|
||||
python::str pylabel, bool with_uoflow)
|
||||
bp::str pylabel, bool with_uoflow)
|
||||
{
|
||||
using namespace ::boost::python;
|
||||
const auto uo = with_uoflow ? axis::uoflow::on : axis::uoflow::off;
|
||||
return new axis::regular<double, Transform>(bin, lower, upper,
|
||||
{extract<const char*>(pylabel)(),
|
||||
static_cast<std::size_t>(len(pylabel))},
|
||||
const auto uo = with_uoflow ? bha::uoflow::on : bha::uoflow::off;
|
||||
return new bha::regular<double, Transform>(bin, lower, upper,
|
||||
{bp::extract<const char*>(pylabel)(),
|
||||
static_cast<std::size_t>(bp::len(pylabel))},
|
||||
uo);
|
||||
}
|
||||
|
||||
axis::regular<double, axis::transform::pow>* regular_pow_init(
|
||||
bha::regular<double, bha::transform::pow>* regular_pow_init(
|
||||
unsigned bin, double lower, double upper, double power,
|
||||
python::str pylabel, bool with_uoflow)
|
||||
bp::str pylabel, bool with_uoflow)
|
||||
{
|
||||
using namespace ::boost::python;
|
||||
const auto uo = with_uoflow ? axis::uoflow::on : axis::uoflow::off;
|
||||
return new axis::regular<double, axis::transform::pow>(
|
||||
const auto uo = with_uoflow ? bha::uoflow::on : bha::uoflow::off;
|
||||
return new bha::regular<double, bha::transform::pow>(
|
||||
bin, lower, upper,
|
||||
{extract<const char*>(pylabel)(),
|
||||
static_cast<std::size_t>(len(pylabel))},
|
||||
uo, power);
|
||||
}
|
||||
|
||||
axis::integer<>* integer_init(int lower, int upper,
|
||||
python::str pylabel, bool with_uoflow)
|
||||
bha::integer<>* integer_init(int lower, int upper,
|
||||
bp::str pylabel, bool with_uoflow)
|
||||
{
|
||||
using namespace ::boost::python;
|
||||
const auto uo = with_uoflow ? axis::uoflow::on : axis::uoflow::off;
|
||||
return new axis::integer<>(lower, upper,
|
||||
const auto uo = with_uoflow ? bha::uoflow::on : bha::uoflow::off;
|
||||
return new bha::integer<>(lower, upper,
|
||||
{extract<const char*>(pylabel)(),
|
||||
static_cast<std::size_t>(len(pylabel))},
|
||||
uo);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void register_axis_types() {
|
||||
using namespace ::boost::python;
|
||||
using namespace ::boost::histogram::axis;
|
||||
using ::boost::python::arg; // resolve ambiguity
|
||||
using bp::arg; // resolve ambiguity
|
||||
docstring_options dopt(true, true, false);
|
||||
|
||||
to_python_converter<
|
||||
interval<int>,
|
||||
bha::interval<int>,
|
||||
axis_interval_to_python<int>
|
||||
>();
|
||||
|
||||
to_python_converter<
|
||||
interval<double>,
|
||||
bha::interval<double>,
|
||||
axis_interval_to_python<double>
|
||||
>();
|
||||
|
||||
to_python_converter<
|
||||
std::pair<int, interval<int>>,
|
||||
std::pair<int, bha::interval<int>>,
|
||||
pair_int_axis_interval_to_python<int>
|
||||
>();
|
||||
|
||||
to_python_converter<
|
||||
std::pair<int, interval<double>>,
|
||||
std::pair<int, bha::interval<double>>,
|
||||
pair_int_axis_interval_to_python<double>
|
||||
>();
|
||||
|
||||
@@ -295,34 +286,34 @@ void register_axis_types() {
|
||||
.def("__iter__", &generic_iterator::self)
|
||||
.def("next", &generic_iterator::next);
|
||||
|
||||
class_<regular<>>(
|
||||
class_<bha::regular<>>(
|
||||
"regular",
|
||||
"Axis for real-valued data and bins of equal width."
|
||||
"\nBinning is a O(1) operation.",
|
||||
no_init)
|
||||
.def("__init__", make_constructor(regular_init<axis::transform::identity>,
|
||||
.def("__init__", make_constructor(regular_init<bha::transform::identity>,
|
||||
default_call_policies(),
|
||||
(arg("bin"), arg("lower"), arg("upper"),
|
||||
arg("label")="", arg("uoflow")=true)))
|
||||
.def(axis_suite<regular<>>());
|
||||
.def(axis_suite<bha::regular<>>());
|
||||
|
||||
#define BOOST_HISTOGRAM_PYTHON_REGULAR_CLASS(x) \
|
||||
class_<regular<double, axis::transform::x>>( \
|
||||
class_<bha::regular<double, bha::transform::x>>( \
|
||||
"regular_"#x, \
|
||||
"Axis for real-valued data and bins of equal width in "#x"-space." \
|
||||
"\nBinning is a O(1) operation.", \
|
||||
no_init) \
|
||||
.def("__init__", make_constructor(regular_init<axis::transform::x>, \
|
||||
.def("__init__", make_constructor(regular_init<bha::transform::x>, \
|
||||
default_call_policies(), \
|
||||
(arg("bin"), arg("lower"), arg("upper"), \
|
||||
arg("label")="", arg("uoflow")=true))) \
|
||||
.def(axis_suite<regular<double, axis::transform::x>>())
|
||||
.def(axis_suite<bha::regular<double, bha::transform::x>>())
|
||||
|
||||
BOOST_HISTOGRAM_PYTHON_REGULAR_CLASS(log);
|
||||
BOOST_HISTOGRAM_PYTHON_REGULAR_CLASS(sqrt);
|
||||
BOOST_HISTOGRAM_PYTHON_REGULAR_CLASS(cos);
|
||||
|
||||
class_<regular<double, axis::transform::pow>>(
|
||||
class_<bha::regular<double, bha::transform::pow>>(
|
||||
"regular_pow",
|
||||
"Axis for real-valued data and bins of equal width in power-space."
|
||||
"\nBinning is a O(1) operation.",
|
||||
@@ -331,9 +322,9 @@ void register_axis_types() {
|
||||
default_call_policies(),
|
||||
(arg("bin"), arg("lower"), arg("upper"), arg("power"),
|
||||
arg("label")="", arg("uoflow")=true)))
|
||||
.def(axis_suite<regular<double, axis::transform::pow>>());
|
||||
.def(axis_suite<bha::regular<double, bha::transform::pow>>());
|
||||
|
||||
class_<circular<>>(
|
||||
class_<bha::circular<>>(
|
||||
"circular",
|
||||
"Axis for real-valued angles."
|
||||
"\nThere are no overflow/underflow bins for this axis,"
|
||||
@@ -342,21 +333,21 @@ void register_axis_types() {
|
||||
no_init)
|
||||
.def(init<unsigned, double, double, const char*>(
|
||||
(arg("self"), arg("bin"), arg("phase") = 0.0,
|
||||
arg("perimeter") = math::double_constants::two_pi,
|
||||
arg("perimeter") = boost::math::double_constants::two_pi,
|
||||
arg("label") = "")))
|
||||
.def(axis_suite<circular<>>());
|
||||
.def(axis_suite<bha::circular<>>());
|
||||
|
||||
class_<variable<>>(
|
||||
class_<bha::variable<>>(
|
||||
"variable",
|
||||
"Axis for real-valued data and bins of varying width."
|
||||
"\nBinning is a O(log(N)) operation. If speed matters and"
|
||||
"\nthe problem domain allows it, prefer a regular axis.",
|
||||
no_init)
|
||||
.def("__init__", raw_function(variable_init))
|
||||
.def(init<const variable<> &>())
|
||||
.def(axis_suite<variable<>>());
|
||||
.def(init<const bha::variable<> &>())
|
||||
.def(axis_suite<bha::variable<>>());
|
||||
|
||||
class_<integer<>>(
|
||||
class_<bha::integer<>>(
|
||||
"integer",
|
||||
"An axis for a contiguous range of integers with bins"
|
||||
"\nthat are one integer wide. Faster than a regular axis."
|
||||
@@ -366,9 +357,9 @@ void register_axis_types() {
|
||||
default_call_policies(),
|
||||
(arg("lower"), arg("upper"), arg("label") = "",
|
||||
arg("uoflow") = true)))
|
||||
.def(axis_suite<integer<>>());
|
||||
.def(axis_suite<bha::integer<>>());
|
||||
|
||||
class_<category<>>(
|
||||
class_<bha::category<>>(
|
||||
"category",
|
||||
"An axis for set of unique integer values. Each value is mapped to"
|
||||
"\na corresponding bin, following the order of the arguments in"
|
||||
@@ -376,8 +367,6 @@ void register_axis_types() {
|
||||
"\nBinning is a O(1) operation.",
|
||||
no_init)
|
||||
.def("__init__", raw_function(category_init))
|
||||
.def(init<const category<> &>())
|
||||
.def(axis_suite<category<>>());
|
||||
}
|
||||
}
|
||||
.def(init<const bha::category<> &>())
|
||||
.def(axis_suite<bha::category<>>());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user