diff --git "a/\320\2403212/vildanov_408379/lab1/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_1_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" "b/\320\2403212/vildanov_408379/lab1/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_1_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" new file mode 100644 index 0000000..5ac8612 Binary files /dev/null and "b/\320\2403212/vildanov_408379/lab1/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_1_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" differ diff --git "a/\320\2403212/vildanov_408379/lab1/functions.py" "b/\320\2403212/vildanov_408379/lab1/functions.py" new file mode 100644 index 0000000..4a68b67 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab1/functions.py" @@ -0,0 +1,175 @@ +import math +import random + +def is_integer(s: str) -> bool: + s2 = s.strip() + if s2.startswith('-'): + s2 = s2[1:] + return s2.isdigit() + +def is_float(s: str) -> bool: + s2 = s.strip() + if s2.startswith('-'): + s2 = s2[1:] + if s2.count('.') > 1: + return False + if '.' in s2: + parts = s2.split('.') + return all(part.isdigit() for part in parts if part != '') + return s2.isdigit() + +def read_matrix_file(filename: str): + try: + f = open(filename, 'r') + except IOError: + return None + lines = [line.strip() for line in f if line.strip() != ''] + f.close() + if len(lines) < 3: + return None + # n + if not is_integer(lines[0]): + return None + n = int(lines[0]) + if n <= 0: + return None + # tol + if not is_float(lines[1]): + return None + tol = float(lines[1]) + if tol <= 0: + return None + # max_iters + if not is_integer(lines[2]): + return None + max_iters = int(lines[2]) + if max_iters <= 0: + return None + data_lines = lines[3:] + if len(data_lines) != n: + return None + mat = [] + for row_str in data_lines: + parts = row_str.split() + if len(parts) != n + 1: + return None + if not all(is_float(tok) for tok in parts): + return None + mat.append([float(tok) for tok in parts]) + return mat, n, tol, max_iters + +def read_matrix_user(): + while True: + s = input("Введите порядок системы (целое > 0): ").strip() + if is_integer(s) and int(s) > 0: + n = int(s) + break + print("Ошибка: нужно целое положительное число.") + while True: + s = input("Введите точность (вещественное > 0): ").strip() + if is_float(s) and float(s) > 0: + tol = float(s) + break + print("Ошибка: нужно вещественное число > 0.") + while True: + s = input("Введите макс. число итераций (целое > 0): ").strip() + if is_integer(s) and int(s) > 0: + max_iters = int(s) + break + print("Ошибка: нужно целое число > 0.") + print(f"Теперь введите расширенную матрицу ({n} строк по {n+1} чисел):") + mat = [] + for i in range(n): + row_str = input(f"Строка {i+1}: ").strip().split() + if len(row_str) != n + 1: + return None + if not all(is_float(tok) for tok in row_str): + return None + mat.append([float(tok) for tok in row_str]) + return mat, n, tol, max_iters + +def random_matrix(): + while True: + s = input("Введите порядок системы (целое > 0): ").strip() + if is_integer(s) and int(s) > 0: + n = int(s) + break + print("Ошибка: нужно целое положительное число.") + while True: + s = input("Введите точность (вещественное > 0): ").strip() + if is_float(s) and float(s) > 0: + tol = float(s) + break + print("Ошибка: нужно вещественное число > 0.") + while True: + s = input("Введите макс. число итераций (целое > 0): ").strip() + if is_integer(s) and int(s) > 0: + max_iters = int(s) + break + print("Ошибка: нужно целое число > 0.") + mat = [[float(random.randint(1, 9)) for _ in range(n + 1)] for _ in range(n)] + return mat, n, tol, max_iters + +def check_diagonal(mat): + n = len(mat) + strict_found = False + for i in range(n): + s = 0.0 + for j in range(n): + if i == j: + continue + s += abs(mat[i][j]) + if abs(mat[i][i]) < s: + return False + if abs(mat[i][i]) > s: + strict_found = True + return strict_found + +def matrix_norm(mat): + n = len(mat) + best = 0.0 + for i in range(n): + row_sum = sum(abs(mat[i][j]) for j in range(n)) + if row_sum > best: + best = row_sum + return best + +def gauss_seidel(mat, n, tol, max_iters, order): + x_old = [0.0] * n + x_new = [0.0] * n + errors = [0.0] * n + iters = 0 + diff = tol + 1.0 + + while diff > tol and iters < max_iters: + for i in range(n): + s = 0.0 + for j in range(n): + if j != i: + s += mat[i][j] * x_new[j] + x_new[i] = (mat[i][n] - s) / mat[i][i] + + diff = 0.0 + for i in range(n): + d = abs(x_new[i] - x_old[i]) + errors[i] = d + if d > diff: + diff = d + + x_old = x_new.copy() + iters += 1 + + if diff > tol: + return None, None, iters + + final = [0.0] * n + for idx_new, orig_idx in enumerate(order): + final[orig_idx] = x_new[idx_new] + return final, errors, iters + +def print_matrix(mat): + n = len(mat) + for i in range(n): + line = " ".join(f"{mat[i][j]:>7.3f}" for j in range(n)) + line += " | " + f"{mat[i][n]:>7.3f}" + print(line) diff --git "a/\320\2403212/vildanov_408379/lab1/main.py" "b/\320\2403212/vildanov_408379/lab1/main.py" new file mode 100644 index 0000000..d6bc7b0 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab1/main.py" @@ -0,0 +1,88 @@ +from functions import ( + read_matrix_file, + read_matrix_user, + random_matrix, + check_diagonal, + matrix_norm, + gauss_seidel, + print_matrix +) + +def main(): + print("=== Решение СЛАУ методом Гаусса–Зейделя ===") + print("1) Ввод с клавиатуры") + print("2) Загрузка из файла") + print("3) Случайная матрица") + choice = input("Выберите режим (1/2/3): ").strip() + + if choice == "1": + data = read_matrix_user() + elif choice == "2": + data = read_matrix_file("input.txt") + elif choice == "3": + data = random_matrix() + else: + print("Некорректный выбор, выход.") + return + + if data is None: + print("\nОшибка при получении матрицы. Проверьте ввод.") + return + + mat, n, tol, max_iters = data + + print("\n=== Введённая (или загруженная) расширенная матрица ===") + print_matrix(mat) + print(f"\nТочность: {tol:.6g}") + print(f"Максимум итераций: {max_iters}\n") + + order = list(range(n)) + + if check_diagonal(mat): + print("Диагональное преобладание выполняется.\n") + else: + print("Нет диагонального преобладания, идет перестановка столбцов...\n") + for i in range(n): + s = sum(abs(mat[i][j]) for j in range(n) if j != i) + if abs(mat[i][i]) < s: + best_j = i + best_val = abs(mat[i][i]) + for j in range(n): + if j != i and abs(mat[i][j]) > best_val: + best_val = abs(mat[i][j]) + best_j = j + if best_j != i and best_val > s: + for row in range(n): + mat[row][i], mat[row][best_j] = mat[row][best_j], mat[row][i] + order[i], order[best_j] = order[best_j], order[i] + if check_diagonal(mat): + break + + if check_diagonal(mat): + print("Достигнуто диагональное преобладание после перестановки.\n") + else: + print("Не удалось обеспечить диагональное преобладание.\n") + + print("=== Новый вид матрицы после перестановок ===") + print_matrix(mat) + print() + + for i in range(n): + if abs(mat[i][i]) < 1e-15: + print("На диагонали найден ноль, решение невозможно.") + return + + norm_val = matrix_norm(mat) + print(f"Норма матрицы коэффициентов: {norm_val:.6g}\n") + + solution, errors, iters = gauss_seidel(mat, n, tol, max_iters, order) + if solution is None: + print(f"[НЕ СОШЛОСЬ] На {iters}-й итерации не удалось добиться точности {tol}.") + return + + print(f"Решение найдено за {iters} итераций:") + print("Вектор решений x =", solution) + print("Вектор погрешностей r =", errors) + +if __name__ == "__main__": + main() diff --git "a/\320\2403212/vildanov_408379/lab2/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_2_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" "b/\320\2403212/vildanov_408379/lab2/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_2_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" new file mode 100644 index 0000000..24f0f1c Binary files /dev/null and "b/\320\2403212/vildanov_408379/lab2/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_2_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" differ diff --git "a/\320\2403212/vildanov_408379/lab2/src/main.py" "b/\320\2403212/vildanov_408379/lab2/src/main.py" new file mode 100644 index 0000000..4d6f187 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab2/src/main.py" @@ -0,0 +1,228 @@ +import math +import sys + +from methods.common_single import ( + read_interval_and_eps_from_keyboard, + read_interval_and_eps_from_file, + plot_function_on_segment, + plot_function_with_point, + equations_map +) +from methods.chord import chord_method +from methods.secant import secant_method +from methods.simple_iter import simple_iteration_method + +from system.common_system import read_initial_guess_system, plot_two_equations +from system.newton_system import newton_system_method + +SYSTEMS_MAP = { + 1: { + 'name': "Система 1: x² + 2·y² − 5 = 0; e^x + y − 1 = 0", + 'functions': lambda x, y: (x**2 + 2*y**2 - 5, math.exp(x) + y - 1), + 'jacobian': lambda x, y: [[2*x, 4*y], [math.exp(x), 1]] + }, + 2: { + 'name': "Система 2: sin(x) + x·y − 0.5 = 0; x + cos(y) − 2 = 0", + 'functions': lambda x, y: (math.sin(x) + x*y - 0.5, x + math.cos(y) - 2), + 'jacobian': lambda x, y: [[math.cos(x) + y, x], [1, -math.sin(y)]] + } +} + + +def choose_single_equation(): + print("Доступные одиночные уравнения:") + for idx, info in equations_map.items(): + print(f" {idx}) {info['description']}") + while True: + s = input("Выберите номер уравнения: ").strip() + if s.isdigit() and int(s) in equations_map: + return int(s) + print("Ошибка: введите корректный номер.") + + +def choose_system(): + print("Доступные системы:") + for idx, info in SYSTEMS_MAP.items(): + print(f" {idx}) {info['name']}") + while True: + s = input("Выберите номер системы (1 или 2): ").strip() + if s.isdigit() and int(s) in SYSTEMS_MAP: + return int(s) + print("Ошибка: введите 1 или 2.") + + +def output_results(choice: str, lines: list[str]): + if choice == 'console': + for line in lines: + print(line) + else: + filename = input("Введите имя файла для сохранения (например result.txt): ").strip() + try: + with open(filename, 'w') as f: + for line in lines: + f.write(line + "\n") + print(f"Результаты сохранены в файл '{filename}'") + except Exception as e: + print(f"Ошибка при записи в файл: {e}") + print("Вывожу результат в консоль вместо файла:") + for line in lines: + print(line) + + +def solve_single_equation_flow(): + key = choose_single_equation() + info = equations_map[key] + f = info['f'] + phi = info['phi'] + phi_prime = info['phi_prime'] + + print("\nСпособ ввода:") + print(" 1) С клавиатуры") + print(" 2) Из файла") + mode = input("Ваш выбор (1/2): ").strip() + if mode == '1': + a, b, eps = read_interval_and_eps_from_keyboard() + elif mode == '2': + res = read_interval_and_eps_from_file("input_single.txt") + if res is None: + print("Не удалось считать из файла. Проверьте формат.") + return + a, b, eps = res + else: + print("Ошибка: нужно ввести 1 или 2.") + return + + try: + fa = f(a) + fb = f(b) + if fa * fb > 0: + print("\nНа отрезке [a, b] нет гарантии единственного корня.") + return + except Exception as e: + print(f"Ошибка при вычислении f(a) или f(b): {e}") + return + + print("\nМетоды уточнения корня:") + print(" 1) Метод хорд") + print(" 2) Метод секущих") + print(" 3) Метод простой итерации") + choice = input("Выберите метод (1–3): ").strip() + if choice not in ('1', '2', '3'): + print("Ошибка: нужно ввести 1, 2 или 3.") + return + + try: + if choice == '1': + print("\n---- Метод хорд ----") + print("Выберите форму:") + print(" a) фиксируем левый конец (x₀ = b)") + print(" b) фиксируем правый конец (x₀ = a)") + form = input("Ваш выбор (a/b): ").strip().lower() + if form == 'a': + root, fval, iters = chord_method(f, a, b, eps, max_iters=1000, fixed_end='left') + elif form == 'b': + root, fval, iters = chord_method(f, a, b, eps, max_iters=1000, fixed_end='right') + else: + print("Ошибка: нужно 'a' или 'b'.") + return + + elif choice == '2': + print("\n---- Метод секущих ----") + root, fval, iters = secant_method(f, a, b, eps, max_iters=1000) + + else: + print("\n---- Метод простой итерации ----") + root, fval, iters = simple_iteration_method(f, phi, phi_prime, a, b, eps, max_iters=1000) + + except Exception as e: + print(f"\nОшибка во время работы метода: {e}") + return + + lines = [] + lines.append(f"=== Результат одиночного уравнения ({info['description']}) ===") + lines.append(f"Корень x* = {root:.6f}") + lines.append(f"f(x*) = {fval:.6e}") + lines.append(f"Число итераций: {iters}") + lines.append(f"Точность ε = {eps}") + lines.append("="*40) + + print("\nВывод результата:") + print(" 1) В консоль") + print(" 2) В файл") + outm = input("Ваш выбор (1/2): ").strip() + if outm == '1': + output_results('console', lines) + elif outm == '2': + output_results('file', lines) + else: + print("Ошибка: неверный выбор. Вывожу в консоль.") + output_results('console', lines) + + print("\n(Строим график функции…)") + plot_function_with_point(f, a, b, root) + +def solve_system_flow(): + key = choose_system() + info = SYSTEMS_MAP[key] + system = { + 'name': info['name'], + 'functions': info['functions'], + 'jacobian': info['jacobian'] + } + + print("\nВведите начальные приближения для x₀ и y₀:") + x0, y0 = read_initial_guess_system() + + while True: + s = input("Введите ε (точность для системы, float > 0): ").strip() + try: + eps = float(s) + if eps > 0: + break + except: + pass + print("Ошибка: ε должно быть положительным вещественным.") + max_iters = 200 + + try: + x_root, y_root, errors, iters = newton_system_method(system, x0, y0, eps, max_iters) + except Exception as e: + print(f"Ошибка в методе Ньютона для системы: {e}") + return + + lines = [] + lines.append(f"=== Результат для системы ({system['name']}) ===") + lines.append(f"Найденное решение: x* = {x_root:.6f}, y* = {y_root:.6f}") + lines.append(f"Число итераций: {iters}") + lines.append(f"Вектор погрешностей: {errors}") + f1_final, f2_final = system['functions'](x_root, y_root) + lines.append(f"Проверка: f₁(x*,y*) = {f1_final:.2e}, f₂(x*,y*) = {f2_final:.2e}") + lines.append("="*40) + + print("\nВывод результата:") + print(" 1) В консоль") + print(" 2) В файл") + outm = input("Ваш выбор (1/2): ").strip() + if outm == '1': + output_results('console', lines) + elif outm == '2': + output_results('file', lines) + else: + print("Ошибка: неверный выбор. Вывожу в консоль.") + output_results('console', lines) + + print("\n(Строим график системы…)") + plot_two_equations(system, (x_root, y_root)) + + +if __name__ == "__main__": + print("=== Решение нелинейных уравнений и систем нелинейных уравнений ===\n") + print("1) Нелинейное уравнение") + print("2) Система нелинейных уравнений") + choice = input("Выберите (1/2): ").strip() + if choice == '1': + solve_single_equation_flow() + elif choice == '2': + solve_system_flow() + else: + print("Ошибка: нужно ввести 1 или 2.") \ No newline at end of file diff --git "a/\320\2403212/vildanov_408379/lab2/src/methods/chord.py" "b/\320\2403212/vildanov_408379/lab2/src/methods/chord.py" new file mode 100644 index 0000000..250f191 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab2/src/methods/chord.py" @@ -0,0 +1,34 @@ +import math + +def chord_method(f, a: float, b: float, tol: float, max_iters: int = 1000, fixed_end: str = 'left'): + fa = f(a) + fb = f(b) + if fa * fb > 0: + raise ValueError("На данном отрезке нет единственного корня.") + + if fixed_end == 'left': + x_prev = b + fixed_val = a + elif fixed_end == 'right': + x_prev = a + fixed_val = b + else: + raise ValueError("fixed_end должен быть 'left' или 'right'") + + for k in range(1, max_iters + 1): + ff = f(fixed_val) + fx = f(x_prev) + denom = fx - ff + if denom == 0: + raise ZeroDivisionError("Деление на ноль при вычислении хорд.") + x_next = x_prev - (x_prev - fixed_val) * fx / denom + + if math.isnan(x_next) or math.isinf(x_next): + raise ArithmeticError("Хорд: вычислен NaN/Inf.") + + if abs(x_next - x_prev) < tol or abs(f(x_next)) < tol: + return x_next, f(x_next), k + + x_prev = x_next + + raise RuntimeError("Хорды: не сошлось за max_iters.") \ No newline at end of file diff --git "a/\320\2403212/vildanov_408379/lab2/src/methods/common_single.py" "b/\320\2403212/vildanov_408379/lab2/src/methods/common_single.py" new file mode 100644 index 0000000..9037374 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab2/src/methods/common_single.py" @@ -0,0 +1,141 @@ +import math +import numpy as np +import matplotlib +matplotlib.use("TkAgg") +import matplotlib.pyplot as plt + + +def _is_int_string(s: str) -> bool: + st = s.strip() + if st.startswith('-'): + st = st[1:] + return st.isdigit() + + +def _is_float_string(s: str) -> bool: + st = s.strip() + if st.startswith('-'): + st = st[1:] + if st.count('.') > 1: + return False + if '.' in st: + parts = st.split('.') + return all(part.isdigit() for part in parts if part != '') + return st.isdigit() + + +def read_interval_and_eps_from_keyboard() -> tuple: + while True: + s = input("Введите a (левая граница, float): ").strip() + if _is_float_string(s): + a = float(s) + break + print("Ошибка: нужно ввести вещественное число.") + while True: + s = input("Введите b (правая граница, float): ").strip() + if _is_float_string(s): + b = float(s) + break + print("Ошибка: нужно ввести вещественное число.") + while True: + s = input("Введите ε (точность, float > 0): ").strip() + if _is_float_string(s) and float(s) > 0: + eps = float(s) + break + print("Ошибка: ε должно быть положительным вещественным числом.") + return a, b, eps + + +def read_interval_and_eps_from_file(path: str) -> tuple or None: + try: + with open(path, 'r') as f: + lines = [line.strip() for line in f if line.strip() != ""] + except IOError: + return None + + if len(lines) < 3: + return None + + if not (_is_float_string(lines[0]) and _is_float_string(lines[1]) and _is_float_string(lines[2])): + return None + + a = float(lines[0]) + b = float(lines[1]) + eps = float(lines[2]) + if eps <= 0: + return None + + return a, b, eps + + +def plot_function_on_segment(func, a: float, b: float, points: int = 300): + xs = np.linspace(a, b, points) + ys = [func(x) for x in xs] + + plt.figure(figsize=(7, 5)) + plt.plot(xs, ys, label="y = f(x)") + plt.axhline(0, color='black', linewidth=0.7, linestyle='--') + plt.axvline(0, color='black', linewidth=0.7, linestyle='--') + plt.title("График функции на отрезке") + plt.xlabel("x") + plt.ylabel("f(x)") + plt.grid(True) + plt.legend() + + plt.show(block=False) + plt.pause(0.5) + +def plot_function_with_point(func, a: float, b: float, root: float, points: int = 300): + xs = np.linspace(a, b, points) + ys = [func(x) for x in xs] + + plt.figure(figsize=(7, 5)) + plt.plot(xs, ys, label="y = f(x)") + plt.axhline(0, color='black', linewidth=0.7, linestyle='--') + plt.axvline(0, color='black', linewidth=0.7, linestyle='--') + plt.scatter([root], [func(root)], color='green', s=60, label=f"Корень ≈ {root:.6f}") + plt.title("График функции") + plt.xlabel("x") + plt.ylabel("f(x)") + plt.grid(True) + plt.legend() + plt.show() + +def numeric_derivative(func, h: float = 1e-6): + return lambda x: (func(x + h) - func(x - h)) / (2 * h) + +_raw_equations = { + 1: { + "description": "f₁(x) = x⁴ − 3·x + 1", + "f": lambda x: x**4 - 3*x + 1, + "phi": lambda x: (3*x - 1)**(1/4) if (3*x - 1) >= 0 else -((-(3*x - 1))**(1/4)) + }, + 2: { + "description": "f₂(x) = e^{−x} − x² + 2", + "f": lambda x: math.exp(-x) - x**2 + 2, + "phi": lambda x: math.sqrt(math.exp(-x) + 2) if (math.exp(-x) + 2) >= 0 else x + }, + 3: { + "description": "f₃(x) = x·sin(x) − 1", + "f": lambda x: x * math.sin(x) - 1, + "phi": lambda x: math.asin(1/x) if (x != 0 and abs(1/x) <= 1) else x + }, + 4: { + "description": "f₄(x) = ln(x + 2) + x² − 3", + "f": lambda x: (math.log(x + 2) + x**2 - 3) if x > -2 else float('inf'), + "phi": lambda x: (math.sqrt(3 - math.log(x + 2)) if x > -2 and (3 - math.log(x + 2)) >= 0 else x) + } +} + +equations_map = {} +for k, info in _raw_equations.items(): + f_fun = info["f"] + phi_fun = info["phi"] + phi_prime_fun = numeric_derivative(phi_fun) + + equations_map[k] = { + "description": info["description"], + "f": f_fun, + "phi": phi_fun, + "phi_prime": phi_prime_fun + } \ No newline at end of file diff --git "a/\320\2403212/vildanov_408379/lab2/src/methods/secant.py" "b/\320\2403212/vildanov_408379/lab2/src/methods/secant.py" new file mode 100644 index 0000000..5d4ae0e --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab2/src/methods/secant.py" @@ -0,0 +1,18 @@ +import math + +def secant_method(f, a: float, b: float, tol: float, max_iters: int = 1000): + x_prev, x_cur = a, b + f_prev, f_cur = f(x_prev), f(x_cur) + + if f_prev == f_cur: + raise ZeroDivisionError("Секущие: f(a) == f(b), деление на ноль.") + + for k in range(1, max_iters + 1): + x_next = x_cur - (x_cur - x_prev) * f_cur / (f_cur - f_prev) + if math.isnan(x_next) or math.isinf(x_next): + raise ArithmeticError("Секущие: получили NaN/Inf.") + if abs(x_next - x_cur) < tol or abs(f(x_next)) < tol: + return x_next, f(x_next), k + x_prev, f_prev = x_cur, f_cur + x_cur, f_cur = x_next, f(x_next) + raise RuntimeError("Секущие: не сошлось за max_iters.") \ No newline at end of file diff --git "a/\320\2403212/vildanov_408379/lab2/src/methods/simple_iter.py" "b/\320\2403212/vildanov_408379/lab2/src/methods/simple_iter.py" new file mode 100644 index 0000000..ce048e6 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab2/src/methods/simple_iter.py" @@ -0,0 +1,17 @@ +import math +import numpy as np + + +def simple_iteration_method(f, phi, phi_prime, a: float, b: float, tol: float, max_iters: int = 1000): + xs = np.linspace(a, b, 200) + q = max(abs(phi_prime(x)) for x in xs) + if q >= 1: + raise ValueError(f"Условие сходимости не выполнено: max|φ'| = {q:.4f} ≥ 1") + + x = (a + b) / 2 + for k in range(1, max_iters + 1): + x_next = phi(x) + if abs(x_next - x) < tol: + return x_next, f(x_next), k + x = x_next + raise RuntimeError("Простая итерация: не сошлось за max_iters.") \ No newline at end of file diff --git "a/\320\2403212/vildanov_408379/lab2/src/system/common_system.py" "b/\320\2403212/vildanov_408379/lab2/src/system/common_system.py" new file mode 100644 index 0000000..dea0efe --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab2/src/system/common_system.py" @@ -0,0 +1,61 @@ +import math +import numpy as np +import matplotlib +matplotlib.use("TkAgg") +import matplotlib.pyplot as plt + + +def _is_float_string(s: str) -> bool: + st = s.strip() + if st.startswith('-'): + st = st[1:] + if st.count('.') > 1: + return False + if '.' in st: + parts = st.split('.') + return all(part.isdigit() for part in parts if part != '') + return st.isdigit() + + +def read_initial_guess_system() -> tuple: + while True: + xs = input("Введите начальное приближение x₀: ").strip() + if _is_float_string(xs): + x0 = float(xs) + break + print("Некорректно. Ожидается вещественное число.") + while True: + ys = input("Введите начальное приближение y₀: ").strip() + if _is_float_string(ys): + y0 = float(ys) + break + print("Некорректно. Ожидается вещественное число.") + return x0, y0 + + +def plot_two_equations(system: dict, root: tuple or None = None): + f1f2 = system['functions'] + name = system['name'] + + x_vals = np.linspace(-3, 3, 300) + y_vals = np.linspace(-3, 3, 300) + X, Y = np.meshgrid(x_vals, y_vals) + + F1 = np.vectorize(lambda x, y: f1f2(x, y)[0])(X, Y) + F2 = np.vectorize(lambda x, y: f1f2(x, y)[1])(X, Y) + + plt.figure(figsize=(7, 7)) + cs1 = plt.contour(X, Y, F1, levels=[0], colors='r', linewidths=1.2) + plt.clabel(cs1, inline=True, fontsize=10, fmt="f₁=0") + cs2 = plt.contour(X, Y, F2, levels=[0], colors='b', linewidths=1.2) + plt.clabel(cs2, inline=True, fontsize=10, fmt="f₂=0") + + if root is not None: + plt.scatter([root[0]], [root[1]], color='green', s=60, label=f"Корень (≈ {root[0]:.4f}, {root[1]:.4f})") + plt.legend() + + plt.title(f"График системы: {name}") + plt.xlabel("x") + plt.ylabel("y") + plt.grid(True) + plt.show() \ No newline at end of file diff --git "a/\320\2403212/vildanov_408379/lab2/src/system/newton_system.py" "b/\320\2403212/vildanov_408379/lab2/src/system/newton_system.py" new file mode 100644 index 0000000..0b72f5a --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab2/src/system/newton_system.py" @@ -0,0 +1,32 @@ +import math + +def newton_system_method(system: dict, x0: float, y0: float, tol: float, max_iters: int = 100): + f1f2 = system['functions'] + jac = system['jacobian'] + + x, y = x0, y0 + errors = [] + + for k in range(1, max_iters + 1): + f1_val, f2_val = f1f2(x, y) + J11, J12 = jac(x, y)[0] + J21, J22 = jac(x, y)[1] + det = J11 * J22 - J12 * J21 + if abs(det) < 1e-14: + raise ValueError("Якобиан вырождён (det≈0).") + + # dx dy через формулу Крамера + dx = (-f1_val * J22 + f2_val * J12) / det + dy = (J11 * (-f2_val) + f1_val * J21) / det + + x_new = x + dx + y_new = y + dy + err = math.hypot(dx, dy) + errors.append(err) + + if err < tol: + return x_new, y_new, errors, k + + x, y = x_new, y_new + + raise RuntimeError("Ньютон (система): не сошлось за max_iters.") \ No newline at end of file diff --git "a/\320\2403212/vildanov_408379/lab3/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_3_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" "b/\320\2403212/vildanov_408379/lab3/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_3_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" new file mode 100644 index 0000000..476f1d9 Binary files /dev/null and "b/\320\2403212/vildanov_408379/lab3/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_3_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" differ diff --git "a/\320\2403212/vildanov_408379/lab3/src/main.py" "b/\320\2403212/vildanov_408379/lab3/src/main.py" new file mode 100644 index 0000000..90ae5e1 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab3/src/main.py" @@ -0,0 +1,113 @@ +import math +from tabulate import tabulate + +from methods.left_rectangle import left_rectangle +from methods.right_rectangle import right_rectangle +from methods.mid_rectangle import mid_rectangle +from methods.trapezoid import trapezoid +from methods.simpson import simpson +from methods.runge import runge_integral +from plot_function import plot_function + +def f1(x: float) -> float: + return 1 / x + +def F1(x: float) -> float: + return math.log(abs(x)) + +def f2(x: float) -> float: + return x**2 + +def F2(x: float) -> float: + return x**3 / 3 + +def f3(x: float) -> float: + return math.sin(x) + +def F3(x: float) -> float: + return -math.cos(x) + +def f4(x: float) -> float: + return -x**3 - x**2 + x + 3 + +def F4(x: float) -> float: + return (-(x**4)/4) - (x**3)/3 + (x**2)/2 + 3*x + +func_descriptions = { + 1: ("y = sin(x)", f3, F3), + 2: ("y = 1/x", f1, F1), + 3: ("y = -x^3 - x^2 + x + 3", f4, F4), + 4: ("y = x^2", f2, F2), +} + + +methods_info = [ + ("Левые прямоугольники", left_rectangle, 1), + ("Правые прямоугольники", right_rectangle, 1), + ("Средние прямоугольники", mid_rectangle, 2), + ("Трапеции", trapezoid, 2), + ("Симпсон", simpson, 4), +] + +def read_float(prompt: str, positive: bool = False) -> float: + while True: + try: + s = input(prompt).strip() + val = float(s) + if positive and val <= 0: + print("Ошибка: нужно ввести положительное число.") + continue + return val + except ValueError: + print("Ошибка: введите корректное число.") + +def main() -> None: + print("=== Лабораторная №3: Численное интегрирование ===\n") + + for idx, (desc, _, _) in func_descriptions.items(): + print(f"{idx}) {desc}") + while True: + try: + choice = int(input("Ваш выбор (1–4): ").strip()) + if choice in func_descriptions: + break + print("Ошибка: выберите индекс от 1 до 4.") + except ValueError: + print("Ошибка: введите целое число.") + desc, f, F_exact = func_descriptions[choice] + + a = read_float("Введите a (левая граница): ") + b = read_float("Введите b (правая граница, > a): ") + if b <= a: + print("Ошибка: правая граница должна быть больше левой.") + return + + eps = read_float("Введите точность ε (> 0): ", positive=True) + + print(f"\nВыбранная функция: {desc}") + print(f"Интервал интегрирования: [{a}, {b}], ε = {eps:e}\n") + + plot_function(f, a, b) + + try: + exact_val = F_exact(b) - F_exact(a) + print(f"Точное значение ∫[{a}, {b}] f(x) dx = {exact_val:.8f}\n") + except Exception: + print("Точное значение не вычислено (нет подходящей первообразной).\n") + + results_table = [] + + for method_name, method_func, order in methods_info: + I_approx, n_used = runge_integral(method_func, f, a, b, eps, order) + results_table.append((method_name, f"{I_approx:.8f}", n_used)) + + print(tabulate( + results_table, + headers=["Метод", "I_approx", "n отрезков"], + tablefmt="github" + )) + + print("\n=== Расчёт завершён ===") + +if __name__ == "__main__": + main() diff --git "a/\320\2403212/vildanov_408379/lab3/src/methods/left_rectangle.py" "b/\320\2403212/vildanov_408379/lab3/src/methods/left_rectangle.py" new file mode 100644 index 0000000..5ba126b --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab3/src/methods/left_rectangle.py" @@ -0,0 +1,7 @@ +def left_rectangle(f, a: float, b: float, n: int) -> float: + h = (b - a) / n + total = 0.0 + for i in range(n): + x_i = a + i * h + total += f(x_i) + return total * h diff --git "a/\320\2403212/vildanov_408379/lab3/src/methods/mid_rectangle.py" "b/\320\2403212/vildanov_408379/lab3/src/methods/mid_rectangle.py" new file mode 100644 index 0000000..17898fe --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab3/src/methods/mid_rectangle.py" @@ -0,0 +1,7 @@ +def mid_rectangle(f, a: float, b: float, n: int) -> float: + h = (b - a) / n + total = 0.0 + for i in range(n): + x_mid = a + (i + 0.5) * h + total += f(x_mid) + return total * h diff --git "a/\320\2403212/vildanov_408379/lab3/src/methods/right_rectangle.py" "b/\320\2403212/vildanov_408379/lab3/src/methods/right_rectangle.py" new file mode 100644 index 0000000..2ce29a4 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab3/src/methods/right_rectangle.py" @@ -0,0 +1,7 @@ +def right_rectangle(f, a: float, b: float, n: int) -> float: + h = (b - a) / n + total = 0.0 + for i in range(n): + x_i = a + (i + 1) * h + total += f(x_i) + return total * h diff --git "a/\320\2403212/vildanov_408379/lab3/src/methods/runge.py" "b/\320\2403212/vildanov_408379/lab3/src/methods/runge.py" new file mode 100644 index 0000000..84fa658 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab3/src/methods/runge.py" @@ -0,0 +1,22 @@ +def runge_integral( + integrator: callable, + f: callable, + a: float, + b: float, + tol: float, + order: int +) -> tuple[float, int]: + + n = 4 + I_n = integrator(f, a, b, n) + I_2n = integrator(f, a, b, 2 * n) + + # пока оценка погрешности > tol, удваиваем n + while abs(I_2n - I_n) / (2**order - 1) > tol: + n *= 2 + I_n = integrator(f, a, b, n) + I_2n = integrator(f, a, b, 2 * n) + + # коррекция Рунге + I_corr = I_2n + (I_2n - I_n) / (2**order - 1) + return I_corr, 2 * n diff --git "a/\320\2403212/vildanov_408379/lab3/src/methods/simpson.py" "b/\320\2403212/vildanov_408379/lab3/src/methods/simpson.py" new file mode 100644 index 0000000..14b1ef2 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab3/src/methods/simpson.py" @@ -0,0 +1,14 @@ +def simpson(f, a: float, b: float, n: int) -> float: + if n % 2 != 0: + n += 1 + h = (b - a) / n + total = f(a) + f(b) + # сумма для нечетных индексов: 4 * f(a + (2k+1)h) + for i in range(1, n, 2): + x_i = a + i * h + total += 4 * f(x_i) + # сумма для четных индексов: 2 * f(a + 2k h) + for i in range(2, n, 2): + x_i = a + i * h + total += 2 * f(x_i) + return total * (h / 3) diff --git "a/\320\2403212/vildanov_408379/lab3/src/methods/trapezoid.py" "b/\320\2403212/vildanov_408379/lab3/src/methods/trapezoid.py" new file mode 100644 index 0000000..511a4fe --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab3/src/methods/trapezoid.py" @@ -0,0 +1,7 @@ +def trapezoid(f, a: float, b: float, n: int) -> float: + h = (b - a) / n + total = f(a) + f(b) + for i in range(1, n): + x_i = a + i * h + total += 2 * f(x_i) + return total * h / 2 diff --git "a/\320\2403212/vildanov_408379/lab3/src/plot_function.py" "b/\320\2403212/vildanov_408379/lab3/src/plot_function.py" new file mode 100644 index 0000000..e6e9eb8 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab3/src/plot_function.py" @@ -0,0 +1,14 @@ +import numpy as np +import matplotlib.pyplot as plt + +def plot_function(f: callable, a: float, b: float, points: int = 500) -> None: + xs = np.linspace(a, b, points) + ys = [f(x) for x in xs] + plt.figure(figsize=(8, 5)) + plt.plot(xs, ys, 'b-', label='f(x)') + plt.title(f'График функции на [{a:.3g}, {b:.3g}]') + plt.xlabel('x') + plt.ylabel('f(x)') + plt.grid(True) + plt.legend() + plt.show() diff --git "a/\320\2403212/vildanov_408379/lab4/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_4_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" "b/\320\2403212/vildanov_408379/lab4/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_4_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" new file mode 100644 index 0000000..36abd38 Binary files /dev/null and "b/\320\2403212/vildanov_408379/lab4/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_4_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" differ diff --git "a/\320\2403212/vildanov_408379/lab4/src/approximations.py" "b/\320\2403212/vildanov_408379/lab4/src/approximations.py" new file mode 100644 index 0000000..8e4986c --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab4/src/approximations.py" @@ -0,0 +1,144 @@ +import math +import numpy as np + +def linear_approximation(X, Y): + sx = sum(X) + sxx = sum(x*x for x in X) + sy = sum(Y) + sxy = sum(x*y for x, y in zip(X, Y)) + A, B = np.linalg.solve([[len(X), sx], [sx, sxx]], [sy, sxy]) + return A, B + +def square_approximation(X, Y): + sx = sum(X) + sxx = sum(x*x for x in X) + sxxx = sum(x**3 for x in X) + sxxxx = sum(x**4 for x in X) + sy = sum(Y) + sxy = sum(x*y for x, y in zip(X, Y)) + sxxy = sum(x*x*y for x, y in zip(X, Y)) + A, B, C = np.linalg.solve( + [[len(X), sx, sxx], + [sx, sxx, sxxx], + [sxx, sxxx, sxxxx]], + [sy, sxy, sxxy] + ) + return A, B, C + +def cube_approximation(X, Y): + sx = sum(X) + sxx = sum(x*x for x in X) + sxxx = sum(x**3 for x in X) + sxxxx = sum(x**4 for x in X) + sxxxxx = sum(x**5 for x in X) + sxxxxxx = sum(x**6 for x in X) + sy = sum(Y) + sxy = sum(x*y for x, y in zip(X, Y)) + sxxy = sum(x*x*y for x, y in zip(X, Y)) + sxxxy = sum(x**3 * y for x, y in zip(X, Y)) + A, B, C, D = np.linalg.solve( + [[len(X), sx, sxx, sxxx], + [sx, sxx, sxxx, sxxxx], + [sxx, sxxx, sxxxx, sxxxxx], + [sxxx, sxxxx, sxxxxx, sxxxxxx]], + [sy, sxy, sxxy, sxxxy] + ) + return A, B, C, D + +def exponential_approximation(X, Y): + lnY = [math.log(y) for y in Y] + A, b = linear_approximation(X, lnY) + return math.exp(A), b + +def logarithmic_approximation(X, Y): + lnX = [math.log(x) for x in X] + A, b = np.linalg.solve( + [[len(X), sum(lnX)], [sum(lnX), sum(v*v for v in lnX)]], + [sum(Y), sum(y*lx for y, lx in zip(Y, lnX))] + ) + return A, b + +def power_approximation(X, Y): + lnX = [math.log(x) for x in X] + lnY = [math.log(y) for y in Y] + A, b = linear_approximation(lnX, lnY) + return math.exp(A), b + +def get_linear_approximation(X, Y): + A, B = linear_approximation(X, Y) + return lambda x: A + B*x + +def get_square_approximation(X, Y): + A, B, C = square_approximation(X, Y) + return lambda x: A + B*x + C*x**2 + +def get_cube_approximation(X, Y): + A, B, C, D = cube_approximation(X, Y) + return lambda x: A + B*x + C*x**2 + D*x**3 + +def get_exponential_approximation(X, Y): + A, b = exponential_approximation(X, Y) + return lambda x: A * np.exp(b*x) + +def get_logarithmic_approximation(X, Y): + A, b = logarithmic_approximation(X, Y) + return lambda x: A + b*np.log(x) + +def get_power_approximation(X, Y): + A, b = power_approximation(X, Y) + return lambda x: A * x**b + +def count_correlation(X, Y): + mx, my = sum(X)/len(X), sum(Y)/len(Y) + num = sum((x-mx)*(y-my) for x,y in zip(X,Y)) + den = math.sqrt(sum((x-mx)**2 for x in X) * sum((y-my)**2 for y in Y)) + return num/den + +def count_R2(Y, PHI): + m = sum(PHI)/len(PHI) + ss_res = sum((y - p)**2 for y, p in zip(Y, PHI)) + ss_tot = sum((y - m)**2 for y in Y) + return 1 - ss_res/ss_tot + +def count_sigma(Y, PHI): + n = len(Y) + return math.sqrt(sum((y - p)**2 for y,p in zip(Y,PHI)) / n) + +FUNCTIONS = [ + (linear_approximation, get_linear_approximation, "Линейная", + lambda c: f"{c[1]:.3f}x + {c[0]:.3f}"), + (square_approximation, get_square_approximation, "Полиноминальная 2-й степени", + lambda c: f"{c[2]:.3f}x^2 + {c[1]:.3f}x + {c[0]:.3f}"), + (cube_approximation, get_cube_approximation, "Полиноминальная 3-й степени", + lambda c: f"{c[3]:.3f}x^3 + {c[2]:.3f}x^2 + {c[1]:.3f}x + {c[0]:.3f}"), + (exponential_approximation, get_exponential_approximation, "Экспоненциальная", + lambda c: f"{c[0]:.3f} * e^{c[1]:.3f}x"), + (logarithmic_approximation, get_logarithmic_approximation, "Логарифмическая", + lambda c: f"{c[1]:.3f} * ln(x) + {c[0]:.3f}"), + (power_approximation, get_power_approximation, "Степенная", + lambda c: f"{c[0]:.3f} * x^{c[1]:.3f}"), +] + +def run_approximations(X, Y): + results = [] + for approx, maker, name, fmt in FUNCTIONS: + try: + coeffs = approx(X, Y) + phi = maker(X, Y) + PHI = [phi(x) for x in X] + sigma = count_sigma(Y, PHI) + R2 = count_R2(Y, PHI) + S = sum((y - p)**2 for y,p in zip(Y,PHI)) + r = count_correlation(X, Y) if name == "Линейная" else None + results.append({ + "name": name, + "formula": fmt(coeffs), + "sigma": sigma, + "R2": R2, + "S": S, + "r": r, + "phi": phi + }) + except Exception: + pass + return results diff --git "a/\320\2403212/vildanov_408379/lab4/src/io_utils.py" "b/\320\2403212/vildanov_408379/lab4/src/io_utils.py" new file mode 100644 index 0000000..6731761 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab4/src/io_utils.py" @@ -0,0 +1,73 @@ +import os + +def choose_input(): + while True: + choice = input("Выберите способ ввода: консоль — '1', файл — '2': ").strip() + if choice == '1': + data = [] + print("Введите точки в формате `x y`. По окончании ввода введите `q`.") + while True: + line = input().strip() + if line.lower() == 'q': + break + parts = line.split() + if len(parts) != 2: + print("Неверный формат, введите два числа через пробел или `q`.") + continue + try: + x, y = float(parts[0]), float(parts[1]) + except ValueError: + print("Ошибка: не число. Попробуйте снова.") + continue + data.append((x, y)) + if not data: + print("Нет ни одной точки! Попробуйте заново.") + continue + + elif choice == '2': + filename = input("Введите имя входного файла: ").strip() + if not os.path.isfile(filename): + print(f"Файл '{filename}' не найден.") + continue + data = [] + with open(filename, encoding='utf-8') as f: + for line in f: + s = line.strip() + if not s or s.startswith('#'): + continue + parts = s.split() + if len(parts) != 2: + print(f"Пропускаю строку с неверным форматом: {s}") + continue + try: + x, y = float(parts[0]), float(parts[1]) + except ValueError: + print(f"Не могу преобразовать числа в строке: {s}") + continue + data.append((x, y)) + if not data: + print("В файле нет корректных точек. Выберите другой файл.") + continue + + else: + print("Введите '1' или '2'.") + continue + + X, Y = zip(*data) + n = len(X) + if not (8 <= n <= 12): + print(f"Ошибка: требуется от 8 до 12 точек, у вас {n}. Попробуйте снова.\n") + continue + + return list(X), list(Y) + + +def choose_output(): + while True: + choice = input("Выберите способ вывода: консоль — '1', файл — '2': ").strip() + if choice == '1': + return None + elif choice == '2': + return "result.txt" + else: + print("Введите '1' или '2'.") diff --git "a/\320\2403212/vildanov_408379/lab4/src/main.py" "b/\320\2403212/vildanov_408379/lab4/src/main.py" new file mode 100644 index 0000000..4d587f7 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab4/src/main.py" @@ -0,0 +1,66 @@ +from io_utils import choose_input, choose_output +from approximations import run_approximations +from plot_utils import plot_results + +def quality_R2(R2): + if R2 >= 0.95: + return "Высокая аппроксимация" + elif R2 >= 0.75: + return "Удовлетворительная аппроксимация" + elif R2 >= 0.5: + return "Слабая аппроксимация" + else: + return "Нет аппроксимации" + +def format_result(res): + lines = [ + f"Аппроксимирующая функция: {res['name']}", + f"Функция: φ(x) = {res['formula']}", + f"Среднеквадратичное отклонение: σ = {res['sigma']:.3f}", + f"Коэффициент детерминации: R² = {res['R2']:.3f} ({quality_R2(res['R2'])})", + f"Мера отклонения (SSE): S = {res['S']:.3f}", + "", + # печатаем массивы + "Массивы значений:", + "xᵢ: " + ", ".join(f"{x:.3f}" for x in res['X']), + "yᵢ: " + ", ".join(f"{y:.3f}" for y in res['Y']), + "φ(xᵢ): " + ", ".join(f"{p:.3f}" for p in res['PHI_list']), + "εᵢ: " + ", ".join(f"{e:.3f}" for e in res['EPS_list']), + "=" * 50 + ] + if res['r'] is not None: + lines.insert(5, f"Коэффициент корреляции Пирсона: r = {res['r']:.3f}") + return "\n".join(lines) + +def main(): + X, Y = choose_input() + + results = run_approximations(X, Y) + + for r in results: + r['X'] = X + r['Y'] = Y + phi_list = [r['phi'](x) for x in X] + r['PHI_list'] = phi_list + r['EPS_list'] = [p - y for p, y in zip(phi_list, Y)] + + best = max(results, key=lambda r: r['R2']) + + out_file = choose_output() + if out_file: + with open(out_file, 'w', encoding='utf-8') as f: + for r in results: + f.write(format_result(r) + "\n") + f.write(f"\nЛучшая аппроксимирующая функция: {best['name']}\n") + f.write(f"Формула: φ(x) = {best['formula']}\n") + print(f"Результаты сохранены в {out_file}") + else: + for r in results: + print(format_result(r)) + print(f"Лучшая аппроксимирующая функция: {best['name']}") + print(f"Формула: φ(x) = {best['formula']}") + + plot_results(X, Y, results) + +if __name__ == "__main__": + main() diff --git "a/\320\2403212/vildanov_408379/lab4/src/plot_utils.py" "b/\320\2403212/vildanov_408379/lab4/src/plot_utils.py" new file mode 100644 index 0000000..c5a92aa --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab4/src/plot_utils.py" @@ -0,0 +1,32 @@ +import matplotlib +matplotlib.use('TkAgg') +import matplotlib.pyplot as plt +import numpy as np + +def plot_results(X, Y, results): + x_min, x_max = min(X), max(X) + dx = (x_max - x_min) * 0.05 + x_vals = np.linspace(x_min - dx, x_max + dx, 400) + + all_y = list(Y) + for res in results: + yv = res["phi"](x_vals) + all_y.extend(yv if isinstance(yv, np.ndarray) else list(yv)) + y_min, y_max = min(all_y), max(all_y) + dy = (y_max - y_min) * 0.05 if y_max != y_min else max(abs(y_max),1)*0.05 + + plt.figure() + plt.title("Аппроксимация функции") + plt.xlabel("x") + plt.ylabel("y") + + plt.scatter(X, Y, label="Вводные точки") + for res in results: + y_vals = res["phi"](x_vals) + plt.plot(x_vals, y_vals, label=res["name"], linewidth=1) + + plt.xlim(x_min - dx, x_max + dx) + plt.ylim(y_min - dy, y_max + dy) + plt.legend() + plt.grid(True) + plt.show() diff --git "a/\320\2403212/vildanov_408379/lab5/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_5_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" "b/\320\2403212/vildanov_408379/lab5/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_5_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" new file mode 100644 index 0000000..f94749e Binary files /dev/null and "b/\320\2403212/vildanov_408379/lab5/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_5_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" differ diff --git "a/\320\2403212/vildanov_408379/lab5/src/diff_utils.py" "b/\320\2403212/vildanov_408379/lab5/src/diff_utils.py" new file mode 100644 index 0000000..2bb75ca --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab5/src/diff_utils.py" @@ -0,0 +1,19 @@ +def build_difference_table(xs, ys): + n = len(xs) + deltas = [ys.copy()] + for i in range(1, n): + row = [] + prev = deltas[i-1] + for j in range(n - i): + row.append(prev[j+1] - prev[j]) + deltas.append(row) + return deltas + +def print_difference_table(deltas): + n = len(deltas[0]) + print("\nТаблица конечных разностей:") + for j in range(n): + for i in range(n - j): + print(f"{deltas[i][j]:>10.4f}", end=" ") + print() + print() diff --git "a/\320\2403212/vildanov_408379/lab5/src/interpolation.py" "b/\320\2403212/vildanov_408379/lab5/src/interpolation.py" new file mode 100644 index 0000000..4c4fb17 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab5/src/interpolation.py" @@ -0,0 +1,121 @@ +from functools import reduce +import math + +def lagrange(xs, ys): + n = len(xs) + def P(x): + total = 0 + for i in range(n): + term = ys[i] + for j in range(n): + if i != j: + term *= (x - xs[j])/(xs[i] - xs[j]) + total += term + return total + return P + +def newton_divided(xs, ys): + n = len(xs) + coeffs = [ys[0]] * n + def compute(a, b): + if a == b: + return ys[a] + num = compute(a+1, b) - compute(a, b-1) + den = xs[b] - xs[a] + res = num/den + if a == 0: + coeffs[b] = res + return res + compute(0, n-1) + def P(x): + res = coeffs[0] + prod = 1 + for k in range(1, n): + prod *= (x - xs[k-1]) + res += coeffs[k] * prod + return res + return P + +def is_equidistant(xs, tol=1e-8): + h = xs[1] - xs[0] + return all(abs((xs[i] - xs[i-1]) - h) < tol for i in range(2, len(xs))) + +def newton_finite(xs, ys, deltas): + def P(x): + h = xs[1] - xs[0] + mid = (xs[0] + xs[-1]) / 2 + if x <= mid: + t = (x - xs[0]) / h + res = deltas[0][0] + for i in range(1, len(deltas)): + term = deltas[i][0] + for j in range(i): + term *= (t - j) + term /= math.factorial(i) + res += term + return res + else: + t = (x - xs[-1]) / h + res = deltas[0][-1] + for i in range(1, len(deltas)): + term = deltas[i][-1] + for j in range(i): + term *= (t + j) + term /= math.factorial(i) + res += term + return res + return P + +def stirling(xs, ys, deltas): + n = len(xs) + if not is_equidistant(xs) or n % 2 == 0: + raise ValueError("Для многочлена Стирлинга нужны нечётные равномерные узлы") + def P(x): + zero = n // 2 + h = xs[1] - xs[0] + t = (x - xs[zero]) / h + res = ys[zero] + for i in range(1, zero+1): + d1 = deltas[2*i-1][zero - i] + d2 = deltas[2*i-1][zero - i + 1] + num = d1 + d2 + term = t + for j in range(1, i): + term *= (t**2 - j**2) + term *= num/(2 * math.factorial(2*i-1)) + res += term + d = deltas[2*i][zero - i] + term2 = 1 + for j in range(i): + term2 *= (t**2 - j**2) + term2 *= d/math.factorial(2*i) + res += term2 + return res + return P + +def bessel(xs, ys, deltas): + n = len(xs) + if not is_equidistant(xs) or n % 2 != 0: + raise ValueError("Число узлов должно быть чётным и равномерным") + def P(x): + zero = n//2 - 1 + h = xs[1] - xs[0] + t = (x - xs[zero]) / h + res = 0 + for i in range(zero+1): + d_even = deltas[2*i][zero - i] + term_e = 1 + for j in range(-i, i): + term_e *= (t + j) + term_e *= (d_even)/(math.factorial(2*i)*2) + res += term_e + + if 2*i+1 < len(deltas): + d_odd = deltas[2*i+1][zero - i] + term_o = (t - 0.5) + for j in range(-i, i): + term_o *= (t + j) + term_o *= d_odd/math.factorial(2*i+1) + res += term_o + return res + return P diff --git "a/\320\2403212/vildanov_408379/lab5/src/io_utils.py" "b/\320\2403212/vildanov_408379/lab5/src/io_utils.py" new file mode 100644 index 0000000..1714ed0 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab5/src/io_utils.py" @@ -0,0 +1,92 @@ +import os +import math + +generative_functions = [ + ("sin(x)", lambda x: math.sin(x)), + ("e^x", lambda x: math.e ** x), + ("3x^3-2x^2+4", lambda x: 3*x**3 - 2*x**2 + 4), +] + +def read_points_console(): + print("Введите точки в формате `x y`. По окончании ввода введите `q`.") + data = [] + while True: + line = input().strip() + if line.lower() == 'q': + break + parts = line.split() + if len(parts) != 2: + print("Неверный формат, нужно два числа или `q`.") + continue + try: + x,y = float(parts[0]), float(parts[1]) + except ValueError: + print("Не число, попробуйте снова.") + continue + data.append((x,y)) + return zip(*data) + +def read_points_file(): + while True: + fname = input("Введите имя файла с точками: ").strip() + if not os.path.isfile(fname): + print(f"Файл «{fname}» не найден. Попробуйте снова.") + continue + xs, ys = [], [] + with open(fname, encoding='utf-8') as f: + for line in f: + s = line.strip() + if not s or s.startswith('#'): + continue + parts = s.split() + if len(parts) != 2: + print(f"Пропускаю строку некорр.: {s}") + continue + try: + x,y = float(parts[0]), float(parts[1]) + except ValueError: + print(f"Не могу распознать числа в: {s}") + continue + xs.append(x); ys.append(y) + if xs: + return xs, ys + print("В файле нет корректных точек.") + +def generate_points(): + # Выбор функции + print("Выберите функцию для генерации узлов:") + for i,(name,_) in enumerate(generative_functions,1): + print(f" {i}. {name}") + while True: + idx = int(input("Ваш выбор: ")) + if 1 <= idx <= len(generative_functions): + fname, f = generative_functions[idx-1] + break + print("Нет такой опции.") + a = float(input("Введите нижнюю границу отрезка: ")) + b = float(input("Введите верхнюю границу отрезка: ")) + n = int(input("Введите число узлов: ")) + h = (b - a) / (n - 1) + xs = [a + i*h for i in range(n)] + ys = [f(x) for x in xs] + return xs, ys + +def choose_nodes(): + print("Выберите способ задания функции: консоль — 1, файл — 2, функция — 3") + while True: + choice = input("Ваш выбор: ").strip() + if choice == '1': + xs, ys = read_points_console() + break + if choice == '2': + xs, ys = read_points_file() + break + if choice == '3': + xs, ys = generate_points() + break + print("Введите 1, 2 или 3.") + return list(xs), list(ys) + +def choose_interpolation_point(): + x0 = float(input("Введите точку интерполяции: ")) + return x0 diff --git "a/\320\2403212/vildanov_408379/lab5/src/main.py" "b/\320\2403212/vildanov_408379/lab5/src/main.py" new file mode 100644 index 0000000..f349189 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab5/src/main.py" @@ -0,0 +1,47 @@ +from io_utils import choose_nodes, choose_interpolation_point +from diff_utils import build_difference_table, print_difference_table +from interpolation import (lagrange, newton_divided, newton_finite, stirling, bessel, is_equidistant) +from plot_utils import plot_interpolations + +def main(): + xs, ys = choose_nodes() + + x0 = choose_interpolation_point() + + deltas = build_difference_table(xs, ys) + print_difference_table(deltas) + + methods = [ + ("Лагранжа", lagrange(xs, ys)), + ("Ньютона (разд.)", newton_divided(xs, ys)), + ] + + if is_equidistant(xs): + methods.append(("Ньютона (кон.)", newton_finite(xs, ys, deltas))) + + try: + methods.append(("Стирлинга", stirling(xs, ys, deltas))) + except ValueError as e: + print("Интерполирующая функция Стирлинга → ОШИБКА:", e) + + try: + methods.append(("Бесселя", bessel(xs, ys, deltas))) + except ValueError as e: + print("Интерполирующая функция Бесселя → ОШИБКА:", e) + else: + print("Стирлинга и Бесселя пропущены: узлы неравномерные") + + print() + for name, func in methods: + try: + val = func(x0) + print(f"Интерполирующая функция: Интерполяционный многочлен {name}") + print(f"P({x0}) = {val}") + except Exception as err: + print(f"{name} → ОШИБКА при вычислении: {err}") + print("="*50) + + plot_interpolations(xs, ys, x0, methods) + +if __name__ == "__main__": + main() diff --git "a/\320\2403212/vildanov_408379/lab5/src/plot_utils.py" "b/\320\2403212/vildanov_408379/lab5/src/plot_utils.py" new file mode 100644 index 0000000..6bcdf70 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab5/src/plot_utils.py" @@ -0,0 +1,28 @@ +import matplotlib +matplotlib.use('TkAgg') +import matplotlib.pyplot as plt +import numpy as np + +def plot_interpolations(xs, ys, x0, methods): + x_min, x_max = min(xs), max(xs) + margin = (x_max - x_min)*0.05 + x_vals = np.linspace(x_min-margin, x_max+margin, 400) + + plt.figure() + plt.title("Интерполяция функции") + plt.xlabel("x") + plt.ylabel("y") + + for name, func in methods: + y_vals = [func(x) for x in x_vals] + plt.plot(x_vals, y_vals, label=name, linewidth=1) + + plt.scatter(xs, ys, color='black', label='Точки') + + for name, func in methods: + y0 = func(x0) + plt.scatter([x0], [y0], marker='x', s=70, label=f"{name} в x={x0}") + + plt.legend(loc='best') + plt.grid(True) + plt.show() diff --git "a/\320\2403212/vildanov_408379/lab6/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_6_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" "b/\320\2403212/vildanov_408379/lab6/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_6_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" new file mode 100644 index 0000000..a47159f Binary files /dev/null and "b/\320\2403212/vildanov_408379/lab6/docs/\320\222\320\253\320\247\320\234\320\220\320\242_\320\233\320\240_6_\320\222\320\270\320\273\321\214\320\264\320\260\320\275\320\276\320\262.pdf" differ diff --git "a/\320\2403212/vildanov_408379/lab6/src/main.py" "b/\320\2403212/vildanov_408379/lab6/src/main.py" new file mode 100644 index 0000000..7a1d470 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab6/src/main.py" @@ -0,0 +1,216 @@ +import math +import numpy as np +import matplotlib.pyplot as plt +from tabulate import tabulate + +from methods.euler import euler_method +from methods.rk4 import rk4_method +from methods.milne import milne_method + + +funcs = [ + [ + "y' = y/3 + 2x", + lambda x, y: y / 3 + 2 * x, + lambda x, x0, y0: ((y0 + 6 * x0 + 18) / math.exp(x0 / 3)) * math.exp(x / 3) - 6 * x - 18 + ], + [ + "y' = x + y", + lambda x, y: x + y, + lambda x, x0, y0: ((y0 + x0 + 1) / math.exp(x0)) * math.exp(x) - x - 1 + ], + [ + "y' = 2y + cos(x)", + lambda x, y: 2 * y + math.cos(x), + lambda x, x0, y0: ( + (y0 + 2 * math.cos(x0) / 5 - math.sin(x0) / 5) / math.exp(2 * x0) + ) * math.exp(2 * x) + + math.sin(x) / 5 - 2 * math.cos(x) / 5 + ], + [ + "y' = y + (1 + x)·y²", + lambda x, y: y + (1 + x) * y ** 2, + lambda x, x0, y0: -math.exp(x) / (x * math.exp(x) - (x0 * math.exp(x0) * y0 + math.exp(x0)) / y0) + ] +] + +methods = [ + ("Метод Эйлера (p=1)", euler_method, 1, "o"), + ("Метод Рунге-Кутта 4-го порядка (p=4)", rk4_method, 4, "s"), + ("Метод Милна", milne_method, None, "^") +] + + +def read_float(prompt: str, positive: bool = False) -> float: + while True: + s = input(prompt).strip() + try: + v = float(s) + if positive and v <= 0: + print("Ошибка: введите положительное число.") + continue + return v + except: + print("Ошибка: нужно ввести вещественное число.") + + +def run_method(name: str, method_func, p: int, marker: str, f, y_true, x0, xn, y0, h_initial, eps) -> tuple[list[float], list[float], str, float]: + print(f"\n=== {name} ===") + h = h_initial + min_pts = 4 + + if p is None: + needed = (xn - x0) / h + 1 + if needed < min_pts: + print("Слишком большой шаг для метода Милна!") + print(f"Нужно не менее {min_pts} точек: (xn − x0)/h +1 ≥ {min_pts}") + h = (xn - x0) / (min_pts - 1) + print("Автоматически назначен шаг h =", h) + + while True: + xs_h, ys_h = method_func(f, x0, xn, y0, h) + + if p is not None: + xs_h2, ys_h2 = method_func(f, x0, xn, y0, h / 2) + y_h = ys_h[-1] + y_h2 = ys_h2[-1] + inaccuracy = abs(y_h - y_h2) / (2 ** p - 1) + + if inaccuracy < eps: + print(f"Достигнута точность ε = {eps:.2e} при эффективном шаге h = {h/2:g}") + print("Погрешность:", f"{inaccuracy:.6g}") + + xs_tab = xs_h2 + ys_tab = ys_h2 + out_x = [] + out_y = [] + out_true = [] + out_err = [] + for xi, yi in zip(xs_tab, ys_tab): + yt = y_true(xi, x0, y0) + out_x.append(xi) + out_y.append(yi) + out_true.append(yt) + out_err.append(abs(yt - yi)) + print(tabulate( + list(zip(out_x, out_y, out_true, out_err)), + headers=["x", "y_num", "y_true", "погрешность"], + floatfmt=(".6g", ".6g", ".6g", ".6g") + )) + return xs_h2, ys_h2, name, inaccuracy + else: + h /= 2 + if h < 1e-6: + print("Шаг слишком мал, останавливаю подбор.") + return xs_h, ys_h, name, inaccuracy + + else: + # оценка точности Милна + errors = [abs(y_true(xi, x0, y0) - yi) for xi, yi in zip(xs_h, ys_h)] + inaccuracy = max(errors) + if inaccuracy <= eps: + print(f"Достигнута точность ε = {eps:.2e} при эффективном шаге h = {h:g}") + print("Погрешность:", f"{inaccuracy:.6g}") + + xs_tab = xs_h + ys_tab = ys_h + out_x = [] + out_y = [] + out_true = [] + out_err = [] + for xi, yi in zip(xs_tab, ys_tab): + yt = y_true(xi, x0, y0) + out_x.append(xi) + out_y.append(yi) + out_true.append(yt) + out_err.append(abs(yt - yi)) + print(tabulate( + list(zip(out_x, out_y, out_true, out_err)), + headers=["x", "y_num", "y_true", "погрешность"], + floatfmt=(".6g", ".6g", ".6g", ".6g") + )) + return xs_h, ys_h, name, inaccuracy + else: + h /= 2 + if h < 1e-6: + print("Шаг слишком мал, останавливаю подбор.") + return xs_h, ys_h, name, inaccuracy + + +def draw_combined(xs_all: list[list[float]], + ys_all: list[list[float]], + y_true_func, + x0: float, + y0: float, + names: list[str], + markers: list[str]): + + x_min = x0 + x_max = max(xs[-1] for xs in xs_all) + x_plot = np.linspace(x_min, x_max, 400) + y_plot = [y_true_func(x, x0, y0) for x in x_plot] + + plt.figure(figsize=(8, 6)) + plt.plot(x_plot, y_plot, "r-", label="Точное решение") + + colors = ["b", "g", "m"] + for i in range(len(xs_all)): + xs = xs_all[i] + ys = ys_all[i] + plt.plot(xs, ys, color=colors[i], linestyle="-", marker=markers[i], markersize=6, label=names[i]) + + plt.title("Сравнение численных методов") + plt.xlabel("x") + plt.ylabel("y") + plt.grid(True) + plt.legend() + plt.show() + + +def main(): + print("=== Лабораторная №6: Численное решение ОДУ ===\n") + for idx, entry in enumerate(funcs, start=1): + print(f"{idx}) {entry[0]}") + while True: + try: + choice = int(input("Ваш выбор (1–4): ").strip()) + if 1 <= choice <= len(funcs): + break + else: + print("Ошибка: введите число от 1 до 4.") + except: + print("Ошибка: введите целое число.") + desc, f, y_true = funcs[choice - 1] + + x0 = read_float("Введите x0 (начало): ") + xn = read_float("Введите xn (конец, > x0): ") + if xn <= x0: + print("Ошибка: xn должен быть больше x0.") + return + y0 = read_float("Введите y(x0) = y0: ") + h_initial = read_float("Введите начальный шаг h: ", positive=True) + eps = read_float("Введите точность ε: ", positive=True) + + xs_all = [] + ys_all = [] + names = [] + markers = [] + + for (name, method_func, p, marker) in methods: + xs_h, ys_h, mname, inacc = run_method( + name, method_func, p, marker, + f, y_true, x0, xn, y0, h_initial, eps + ) + xs_all.append(xs_h) + ys_all.append(ys_h) + names.append(mname) + markers.append(marker) + print("\n" + "-" * 60) + + draw_combined(xs_all, ys_all, y_true, x0, y0, names, markers) + + print("\n=== Работа завершена ===") + + +if __name__ == "__main__": + main() diff --git "a/\320\2403212/vildanov_408379/lab6/src/methods/euler.py" "b/\320\2403212/vildanov_408379/lab6/src/methods/euler.py" new file mode 100644 index 0000000..4e6864c --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab6/src/methods/euler.py" @@ -0,0 +1,13 @@ +import math + +def euler_method(f, x0: float, xn: float, y0: float, h: float) -> tuple[list[float], list[float]]: + xs = [x0] + ys = [y0] + x = x0 + while x < xn and not math.isclose(x, xn): + y_prev = ys[-1] + y_next = y_prev + h * f(x, y_prev) + x = round(x + h, 12) + xs.append(x) + ys.append(y_next) + return xs, ys diff --git "a/\320\2403212/vildanov_408379/lab6/src/methods/milne.py" "b/\320\2403212/vildanov_408379/lab6/src/methods/milne.py" new file mode 100644 index 0000000..5c80eed --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab6/src/methods/milne.py" @@ -0,0 +1,35 @@ +import math +from methods.rk4 import rk4_method + + +def milne_method(f, x0: float, xn: float, y0: float, h: float) -> tuple[list[float], list[float]]: + xs_rk, ys_rk = rk4_method(f, x0, x0 + 3*h, y0, h) + xs = xs_rk.copy() + ys = ys_rk.copy() + + while xs[-1] < xn and not math.isclose(xs[-1], xn): + i = len(xs) - 1 # текущий индекс + x_i = xs[i]; y_i = ys[i] + x_im1, y_im1 = xs[i-1], ys[i-1] + x_im2, y_im2 = xs[i-2], ys[i-2] + x_im3, y_im3 = xs[i-3], ys[i-3] + + # предиктор + y_pred = y_im3 + (4*h/3) * ( + 2*f(x_im2, y_im2) + - f(x_im1, y_im1) + + 2*f(x_i, y_i) + ) + x_next = round(x_i + h, 12) + + # корректор + y_corr = y_im1 + (h/3) * ( + f(x_im1, y_im1) + + 4 * f(x_i, y_i) + + f(x_next, y_pred) + ) + + xs.append(x_next) + ys.append(y_corr) + + return xs, ys diff --git "a/\320\2403212/vildanov_408379/lab6/src/methods/rk4.py" "b/\320\2403212/vildanov_408379/lab6/src/methods/rk4.py" new file mode 100644 index 0000000..6c73ca3 --- /dev/null +++ "b/\320\2403212/vildanov_408379/lab6/src/methods/rk4.py" @@ -0,0 +1,20 @@ +import math + + +def rk4_method(f, x0: float, xn: float, y0: float, h: float) -> tuple[list[float], list[float]]: + xs = [x0] + ys = [y0] + x = x0 + while x < xn and not math.isclose(x, xn): + y = ys[-1] + + k1 = h * f(x, y) + k2 = h * f(x + h / 2, y + k1 / 2) + k3 = h * f(x + h / 2, y + k2 / 2) + k4 = h * f(x + h, y + k3) + + y_next = y + (k1 + 2 * k2 + 2 * k3 + k4) / 6 + x = round(x + h, 12) + xs.append(x) + ys.append(y_next) + return xs, ys