LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
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
28
29namespace py = pybind11;
30using namespace pybind11::literals;
31
32namespace lsst {
33namespace sphgeom {
34
35namespace {
36
38uint64_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
51RangeSet 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
69py::list ranges(RangeSet const &self) {
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
86template <>
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) &
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) &
184 "first"_a, "last"_a);
185 cls.def("isDisjointFrom",
186 (bool (RangeSet::*)(RangeSet const &) const) &
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
RangeSet intersection(RangeSet const &s) const
intersection returns the intersection of this set and s.
Definition: RangeSet.cc:135
bool intersects(uint64_t u) const
Definition: RangeSet.h:425
void clear()
clear removes all integers from this set.
Definition: RangeSet.h:501
bool isWithin(uint64_t u) const
Definition: RangeSet.h:445
void insert(uint64_t u)
Definition: RangeSet.h:285
bool full() const
full checks whether all integers in the universe of range sets, [0, 2^64), are in this set.
Definition: RangeSet.h:511
bool contains(uint64_t u) const
Definition: RangeSet.h:435
RangeSet join(RangeSet const &s) const
join returns the union of this set and s.
Definition: RangeSet.cc:145
RangeSet & scale(uint64_t i)
scale multiplies the endpoints of each range in this set by the given integer.
Definition: RangeSet.cc:354
bool isDisjointFrom(uint64_t u) const
Definition: RangeSet.h:455
RangeSet simplified(uint32_t n) const
simplified returns a simplified copy of this set.
Definition: RangeSet.h:479
bool empty() const
empty checks whether there are any integers in this set.
Definition: RangeSet.h:507
RangeSet scaled(uint64_t i) const
scaled returns a scaled copy of this set.
Definition: RangeSet.h:494
RangeSet & complement()
complement replaces this set S with U ∖ S, where U is the universe of range sets, [0,...
Definition: RangeSet.h:328
size_t size() const
size returns the number of ranges in this set.
Definition: RangeSet.h:539
void fill()
fill adds all the unsigned 64 bit integers to this set.
Definition: RangeSet.h:504
void erase(uint64_t u)
Definition: RangeSet.h:306
RangeSet complemented() const
complemented returns a complemented copy of this set.
Definition: RangeSet.h:331
RangeSet difference(RangeSet const &s) const
difference returns the difference between this set and s.
Definition: RangeSet.cc:157
RangeSet & simplify(uint32_t n)
simplify simplifies this range set by "coarsening" its ranges.
Definition: RangeSet.cc:308
uint64_t cardinality() const
cardinality returns the number of integers in this set.
Definition: RangeSet.cc:300
RangeSet symmetricDifference(RangeSet const &s) const
symmetricDifference returns the symmetric difference of this set and s.
Definition: RangeSet.cc:166
daf::base::PropertyList * list
Definition: fits.cc:913
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(Pybind11Class &cls)
A base class for image defects.