Computational_Mathematics/simplex.py

101 lines
5.0 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
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