-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Port ManimGL's Mobject family memoization #3742
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
for more information, see https://pre-commit.ci
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some questions/typing stuff, but overall the changes look good to me!
Would also be great to have some tests.
I addressed the changes you requested. self.play(
Transform(title, transform_title),
# ...
) For some reason the amount of points don't match, leading to this error:
I'll be taking a look at this bug, any help is appreciated. |
GOOD NEWS: it's now open for review again!Regarding the bug I previously mentioned, the issue was in I also prevented the deepcopying of |
Some news:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found some review comments from a review I must not have finished lol.
From a quick look at the PR description again, my main concern with this is that users have done, e.g., mob.submobjects.reverse()
, and that's still fully possible with the current implementation. I don't know how much of a breaking change/effort this would be, but maybe making the submobjects
property return an immutable value is something to consider?
e.g. any other parents of a submobject. | ||
""" | ||
ancestors = [] | ||
to_process = self.get_family(recurse=extended).copy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On another note, it's interesting how often the words extended and recurse are used in such scenarios, do they mean the same thing?
Maybe in a future PR, it might make sense to unify these to be more consistent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case extended
has a different meaning.
If it had the same meaning as get_family()
's recurse
, then it would mean something like "if recurse=False
return a list with only this Mobject
, otherwise keep recursing through this Mobject
's parents, its parents' parents, etc... and return a list containing all of them".
However, this method always returns the ancestors of this Mobject
.
extended
here means "if extended=False
only return the ancestors of this Mobject
. Otherwise, get the entire family, and then also return the ancestors of all the family members". It's more in the sense of "extended family", in this case meaning your spouse, parents-in-law, children-in-law, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In any case, I just copy-pasted this from ManimGL TBH, and it's currently not being used anywhere 🤷
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah that makes sense - maybe it's a good idea to document this somewhere and/or add tests?
Hey, thanks for reviewing this! I applied the changes you requested.
It's complicated, I tried returning a tuple instead of a list, but many other methods around the source code access the |
self.submobjects = [self.get_point_mobject() for k in range(n)] | ||
return None | ||
self._submobjects = [self.get_point_mobject() for _ in range(n)] | ||
for submob in self._submobjects: |
Check failure
Code scanning / CodeQL
Suspicious unused loop iteration variable Error
Another solution is to make a wrapper like described here, but it seems overkill. Anyways, there are 2 choices I can think of rn:
What do you think, @JasonGrace2282? |
I think for now, option 2 is better. The experimental branch has fried my brains in regards to families, though, so I think I will take a look at this hopefully in the near future, just not today. |
Related issue: #373
Although I like the proposal described in the issue, ManimGL already implemented something different: family memoization. So it's easier to port that, at least for now.
Essentially, when we call
Mobject.get_family()
, instead of recomputing the whole family recursively and from scratch, we memoize it as in ManimGL. Every time a method like.add()
or.remove()
is called, which alters the submobjects and therefore the family, we delete the previous memo by setting it asNone
, to signal that it must be recalculated. The same must be done for all the parents of the Mobject, which this PR also ports from ManimGL.This is an important step in calculating bounding boxes more efficiently.
Some points for discussion:
Mobject.submobjects
a property, because if you set it manually, the family must be altered. It works, but I don't like thatsubmobjects.setter
hides the deletion of the family behind the scenes. @JasonGrace2282 proposed makingsubmobjects
a read-only property, and only allowing it to be directly changed through aMobject.set_submobjects()
method:I like the proposal, although it's a slightly breaking change and it might be done in a subsequent PR. Please share your opinions about this. I'd be glad to make that change if we agree on that.
There were some methods, like
Mobject.insert()
orMobject.shuffle()
, which returned None instead of Self like other similar methods. I think they should also return Self, but it definitely should be another PR.There are some methods which we could optimize if we reaaaally wanted to, such as
Mobject.add()
, which instead of voiding the entire family for the current Mobject, it could append the submobjects' subfamilies to this family and filter redundancies, and only void the parents' families depending on the position of the Mobject. It would get more complex, however, and it doesn't seem to be really justified for now. Plus, I tried that before, and didn't manage to get it working because of the complexity. I decided to simply stick to the ManimGL implementation as-is, as much as possible.Links to added or changed documentation pages
Further Information and Comments
Profiling with this test scene with a huge amount of nested Mobjects:
Reviewer Checklist