sdata 1.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sdata/__init__.py +140 -0
- sdata/base.py +684 -0
- sdata/contrib/__init__.py +0 -0
- sdata/contrib/piexif/__init__.py +12 -0
- sdata/contrib/piexif/_common.py +94 -0
- sdata/contrib/piexif/_dump.py +346 -0
- sdata/contrib/piexif/_exceptions.py +2 -0
- sdata/contrib/piexif/_exif.py +638 -0
- sdata/contrib/piexif/_insert.py +60 -0
- sdata/contrib/piexif/_load.py +270 -0
- sdata/contrib/piexif/_remove.py +56 -0
- sdata/contrib/piexif/_transplant.py +45 -0
- sdata/contrib/piexif/_webp.py +240 -0
- sdata/contrib/piexif/helper.py +66 -0
- sdata/contrib/ranger/__init__.py +8 -0
- sdata/contrib/ranger/collections/__init__.py +0 -0
- sdata/contrib/ranger/collections/rangebucketmap.py +346 -0
- sdata/contrib/ranger/collections/rangemap.py +396 -0
- sdata/contrib/ranger/collections/rangeset.py +483 -0
- sdata/contrib/ranger/range/__init__.py +0 -0
- sdata/contrib/ranger/range/cut.py +285 -0
- sdata/contrib/ranger/range/range.py +644 -0
- sdata/contrib/sobol_seq.py +394 -0
- sdata/contrib/sortedcontainers/LICENSE +13 -0
- sdata/contrib/sortedcontainers/__init__.py +74 -0
- sdata/contrib/sortedcontainers/sorteddict.py +789 -0
- sdata/contrib/sortedcontainers/sortedlist.py +2646 -0
- sdata/contrib/sortedcontainers/sortedset.py +733 -0
- sdata/contrib/sqlitedict.py +598 -0
- sdata/contrib/timeflake/__init__.py +40 -0
- sdata/contrib/timeflake/flake.py +69 -0
- sdata/contrib/timeflake/utils.py +47 -0
- sdata/deprecated/__init__.py +10 -0
- sdata/deprecated/data.py +1503 -0
- sdata/did/__init__.py +129 -0
- sdata/did/_http.py +67 -0
- sdata/did/base58btc.py +49 -0
- sdata/did/did_github.py +152 -0
- sdata/did/did_peer4.py +155 -0
- sdata/did/did_web.py +222 -0
- sdata/did/diddoc.py +75 -0
- sdata/did/ed25519.py +225 -0
- sdata/did/eddsa.py +107 -0
- sdata/did/errors.py +40 -0
- sdata/did/issue_vc.py +193 -0
- sdata/did/jose.py +126 -0
- sdata/did/keys.py +104 -0
- sdata/did/utils_didkey.py +161 -0
- sdata/did/verify_vp.py +158 -0
- sdata/doe.py +101 -0
- sdata/dtypes.py +510 -0
- sdata/experiments/__init__.py +331 -0
- sdata/experiments/blob0.py +131 -0
- sdata/experiments/file.py +42 -0
- sdata/experiments/filegroup.py +144 -0
- sdata/experiments/image_old.py +313 -0
- sdata/experiments/ks2.py +15 -0
- sdata/experiments/lapshear.py +8 -0
- sdata/experiments/material.py +7 -0
- sdata/experiments/parameters_deprecated.py +394 -0
- sdata/experiments/workbook.py +226 -0
- sdata/format.py +125 -0
- sdata/imagemeta.py +533 -0
- sdata/interactive.py +118 -0
- sdata/iolib/__init__.py +51 -0
- sdata/iolib/hashtree.py +264 -0
- sdata/iolib/json1sqlitestore.py +554 -0
- sdata/iolib/jsonsqlitestore.py +704 -0
- sdata/iolib/pud.py +242 -0
- sdata/iolib/reader.py +262 -0
- sdata/iolib/writer.py +419 -0
- sdata/metadata.py +882 -0
- sdata/parameter.py +414 -0
- sdata/schema.py +273 -0
- sdata/sclass/__init__.py +111 -0
- sdata/sclass/bfo_classes.py +362 -0
- sdata/sclass/blob.py +362 -0
- sdata/sclass/content.py +87 -0
- sdata/sclass/dataframe.py +1251 -0
- sdata/sclass/dataframegroup.py +187 -0
- sdata/sclass/dependency_graph.py +85 -0
- sdata/sclass/filereference.py +124 -0
- sdata/sclass/image.py +218 -0
- sdata/sclass/lazy_namespace.py +155 -0
- sdata/sclass/process.py +383 -0
- sdata/sclass/process_graph.py +221 -0
- sdata/sclass/zipfile.py +135 -0
- sdata/semantic.py +346 -0
- sdata/suuid.py +136 -0
- sdata/timestamp.py +336 -0
- sdata/tools.py +14 -0
- sdata/units.py +602 -0
- sdata/vocab.py +149 -0
- sdata-1.5.0.dist-info/METADATA +264 -0
- sdata-1.5.0.dist-info/RECORD +98 -0
- sdata-1.5.0.dist-info/WHEEL +5 -0
- sdata-1.5.0.dist-info/licenses/LICENSE-MIT +21 -0
- sdata-1.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
from bisect import bisect_left
|
|
2
|
+
from sdata.contrib.ranger.range.range import Range
|
|
3
|
+
from collections import deque
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class RangeMap(object):
|
|
7
|
+
""" Class used to represent a mapping of disjoint ranges to some objects.
|
|
8
|
+
Ranges do not coalesce. If a new Range is added over an existing Range,
|
|
9
|
+
it overwrites the overlapping part of the existing Range
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, range_dict=None):
|
|
13
|
+
""" Instantiates a RangeMap
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
range_dict : Dictionary of Range -> object
|
|
18
|
+
Dictionary to start off the RangeMap with. Note that this will
|
|
19
|
+
not be traversed in any particular order, so it may result in
|
|
20
|
+
unexpected behavior if instantiated with any overlapping ranges
|
|
21
|
+
"""
|
|
22
|
+
# Holds lower and upper cut points of ranges
|
|
23
|
+
self.lower_cuts = []
|
|
24
|
+
self.upper_cuts = []
|
|
25
|
+
# Holds the actual range objects that are the keys
|
|
26
|
+
self.ranges = []
|
|
27
|
+
# Holds items mapping to each range
|
|
28
|
+
self.items = []
|
|
29
|
+
if range_dict is not None:
|
|
30
|
+
for range_key, val in range_dict.iteritems():
|
|
31
|
+
self.put(range_key, val)
|
|
32
|
+
|
|
33
|
+
def __getitem__(self, key):
|
|
34
|
+
return self.get(key)
|
|
35
|
+
|
|
36
|
+
def __setitem__(self, key, value):
|
|
37
|
+
self.put(key, value)
|
|
38
|
+
|
|
39
|
+
def __delitem__(self, key):
|
|
40
|
+
self.remove(key)
|
|
41
|
+
|
|
42
|
+
def __iter__(self):
|
|
43
|
+
return iter(self.ranges)
|
|
44
|
+
|
|
45
|
+
def __eq__(self, other):
|
|
46
|
+
if not isinstance(other, RangeMap):
|
|
47
|
+
return False
|
|
48
|
+
elif len(self) != len(other):
|
|
49
|
+
return False
|
|
50
|
+
for k1, v1, k2, v2 in zip(self.ranges, self.items,
|
|
51
|
+
other.ranges, other.items):
|
|
52
|
+
if (k1 != k2 or v1 != v2):
|
|
53
|
+
return False
|
|
54
|
+
return True
|
|
55
|
+
|
|
56
|
+
def __ne__(self, other):
|
|
57
|
+
return not self.__eq__(other)
|
|
58
|
+
|
|
59
|
+
def __len__(self):
|
|
60
|
+
return len(self.ranges)
|
|
61
|
+
|
|
62
|
+
def __repr__(self):
|
|
63
|
+
if len(self) < 5:
|
|
64
|
+
return_str = "{%s}" % ", ".join([
|
|
65
|
+
"%s : %s" % (k, v) for k, v in zip(self.ranges, self.items)
|
|
66
|
+
])
|
|
67
|
+
else:
|
|
68
|
+
return_str = "{%s, ..., %s}" % (", ".join([
|
|
69
|
+
"%s : %s" % (k, v) for k, v in zip(self.ranges[:2], self.items[:2])
|
|
70
|
+
]), ", ".join([
|
|
71
|
+
"%s : %s" % (k, v) for k, v in zip(self.ranges[-2:], self.items[-2:])
|
|
72
|
+
])
|
|
73
|
+
)
|
|
74
|
+
return return_str
|
|
75
|
+
|
|
76
|
+
def __missing__(self, key):
|
|
77
|
+
raise KeyError(str(key))
|
|
78
|
+
|
|
79
|
+
def contains(self, val):
|
|
80
|
+
""" Returns true if any of the ranges fully enclose the given
|
|
81
|
+
value, which can be a single value or a Range object
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
val : A single value or a Range object
|
|
86
|
+
|
|
87
|
+
Raises
|
|
88
|
+
------
|
|
89
|
+
ValueError
|
|
90
|
+
If the value type not compatible with the ranges
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
true if any of the ranges fully enclose the given value
|
|
95
|
+
"""
|
|
96
|
+
if len(self) == 0: return False
|
|
97
|
+
# Get the index+1 of the highest lower cut <= to the value or its
|
|
98
|
+
# lower cutpoint and check if the value contained
|
|
99
|
+
if isinstance(val, Range):
|
|
100
|
+
lower_ind = max(bisect_left(self.lower_cuts, val.lower_cut) - 1, 0)
|
|
101
|
+
return self.ranges[lower_ind].encloses(val)
|
|
102
|
+
else:
|
|
103
|
+
lower_ind = max(bisect_left(self.lower_cuts, val) - 1, 0)
|
|
104
|
+
return self.ranges[lower_ind].contains(val)
|
|
105
|
+
|
|
106
|
+
def get(self, key):
|
|
107
|
+
""" Get the item(s) corresponding to a given key. The key can be a
|
|
108
|
+
Range or a single value that is within a Range
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
key : A single value or Range object
|
|
113
|
+
|
|
114
|
+
Raises
|
|
115
|
+
------
|
|
116
|
+
KeyError
|
|
117
|
+
If there is no overlap with the key
|
|
118
|
+
ValueError
|
|
119
|
+
If the key type not compatible with the ranges
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
A set containing all overlapping items
|
|
124
|
+
"""
|
|
125
|
+
if not self.overlaps(key):
|
|
126
|
+
self.__missing__(key)
|
|
127
|
+
elif isinstance(key, Range):
|
|
128
|
+
# If this is a single value
|
|
129
|
+
return_set = set()
|
|
130
|
+
# Get the bounding indices
|
|
131
|
+
ovlap_lower_ind = max(bisect_left(self.lower_cuts, key.lower_cut) - 1, 0)
|
|
132
|
+
ovlap_upper_ind = bisect_left(self.lower_cuts, key.upper_cut)
|
|
133
|
+
for i in range(ovlap_lower_ind, ovlap_upper_ind):
|
|
134
|
+
try:
|
|
135
|
+
# Get intersection of the ranges
|
|
136
|
+
intersect = key.intersection(self.ranges[i])
|
|
137
|
+
if not intersect.is_empty():
|
|
138
|
+
# If overlapping with this range, put its
|
|
139
|
+
# item in the return set
|
|
140
|
+
return_set.add(self.items[i])
|
|
141
|
+
except ValueError:
|
|
142
|
+
# Continue if no overlap with this range
|
|
143
|
+
continue
|
|
144
|
+
# Return the set of items
|
|
145
|
+
return return_set
|
|
146
|
+
else:
|
|
147
|
+
# If this is a single value
|
|
148
|
+
# Get the index of the range containing the value
|
|
149
|
+
lower_ind = max(bisect_left(self.lower_cuts, key) - 1, 0)
|
|
150
|
+
# Return the item at that value
|
|
151
|
+
return set([self.items[lower_ind]])
|
|
152
|
+
|
|
153
|
+
def overlaps(self, val):
|
|
154
|
+
""" Returns true if any of the ranges at least partially overlap
|
|
155
|
+
the given value, which can be a single value or a Range object
|
|
156
|
+
|
|
157
|
+
Parameters
|
|
158
|
+
----------
|
|
159
|
+
val : A single value or a Range object
|
|
160
|
+
|
|
161
|
+
Raises:
|
|
162
|
+
-------
|
|
163
|
+
ValueError
|
|
164
|
+
If the value type not compatible with the ranges
|
|
165
|
+
|
|
166
|
+
Returns
|
|
167
|
+
-------
|
|
168
|
+
true if any of the ranges fully enclose the given value
|
|
169
|
+
"""
|
|
170
|
+
if len(self) == 0: return False
|
|
171
|
+
# Get the index+1 of the highest lower cut <= to the value or its
|
|
172
|
+
# lower cutpoint and check if the value overlaps
|
|
173
|
+
if isinstance(val, Range):
|
|
174
|
+
lower_ind = bisect_left(self.lower_cuts, val.lower_cut) - 1
|
|
175
|
+
upper_ind = bisect_left(self.lower_cuts, val.upper_cut)
|
|
176
|
+
for i in range(lower_ind, upper_ind):
|
|
177
|
+
if val.is_connected(self.ranges[i]):
|
|
178
|
+
if not self.ranges[i].intersection(val).is_empty():
|
|
179
|
+
return True
|
|
180
|
+
return False
|
|
181
|
+
else:
|
|
182
|
+
lower_ind = bisect_left(self.lower_cuts, val) - 1
|
|
183
|
+
return self.ranges[lower_ind].contains(val)
|
|
184
|
+
|
|
185
|
+
def put(self, key, val):
|
|
186
|
+
""" Creates a mapping from a Range to a value. Note that if the
|
|
187
|
+
key Range overlaps any existing ranges, it will replace those
|
|
188
|
+
Range(s) over the intersection
|
|
189
|
+
|
|
190
|
+
Parameters
|
|
191
|
+
----------
|
|
192
|
+
key : Range object
|
|
193
|
+
A Range to serve as a key
|
|
194
|
+
val : value
|
|
195
|
+
Some value that the Range should map to
|
|
196
|
+
|
|
197
|
+
Raises
|
|
198
|
+
------
|
|
199
|
+
TypeError
|
|
200
|
+
If the key is not a Range object
|
|
201
|
+
"""
|
|
202
|
+
if not isinstance(key, Range):
|
|
203
|
+
raise TypeError("key is not a Range")
|
|
204
|
+
elif key.is_empty():
|
|
205
|
+
# Skip if this is an empty range
|
|
206
|
+
return
|
|
207
|
+
# Figure out where to the key/value
|
|
208
|
+
if not self.overlaps(key):
|
|
209
|
+
# If this range is completely on its own, just insert
|
|
210
|
+
insert_ind = bisect_left(self.lower_cuts, key.lower_cut)
|
|
211
|
+
self.ranges.insert(insert_ind, key)
|
|
212
|
+
self.lower_cuts.insert(insert_ind, key.lower_cut)
|
|
213
|
+
self.upper_cuts.insert(insert_ind, key.upper_cut)
|
|
214
|
+
self.items.insert(insert_ind, val)
|
|
215
|
+
return
|
|
216
|
+
else:
|
|
217
|
+
# If this range has some overlap with existing ranges
|
|
218
|
+
ovlap_lower_ind = max(bisect_left(self.lower_cuts, key.lower_cut) - 1, 0)
|
|
219
|
+
ovlap_upper_ind = bisect_left(self.lower_cuts, key.upper_cut)
|
|
220
|
+
# Create queue or indices marked for removal
|
|
221
|
+
remove_ranges = deque()
|
|
222
|
+
# Create queue ranges to add
|
|
223
|
+
add_ranges = deque()
|
|
224
|
+
# Create queue of items to add
|
|
225
|
+
add_items = deque()
|
|
226
|
+
for i in range(ovlap_lower_ind, ovlap_upper_ind):
|
|
227
|
+
try:
|
|
228
|
+
# Get intersection of the ranges
|
|
229
|
+
intersect = key.intersection(self.ranges[i])
|
|
230
|
+
if not intersect.is_empty():
|
|
231
|
+
if intersect == self.ranges[i]:
|
|
232
|
+
# Mark range for removal
|
|
233
|
+
remove_ranges.append(i)
|
|
234
|
+
elif self.lower_cuts[i] == intersect.lower_cut:
|
|
235
|
+
# If equal on left cutpoint, subtract out left
|
|
236
|
+
# part
|
|
237
|
+
self.lower_cuts[i] = intersect.upper_cut
|
|
238
|
+
self.ranges[i] = Range(intersect.upper_cut,
|
|
239
|
+
self.upper_cuts[i])
|
|
240
|
+
elif self.upper_cuts[i] == intersect.upper_cut:
|
|
241
|
+
# If equal on right cutpoint, subtract out
|
|
242
|
+
# right part
|
|
243
|
+
self.upper_cuts[i] = intersect.lower_cut
|
|
244
|
+
self.ranges[i] = Range(self.lower_cuts[i],
|
|
245
|
+
intersect.lower_cut)
|
|
246
|
+
else:
|
|
247
|
+
# If in the middle, split into two parts, putting
|
|
248
|
+
# both in add queue and placing the old range index
|
|
249
|
+
# in the remove queue
|
|
250
|
+
add_ranges.append(Range(self.lower_cuts[i],
|
|
251
|
+
intersect.lower_cut))
|
|
252
|
+
add_ranges.append(Range(intersect.upper_cut,
|
|
253
|
+
self.upper_cuts[i]))
|
|
254
|
+
add_items.append(self.items[i])
|
|
255
|
+
add_items.append(self.items[i])
|
|
256
|
+
remove_ranges.append(i)
|
|
257
|
+
except ValueError:
|
|
258
|
+
# Continue if no overlap with this range
|
|
259
|
+
continue
|
|
260
|
+
# Remove any ranges that are marked for removal
|
|
261
|
+
while len(remove_ranges) > 0:
|
|
262
|
+
remove_ind = remove_ranges.pop()
|
|
263
|
+
self.ranges.pop(remove_ind)
|
|
264
|
+
self.lower_cuts.pop(remove_ind)
|
|
265
|
+
self.upper_cuts.pop(remove_ind)
|
|
266
|
+
self.items.pop(remove_ind)
|
|
267
|
+
add_items.append(val)
|
|
268
|
+
add_ranges.append(key)
|
|
269
|
+
# Use recursive call to place the pairs, which now
|
|
270
|
+
# should not overlap with any other ranges
|
|
271
|
+
while len(add_ranges) > 0:
|
|
272
|
+
self.put(add_ranges.pop(), add_items.pop())
|
|
273
|
+
|
|
274
|
+
def remove(self, a_range):
|
|
275
|
+
""" Removes a range and its value from the range set
|
|
276
|
+
|
|
277
|
+
Parameters
|
|
278
|
+
----------
|
|
279
|
+
a_range : A Range object
|
|
280
|
+
The Range to remove
|
|
281
|
+
|
|
282
|
+
Raises
|
|
283
|
+
------
|
|
284
|
+
ValueError
|
|
285
|
+
If removing range of type not compatible with previously
|
|
286
|
+
added ranges
|
|
287
|
+
TypeError
|
|
288
|
+
If not a Range
|
|
289
|
+
"""
|
|
290
|
+
if not isinstance(a_range, Range):
|
|
291
|
+
raise TypeError("a_range is not a Range")
|
|
292
|
+
elif a_range.is_empty():
|
|
293
|
+
# Skip if this is an empty range
|
|
294
|
+
return
|
|
295
|
+
# Check for compatibility of types if necessary
|
|
296
|
+
if len(self) > 0:
|
|
297
|
+
if not (issubclass(a_range.lower_cut.the_type,
|
|
298
|
+
self.ranges[0].lower_cut.the_type) or \
|
|
299
|
+
issubclass(self.ranges[0].lower_cut.the_type,
|
|
300
|
+
a_range.lower_cut.the_type)):
|
|
301
|
+
raise ValueError("Range not compatible with previously added ranges")
|
|
302
|
+
# Check if the range actually overlaps with the key set
|
|
303
|
+
if not self.overlaps(a_range):
|
|
304
|
+
return
|
|
305
|
+
else:
|
|
306
|
+
# There's some overlap, so deal with that
|
|
307
|
+
# Determine where overlap occurs
|
|
308
|
+
ovlap_lower_ind = max(bisect_left(self.lower_cuts,
|
|
309
|
+
a_range.lower_cut) - 1, 0)
|
|
310
|
+
ovlap_upper_ind = bisect_left(self.lower_cuts, a_range.upper_cut)
|
|
311
|
+
# Create queue of indices marked for removal
|
|
312
|
+
remove_ranges = deque()
|
|
313
|
+
# Create queue of ranges to add
|
|
314
|
+
add_ranges = deque()
|
|
315
|
+
# Create queue of items to add with the add_ranges
|
|
316
|
+
add_items = deque()
|
|
317
|
+
for i in range(ovlap_lower_ind, ovlap_upper_ind):
|
|
318
|
+
try:
|
|
319
|
+
# Get intersection of the ranges
|
|
320
|
+
intersect = a_range.intersection(self.ranges[i])
|
|
321
|
+
if not intersect.is_empty():
|
|
322
|
+
if intersect == self.ranges[i]:
|
|
323
|
+
# Mark range for removal
|
|
324
|
+
remove_ranges.append(i)
|
|
325
|
+
elif self.lower_cuts[i] == intersect.lower_cut:
|
|
326
|
+
# If equal on the left cutpoint, subtract
|
|
327
|
+
# out left part
|
|
328
|
+
self.lower_cuts[i] = intersect.upper_cut
|
|
329
|
+
self.ranges[i] = Range(intersect.upper_cut,
|
|
330
|
+
self.upper_cuts[i])
|
|
331
|
+
elif self.upper_cuts[i] == intersect.upper_cut:
|
|
332
|
+
# If equal on right cutpoint, subtract out
|
|
333
|
+
# right part
|
|
334
|
+
self.upper_cuts[i] = intersect.lower_cut
|
|
335
|
+
self.ranges[i] = Range(self.lower_cuts[i],
|
|
336
|
+
intersect.lower_cut)
|
|
337
|
+
else:
|
|
338
|
+
# If in the middle, split into two parts, putting
|
|
339
|
+
# both in add queue and placing the old range index
|
|
340
|
+
# into the remove queue
|
|
341
|
+
add_ranges.append(Range(self.lower_cuts[i],
|
|
342
|
+
intersect.lower_cut))
|
|
343
|
+
add_items.append(self.items[i])
|
|
344
|
+
add_ranges.append(Range(intersect.upper_cut,
|
|
345
|
+
self.upper_cuts[i]))
|
|
346
|
+
add_items.append(self.items[i])
|
|
347
|
+
remove_ranges.append(i)
|
|
348
|
+
except ValueError:
|
|
349
|
+
# Continue if no overlap with this range
|
|
350
|
+
continue
|
|
351
|
+
# Remove any ranges that are marked for removal
|
|
352
|
+
while len(remove_ranges) > 0:
|
|
353
|
+
remove_ind = remove_ranges.pop()
|
|
354
|
+
self.ranges.pop(remove_ind)
|
|
355
|
+
self.lower_cuts.pop(remove_ind)
|
|
356
|
+
self.upper_cuts.pop(remove_ind)
|
|
357
|
+
self.items.pop(remove_ind)
|
|
358
|
+
# Add any pairs that need to be added
|
|
359
|
+
while len(add_ranges) > 0:
|
|
360
|
+
self.put(add_ranges.pop(), add_items.pop())
|
|
361
|
+
|
|
362
|
+
def which_overlaps(self, val):
|
|
363
|
+
""" Returns which of the Ranges overlap with a single value or
|
|
364
|
+
Range object
|
|
365
|
+
|
|
366
|
+
Parameters
|
|
367
|
+
----------
|
|
368
|
+
val : A single value or a Range object
|
|
369
|
+
|
|
370
|
+
Raises:
|
|
371
|
+
-------
|
|
372
|
+
ValueError
|
|
373
|
+
If the value type not compatible with the ranges
|
|
374
|
+
|
|
375
|
+
Returns
|
|
376
|
+
-------
|
|
377
|
+
set of ranges overlapping with the value
|
|
378
|
+
"""
|
|
379
|
+
if len(self) == 0: return False
|
|
380
|
+
# Get the index+1 of the highest lower cut <= to the value or its
|
|
381
|
+
# lower cutpoint and check if the value overlaps. If it does, add
|
|
382
|
+
# to set
|
|
383
|
+
overlap_set = set()
|
|
384
|
+
if isinstance(val, Range):
|
|
385
|
+
lower_ind = bisect_left(self.lower_cuts, val.lower_cut) - 1
|
|
386
|
+
upper_ind = bisect_left(self.lower_cuts, val.upper_cut)
|
|
387
|
+
for i in range(lower_ind, upper_ind):
|
|
388
|
+
if val.is_connected(self.ranges[i]):
|
|
389
|
+
if not self.ranges[i].intersection(val).is_empty():
|
|
390
|
+
overlap_set.add(self.ranges[i])
|
|
391
|
+
return overlap_set
|
|
392
|
+
else:
|
|
393
|
+
lower_ind = bisect_left(self.lower_cuts, val) - 1
|
|
394
|
+
if self.ranges[lower_ind].contains(val):
|
|
395
|
+
overlap_set.add(self.ranges[lower_ind])
|
|
396
|
+
return overlap_set
|