Skip to content

Commit

Permalink
Remove apply_annotation from transform module (#758)
Browse files Browse the repository at this point in the history
  • Loading branch information
gertjanvanzwieten committed Jan 10, 2023
2 parents 49d1227 + e3179cd commit ff21621
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 43 deletions.
4 changes: 2 additions & 2 deletions nutils/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def simplex_transforms(self):
first unit vector to the second, the second to the third, and so on.
'''

return tuple(transform.Square((vertices[1:] - vertices[0]).T, vertices[0]) for vertices in self.vertices[self.simplices])
return tuple(transform.simplex(vertices) for vertices in self.vertices[self.simplices])

def inside(self, point, eps=0):
for strans in self.simplex_transforms:
Expand Down Expand Up @@ -1059,7 +1059,7 @@ def __init__(self, baseref, edge_refs: tuple, midpoint: types.arraydata):
self._midpoint = midpoint
self.edge_vertices = tuple(edge_vertices)
self.edge_refs = edge_refs + (getsimplex(baseref.ndims-1),) * len(orientation)
self.edge_transforms = baseref.edge_transforms + tuple(transform.Updim((vertices[1:] - vertices[0]).T, vertices[0], isflipped)
self.edge_transforms = baseref.edge_transforms + tuple(transform.simplex(vertices, isflipped)
for vertices, isflipped in zip(self.vertices[numpy.array(edge_vertices[baseref.nedges:])], orientation))

super().__init__(baseref.ndims)
Expand Down
2 changes: 1 addition & 1 deletion nutils/mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ def simplex(nodes, cnodes, coords, tags, btags, ptags, name='simplex', *, space=

pgroups = {}
if ptags:
ptrans = [transform.Point(offset) for offset in numpy.eye(ndims+1)[:, 1:]]
ptrans = [transform.Point(types.arraydata(offset)) for offset in numpy.eye(ndims+1)[:, 1:]]
pmap = {inode: numpy.array(numpy.equal(nodes, inode).nonzero()).T for inode in set.union(*map(set, ptags.values()))}
for pname, inodes in ptags.items():
ptransforms = transformseq.PlainTransforms([topo.transforms[ielem] + (ptrans[ivertex],) for inode in inodes for ielem, ivertex in pmap[inode]], ndims, 0)
Expand Down
103 changes: 68 additions & 35 deletions nutils/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""

from typing import Tuple, Dict
from numbers import Integral
from . import cache, numeric, _util as util, types
import numpy
import collections
Expand Down Expand Up @@ -85,8 +86,9 @@ class TransformItem(types.Singleton):

__slots__ = 'todims', 'fromdims'

@types.apply_annotations
def __init__(self, todims, fromdims: int):
def __init__(self, todims: Integral, fromdims: Integral):
assert isinstance(todims, Integral), f'todims={todims!r}'
assert isinstance(fromdims, Integral), f'fromdims={fromdims!r}'
super().__init__()
self.todims = todims
self.fromdims = fromdims
Expand Down Expand Up @@ -118,14 +120,16 @@ class Matrix(TransformItem):

__slots__ = 'linear', 'offset'

@types.apply_annotations
def __init__(self, linear: types.arraydata, offset: types.arraydata):
assert linear.ndim == 2 and linear.dtype == float
assert offset.ndim == 1 and offset.dtype == float
assert offset.shape[0] == linear.shape[0]
def __init__(self, linear, offset):
# we don't worry about mutability here as the meta class prevents
# direct instantiation from mutable arguments, and derived classes are
# trusted to not mutate arguments after construction.
self.linear = numpy.asarray(linear)
self.offset = numpy.asarray(offset)
super().__init__(linear.shape[0], linear.shape[1])
assert self.linear.ndim == 2 and self.linear.dtype == float
assert self.offset.ndim == 1 and self.offset.dtype == float
assert self.offset.shape[0] == self.linear.shape[0]
super().__init__(*self.linear.shape)

@types.lru_cache
def apply(self, points):
Expand All @@ -134,8 +138,8 @@ def apply(self, points):

def __mul__(self, other):
assert isinstance(other, Matrix) and self.fromdims == other.todims
linear = numpy.dot(self.linear, other.linear)
offset = self.apply(other.offset)
linear = types.arraydata(self.linear @ other.linear)
offset = types.arraydata(self.apply(other.offset))
return Square(linear, offset) if self.todims == other.fromdims \
else Updim(linear, offset, self.isflipped ^ other.isflipped) if self.todims == other.fromdims+1 \
else Matrix(linear, offset)
Expand All @@ -160,11 +164,10 @@ class Square(Matrix):
__slots__ = '_transform_matrix',
__cache__ = 'det',

@types.apply_annotations
def __init__(self, linear: types.arraydata, offset: types.arraydata):
assert linear.shape[0] == linear.shape[1]
def __init__(self, linear, offset):
self._transform_matrix = {}
super().__init__(linear, offset)
assert self.fromdims == self.todims

@types.lru_cache
def invapply(self, points):
Expand All @@ -176,7 +179,7 @@ def det(self):

@property
def isflipped(self):
return self.fromdims > 0 and self.det < 0
return bool(self.det < 0)

@types.lru_cache
def transform_poly(self, coeffs):
Expand Down Expand Up @@ -217,7 +220,8 @@ class Identity(Square):

det = 1.

def __init__(self, ndims):
def __init__(self, ndims: Integral):
assert isinstance(ndims, Integral) and ndims >= 0, f'ndims={ndims!r}'
super().__init__(numpy.eye(ndims), numpy.zeros(ndims))

def apply(self, points):
Expand All @@ -240,8 +244,9 @@ class Index(Identity):

__slots__ = 'index'

@types.apply_annotations
def __init__(self, ndims: int, index: int):
def __init__(self, ndims: Integral, index: Integral):
assert isinstance(ndims, Integral) and ndims >= 0, f'ndims={ndims!r}'
assert isinstance(index, Integral), f'index={index!r}'
self.index = index
super().__init__(ndims)

Expand All @@ -260,14 +265,15 @@ class Updim(Matrix):
The offset :math:`b`.
'''

__slots__ = 'isflipped',
__slots__ = 'isflipped', '_affine'
__cache__ = 'ext',

@types.apply_annotations
def __init__(self, linear: types.arraydata, offset: types.arraydata, isflipped: bool):
assert linear.shape[0] == linear.shape[1] + 1
def __init__(self, linear, offset, isflipped: bool):
assert isinstance(isflipped, bool), f'isflipped={isflipped!r}'
self._affine = linear, offset
self.isflipped = isflipped
super().__init__(linear, offset)
assert self.todims == self.fromdims + 1

@property
def ext(self):
Expand All @@ -276,7 +282,8 @@ def ext(self):

@property
def flipped(self):
return Updim(self.linear, self.offset, not self.isflipped)
assert type(self) == Updim
return Updim(*self._affine, not self.isflipped)

def swapdown(self, other):
if isinstance(other, TensorChild):
Expand All @@ -294,17 +301,20 @@ class SimplexEdge(Updim):
((0, 3), (1, 3), (2, 3), (4, 3)),
)

