LabWork01: done?

This commit is contained in:
parent ff12534cae
commit 837539b67a

185
main.py
View File

@ -0,0 +1,185 @@
import numpy as np
import tkinter as tk
from tkinter import messagebox
from typing import List, Tuple
class TransportProblemApp:
def __init__(self, root: tk.Tk) -> None:
"""
Инициализация приложения.
:param root: Основное окно приложения (Tkinter).
"""
self.root: tk.Tk = root
self.root.title("Транспортная задача")
self.suppliers: int = 3
self.consumers: int = 3
self.setup_ui()
def setup_ui(self) -> None:
"""
Создание интерфейса приложения, включая поля для ввода данных и кнопки.
"""
self.frame_controls: tk.Frame = tk.Frame(self.root)
self.frame_controls.pack(pady=10)
tk.Label(self.frame_controls, text="Количество поставщиков:").grid(row=0, column=0)
self.entry_suppliers: tk.Entry = tk.Entry(self.frame_controls, width=5)
self.entry_suppliers.insert(0, str(self.suppliers))
self.entry_suppliers.grid(row=0, column=1)
tk.Label(self.frame_controls, text="Количество потребителей:").grid(row=0, column=2)
self.entry_consumers: tk.Entry = tk.Entry(self.frame_controls, width=5)
self.entry_consumers.insert(0, str(self.consumers))
self.entry_consumers.grid(row=0, column=3)
tk.Button(self.frame_controls, text="Применить", command=self.update_table).grid(row=0, column=4, padx=10)
self.frame_table: tk.Frame = tk.Frame(self.root)
self.frame_table.pack(pady=10)
self.update_table()
self.frame_buttons: tk.Frame = tk.Frame(self.root)
self.frame_buttons.pack(pady=10)
tk.Button(self.frame_buttons, text="Рассчитать", command=self.solve).pack()
def update_table(self) -> None:
"""
Обновление таблицы для ввода данных о поставщиках, потребителях, запасах и потребностях.
"""
self.suppliers = int(self.entry_suppliers.get())
self.consumers = int(self.entry_consumers.get())
for widget in self.frame_table.winfo_children():
widget.destroy()
self.entries_costs: List[List[tk.Entry]] = []
self.entries_supplies: List[tk.Entry] = []
self.entries_demands: List[tk.Entry] = []
# Заголовок "Пункт назначения"
tk.Label(self.frame_table, text="Пункт назначения").grid(row=0, column=1, columnspan=self.consumers)
tk.Label(self.frame_table, text="Пункт отправления").grid(row=1, column=0)
for j in range(self.consumers):
tk.Label(self.frame_table, text=f"B{j+1}").grid(row=1, column=j+1)
tk.Label(self.frame_table, text="Запас груза").grid(row=1, column=self.consumers+1)
# Данные для поставщиков
for i in range(self.suppliers):
tk.Label(self.frame_table, text=f"A{i+1}").grid(row=i+2, column=0)
row_entries: List[tk.Entry] = []
for j in range(self.consumers):
entry: tk.Entry = tk.Entry(self.frame_table, width=5)
entry.grid(row=i+2, column=j+1)
row_entries.append(entry)
self.entries_costs.append(row_entries)
entry_supply: tk.Entry = tk.Entry(self.frame_table, width=5)
entry_supply.grid(row=i+2, column=self.consumers+1)
self.entries_supplies.append(entry_supply)
# Данные для потребителей
tk.Label(self.frame_table, text="Потребность в грузе").grid(row=self.suppliers+2, column=0)
for j in range(self.consumers):
entry_demand: tk.Entry = tk.Entry(self.frame_table, width=5)
entry_demand.grid(row=self.suppliers+2, column=j+1)
self.entries_demands.append(entry_demand)
def solve(self) -> None:
"""
Решение транспортной задачи методом минимальных элементов.
Вычисляет и отображает результаты.
"""
try:
supplies: np.ndarray = np.array([int(entry.get()) for entry in self.entries_supplies])
demands: np.ndarray = np.array([int(entry.get()) for entry in self.entries_demands])
costs: np.ndarray = np.array([[int(entry.get()) for entry in row] for row in self.entries_costs], dtype=float)
if supplies.sum() != demands.sum():
messagebox.showerror("Ошибка", "Сумма запасов должна равняться сумме потребностей.")
return
# Создание копии массива для расчета итоговой стоимости
original_costs: np.ndarray = costs.copy()
allocation: np.ndarray = self.minimum_cost_method(supplies, demands, costs)
total_cost, abs_errors = self.calculate_results(allocation, original_costs)
self.show_results(allocation, total_cost, abs_errors)
except ValueError:
messagebox.showerror("Ошибка", "Все значения должны быть целыми числами.")
def minimum_cost_method(self, supplies: np.ndarray, demands: np.ndarray, costs: np.ndarray) -> np.ndarray:
"""
Метод минимальных элементов для решения транспортной задачи.
:param supplies: Запасы для поставщиков.
:param demands: Потребности для потребителей.
:param costs: Стоимость перевозки между поставщиками и потребителями.
:return: Распределение грузов между поставщиками и потребителями.
"""
allocation: np.ndarray = np.zeros_like(costs)
while supplies.sum() > 0 and demands.sum() > 0:
min_index: Tuple[int, int] = np.unravel_index(np.argmin(costs, axis=None), costs.shape) # type: ignore
i, j = min_index
qty: int = min(supplies[i], demands[j])
allocation[i, j] = qty
supplies[i] -= qty
demands[j] -= qty
costs[i, j] = np.inf # Исключить обработанную клетку
return allocation
def calculate_results(self, allocation: np.ndarray, costs: np.ndarray) -> Tuple[float, np.ndarray]:
"""
Подсчет общей стоимости перевозок и абсолютных погрешностей для решения задачи.
:param allocation: Распределение грузов между поставщиками и потребителями.
:param costs: Стоимость перевозки между поставщиками и потребителями.
:return: Общая стоимость перевозок и массив абсолютных погрешностей.
"""
# Замена np.inf на 0 для расчётов
costs_no_inf: np.ndarray = np.where(costs == np.inf, 0, costs)
total_cost: float = np.sum(allocation * costs_no_inf)
abs_errors: np.ndarray = allocation * 0.05 # 5% допустимая погрешность
return total_cost, abs_errors
def show_results(self, allocation: np.ndarray, total_cost: float, abs_errors: np.ndarray) -> None:
"""
Отображение результатов решения задачи.
:param allocation: Распределение грузов между поставщиками и потребителями.
:param total_cost: Общая стоимость перевозок.
:param abs_errors: Абсолютные погрешности для каждого элемента распределения.
"""
results_window: tk.Toplevel = tk.Toplevel(self.root)
results_window.title("Результаты")
tk.Label(results_window, text="Распределение грузов:").pack(pady=5)
allocation_text: tk.Text = tk.Text(results_window, height=10, width=50)
allocation_text.insert(tk.END, str(allocation))
allocation_text.config(state=tk.DISABLED)
allocation_text.pack()
tk.Label(results_window, text=f"Общая стоимость перевозок: {total_cost}").pack(pady=5)
tk.Label(results_window, text="Абсолютные погрешности:").pack(pady=5)
errors_text: tk.Text = tk.Text(results_window, height=10, width=50)
errors_text.insert(tk.END, str(abs_errors))
errors_text.config(state=tk.DISABLED)
errors_text.pack()
if __name__ == "__main__":
root: tk.Tk = tk.Tk()
app: TransportProblemApp = TransportProblemApp(root)
root.mainloop()