You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NLopt调用add_inequality_mconstraint时出现无效参数错误求助

Troubleshooting "nlopt invalid argument" When Adding Vector Inequality Constraints for Grid Placement Optimization

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

  1. Integer Tolerance Array for Constraints
    NLopt expects tolerance values passed to add_inequality_mconstraint to be floating-point numbers. Your gtol is an integer array (np.array([2,2,...])), which can trigger type mismatches leading to the "invalid argument" error.

  2. 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 outside 0-5 (since you have 6 grid cells), NLopt will throw errors when accessing gridWts[loc].

  3. Unnecessary Gradient Handling for Derivative-Free Algorithm
    You're using LN_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 assert statement 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_NELDERMEAD shouldn't require this).
  • Error Handling: The try-except block catches and prints unexpected errors, making debugging easier.

内容的提问来源于stack exchange,提问作者Rajkumar Seshsayee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 12:52:28