如何在scipy.optimize.minimize函数中约束x为整数?
scipy.optimize.minimize Hey there! The standard scipy.optimize.minimize tool is built for continuous optimization—it doesn't have native support for integer constraints, which is why you're getting decimal results even after setting value ranges. But there are a couple of reliable workarounds depending on your problem type:
1. Use scipy.optimize.milp (for Linear Problems)
If your objective function and constraints are linear, milp (Mixed Integer Linear Programming) is the most straightforward choice. It natively supports integer variable declarations.
Example Code:
import numpy as np from scipy.optimize import milp, LinearConstraint # Define your linear objective coefficients (e.g., minimize sum(x)) objective_coeffs = np.array([1, 1, 1, 1, 1]) # Set bounds for each variable: [0, 12] for all 5 variables variable_bounds = [(0, 12) for _ in range(5)] # Mark all variables as integers (1 = integer, 0 = continuous) integrality_flags = [1] * 5 # Run the mixed integer linear optimization result = milp(c=objective_coeffs, bounds=variable_bounds, integrality=integrality_flags) # Print the integer solution print("Integer solution:", result.x)
2. Use Heuristic Methods (for Non-Linear Problems)
If your objective function is non-linear, milp won't work. Instead, you can use a heuristic optimizer like scipy.optimize.basinhopping with a callback to enforce integer constraints at each iteration.
Example Code:
import numpy as np from scipy.optimize import basinhopping, minimize # Your non-linear objective function (customize this to your use case) def non_linear_objective(x): return (x[0]-2)**2 + (x[1]-10)**2 + (x[2]-5)**2 + (x[3]-7)**2 + (x[4]-3)**2 # Callback function to clamp values to integers within [0,12] def enforce_integer_constraint(x, f, accept): # Round to nearest integer and clip to stay within bounds x_int = np.round(x).astype(int) x_clamped = np.clip(x_int, 0, 12) # Update the current solution to the integer version x[:] = x_clamped return accept # Initial guess (your original decimal result) initial_guess = np.array([1.0, 11.1, 5.4, 6.9, 3.4]) # Run basinhopping with integer constraints result = basinhopping( non_linear_objective, initial_guess, minimizer_kwargs={"bounds": [(0, 12)]*5}, # Keep values in range callback=enforce_integer_constraint, niter=100 # Adjust iterations based on your problem complexity ) # Print the integer solution print("Integer solution:", result.x)
Notes on Basinhopping:
- It's a stochastic method, so you might need to tweak
niteror other parameters to find a good solution. - For more complex non-linear integer problems, you could also explore third-party libraries like
DEAP(genetic algorithms) orPuLP, but the above method works within the SciPy ecosystem.
3. Brute-Force Grid Search (Small Problem Sizes Only)
If you have a very small number of variables, you could brute-force all integer combinations within your bounds. But this becomes infeasible quickly as the number of variables grows (curse of dimensionality!).
内容的提问来源于stack exchange,提问作者ThReSholD




