LSST Applications  21.0.0-147-g0e635eb1+1acddb5be5,22.0.0+052faf71bd,22.0.0+1ea9a8b2b2,22.0.0+6312710a6c,22.0.0+729191ecac,22.0.0+7589c3a021,22.0.0+9f079a9461,22.0.1-1-g7d6de66+b8044ec9de,22.0.1-1-g87000a6+536b1ee016,22.0.1-1-g8e32f31+6312710a6c,22.0.1-10-gd060f87+016f7cdc03,22.0.1-12-g9c3108e+df145f6f68,22.0.1-16-g314fa6d+c825727ab8,22.0.1-19-g93a5c75+d23f2fb6d8,22.0.1-19-gb93eaa13+aab3ef7709,22.0.1-2-g8ef0a89+b8044ec9de,22.0.1-2-g92698f7+9f079a9461,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gac51dbf+052faf71bd,22.0.1-2-gb66926d+6312710a6c,22.0.1-2-gcb770ba+09e3807989,22.0.1-20-g32debb5+b8044ec9de,22.0.1-23-gc2439a9a+fb0756638e,22.0.1-3-g496fd5d+09117f784f,22.0.1-3-g59f966b+1e6ba2c031,22.0.1-3-g849a1b8+f8b568069f,22.0.1-3-gaaec9c0+c5c846a8b1,22.0.1-32-g5ddfab5d3+60ce4897b0,22.0.1-4-g037fbe1+64e601228d,22.0.1-4-g8623105+b8044ec9de,22.0.1-5-g096abc9+d18c45d440,22.0.1-5-g15c806e+57f5c03693,22.0.1-7-gba73697+57f5c03693,master-g6e05de7fdc+c1283a92b8,master-g72cdda8301+729191ecac,w.2021.39
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.