diff --git "a/\320\2403212/dmitriev_408542/lab1/main.py" "b/\320\2403212/dmitriev_408542/lab1/main.py" new file mode 100644 index 0000000..6f86b38 --- /dev/null +++ "b/\320\2403212/dmitriev_408542/lab1/main.py" @@ -0,0 +1,187 @@ +import numpy as np + + +def gauss_with_pivoting(A, b): + n = len(b) + # задаём вот здеся матрицу (A|B) + Ab = np.hstack([A, b.reshape(n, 1)]) + # инициализируем определитель. Будем его вычислять с помощью знания + # гласящего что при диагональной матрице определитель равен произведению диагоналей на перестановки + det = 1.0 + + # Для начала прямой ход - подробно описан в отчёте + for k in range(n): + # Здесь выбор главного элемента по столбцу(для сути нашего метода) + max_row = np.argmax(np.abs(Ab[k:, k])) + k + if Ab[max_row, k] == 0: + raise ValueError("Матрица вырождена, система не имеет единственного решения или решений нет.") + + # Здесь меняем строки местами + if max_row != k: + Ab[[k, max_row]] = Ab[[max_row, k]] + det *= -1 + + # Зануляем элементы ниже главного элемента для приведения к диагональному виду + for i in range(k + 1, n): + factor = Ab[i, k] / Ab[k, k] + Ab[i, k:] -= factor * Ab[k, k:] + + # про то что говорили ранее: получаем определитель путём умножения диагональных элементов + det *= Ab[k, k] + + # Обратный ход - нахождение самого решения. + x = np.zeros(n) + for i in range(n - 1, -1, -1): + x[i] = (Ab[i, -1] - np.dot(Ab[i, i + 1:n], x[i + 1:])) / Ab[i, i] + + return x, Ab, det + + +def input_manual(n): + print(f"Введите матрицу A ({n}x{n}):") + A = [] + for i in range(n): + while True: + row_input = input(f"Строка {i + 1}: ") + try: + row = list(map(float, row_input.split())) + if len(row) != n: + print(f"В строке должно быть ровно {n} чисел, го снова.") + continue + A.append(row) + break + except ValueError: + print("Введите числа которые разделены пробелами, го снова.") + A = np.array(A) + + print("Введите вектор b:") + while True: + b_input = input() + try: + b = list(map(float, b_input.split())) + if len(b) != n: + print(f"В векторе должно быть ровно {n} чисел, не забудьте попробовать снова ;)") + continue + break + except ValueError: + print("Введите числа, разделённые пробелами. Попробуйте снова.") + b = np.array(b) + + return A, b + + +def input_file(filename): + try: + with open(filename, 'r') as file: + lines = file.readlines() + if not lines: + raise ValueError("Файл пуст.") + + n = len(lines) - 1 + A = [] + for line in lines: + try: + row = list(map(float, line.split())) + A.append(row) + except ValueError as e: + raise ValueError(f"Ошибка в данных файла: {e}") + A = np.array(A) + b = A[-1] + A = A[:-1] + except FileNotFoundError: + raise FileNotFoundError("Файл не найден.") + except Exception as e: + raise ValueError(e) + + return A, b + + +def generate_random_matrix(n): + A = np.random.uniform(-10, 10, (n, n)) + for i in range(n): + row_sum = np.sum(np.abs(A[i, :])) - np.abs(A[i, i]) + A[i, i] = row_sum + np.random.uniform(1, 10) + b = np.random.uniform(-10, 10, n) + return A, b + + + + +def main(): + print("Выберите способ ввода данных:") + print("1. Вручную") + print("2. Из файла") + print("3. Блесс РНГ или рандомная матрица.") + choice = input("Выберите ваш способ ввода данных из двух: ") + + try: + if choice == '1': + while True: + try: + n = int(input("Введите размерность системы (n, не более 20): ")) + if n <= 0 or n > 20: + print("Размерность должна быть от 1 до 20, постарайтесь в этот раз не ошибиться!") + continue + break + except ValueError: + print("Введите целое число, а также опробуйте снова!") + A, b = input_manual(n) + elif choice == '2': + filename = input("Введите имя файла: ") + A, b = input_file(filename) + elif choice == '3': + while True: + try: + n = int(input("Введите размерность системы (n, не более 20): ")) + if n <= 0 or n > 20: + print("Размерность должна быть от 1 до 20, постарайтесь в этот раз не ошибиться!") + continue + break + except ValueError: + print("Введите целое число, а также опробуйте снова!") + A, b = generate_random_matrix(n) + print("\nСгенерированная матрица A:") + print(A) + print("\nСгенерированный вектор b:") + print(b) + else: + print("Неверный выбор.") + return + print(A) + + if A.shape[0] != A.shape[1]: + raise ValueError("Матрица A должна быть квадратной.") + + + x, Ab_triangular, det = gauss_with_pivoting(A, b) + + print("\nТреугольная матрица (с преобразованным столбцом B):") + print(Ab_triangular) + print("\nВектор неизвестных x:") + print(x) + print("\nОпределитель матрицы A:") + print(det) + + residual = np.dot(A, x) - b + print("\nВектор невязок:") + print(residual) + + x_numpy = np.linalg.solve(A, b) + det_numpy = np.linalg.det(A) + + print("\nРешение с использованием бииииблиотеки NumPy:") + print(x_numpy) + print("\nОпределитель с использованием биииииблиотеки NumPy:") + print(det_numpy) + + print("\nРазница между решениями (метод Гаусса и NumPy):") + print(x - x_numpy) + print("\nРазница между определителями (метод Гаусса и NumPy):") + print(det - det_numpy) + + except Exception as e: + print(f"Ошибка: {e}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git "a/\320\2403212/dmitriev_408542/lab2/main.py" "b/\320\2403212/dmitriev_408542/lab2/main.py" new file mode 100644 index 0000000..0889f2d --- /dev/null +++ "b/\320\2403212/dmitriev_408542/lab2/main.py" @@ -0,0 +1,461 @@ +import math +import numpy as np +import matplotlib + +matplotlib.use('Agg') +import matplotlib.pyplot as plt +from numpy.linalg import norm + + +def f1(x): + return x ** 2 - 2 + + +def df1(x): + return 2 * x + + +def phi1(x): + return math.sqrt(2 + x) + + +def f2(x): + return math.sin(x) + + +def df2(x): + return math.cos(x) + + +def phi2(x): + return x - math.sin(x) + + +def f3(x): + return math.exp(x) - 3 + + +def df3(x): + return math.exp(x) + + +def phi3(x): + return math.log(3) + + +def f4(x): + return x ** 3 - x - 2 + + +def df4(x): + return 3 * x ** 2 - 1 + + +def phi4(x): + return (x + 2) ** (1 / 3) + + +def system1(X): + x, y = X + return np.array([ + 1.1 - 0.1 * y, + 1.2 - 0.2 * x + ]) + + +def system1_f(X): + x, y = X + return np.array([ + x + 0.1 * y - 1.1, + 0.2 * x + y - 1.2 + ]) + + +def system2(X): + x, y = X + return np.array([ + 0.5 * math.sin(y) + 0.5, + 0.5 * math.cos(x) + 0.5 + ]) + + +def system2_f(X): + x, y = X + return np.array([ + x - 0.5 * math.sin(y) - 0.5, + y - 0.5 * math.cos(x) - 0.5 + ]) + + +def bisection(f, a, b, epsilon=1e-6, max_iter=1000): + fa = f(a) + fb = f(b) + print(f"f(a) = {fa:.6f}, f(b) = {fb:.6f}") + if fa * fb >= 0: + raise ValueError("Функция не меняет знак на интервале") + iter_count = 0 + while iter_count < max_iter: + iter_count += 1 + c = (a + b) / 2 + fc = f(c) + if abs(fc) < epsilon or (b - a) / 2 < epsilon: + if iter_count == 1 and abs(fc) == 0: + print("Корень найден на первой итерации: середина интервала является корнем.") + return c, iter_count + if f(a) * fc < 0: + b = c + else: + a = c + raise RuntimeError("Достигнуто максимальное число итераций") + + +def newton(f, df, x0, epsilon=1e-6, max_iter=1000): + x = x0 + iter_count = 0 + for _ in range(max_iter): + fx = f(x) + if abs(fx) < epsilon: + return x, iter_count + dfx = df(x) + if abs(dfx) < 1e-10: + raise ValueError("Производная близка к нулю") + x = x - fx / dfx + iter_count += 1 + raise RuntimeError("Достигнуто максимальное число итераций") + + +def simple_iteration(phi, x0, epsilon=1e-6, max_iter=1000): + x = x0 + iter_count = 0 + for _ in range(max_iter): + x_new = phi(x) + if abs(x_new - x) < epsilon: + return x_new, iter_count + x = x_new + iter_count += 1 + raise RuntimeError("Достигнуто максимальное число итераций") + + +def system_simple_iteration(phi, phi_f, X0, epsilon=1e-6, max_iter=1000, alpha=1.0): + X = X0.copy() + iter_count = 0 + errors = [] + for _ in range(max_iter): + X_new = phi(X) + X_new = (1 - alpha) * X + alpha * X_new + error = norm(X_new - X) + errors.append(error) + print(f"Итерация {iter_count}: x = {X_new[0]:.6f}, y = {X_new[1]:.6f}, погрешность = {error:.6e}") + if error < epsilon: + residual = norm(phi_f(X_new)) + return X_new, iter_count, np.array(errors), residual + X = X_new + iter_count += 1 + raise RuntimeError("Максимальное число итераций достигнуто") + + +def check_convergence(phi, a, b): + def dphi(x): + h = 1e-5 + return (phi(x + h) - phi(x - h)) / (2 * h) + + points = np.linspace(a, b, 100) + for p in points: + if abs(dphi(p)) >= 1: + return False + return True + + +def check_system_convergence(phi, X0): + h = 1e-6 + J = np.zeros((2, 2)) + for i in range(2): + for j in range(2): + X_plus = X0.copy() + X_plus[j] += h + try: + J[i, j] = (phi(X_plus)[i] - phi(X0)[i]) / h + except ValueError: + return False + return np.linalg.norm(J, ord=np.inf) < 1 + + +def check_multiple_roots(f, a, b): + points = np.linspace(a, b, 100) + sign_changes = 0 + for i in range(len(points) - 1): + if f(points[i]) * f(points[i + 1]) < 0: + sign_changes += 1 + return sign_changes + + +def plot_function(equation_choice, root, a, b, filename='function_plot.png'): + x = np.linspace(a, b, 100) + plt.figure(figsize=(8, 6)) + + if equation_choice == 1: + y = x ** 2 - 2 + plt.plot(x, y, 'r', label='x² - 2 = 0') + elif equation_choice == 2: + y = np.sin(x) + plt.plot(x, y, 'r', label='sin(x) = 0') + elif equation_choice == 3: + y = np.exp(x) - 3 + plt.plot(x, y, 'r', label='e^x - 3 = 0') + elif equation_choice == 4: + y = x ** 3 - x - 2 + plt.plot(x, y, 'r', label='x³ - x - 2 = 0') + + plt.axhline(0, color='black', linestyle='--') + plt.scatter(root, 0, c='g', s=100, label='Решение') + + plt.xlabel('x') + plt.ylabel('y') + + plt.xticks(np.arange(round(a), round(b) + 1, 1)) + plt.yticks(np.arange(round(min(y)), round(max(y)) + 1, 1)) + + plt.legend() + plt.grid(True) + plt.savefig(filename) + plt.close() + + +def plot_system(system_choice, solution, filename='system_plot.png'): + x = np.linspace(-2, 2, 100) + plt.figure(figsize=(8, 6)) + if system_choice == 1: + plt.plot(x, (1.1 - x) / 0.1, 'r', label='x + 0.1y = 1.1') + plt.plot(x, (1.2 - 0.2 * x), 'b', label='0.2x + y = 1.2') + y1 = (1.1 - x) / 0.1 + y2 = (1.2 - 0.2 * x) + y_min = min(min(y1), min(y2)) + y_max = max(max(y1), max(y2)) + elif system_choice == 2: + y = np.linspace(-2, 2, 100) + x1 = 0.5 * np.sin(y) + 0.5 + y2 = 0.5 * np.cos(x) + 0.5 + plt.plot(x1, y, 'r', label='x = 0.5sin(y) + 0.5') + plt.plot(x, y2, 'b', label='y = 0.5cos(x) + 0.5') + y_min = min(min(y), min(y2)) + y_max = max(max(y), max(y2)) + + plt.scatter(*solution, c='g', s=100, label='Решение') + + plt.xlabel('x') + plt.ylabel('y') + + plt.xticks(np.arange(-2, 3, 1)) + plt.yticks(np.arange(round(y_min), round(y_max) + 1, 1)) + + plt.legend() + plt.grid(True) + plt.savefig(filename) + plt.close() + + +def input_data(method, from_file=False): + if from_file: + filename = input("Введите имя файла с данными: ") + try: + with open(filename, 'r') as file: + lines = file.readlines() + if method in ['bisection', 'simple_iteration']: + a = float(lines[0].strip()) + b = float(lines[1].strip()) + epsilon = float(lines[2].strip()) + return a, b, epsilon + elif method == 'newton': + x0 = float(lines[0].strip()) + epsilon = float(lines[1].strip()) + return x0, epsilon + elif method == 'system_simple_iteration': + x0 = float(lines[0].strip()) + y0 = float(lines[1].strip()) + epsilon = float(lines[2].strip()) + return np.array([x0, y0]), epsilon + except Exception as e: + raise ValueError(f"Ошибка чтения файла: {e}") + else: + if method in ['bisection', 'simple_iteration']: + a = float(input("Введите левую границу интервала: ")) + b = float(input("Введите правую границу интервала: ")) + epsilon = float(input("Введите погрешность: ")) + return a, b, epsilon + elif method == 'newton': + x0 = float(input("Введите начальное приближение: ")) + epsilon = float(input("Введите погрешность: ")) + return x0, epsilon + elif method == 'system_simple_iteration': + x0 = float(input("Введите начальное x: ")) + y0 = float(input("Введите начальное y: ")) + epsilon = float(input("Введите погрешность: ")) + return np.array([x0, y0]), epsilon + + +def output_results(root, f, iters, output_to_file=False): + result = f"Корень: {root:.6f}\n" + result += f"Значение функции в корне: {f(root):.6e}\n" + result += f"Число итераций: {iters}\n" + if output_to_file: + filename = input("Введите имя файла для вывода результатов: ") + with open(filename, 'w') as file: + file.write(result) + print("Результаты записаны в файл.") + else: + print(result) + + +def output_system_results(X, iters, errors, residual, output_to_file=False): + result = f"Вектор неизвестных: x = {X[0]:.6f}, y = {X[1]:.6f}\n" + result += f"Число итераций: {iters}\n" + result += f"Вектор погрешностей (последние 5): {errors[-5:]}\n" + result += f"Остаток (норма системы): {residual:.6e}\n" + if output_to_file: + filename = input("Введите имя файла для вывода результатов: ") + with open(filename, 'w') as file: + file.write(result) + print("Результаты записаны в файл.") + else: + print(result) + + +def choose_problem_type(): + print("Выберите тип задачи:") + print("1. Одиночное уравнение") + print("2. Система уравнений") + return int(input("Введите номер: ")) + + +def choose_equation(): + print("\nВыберите уравнение:") + print("1. x^2 - 2 = 0") + print("2. sin(x) = 0") + print("3. e^x - 3 = 0") + print("4. x^3 - x - 2 = 0") + choice = int(input("Введите номер: ")) + if choice == 1: + return f1, df1, phi1, choice + elif choice == 2: + return f2, df2, phi2, choice + elif choice == 3: + return f3, df3, phi3, choice + elif choice == 4: + return f4, df4, phi4, choice + else: + raise ValueError("Неверный выбор уравнения") + + +def choose_system(): + print("\nВыберите систему:") + print("1. x + 0.1y = 1.1, 0.2x + y = 1.2") + print("2. x = 0.5sin(y) + 0.5, y = 0.5cos(x) + 0.5") + choice = int(input("Введите номер: ")) + if choice == 1: + return system1, system1_f, choice + elif choice == 2: + return system2, system2_f, choice + else: + raise ValueError("Неверный выбор системы") + + +try: + print("Выберите способ ввода данных:") + print("1. С клавиатуры") + print("2. Из файла") + input_choice = int(input("Введите номер: ")) + from_file = (input_choice == 2) + + problem_type = choose_problem_type() + + if problem_type == 1: + f, df, phi, equation_choice = choose_equation() + + print("\nВыберите метод:") + print("1. Метод дихотомии") + print("2. Метод Ньютона") + print("3. Метод простой итерации") + method_choice = int(input("Введите номер метода: ")) + + if method_choice == 1: + method = 'bisection' + elif method_choice == 2: + method = 'newton' + elif method_choice == 3: + method = 'simple_iteration' + else: + raise ValueError("Неверный выбор метода") + + args = input_data(method, from_file) + + print("\nВыберите способ вывода результатов:") + print("1. На экран") + print("2. В файл") + output_choice = int(input("Введите номер: ")) + output_to_file = (output_choice == 2) + + if method == 'bisection': + a, b, epsilon = args + sign_changes = check_multiple_roots(f, a, b) + if sign_changes > 1: + print( + f"Внимание: на интервале [{a}, {b}] найдено {sign_changes} смен знака. Возможно несколько корней!") + elif sign_changes == 0: + print("Ошибка: на интервале нет корней!") + else: + root, iterations = bisection(f, a, b, epsilon) + output_results(root, f, iterations, output_to_file) + plot_function(equation_choice, root, a, b) + + elif method == 'newton': + x0, epsilon = args + print(f"Выбрано начальное приближение: x0 = {x0}") + root, iterations = newton(f, df, x0, epsilon) + output_results(root, f, iterations, output_to_file) + plot_function(equation_choice, root, x0 - 1, x0 + 1) + + elif method == 'simple_iteration': + a, b, epsilon = args + sign_changes = check_multiple_roots(f, a, b) + if sign_changes > 1: + print( + f"Внимание: на интервале [{a}, {b}] найдено {sign_changes} смен знака. Возможно несколько корней!") + elif sign_changes == 0: + print("Ошибка: на интервале нет корней!") + else: + if not check_convergence(phi, a, b): + print("Ошибка: условие сходимости не выполнено!") + else: + x0 = (a + b) / 2 + print(f"Выбрано начальное приближение: x0 = {x0}") + root, iterations = simple_iteration(phi, x0, epsilon) + output_results(root, f, iterations, output_to_file) + plot_function(equation_choice, root, a, b) + + elif problem_type == 2: + system, system_f, system_choice = choose_system() + args = input_data('system_simple_iteration', from_file) + X0, epsilon = args + + print("\nВыберите способ вывода результатов:") + print("1. На экран") + print("2. В файл") + output_choice = int(input("Введите номер: ")) + output_to_file = (output_choice == 2) + + if not check_system_convergence(system, X0): + print("Условие сходимости не выполнено!") + else: + sol, iters, errs, residual = system_simple_iteration(system, system_f, X0, epsilon, alpha=1.0) + output_system_results(sol, iters, errs, residual, output_to_file) + plot_system(system_choice, sol) + + else: + print("Неверный выбор типа задачи!") + +except ValueError as e: + print(f"Ошибка ввода: {e}") +except RuntimeError as e: + print(f"Ошибка вычислений: {e}") +except Exception as e: + print(f"Неизвестная ошибка: {e}") \ No newline at end of file diff --git "a/\320\2403212/dmitriev_408542/lab3/dop_task.py" "b/\320\2403212/dmitriev_408542/lab3/dop_task.py" new file mode 100644 index 0000000..8351c20 --- /dev/null +++ "b/\320\2403212/dmitriev_408542/lab3/dop_task.py" @@ -0,0 +1,209 @@ +import numpy as np + +def safe_inv(x): + with np.errstate(divide='ignore', invalid='ignore'): + return 1 / x +def safe_sqrt(x): + with np.errstate(divide='ignore', invalid='ignore'): + return 1 / np.sqrt(x) +def safe_sqrt_5(x): + with np.errstate(divide='ignore', invalid='ignore'): + return 1 / np.sqrt(abs(x - 0.5)) + +functions = { + "1": {"func": safe_sqrt, + "description": "1/sqrt(x)"}, + "2": {"func": safe_inv, + "description": "1/x"}, + "3": {"func": safe_sqrt_5, + "description": "1/sqrt|x-0.5|"}, +} + +def detect_singularities(f, a, b, num_points=1000, threshold=1e6, merge_tol=1e-2): + x = np.linspace(a, b, num_points) + y = np.empty_like(x) + + for i, xi in enumerate(x): + try: + y[i] = f(xi) + except: + y[i] = np.inf + + abs_y = np.abs(y) + inf_indices = np.where(np.isinf(abs_y))[0] + singular_points = [x[i] for i in inf_indices] + + if a <= 0 <= b: + try: + f_at_zero = f(0) + if np.isinf(f_at_zero) or abs(f_at_zero) > threshold: + singular_points.append(0.0) + except: + singular_points.append(0.0) + + singular_points = sorted(np.unique(np.round(singular_points, 6))) + merged_points = [] + if singular_points: + current = singular_points[0] + for sp in singular_points[1:]: + if abs(sp - current) < merge_tol: + current = (current + sp) / 2 + else: + merged_points.append(current) + current = sp + merged_points.append(current) + + return merged_points + +def check_convergence(f, point, a, b): + if point <= a or point >= b: + try: + value = f(point) + return not np.isinf(value) and not np.isnan(value) + except: + return False + + try: + epsilon = 1e-10 + left_value = f(point - epsilon) + right_value = f(point + epsilon) + if abs(left_value) > 1e6 or abs(right_value) > 1e6: + return False + return True + except: + return False + +def rectangle_method(f, a, b, n=1000, mode='left'): + h = (b - a) / n + result = 0.0 + for i in range(n): + x = a + i * h + xi = x + h / 2 if mode == 'mid' else x + h * (mode == 'right') + try: + result += f(xi) if not np.isinf(f(xi)) else 0 + except: + continue + return result * h + +def trapezoidal_method(f, a, b, n=1000): + h = (b - a) / n + result = 0 + for i in range(n + 1): + x = a + i * h + try: + fx = f(x) if not np.isinf(f(x)) else 0 + if i in (0, n): + result += fx / 2 + else: + result += fx + except: + continue + return result * h + +def adaptive_simpson(f, a, b, tol=1e-6, max_depth=15): + def safe_f(x): + try: + return f(x) if not np.isinf(f(x)) else 0 + except: + return 0 + + def _adaptive(a, b, tol, depth): + if depth > max_depth: + return 0 + + c = (a + b) / 2 + h = b - a + fa, fc, fb = safe_f(a), safe_f(c), safe_f(b) + + s = h * (fa + 4 * fc + fb) / 6 + s_left = h * (fa + 4 * safe_f((a + c) / 2) + fc) / 12 + s_right = h * (fc + 4 * safe_f((c + b) / 2) + fb) / 12 + + if abs(s_left + s_right - s) <= 15 * tol: + return s_left + s_right + (s_left + s_right - s) / 15 + + return _adaptive(a, c, tol / 2, depth + 1) + _adaptive(c, b, tol / 2, depth + 1) + + return _adaptive(a, b, tol, 0) + +def integrate(f, a, b, eps, method='adaptive_simpson', **kwargs): + singular_points = detect_singularities(f, a, b) + convergent = all(check_convergence(f, p, a, b) for p in singular_points) + + if convergent: + if method == 'rectangle': + result = rectangle_method(f, a, b, **kwargs) + elif method == 'trapezoidal': + result = trapezoidal_method(f, a, b, **kwargs) + else: + result = adaptive_simpson(f, a, b, **kwargs) + return result, "Интеграл сходится" + else: + points = sorted([a, b] + singular_points) + total = 0.0 + prev = a + + for p in points: + if p <= prev: + continue + if p in singular_points: + total += adaptive_simpson(f, prev, p - eps) + prev = p + eps + else: + total += adaptive_simpson(f, prev, p) + prev = p + + if prev < b: + total += adaptive_simpson(f, prev, b) + + return total, "Интеграл расходится" + +def main(): + print("Доступные функции:") + for k, v in functions.items(): + print(f"{k}. {v['description']}") + + choice = input("Выберите функцию: ") + if choice not in functions: + print("Неверный выбор!") + return + + methods = { + '1': ('adaptive_simpson', 'Метод Симпсона'), + '2': ('trapezoidal', 'Метод трапеций'), + '3': ('rectangle', 'Метод прямоугольников') + } + + print("\nДоступные методы интегрирования:") + for k, v in methods.items(): + print(f"{k}. {v[1]}") + + method_choice = input("Выберите метод интегрирования: ") + if method_choice not in methods: + print("Неверный выбор метода!") + return + + method, method_name = methods[method_choice] + params = {} + + try: + a = float(input("Левая граница a: ")) + b = float(input("Правая граница b: ")) + eps = float(input("Параметр eps: ")) + if method != 'adaptive_simpson': + n = int(input("Количество разбиений: ")) + params['n'] = n + except: + print("Ошибка ввода!") + return + + func = functions[choice] + result, status = integrate(func["func"], a, b, eps, method=method, **params) + + print(f"\nМетод: {method_name}") + print(f"Найденные особенности: {detect_singularities(func['func'], a, b)}") + print(f"Статус: {status}") + print(f"Результат: {result:.6f}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git "a/\320\2403212/dmitriev_408542/lab3/main.py" "b/\320\2403212/dmitriev_408542/lab3/main.py" new file mode 100644 index 0000000..867b363 --- /dev/null +++ "b/\320\2403212/dmitriev_408542/lab3/main.py" @@ -0,0 +1,113 @@ +import math + + +def f1(x): + return x ** 2 + + +def f2(x): + return math.sin(x) + + +def f3(x): + return math.exp(x) + + +def f4(x): + return x ** 3 + 2 * x + + +def left_rect(f, a, b, n): + h = (b - a) / n + return sum(f(a + i * h) * h for i in range(n)) + + +def right_rect(f, a, b, n): + h = (b - a) / n + return sum(f(a + (i + 1) * h) * h for i in range(n)) + + +def mid_rect(f, a, b, n): + h = (b - a) / n + return sum(f(a + (i + 0.5) * h) * h for i in range(n)) + + +def trapezoid(f, a, b, n): + h = (b - a) / n + return (h / 2) * (f(a) + f(b) + 2 * sum(f(a + i * h) for i in range(1, n))) + + +def simpson(f, a, b, n): + if n % 2 != 0: + n += 1 + h = (b - a) / n + sum_odd = sum(f(a + i * h) for i in range(1, n, 2)) + sum_even = sum(f(a + i * h) for i in range(2, n, 2)) + return (h / 3) * (f(a) + f(b) + 4 * sum_odd + 2 * sum_even) + + +def runge_rule(method, f, a, b, eps, n_start=4): + n = n_start + k = 4 if method.__name__ == 'simpson' else 2 + + prev_result = method(f, a, b, n) + while True: + n *= 2 + current_result = method(f, a, b, n) + error = abs(current_result - prev_result) / (2 ** k - 1) + + if error < eps: + return current_result, n + prev_result = current_result + + +def main(): + functions = { + 1: (f1, "x²"), + 2: (f2, "sin(x)"), + 3: (f3, "e^x"), + 4: (f4, "x³ + 2x") + } + + methods = { + 1: (left_rect, "Левые прямоугольники"), + 2: (right_rect, "Правые прямоугольники"), + 3: (mid_rect, "Средние прямоугольники"), + 4: (trapezoid, "Трапеции"), + 5: (simpson, "Симпсона") + } + + try: + print("Доступные функции:") + for key, (_, desc) in functions.items(): + print(f"{key}. {desc}") + func_choice = int(input("Выберите функцию (1-4): ")) + f, f_desc = functions[func_choice] + + a = float(input("Введите нижний предел интегрирования a: ")) + b = float(input("Введите верхний предел интегрирования b: ")) + eps = float(input("Введите требуемую точность ε: ")) + + print("\nДоступные методы:") + for key, (_, desc) in methods.items(): + print(f"{key}. {desc}") + method_choice = int(input("Выберите метод (1-5): ")) + method, method_desc = methods[method_choice] + + result, n = runge_rule(method, f, a, b, eps) + + print(f"\nРезультат интегрирования функции {f_desc} на интервале [{a}, {b}]") + print(f"Метод: {method_desc}") + print(f"Значение интеграла: {result:.8f}") + print(f"Достигнутая точность при n = {n}") + + except ValueError as e: + print(f"Ошибка ввода данных: {e}") + except KeyError: + print("Ошибка: неверный номер функции или метода") + except Exception as e: + print(f"Ошибка: {e}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git "a/\320\2403212/dmitriev_408542/lab4/main.py" "b/\320\2403212/dmitriev_408542/lab4/main.py" new file mode 100644 index 0000000..07473a9 --- /dev/null +++ "b/\320\2403212/dmitriev_408542/lab4/main.py" @@ -0,0 +1,280 @@ +import numpy as np +import matplotlib.pyplot as plt +from scipy.stats import pearsonr +import json +import os + +class ApproximationCore: + def __init__(self, x, y): + self.x = np.array(x) + self.y = np.array(y) + self.results = {} + + def _solve_linear(self): + n = len(self.x) + Sx = np.sum(self.x) + Sy = np.sum(self.y) + Sxx = np.sum(self.x**2) + Sxy = np.sum(self.x * self.y) + A = np.array([[Sxx, Sx], [Sx, n]]) + B = np.array([Sxy, Sy]) + return np.linalg.solve(A, B) + + def _solve_quadratic(self): + n = len(self.x) + Sx = np.sum(self.x) + Sx2 = np.sum(self.x**2) + Sx3 = np.sum(self.x**3) + Sx4 = np.sum(self.x**4) + Sy = np.sum(self.y) + Sxy = np.sum(self.x * self.y) + Sx2y = np.sum(self.x**2 * self.y) + A = np.array([[Sx4, Sx3, Sx2], [Sx3, Sx2, Sx], [Sx2, Sx, n]]) + B = np.array([Sx2y, Sxy, Sy]) + return np.linalg.solve(A, B) + + def _solve_cubic(self): + n = len(self.x) + Sx = np.sum(self.x) + Sx2 = np.sum(self.x**2) + Sx3 = np.sum(self.x**3) + Sx4 = np.sum(self.x**4) + Sx5 = np.sum(self.x**5) + Sx6 = np.sum(self.x**6) + Sy = np.sum(self.y) + Sxy = np.sum(self.x * self.y) + Sx2y = np.sum(self.x**2 * self.y) + Sx3y = np.sum(self.x**3 * self.y) + A = np.array([[Sx6, Sx5, Sx4, Sx3], [Sx5, Sx4, Sx3, Sx2], [Sx4, Sx3, Sx2, Sx], [Sx3, Sx2, Sx, n]]) + B = np.array([Sx3y, Sx2y, Sxy, Sy]) + return np.linalg.solve(A, B) + + def _solve_exponential(self): + y_safe = np.where(self.y <= 1e-9, 1e-9, self.y) + y_log = np.log(y_safe) + n = len(self.x) + Sx = np.sum(self.x) + Sy = np.sum(y_log) + Sxx = np.sum(self.x**2) + Sxy = np.sum(self.x * y_log) + A = np.array([[Sxx, Sx], [Sx, n]]) + B = np.array([Sxy, Sy]) + b, ln_a = np.linalg.solve(A, B) + return [np.exp(ln_a), b] if abs(b) < 100 else None + + def _solve_logarithmic(self): + x_safe = np.where(self.x <= 1e-9, 1e-9, self.x) + x_log = np.log(x_safe) + n = len(x_log) + Sx = np.sum(x_log) + Sy = np.sum(self.y) + Sxx = np.sum(x_log**2) + Sxy = np.sum(x_log * self.y) + A = np.array([[Sxx, Sx], [Sx, n]]) + B = np.array([Sxy, Sy]) + return np.linalg.solve(A, B) + + def _solve_power(self): + x_safe = np.where(self.x <= 1e-9, 1e-9, self.x) + y_safe = np.where(self.y <= 1e-9, 1e-9, self.y) + x_log = np.log(x_safe) + y_log = np.log(y_safe) + n = len(x_log) + Sx = np.sum(x_log) + Sy = np.sum(y_log) + Sxx = np.sum(x_log**2) + Sxy = np.sum(x_log * y_log) + A = np.array([[Sxx, Sx], [Sx, n]]) + B = np.array([Sxy, Sy]) + b, ln_a = np.linalg.solve(A, B) + return [np.exp(ln_a), b] if abs(b) < 100 else None + + def calculate(self): + models = { + 'Линейная': (self._solve_linear, lambda x, a, b: a*x + b), + 'Квадратичная': (self._solve_quadratic, lambda x, a, b, c: a*x**2 + b*x + c), + 'Кубическая': (self._solve_cubic, lambda x, a, b, c, d: a*x**3 + b*x**2 + c*x + d), + 'Экспоненциальная': (self._solve_exponential, lambda x, a, b: a*np.exp(b*x)), + 'Логарифмическая': (self._solve_logarithmic, lambda x, a, b: a*np.log(np.maximum(x, 1e-9)) + b), + 'Степенная': (self._solve_power, lambda x, a, b: a*np.power(np.maximum(x, 1e-9), b)) + } + + for name, (solver, func) in models.items(): + try: + coeffs = solver() + if coeffs is None: continue + y_pred = func(self.x, *coeffs) + ss_res = np.sum((self.y - y_pred)**2) + ss_tot = np.sum((self.y - np.mean(self.y))**2) + r2 = max(0, min(1 - (ss_res/ss_tot if ss_tot != 0 else 0), 1)) + self.results[name] = { + 'coeffs': np.round(coeffs, 4).tolist(), + 'mse': round(np.mean((self.y - y_pred)**2), 4), + 'r2': round(r2, 2), + 'y_pred': np.round(y_pred, 3).tolist(), + 'errors': np.round(y_pred - self.y, 3).tolist() + } + except: + self.results[name] = None + + return self.results + + def get_pearson(self): + return pearsonr(self.x, self.y)[0] + + @staticmethod + def calculate_best_model(results): + valid = [(k, v) for k, v in results.items() if v] + return min(valid, key=lambda x: x[1]['mse'])[0] if valid else None + +class UserInterface: + @staticmethod + def get_input_choice(): + print("Выберите источник данных:") + print("1. Ввести данные вручную") + print("2. Загрузить из файла") + return input("Ваш выбор: ").strip() + + @staticmethod + def manual_input(): + print("\nВведите данные в формате: x1,y1;x2,y2;...") + while True: + try: + input_str = input("> ").replace(' ', '') + pairs = [p.split(',') for p in input_str.split(';')] + x = [float(p[0]) for p in pairs] + y = [float(p[1]) for p in pairs] + if 8 <= len(x) <= 12 and len(x) == len(y): + return x, y + print("Ошибка: требуется 8-12 пар значений x,y") + except: + print("Некорректный формат! Пример: 0,0;0.2,0.24;...") + + @staticmethod + def file_input(): + while True: + filepath = input("\nВведите путь к файлу: ").strip() + if not os.path.exists(filepath): + print("Файл не существует!") + continue + try: + with open(filepath, 'r') as f: + data = json.load(f) + x = data['x'] + y = data['y'] + if 8 <= len(x) <= 12 and len(x) == len(y): + return x, y + print("Ошибка: файл должен содержать 8-12 пар значений") + except: + print("Ошибка чтения файла! Формат: {'x': [...], 'y': [...]}") + + @staticmethod + def interpret_r2(r2): + if r2 > 0.9: + return "Очень сильная связь" + elif r2 > 0.7: + return "Сильная связь" + elif r2 > 0.5: + return "Умеренная связь" + else: + return "Cлабая связь" + + @staticmethod + def show_results(results, pearson): + print("\nРезультаты:") + print("{:<15} {:<25} {:<10} {:<15} {:<20}".format('Модель', 'Коэффициенты', 'СКО', 'R²', 'Интерпретация R²')) + for name, data in results.items(): + if data: + interp = UserInterface.interpret_r2(data['r2']) + print("{:<15} {:<25} {:<10.4f} {:<15.2f} {:<20}".format( + name, str(data['coeffs']), data['mse'], data['r2'], interp)) + sign = "положительная" if pearson > 0 else "отрицательная" + abs_pearson = abs(pearson) + + print(f"\nКоэффициент Пирсона: {pearson:.3f} ({sign} корреляция)") + + if abs_pearson >= 0.7: + strength = "сильная" + elif abs_pearson >= 0.5: + strength = "умеренная" + elif abs_pearson >= 0.3: + strength = "слабая" + else: + strength = "очень слабая/отсутствует" + + print(f"Сила линейной связи: {strength}") + + @staticmethod + def show_detailed_results(x, y, results, best_model): + print("\nДетализированные результаты:") + print("{:<5} {:<10} {:<10} {:<15} {:<10}".format('i', 'x', 'y', 'y_pred', 'Ошибка')) + for i in range(len(x)): + print("{:<5} {:<10.3f} {:<10.3f} {:<15.3f} {:<10.3f}".format( + i, x[i], y[i], results[best_model]['y_pred'][i], results[best_model]['errors'][i])) + + @staticmethod + def save_to_file(results, pearson, filename='results.txt'): + with open(filename, 'w', encoding='utf-8') as f: + f.write("Результаты аппроксимации\n") + f.write("{:<15} {:<25} {:<10} {:<15}\n".format('Модель', 'Коэффициенты', 'СКО', 'R²')) + for name, data in results.items(): + if data: + f.write("{:<15} {:<25} {:<10.4f} {:<15.2f}\n".format( + name, str(data['coeffs']), data['mse'], data['r2'])) + f.write(f"\nКоэффициент Пирсона: {pearson:.3f}\n") + + @staticmethod + def plot_results(x, y, results): + plt.figure(figsize=(12, 7)) + x_smooth = np.linspace(min(x)-0.5, max(x)+0.5, 200) + plt.scatter(x, y, s=80, label='Данные', zorder=3) + for name, data in results.items(): + if data and data['r2'] > 0: + coeffs = data['coeffs'] + if name == 'Линейная': + y_smooth = coeffs[0] * x_smooth + coeffs[1] + elif name == 'Квадратичная': + y_smooth = coeffs[0]*x_smooth**2 + coeffs[1]*x_smooth + coeffs[2] + elif name == 'Кубическая': + y_smooth = coeffs[0]*x_smooth**3 + coeffs[1]*x_smooth**2 + coeffs[2]*x_smooth + coeffs[3] + elif name == 'Экспоненциальная': + y_smooth = coeffs[0] * np.exp(coeffs[1] * x_smooth) + elif name == 'Логарифмическая': + y_smooth = coeffs[0] * np.log(np.maximum(x_smooth, 1e-9)) + coeffs[1] + elif name == 'Степенная': + y_smooth = coeffs[0] * np.power(np.maximum(x_smooth, 1e-9), coeffs[1]) + else: + continue + plt.plot(x_smooth, y_smooth, label=f"{name} (R²={data['r2']})") + plt.xlabel('x') + plt.ylabel('y') + plt.legend() + plt.grid(True) + plt.title("Аппроксимирующие функции") + plt.savefig("approx_plot.png", dpi=300, bbox_inches='tight') + plt.show() + + @staticmethod + def uncorrected_input(): + print("Некорректный выбор! Перезапустите программу...") + exit() + +if __name__ == "__main__": + choice = UserInterface.get_input_choice() + if choice == '1': + x, y = UserInterface.manual_input() + elif choice == '2': + x, y = UserInterface.file_input() + else: + UserInterface.uncorrected_input() + + core = ApproximationCore(x, y) + results = core.calculate() + pearson = core.get_pearson() + best_model = ApproximationCore.calculate_best_model(results) + + UserInterface.show_results(results, pearson) + if best_model: + UserInterface.show_detailed_results(x, y, results, best_model) + UserInterface.save_to_file(results, pearson) + UserInterface.plot_results(x, y, results) \ No newline at end of file diff --git "a/\320\2403212/dmitriev_408542/lab5/main.py" "b/\320\2403212/dmitriev_408542/lab5/main.py" new file mode 100644 index 0000000..0f0e768 --- /dev/null +++ "b/\320\2403212/dmitriev_408542/lab5/main.py" @@ -0,0 +1,218 @@ +import numpy as np +import matplotlib.pyplot as plt +from math import factorial + + +class InterpolationCore: + def __init__(self, x, y): + self.x = np.array(x) + self.y = np.array(y) + self._validate_input() + self._sort_points() + + def _validate_input(self): + if len(self.x) != len(self.y): + raise ValueError("Количество x и y значений должно быть одинаковым") + if len(self.x) < 2: + raise ValueError("Нужно как минимум 2 точки для интерполяции") + if len(np.unique(self.x)) != len(self.x): + raise ValueError("Все x значения должны быть уникальными") + + def _sort_points(self): + order = np.argsort(self.x) + self.x = self.x[order] + self.y = self.y[order] + + def lagrange(self, x_val): + result = 0.0 + for i in range(len(self.x)): + term = self.y[i] + for j in range(len(self.x)): + if i != j: + term *= (x_val - self.x[j]) / (self.x[i] - self.x[j]) + result += term + return result + + def newton_divided_differences(self): + n = len(self.y) + table = np.zeros((n, n)) + table[:, 0] = self.y + + for j in range(1, n): + for i in range(n - j): + table[i, j] = (table[i + 1, j - 1] - table[i, j - 1]) / (self.x[i + j] - self.x[i]) + return table[0] + + def newton(self, x_val, dd=None): + if dd is None: + dd = self.newton_divided_differences() + result = dd[0] + product = 1.0 + for i in range(1, len(dd)): + product *= (x_val - self.x[i - 1]) + result += dd[i] * product + return result + + def gauss(self, x_val): + n = len(self.x) + h = self.x[1] - self.x[0] + center_idx = np.abs(self.x - x_val).argmin() + + k = min(center_idx, n - center_idx - 1) + start = center_idx - k + end = center_idx + k + 1 + selected_x = self.x[start:end] + selected_y = self.y[start:end] + + t = (x_val - selected_x[k]) / h + result = selected_y[k] + product = 1 + + for i in range(1, k + 1): + product *= (t + (-1) ** (i % 2) * (i // 2)) + delta = self._central_difference(selected_y, k, i) + result += product * delta / factorial(i) + + return result + + def _central_difference(self, y, center, order): + if order == 0: + return y[center] + return self._central_difference(y, center + 1, order - 1) - self._central_difference(y, center - 1, order - 1) + + +class DataInputHandler: + @staticmethod + def get_choice(): + print("\nВыберите источник данных:") + print("1. Ручной ввод") + print("2. Загрузка из файла") + print("3. Генерация по функции") + return input("> ").strip() + + @staticmethod + def manual_input(): + print("\nВведите данные в формате: x1,y1;x2,y2;...") + while True: + try: + data = input("> ").replace(' ', '').split(';') + pairs = [p.split(',') for p in data if p] + x, y = zip(*[(float(p[0]), float(p[1])) for p in pairs]) + return np.array(x), np.array(y) + except Exception as e: + print(f"Ошибка: {str(e)}. Попробуйте снова.") + + @staticmethod + def file_input(): + print("\nВведите имя файла:") + while True: + try: + filename = input("> ").strip() + with open(filename) as f: + data = [line.strip().split(',') for line in f if line.strip()] + x, y = zip(*[(float(p[0]), float(p[1])) for p in data]) + return np.array(x), np.array(y) + except Exception as e: + print(f"Ошибка: {str(e)}. Попробуйте снова.") + + @staticmethod + def function_input(): + print("\nВыберите функцию:") + print("1. sin(x)") + print("2. cos(x)") + print("3. exp(x)") + func = input("> ").strip() + + print("Введите интервал [a, b] и количество точек:") + a = float(input("a = ")) + b = float(input("b = ")) + n = int(input("n = ")) + + x = np.linspace(a, b, n) + if func == '1': + y = np.sin(x) + elif func == '2': + y = np.cos(x) + elif func == '3': + y = np.exp(x) + else: + print("Неизвестная функция, используется sin(x)") + y = np.sin(x) + + return x, y + + +class ResultVisualizer: + @staticmethod + def plot_results(x, y, x_val, results): + plt.figure(figsize=(12, 7)) + + plt.scatter(x, y, s=100, c='red', zorder=4, label='Узлы интерполяции') + + plt.scatter([x_val], [results['Ньютон']], s=200, marker='*', + edgecolor='black', facecolor='gold', zorder=5, + label=f'Интерполяция: {results["Ньютон"]:.4f}') + + x_smooth = np.linspace(min(x) - 0.5, max(x) + 0.5, 200) + core = InterpolationCore(x, y) + + y_lagrange = [core.lagrange(xi) for xi in x_smooth] + plt.plot(x_smooth, y_lagrange, '--', lw=2, alpha=0.7, + label=f'Лагранж ({results["Лагранж"]:.4f})') + + dd = core.newton_divided_differences() + y_newton = [core.newton(xi, dd) for xi in x_smooth] + plt.plot(x_smooth, y_newton, '-.', lw=2, alpha=0.7, + label=f'Ньютон ({results["Ньютон"]:.4f})') + + try: + y_gauss = [core.gauss(xi) for xi in x_smooth] + plt.plot(x_smooth, y_gauss, ':', lw=2, alpha=0.7, + label=f'Гаусс ({results["Гаусс"]:.4f})') + except Exception as e: + print(f"Ошибка метода Гаусса: {str(e)}") + + plt.title("Сравнение методов интерполяции", pad=20, fontsize=14) + plt.xlabel("x", fontsize=12) + plt.ylabel("y", fontsize=12) + plt.legend() + plt.grid(alpha=0.3) + filename = f"interpolation_plot.png" + plt.savefig(filename, dpi=300) +def main(): + try: + choice = DataInputHandler.get_choice() + if choice == '1': + x, y = DataInputHandler.manual_input() + elif choice == '2': + x, y = DataInputHandler.file_input() + elif choice == '3': + x, y = DataInputHandler.function_input() + else: + raise ValueError("Некорректный выбор") + + core = InterpolationCore(x, y) + + dd = core.newton_divided_differences() + print("\nТаблица разделенных разностей Ньютона:") + print("[", ", ".join(f"{val:.4f}" for val in dd), "]") + + x_val = float(input("\nВведите x для интерполяции: ")) + results = { + 'Лагранж': core.lagrange(x_val), + 'Ньютон': core.newton(x_val), + 'Гаусс': core.gauss(x_val) + } + + print("\nРезультаты интерполяции:") + for method, value in results.items(): + print(f"{method:8}: {value:.6f}") + ResultVisualizer.plot_results(x, y, x_val, results) + + except Exception as e: + print(f"\nОшибка: {str(e)}") + print("Проверьте корректность входных данных!") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git "a/\320\2403212/dmitriev_408542/lab6/main.py" "b/\320\2403212/dmitriev_408542/lab6/main.py" new file mode 100644 index 0000000..2622d1b --- /dev/null +++ "b/\320\2403212/dmitriev_408542/lab6/main.py" @@ -0,0 +1,165 @@ +import numpy as np +import matplotlib.pyplot as plt + + +class ODECore: + + def __init__(self, f, x0, y0, xn, h): + self.f = f + self.x0 = x0 + self.y0 = y0 + self.xn = xn + self.h = h + self.x = None + self.y = None + self.errors = None + + def improved_euler(self): + n = int((self.xn - self.x0) / self.h) + 1 + self.x = np.linspace(self.x0, self.xn, n) + self.y = np.zeros(n) + self.y[0] = self.y0 + + for i in range(n - 1): + k1 = self.h * self.f(self.x[i], self.y[i]) + k2 = self.h * self.f(self.x[i] + self.h, self.y[i] + k1) + self.y[i + 1] = self.y[i] + 0.5 * (k1 + k2) + + return self.x, self.y + + def runge_kutta4(self): + n = int((self.xn - self.x0) / self.h) + 1 + self.x = np.linspace(self.x0, self.xn, n) + self.y = np.zeros(n) + self.y[0] = self.y0 + + for i in range(n - 1): + k1 = self.h * self.f(self.x[i], self.y[i]) + k2 = self.h * self.f(self.x[i] + self.h / 2, self.y[i] + k1 / 2) + k3 = self.h * self.f(self.x[i] + self.h / 2, self.y[i] + k2 / 2) + k4 = self.h * self.f(self.x[i] + self.h, self.y[i] + k3) + self.y[i + 1] = self.y[i] + (k1 + 2 * k2 + 2 * k3 + k4) / 6 + + return self.x, self.y + + def milne(self, exact_solution=None): + x_rk, y_rk = self.runge_kutta4() + n = len(x_rk) + self.x = x_rk + self.y = np.zeros(n) + self.y[:4] = y_rk[:4] + + for i in range(3, n - 1): + y_pred = self.y[i - 3] + 4 * self.h / 3 * (2 * self.f(self.x[i], self.y[i]) + - self.f(self.x[i - 1], self.y[i - 1]) + + 2 * self.f(self.x[i - 2], self.y[i - 2])) + + self.y[i + 1] = self.y[i - 1] + self.h / 3 * (self.f(self.x[i + 1], y_pred) + + 4 * self.f(self.x[i], self.y[i]) + + self.f(self.x[i - 1], self.y[i - 1])) + + if exact_solution: + self.errors = [abs(exact_solution(xi) - yi) for xi, yi in zip(self.x, self.y)] + + return self.x, self.y + + +class UserInterface: + + @staticmethod + def get_float_input(prompt, default=None): + while True: + try: + value = input(prompt) + return float(value) if value else default + except ValueError: + print("Ошибка: введите числовое значение!") + + @staticmethod + def get_equation_choice(): + equations = { + '1': {'func': lambda x, y: y + x ** 2, 'exact': lambda x: 2 * np.exp(x) - x ** 2 - 2 * x - 2}, + '2': {'func': lambda x, y: x - y, 'exact': lambda x: (x - 1) + 2 * np.exp(-x)}, + '3': {'func': lambda x, y: 2 * y, 'exact': lambda x: np.exp(2 * x)} + } + + while True: + print("\nВыберите уравнение:") + print("1. y' = y + x²") + print("2. y' = x - y") + print("3. y' = 2y") + choice = input("> ").strip() + + if choice in equations: + return equations[choice] + print("Некорректный выбор! Попробуйте снова.") + + @staticmethod + def get_parameters(): + print("\nВведите параметры дифференциального уравнения:") + + while True: + x0 = UserInterface.get_float_input("Начальное значение x0: ") + y0 = UserInterface.get_float_input("Начальное значение y0: ") + xn = UserInterface.get_float_input("Конец интервала xn: ") + h = UserInterface.get_float_input("Шаг h: ") + + if xn <= x0: + print("Ошибка: xn должен быть больше x0!") + continue + + if h <= 0: + print("Ошибка: шаг h должен быть положительным!") + continue + + return x0, y0, xn, h + + @staticmethod + def show_results(x, y_euler, y_rk, y_milne, exact=None): + print("\nРезультаты вычислений:") + print("{:<8} {:<12} {:<12} {:<12} {:<12}".format( + 'x', 'Эйлер', 'Рунге-Кутта', 'Милн', 'Точное' if exact else '')) + + for i in range(len(x)): + exact_val = exact['exact'](x[i]) if exact else '' + print(f"{x[i]:.3f} {y_euler[i]:<12.6f} {y_rk[i]:<12.6f} " + f"{y_milne[i]:<12.6f} {exact_val if exact else '':<12.6f}") + + @staticmethod + def plot_results(x, y_euler, y_rk, y_milne, exact=None): + plt.figure(figsize=(12, 7)) + + plt.plot(x, y_euler, label='Метод Эйлера', linestyle='--', alpha=0.7) + plt.plot(x, y_rk, label='Рунге-Кутта 4', linestyle='-.', alpha=0.7) + plt.plot(x, y_milne, label='Метод Милна', linestyle=':', alpha=0.7) + + if exact: + x_exact = np.linspace(x[0], x[-1], 100) + plt.plot(x_exact, exact['exact'](x_exact), 'black', label='Точное решение') + + plt.title("Сравнение методов решения ОДУ", fontsize=14) + plt.xlabel("x", fontsize=12) + plt.ylabel("y", fontsize=12) + plt.legend() + plt.grid(True) + plt.savefig('ode_solution.png', dpi=300) + plt.show() + + +if __name__ == "__main__": + try: + equation = UserInterface.get_equation_choice() + + x0, y0, xn, h = UserInterface.get_parameters() + + core = ODECore(equation['func'], x0, y0, xn, h) + + x_euler, y_euler = core.improved_euler() + x_rk, y_rk = core.runge_kutta4() + x_milne, y_milne = core.milne(equation['exact']) + + UserInterface.show_results(x_euler, y_euler, y_rk, y_milne, equation) + UserInterface.plot_results(x_euler, y_euler, y_rk, y_milne, equation) + + except Exception as e: + print(f"\nОшибка: {str(e)}") diff --git "a/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._1.pdf" "b/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._1.pdf" new file mode 100644 index 0000000..3d3b862 Binary files /dev/null and "b/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._1.pdf" differ diff --git "a/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._2.pdf" "b/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._2.pdf" new file mode 100644 index 0000000..0d6f0e4 Binary files /dev/null and "b/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._2.pdf" differ diff --git "a/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._3.pdf" "b/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._3.pdf" new file mode 100644 index 0000000..862eb3e Binary files /dev/null and "b/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._3.pdf" differ diff --git "a/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._4.pdf" "b/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._4.pdf" new file mode 100644 index 0000000..ec3a4d7 Binary files /dev/null and "b/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._4.pdf" differ diff --git "a/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._5.pdf" "b/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._5.pdf" new file mode 100644 index 0000000..97dea5c Binary files /dev/null and "b/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._5.pdf" differ diff --git "a/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._6.pdf" "b/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._6.pdf" new file mode 100644 index 0000000..7bbde71 Binary files /dev/null and "b/\320\2403212/dmitriev_408542/reports/\320\224\320\274\320\270\321\202\321\200\320\270\320\265\320\262_\320\224.\320\241._6.pdf" differ