@@ -1340,24 +1340,32 @@ def contains_branch_seperately(self, other_transform):
13401340
13411341 def __sub__ (self , other ):
13421342 """
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::
1346-
1347- # normally
1348- A - B == a + b.inverted()
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.
1353-
1354- (A + B) - (B)^-1 == A
1355-
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)``.
1343+ Compose *self* with the inverse of *other*, cancelling identical terms
1344+ if any::
1345+
1346+ # In general:
1347+ A - B == A + B.inverted()
1348+ # (but see note regarding frozen transforms below).
1349+
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+
1354+ # Likewise, if B "starts with" A (B = A + B'), we can cancel out A:
1355+ A - (A + B') == B'.inverted() == B'^-1
1356+
1357+ Cancellation (rather than naively returning ``A + B.inverted()``) is
1358+ important for multiple reasons:
1359+
1360+ - It avoids floating-point inaccuracies when computing the inverse of
1361+ B: ``B - B`` is guaranteed to cancel out exactly (resulting in the
1362+ identity transform), whereas ``B + B.inverted()`` may differ by a
1363+ small epsilon.
1364+ - ``B.inverted()`` always returns a frozen transform: if one computes
1365+ ``A + B + B.inverted()`` and later mutates ``B``, then
1366+ ``B.inverted()`` won't be updated and the last two terms won't cancel
1367+ out anymore; on the other hand, ``A + B - B`` will always be equal to
1368+ ``A`` even if ``B`` is mutated.
13611369 """
13621370 # we only know how to do this operation if other is a Transform.
13631371 if not isinstance (other , Transform ):
0 commit comments