101 lines
5.0 KiB
Python
101 lines
5.0 KiB
Python
import numpy as np
|
||
|
||
|
||
class simplex:
|
||
def __init__(self, source):
|
||
# m - кол-во строк, n - кол-во столбцов
|
||
m, n = source.shape
|
||
# таблица с m строк и n+m-1 столбцов, для базисных переменных
|
||
self.table = np.zeros((m, n + m - 1))
|
||
# базисные переменные
|
||
self.basis = []
|
||
|
||
# начальная симплекс-таблица
|
||
for i in range(m):
|
||
for j in range(self.table.shape[1]):
|
||
if j < n:
|
||
# пока мы находимся на столбцах исходной таблицы,
|
||
# то просто копируем значения коэффициентов
|
||
self.table[i, j] = source[i, j]
|
||
else:
|
||
# вышли за n, значит добавляем базисные столбцы
|
||
self.table[i, j] = 0
|
||
|
||
# выставляем единицы по диагонали
|
||
if (n + i) < self.table.shape[1]:
|
||
# ставим единицу в соответствующем столбце для базисной переменной
|
||
self.table[i, n + i] = 1
|
||
# записываем номер столбца базисной переменной в список
|
||
self.basis.append(n + i)
|
||
|
||
# обновляем размерности матрицы
|
||
self.m = m
|
||
self.n = self.table.shape[1]
|
||
|
||
def calculate(self, result):
|
||
# основной цикл симплекс-метода
|
||
while not self.is_it_end():
|
||
# находим ведущие колонку и строку
|
||
main_col = self.find_main_col()
|
||
main_row = self.find_main_row(main_col)
|
||
# обновляем список базисных переменных
|
||
self.basis[main_row] = main_col
|
||
|
||
# Пересчет симплекс-таблицы
|
||
new_table = np.zeros((self.m, self.n))
|
||
for j in range(self.n):
|
||
# нормализуем значение матрицы
|
||
# элементы ведущей строки делим на ведущий столбец
|
||
new_table[main_row, j] = self.table[main_row, j] / self.table[main_row, main_col]
|
||
for i in range(self.m):
|
||
# пропускаем ведущую строку
|
||
if i == main_row:
|
||
continue
|
||
for j in range(self.n):
|
||
# обновляем остальные строки таблицы
|
||
new_table[i, j] = self.table[i, j] - self.table[i, main_col] * new_table[main_row, j]
|
||
self.table = new_table
|
||
|
||
# получаем решение
|
||
for i in range(len(result)):
|
||
# получаем значения переменных из базиса
|
||
# если индекс переменной есть в списке базисов, то получаем значение переменной из таблицы
|
||
k = self.basis.index(i + 1) if i + 1 in self.basis else -1
|
||
result[i] = self.table[k, 0] if k != -1 else 0
|
||
|
||
return self.table
|
||
|
||
def is_it_end(self):
|
||
# если все элементы последней строки f(x) неотрицательны,
|
||
# значит допустимое базисное решение оптиммально
|
||
return np.all(self.table[self.m - 1, 1:] >= 0)
|
||
|
||
def find_main_col(self):
|
||
# находим ведущую колонку,
|
||
# минимальный отрицательный коэффициент в последней строке f(x)
|
||
main_col = 1
|
||
for j in range(2, self.n):
|
||
if self.table[self.m - 1, j] < self.table[self.m - 1, main_col]:
|
||
main_col = j
|
||
return main_col
|
||
|
||
def find_main_row(self, main_col):
|
||
# находим ведущую строку:
|
||
# минимальное положительное отношение свободного члена к ведущему элементу
|
||
main_row = 0
|
||
# находим первую положительную строку
|
||
for i in range(self.m - 1):
|
||
if self.table[i, main_col] >= 0:
|
||
main_row = i
|
||
break
|
||
|
||
for i in range(main_row + 1, self.m - 1):
|
||
# проверяем значение на неотрицательность,
|
||
if (self.table[i, main_col] >= 0
|
||
# если текущее отношение меньше, чем в "ведущей строке",
|
||
# то обновляем индекс ведущей строки
|
||
and (self.table[i, 0] / self.table[i, main_col]) <
|
||
(self.table[main_row, 0] / self.table[main_row, main_col])):
|
||
main_row = i
|
||
return main_row
|