LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
_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 "lsst/sphgeom/python.h"
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 
35 namespace {
36 
38 uint64_t _uint64(py::handle const &obj) {
39  try {
40  return obj.cast<uint64_t>();
41  } catch (py::cast_error const &) {
42  throw py::value_error(
43  "RangeSet elements and range beginning and "
44  "end points must be non-negative integers "
45  "less than 2**64");
46  }
47 }
48 
51 RangeSet makeRangeSet(py::iterable iterable) {
52  RangeSet rs;
53  for (py::handle item : iterable) {
54  PyObject *o = item.ptr();
55  if (PySequence_Check(o) && PySequence_Size(o) == 2) {
56  uint64_t first = _uint64(py::reinterpret_steal<py::object>(
57  PySequence_GetItem(o, 0)));
58  uint64_t last = _uint64(py::reinterpret_steal<py::object>(
59  PySequence_GetItem(o, 1)));
60  rs.insert(first, last);
61  } else {
62  rs.insert(_uint64(item));
63  }
64  }
65  return rs;
66 }
67 
69 py::list ranges(RangeSet const &self) {
70  py::list list;
71  for (auto t : self) {
72  list.append(py::make_tuple(py::int_(std::get<0>(t)),
73  py::int_(std::get<1>(t))));
74  }
75  return list;
76 }
77 
78 // TODO: In C++, the end-point of a range containing 2**64 - 1 is 0, because
79 // unsigned integer arithmetic is modular, and 2**64 does not fit in a
80 // uint64_t. In Python, it would perhaps be nicer to map between C++
81 // range end-point values of 0 and the Python integer 2**64. Since this is
82 // somewhat involved, it is left as future work.
83 
84 } // <anonymous>
85 
86 template <>
88  cls.def(py::init<>());
89  cls.def(py::init<uint64_t>(), "integer"_a);
90  cls.def(py::init([](uint64_t a, uint64_t b) {
91  return new RangeSet(a, b);
92  }),
93  "first"_a, "last"_a);
94  cls.def(py::init<RangeSet const &>(), "rangeSet"_a);
95  cls.def(py::init(
96  [](py::iterable iterable) {
97  return new RangeSet(makeRangeSet(iterable));
98  }),
99  "iterable"_a);
100  cls.def("__eq__", &RangeSet::operator==, py::is_operator());
101  cls.def("__ne__", &RangeSet::operator!=, py::is_operator());
102 
103  cls.def("insert", (void (RangeSet::*)(uint64_t)) & RangeSet::insert,
104  "integer"_a);
105  cls.def("insert",
106  (void (RangeSet::*)(uint64_t, uint64_t)) & RangeSet::insert,
107  "first"_a, "last"_a);
108  cls.def("erase", (void (RangeSet::*)(uint64_t)) & RangeSet::erase,
109  "integer"_a);
110  cls.def("erase", (void (RangeSet::*)(uint64_t, uint64_t)) & RangeSet::erase,
111  "first"_a, "last"_a);
112 
113  cls.def("complement", &RangeSet::complement);
114  cls.def("complemented", &RangeSet::complemented);
115  cls.def("intersection", &RangeSet::intersection, "rangeSet"_a);
116  // In C++, the set union function is named join because union is a keyword.
117  // Python does not suffer from the same restriction.
118  cls.def("union", &RangeSet::join, "rangeSet"_a);
119  cls.def("difference", &RangeSet::difference, "rangeSet"_a);
120  cls.def("symmetricDifference", &RangeSet::symmetricDifference,
121  "rangeSet"_a);
122  cls.def("__invert__", &RangeSet::operator~, py::is_operator());
123  cls.def("__and__", &RangeSet::operator&, py::is_operator());
124  cls.def("__or__", &RangeSet::operator|, py::is_operator());
125  cls.def("__sub__", &RangeSet::operator-, py::is_operator());
126  cls.def("__xor__", &RangeSet::operator^, py::is_operator());
127  cls.def("__iand__", &RangeSet::operator&=);
128  cls.def("__ior__", &RangeSet::operator|=);
129  cls.def("__isub__", &RangeSet::operator-=);
130  cls.def("__ixor__", &RangeSet::operator^=);
131 
132  cls.def("__len__", &RangeSet::size);
133  cls.def("__getitem__", [](RangeSet const &self, py::int_ i) {
134  auto j = python::convertIndex(static_cast<ptrdiff_t>(self.size()), i);
135  return py::cast(self.begin()[j]);
136  });
137 
138  cls.def("intersects",
139  (bool (RangeSet::*)(uint64_t) const) & RangeSet::intersects,
140  "integer"_a);
141  cls.def("intersects",
142  (bool (RangeSet::*)(uint64_t, uint64_t) const) &
143  RangeSet::intersects,
144  "first"_a, "last"_a);
145  cls.def("intersects",
146  (bool (RangeSet::*)(RangeSet const &) const) & RangeSet::intersects,
147  "rangeSet"_a);
148 
149  cls.def("contains",
150  (bool (RangeSet::*)(uint64_t) const) & RangeSet::contains,
151  "integer"_a);
152  cls.def("contains",
153  (bool (RangeSet::*)(uint64_t, uint64_t) const) & RangeSet::contains,
154  "first"_a, "last"_a);
155  cls.def("contains",
156  (bool (RangeSet::*)(RangeSet const &) const) & RangeSet::contains,
157  "rangeSet"_a);
158  cls.def("__contains__",
159  (bool (RangeSet::*)(uint64_t) const) & RangeSet::contains,
160  "integer"_a, py::is_operator());
161  cls.def("__contains__",
162  (bool (RangeSet::*)(uint64_t, uint64_t) const) & RangeSet::contains,
163  "first"_a, "last"_a, py::is_operator());
164  cls.def("__contains__",
165  (bool (RangeSet::*)(RangeSet const &) const) & RangeSet::contains,
166  "rangeSet"_a, py::is_operator());
167 
168  cls.def("isWithin",
169  (bool (RangeSet::*)(uint64_t) const) & RangeSet::isWithin,
170  "integer"_a);
171  cls.def("isWithin",
172  (bool (RangeSet::*)(uint64_t, uint64_t) const) & RangeSet::isWithin,
173  "first"_a, "last"_a);
174  cls.def("isWithin",
175  (bool (RangeSet::*)(RangeSet const &) const) & RangeSet::isWithin,
176  "rangeSet"_a);
177 
178  cls.def("isDisjointFrom",
179  (bool (RangeSet::*)(uint64_t) const) & RangeSet::isDisjointFrom,
180  "integer"_a);
181  cls.def("isDisjointFrom",
182  (bool (RangeSet::*)(uint64_t, uint64_t) const) &
183  RangeSet::isDisjointFrom,
184  "first"_a, "last"_a);
185  cls.def("isDisjointFrom",
186  (bool (RangeSet::*)(RangeSet const &) const) &
187  RangeSet::isDisjointFrom,
188  "rangeSet"_a);
189 
190  cls.def("simplify", &RangeSet::simplify, "n"_a);
191  cls.def("simplified", &RangeSet::simplified, "n"_a);
192  cls.def("scale", &RangeSet::scale, "factor"_a);
193  cls.def("scaled", &RangeSet::scaled, "factor"_a);
194  cls.def("fill", &RangeSet::fill);
195  cls.def("clear", &RangeSet::clear);
196  cls.def("empty", &RangeSet::empty);
197  cls.def("full", &RangeSet::full);
198  cls.def("size", &RangeSet::size);
199  cls.def("cardinality", &RangeSet::cardinality);
200  // max_size() and swap() are omitted. The former is a C++ container
201  // requirement, and the latter doesn't seem relevant to Python.
202  cls.def("isValid", &RangeSet::cardinality);
203  cls.def("ranges", &ranges);
204 
205  cls.def("__str__",
206  [](RangeSet const &self) { return py::str(ranges(self)); });
207  cls.def("__repr__", [](RangeSet const &self) {
208  return py::str("RangeSet({!s})").format(ranges(self));
209  });
210 
211  cls.def("__reduce__", [cls](RangeSet const &self) {
212  return py::make_tuple(cls, py::make_tuple(ranges(self)));
213  });
214 }
215 
216 } // sphgeom
217 } // lsst
This file provides a type for representing integer sets.
table::Key< int > b
table::Key< int > a
A RangeSet is a set of unsigned 64 bit integers.
Definition: RangeSet.h:99
daf::base::PropertyList * list
Definition: fits.cc:913
def scale(algorithm, min, max=None, frame=None)
Definition: ds9.py:108
def erase(frame=None)
Definition: ds9.py:96
PolynomialFunction1d simplified(ScaledPolynomialFunction1d const &f)
Calculate the standard polynomial function that is equivalent to a scaled standard polynomial functio...
ptrdiff_t convertIndex(ptrdiff_t len, pybind11::int_ i)
Convert a Python index i over a sequence with length len to a non-negative (C++ style) index,...
Definition: utils.h:40
void defineClass(py::class_< RangeSet, std::shared_ptr< RangeSet >> &cls)
Definition: _rangeSet.cc:87
A base class for image defects.