4

SciPy を使用して、かなり基本的な最適化問題を解決しようとしています。問題は制約されており、境界が可変であり、線形であると確信しています。

次のコードを実行すると、「Singular matrix C in LSQ subproblem」というエラー メッセージが表示されて実行が失敗します。問題が何であるかを知っている人はいますか?前もって感謝します。

編集:コードが何をすべきかについての簡単な説明をここに追加します。コードの先頭で「需要」ベクトルを定義します。このベクトルは、一定期間にわたってインデックス化された特定の製品の需要を表します。私が理解したいのは、いくつかの制約の下でこの需要を満たすために一連の注文を出す方法です。これらの制約は次のとおりです。

  • ある時点で需要があれば在庫を持たなければならない(需要指数)
  • 注文後、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)
4

1 に答える 1

5

私はオペレーショナル リサーチャーではありませんが、実装した制約が連続的ではないためだと思います。制約が本質的に連続するように、少し変更を加えました。

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週間以内のご注文は承っておりません。
  • 過去 4 週間の購入なし
于 2019-05-20T16:51:16.620 に答える