2023-12-15 11:23:29 +04:00

74 lines
5.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import numpy as np
def simplex_method(c, A, b):
m, n = A.shape
c = np.concatenate([c, np.zeros(m)]) # Дополнение коэффициентов целевой функции нулями
A = np.column_stack([A, np.eye(m)]) # Дополнение матрицы A единичной матрицей
basis = np.arange(n, n + m) # Индексы базисных переменных
while True:
# Шаг 1: Проверка на оптимальность
# Рассчитываем приведенные затраты (reduced_costs), вычитая из коэффициентов целевой функции (c)
# линейную комбинацию базисных переменных и соответствующих им строк матрицы A.
# Приведенные затраты - оценки изменения целевой функции при изменении значений переменных.
reduced_costs = c - np.dot(c[basis], A)
# Если все приведенные затраты неотрицательны (все переменные в базисе удовлетворяют условиям оптимальности),
# то достигнуто оптимальное решение, и цикл прерывается.
if all(reduced_costs >= 0):
break
# Шаг 2: Выбор входящей переменной
# определяем индекс переменной, которую мы добавим в базис (войдет в решение) на следующей итерации.
# выбираем переменную с наименьшим уменьшенным коэффициентом в функции цели.
entering_var = np.argmin(reduced_costs)
# Шаг 3: Проверка на неограниченность
# Проверяем, если все элементы столбца матрицы A, соответствующего входящей переменной,
# меньше или равны нулю. Если это условие выполняется, то проблема неограничена.
if all(A[:, entering_var] <= 0):
raise Exception("Проблема неограничена")
# Шаг 4: Выбор выходящей переменной
# Рассчитываем отношения значений правых частей к соответствующим коэффициентам входящей переменной в матрице A.
# Если коэффициент входящей переменной положителен, оставляем отношение, иначе присваиваем бесконечность.
ratios = np.divide(b, A[:, entering_var], out=np.full_like(b, np.inf, dtype=float), where=A[:, entering_var] > 0)
# Находим индекс минимального отношения, который определяет выходящую переменную.
leaving_var = np.argmin(ratios)
# Шаг 5: Обновление базиса
# Обновляем базис, заменяя выходящую переменную на входящую переменную.
basis[leaving_var] = entering_var
# Шаг 6: Обновление симплекс-таблицы
pivot = A[leaving_var, entering_var] # Выбор опорного элемента (пересечение строки и столбца)
A[leaving_var, :] /= pivot # Деление строки с опорным элементом на опорный элемент
b[leaving_var] /= pivot # Деление правой части на опорный элемент
for i in range(m):
if i != leaving_var:
factor = A[i, entering_var] # Выбор элемента в столбце входящей переменной
A[i, :] -= factor * A[leaving_var, :] # Обновление строки матрицы
b[i] -= factor * b[leaving_var] # Обновление правой части
c -= reduced_costs[entering_var] * A[leaving_var, :] # Обновление коэффициентов целевой функции
# Извлечение решения из симплекс-таблицы
solution = np.zeros(n)
for i in range(m):
if basis[i] < n:
solution[basis[i]] = b[i] # Извлечение значений базисных переменных из симплекс-таблицы
return solution
# Пример использования:
c = np.array([-3, -2]) # Коэффициенты целевой функции для минимизации
A = np.array([[1, 2], [2, 1], [1, -1]]) # Коэффициенты ограничений-неравенств
b = np.array([4, 7, 1]) # Значения правых частей ограничений
result = simplex_method(c, A, b)
print("Оптимальное решение:", result)