narijauskas / PRONTO.jl

A Julia implementation of PRONTO
https://narijauskas.github.io/PRONTO.jl/dev
MIT License
21 stars 3 forks source link

ξ.<TAB> freezes julia #16

Closed baggepinnen closed 1 year ago

baggepinnen commented 1 year ago

Hello! I just tried out the pendulum example, and when I tried to inspect the resulting return value ξ by typing ξ. and the pressing to look at the properties, Julia froze with 100% CPU for several minutes. Does this object somehow overload getproperty with some faulty logic?

narijauskas commented 1 year ago

Hello! So this bug is strange. I would expect ξ. to call propertynames(ξ). However, I have not defined any sort of custom propertynames or getproperty methods for the Trajectory type. Actually, running any of the following commands works totally fine:

propertynames(ξ)
propertynames(ξ, true)
propertynames(ξ, false)
fieldnames(typeof(ξ))
getproperty(ξ, :x)
getproperty(ξ, :u)
getproperty(ξ, :θ)

Then it got bizarre. I noticed I could not recreate this bug on trajectories taken from earlier iterations of the algorithm... only later ones. It seems that the cause is two-fold:

  1. Tab autocomplete actually tries to traverse the entire object tree (I will assume this is by design)
  2. PRONTO Trajectory objects take up a linearly increasing amount of memory with each iteration, as evidenced by Base.summarysize.(ξ for ξ in data.ξ)

This comes from the fact that ODESolution objects use lazy evaluation to interpolate their solutions, which means storing the parameters of the original ODEProblem. Since PRONTO necessitates solving a sequence of ODEs forwards and backwards in a loop (each using previous solutions as parameters), this creates an endlessly growing chain: ξ[i] references ξ[i-1], which references ξ[i-2], etc.

The interim solution is to sample ξ.x as well as ξ.u to a fixed timestep during the projection operator, and represent both these trajectory components as interpolants rather than ODESolution objects. This slightly decreases PRONTO's ability to converge to tight tolerances, but I think it is important to correct this bug first. Ultimately, we would want to use some kind of variable timestep interpolant which doesn't need to capture the original ODEProblem to represent both x and u.

This has been implemented in #17 , along with a resample_dt kwarg to adjust the timestep