scipy 最小化 SLSQP - 'LSQ 子问题中的奇异矩阵 C'

Posted

技术标签:

【中文标题】scipy 最小化 SLSQP - \'LSQ 子问题中的奇异矩阵 C\'【英文标题】:scipy minimize SLSQP - 'Singular matrix C in LSQ subproblem'scipy 最小化 SLSQP - 'LSQ 子问题中的奇异矩阵 C' 【发布时间】:2019-10-06 21:41:37 【问题描述】:

我正在尝试使用 SciPy 解决一个非常基本的优化问题。问题受到约束并且具有可变界限,我很确定它是线性的。

当我运行以下代码时,执行失败并显示错误消息“LSQ 子问题中的奇异矩阵 C”。有谁知道问题可能是什么?提前致谢。

编辑:我将在此处添加代码应执行的简短说明。 我在代码的开头定义了一个“需求”向量。该向量描述了在一段时间内索引的某个产品的需求。我想弄清楚的是如何下一组订单,以便在一些约束下满足这个需求。这些约束是;

如果在某个时间点有需求,我们必须有库存商品(需求指数) 在下订单后的 4 个“时间单位”之前,我们不能再下订单 我们无法在最近 4 个时间单位下订单

这是我的代码;

from scipy.optimize import minimize
import numpy as np

demand = np.array([5, 10, 10, 7, 3, 7, 1, 0, 0, 0, 8])
orders = np.array([0.] * len(demand))

def objective(orders):
  return np.sum(orders)

def items_in_stock(orders):
  stock = 0
  for i in range(len(orders)):
    stock += orders[i]
    stock -= demand[i]
    if stock < 0.:
      return -1.
  return 0.

def four_weeks_order_distance(orders):
  for i in range(len(orders)):
    if orders[i] != 0.:
      num_orders = (orders[i+1:i+5] != 0.).any()
      if num_orders:
        return -1.
  return 0.

def four_weeks_from_end(orders):
  if orders[-4:].any():
    return -1.
  else:
    return 0.

con1 = 'type': 'eq', 'fun': items_in_stock
con2 = 'type': 'eq', 'fun': four_weeks_order_distance
con3 = 'type': 'eq', 'fun': four_weeks_from_end
cons = [con1, con2, con3]

b = [(0, 100)]
bnds = b * len(orders)

x0 = orders
x0[0] = 10.

minimize(objective, x0, method='SLSQP', bounds=bnds, constraints=cons)

【问题讨论】:

如果模型是线性的,SLSQP 并不是一个很好的解决方案。线性模型的求解器将是更明显的选择。 感谢您的快速回复。我查看了 scipy 的 linprog 模块,但我很难定义我的一些约束。例如,“four_weeks_order_distance”方法施加了一个约束,基本上是说在任何其他订单后四个星期才能下订单。这种约束并不能很好地转化为矩阵形式,或者至少从我的经验水平来看。 计数通常使用二进制变量完成。支持二进制变量的线性求解器称为 MIP(混合整数规划)求解器。 Scipy 没有(但在 Python 环境中使用的 MIP 求解器很容易获得)。您所说的约束对 SLSQP 不利,因为它违反了平滑假设。 【参考方案1】:

虽然我不是运筹学研究员,但我相信这是因为您实施的约束不是连续的。我做了一些小改动,以使约束现在本质上是连续的。

from scipy.optimize import minimize
import numpy as np

demand = np.array([5, 10, 10, 7, 3, 7, 1, 0, 0, 0, 8])
orders = np.array([0.] * len(demand))

def objective(orders):
    return np.sum(orders)


def items_in_stock(orders):
    """In-equality Constraint: Idea is to keep the balance of stock and demand.
    Cumulated stock should be greater than demand. Also, demand should never cross the stock.
    """
    stock = 0
    stock_penalty = 0
    for i in range(len(orders)):
        stock += orders[i]
        stock -= demand[i]
        if stock < 0:
            stock_penalty -= abs(stock)
    return stock_penalty


def four_weeks_order_distance(orders):
    """Equality Constraint: An order can't be placed until four weeks after any other order.
    """
    violation_count = 0
    for i in range(len(orders) - 6):
        if orders[i] != 0.:
            num_orders = orders[i + 1: i + 5].sum()
            violation_count -= num_orders
    return violation_count


def four_weeks_from_end(orders):
    """Equality Constraint: No orders in the last 4 weeks
    """
    return orders[-4:].sum()


con1 = 'type': 'ineq', 'fun': items_in_stock # Forces value to be greater than zero. 
con2 = 'type': 'eq', 'fun': four_weeks_order_distance # Forces value to be zero. 
con3 = 'type': 'eq', 'fun': four_weeks_from_end # Forces value to be zero. 
cons = [con1, con2, con3]

b = [(0, 100)]
bnds = b * len(orders)

x0 = orders
x0[0] = 10.

res = minimize(objective, x0, method='SLSQP', bounds=bnds, constraints=cons,
               options='eps': 1)

结果

  status: 0
 success: True
    njev: 22
    nfev: 370
     fun: 51.000002688311334
       x: array([  5.10000027e+01,   1.81989405e-15,  -6.66999371e-16,
         1.70908182e-18,   2.03187432e-16,   1.19349893e-16,
         1.25059614e-16,   4.55582386e-17,   6.60988392e-18,
         3.37907550e-17,  -5.72760251e-18])
 message: 'Optimization terminated successfully.'
     jac: array([ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  0.])
     nit: 23
[ round(l, 2) for l in res.x ]
[51.0, 0.0, -0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.0]

所以,解决方案建议在第一周完成所有订单。

避免了缺货的情况 单次购买(订单)尊重下单后四个星期内无订单。 最近 4 周没有购买

【讨论】:

ifabs 不是两次连续可微的。它有时可能会起作用,但同样,这违反了 SLSQP 的平滑假设。

以上是关于scipy 最小化 SLSQP - 'LSQ 子问题中的奇异矩阵 C'的主要内容,如果未能解决你的问题,请参考以下文章

具有线性约束的 Scipy.optimize.minimize SLSQP 失败

Scipy优化算法--scipy.optimize.fmin_tnc()/minimize()

Python中的约束最小二乘估计

使用优化模块的 Scipy 错误。将数组转换为 fortran 失败

当我尝试使用 for 循环设置约束时,Scipy 优化未运行

SLSQP 优化算法是如何工作的?