AlgoVerse

روش سیمپلکس

مسئله‌ی برنامه‌ریزی خطی را حل می‌کند: از گوشه‌ای از ناحیه‌ی شدنی شروع می‌کند و تا وقتی تابع هدف بهتر می‌شود به گوشه‌ی مجاور می‌رود؛ با کسرهای دقیق.

برنامه‌ریزی خطی: بیشینه کردن تابع خطی c·x با قیدهای خطی A·x ≤ b و x ≥ 0. ناحیه‌ی شدنی یک چندوجهی است و اگر جواب بهینه‌ای باشد، روی یکی از گوشه‌هاست.

ادامه‌ی توضیح ↓
ورودی:
A 3×3 · b 3×1 · c 1×3خروجی PDF

بیشینه‌ی 3x1 + x2 + 2x3 با سه قید؛ جواب ۲۸ در x = (8, 4, 0).

  1. from fractions import Fraction
  2. def simplex(A, b, c):
  3. # Maximize c·x subject to A·x ≤ b and x ≥ 0 (with b ≥ 0, so x = 0 is a starting corner).
  4. m, n = len(A), len(c[0])
  5. # The tableau: [A | I | b] for the constraints, and [−c | 0 | 0] for the objective at the bottom.
  6. T = [[Fraction(v) for v in A[i]] + [Fraction(int(i == k)) for k in range(m)] + [Fraction(b[i][0])] for i in range(m)]
  7. T.append([Fraction(-v) for v in c[0]] + [Fraction(0)] * (m + 1))
  8. basis = [n + i for i in range(m)]
  9. while True:
  10. # Bland's rule: the first variable whose objective entry is negative enters.
  11. col = next((j for j in range(n + m) if T[m][j] < 0), None)
  12. if col is None:
  13. break
  14. rows = [i for i in range(m) if T[i][col] > 0]
  15. if not rows:
  16. return None
  17. row = min(rows, key=lambda i: (T[i][-1] / T[i][col], basis[i]))
  18. pivot = T[row][col]
  19. T[row] = [v / pivot for v in T[row]]
  20. for i in range(m + 1):
  21. if i != row and T[i][col] != 0:
  22. f = T[i][col]
  23. T[i] = [v - f * w for v, w in zip(T[i], T[row])]
  24. basis[row] = col
  25. x = [Fraction(0)] * n
  26. for i, var in enumerate(basis):
  27. if var < n:
  28. x[var] = T[i][-1]
  29. return str(T[m][-1]), [str(v) for v in x]

ناوردا: جدول همیشه یک گوشه‌ی شدنی را نشان می‌دهد (ستون آخر نامنفی است) و مقدار تابع هدف با هر محورگیری بدتر نمی‌شود.

شروع اجرا

basis—

جدول هنوز خالی است.

متغیرهای محلی

نارنجی = در همین گام عوض شد

A list

[1, 1, 3][2, 2, 5][4, 1, 2]

b list

[30][24][36]

c list

[3, 1, 2]

Call stack

  1. simplex()خط 4
گام ۱ از ۶۸
خط سیاه = pivot · خط نارنجی = گام کلیدیstart: 0/1 · ratio_test: 0/2 · pivot: 0/2 · optimal: 0/1
    توضیح

    ایده

    برنامه‌ریزی خطی: بیشینه کردن تابع خطی c·x با قیدهای خطی A·x ≤ b و x ≥ 0. ناحیه‌ی شدنی یک چندوجهی است و اگر جواب بهینه‌ای باشد، روی یکی از گوشه‌هاست.

    سیمپلکس

    1. از گوشه‌ی x = 0 شروع کن (چون b ≥ 0 شدنی است). متغیرهای کمبود (slack) اول در «پایه»اند.
    2. اگر در سطر هدف ضریب منفی هست، افزایش آن متغیر سود دارد: وارد پایه می‌شود.
    3. آزمون نسبت تعیین می‌کند تا کجا می‌شود جلو رفت و کدام متغیر از پایه بیرون می‌رود.
    4. محورگیری (مثل حذف گاوسی) جدول را برای گوشه‌ی تازه بازنویسی می‌کند.
    5. وقتی هیچ ضریب منفی‌ای نماند، جواب بهینه است.

    قاعده‌ی بلند (همیشه اولین ستون منفی) از دور زدن بی‌پایان جلوگیری می‌کند.

    هزینه

    در بدترین حالت نمایی است، ولی در عمل خیلی سریع است و هنوز پرکاربردترین روش است.

    در trace به چه چیزی نگاه کنی

    • جدول T را بعد از هر محورگیری ببین؛ ستون آخر مقدار متغیرهای پایه و گوشه‌ی پایین-راست مقدار تابع هدف است.