@@ -1341,23 +1341,24 @@ def contains_branch_seperately(self, other_transform):
1341
1341
def __sub__ (self , other ):
1342
1342
"""
1343
1343
Return a transform stack which goes all the way down self's transform
1344
- stack, and then ascends back up other's stack. If it can, this is
1345
- optimised ::
1344
+ stack, and then ascends back up other's stack. If possible, identical
1345
+ terms are cancelled ::
1346
1346
1347
- # normally
1348
- A - B == a + b .inverted()
1347
+ # In general:
1348
+ A - B == A + B .inverted()
1349
1349
1350
- # sometimes, when A contains the tree B there is no need to
1351
- # descend all the way down to the base of A (via B), instead we
1352
- # can just stop at B.
1350
+ # If A "ends with" B (i.e. A == A' + B for some A') we can cancel
1351
+ # out B:
1352
+ (A' + B) - B == A'
1353
1353
1354
- (A + B) - (B)^-1 == A
1354
+ # Likewise, if B "starts with" A (B = A + B'), we can cancel out A:
1355
+ A - (A + B') == B'.inverted() == B'^-1
1355
1356
1356
- # similarly, when B contains tree A, we can avoid descending A at
1357
- # all, basically :
1358
- A - (A + B) == ((B + A) - A).inverted() or B^-1
1359
-
1360
- For clarity, the result of ``(A + B) - B + B == (A + B)`` .
1357
+ Cancellation is important not only for performance, but also because it
1358
+ avoids floating-point inaccuracies when computing the inverse of B :
1359
+ ``B - B`` is guaranteed to cancel out exactly (resulting in the
1360
+ identity transform), whereas ``B + B.inverted()`` may differ by a small
1361
+ epsilon .
1361
1362
"""
1362
1363
# we only know how to do this operation if other is a Transform.
1363
1364
if not isinstance (other , Transform ):
0 commit comments