LSSTApplications  19.0.0+10,19.0.0+80,19.0.0-1-g20d9b18+31,19.0.0-1-g49a97f9+4,19.0.0-1-g8c57eb9+31,19.0.0-1-g9a028c0+13,19.0.0-1-ga72da6b+3,19.0.0-1-gb77924a+15,19.0.0-1-gbfe0924+66,19.0.0-1-gc3516c3,19.0.0-1-gefe1d0d+49,19.0.0-1-gf8cb8b4+3,19.0.0-14-g7511ce4+6,19.0.0-16-g3dc1a33c+6,19.0.0-17-g59f0e8a+4,19.0.0-17-g9c22e3c+9,19.0.0-18-g35bb99870+2,19.0.0-19-g2772d4a+9,19.0.0-2-g260436e+53,19.0.0-2-g31cdcee,19.0.0-2-g9675b69+3,19.0.0-2-gaa2795f,19.0.0-2-gbcc4de1,19.0.0-2-gd6f004e+6,19.0.0-2-gde8e5e3+5,19.0.0-2-gff6972b+15,19.0.0-21-ge306cd8,19.0.0-21-gf122e69+2,19.0.0-3-g2d43a51+2,19.0.0-3-gf3b1435+6,19.0.0-4-g56feb96,19.0.0-4-gac56cce+17,19.0.0-49-gce872c1+1,19.0.0-5-g66946eb+6,19.0.0-5-gd8897ba+6,19.0.0-51-gfc4a647e,19.0.0-7-g686a884+5,19.0.0-7-g886f805+5,19.0.0-8-g305ff64,w.2020.17
LSSTDataManagementBasePackage
rangeSet.cc
Go to the documentation of this file.
1 /*
2  * LSST Data Management System
3  * See COPYRIGHT file at the top of the source tree.
4  *
5  * This product includes software developed by the
6  * LSST Project (http://www.lsst.org/).
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the LSST License Statement and
19  * the GNU General Public License along with this program. If not,
20  * see <https://www.lsstcorp.org/LegalNotices/>.
21  */
22 #include "pybind11/pybind11.h"
23 
24 #include <stdexcept>
25 
26 #include "lsst/sphgeom/RangeSet.h"
28 
29 namespace py = pybind11;
30 using namespace pybind11::literals;
31 
32 namespace lsst {
33 namespace sphgeom {
34 namespace {
35 
37 uint64_t _uint64(py::handle const & obj) {
38  try {
39  return obj.cast<uint64_t>();
40  } catch (py::cast_error const &) {
41  throw py::value_error(
42  "RangeSet elements and range beginning and "
43  "end points must be non-negative integers "
44  "less than 2**64");
45  }
46 }
47 
50 RangeSet makeRangeSet(py::iterable iterable) {
51  RangeSet rs;
52  for (py::handle item : iterable) {
53  PyObject *o = item.ptr();
54  if (PySequence_Check(o) && PySequence_Size(o) == 2) {
55  uint64_t first = _uint64(py::reinterpret_steal<py::object>(
56  PySequence_GetItem(o, 0)));
57  uint64_t last = _uint64(py::reinterpret_steal<py::object>(
58  PySequence_GetItem(o, 1)));
59  rs.insert(first, last);
60  } else {
61  rs.insert(_uint64(item));
62  }
63  }
64  return rs;
65 }
66 
68 py::list ranges(RangeSet const &self) {
69  py::list list;
70  for (auto t : self) {
71  list.append(py::make_tuple(py::int_(std::get<0>(t)),
72  py::int_(std::get<1>(t))));
73  }
74  return list;
75 }
76 
77 // TODO: In C++, the end-point of a range containing 2**64 - 1 is 0, because
78 // unsigned integer arithmetic is modular, and 2**64 does not fit in a
79 // uint64_t. In Python, it would perhaps be nicer to map between C++
80 // range end-point values of 0 and the Python integer 2**64. Since this is
81 // somewhat involved, it is left as future work.
82 
84  py::class_<RangeSet, std::shared_ptr<RangeSet>> cls(mod, "RangeSet");
85 
86  cls.def(py::init<>());
87  cls.def(py::init<uint64_t>(), "integer"_a);
88  cls.def(py::init<uint64_t, uint64_t>(), "first"_a, "last"_a);
89  cls.def(py::init<RangeSet const &>(), "rangeSet"_a);
90  cls.def(py::init(
91  [](py::iterable iterable) {
92  return new RangeSet(makeRangeSet(iterable));
93  }),
94  "iterable"_a);
95 
96  cls.def("__eq__", &RangeSet::operator==, py::is_operator());
97  cls.def("__ne__", &RangeSet::operator!=, py::is_operator());
98 
99  cls.def("insert", (void (RangeSet::*)(uint64_t)) & RangeSet::insert,
100  "integer"_a);
101  cls.def("insert",
102  (void (RangeSet::*)(uint64_t, uint64_t)) & RangeSet::insert,
103  "first"_a, "last"_a);
104  cls.def("erase", (void (RangeSet::*)(uint64_t)) & RangeSet::erase,
105  "integer"_a);
106  cls.def("erase", (void (RangeSet::*)(uint64_t, uint64_t)) & RangeSet::erase,
107  "first"_a, "last"_a);
108 
109  cls.def("complement", &RangeSet::complement);
110  cls.def("complemented", &RangeSet::complemented);
111  cls.def("intersection", &RangeSet::intersection, "rangeSet"_a);
112  // In C++, the set union function is named join because union is a keyword.
113  // Python does not suffer from the same restriction.
114  cls.def("union", &RangeSet::join, "rangeSet"_a);
115  cls.def("difference", &RangeSet::difference, "rangeSet"_a);
116  cls.def("symmetricDifference", &RangeSet::symmetricDifference,
117  "rangeSet"_a);
118  cls.def("__invert__", &RangeSet::operator~, py::is_operator());
119  cls.def("__and__", &RangeSet::operator&, py::is_operator());
120  cls.def("__or__", &RangeSet::operator|, py::is_operator());
121  cls.def("__sub__", &RangeSet::operator-, py::is_operator());
122  cls.def("__xor__", &RangeSet::operator^, py::is_operator());
123  cls.def("__iand__", &RangeSet::operator&=);
124  cls.def("__ior__", &RangeSet::operator|=);
125  cls.def("__isub__", &RangeSet::operator-=);
126  cls.def("__ixor__", &RangeSet::operator^=);
127 
128  cls.def("__len__", &RangeSet::size);
129  cls.def("__getitem__", [](RangeSet const &self, py::int_ i) {
130  auto j = python::convertIndex(static_cast<ptrdiff_t>(self.size()), i);
131  return py::cast(self.begin()[j]);
132  });
133 
134  cls.def("intersects",
135  (bool (RangeSet::*)(uint64_t) const) & RangeSet::intersects,
136  "integer"_a);
137  cls.def("intersects",
138  (bool (RangeSet::*)(uint64_t, uint64_t) const) &
139  RangeSet::intersects,
140  "first"_a, "last"_a);
141  cls.def("intersects",
142  (bool (RangeSet::*)(RangeSet const &) const) & RangeSet::intersects,
143  "rangeSet"_a);
144 
145  cls.def("contains",
146  (bool (RangeSet::*)(uint64_t) const) & RangeSet::contains,
147  "integer"_a);
148  cls.def("contains",
149  (bool (RangeSet::*)(uint64_t, uint64_t) const) & RangeSet::contains,
150  "first"_a, "last"_a);
151  cls.def("contains",
152  (bool (RangeSet::*)(RangeSet const &) const) & RangeSet::contains,
153  "rangeSet"_a);
154  cls.def("__contains__",
155  (bool (RangeSet::*)(uint64_t) const) & RangeSet::contains,
156  "integer"_a, py::is_operator());
157  cls.def("__contains__",
158  (bool (RangeSet::*)(uint64_t, uint64_t) const) & RangeSet::contains,
159  "first"_a, "last"_a, py::is_operator());
160  cls.def("__contains__",
161  (bool (RangeSet::*)(RangeSet const &) const) & RangeSet::contains,
162  "rangeSet"_a, py::is_operator());
163 
164  cls.def("isWithin",
165  (bool (RangeSet::*)(uint64_t) const) & RangeSet::isWithin,
166  "integer"_a);
167  cls.def("isWithin",
168  (bool (RangeSet::*)(uint64_t, uint64_t) const) & RangeSet::isWithin,
169  "first"_a, "last"_a);
170  cls.def("isWithin",
171  (bool (RangeSet::*)(RangeSet const &) const) & RangeSet::isWithin,
172  "rangeSet"_a);
173 
174  cls.def("isDisjointFrom",
175  (bool (RangeSet::*)(uint64_t) const) & RangeSet::isDisjointFrom,
176  "integer"_a);
177  cls.def("isDisjointFrom",
178  (bool (RangeSet::*)(uint64_t, uint64_t) const) &
179  RangeSet::isDisjointFrom,
180  "first"_a, "last"_a);
181  cls.def("isDisjointFrom",
182  (bool (RangeSet::*)(RangeSet const &) const) &
183  RangeSet::isDisjointFrom,
184  "rangeSet"_a);
185 
186  cls.def("simplify", &RangeSet::simplify, "n"_a);
187  cls.def("simplified", &RangeSet::simplified, "n"_a);
188  cls.def("scale", &RangeSet::scale, "factor"_a);
189  cls.def("scaled", &RangeSet::scaled, "factor"_a);
190  cls.def("fill", &RangeSet::fill);
191  cls.def("clear", &RangeSet::clear);
192  cls.def("empty", &RangeSet::empty);
193  cls.def("full", &RangeSet::full);
194  cls.def("size", &RangeSet::size);
195  cls.def("cardinality", &RangeSet::cardinality);
196  // max_size() and swap() are omitted. The former is a C++ container
197  // requirement, and the latter doesn't seem relevant to Python.
198  cls.def("isValid", &RangeSet::cardinality);
199  cls.def("ranges", &ranges);
200 
201  cls.def("__str__",
202  [](RangeSet const &self) { return py::str(ranges(self)); });
203  cls.def("__repr__", [](RangeSet const &self) {
204  return py::str("RangeSet({!s})").format(ranges(self));
205  });
206 
207  cls.def("__reduce__", [cls](RangeSet const &self) {
208  return py::make_tuple(cls, py::make_tuple(ranges(self)));
209  });
210 }
211 
212 } // <anonymous>
213 } // sphgeom
214 } // lsst
def erase(frame=None)
Definition: ds9.py:97
def init()
Definition: tests.py:65
PYBIND11_MODULE(camera, mod)
Definition: camera.cc:133
def scale(algorithm, min, max=None, frame=None)
Definition: ds9.py:109
PolynomialFunction1d simplified(ScaledPolynomialFunction1d const &f)
Calculate the standard polynomial function that is equivalent to a scaled standard polynomial functio...
A base class for image defects.
This file provides a type for representing integer sets.
T begin(T... args)
daf::base::PropertyList * list
Definition: fits.cc:913