Skip to content

Commit 23b573c

Browse files
author
Gertjan van Zwieten
committed
Speed improvements (#915)
2 parents 7a12f40 + 30e1fc1 commit 23b573c

File tree

2 files changed

+16
-8
lines changed

2 files changed

+16
-8
lines changed

nutils/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
'Numerical Utilities for Finite Element Analysis'
22

3-
__version__ = version = '9a63'
3+
__version__ = version = '9a64'
44
version_name = 'jook-sing'

nutils/evaluable.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,14 @@ def assparse(self):
601601
value_parts.append(_flat(values))
602602
index_parts.append(_flat(flatindex))
603603
if value_parts:
604-
flatindex, inverse = unique(concatenate(index_parts), return_inverse=True)
605-
values = Inflate(concatenate(value_parts), inverse, flatindex.shape[0])
604+
# Guard the concatenation to avoid expensive swap-inflate-take
605+
# operations due to take in unique
606+
flatindex, inverse = unique(Guard(concatenate(index_parts)), return_inverse=True)
607+
# The next three lines are equivalent to values = Inflate(concatenate(value_parts), inverse, flatindex.shape[0])
608+
lengths = [arg.shape[0] for arg in value_parts]
609+
slices = [Range(length) + offset for length, offset in zip(lengths, util.cumsum(lengths))]
610+
values = util.sum(Inflate(f, Take(inverse, s), flatindex.shape[0]) for f, s in zip(value_parts, slices))
611+
# Unravel indices
606612
indices = [flatindex]
607613
for n in reversed(self.shape[1:]):
608614
indices[:1] = divmod(indices[0], n)
@@ -3475,7 +3481,7 @@ def _unravel(self, axis, shape):
34753481
return Inflate(unravel(self.func, axis, shape), self.dofmap, self.length)
34763482

34773483
def _sign(self):
3478-
if isinstance(self.dofmap, Constant) and _isunique(self.dofmap.value):
3484+
if isinstance(self.dofmap, Constant) and _ismonotonic(numpy.sort(self.dofmap.value, axis=None)):
34793485
return Inflate(Sign(self.func), self.dofmap, self.length)
34803486

34813487
@cached_property
@@ -3521,8 +3527,8 @@ def __iter__(self):
35213527

35223528
@staticmethod
35233529
def evalf(inflateidx, takeidx):
3524-
uniqueinflate = _isunique(inflateidx)
3525-
uniquetake = _isunique(takeidx)
3530+
uniqueinflate = _ismonotonic(numpy.sort(inflateidx, axis=None))
3531+
uniquetake = _ismonotonic(numpy.sort(takeidx, axis=None))
35263532
unique = uniqueinflate and uniquetake
35273533
# If both indices are unique (i.e. they do not contain duplicates) then the
35283534
# take and inflate operations can simply be restricted to the intersection,
@@ -5916,8 +5922,10 @@ def _inflate_scalar(arg, shape):
59165922
return arg
59175923

59185924

5919-
def _isunique(array):
5920-
return numpy.unique(array).size == array.size
5925+
def _ismonotonic(indices):
5926+
'check if indices are strict monotonic ascending'
5927+
assert indices.ndim == 1 and indices.dtype == int
5928+
return len(indices) <= 1 or indices[-1] - indices[0] >= len(indices) - 1 and (indices[1:] > indices[:-1]).all()
59215929

59225930

59235931
def _make_loop_ids_unique(funcs: typing.Tuple[Evaluable, ...]) -> typing.Tuple[Evaluable, ...]:

0 commit comments

Comments
 (0)