@types.apply_annotations
def __init__(self, ndims: types.strictint, iedge: types.strictint, inverted: bool = False):
def __init__(self, ndims: Integral, iedge: Integral, inverted: bool = False):
assert isinstance(ndims, Integral) and ndims >= 0, f'ndims={ndims!r}'
assert isinstance(iedge, Integral) and iedge >= 0, f'iedge={iedge!r}'
assert isinstance(inverted, bool), f'inverted={inverted!r}'
assert ndims >= iedge >= 0
self.iedge = iedge
self.inverted = inverted
vertices = numpy.concatenate([numpy.zeros(ndims)[_, :], numpy.eye(ndims)], axis=0)
coords = vertices[list(range(iedge))+list(range(iedge+1, ndims+1))]
super().__init__((coords[1:]-coords[0]).T, coords[0], inverted ^ (iedge % 2))
super().__init__((coords[1:]-coords[0]).T, coords[0], inverted ^ bool(iedge % 2))

@property
def flipped(self):
assert type(self) == SimplexEdge
return SimplexEdge(self.todims, self.iedge, not self.inverted)

def swapup(self, other):
Expand All @@ -330,7 +340,9 @@ class SimplexChild(Square):

__slots__ = 'ichild',

def __init__(self, ndims, ichild):
def __init__(self, ndims: Integral, ichild: Integral):
assert isinstance(ndims, Integral) and ndims >= 0, f'ndims={ndims!r}'
assert isinstance(ichild, Integral) and ichild >= 0, f'ichild={ichild!r}'
self.ichild = ichild
if ichild <= ndims:
linear = numpy.eye(ndims) * .5
Expand Down Expand Up @@ -359,8 +371,10 @@ class ScaledUpdim(Updim):

__slots__ = 'trans1', 'trans2'

def __init__(self, trans1, trans2):
assert trans1.todims == trans1.fromdims == trans2.todims == trans2.fromdims + 1
def __init__(self, trans1: Square, trans2: Updim):
assert isinstance(trans1, Square), f'trans1={trans1!r}'
assert isinstance(trans2, Updim), f'trans2={trans2!r}'
assert trans1.fromdims == trans2.todims
self.trans1 = trans1
self.trans2 = trans2
super().__init__(numpy.dot(trans1.linear, trans2.linear), trans1.apply(trans2.offset), trans1.isflipped ^ trans2.isflipped)
Expand All @@ -371,14 +385,17 @@ def swapup(self, other):

@property
def flipped(self):
assert type(self) == ScaledUpdim
return ScaledUpdim(self.trans1, self.trans2.flipped)


class TensorEdge1(Updim):

__slots__ = 'trans',

def __init__(self, trans1, ndims2):
def __init__(self, trans1: Updim, ndims2: Integral):
assert isinstance(trans1, Updim), f'trans1={trans1!r}'
assert isinstance(ndims2, Integral), f'trans2={trans2!r}'
self.trans = trans1
super().__init__(linear=numeric.blockdiag([trans1.linear, numpy.eye(ndims2)]), offset=numpy.concatenate([trans1.offset, numpy.zeros(ndims2)]), isflipped=trans1.isflipped)

