NLopt调用add_inequality_mconstraint时出现无效参数错误求助
Let's break down the issues with your NLopt implementation and fix the "invalid argument" error you're encountering. First, let's recap your problem: you're trying to place weighted graph nodes on a 2x3 grid to minimize the sum of weighted Euclidean distances, with constraints that each grid cell's total node weight doesn't exceed its capacity.
Key Issues Causing the Error
Integer Tolerance Array for Constraints
NLopt expects tolerance values passed toadd_inequality_mconstraintto be floating-point numbers. Yourgtolis an integer array (np.array([2,2,...])), which can trigger type mismatches leading to the "invalid argument" error.Potential Grid Index Out-of-Bounds
While your original grid index calculation looks correct on paper, it's risky to assume it will never produce invalid indices. If an index falls outside0-5(since you have 6 grid cells), NLopt will throw errors when accessinggridWts[loc].Unnecessary Gradient Handling for Derivative-Free Algorithm
You're usingLN_NELDERMEAD, a derivative-free optimization algorithm. Leaving gradient checks in place isn't harmful, but it's cleaner to explicitly skip gradient calculations since the algorithm won't use them.
Fixed Code Implementation
Here's the revised code with these issues addressed:
import numpy as np import nlopt as nlo # Problem data creation num_nodes = 10 nodeWts = np.array([16.,21.,15.,24.,4.,14.,31.,11.,12.,10.]) num_grid_cells = 6 gridCellCapacities = np.array([40.,40.,40.,40.,40.,40.]) # Use floating-point tolerance values to match NLopt's expectations gtol = np.array([2., 2., 2., 2., 2., 2.]) # Connectivity matrix cellConnectivity = np.matrix([ [0.,5.,2.,0.,0.,0.,0.,0.,0.,0.], [5.,0.,0.,2.,0.,0.,0.,0.,0.,8.], [2.,0.,0.,2.,3.,0.,5.,0.,0.,0.], [0.,2.,2.,0.,2.,4.,0.,0.,0.,0.], [0.,0.,3.,2.,0.,2.,3.,0.,0.,6.], [0.,0.,0.,4.,2.,0.,0.,0.,0.,0.], [0.,0.,5.,0.,3.,0.,0.,0.,3.,0.], [0.,0.,0.,0.,0.,0.,0.,0.,2.,3.], [0.,0.,0.,0.,0.,0.,3.,2.,0.,8.], [0.,8.,0.,0.,6.,0.,0.,3.,8.,0.] ]) ccr = cellConnectivity.reshape(num_nodes, num_nodes) # Initial setup XYLen = 2 * num_nodes initialXY = np.array([ 0.5,0.5,1.5,1.5,0.5,1.5,0.5,1.5,1.5,2.5, 0.5,0.5,0.5,0.5,1.5,1.5,1.5,1.5,1.5,0.5 ]) def myobj(XY, grad): # Derivative-free algorithm doesn't need gradients if grad.size > 0: grad[:] = 0.0 # Explicitly set to 0 to avoid unexpected behavior result = 0. for i in range(num_nodes): xi = XY[i] yi = XY[i + num_nodes] for j in range(num_nodes): if i != j: xr = (xi - XY[j]) ** 2 yr = (yi - XY[j + num_nodes]) ** 2 result += 0.5 * ccr[i,j] * np.sqrt(xr + yr) return result def myconstr(cresult, XY, grad): # Derivative-free algorithm doesn't need gradients if grad.size > 0: grad[:] = 0.0 gridWts = np.zeros(num_grid_cells) for i in range(num_nodes): xi = XY[i] yi = XY[i + num_nodes] # Calculate grid cell index (matches 2x3 grid structure) x_col = int(np.ceil(xi) - 1) # 0,1,2 for X ranges (0,1],(1,2],(2,3] y_row = int(np.ceil(yi) - 1) # 0,1 for Y ranges (0,1],(1,2] loc = y_row * 3 + x_col # Convert row-col pair to flat index # Safety check to catch invalid indices early assert 0 <= loc < num_grid_cells, f"Invalid grid index {loc} for node {i} (X: {xi}, Y: {yi})" gridWts[loc] += nodeWts[i] # Constraint: gridWts[k] - gridCellCapacities[k] ≤ 0 (with tolerance) for k in range(num_grid_cells): cresult[k] = gridWts[k] - gridCellCapacities[k] # Initialize optimizer opt = nlo.opt(nlo.LN_NELDERMEAD, XYLen) # Set bounds lb = np.zeros(XYLen) ub = np.zeros(XYLen) for i in range(XYLen): if i < num_nodes: lb[i] = 0.1 ub[i] = 3.0 else: lb[i] = 0.1 ub[i] = 2.0 opt.set_lower_bounds(lb) opt.set_upper_bounds(ub) opt.set_min_objective(myobj) opt.add_inequality_mconstraint(myconstr, gtol) opt.set_initial_step(0.1) # Run optimization with error handling try: optimal_XY = opt.optimize(initialXY) print('OPTIMAL OBJECTIVE VALUE: ', opt.last_optimum_value()) print('OPTIMIZATION RESULT CODE: ', opt.last_optimize_result()) print('OPTIMAL NODE POSITIONS:\n', optimal_XY.reshape(num_nodes, 2)) except Exception as e: print(f"Optimization failed with error: {e}")
Additional Notes
- Grid Index Clarity: I replaced your original index formula with a row-column to flat index conversion that's easier to read and verify, matching your 2x3 grid structure.
- Safety Assertion: The
assertstatement will catch invalid grid indices early, helping you debug if node positions drift outside expected bounds. - Gradient Explicitness: Setting gradients to 0 ensures compatibility even if the algorithm accidentally checks for gradients (though
LN_NELDERMEADshouldn't require this). - Error Handling: The
try-exceptblock catches and prints unexpected errors, making debugging easier.
内容的提问来源于stack exchange,提问作者Rajkumar Seshsayee

