opensim-org / opensim-core

SimTK OpenSim C++ libraries and command-line applications, and Java/Python wrapping.
https://opensim.stanford.edu
Apache License 2.0
803 stars 324 forks source link

OptimizerSystem may not return best solution it has evaluated #1395

Open tkuchida opened 8 years ago

tkuchida commented 8 years ago

The last objective function value reported from within objectiveFunc() (:car:) is better than the final objective function value returned by the SimTK::Optimizer (:checkered_flag:). It may be that some algorithms would evaluate the objective function for candidate solutions that violate constraints (whereupon it might be justified to get a :checkered_flag: that is worse than :car:), but there's no such excuse when solving an unconstrained problem. Not returning the best solution seems to violate a fundamental property of what an optimizer should be expected to do (similar to the expectation that it will return a solution that is no worse than the initial guess). The difference between :car: and :checkered_flag: is likely small in most practical cases, but perhaps not always.

(Using SimTK::InteriorPoint with numerical gradient.)

chrisdembia commented 8 years ago

Uh oh. Would it be easy to give a very small example that demonstrates this bug? Did you discover this via print statements (or something similar) inside your objectiveFunc()?

tkuchida commented 8 years ago

Would it be easy to give a very small example that demonstrates this bug?

Yes: run the Examples/exampleOptimization project (no modifications necessary). Here's the output I get:

Updating Model file from 30000 to latest format...
Loaded model arm26_optimize from file Arm26_Optimize.osim
objective evaluation #: 1  controls = ~[0.01 0.01 0.01 0.99 0.99 0.99] bestSoFar = -3.4539
...
objective evaluation #: 207  controls = ~[0.0601281 0.0212095 0.021541 0.987047 0.72514 0.30172] bestSoFar = -4.69238
Elapsed time = 72s
TRIlong control value = 0.0601281
TRIlat control value = 0.0212095
TRImed control value = 0.021541
BIClong control value = 0.987047
BICshort control value = 0.709847
BRA control value = 0.30172
Maximum hand velocity = 4.67874m/s
OpenSim example completed successfully.
Press any key to continue . . .

The bestSoFar value is reported from within objectiveFunc() and reaches -4.69238, but the optimizer returns -4.67874 (a worse result). Notice that all the controls reported for the last objective function evaluation were within the bounds of [0.01, 0.99].

Did you discover this via print statements (or something similar) inside your objectiveFunc()?

Yes, I'm monitoring the progress of the optimizer in a similar way as appears in OptimizationExample.cpp.

chrisdembia commented 8 years ago

Okay; thank you for those details.

carmichaelong commented 8 years ago

Do you know what the root cause could be? Is it possible that the Optimizer is just returning its last function evaluation?

tkuchida commented 8 years ago

Is it possible that the Optimizer is just returning its last function evaluation?

Yes, that is one possibility of many. It may also be the case that bestSoFar and the value returned by the optimizer are within the convergence tolerance, in which case it could be argued that returning either would be equally acceptable—but I disagree with that argument. I can investigate further if we decide this is a priority, but I don't know enough about the code to attempt a quick fix.