Expand Down Expand Up @@ -407,16 +424,19 @@ def swapdown(self, other):

@property
def flipped(self):
assert type(self) == TensorEdge1
return TensorEdge1(self.trans.flipped, self.fromdims-self.trans.fromdims)


class TensorEdge2(Updim):

__slots__ = 'trans'

def __init__(self, ndims1, trans2):
def __init__(self, ndims1: Integral, trans2: Updim):
assert isinstance(ndims1, Integral) and ndims1 >= 0, f'ndims1={ndims1!r}'
assert isinstance(trans2, Updim), f'trans2={trans2!r}'
self.trans = trans2
super().__init__(linear=numeric.blockdiag([numpy.eye(ndims1), trans2.linear]), offset=numpy.concatenate([numpy.zeros(ndims1), trans2.offset]), isflipped=trans2.isflipped ^ (ndims1 % 2))
super().__init__(linear=numeric.blockdiag([numpy.eye(ndims1), trans2.linear]), offset=numpy.concatenate([numpy.zeros(ndims1), trans2.offset]), isflipped=trans2.isflipped ^ bool(ndims1 % 2))

def swapup(self, other):
# prioritize ascending transformations, i.e. change updim << scale to scale << updim
Expand All @@ -443,6 +463,7 @@ def swapdown(self, other):

@property
def flipped(self):
assert type(self) == TensorEdge2
return TensorEdge2(self.fromdims-self.trans.fromdims, self.trans.flipped)


Expand All @@ -451,8 +472,9 @@ class TensorChild(Square):
__slots__ = 'trans1', 'trans2'
__cache__ = 'det',

def __init__(self, trans1, trans2):
assert trans1.fromdims and trans2.fromdims
def __init__(self, trans1: Square, trans2: Square):
assert isinstance(trans1, Square), f'trans1={trans1!r}'
assert isinstance(trans2, Square), f'trans2={trans2!r}'
self.trans1 = trans1
self.trans2 = trans2
linear = numeric.blockdiag([trans1.linear, trans2.linear])
Expand All @@ -466,9 +488,20 @@ def det(self):

class Point(Matrix):

@types.apply_annotations
def __init__(self, offset: types.arraydata):
def __init__(self, offset):
offset = numpy.asarray(offset)
super().__init__(numpy.zeros((offset.shape[0], 0)), offset)


def simplex(vertices, isflipped = None):
'''Create transform item from simplex vertices.'''

linear = types.arraydata((vertices[1:] - vertices[0]).T)
offset = types.arraydata(vertices[0])
if isflipped is None:
return Square(linear, offset)
else:
return Updim(linear, offset, isflipped)


# vim:sw=4:sts=4:et
8 changes: 4 additions & 4 deletions tests/test_transform.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from nutils import transform, evaluable, numeric
from nutils import transform, evaluable, numeric, types
from nutils.testing import TestCase
import numpy

Expand Down Expand Up @@ -59,13 +59,13 @@ def test_ext(self):
class Matrix(TestTransform):

def setUp(self):
super().setUp(trans=transform.Matrix([[1.], [2]], [3., 4]), linear=[[1], [2]], offset=[3, 4])
super().setUp(trans=transform.Matrix(types.arraydata([[1.], [2]]), types.arraydata([3., 4])), linear=[[1], [2]], offset=[3, 4])


class Qquare(TestInvertible):

def setUp(self):
super().setUp(trans=transform.Square([[1., 2], [1, 3]], [5., 6]), linear=[[1, 2], [1, 3]], offset=[5, 6])
super().setUp(trans=transform.Square(types.arraydata([[1., 2], [1, 3]]), types.arraydata([5., 6])), linear=[[1, 2], [1, 3]], offset=[5, 6])


class Identity(TestInvertible):
Expand Down Expand Up @@ -95,7 +95,7 @@ def setUp(self):
class Point(TestTransform):

def setUp(self):
super().setUp(trans=transform.Point(numpy.array([1., 2., 3.])), linear=numpy.zeros((3, 0)), offset=[1., 2., 3.])
super().setUp(trans=transform.Point(types.arraydata([1., 2., 3.])), linear=numpy.zeros((3, 0)), offset=[1., 2., 3.])


del TestTransform, TestInvertible, TestUpdim
2 changes: 1 addition & 1 deletion tests/test_transformseq.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def test_contains_with_tail(self):
if self.checkfromdims > 0:
for etrans in ref.edge_transforms:
for shuffle in lambda t: t, nutils.transform.canonical:
self.assertTrue(self.seq.contains_with_tail(trans+(etrans,)))
self.assertTrue(self.seq.contains_with_tail(shuffle(trans+(etrans,))))

def test_contains_with_tail_missing(self):
for trans in self.checkmissing:
Expand Down

0 comments on commit ff21621

Please sign in to comment.