Skip to content

Commit 3d8ee29

Browse files
authored
optimize vec_transform again (#104)
1 parent e436128 commit 3d8ee29

File tree

2 files changed

+45
-22
lines changed

2 files changed

+45
-22
lines changed

pylinalg/vector.py

+43-20
Original file line numberDiff line numberDiff line change
@@ -105,28 +105,51 @@ def vec_transform(
105105
transformed vectors
106106
"""
107107

108-
matrix = np.asarray(matrix, dtype="f8")
108+
matrix = np.asarray(matrix)
109+
vectors = np.asarray(vectors)
109110

110-
if projection:
111-
vectors = vec_homogeneous(vectors, w=w, dtype="f8")
112-
if vectors.ndim == 1:
113-
vectors = matrix @ vectors
114-
vectors[:-1] /= vectors[-1]
115-
vectors = vectors[:-1]
116-
elif vectors.ndim == 2:
117-
vectors = (matrix @ vectors.T).T
118-
vectors = vectors[..., :-1] / vectors[..., -1, None]
119-
else:
120-
raise ValueError("vectors must be a 1D or 2D array")
111+
# this code has been micro-optimized for the 1D and 2D cases
112+
vectors_ndim = vectors.ndim
113+
if vectors_ndim > 2:
114+
raise ValueError("vectors must be a 1D or 2D array")
115+
116+
# determine if we are working with a batch of vectors
117+
batch = vectors_ndim != 1
118+
119+
# we don't need to work in homogeneous vector space
120+
# if matrix is purely affine and vectors is a single vector
121+
homogeneous = projection or batch
122+
123+
if homogeneous:
124+
vectors = vec_homogeneous(vectors, w=w)
125+
matmul_matrix = matrix
121126
else:
122-
if vectors.ndim == 1:
123-
vectors = matrix[:-1, :-1] @ vectors + matrix[:-1, -1]
124-
elif vectors.ndim == 2:
125-
vectors = vec_homogeneous(vectors, w=w, dtype="f8")
126-
vectors = (matrix @ vectors.T).T
127-
vectors = vectors[..., :-1]
128-
else:
129-
raise ValueError("vectors must be a 1D or 2D array")
127+
# if we are not working in homogeneous space, it's
128+
# more efficient to matmul the 3x3 (scale + rotation)
129+
# part of the matrix with the vectors and then add
130+
# the translation part after
131+
matmul_matrix = matrix[:-1, :-1]
132+
133+
if batch:
134+
# transposing the vectors array performs better
135+
# than transposing the matrix
136+
vectors = (matmul_matrix @ vectors.T).T
137+
else:
138+
vectors = matmul_matrix @ vectors
139+
if not homogeneous:
140+
# as alluded to before, we add the translation
141+
# part of the matrix after the matmul
142+
# if we are not working in homogeneous space
143+
vectors = vectors + matrix[:-1, -1]
144+
145+
if projection:
146+
# if we are projecting, we divide by the last
147+
# element of the vectors array
148+
vectors = vectors[..., :-1] / vectors[..., -1, None]
149+
elif homogeneous:
150+
# if we are NOT projecting but we are working in
151+
# homogeneous space, just drop the last element
152+
vectors = vectors[..., :-1]
130153

131154
if out is None:
132155
out = vectors

tests/test_vectors.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,9 @@ def test_vec_transform_projection_flag():
101101
[0, 0, 0],
102102
[7, 8, -9],
103103
],
104-
dtype="f4",
104+
dtype="f8",
105105
)
106-
translation = np.array([-1, 2, 2], dtype=float)
106+
translation = np.array([-1, 2, 2], dtype="f8")
107107
expected = vectors + translation[None, :]
108108

109109
matrix = la.mat_from_translation(translation)

0 commit comments

Comments
 (0)