在Python中使用nlopt,具有基于矩阵系数的多个约束

问题描述 投票:0回答:1

我在Python中使用nlopt,我在矩阵中获取一些值,在与其二维之和一样多的变量中定义一个函数,设置一些约束并进行优化。这帮助我找到最大化图熵表达式的参数。

基于这个矩阵添加可变数量的约束是很困难的,我不断收到“索引 0 超出范围”错误:

    result[count] = vars[i] * vars[j] - 1  # vars[i] * vars[j] < 1
    ~~~~~~^^^^^^^
    IndexError: index 0 is out of bounds for axis 0 with size 0
   

当我尝试添加约束时。从本质上讲,这种添加约束的方法有什么问题?

import numpy as np
import sympy as sp
import ast
import nlopt

Qgreen = np.array([[1, 2, 3], 
                  [4, 5, 6], 
                  [7, 8, 9]])

len1, len2 = Qgreen.shape

# Calculate strength along the rows
strength1 = [np.sum(Qgreen[i, :]) for i in range(len1)]

# Calculate strength along the columns
strength2 = [np.sum(Qgreen[:, i]) for i in range(len2)]

# Combine the strengths into one list
str_combined = strength1 + strength2

# Define symbolic variables
vars = sp.symbols(f'x1:{len(str_combined)+1}')  # x1, x2, ..., x6

# Create the function using symbolic expressions
f_sum = sum(s * sp.log(v) for s, v in zip(str_combined, vars))

# Flatten the product terms and their logarithms
product_terms = []
for i in range(len1):
    for j in range(len1, len1 + len2):
        product_terms.append(vars[i] * vars[j])

# Adding the log(1 - product_terms) part of the expression
f_product = sum(sp.log(1 - term) for term in product_terms)

# Final function combining both parts
f = f_sum + f_product

# Create a lambda function for fast evaluation
f_lambdified = sp.lambdify(vars, f, "numpy")

# Define the function for nlopt (minimization)
def nlopt_function(vars, grad):
    if grad.size > 0:
        # Compute the gradient if needed
        grad[:] = np.array([sp.diff(f, var).evalf(subs={v: vars[i] for i, v in enumerate(vars)}) for i, var in enumerate(vars)])
    return f_lambdified(*vars)

def constraints(vars, result):
    count = 0
    num_vars = len(vars)  # Total number of variables
    print(num_vars)
    for i in range(num_vars):
        for j in range(num_vars):
                if i != j:  # Avoid self-products
                    result[count] = vars[i] * vars[j] - 1  # The constraints are vars[i] * vars[j] < 1
                    count += 1

opt = nlopt.opt(nlopt.LN_COBYLA, len(vars))  # Use COBYLA which supports constraints
opt.set_max_objective(nlopt_function)
opt.add_inequality_constraint(constraints, 1e-8)
initial_guess = np.random.uniform(0, 1, len(vars))
optimized_vars = opt.optimize(initial_guess)
max_val = opt.last_optimum_value()
print("Optimized variables:", optimized_vars)
print("Maximum value:", max_val)

我正在尝试添加约束的各种组合,但不断出现相同的索引越界错误。

python nlopt
1个回答
0
投票

有几件事:

  1. 您需要将公差参数作为向量给出,而其维度定义约束的数量。
  2. 您需要拨打
    dd_inequality_mconstraint
    而不是
    dd_inequality_constraint
  3. 约束函数具有不同的签名。

我做了一个更简单的例子,尽管在我的例子中它都是线性的,但非线性问题的语法是相同的。

from numpy import eye
from nlopt import opt, LN_COBYLA


def objective(x, grad):
    if grad.size:
        grad[:] = 1
    return sum(x)


def constraints(results, x, grad):
    if grad.size:
        grad[:, :] = eye(3)
    results[:] = x - [2, 3, 4]


def main():
    opti = opt(LN_COBYLA, 3)
    opti.set_max_objective(objective)
    opti.add_inequality_mconstraint(constraints, [1e-8] * 3)

    opti.set_ftol_abs(1e-4)
    optimized_vars = opti.optimize([1] * 3)
    max_val = opti.last_optimum_value()
    print("Optimized variables:", optimized_vars)
    print("Maximum value:", max_val)

if __name__ == '__main__':
    main()

在这里,我只是在

x[0] + x[1] + x[2]
x[0] < 2
x[1] < 3
约束下最大化总和
x[2] < 3
。显然,解决方案是
[2, 3, 4]
:

Optimized variables: [2.00000882 3.00001096 4.00001634] 
Maximum value: 9.000036118453766
© www.soinside.com 2019 - 2024. All rights reserved.