csu-hmc / opty

A library for using direct collocation in the optimization of dynamic systems.
http://opty.readthedocs.io
Other
86 stars 20 forks source link

Implements support for variable duration solutions #150

Closed moorepants closed 1 month ago

moorepants commented 1 month ago

Fixes #19

This PR allows a user to pass in a symbol as the node interval value instead of a float and then specify instance constraints in terms of node index instead of time. This adds the node interval value as a free optimization variable (as the last element) and the resulting constraint equations and Jacobian takes into account the variable interval. I demonstrate it on the pendulum swing up problem.

moorepants commented 1 month ago

@tjstienstra, if you're interested in reviewing this, it is much appreciated. I've only tried it out on the example pendulum problem here, nothing more complicated yet.

moorepants commented 1 month ago

If you have any comments on the API for the instance constraints, I'd be interested. The basic idea is that if you have fixed duration problems you give something like x(1.23) where the argument is time and then I find the nearest node index. If you have a variable duration, then you give x(4) as the 4th node as the argument. I'm not sure this is the best approach.

moorepants commented 1 month ago

Variable duration pendulum swing up solution: image

tjstienstra commented 1 month ago

If you have any comments on the API for the instance constraints, I'd be interested.

I would have a preference not to use round brackets substituting t for indices. That may not just be confusing at first, especially since we normally find the index for the supplied time value, but it will also cause problems for possible future features.

The closest solution would be to use a multiple of h, e.g. 4*h when selecting the fifth node.

tjstienstra commented 1 month ago

One of my main curiosities is also what would the API look like if variable time steps were supported?

moorepants commented 1 month ago

I would have a preference not to use round brackets substituting t for indices.

I suspect I could support something like theta[0] but that could take considerably use more work. I'm using (or abusing) SymPy Function behavior. I guess you could create an sympy.Indexed.

The closest solution would be to use a multiple of h, e.g. 4*h when selecting the fourth node.

I originally wrote it like this and then realized it was much simpler to ask the node number from the user, so switched to it.

moorepants commented 1 month ago

One of my main curiosities is also what would the API look like if variable time steps were supported?

I guess the API wouldn't really change other than free being made longer with all the h values. We could have a flag fixed_interval_size or something.

tjstienstra commented 1 month ago

I suspect I could support something like theta[0] but that could take considerably use more work.

Yeah, that was the other thing I thought of.

The closest solution would be to use a multiple of h, e.g. 4*h when selecting the fourth node.

I originally wrote it like this and then realized it was much simpler to ask the node number from the user, so switched to it.

I would prefer the additional difficulty, because it is clearer and mathematically correct. t=4h for the fifth node.

Another solution is to create a boolean keyword argument to interpret supplied time values as indices.

tjstienstra commented 1 month ago

One of my main curiosities is also what would the API look like if variable time steps were supported?

I guess the API wouldn't really change other than free being made longer with all the h values. We could have a flag fixed_interval_size or something.

I was more thinking toward supplying an iterable as node_time_interval, which may include multiples of h.

moorepants commented 1 month ago

I was more thinking toward supplying an iterable as node_time_interval, which may include multiples of h.

I'm not sure why you'd want to do that. What is the reason that you'd want to specify unequal proportional spacing? Wouldn't it mean you are trying to guess where the solution is stiff (smaller spacing in stiff areas) without knowing the solution?

tjstienstra commented 1 month ago

I was more thinking toward supplying an iterable as node_time_interval, which may include multiples of h.

I'm not sure why you'd want to do that. What is the reason that you'd want to specify unequal proportional spacing? Wouldn't it mean you are trying to guess where the solution is stiff (smaller spacing in stiff areas) without knowing the solution?

If a problem is partially reusable then we could start iterating to improve the solution. A bit like what pycollo does only then way simpler. In several problems you know where you want a bit higher resolution and where you do not need that many points.

moorepants commented 1 month ago

I see, yes, if you have a sense of the solution you could proportional time to reflect that.

moorepants commented 1 month ago

I switched to integer multiples of the time interval symbol.