import sys from PyQt6.QtWidgets import ( QMessageBox, QMainWindow, QLabel, QComboBox, QPushButton, QFormLayout, QWidget, QLineEdit, QHBoxLayout, QLayout, QApplication, ) from PyQt6.QtCore import Qt import numpy as np import task import algorithm import solution class DisplayField(QWidget): label_text: str def __init__(self, parent, label_text="", text=""): super().__init__(parent) self._layout = QHBoxLayout(self) self._layout.setContentsMargins(0, 0, 0, 0) self.label_text = label_text self.text = QLabel(f"{self.label_text}{text}") self.text.setAlignment(Qt.AlignmentFlag.AlignLeft) self._layout.addWidget(self.text) def set_visible(self, visible): self.text.setVisible(visible) def set_text(self, text): self.text.setText(f"{self.label_text}{text}") class InputField(QWidget): value: str change_func: callable = None def __init__( self, parent, label_text="", placeholder_text="", lineedit_text="", label_position="left", ): super().__init__(parent) self._layout = QHBoxLayout(self) self._layout.setContentsMargins(0, 0, 0, 0) self.label = QLabel(label_text) self.lineedit = QLineEdit(lineedit_text) self.lineedit.setPlaceholderText(placeholder_text) self.lineedit.setMinimumWidth(50) if label_position == "left": self._layout.addWidget(self.label) self._layout.addWidget(self.lineedit) elif label_position == "right": self._layout.addWidget(self.lineedit) self._layout.addWidget(self.label) elif label_position == "none": self._layout.addWidget(self.lineedit) self.value = self.get_value() self.lineedit.textChanged.connect(self._on_change) def get_value(self): return self.lineedit.text() def set_value(self, value): self.lineedit.setText(value) def on_change(self, func): self.change_func = func def _on_change(self): if self.change_func: self.change_func(self) self.value = self.get_value() def on_input_float_number(widget: InputField): try: str_value = widget.get_value() if not (str_value == "" or str_value == "-"): widget.value = str(float(str_value)) except: widget.set_value(str(widget.value)) def on_input_int_number(widget: InputField): try: str_value = widget.get_value() if not (str_value == "" or str_value == "-"): widget.value = str(int(str_value)) except: widget.set_value(str(widget.value)) class MatrixRowWidget(QWidget): x_inputs: list[InputField] b_input: InputField def __init__(self, parent, i: int, n: int): super().__init__(parent) self._layout = QHBoxLayout() self._layout.setContentsMargins(0, 0, 0, 0) self.x_inputs = [] for j in range(n): inp = InputField(self, f"x{j + 1}", "", "0.0", "right") inp.lineedit.setAlignment(Qt.AlignmentFlag.AlignRight) self.x_inputs.append(inp) self._layout.addWidget(inp) if j != n - 1: self._layout.addWidget(QLabel(" + ")) self._layout.addWidget(QLabel(" = ")) self.b_input = InputField(self, "", "", "0.0", "none") self.b_input.lineedit.setAlignment(Qt.AlignmentFlag.AlignCenter) self._layout.addWidget(self.b_input) self.setLayout(self._layout) def get_value_x(self, i: int): return self.x_inputs[i].get_value() def get_value_b(self): return self.b_input.get_value() def on_change(self, func): for inp in self.x_inputs: inp.on_change(func) self.b_input.on_change(func) class MatrixWidget(QWidget): rows: list[MatrixRowWidget] _layout: QFormLayout on_change_func = None def __init__(self, parent, n: int): super().__init__(parent) self._initialize() self._create(n) def _initialize(self): self.rows = [] self._layout = QFormLayout() self._layout.setContentsMargins(0, 0, 0, 0) def _create(self, n: int): for i in range(n): self.rows.append(MatrixRowWidget(self, i, n)) for row in self.rows: self._layout.addRow(row) if self.on_change_func: row.on_change(self.on_change_func) self.setLayout(self._layout) def recreate(self, n: int): for row in self.rows: row.deleteLater() self.rows = [] self._create(n) def set_value_x(self, i: int, j: int, value: float): self.rows[i].x_inputs[j].set_value(value) def set_value_b(self, i: int, value: float): self.rows[i].b_input.set_value(value) def get_value_x(self, i: int, j: int): return self.rows[i].get_value_x(j) def get_value_b(self, i: int): return self.rows[i].get_value_b() def on_change(self, func): self.on_change_func = func for row in self.rows: if self.on_change_func: row.on_change(self.on_change_func) class MainWindow(QMainWindow): initialized = False matrix_a: np.matrix matrix_b: np.matrix eps_input: InputField n_input: InputField det_display: DisplayField cond_display: DisplayField def __init__(self): super().__init__() self.setupUI() self.initialized = True self.update_stats() def setupUI(self): self.setWindowTitle("Лабораторная работа №3") self.resize(700, 200) self.central_widget = QWidget() self.setCentralWidget(self.central_widget) layout = QFormLayout() label1 = QLabel("Вариант 6", self) layout.addWidget(label1) inputs_row = QWidget() inputs_row_layout = QHBoxLayout() self.n_input = InputField(self, " n: ", "число строк", str(4), "left") self.n_input.on_change(lambda w: self.on_n_input_changed(w)) inputs_row_layout.addWidget(self.n_input) self.eps_input = InputField(self, " eps: ", "точность", str(0.001), "left") self.eps_input.on_change(lambda w: self.on_eps_input_changed(w)) inputs_row_layout.addWidget(self.eps_input) inputs_row.setLayout(inputs_row_layout) layout.addWidget(inputs_row) buttons_row = QWidget() buttons_row_layout = QHBoxLayout() buttons_row_layout.setContentsMargins(0, 0, 0, 0) self.reset_button = QPushButton("Сбросить", self) self.reset_button.clicked.connect(self.on_reset_button_clicked) buttons_row_layout.addWidget(self.reset_button) self.paste_button = QPushButton("Вставить", self) self.paste_button.clicked.connect(self.on_paste_button_clicked) buttons_row_layout.addWidget(self.paste_button) self.random_button = QPushButton("Случайная", self) self.random_button.clicked.connect(self.on_random_button_clicked) buttons_row_layout.addWidget(self.random_button) buttons_row.setLayout(buttons_row_layout) layout.addWidget(buttons_row) self.matrix = MatrixWidget(self, 4) self.matrix.on_change(lambda w: self.on_matrix_changed(w)) self.set_matrix(task.A(), task.B()) layout.addWidget(self.matrix) self.det_display = DisplayField(self, "Определитель: ", "") layout.addWidget(self.det_display) self.cond_display = DisplayField(self, "Число обусловленности: ", "") layout.addWidget(self.cond_display) find_solution_button = QPushButton("Решить", self) find_solution_button.clicked.connect(self.on_find_solution_clicked) layout.addWidget(find_solution_button) self.solution_display = DisplayField(self, "Решение: ", "") layout.addWidget(self.solution_display) self.solution_display.set_visible(False) self.central_widget.setLayout(layout) def on_eps_input_changed(self, widget: InputField): on_input_float_number(widget) eps = widget.get_value() try: if float(eps) < 0: eps = 0 self.eps_input.set_value(eps) except: return def on_random_button_clicked(self): n = int(self.n_input.get_value()) self.matrix_a = np.round(np.random.rand(n, n) * 10, 2) self.matrix_b = np.round(np.random.rand(n, 1) * 10, 2) self.set_matrix(self.matrix_a, self.matrix_b) def on_find_solution_clicked(self): try: print(f"Numpy solution: {np.linalg.solve(self.matrix_a, self.matrix_b)}") except: print("Numpy could not solve the system") try: eps = float(self.eps_input.get_value()) except: eps = 0 x = solution.iterative_method(self.matrix_a, self.matrix_b, eps) print(f"Iterative solution: {x}") if x is None: self.solution_display.set_visible(True) self.solution_display.set_text("Нет решения") else: self.solution_display.set_visible(True) solution_text = "\n" for i in range(x.shape[0]): solution_text += f"x{i + 1} = {x[i, 0]:.5f}" if i < x.shape[0] - 1: solution_text += "\n" self.solution_display.set_text(solution_text) def on_paste_button_clicked(self): text = QApplication.clipboard().text() try: input_np = np.fromstring(text, dtype=np.float64, sep=" ") n = 0.5 * (np.sqrt(4.0 * input_np.shape[0] + 1.0) - 1.0) if n % 1.0 != 0.0: return n = int(n) input_np = np.reshape(input_np, (n, n + 1)) self.n_input.set_value(str(n)) self.matrix_a = np.copy(input_np[:n, :n]) self.matrix_b = np.copy(input_np[:n, n:]) self.set_matrix(self.matrix_a, self.matrix_b) except Exception as e: print(e) return def on_n_input_changed(self, widget: InputField): MAX_N = 8 on_input_int_number(widget) try: n = int(widget.get_value()) if n < 1: widget.set_value(str(1)) return if n > MAX_N: widget.set_value(str(MAX_N)) return self.matrix.recreate(int(self.n_input.get_value())) self.input_matrix_from_widget() self.update_stats() except: return def on_reset_button_clicked(self): self.n_input.set_value(str(4)) self.eps_input.set_value(str(0.001)) self.set_matrix(task.A(), task.B()) def on_matrix_changed(self, widget: InputField): on_input_float_number(widget) try: self.input_matrix_from_widget() self.update_stats() except: return def input_matrix_from_widget(self): try: self.matrix_a = np.matrix( [ [ self.matrix.get_value_x(i, j) for j in range(self.matrix.rows[0].x_inputs.__len__()) ] for i in range(self.matrix.rows.__len__()) ], dtype=np.float64, ) self.matrix_b = np.matrix( [ [self.matrix.get_value_b(i)] for i in range(self.matrix.rows.__len__()) ], dtype=np.float64, ) except: return def update_stats(self): if not self.initialized: return self.solution_display.set_visible(False) try: self.det_display.set_text(f"{algorithm.det(self.matrix_a):.5f}") except: self.det_display.set_text("Невозможно вычислить") try: self.cond_display.set_text(f"{algorithm.cond(self.matrix_a):.5f}") except: self.cond_display.set_text("Невозможно вычислить") def set_matrix(self, A: np.matrix, B: np.matrix): for i in range(A.shape[0]): for j in range(A.shape[1]): self.matrix.set_value_x(i, j, str(A[i, j])) for i in range(B.shape[0]): self.matrix.set_value_b(i, str(B[i, 0])) self.update_stats()