virtuelle Umgebung teil20b
This commit is contained in:
732
teil20b/lib/python3.11/site-packages/pandas/_libs/sparse.pyx
Normal file
732
teil20b/lib/python3.11/site-packages/pandas/_libs/sparse.pyx
Normal file
@@ -0,0 +1,732 @@
|
||||
cimport cython
|
||||
|
||||
import numpy as np
|
||||
|
||||
cimport numpy as cnp
|
||||
from libc.math cimport (
|
||||
INFINITY as INF,
|
||||
NAN as NaN,
|
||||
)
|
||||
from numpy cimport (
|
||||
float64_t,
|
||||
int8_t,
|
||||
int32_t,
|
||||
int64_t,
|
||||
ndarray,
|
||||
uint8_t,
|
||||
)
|
||||
|
||||
cnp.import_array()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
cdef class SparseIndex:
|
||||
"""
|
||||
Abstract superclass for sparse index types.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
cdef class IntIndex(SparseIndex):
|
||||
"""
|
||||
Object for holding exact integer sparse indexing information
|
||||
|
||||
Parameters
|
||||
----------
|
||||
length : integer
|
||||
indices : array-like
|
||||
Contains integers corresponding to the indices.
|
||||
check_integrity : bool, default=True
|
||||
Check integrity of the input.
|
||||
"""
|
||||
|
||||
cdef readonly:
|
||||
Py_ssize_t length, npoints
|
||||
ndarray indices
|
||||
|
||||
def __init__(self, Py_ssize_t length, indices, bint check_integrity=True):
|
||||
self.length = length
|
||||
self.indices = np.ascontiguousarray(indices, dtype=np.int32)
|
||||
self.npoints = len(self.indices)
|
||||
|
||||
if check_integrity:
|
||||
self.check_integrity()
|
||||
|
||||
def __reduce__(self):
|
||||
args = (self.length, self.indices)
|
||||
return IntIndex, args
|
||||
|
||||
def __repr__(self) -> str:
|
||||
output = "IntIndex\n"
|
||||
output += f"Indices: {repr(self.indices)}\n"
|
||||
return output
|
||||
|
||||
@property
|
||||
def nbytes(self) -> int:
|
||||
return self.indices.nbytes
|
||||
|
||||
cdef check_integrity(self):
|
||||
"""
|
||||
Checks the following:
|
||||
|
||||
- Indices are strictly ascending
|
||||
- Number of indices is at most self.length
|
||||
- Indices are at least 0 and at most the total length less one
|
||||
|
||||
A ValueError is raised if any of these conditions is violated.
|
||||
"""
|
||||
|
||||
if self.npoints > self.length:
|
||||
raise ValueError(
|
||||
f"Too many indices. Expected {self.length} but found {self.npoints}"
|
||||
)
|
||||
|
||||
# Indices are vacuously ordered and non-negative
|
||||
# if the sequence of indices is empty.
|
||||
if self.npoints == 0:
|
||||
return
|
||||
|
||||
if self.indices.min() < 0:
|
||||
raise ValueError("No index can be less than zero")
|
||||
|
||||
if self.indices.max() >= self.length:
|
||||
raise ValueError("All indices must be less than the length")
|
||||
|
||||
monotonic = np.all(self.indices[:-1] < self.indices[1:])
|
||||
if not monotonic:
|
||||
raise ValueError("Indices must be strictly increasing")
|
||||
|
||||
def equals(self, other: object) -> bool:
|
||||
if not isinstance(other, IntIndex):
|
||||
return False
|
||||
|
||||
if self is other:
|
||||
return True
|
||||
|
||||
same_length = self.length == other.length
|
||||
same_indices = np.array_equal(self.indices, other.indices)
|
||||
return same_length and same_indices
|
||||
|
||||
@property
|
||||
def ngaps(self) -> int:
|
||||
return self.length - self.npoints
|
||||
|
||||
cpdef to_int_index(self):
|
||||
return self
|
||||
|
||||
def to_block_index(self):
|
||||
locs, lens = get_blocks(self.indices)
|
||||
return BlockIndex(self.length, locs, lens)
|
||||
|
||||
cpdef IntIndex intersect(self, SparseIndex y_):
|
||||
cdef:
|
||||
Py_ssize_t xi, yi = 0, result_indexer = 0
|
||||
int32_t xind
|
||||
ndarray[int32_t, ndim=1] xindices, yindices, new_indices
|
||||
IntIndex y
|
||||
|
||||
# if is one already, returns self
|
||||
y = y_.to_int_index()
|
||||
|
||||
if self.length != y.length:
|
||||
raise Exception("Indices must reference same underlying length")
|
||||
|
||||
xindices = self.indices
|
||||
yindices = y.indices
|
||||
new_indices = np.empty(min(
|
||||
len(xindices), len(yindices)), dtype=np.int32)
|
||||
|
||||
for xi in range(self.npoints):
|
||||
xind = xindices[xi]
|
||||
|
||||
while yi < y.npoints and yindices[yi] < xind:
|
||||
yi += 1
|
||||
|
||||
if yi >= y.npoints:
|
||||
break
|
||||
|
||||
# TODO: would a two-pass algorithm be faster?
|
||||
if yindices[yi] == xind:
|
||||
new_indices[result_indexer] = xind
|
||||
result_indexer += 1
|
||||
|
||||
new_indices = new_indices[:result_indexer]
|
||||
return IntIndex(self.length, new_indices)
|
||||
|
||||
cpdef IntIndex make_union(self, SparseIndex y_):
|
||||
|
||||
cdef:
|
||||
ndarray[int32_t, ndim=1] new_indices
|
||||
IntIndex y
|
||||
|
||||
# if is one already, returns self
|
||||
y = y_.to_int_index()
|
||||
|
||||
if self.length != y.length:
|
||||
raise ValueError("Indices must reference same underlying length")
|
||||
|
||||
new_indices = np.union1d(self.indices, y.indices)
|
||||
return IntIndex(self.length, new_indices)
|
||||
|
||||
@cython.wraparound(False)
|
||||
cpdef int32_t lookup(self, Py_ssize_t index):
|
||||
"""
|
||||
Return the internal location if value exists on given index.
|
||||
Return -1 otherwise.
|
||||
"""
|
||||
cdef:
|
||||
int32_t res
|
||||
ndarray[int32_t, ndim=1] inds
|
||||
|
||||
inds = self.indices
|
||||
if self.npoints == 0:
|
||||
return -1
|
||||
elif index < 0 or self.length <= index:
|
||||
return -1
|
||||
|
||||
res = inds.searchsorted(index)
|
||||
if res == self.npoints:
|
||||
return -1
|
||||
elif inds[res] == index:
|
||||
return res
|
||||
else:
|
||||
return -1
|
||||
|
||||
@cython.wraparound(False)
|
||||
cpdef ndarray[int32_t] lookup_array(self, ndarray[int32_t, ndim=1] indexer):
|
||||
"""
|
||||
Vectorized lookup, returns ndarray[int32_t]
|
||||
"""
|
||||
cdef:
|
||||
Py_ssize_t n
|
||||
ndarray[int32_t, ndim=1] inds
|
||||
ndarray[uint8_t, ndim=1, cast=True] mask
|
||||
ndarray[int32_t, ndim=1] masked
|
||||
ndarray[int32_t, ndim=1] res
|
||||
ndarray[int32_t, ndim=1] results
|
||||
|
||||
n = len(indexer)
|
||||
results = np.empty(n, dtype=np.int32)
|
||||
results[:] = -1
|
||||
|
||||
if self.npoints == 0:
|
||||
return results
|
||||
|
||||
inds = self.indices
|
||||
mask = (inds[0] <= indexer) & (indexer <= inds[len(inds) - 1])
|
||||
|
||||
masked = indexer[mask]
|
||||
res = inds.searchsorted(masked).astype(np.int32)
|
||||
|
||||
res[inds[res] != masked] = -1
|
||||
results[mask] = res
|
||||
return results
|
||||
|
||||
|
||||
cpdef get_blocks(ndarray[int32_t, ndim=1] indices):
|
||||
cdef:
|
||||
Py_ssize_t i, npoints, result_indexer = 0
|
||||
int32_t block, length = 1, cur, prev
|
||||
ndarray[int32_t, ndim=1] locs, lens
|
||||
|
||||
npoints = len(indices)
|
||||
|
||||
# just handle the special empty case separately
|
||||
if npoints == 0:
|
||||
return np.array([], dtype=np.int32), np.array([], dtype=np.int32)
|
||||
|
||||
# block size can't be longer than npoints
|
||||
locs = np.empty(npoints, dtype=np.int32)
|
||||
lens = np.empty(npoints, dtype=np.int32)
|
||||
|
||||
# TODO: two-pass algorithm faster?
|
||||
prev = block = indices[0]
|
||||
for i in range(1, npoints):
|
||||
cur = indices[i]
|
||||
if cur - prev > 1:
|
||||
# new block
|
||||
locs[result_indexer] = block
|
||||
lens[result_indexer] = length
|
||||
block = cur
|
||||
length = 1
|
||||
result_indexer += 1
|
||||
else:
|
||||
# same block, increment length
|
||||
length += 1
|
||||
|
||||
prev = cur
|
||||
|
||||
locs[result_indexer] = block
|
||||
lens[result_indexer] = length
|
||||
result_indexer += 1
|
||||
locs = locs[:result_indexer]
|
||||
lens = lens[:result_indexer]
|
||||
return locs, lens
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# BlockIndex
|
||||
|
||||
cdef class BlockIndex(SparseIndex):
|
||||
"""
|
||||
Object for holding block-based sparse indexing information
|
||||
|
||||
Parameters
|
||||
----------
|
||||
"""
|
||||
cdef readonly:
|
||||
int32_t nblocks, npoints, length
|
||||
ndarray blocs, blengths
|
||||
|
||||
cdef:
|
||||
object __weakref__ # need to be picklable
|
||||
int32_t *locbuf
|
||||
int32_t *lenbuf
|
||||
|
||||
def __init__(self, length, blocs, blengths):
|
||||
|
||||
self.blocs = np.ascontiguousarray(blocs, dtype=np.int32)
|
||||
self.blengths = np.ascontiguousarray(blengths, dtype=np.int32)
|
||||
|
||||
# in case we need
|
||||
self.locbuf = <int32_t*>self.blocs.data
|
||||
self.lenbuf = <int32_t*>self.blengths.data
|
||||
|
||||
self.length = length
|
||||
self.nblocks = np.int32(len(self.blocs))
|
||||
self.npoints = self.blengths.sum()
|
||||
|
||||
self.check_integrity()
|
||||
|
||||
def __reduce__(self):
|
||||
args = (self.length, self.blocs, self.blengths)
|
||||
return BlockIndex, args
|
||||
|
||||
def __repr__(self) -> str:
|
||||
output = "BlockIndex\n"
|
||||
output += f"Block locations: {repr(self.blocs)}\n"
|
||||
output += f"Block lengths: {repr(self.blengths)}"
|
||||
|
||||
return output
|
||||
|
||||
@property
|
||||
def nbytes(self) -> int:
|
||||
return self.blocs.nbytes + self.blengths.nbytes
|
||||
|
||||
@property
|
||||
def ngaps(self) -> int:
|
||||
return self.length - self.npoints
|
||||
|
||||
cdef check_integrity(self):
|
||||
"""
|
||||
Check:
|
||||
- Locations are in ascending order
|
||||
- No overlapping blocks
|
||||
- Blocks to not start after end of index, nor extend beyond end
|
||||
"""
|
||||
cdef:
|
||||
Py_ssize_t i
|
||||
ndarray[int32_t, ndim=1] blocs, blengths
|
||||
|
||||
blocs = self.blocs
|
||||
blengths = self.blengths
|
||||
|
||||
if len(blocs) != len(blengths):
|
||||
raise ValueError("block bound arrays must be same length")
|
||||
|
||||
for i in range(self.nblocks):
|
||||
if i > 0:
|
||||
if blocs[i] <= blocs[i - 1]:
|
||||
raise ValueError("Locations not in ascending order")
|
||||
|
||||
if i < self.nblocks - 1:
|
||||
if blocs[i] + blengths[i] > blocs[i + 1]:
|
||||
raise ValueError(f"Block {i} overlaps")
|
||||
else:
|
||||
if blocs[i] + blengths[i] > self.length:
|
||||
raise ValueError(f"Block {i} extends beyond end")
|
||||
|
||||
# no zero-length blocks
|
||||
if blengths[i] == 0:
|
||||
raise ValueError(f"Zero-length block {i}")
|
||||
|
||||
def equals(self, other: object) -> bool:
|
||||
if not isinstance(other, BlockIndex):
|
||||
return False
|
||||
|
||||
if self is other:
|
||||
return True
|
||||
|
||||
same_length = self.length == other.length
|
||||
same_blocks = (np.array_equal(self.blocs, other.blocs) and
|
||||
np.array_equal(self.blengths, other.blengths))
|
||||
return same_length and same_blocks
|
||||
|
||||
def to_block_index(self):
|
||||
return self
|
||||
|
||||
cpdef to_int_index(self):
|
||||
cdef:
|
||||
int32_t i = 0, j, b
|
||||
int32_t offset
|
||||
ndarray[int32_t, ndim=1] indices
|
||||
|
||||
indices = np.empty(self.npoints, dtype=np.int32)
|
||||
|
||||
for b in range(self.nblocks):
|
||||
offset = self.locbuf[b]
|
||||
|
||||
for j in range(self.lenbuf[b]):
|
||||
indices[i] = offset + j
|
||||
i += 1
|
||||
|
||||
return IntIndex(self.length, indices)
|
||||
|
||||
@property
|
||||
def indices(self):
|
||||
return self.to_int_index().indices
|
||||
|
||||
cpdef BlockIndex intersect(self, SparseIndex other):
|
||||
"""
|
||||
Intersect two BlockIndex objects
|
||||
|
||||
Returns
|
||||
-------
|
||||
BlockIndex
|
||||
"""
|
||||
cdef:
|
||||
BlockIndex y
|
||||
ndarray[int32_t, ndim=1] xloc, xlen, yloc, ylen, out_bloc, out_blen
|
||||
Py_ssize_t xi = 0, yi = 0, max_len, result_indexer = 0
|
||||
int32_t cur_loc, cur_length, diff
|
||||
|
||||
y = other.to_block_index()
|
||||
|
||||
if self.length != y.length:
|
||||
raise Exception("Indices must reference same underlying length")
|
||||
|
||||
xloc = self.blocs
|
||||
xlen = self.blengths
|
||||
yloc = y.blocs
|
||||
ylen = y.blengths
|
||||
|
||||
# block may be split, but can't exceed original len / 2 + 1
|
||||
max_len = min(self.length, y.length) // 2 + 1
|
||||
out_bloc = np.empty(max_len, dtype=np.int32)
|
||||
out_blen = np.empty(max_len, dtype=np.int32)
|
||||
|
||||
while True:
|
||||
# we are done (or possibly never began)
|
||||
if xi >= self.nblocks or yi >= y.nblocks:
|
||||
break
|
||||
|
||||
# completely symmetric...would like to avoid code dup but oh well
|
||||
if xloc[xi] >= yloc[yi]:
|
||||
cur_loc = xloc[xi]
|
||||
diff = xloc[xi] - yloc[yi]
|
||||
|
||||
if ylen[yi] <= diff:
|
||||
# have to skip this block
|
||||
yi += 1
|
||||
continue
|
||||
|
||||
if ylen[yi] - diff < xlen[xi]:
|
||||
# take end of y block, move onward
|
||||
cur_length = ylen[yi] - diff
|
||||
yi += 1
|
||||
else:
|
||||
# take end of x block
|
||||
cur_length = xlen[xi]
|
||||
xi += 1
|
||||
|
||||
else: # xloc[xi] < yloc[yi]
|
||||
cur_loc = yloc[yi]
|
||||
diff = yloc[yi] - xloc[xi]
|
||||
|
||||
if xlen[xi] <= diff:
|
||||
# have to skip this block
|
||||
xi += 1
|
||||
continue
|
||||
|
||||
if xlen[xi] - diff < ylen[yi]:
|
||||
# take end of x block, move onward
|
||||
cur_length = xlen[xi] - diff
|
||||
xi += 1
|
||||
else:
|
||||
# take end of y block
|
||||
cur_length = ylen[yi]
|
||||
yi += 1
|
||||
|
||||
out_bloc[result_indexer] = cur_loc
|
||||
out_blen[result_indexer] = cur_length
|
||||
result_indexer += 1
|
||||
|
||||
out_bloc = out_bloc[:result_indexer]
|
||||
out_blen = out_blen[:result_indexer]
|
||||
|
||||
return BlockIndex(self.length, out_bloc, out_blen)
|
||||
|
||||
cpdef BlockIndex make_union(self, SparseIndex y):
|
||||
"""
|
||||
Combine together two BlockIndex objects, accepting indices if contained
|
||||
in one or the other
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other : SparseIndex
|
||||
|
||||
Notes
|
||||
-----
|
||||
union is a protected keyword in Cython, hence make_union
|
||||
|
||||
Returns
|
||||
-------
|
||||
BlockIndex
|
||||
"""
|
||||
return BlockUnion(self, y.to_block_index()).result
|
||||
|
||||
cpdef Py_ssize_t lookup(self, Py_ssize_t index):
|
||||
"""
|
||||
Return the internal location if value exists on given index.
|
||||
Return -1 otherwise.
|
||||
"""
|
||||
cdef:
|
||||
Py_ssize_t i, cum_len
|
||||
ndarray[int32_t, ndim=1] locs, lens
|
||||
|
||||
locs = self.blocs
|
||||
lens = self.blengths
|
||||
|
||||
if self.nblocks == 0:
|
||||
return -1
|
||||
elif index < locs[0]:
|
||||
return -1
|
||||
|
||||
cum_len = 0
|
||||
for i in range(self.nblocks):
|
||||
if index >= locs[i] and index < locs[i] + lens[i]:
|
||||
return cum_len + index - locs[i]
|
||||
cum_len += lens[i]
|
||||
|
||||
return -1
|
||||
|
||||
@cython.wraparound(False)
|
||||
cpdef ndarray[int32_t] lookup_array(self, ndarray[int32_t, ndim=1] indexer):
|
||||
"""
|
||||
Vectorized lookup, returns ndarray[int32_t]
|
||||
"""
|
||||
cdef:
|
||||
Py_ssize_t n, i, j, ind_val
|
||||
ndarray[int32_t, ndim=1] locs, lens
|
||||
ndarray[int32_t, ndim=1] results
|
||||
|
||||
locs = self.blocs
|
||||
lens = self.blengths
|
||||
|
||||
n = len(indexer)
|
||||
results = np.empty(n, dtype=np.int32)
|
||||
results[:] = -1
|
||||
|
||||
if self.npoints == 0:
|
||||
return results
|
||||
|
||||
for i in range(n):
|
||||
ind_val = indexer[i]
|
||||
if not (ind_val < 0 or self.length <= ind_val):
|
||||
cum_len = 0
|
||||
for j in range(self.nblocks):
|
||||
if ind_val >= locs[j] and ind_val < locs[j] + lens[j]:
|
||||
results[i] = cum_len + ind_val - locs[j]
|
||||
cum_len += lens[j]
|
||||
return results
|
||||
|
||||
|
||||
@cython.internal
|
||||
cdef class BlockMerge:
|
||||
"""
|
||||
Object-oriented approach makes sharing state between recursive functions a
|
||||
lot easier and reduces code duplication
|
||||
"""
|
||||
cdef:
|
||||
BlockIndex x, y, result
|
||||
ndarray xstart, xlen, xend, ystart, ylen, yend
|
||||
int32_t xi, yi # block indices
|
||||
|
||||
def __init__(self, BlockIndex x, BlockIndex y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
if x.length != y.length:
|
||||
raise Exception("Indices must reference same underlying length")
|
||||
|
||||
self.xstart = self.x.blocs
|
||||
self.ystart = self.y.blocs
|
||||
|
||||
self.xend = self.x.blocs + self.x.blengths
|
||||
self.yend = self.y.blocs + self.y.blengths
|
||||
|
||||
# self.xlen = self.x.blengths
|
||||
# self.ylen = self.y.blengths
|
||||
|
||||
self.xi = 0
|
||||
self.yi = 0
|
||||
|
||||
self.result = self._make_merged_blocks()
|
||||
|
||||
cdef _make_merged_blocks(self):
|
||||
raise NotImplementedError
|
||||
|
||||
cdef _set_current_indices(self, int32_t xi, int32_t yi, bint mode):
|
||||
if mode == 0:
|
||||
self.xi = xi
|
||||
self.yi = yi
|
||||
else:
|
||||
self.xi = yi
|
||||
self.yi = xi
|
||||
|
||||
|
||||
@cython.internal
|
||||
cdef class BlockUnion(BlockMerge):
|
||||
"""
|
||||
Object-oriented approach makes sharing state between recursive functions a
|
||||
lot easier and reduces code duplication
|
||||
"""
|
||||
|
||||
cdef _make_merged_blocks(self):
|
||||
cdef:
|
||||
ndarray[int32_t, ndim=1] xstart, xend, ystart
|
||||
ndarray[int32_t, ndim=1] yend, out_bloc, out_blen
|
||||
int32_t nstart, nend
|
||||
Py_ssize_t max_len, result_indexer = 0
|
||||
|
||||
xstart = self.xstart
|
||||
xend = self.xend
|
||||
ystart = self.ystart
|
||||
yend = self.yend
|
||||
|
||||
max_len = min(self.x.length, self.y.length) // 2 + 1
|
||||
out_bloc = np.empty(max_len, dtype=np.int32)
|
||||
out_blen = np.empty(max_len, dtype=np.int32)
|
||||
|
||||
while True:
|
||||
# we are done (or possibly never began)
|
||||
if self.xi >= self.x.nblocks and self.yi >= self.y.nblocks:
|
||||
break
|
||||
elif self.yi >= self.y.nblocks:
|
||||
# through with y, just pass through x blocks
|
||||
nstart = xstart[self.xi]
|
||||
nend = xend[self.xi]
|
||||
self.xi += 1
|
||||
elif self.xi >= self.x.nblocks:
|
||||
# through with x, just pass through y blocks
|
||||
nstart = ystart[self.yi]
|
||||
nend = yend[self.yi]
|
||||
self.yi += 1
|
||||
else:
|
||||
# find end of new block
|
||||
if xstart[self.xi] < ystart[self.yi]:
|
||||
nstart = xstart[self.xi]
|
||||
nend = self._find_next_block_end(0)
|
||||
else:
|
||||
nstart = ystart[self.yi]
|
||||
nend = self._find_next_block_end(1)
|
||||
|
||||
out_bloc[result_indexer] = nstart
|
||||
out_blen[result_indexer] = nend - nstart
|
||||
result_indexer += 1
|
||||
|
||||
out_bloc = out_bloc[:result_indexer]
|
||||
out_blen = out_blen[:result_indexer]
|
||||
|
||||
return BlockIndex(self.x.length, out_bloc, out_blen)
|
||||
|
||||
cdef int32_t _find_next_block_end(self, bint mode) except -1:
|
||||
"""
|
||||
Wow, this got complicated in a hurry
|
||||
|
||||
mode 0: block started in index x
|
||||
mode 1: block started in index y
|
||||
"""
|
||||
cdef:
|
||||
ndarray[int32_t, ndim=1] xstart, xend, ystart, yend
|
||||
int32_t xi, yi, ynblocks, nend
|
||||
|
||||
if mode != 0 and mode != 1:
|
||||
raise Exception("Mode must be 0 or 1")
|
||||
|
||||
# so symmetric code will work
|
||||
if mode == 0:
|
||||
xstart = self.xstart
|
||||
xend = self.xend
|
||||
xi = self.xi
|
||||
|
||||
ystart = self.ystart
|
||||
yend = self.yend
|
||||
yi = self.yi
|
||||
ynblocks = self.y.nblocks
|
||||
else:
|
||||
xstart = self.ystart
|
||||
xend = self.yend
|
||||
xi = self.yi
|
||||
|
||||
ystart = self.xstart
|
||||
yend = self.xend
|
||||
yi = self.xi
|
||||
ynblocks = self.x.nblocks
|
||||
|
||||
nend = xend[xi]
|
||||
|
||||
# done with y?
|
||||
if yi == ynblocks:
|
||||
self._set_current_indices(xi + 1, yi, mode)
|
||||
return nend
|
||||
elif nend < ystart[yi]:
|
||||
# block ends before y block
|
||||
self._set_current_indices(xi + 1, yi, mode)
|
||||
return nend
|
||||
else:
|
||||
while yi < ynblocks and nend > yend[yi]:
|
||||
yi += 1
|
||||
|
||||
self._set_current_indices(xi + 1, yi, mode)
|
||||
|
||||
if yi == ynblocks:
|
||||
return nend
|
||||
|
||||
if nend < ystart[yi]:
|
||||
# we're done, return the block end
|
||||
return nend
|
||||
else:
|
||||
# merge blocks, continue searching
|
||||
# this also catches the case where blocks
|
||||
return self._find_next_block_end(1 - mode)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Sparse arithmetic
|
||||
|
||||
include "sparse_op_helper.pxi"
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# SparseArray mask create operations
|
||||
|
||||
def make_mask_object_ndarray(ndarray[object, ndim=1] arr, object fill_value):
|
||||
cdef:
|
||||
object value
|
||||
Py_ssize_t i
|
||||
Py_ssize_t new_length = len(arr)
|
||||
ndarray[int8_t, ndim=1] mask
|
||||
|
||||
mask = np.ones(new_length, dtype=np.int8)
|
||||
|
||||
for i in range(new_length):
|
||||
value = arr[i]
|
||||
if value == fill_value and type(value) is type(fill_value):
|
||||
mask[i] = 0
|
||||
|
||||
return mask.view(dtype=bool)
|
Reference in New Issue
Block a user