diff --git "a/\320\2403212/metel_409127/lab1/Task.py" "b/\320\2403212/metel_409127/lab1/Task.py" new file mode 100644 index 0000000..8653482 --- /dev/null +++ "b/\320\2403212/metel_409127/lab1/Task.py" @@ -0,0 +1,237 @@ +import numpy as np +import os + +class GaussMethod: + def __init__(self, matrix, vector_b=None): + """ + Инициализация метода Гаусса + :param matrix: Матрица коэффициентов системы + :param vector_b: Вектор правых частей (если None, берется последний столбец матрицы) + """ + if vector_b is None: + # Если вектор b не передан, считаем, что последний столбец матрицы - это вектор b + self.A = np.array(matrix[:, :-1], dtype=float) + self.b = np.array(matrix[:, -1], dtype=float) + else: + self.A = np.array(matrix, dtype=float) + self.b = np.array(vector_b, dtype=float) + + self.n = len(self.b) + self.x = np.zeros(self.n) + self.residuals = np.zeros(self.n) + self.determinant = 1.0 + + # Сохраняем исходные данные для вычисления невязок + self.original_A = self.A.copy() + self.original_b = self.b.copy() + + # Создаем расширенную матрицу для метода Гаусса + self.augmented = np.column_stack((self.A, self.b)) + + def solve(self): + """ + Решение системы методом Гаусса с выбором главного элемента + """ + # Прямой ход метода Гаусса с выбором главного элемента + for i in range(self.n): + # Поиск максимального элемента в текущем столбце + max_row = i + max_val = abs(self.augmented[i, i]) + + for k in range(i + 1, self.n): + if abs(self.augmented[k, i]) > max_val: + max_val = abs(self.augmented[k, i]) + max_row = k + + # Обмен строк, если найден больший элемент + if max_row != i: + self.augmented[[i, max_row]] = self.augmented[[max_row, i]] + self.determinant *= -1 # При обмене строк определитель меняет знак + + # Если главный элемент равен нулю, матрица вырожденная + if abs(self.augmented[i, i]) < 1e-10: + self.determinant = 0 + return False + + # Обновление определителя + self.determinant *= self.augmented[i, i] + + # Вычитание из всех строк ниже (без нормализации текущей строки) + pivot = self.augmented[i, i] + for j in range(i + 1, self.n): + factor = self.augmented[j, i] / pivot + self.augmented[j] -= factor * self.augmented[i] + + # Обратный ход метода Гаусса + for i in range(self.n - 1, -1, -1): + self.x[i] = self.augmented[i, -1] + for j in range(i + 1, self.n): + self.x[i] -= self.augmented[i, j] * self.x[j] + self.x[i] /= self.augmented[i, i] # Делим на диагональный элемент + + # Вычисление невязок + self.calculate_residuals() + + return True + + def calculate_residuals(self): + """ + Вычисление вектора невязок r = Ax - b + """ + for i in range(self.n): + self.residuals[i] = -self.original_b[i] + for j in range(self.n): + self.residuals[i] += self.original_A[i, j] * self.x[j] + + def get_triangular_matrix(self): + """ + Возвращает треугольную матрицу после прямого хода метода Гаусса + """ + return self.augmented[:, :-1] + + def get_determinant(self): + """ + Возвращает определитель матрицы + """ + return self.determinant + + def get_solution(self): + """ + Возвращает вектор решения + """ + return self.x + + def get_residuals(self): + """ + Возвращает вектор невязок + """ + return self.residuals + + +def read_matrix_from_file(filename): + """ + Чтение матрицы из файла + """ + with open(filename, 'r') as file: + lines = file.readlines() + + matrix = [] + for line in lines: + row = [float(x) for x in line.strip().split()] + matrix.append(row) + + return np.array(matrix) + + +def input_matrix_manually(): + """ + Ввод матрицы с клавиатуры + """ + n = int(input("Введите размерность матрицы (n <= 20): ")) + if n > 20: + print("Размерность матрицы должна быть не более 20") + return input_matrix_manually() + + print(f"Введите {n} строк матрицы (включая столбец свободных членов):") + matrix = [] + for i in range(n): + while True: + try: + row = list(map(float, input(f"Строка {i+1}: ").strip().split())) + if len(row) != n + 1: + print(f"Строка должна содержать {n+1} чисел") + continue + matrix.append(row) + break + except ValueError: + print("Ошибка ввода. Введите числа, разделенные пробелами") + + return np.array(matrix) + + +def main(): + print("Решение СЛАУ методом Гаусса с выбором главного элемента") + print("=" * 60) + input_choice = input("Введите имя файла или нажмите Enter для ручного ввода: ") + matrix = None + if input_choice.strip(): + while True: + try: + matrix = read_matrix_from_file(input_choice) + break + except FileNotFoundError: + input_choice = input("Файл не найден. Попробуйте снова или нажмите Enter для ручного ввода: ") + if not input_choice.strip(): + break + except Exception as e: + print(f"Ошибка при чтении файла: {e}") + input_choice = input("Попробуйте снова или нажмите Enter для ручного ввода: ") + if not input_choice.strip(): + break + + if matrix is None: + matrix = input_matrix_manually() + + # Решение системы + gauss = GaussMethod(matrix) + success = gauss.solve() + + if not success: + print("Матрица вырожденная, решение не существует") + return + + # Вывод результатов + print("\nРезультаты:") + print("-" * 60) + + print("\nТреугольная матрица:") + triangular = gauss.get_triangular_matrix() + for row in triangular: + print(" ".join(f"{x:10.6f}" for x in row)) + + print("\nОпределитель матрицы:") + print(f"{gauss.get_determinant():10.6f}") + + print("\nВектор неизвестных:") + solution = gauss.get_solution() + for i, x in enumerate(solution): + print(f"x{i+1} = {x:10.6f}") + + print("\nВектор невязок:") + residuals = gauss.get_residuals() + for i, r in enumerate(residuals): + print(f"r{i+1} = {r:10.6e}") + + # Сравнение с библиотечным решением + print("\nСравнение с библиотечным решением:") + print("-" * 60) + + A = matrix[:, :-1] + b = matrix[:, -1] + + try: + # Решение с помощью numpy + numpy_solution = np.linalg.solve(A, b) + numpy_det = np.linalg.det(A) + + print("\nРешение с помощью numpy:") + for i, x in enumerate(numpy_solution): + print(f"x{i+1} = {x:10.6f}") + + print(f"\nОпределитель (numpy): {numpy_det:10.6f}") + + # Сравнение решений + diff = np.linalg.norm(solution - numpy_solution) + print(f"\nРазница между решениями: {diff:10.6e}") + + if diff < 1e-10: + print("Решения совпадают с высокой точностью") + else: + print("Есть различия в решениях") + + except np.linalg.LinAlgError: + print("Библиотека numpy не смогла решить систему (вырожденная матрица)") + + +if __name__ == "__main__": + main() diff --git "a/\320\2403212/metel_409127/lab1/\320\222\321\213\321\207\320\274\320\260\321\202_\342\204\2261.docx" "b/\320\2403212/metel_409127/lab1/\320\222\321\213\321\207\320\274\320\260\321\202_\342\204\2261.docx" new file mode 100644 index 0000000..39c7401 Binary files /dev/null and "b/\320\2403212/metel_409127/lab1/\320\222\321\213\321\207\320\274\320\260\321\202_\342\204\2261.docx" differ diff --git "a/\320\2403212/metel_409127/lab2/Task2.py" "b/\320\2403212/metel_409127/lab2/Task2.py" new file mode 100644 index 0000000..3338540 --- /dev/null +++ "b/\320\2403212/metel_409127/lab2/Task2.py" @@ -0,0 +1,292 @@ +import math +import random +import numpy as np +import matplotlib.pyplot as plt + +def r_uravnenie(degree, min_k, max_k): + + koefs = [random.randint(min_k, max_k) for _ in range(degree + 1)] + def uravnenie(x): + return sum(koefs[i] * x**i for i in range(len(koefs))) + return uravnenie, koefs + + +def plot_function_system(f_system, x_min, x_max, y_min, y_max, root, title="График системы с решением"): + def f1(x, y): + return f_system([x, y])[0] + + def f2(x, y): + return f_system([x, y])[1] + + X, Y = np.meshgrid( + np.linspace(x_min, x_max, 300), + np.linspace(y_min, y_max, 300) + ) + + Z1 = np.zeros_like(X) + Z2 = np.zeros_like(X) + + for i in range(X.shape[0]): + for j in range(X.shape[1]): + Z1[i, j] = f1(X[i, j], Y[i, j]) + Z2[i, j] = f2(X[i, j], Y[i, j]) + + plt.figure(figsize=(7, 6)) + + plt.contour(X, Y, Z1, levels=[0], colors='red') + plt.contour(X, Y, Z2, levels=[0], colors='blue') + + + x, y = root + plt.axhline(0, color='black', linewidth=0.8) + plt.axvline(0, color='black', linewidth=0.8) + + plt.plot(x, y, 'go', label=f'Решение ({x:.4f}, {y:.4f})') + plt.text(x, y, f"({x:.4f}, {y:.4f})", fontsize=9, ha='left', va='bottom') + + plt.grid(True) + plt.xlim(x_min, x_max) + plt.ylim(y_min, y_max) + plt.title(title) + plt.legend() + plt.show() + + +def p_r_uravnenie(koefs): + + p_koefs = [] + for i in range(1, len(koefs)): + p_koefs.append(i * koefs[i]) + def p_uravnenie(x): + return sum(p_koefs[i] * x**i for i in range(len(p_koefs))) + return p_uravnenie, p_koefs + + + +def f_example(x): + # return math.cos(2*x) - 7 * math.sin(x) - 4 + return x**3 - x + 4 + +def df_example(x): + # return -2 * math.sin(2 * x) - 7 * math.cos(x) + return 3*x**2 - 1 + + + +def f_system(vars_xy): + x, y = vars_xy + # return np.array([ + # math.cos(x - 1) + y - 0.5, + # x - math.cos(y) - 3 + # ]) + return np.array([ + x**2 + y**2 - 4, + y - 3*x**2 + ]) + +def df_system(vars_xy): + x, y = vars_xy + # return np.array([ + # [-math.sin(x - 1), 1], + # [1, math.sin(y)] + # ]) + return np.array([ + [2*x, 2*y], + [-6*x, 1] + ]) + +def plot_function(f, a, b,root, title="График функции"): + + x_vals = np.linspace(a, b, 400) + y_vals = [f(x) for x in x_vals] + plt.figure(figsize=(7, 4)) + plt.plot(x_vals, y_vals, label='f(x)') + plt.axhline(0, color='black', linewidth=0.8) + + y_root = f(root) + plt.plot(root, y_root, 'ro', label=f'Решение: x={root:.4f}') + plt.text(root, y_root, f"({root:.4f}, {y_root:.4f})", fontsize=9, ha='left', va='bottom') + + plt.grid(True) + plt.xlim(a, b) + ymin, ymax = min(y_vals), max(y_vals) + plt.ylim(ymin - abs(ymin)*0.1, ymax + abs(ymax)*0.1) + plt.title(title) + plt.legend() + plt.show() + + +def bisection_method(f, a, b, accuracy, m_c): + if f(a) * f(b) > 0: + raise ValueError("На отрезке [a, b] функция не меняет знак. Корень может отсутствовать или быть не единственным.") + + count = 0 + while count < int(m_c): + count += 1 + x = (a + b) / 2 + if abs(f(x)) <= accuracy or abs(b - a) <= accuracy: + return x, count, f(x) + + if f(a) * f(x) < 0: + b = x + else: + a = x + + x = (a + b) / 2 + return x, count, f(x) + + +def secant_method(f, x0, x1, accuracy, m_c): + count = 0 + for _ in range(int(m_c)): + count += 1 + value_in_x0 = f(x0) + value_in_x1 = f(x1) + if abs(value_in_x1 - value_in_x0) < 1e-14: + raise ZeroDivisionError("Разница f(x1) и f(x0) слишком мала, деление невозможно.") + x2 = x1 - value_in_x1 * (x1 - x0) / (value_in_x1 - value_in_x0) + if abs(x2 - x1) < accuracy: + return x2, count, f(x2) + x0, x1 = x1, x2 + return x2, count, f(x2) + + +def iteration_easy_method(fi, x0, accuracy, m_c): + count = 0 + for _ in range(int(m_c)): + count += 1 + x1 = fi(x0) + if abs(x1 - x0) < accuracy: + return x1, count + x0 = x1 + return x0, count + + +def compute_alpha(df, a, b, steps=100): + mas_val = np.linspace(a, b, steps) + max_val = max(abs(df(x)) for x in mas_val) + if (max_val == 0): + max_val = 1 + return 1.0 / max_val + + + +def newton_method_system(fun, dfun, x0, accuracy, count): + x = np.array(x0, dtype=float) + for i in range(count): + F = fun(x) + dF = dfun(x) + try: + delta = np.linalg.solve(dF, F) + except np.linalg.LinAlgError: + return x, i + x_new = x - delta + + + if abs(x_new[0] - x[0]) <= accuracy and abs(x_new[1] - x[1]) <= accuracy: + return x_new, i + 1 + x = x_new + return x, count + + + + +def main(): + print("Хотите решить ОДНОМЕРНОЕ уравнение или СИСТЕМУ?") + print("1) Одномерное уравнение") + print("2) Система (метод Ньютона)") + choice_global = input("Выберите (1 или 2): ") + + if choice_global == '1': + print("1) Использовать случайное уравнение?") + print("2) Использовать функцию ?") + choice = input("Выберите (1 или 2): ") + + if choice == '1': + deg = int(input("Введите степень случайного уравнения: ")) + poly, coeffs = r_uravnenie(deg, -5, 5) + print(f"Случайно сгенерированное уравнение (коэффициенты): {coeffs[::-1]}") + f = poly + dpoly, dcoeffs = p_r_uravnenie(coeffs) + df = dpoly + else: + f = f_example + df = df_example + + print("Введите границы интервала (a b): ") + inp = input().split() + a = float(inp[0]) + b = float(inp[1]) + + # plot_function(f, a, b, title="График выбранной функции на интервале") + + print("Введите требуемую точность: ") + accuracy = float(input()) + + print("Введите максимальное число итераций: ") + count = int(input()) + + print("Какой метод использовать?") + print("1) Метод половинного деления") + print("2) Метод секущих") + print("3) Метод простой итерации") + choice_method = input("Выберите (1, 2, 3): ") + + if choice_method == '1': + try: + root, n_iter, f_val = bisection_method(f, a, b, accuracy, count) + print(f"\nМетод половинного деления:\nНайденный корень: {root}\nКоличество итераций: {n_iter}\nf(root) = {f_val}") + plot_function(f, a, b, root, title="График выбранной функции на интервале") + except ValueError as e: + print(f"Ошибка: {e}") + + elif choice_method == '2': + try: + root, n_iter, f_val = secant_method(f, a, b, accuracy, count) + print(f"\nМетод секущих:\nНайденный корень: {root}\nКоличество итераций: {n_iter}\nf(root) = {f_val}") + plot_function(f, a, b, root, title="График выбранной функции на интервале") + except ZeroDivisionError as e: + print(f"Ошибка: {e}") + + elif choice_method == '3': + alpha = compute_alpha(df, a, b) + print(f"Вычислен alpha = {alpha}") + def fi(x): + return x - alpha * f(x) + x0 = (a + b) / 2 + + root, n_iter = iteration_easy_method(fi, x0, accuracy, count) + print(f"\nМетод простой итерации:\nНайденный корень: {root}\nКоличество итераций: {n_iter}\nf(root) = {f(root)}") + plot_function(f, a, b, root, title="График выбранной функции на интервале") + else: + print("Неправильный выбор метода!") + + else: + print("Решаем систему методом Ньютона.") + print("Для демонстрации возьмём систему со слайдов:\n 1) x^2 + y^2 = 4\n 2) y - 3x^2 = 0\n") + + print("Введите начальное приближение (x0, y0): ") + inp = input().split() + x0 = float(inp[0]) + y0 = float(inp[1]) + + print("Введите требуемую точность: ") + accuracy = float(input()) + + print("Введите максимальное число итераций: ") + count = int(input()) + + root, iters = newton_method_system(f_system, df_system, [x0, y0], accuracy, count) + if (root[0] == x0 and root[1] == y0) and (f_system([x0, y0])[0] != 0 or f_system([x0, y0])[1] != 0): + root, iters = newton_method_system(f_system, df_system, [x0 + accuracy, y0 + accuracy], accuracy, count) + print(f_system([0, 0])) + print("\nМетод Ньютона") + print(f"Решения: x = {root[0]:.6f}, y = {root[1]:.6f}") + print(f"Число итераций: {iters}") + print(f"f1(x,y) = {f_system(root)[0]:.6e}") + print(f"f2(x,y) = {f_system(root)[1]:.6e}") + plot_function_system(f_system, root[0] - 3, root[0] + 3, root[1] - 3, root[1] + 3, root, title="График системы с решением") + + +if __name__ == "__main__": + main() diff --git "a/\320\2403212/metel_409127/lab2/\320\222\321\213\321\207\320\274\320\260\321\2022.docx" "b/\320\2403212/metel_409127/lab2/\320\222\321\213\321\207\320\274\320\260\321\2022.docx" new file mode 100644 index 0000000..806b3d8 Binary files /dev/null and "b/\320\2403212/metel_409127/lab2/\320\222\321\213\321\207\320\274\320\260\321\2022.docx" differ diff --git "a/\320\2403212/metel_409127/lab3/Vich_Mat_3.py" "b/\320\2403212/metel_409127/lab3/Vich_Mat_3.py" new file mode 100644 index 0000000..72284ed --- /dev/null +++ "b/\320\2403212/metel_409127/lab3/Vich_Mat_3.py" @@ -0,0 +1,123 @@ +import math +import random +import numpy as np + +def generate_polynomial(degree, min_val, max_val): + coeffs = [random.randint(min_val, max_val) for _ in range(degree + 1)] + def poly(x_val): + return sum(coeffs[i] * x_val**i for i in range(len(coeffs))) + return poly, coeffs + +def derive_polynomial(coeffs): + derived = [i * coeffs[i] for i in range(1, len(coeffs))] + def derived_poly(x_val): + return sum(derived[i] * x_val**i for i in range(len(derived))) + return derived_poly, derived + +def sample_func(x): + return x**4 / 10 + x**2 / 5 - 7 + +def first_derivative(x): + return 0.4 * x**3 + 0.4 * x + +def second_derivative(x): + return 1.2 * x**2 + 0.4 + +def third_derivative(x): + return 2.4 * x + +def fourth_derivative(x): + return 2.4 + +def rectangle_integrate_full(f, f_dd, left, right, eps, variant, parts=100): + grid = np.linspace(left, right, parts) + max_d2 = max(abs(f_dd(pt)) for pt in grid) + n = int(((max_d2 * (right - left) ** 3) / (24 * eps)) ** 0.5) + 1 + prev = rectangle_integrate(f, left, right, n, variant) + for iteration in range(1000): + n *= 2 + curr = rectangle_integrate(f, left, right, n, variant) + if abs(curr - prev) < eps: + return curr, iteration + 1 + prev = curr + return prev, 1000 + +def rectangle_integrate(f, left, right, segments, variant): + h = (right - left) / segments + acc = 0 + if variant == 1: + acc = sum(f(left + i * h) for i in range(segments)) + elif variant == 2: + acc = sum(f(left + i * h) for i in range(1, segments + 1)) + else: + acc = sum(f(left + (i + 0.5) * h) for i in range(segments)) + return acc * h + +def trapezoid_integrate_full(f, f_dd, left, right, eps, steps=100): + points = np.linspace(left, right, steps) + m2 = max(abs(f_dd(x)) for x in points) + n = int(((m2 * (right - left)**3) / (12 * eps))**0.5) + 2 + prev = trapezoid_integrate(f, left, right, n) + for iteration in range(1000): + n *= 2 + curr = trapezoid_integrate(f, left, right, n) + if abs(curr - prev) <= eps: + return curr, iteration + 1 + prev = curr + return prev, 1000 + +def trapezoid_integrate(f, a, b, n): + h = (b - a) / n + acc = 0.5 * (f(a) + f(b)) + acc += sum(f(a + i * h) for i in range(1, n)) + return acc * h + +def simpsons_integrate_full(f, d4f, a, b, eps, precision=100): + samples = np.linspace(a, b, precision) + m4 = max(abs(d4f(x)) for x in samples) + n = int(((m4 * (b - a) ** 5) / (180 * eps)) ** 0.25) + if n % 2 != 0: + n += 1 + prev = simpsons_integrate(f, a, b, n) + for iteration in range(1000): + n *= 2 + curr = simpsons_integrate(f, a, b, n) + if abs(curr - prev) <= eps: + return curr, iteration + 1 + prev = curr + return prev, 1000 + +def simpsons_integrate(f, a, b, n): + h = (b - a) / n + acc = f(a) + f(b) + for i in range(1, n): + coeff = 4 if i % 2 else 2 + acc += coeff * f(a + i * h) + return acc * h / 3 + +def improper_integral(f, f_dd, a, b, eps, singular_point, middle=0): + delta = 0.001 * (b - a) + result = None + if singular_point == 'a': + for _ in range(500): + current, _ = trapezoid_integrate_full(f, f_dd, a + delta, b, eps) + if result is not None and abs(current - result) < eps: + return current + result = current + delta /= 2 + elif singular_point == 'b': + for _ in range(500): + current, _ = trapezoid_integrate_full(f, f_dd, a, b - delta, eps) + if result is not None and abs(current - result) < eps: + return current + result = current + delta /= 2 + elif singular_point == 'c': + for _ in range(500): + left, _ = trapezoid_integrate_full(f, f_dd, a, middle - delta, eps) + right, _ = trapezoid_integrate_full(f, f_dd, middle + delta, b, eps) + total = left + right + if result is not None and abs(total - result) < eps: + return total + result = total + delta /= 2 diff --git "a/\320\2403212/metel_409127/lab4/Lab4.py" "b/\320\2403212/metel_409127/lab4/Lab4.py" new file mode 100644 index 0000000..ec5220c --- /dev/null +++ "b/\320\2403212/metel_409127/lab4/Lab4.py" @@ -0,0 +1,487 @@ +import numpy as np +import matplotlib.pyplot as plt +from scipy import optimize +import sys +import os +import re + +class ApproximationMethod: + def __init__(self): + self.x = None + self.y = None + self.n = 0 + self.approximations = {} + self.best_approximation = None + + def input_data(self, source='console'): + if source == 'console': + while True: + try: + n = input("Введите количество точек (8-12): ") + self.n = int(n) + if not 8 <= self.n <= 12: + print("Ошибка: Количество точек должно быть от 8 до 12. Попробуйте еще раз.") + continue + + self.x = np.zeros(self.n) + self.y = np.zeros(self.n) + + print("Введите пары значений x и y:") + i = 0 + while i < self.n: + try: + values = input(f"Точка {i+1} (x y): ").split() + if len(values) != 2: + print(f"Ошибка: Неверный формат ввода для точки {i+1}. Нужно ввести два числа, разделенных пробелом.") + continue + + x_val = float(values[0]) + y_val = float(values[1]) + self.x[i] = x_val + self.y[i] = y_val + i += 1 + except ValueError: + print(f"Ошибка: Введите числовые значения для точки {i+1}. Попробуйте еще раз.") + + return + except ValueError: + print("Ошибка: Введите корректное числовое значение для количества точек. Попробуйте еще раз.") + else: + attempts = 0 + max_attempts = 3 + while attempts < max_attempts: + try: + if not os.path.exists(source): + print(f"Ошибка: Файл {source} не найден. Попробуйте еще раз.") + source = input("Введите корректное имя файла: ") + attempts += 1 + continue + + with open(source, 'r') as f: + lines = f.readlines() + + points = [] + for line in lines: + matches = re.findall(r'-?\d+\.?\d*', line) + if len(matches) >= 2: + points.append((float(matches[0]), float(matches[1]))) + + self.n = len(points) + if not 8 <= self.n <= 12: + print(f"Ошибка: В файле {source} содержится {self.n} точек, а должно быть от 8 до 12.") + source = input("Введите другое имя файла: ") + attempts += 1 + continue + + self.x = np.array([point[0] for point in points]) + self.y = np.array([point[1] for point in points]) + return + + except Exception as e: + print(f"Ошибка при чтении файла: {e}") + if attempts < max_attempts - 1: + source = input("Введите другое имя файла: ") + attempts += 1 + + print(f"После {max_attempts} неудачных попыток чтения файла, переключаемся на ввод с консоли.") + self.input_data('console') + + def approximate(self): + if self.x is None or self.y is None or self.n == 0: + raise ValueError("Сначала введите данные") + + if np.isnan(self.x).any() or np.isnan(self.y).any() or np.isinf(self.x).any() or np.isinf(self.y).any(): + raise ValueError("Данные содержат недопустимые значения") + + self._linear_approximation() + self._polynomial_approximation(2) + self._polynomial_approximation(3) + self._exponential_approximation() + self._logarithmic_approximation() + self._power_approximation() + + self._find_best_approximation() + + def _linear_approximation(self): + try: + a, b = np.polyfit(self.x, self.y, 1) + f_x = a * self.x + b + errors = f_x - self.y + mse = np.mean(errors**2) #среднеарифмитическое + rmse = np.sqrt(mse) + r = np.corrcoef(self.x, self.y)[0, 1] + r_squared = r**2 + + self.approximations['linear'] = { + 'type': 'linear', + 'params': {'a': a, 'b': b}, + 'function': lambda x: a * x + b, + 'formula': f'f(x) = {a:.6f}*x + {b:.6f}', + 'f_x': f_x, + 'errors': errors, + 'rmse': rmse, + 'r': r, + 'r_squared': r_squared + } + except Exception as e: + print(f"Ошибка при линейной аппроксимации: {e}") + self.approximations['linear'] = None + + def _polynomial_approximation(self, degree): + try: + coeffs = np.polyfit(self.x, self.y, degree) + f_x = np.polyval(coeffs, self.x) + errors = f_x - self.y + mse = np.mean(errors**2) + rmse = np.sqrt(mse) + ss_total = np.sum((self.y - np.mean(self.y))**2) + ss_residual = np.sum(errors**2) + r_squared = 1 - (ss_residual / ss_total) + + formula = "f(x) = " + for i, coef in enumerate(coeffs): + power = degree - i + if power > 1: + formula += f"{coef:.6f}*x^{power} + " + elif power == 1: + formula += f"{coef:.6f}*x + " + else: + formula += f"{coef:.6f}" + + self.approximations[f'polynomial_{degree}'] = { + 'type': f'polynomial_{degree}', + 'params': {'coeffs': coeffs}, + 'function': lambda x: np.polyval(coeffs, x), + 'formula': formula, + 'f_x': f_x, + 'errors': errors, + 'rmse': rmse, + 'r_squared': r_squared + } + except Exception as e: + print(f"Ошибка при полиномиальной аппроксимации степени {degree}: {e}") + self.approximations[f'polynomial_{degree}'] = None + + def _exponential_approximation(self): + try: + if np.any(self.y <= 0): + raise ValueError("Экспоненциальная аппроксимация невозможна для отрицательных значений y") + + ln_y = np.log(self.y) + b, ln_a = np.polyfit(self.x, ln_y, 1) + a = np.exp(ln_a) + + def exp_func(x, a, b): + return a * np.exp(b * x) + + try: + params, _ = optimize.curve_fit(exp_func, self.x, self.y, p0=[a, b]) + a, b = params + except RuntimeError: + pass + + f_x = a * np.exp(b * self.x) + errors = f_x - self.y + mse = np.mean(errors**2) + rmse = np.sqrt(mse) + ss_total = np.sum((self.y - np.mean(self.y))**2) + ss_residual = np.sum(errors**2) + r_squared = 1 - (ss_residual / ss_total) + + self.approximations['exponential'] = { + 'type': 'exponential', + 'params': {'a': a, 'b': b}, + 'function': lambda x: a * np.exp(b * x), + 'formula': f'f(x) = {a:.6f}*exp({b:.6f}*x)', + 'f_x': f_x, + 'errors': errors, + 'rmse': rmse, + 'r_squared': r_squared + } + except Exception as e: + print(f"Ошибка при экспоненциальной аппроксимации: {e}") + self.approximations['exponential'] = None + + def _logarithmic_approximation(self): + try: + if np.any(self.x <= 0): + raise ValueError("Логарифмическая аппроксимация невозможна для отрицательных значений x") + + ln_x = np.log(self.x) + a, b = np.polyfit(ln_x, self.y, 1) + + f_x = a * np.log(self.x) + b + errors = f_x - self.y + mse = np.mean(errors**2) + rmse = np.sqrt(mse) + ss_total = np.sum((self.y - np.mean(self.y))**2) + ss_residual = np.sum(errors**2) + r_squared = 1 - (ss_residual / ss_total) + + self.approximations['logarithmic'] = { + 'type': 'logarithmic', + 'params': {'a': a, 'b': b}, + 'function': lambda x: a * np.log(x) + b, + 'formula': f'f(x) = {a:.6f}*ln(x) + {b:.6f}', + 'f_x': f_x, + 'errors': errors, + 'rmse': rmse, + 'r_squared': r_squared + } + except Exception as e: + print(f"Ошибка при логарифмической аппроксимации: {e}") + self.approximations['logarithmic'] = None + + def _power_approximation(self): + try: + if np.any(self.x <= 0) or np.any(self.y <= 0): + raise ValueError("Степенная аппроксимация невозможна для отрицательных значений x или y") + + ln_x = np.log(self.x) + ln_y = np.log(self.y) + b, ln_a = np.polyfit(ln_x, ln_y, 1) + a = np.exp(ln_a) + + f_x = a * np.power(self.x, b) + errors = f_x - self.y + mse = np.mean(errors**2) + rmse = np.sqrt(mse) + ss_total = np.sum((self.y - np.mean(self.y))**2) + ss_residual = np.sum(errors**2) + r_squared = 1 - (ss_residual / ss_total) + + self.approximations['power'] = { + 'type': 'power', + 'params': {'a': a, 'b': b}, + 'function': lambda x: a * np.power(x, b), + 'formula': f'f(x) = {a:.6f}*x^{b:.6f}', + 'f_x': f_x, + 'errors': errors, + 'rmse': rmse, + 'r_squared': r_squared + } + except Exception as e: + print(f"Ошибка при степенной аппроксимации: {e}") + self.approximations['power'] = None + + def _find_best_approximation(self): + min_rmse = float('inf') + for appr_type, data in self.approximations.items(): + if data is not None and data['rmse'] < min_rmse: + min_rmse = data['rmse'] + self.best_approximation = appr_type + + def print_results(self, output='console'): + if not self.approximations: + raise ValueError("Сначала выполните аппроксимацию") + + results = ["\n" + "="*80, "РЕЗУЛЬТАТЫ АППРОКСИМАЦИИ", "="*80] + + results.append(f"\nИсходные данные (всего {self.n} точек):") + for i in range(self.n): + results.append(f"Точка {i+1}: x = {self.x[i]:.6f}, y = {self.y[i]:.6f}") + + results.append("\nРезультаты аппроксимации:") + for appr_type, data in self.approximations.items(): + if data is None: + results.append(f"\n{appr_type.upper()}: не удалось выполнить аппроксимацию") + continue + + results.append(f"\n{appr_type.upper()}:") + results.append(f"Формула: {data['formula']}") + results.append(f"Среднеквадратическое отклонение (RMSE): {data['rmse']:.6f}") + + if appr_type == 'linear': + r = data['r'] + results.append(f"Коэффициент корреляции Пирсона: {r:.6f}") + r_abs = abs(r) + if r_abs < 0.3: + corr = "очень слабая" + elif r_abs < 0.5: + corr = "слабая" + elif r_abs < 0.7: + corr = "средняя" + elif r_abs < 0.9: + corr = "сильная" + else: + corr = "очень сильная" + direction = "положительная" if r > 0 else "отрицательная" + results.append(f"Интерпретация: {corr} {direction} корреляция") + + r_squared = data['r_squared'] + results.append(f"Коэффициент детерминации (R^2): {r_squared:.6f}") + if r_squared < 0.3: + determ = "Модель объясняет малую часть дисперсии данных" + elif r_squared < 0.5: + determ = "Модель объясняет некоторую часть дисперсии данных" + elif r_squared < 0.7: + determ = "Модель хорошо объясняет дисперсию данных" + else: + determ = "Модель очень хорошо объясняет дисперсию данных" + results.append(f"Интерпретация: {determ}") + + results.append("\nТочки аппроксимации:") + for i in range(min(5, self.n)): # Выводим только первые 5 точек для краткости + error = data['errors'][i] + results.append(f"Точка {i+1}: x = {self.x[i]:.6f}, y = {self.y[i]:.6f}, f(x) = {data['f_x'][i]:.6f}, e = {error:.6f}") + if self.n > 5: + results.append("...") + + results.append("\n" + "="*80) + results.append(f"НАИЛУЧШАЯ АППРОКСИМАЦИЯ: {self.best_approximation.upper()}") + results.append(f"Формула: {self.approximations[self.best_approximation]['formula']}") + results.append(f"Среднеквадратическое отклонение (RMSE): {self.approximations[self.best_approximation]['rmse']:.6f}") + results.append("="*80) + + if output == 'console': + for line in results: + print(line) + else: + with open(output, 'w') as f: + for line in results: + f.write(line + "\n") + print(f"Результаты сохранены в файл {output}") + + def plot_graphs(self, save_to_file=None): + if not self.approximations: + raise ValueError("Сначала выполните аппроксимацию") + + fig, axs = plt.subplots(2, 3, figsize=(15, 10)) + axs = axs.flatten() + + x_min, x_max = np.min(self.x), np.max(self.x) + y_min, y_max = np.min(self.y), np.max(self.y) + + x_range, y_range = x_max - x_min, y_max - y_min + x_min, x_max = x_min - 0.2 * x_range, x_max + 0.2 * x_range + y_min, y_max = y_min - 0.2 * y_range, y_max + 0.2 * y_range + + x_grid = np.linspace(x_min, x_max, 1000) + + type_names = { + 'linear': 'Линейная', + 'polynomial_2': 'Полиномиальная 2-й степени', + 'polynomial_3': 'Полиномиальная 3-й степени', + 'exponential': 'Экспоненциальная', + 'logarithmic': 'Логарифмическая', + 'power': 'Степенная' + } + + for i, (appr_type, data) in enumerate(self.approximations.items()): + if data is None: + axs[i].set_title(f"{type_names.get(appr_type, appr_type)}: не удалось") + continue + + try: + if appr_type in ['logarithmic', 'power']: + valid_x = x_grid[x_grid > 0] + y_grid = data['function'](valid_x) + axs[i].plot(valid_x, y_grid, 'r-', linewidth=2) + else: + y_grid = data['function'](x_grid) + axs[i].plot(x_grid, y_grid, 'r-', linewidth=2) + + axs[i].scatter(self.x, self.y, color='blue', s=30) + axs[i].set_title(f"{type_names.get(appr_type, appr_type)}: RMSE={data['rmse']:.4f}") + axs[i].set_xlabel('x') + axs[i].set_ylabel('y') + axs[i].text(0.05, 0.95, data['formula'], transform=axs[i].transAxes, + fontsize=8, verticalalignment='top', bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5)) + axs[i].set_xlim(x_min, x_max) + axs[i].set_ylim(y_min, y_max) + + if appr_type == self.best_approximation: + axs[i].set_facecolor('#e0ffe0') + axs[i].set_title(f"{type_names.get(appr_type, appr_type)}: НАИЛУЧШАЯ! RMSE={data['rmse']:.4f}") + except Exception as e: + print(f"Ошибка при построении графика для {appr_type}: {e}") + + fig.tight_layout() + + if save_to_file: + plt.savefig(save_to_file, dpi=300) + print(f"Графики сохранены в файл {save_to_file}") + else: + plt.show() + +def main(): + approx = ApproximationMethod() + while True: + source = input("Выберите источник данных (1 - консоль, 2 - файл): ") + if source == '1': + approx.input_data('console') + break + elif source == '2': + filename = input("Введите имя файла с данными: ") + approx.input_data(filename) + break + else: + print("Неверный выбор. Выберите 1 или 2.") + + try: + approx.approximate() + except Exception as e: + print(f"Ошибка при аппроксимации: {e}") + return + + while True: + output = input("Выберите способ вывода результатов (1 - консоль, 2 - файл, 3 - оба): ") + if output == '1': + approx.print_results('console') + break + elif output == '2': + while True: + try: + filename = input("Введите имя файла для сохранения результатов: ") + approx.print_results(filename) + break + except Exception as e: + print(f"Ошибка при сохранении результатов: {e}. Попробуйте другое имя файла.") + break + elif output == '3': + while True: + try: + filename = input("Введите имя файла для сохранения результатов: ") + approx.print_results('console') + approx.print_results(filename) + break + except Exception as e: + print(f"Ошибка при сохранении результатов: {e}. Попробуйте другое имя файла.") + break + else: + print("Неверный выбор. Выберите 1, 2 или 3.") + + while True: + graph_option = input("Построить графики? (y/n): ").lower() + if graph_option == 'y': + while True: + save_option = input("Сохранить графики в файл? (y/n): ").lower() + if save_option == 'y': + while True: + try: + image_file = input("Введите имя файла для сохранения графиков: ") + approx.plot_graphs(save_to_file=image_file) + break + except Exception as e: + print(f"Ошибка при сохранении графиков: {e}. Попробуйте другое имя файла.") + break + elif save_option == 'n': + try: + approx.plot_graphs() + except Exception as e: + print(f"Ошибка при построении графиков: {e}") + break + else: + print("Неверный выбор. Введите 'y' или 'n'.") + break + elif graph_option == 'n': + break + else: + print("Неверный выбор. Введите 'y' или 'n'.") + +if __name__ == "__main__": + try: + main() + except Exception as e: + print(f"Произошла ошибка: {e}") + sys.exit(1) diff --git "a/\320\2403212/metel_409127/lab4/\320\222\321\213\321\207\320\274\320\260\321\2024.docx" "b/\320\2403212/metel_409127/lab4/\320\222\321\213\321\207\320\274\320\260\321\2024.docx" new file mode 100644 index 0000000..885cc46 Binary files /dev/null and "b/\320\2403212/metel_409127/lab4/\320\222\321\213\321\207\320\274\320\260\321\2024.docx" differ diff --git "a/\320\2403212/metel_409127/lab5/Lab5.docx" "b/\320\2403212/metel_409127/lab5/Lab5.docx" new file mode 100644 index 0000000..767dd1c Binary files /dev/null and "b/\320\2403212/metel_409127/lab5/Lab5.docx" differ diff --git "a/\320\2403212/metel_409127/lab5/\320\244\320\265\320\264\320\265\321\200\320\260\320\273\321\214\320\275\320\276\320\265 \320\263\320\276\321\201\321\203\320\264\320\260\321\200\321\201\321\202\320\262\320\265\320\275\320\275\320\276\320\265 \320\260\320\262\321\202\320\276\320\275\320\276\320\274\320\275\320\276\320\265 \320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\214\320\275\320\276\320\265 \321\203\321\207\321\200\320\265\320\266\320\264\320\265\320\275\320\270\320\265 \320\262\321\213\321\201\321\210\320\265\320\263\320\276 \320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\321\217.docx" "b/\320\2403212/metel_409127/lab5/\320\244\320\265\320\264\320\265\321\200\320\260\320\273\321\214\320\275\320\276\320\265 \320\263\320\276\321\201\321\203\320\264\320\260\321\200\321\201\321\202\320\262\320\265\320\275\320\275\320\276\320\265 \320\260\320\262\321\202\320\276\320\275\320\276\320\274\320\275\320\276\320\265 \320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\214\320\275\320\276\320\265 \321\203\321\207\321\200\320\265\320\266\320\264\320\265\320\275\320\270\320\265 \320\262\321\213\321\201\321\210\320\265\320\263\320\276 \320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\321\217.docx" new file mode 100644 index 0000000..88dea4e Binary files /dev/null and "b/\320\2403212/metel_409127/lab5/\320\244\320\265\320\264\320\265\321\200\320\260\320\273\321\214\320\275\320\276\320\265 \320\263\320\276\321\201\321\203\320\264\320\260\321\200\321\201\321\202\320\262\320\265\320\275\320\275\320\276\320\265 \320\260\320\262\321\202\320\276\320\275\320\276\320\274\320\275\320\276\320\265 \320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\214\320\275\320\276\320\265 \321\203\321\207\321\200\320\265\320\266\320\264\320\265\320\275\320\270\320\265 \320\262\321\213\321\201\321\210\320\265\320\263\320\276 \320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\321\217.docx" differ diff --git "a/\320\2403212/metel_409127/lab6/Task.py" "b/\320\2403212/metel_409127/lab6/Task.py" new file mode 100644 index 0000000..7ccd080 --- /dev/null +++ "b/\320\2403212/metel_409127/lab6/Task.py" @@ -0,0 +1,271 @@ +import numpy as np +import matplotlib.pyplot as plt +from typing import Callable, Tuple, List +import warnings +warnings.filterwarnings('ignore') + +class ODESolver: + def __init__(self): + self.equations = { + 1: { + 'name': "y' = x + y", + 'func': lambda x, y: x + y, + 'exact': lambda x, x0, y0: (y0 + x0 + 1) * np.exp(x - x0) - x - 1, + 'description': "Точное решение: y = (y₀ + x₀ + 1) * e^(x-x₀) - x - 1" + }, + 2: { + 'name': "y' = x² - 2y", + 'func': lambda x, y: x**2 - 2*y, + 'exact': lambda x, x0, y0: (y0 - x0**2/2 + x0/2 - 1/4) * np.exp(-2*(x - x0)) + x**2/2 - x/2 + 1/4, + 'description': "Точное решение: y = (y₀ - x₀²/2 + x₀/2 - 1/4) * e^(-2(x-x₀)) + x²/2 - x/2 + 1/4" + }, + 3: { + 'name': "y' = sin(x) + y", + 'func': lambda x, y: np.sin(x) + y, + 'exact': lambda x, x0, y0: (y0 + np.cos(x0)/2 + np.sin(x0)/2) * np.exp(x - x0) - np.cos(x)/2 - np.sin(x)/2, + 'description': "Точное решение: y = (y₀ + cos(x₀)/2 + sin(x₀)/2) * e^(x-x₀) - cos(x)/2 - sin(x)/2" + } + } + + def euler_method(self, f: Callable, x0: float, y0: float, xn: float, h: float) -> Tuple[np.ndarray, np.ndarray]: + n = int((xn - x0) / h) + x = np.linspace(x0, xn, n + 1) + y = np.zeros(n + 1) + y[0] = y0 + for i in range(n): + y[i + 1] = y[i] + h * f(x[i], y[i]) + + return x, y + + def improved_euler_method(self, f: Callable, x0: float, y0: float, xn: float, h: float) -> Tuple[np.ndarray, np.ndarray]: + n = round((xn - x0) / (h)) + x = np.linspace(x0, xn, n + 1) + y = np.zeros(n + 1) + y[0] = y0 + for i in range(n): + k1 = f(x[i], y[i]) + k2 = f(x[i] + h, y[i] + h * k1) + y[i + 1] = y[i] + h * (k1 + k2) / 2 + + return x, y + + def milne_method(self, f: Callable, x0: float, y0: float, xn: float, h: float) -> Tuple[np.ndarray, np.ndarray]: + n = int((xn - x0) / h) + x = np.linspace(x0, xn, n + 1) + y = np.zeros(n + 1) + if n < 4: + return self.improved_euler_method(f, x0, y0, xn, h) + + x_start, y_start = self.improved_euler_method(f, x0, y0, x0 + 3*h, h) + y[:4] = y_start + + for i in range(4, n + 1): + f_i_3 = f(x[i-3], y[i-3]) + f_i_2 = f(x[i-2], y[i-2]) + f_i_1 = f(x[i-1], y[i-1]) + + y_pred = y[i-4] + (4*h/3) * (2*f_i_3 - f_i_2 + 2*f_i_1) + + f_i_pred = f(x[i], y_pred) + + y[i] = y[i-2] + (h/3) * (f_i_2 + 4*f_i_1 + f_i_pred) + + return x, y + + def runge_rule_error(self, f: Callable, x0: float, y0: float, xn: float, h: float, method: str) -> float: + if method == 'euler': + _, y_h = self.euler_method(f, x0, y0, xn, h) + _, y_h2 = self.euler_method(f, x0, y0, xn, h/2) + p = 1 # порядок + elif method == 'improved_euler': + _, y_h = self.improved_euler_method(f, x0, y0, xn, h) + _, y_h2 = self.improved_euler_method(f, x0, y0, xn, h/2) + p = 2 + + # Сравниваем значения в одних и тех же точках + y_h2_interp = y_h2[::2] + + runge_error = np.max(np.abs(y_h - y_h2_interp)) / (2**p - 1) + return runge_error + + def exact_error(self, exact_func: Callable, x: np.ndarray, y_numerical: np.ndarray, x0: float, y0: float) -> float: + y_exact = exact_func(x, x0, y0) + return np.max(np.abs(y_exact - y_numerical)) + + def create_results_table(self, x: np.ndarray, methods_results: dict, exact_func: Callable, x0: float, y0: float): + print("\n" + "="*80) + print("ТАБЛИЦА ПРИБЛИЖЕННЫХ ЗНАЧЕНИЙ") + print("="*80) + + header = f"{'x':>8} " + for method_name in methods_results.keys(): + header += f"{method_name:>15} " + if exact_func: + header += f"{'Точное':>15}" + print(header) + print("-" * len(header)) + + step = max(1, len(x) // 10) + for i in range(0, len(x), step): + row = f"{x[i]:>8.3f} " + for method_name, (_, y_vals) in methods_results.items(): + if i < len(y_vals): + row += f"{y_vals[i]:>15.6f} " + else: + row += f"{'N/A':>15} " + + if exact_func: + y_exact_val = exact_func(x[i], x0, y0) + row += f"{y_exact_val:>15.6f}" + + print(row) + + def solve_and_analyze(self, equation_num: int, x0: float, y0: float, xn: float, h: float, epsilon: float): + if equation_num not in self.equations: + print("Ошибка: Неверный номер уравнения!") + return + + eq = self.equations[equation_num] + f = eq['func'] + exact_func = eq['exact'] + + print(f"\nРешение уравнения: {eq['name']}") + print(f"Начальные условия: y({x0}) = {y0}") + print(f"Интервал: [{x0}, {xn}], шаг h = {h}") + print(f"{eq['description']}") + + # Решение всеми методами + x_euler, y_euler = self.euler_method(f, x0, y0, xn, h) + x_improved, y_improved = self.improved_euler_method(f, x0, y0, xn, h) + x_milne, y_milne = self.milne_method(f, x0, y0, xn, h) + + # Сохраняем результаты + methods_results = { + 'Эйлер': (x_euler, y_euler), + 'Улучш. Эйлер': (x_improved, y_improved), + 'Милн': (x_milne, y_milne) + } + + # Создаем таблицу результатов + self.create_results_table(x_euler, methods_results, exact_func, x0, y0) + + # Анализ погрешностей + print("\n" + "="*80) + print("АНАЛИЗ ПОГРЕШНОСТЕЙ") + print("="*80) + + # Правило Рунге для одношаговых методов + euler_runge_error = self.runge_rule_error(f, x0, y0, xn, h, 'euler') + improved_euler_runge_error = self.runge_rule_error(f, x0, y0, xn, h, 'improved_euler') + + print(f"Погрешность по правилу Рунге:") + print(f" Метод Эйлера: {euler_runge_error:.2e}") + print(f" Усовершенствованный метод Эйлера: {improved_euler_runge_error:.2e}") + + milne_exact_error = self.exact_error(exact_func, x_milne, y_milne, x0, y0) + + print(f"\nТочная погрешность (ε = max|y_точн - y_i|):") + print(f" Метод Милна: {milne_exact_error:.2e}") + + # Построение графиков + plt.figure(figsize=(12, 8)) + + # График численных решений + plt.plot(x_euler, y_euler, 'r--', label='Метод Эйлера', linewidth=2) + plt.plot(x_improved, y_improved, 'b-', label='Усовершенствованный метод Эйлера', linewidth=2) + plt.plot(x_milne, y_milne, 'g:', label='Метод Милна', linewidth=2, markersize=6) + + + x_exact = np.linspace(x0, xn, 1000) + y_exact = exact_func(x_exact, x0, y0) + plt.plot(x_exact, y_exact, 'k-', label='Точное решение', linewidth=1, alpha=0.7) + + plt.xlabel('x') + plt.ylabel('y') + plt.title(f'Решение ОДУ: {eq["name"]}') + plt.legend() + plt.grid(True, alpha=0.3) + plt.tight_layout() + plt.show() + + # Анализ достижения требуемой точности + print("\n" + "="*80) + print("АНАЛИЗ ДОСТИЖЕНИЯ ТРЕБУЕМОЙ ТОЧНОСТИ") + print("="*80) + print(f"Требуемая точность ε = {epsilon:.2e}") + + # Проверяем точность + accuracy_achieved = True + + errors = [ + ("Метод Эйлера", euler_runge_error), + ("Усовершенствованный метод Эйлера", improved_euler_runge_error), + ("Метод Милна", milne_exact_error) + ] + + print(f"\nСравнение погрешностей с требуемой точностью:") + for method_name, error in errors: + if error <= epsilon: + print(f"✓ {method_name}: точность ДОСТИГНУТА ({error:.2e} ≤ {epsilon:.2e})") + else: + print(f"✗ {method_name}: точность НЕ ДОСТИГНУТА ({error:.2e} > {epsilon:.2e})") + accuracy_achieved = False + + print(f"\n{'='*80}") + if accuracy_achieved: + print("ВЫВОД: Требуемая точность достигнута всеми методами!") + else: + print("ВЫВОД: Требуемая точность НЕ достигнута некоторыми методами.") + print("Рекомендация: уменьшите шаг интегрирования h и повторите вычисления.") + print("="*80) + + +def validate_input(prompt: str, input_type: type, condition=None): + """Валидация пользовательского ввода""" + while True: + try: + value = input_type(input(prompt)) + if condition and not condition(value): + print("Некорректное значение! Попробуйте снова.") + continue + return value + except ValueError: + print("Некорректный формат! Попробуйте снова.") + + +def main(): + solver = ODESolver() + while True: + print("\nДоступные уравнения:") + for num, eq in solver.equations.items(): + print(f"{num}. {eq['name']}") + print(f" {eq['description']}") + + equation_num = validate_input( + "\nВыберите номер уравнения (1-3): ", + int, + lambda x: x in solver.equations + ) + + print("\nВвод параметров:") + x0 = validate_input("Начальная точка x₀: ", float) + y0 = validate_input("Начальное условие y₀ = y(x₀): ", float) + xn = validate_input("Конечная точка xₙ: ", float, lambda x: x > x0) + h = validate_input("Шаг интегрирования h: ", float, lambda x: 0 < x < (xn - x0)) + epsilon = validate_input("Требуемая точность ε: ", float, lambda x: x > 0) + + try: + solver.solve_and_analyze(equation_num, x0, y0, xn, h, epsilon) + except Exception as e: + print(f"Ошибка при вычислениях: {e}") + print("Возможно, выбранные параметры привели к неустойчивости численного метода.") + + continue_work = input("\nХотите решить другое уравнение? (y/n): ").lower() + if continue_work != 'y': + break + + print("\nПрограмма завершена. Спасибо за использование!") + + +if __name__ == "__main__": + main() diff --git "a/\320\2403212/metel_409127/lab6/\320\222\321\213\321\207\320\274\320\260\321\202_\342\204\2266.docx" "b/\320\2403212/metel_409127/lab6/\320\222\321\213\321\207\320\274\320\260\321\202_\342\204\2266.docx" new file mode 100644 index 0000000..17307ed Binary files /dev/null and "b/\320\2403212/metel_409127/lab6/\320\222\321\213\321\207\320\274\320\260\321\202_\342\204\2266.docx" differ