Open sea-bass opened 3 weeks ago
A non-reduced repro case I can provide right away:
Clone this branch of this repo: https://github.com/sea-bass/pyroboplan/tree/traj-opt-collision
git clone -b traj-opt-collision https://github.com/sea-bass/pyroboplan.git
Go into the repo root and run
pip install -e .
Run the example:
python3 examples/example_optimize_rrt_path.py
Notice that you will get quite a few optimization failures, but when there is a successful trajectory, this get right up to the max velocity/acceleration/jerk limits specified.
Now go into this line and uncomment it: https://github.com/sea-bass/pyroboplan/blob/0cddcac468b5ce35e617ed850cd461874b3f629c/src/pyroboplan/trajectory/trajectory_optimization.py#L611-L612
Trying again, you will see more successes, but for some reason the cost of minimizing the trajectory time (or segment time) is not minimized at all, and is always the upper bound.
FYI Sometimes when it seems like a nonlinear solver is misbehaving, the fault actually lies with the mathematical program's setup being either ill-formed, or too stiff -- rather than a problem with the solver. Hopefully a smaller reproducer will help either find such a fault, or rule it out.
I just got a REALLY simple repro. Check this out!
import numpy as np
from pydrake.solvers import MathematicalProgram, SolverOptions, SnoptSolver
prog = MathematicalProgram()
x = prog.NewContinuousVariables(1)
# Limit the variable, but also minimize it
prog.AddBoundingBoxConstraint(0.01, 10.0, x)
prog.AddQuadraticCost(Q=np.eye(1), b=np.zeros(1), vars=x)
# Solve the program.
solver = SnoptSolver()
solver_options = SolverOptions()
# solver_options.SetOption(SnoptSolver.id(), "Max iterations", 1000) # Uncomment this!
result = solver.Solve(prog, solver_options=solver_options)
x_opt = result.GetSolution(x)
print(f"Solved with solver: {result.get_solver_id().name()}")
print(f"Optimal value: {x_opt}")
With the line commented out, I get an optimal value of 0.01 (minimum value possible), but if I uncomment it, the result is 10.0 (the maximum).
EDIT: I then added this line
solver_options.SetOption(SnoptSolver.id(), "Minimize", "1") # Restore sanity in the world
and it again fixes the solution to return 0.01.
About option names, the SNOPT manual says "Some of the keywords have synonyms, and certain abbreviations are allowed, as long as there is no ambiguity.".
I think what is probably happening is that it's mapping "Max iterations" (which is not a thing that exists in SNOPT land, as far as I can tell) to "Maximize", and solving the max cost instead of min cost program.
So, I think the bug here is that SNOPT itself fails to reject typos in its option names.
Either we document that trap in the class SnoptSolver
overview to help warn future users, or else we add to Drake's snopt_solver.cc
a manually-collected listing of all ~80 known SNOPT option names, and warn in case the user passes a name that isn't in the hard-coded list.
Any votes on the solution here +@hongkai-dai?
Interesting! The latter option seems "right", but it will also be very annoying to keep that up to date every time the SNOPT version used in Drake is updated.
... annoying to keep that up to date every time the SNOPT version used in Drake is updated.
I had the same initial reaction, but in practice updates won't be a problem. Versions of SNOPT newer than 7.4 have enough severe regressions (for robotics problems) that we stopped upgrading more than 5 years ago. (See #10430.)
So the only real work is building the list for SNOPT 7.4 and SNOPT 7.6 (which are the only two versions we support).
BTW, to set the iterations limit SNOPT, you should use SetSolverOptions(SnoptSolver::id(), "major iterations limit", ITERATION_LIMIT)
for the number of QPs, and `SetSolverOptions(SnoptSolver::id(), "minor iterations limit" for the total number of steps inside QPs.
Edit: Original title was: Changing SNOPT "Max iterations" property seems to invalidate cost minimization.
What happened?
I'm running into a weird issue where I have a trajectory optimization problem that fails pretty frequently.
It succeeds a lot more if I turn up the maximum SNOPT iterations as follows:
... however, when I change this option (doesn't matter what value, so long as I set it) this it seems to completely invalidate my one cost function (in my case, quadratic cost on the trajectory time), and always returns the maximum allowable time limit I specify.
The fact that the number I set seems to be less important than setting the option itself indicates to me that, somehow, setting this option turns the problem from an objective function minimization to a "Feasible solution" solve.
I can put together a repro case if needed, but it will take me some time to strip down my code, so I was first wondering if there was something known here?
Version
1.29.0
What operating system are you using?
Ubuntu 24.04
What installation option are you using?
pip install drake
Relevant log output
No response