manim
manim copied to clipboard
ImageMobjects are not properly hashed
Description of bug / unexpected behavior
I found that certain operations on ImageMobjects do not invalidate the animation cache, that is, they don't change the mobject's hash value.
In consequence, in a typical workflow of repeated renders, Manim sometimes generates videos that do not match the code they were generated with.
This is because the pixel_array is explicitly filtered out of the hashing operation:
https://github.com/ManimCommunity/manim/blob/b26137e9b62666e3f0bba0d18a72399077d3dbb6/manim/utils/hashing.py#L21-L26
Expected behavior
All (visible) modifications to an ImageMobject should result in its hash being different.
How to reproduce the issue
Code for reproducing the problem
- Run the provided code (
manim filename.pywithout amanim.cfg) - Change the alpha value
- Run it again
- Manim inappropriately re-uses the cached animation.
from manim import *
class TestImageCaching(Scene):
def construct(self):
im = ImageMobject('example.png')
# change here ↓↓↓
im.set_color(RED, alpha=0.2)
self.add(im)
self.wait()
Additional comments
The most obvious “fix” would be to remove "pixel_array" from the exclude list – which, considering that #2923 works, doesn't break Manim – but I assume it's there for a reason.
Edit: As you can see in the code snipped below, #2923 “works”, because a repr of the (truncated) array is hashed, not all of its values. In other words, this only works if you're lucky.
@huguesdevimeux As you are the caching expert, do you have an idea why pixel_array is in the exclude list ?
If im not mistaken, it may have something to do with the fact that numpy arrays are not hashable.
>>> from functools import cache
>>> cache(lambda i:i)(np.array([1,2,3]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'numpy.ndarray'
For reference, here's what happens to ndarrays that aren't filtered out: https://github.com/ManimCommunity/manim/blob/b26137e9b62666e3f0bba0d18a72399077d3dbb6/manim/utils/hashing.py#L210-L215
@huguesdevimeux As you are the caching expert, do you have an idea why pixel_array is in the exclude list ?
I think the issue what they were too large, so there is a workaround.
Hope it's clear.
ÉDIT : @icedcoffeeee It's an old piece of code, but I don't think it's related to the hashability of an np array. It's really just a matter of size
ÉDIT 2 : this issue looks interesting, I will definetly take a look when I can !
Hello and sorry, this went off my mind.
I think the most straightforward and logical thing would be to exclude ImageMobject from being cached. The main reason is that such mobject is really computationally expensive to hash, and there is no really workaround around it.
My proposal would be to generate a short random sequence as an, hash for every pixel_array, in order to invalidate the cache systematically. That's the most straightforward and simple solution I can think.