csu-hmc / opty

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

Question concerning the number of iterations #133

Closed Peter230655 closed 6 months ago

Peter230655 commented 6 months ago

If I use the line prob.plot_objective_value() I get a plot where on the x axis are the number of iterations (vs. the value of the objective function at that iteration, I assume)

Question: can I get the number of iterations without plotting this? I did not find anything in the info dictionary. (Did I overlook something?)

Reason for asking: I sometimes loop from an 'easy' problem to a more difficult one, using the solution of loop i as initial_guess for the next look. If, say, iteration i uses 1000 iterations, and i+1 uses 10, then chances are I can male the 'step' larger (of course only my guess, no idea if true)

Thank you!

tjstienstra commented 6 months ago

Question: can I get the number of iterations without plotting this? I did not find anything in the info dictionary. (Did I overlook something?)

prob.solve returns solution, info. I'm not sure if it is in info. Another option is that you can specify an output file where it writes runtime information to: problem.add_option("output_file", "ipopt.txt") Here is a simple function to extract information from this file (copied from BRiM paper source code:

import re
def get_ipopt_statistics(output_file):
    with open(output_file, "r", encoding="utf-8") as f:
        ipopt_output = f.read()
    objective = float(re.search(
        re.compile(r"Objective.*?:\s+(.*?)\s+(.*)"), ipopt_output).group(2))
    nlp_iterations = int(re.search(
        re.compile(r"Number of Iterations\.\.\.\.: (\d+)"), ipopt_output).group(1))
    ipopt_time = float(re.search(
        re.compile(r"Total seconds in IPOPT[ ]+= (\d+\.\d+)"), ipopt_output).group(1))
    ipopt_exit = re.search(re.compile(f"EXIT: (.*)"), ipopt_output).group(1)
    return {
        "Objective": objective,
        "#NLP iterations": nlp_iterations,
        "Time in Ipopt": ipopt_time,
        "Ipopt exit status": ipopt_exit,
    }

I sometimes loop from an 'easy' problem to a more difficult one, using the solution of loop i as initial_guess for the next look.

Sounds good.

If, say, iteration i uses 1000 iterations, and i+1 uses 10, then chances are I can male the 'step' larger (of course only my guess, no idea if true)

Not entirely sure what you mean with this

Peter230655 commented 6 months ago

1. I will try your suggestion, thanks! 2. What I meant was this: say the center of my skateboard should follow a curve. I start with a straight line and gradually deform it. If loop i took 1000 iterations and loop i+1 takes only 10, this could mean that I can deform my curve more from step i to step i+1, getting to the final curve with fewer loops. ( But then again, each loop may take much longer?)

tjstienstra commented 6 months ago

What I meant was this: say the center of my skateboard should follow a curve. I start with a straight line and gradually deform it. If loop i took 1000 iterations and loop i+1 takes only 10, this could mean that I can deform my curve more from step i to step i+1, getting to the final curve with fewer loops. ( But then again, each loop may take much longer?)

Curious way to solve the problem. It is indeed a bit of trying things. One thing you may want to look into as well if you want to try this method is use the warm start option of ipopt that tells the optimizer that it is already close to the solution.

When solving the trajectory-tracking problems with bicycle-riders I did notice that once you figured out the best constraints and a reasonable trajectory etc then it solves with just a straight line.

Peter230655 commented 6 months ago

It is a whole lot of trying! :-) Actually my 'problem' is this: I want to steer and push the axles of a 'skateboard' in such a way that its center follows a prescribed line. So, I start with a simple line, like a straight line, and gardually deform it to my final line.

use the warm start option of ipopt that tells the optimizer that it is already close to the solution. How do I get this? I only know opty. Can I set it there?

Thanks again!

tjstienstra commented 6 months ago

use the warm start option of ipopt that tells the optimizer that it is already close to the solution. How do I get this? I only know opty. Can I set it there?

problem.add_option("warm_start_init_point", "yes") would enable warm start, I think.

It is a whole lot of trying! :-)

Yeah, I have not yet doven into that many rabbit holes when working with direct collocation, so for me, a lot is making educated guesses and trying whether something works.

Peter230655 commented 6 months ago

Above you gave me this function. 1. What does import re means? It worked without any problems on my program. 2. Where does the argument output_file come from?

Sorry, I am VERY stupid in these things! Thanks!!

_import re def get_ipopt_statistics(output_file): with open(output_file, "r", encoding="utf-8") as f: ipopt_output = f.read() objective = float(re.search( re.compile(r"Objective.?:\s+(.?)\s+(.)"), ipopt_output).group(2)) nlp_iterations = int(re.search( re.compile(r"Number of Iterations....: (\d+)"), ipopt_output).group(1)) ipopt_time = float(re.search( re.compile(r"Total seconds in IPOPT[ ]+= (\d+.\d+)"), ipopt_output).group(1))import re def get_ipopt_statistics(output_file): with open(output_file, "r", encoding="utf-8") as f: ipopt_output = f.read() objective = float(re.search( re.compile(r"Objective.?:\s+(.?)\s+(.)"), ipopt_output).group(2)) nlp_iterations = int(re.search( re.compile(r"Number of Iterations....: (\d+)"), ipopt_output).group(1)) ipopt_time = float(re.search( re.compile(r"Total seconds in IPOPT[ ]+= (\d+.\d+)"), ipopt_output).group(1)) ipopt_exit = re.search(re.compile(f"EXIT: (.*)"), ipopt_output).group(1) return { "Objective": objective, "#NLP iterations": nlp_iterations, "Time in Ipopt": ipopt_time, "Ipopt exit status": ipopt_exit, }

tjstienstra commented 6 months ago

What does import re means? It worked without any problems on my program.

re is a default regular expression library.

Where does the argument output_file come from?

output_file = "ipopt.txt"
problem.add_option("output_file", output_file)
get_ipopt_statistics(output_file)
tjstienstra commented 6 months ago

For the number of iterations, you can also simply use len(problem.obj_value), if I'm not mistaken.

Peter230655 commented 6 months ago

You were right! Thanks!