We now use a single copy of each object throughout a dynamic simulation, mutating its dynamic properties, recomputing dynamic final properties, and explicitly clearing the caches for cached properties/methods (for those using Scenic's own internal decorators, of course: people using functools.cached etc. probably don't expect that to get cleared every step). As a result, we no longer need to run specifier resolution at each time step (previously necessary to ensure dynamic final properties were updated), which turned out to cause major slowdowns when an object had a property storing a large nested list. For such cases the major performance regression from Scenic 2 to 3 should be substantially reduced.
(I've removed my previous comment about the remaining overhead when recomputing dynamic finals: the latest version of this PR gets rid of all the extraneous work we can eliminate without special-casing known properties like orientation to remove type checks, etc.)
We now use a single copy of each object throughout a dynamic simulation, mutating its dynamic properties, recomputing dynamic final properties, and explicitly clearing the caches for cached properties/methods (for those using Scenic's own internal decorators, of course: people using
functools.cached
etc. probably don't expect that to get cleared every step). As a result, we no longer need to run specifier resolution at each time step (previously necessary to ensure dynamic final properties were updated), which turned out to cause major slowdowns when an object had a property storing a large nested list. For such cases the major performance regression from Scenic 2 to 3 should be substantially reduced.(I've removed my previous comment about the remaining overhead when recomputing dynamic finals: the latest version of this PR gets rid of all the extraneous work we can eliminate without special-casing known properties like
orientation
to remove type checks, etc.)