Постановка проблемы: я пытаюсь использовать nlopt с интерфейсом python, чтобы минимизировать целевую функцию, которая минимизирует сумму евклидовых расстояний между взвешенными узлами неориентированного графа с взвешенными ребрами, когда они размещаются на сетке. Ограничения заключаются в том, что емкость любой ячейки сетки не нарушается. То есть сумма весов узлов в ячейке сетки не превышает ее емкости. При попытке добавить вектор ограничений неравенства с помощью opt.add_inequality_mconstraint появляется ошибка «nlopt invalid аргумент». Мои ограничения для каждой ячейки сетки, длина которой равна 6. Вот мой код:
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
import nlopt as nlo
# Problem data creation
# Given a set of nodes and weighted edges,
# place them on a grid of cells which have a link capacity,
# such that the number of nodes in a grid cell
# dont exceed a certain capacity
#E.g graph - 10 nodes with connectivity matrix
#6 grid cells arranged as 2x3
num_nodes = 10
#Weight of each node
nodeWts = np.array([16.,21.,15.,24.,4.,14.,31.,11.,12.,10.])
num_grid_cells = 6
#Capacity of each grid cell
gridCellCapacities = np.array([40.,40.,40.,40.,40.,40.])
gtol = np.array([2,2,2,2,2,2])
gridIds = np.arange(6)
splitGrid = np.split(gridIds,2)
splitGridR = splitGrid[::-1]
splitGridMtx = np.vstack(splitGridR)
gridMtx = gridIds.reshape(2,3)
print('gids: ', gridIds)
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)
print('sg: ', splitGridR)
print('gmx: ', splitGridMtx)
X = np.zeros(num_nodes, order='C')
Y = np.zeros(num_nodes, order='C')
XY = np.hstack([X,Y])
XYLen = len(XY)
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])
print('XY: ', XY)
def myobj(XY, grad):
if (grad.size > 0):
print('GRAD NOT YET IMPLEMENTED')
result = 0.
xr = 0.
yr = 0.
for i in range(num_nodes):
for j in range(num_nodes):
if (i != j):
xr = np.square(XY[i]-XY[j])
yr = np.square(XY[i+num_nodes] - XY[j+num_nodes])
result += 0.5*(ccr[i,j])*(np.sqrt(xr+yr))
return result
def myconstr(cresult, XY, grad):
if (grad.size > 0):
print('CONSTRAINT GRADIENT NOT IMPLEMENTED')
gridWts = np.zeros(num_grid_cells)
gridLoc = np.zeros(shape=(num_nodes,num_grid_cells))
for i in range(num_nodes):
for j in range(num_grid_cells):
gridLoc[i,j] = np.ceil(XY[i]) + np.abs(np.square(np.ceil(XY[i+num_nodes]))) - 2
loc = int(gridLoc[i,j])
gridWts[loc] += nodeWts[i]
for k in range(num_grid_cells):
cresult[k] = gridWts[k] - gridCellCapacities[k]
opt = nlo.opt(nlo.LN_NELDERMEAD, XYLen)
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
print('LB: ', lb)
print('UB: ', ub)
grad = np.array([])
cresult = np.zeros(num_grid_cells)
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)
opt.optimize(initialXY)
print('OPTIMAL WL: ', opt.last_optimum_value())
print('LOR: ', opt.last_optimize_result())
print('XY: ', XY)