Python下Pyomo+IPOPT求解器优化收敛曲线获取求助
Got it, let's break this down step by step—getting IPOPT's iteration data in Pyomo, parsing it, and building convergence curves is totally doable, even if the docs feel a bit scattered at first. Here's how to pull it off:
First, you need to tell IPOPT to spit out full iteration data when solving your Pyomo model. This requires setting specific solver options to enable verbose logging and save the output to a file for later parsing.
from pyomo.environ import * # Replace this with your actual nonlinear model model = ConcreteModel() model.x = Var(initialize=1.0) model.y = Var(initialize=1.0) model.obj = Objective(expr=(model.x-2)**2 + (model.y-3)**2 + model.x*model.y) model.con1 = Constraint(expr=model.x + model.y >= 4) # Initialize IPOPT solver solver = SolverFactory('ipopt') # Key IPOPT options for iteration logging solver.options['print_level'] = 5 # Level 5 enables full iteration table output solver.options['output_file'] = 'ipopt_iterations.log' # Save log to file solver.options['tee'] = True # Optional: Print log to console while solving # Run the solver result = solver.solve(model, tee=True)
The print_level=5 flag is critical—it tells IPOPT to output every iteration's key metrics (objective value, primal/dual residuals, etc.). The output_file ensures you have a persistent copy of this data to parse.
IPOPT's iteration log follows a fixed format. We'll use a regex to extract the columns we care about (iteration number, objective value, residuals) and load them into a Pandas DataFrame for easy manipulation.
import re import pandas as pd def parse_ipopt_log(log_path): # Regex pattern to match IPOPT's iteration lines iter_pattern = re.compile(r'^\s*(\d+)\s+([-+]?\d+\.\d+(?:e[+-]?\d+)?)\s+([-+]?\d+\.\d+(?:e[+-]?\d+)?)\s+([-+]?\d+\.\d+(?:e[+-]?\d+)?)\s+([-+]?\d+\.\d+(?:e[+-]?\d+)?)\s+.*') iterations = [] with open(log_path, 'r') as f: for line in f: match = iter_pattern.match(line) if match: # Extract core convergence metrics iterations.append({ 'iteration': int(match.group(1)), 'objective': float(match.group(2)), 'primal_residual': float(match.group(3)), 'dual_residual': float(match.group(4)), 'log_mu': float(match.group(5)) }) return pd.DataFrame(iterations) # Parse the log file df_ipopt = parse_ipopt_log('ipopt_iterations.log') print(df_ipopt.head())
Adjust the regex if your IPOPT version has a slightly different log format—just print a few iteration lines from your log and tweak the pattern to match.
Use Matplotlib to visualize the convergence behavior. Plotting the objective function and residuals (on a log scale) will clearly show how quickly IPOPT converges to a solution.
import matplotlib.pyplot as plt # Set a clean plotting style plt.style.use('seaborn-v0_8') # Create a 1x2 grid of plots fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5)) # Plot 1: Objective function over iterations ax1.plot(df_ipopt['iteration'], df_ipopt['objective'], marker='o', linestyle='-', color='navy') ax1.set_xlabel('Iteration Count') ax1.set_ylabel('Objective Value') ax1.set_title('IPOPT Objective Function Convergence') ax1.grid(True) # Plot 2: Primal/dual residuals (log scale for clarity) ax2.semilogy(df_ipopt['iteration'], df_ipopt['primal_residual'], marker='s', linestyle='--', color='crimson', label='Primal Residual') ax2.semilogy(df_ipopt['iteration'], df_ipopt['dual_residual'], marker='^', linestyle=':', color='forestgreen', label='Dual Residual') ax2.set_xlabel('Iteration Count') ax2.set_ylabel('Residual (Log Scale)') ax2.set_title('IPOPT Primal/Dual Residual Convergence') ax2.legend() ax2.grid(True) plt.tight_layout() plt.show()
These plots will let you verify if the solver is converging smoothly, if residuals drop below acceptable thresholds, and how many iterations it takes to reach the optimal solution.
To compare IPOPT with other nonlinear solvers (like Bonmin, Couenne, or even different IPOPT configurations), repeat the same workflow:
- Configure the target solver to output its iteration log (most solvers have a
print_levelequivalent) - Write a parser for that solver's log format (adjust the regex to match its iteration line structure)
- Plot all solver data on the same axes to compare convergence speed, objective value trajectory, and residual behavior.
For example, adding Bonmin data to the objective plot would look like this:
# Assume df_bonmin is your parsed Bonmin iteration data ax1.plot(df_bonmin['iteration'], df_bonmin['objective'], marker='x', linestyle='-', color='orange', label='Bonmin') ax1.legend()
- If you don't see iteration data in your log, bump
print_levelto 6 (some IPOPT versions require this for full output) - If the regex doesn't match, print a sample iteration line from your log and adjust the pattern to fit
- Ensure the
output_filepath is writable if you're running on a remote server or cluster
内容的提问来源于stack exchange,提问作者Wilson Mendes

