LSSTApplications  19.0.0-11-g2ce9f25+2,20.0.0+1,20.0.0+11,20.0.0+2,20.0.0+3,20.0.0+4,20.0.0+5,20.0.0+8,20.0.0+9,20.0.0-1-g009f3de,20.0.0-1-g10df615+8,20.0.0-1-g253301a+4,20.0.0-1-g32a200e+8,20.0.0-1-g596936a+9,20.0.0-1-g8a53f90+1,20.0.0-1-gc96f8cb+10,20.0.0-1-gd1c87d7+1,20.0.0-15-g34741e2+3,20.0.0-2-g04cfba9+2,20.0.0-2-gec03fae+2,20.0.0-3-g082faa5+1,20.0.0-3-g2fa8bb8+6,20.0.0-3-gbdbfa727+1,20.0.0-4-gde602ef96+3,20.0.0-4-ge48a6ca+4,20.0.0-8-g1acaa36,20.0.0-8-g7eef53f7+5,w.2020.27
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 
83 PYBIND11_MODULE(rangeSet, mod) {
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
utils.h
lsst::afw::table._match.first
first
Definition: _match.py:76
lsst::afw::geom.transform.transformContinued.cls
cls
Definition: transformContinued.py:33
lsst::geom::polynomials::simplified
PolynomialFunction1d simplified(ScaledPolynomialFunction1d const &f)
Calculate the standard polynomial function that is equivalent to a scaled standard polynomial functio...
Definition: PolynomialFunction1d.cc:32
astshim.fitsChanContinued.contains
def contains(self, name)
Definition: fitsChanContinued.py:127
lsst
A base class for image defects.
Definition: imageAlgorithm.dox:1
list
daf::base::PropertyList * list
Definition: fits.cc:913
std::begin
T begin(T... args)
lsst::afw.display.ds9.scale
def scale(algorithm, min, max=None, frame=None)
Definition: ds9.py:109
pybind11
Definition: _GenericMap.cc:40
RangeSet.h
This file provides a type for representing integer sets.
lsst::utils.tests.init
def init()
Definition: tests.py:58
lsst::afw.display.ds9.erase
def erase(frame=None)
Definition: ds9.py:97
lsst::afw::cameraGeom::PYBIND11_MODULE
PYBIND11_MODULE(camera, mod)
Definition: camera.cc:133