diff --git "a/\320\2403213/molodichenko_409163/lab1/main1.py" "b/\320\2403213/molodichenko_409163/lab1/main1.py" new file mode 100644 index 0000000..55f9561 --- /dev/null +++ "b/\320\2403213/molodichenko_409163/lab1/main1.py" @@ -0,0 +1,144 @@ +import numpy as np + + + + + +def read_matrix_from_file(filename): + """Считывает матрицу A и вектор b из файла.""" + with open(filename, 'r') as file: + while True: + try: + n = int(file.readline()) + if n > 20: + print("ValueError: Размерность матрицы должна быть не более 20.") + continue + break + except ValueError: + print("ValueError: Размерность матрицы должна быть не более 20.") + A = [list(map(float, file.readline().split())) for _ in range(n)] + b = list(map(float, file.readline().split())) + return np.array(A), np.array(b) + + + + +def read_matrix_from_input(): + """Считывает матрицу A и вектор b с клавиатуры.""" + while True: + try: + n = int(input("Введите размерность матрицы (не более 20): ")) + if n > 20: + print("ValueError: Размерность матрицы должна быть не более 20.") + continue + break + except ValueError: + print("ValueError: Размерность матрицы должна быть не более 20.") + A = [] + print("Введите коэффициенты матрицы A (по строкам, через пробел):") + for _ in range(n): + while True: + try: + row = list(map(float, input().split())) + if len(row) != n: + raise ValueError(f"Ожидалось {n} чисел, введено {len(row)}.") + A.append(row) + break + except ValueError as e: + print("Ошибка ввода! Повторите ввод строки:", e) + print("Введите коэффициенты вектора b (через пробел):") + while True: + try: + b = list(map(float, input().split())) + if len(b) != n: + raise ValueError(f"Ожидалось {n} чисел, введено {len(b)}.") + break + except ValueError as e: + print("Ошибка ввода! Повторите ввод:", e) + return np.array(A), np.array(b) + + +def check_diagonal_dominance(A): + """Проверяет, обладает ли матрица диагональным преобладанием.""" + n = A.shape[0] + for i in range(n): + sum_row = sum(abs(A[i, j]) for j in range(n) if i != j) + if abs(A[i, i]) < sum_row: + return False + return True + + + + +def enforce_diagonal_dominance(A, b): + """Пытается добиться диагонального преобладания путем перестановки строк.""" + n = A.shape[0] + indices = np.argsort(-np.abs(A.diagonal())) + A, b = A[indices], b[indices] + if not check_diagonal_dominance(A): + print("Невозможно достичь диагонального преобладания.") + return None, None + return A, b + + + + +def compute_determinant(A): + """Вычисляет определитель матрицы A.""" + return np.linalg.det(A) + + +def gauss_seidel(A, b, tol=1e-6, max_iterations=1000): + """Решает систему методом Гаусса-Зейделя.""" + n = len(A) + x = np.zeros(n) + for iteration in range(max_iterations): + x_new = np.copy(x) + for i in range(n): + sum1 = sum(A[i][j] * x_new[j] for j in range(i)) + sum2 = sum(A[i][j] * x[j] for j in range(i + 1, n)) + x_new[i] = (b[i] - sum1 - sum2) / A[i][i] + error = np.linalg.norm(x_new - x, ord=np.inf) + if error < tol: + return x_new, iteration + 1 + x = x_new + print("Метод не сошелся за", max_iterations, "итераций.") + return x, max_iterations + + +def main(): + choice = input("Вы хотите ввести данные с клавиатуры (k) или из файла (f)? ") + if choice.lower() == 'f': + filename = input("Введите имя файла: ") + A, b = read_matrix_from_file(filename) + else: + A, b = read_matrix_from_input() + + print("Определитель матрицы:", compute_determinant(A)) + + if not check_diagonal_dominance(A): + print("Матрица не обладает диагональным преобладанием. Пытаемся переставить строки...") + A, b = enforce_diagonal_dominance(A, b) + if A is None: + return + + print("Решаем методом Гаусса-Зейделя...") + solution, iterations = gauss_seidel(A, b) + print("Вектор неизвестных:", solution) + print("Количество итераций:", iterations) + + # Вычисление невязки + residual = b - np.dot(A, solution) + print("Вектор невязок:", residual) + + # Вычисление нормы погрешности + print("Норма погрешности:", np.linalg.norm(residual)) + + # Проверка с решением с помощью numpy.linalg.solve + lib_solution = np.linalg.solve(A, b) + print("Решение с использованием библиотеки:", lib_solution) + print("Разница между решениями:", np.linalg.norm(solution - lib_solution)) + + +if __name__ == "__main__": + main() diff --git "a/\320\2403213/molodichenko_409163/lab1/\320\262\321\213\321\207\320\274\320\260\321\202, \320\273\320\260\320\261 1.pdf" "b/\320\2403213/molodichenko_409163/lab1/\320\262\321\213\321\207\320\274\320\260\321\202, \320\273\320\260\320\261 1.pdf" new file mode 100644 index 0000000..1c29e66 Binary files /dev/null and "b/\320\2403213/molodichenko_409163/lab1/\320\262\321\213\321\207\320\274\320\260\321\202, \320\273\320\260\320\261 1.pdf" differ diff --git "a/\320\2403213/molodichenko_409163/lab2/lab2.py" "b/\320\2403213/molodichenko_409163/lab2/lab2.py" new file mode 100644 index 0000000..c077da6 --- /dev/null +++ "b/\320\2403213/molodichenko_409163/lab2/lab2.py" @@ -0,0 +1,173 @@ +import numpy as np +import matplotlib.pyplot as plt +from sympy import symbols, diff, sin, cos, lambdify + + +def get_input(prompt, type_func=float, from_file=None): + if from_file: + value = from_file.readline().strip() + print(f"{prompt} {value}") + return type_func(value) + while True: + try: + return type_func(input(prompt)) + except ValueError: + print("Некорректный ввод. Попробуйте снова.") + + +def plot_function(f, a, b, root): + x_vals = np.linspace(a, b, 400) + y_vals = [f(x) for x in x_vals] + + plt.figure(figsize=(8, 5)) + plt.plot(x_vals, y_vals, label="f(x)", color="blue") + plt.axhline(0, color="black", linewidth=1) + plt.axvline(root, color="red", linestyle="--", label="Найденный корень") + plt.grid() + plt.legend() + plt.title("График функции") + plt.xlabel("x") + plt.ylabel("f(x)") + plt.show() + + +def bisection_method(f, a, b, tol): + if f(a) * f(b) >= 0: + print("Некорректный интервал: f(a) и f(b) должны иметь разные знаки.") + return None, [] + + iterations = [] + while abs(b - a) > tol: + c = (a + b) / 2 + iterations.append([a, b, c, f(a), f(b), f(c), abs(b - a)]) + + if f(c) == 0: + break + elif f(a) * f(c) < 0: + b = c + else: + a = c + + return c, iterations + + +def secant_method(f, x0, x1, tol): + iterations = [] + while abs(x1 - x0) > tol: + if f(x1) - f(x0) == 0: + print("Ошибка: Деление на ноль в методе секущих.") + return None, [] + x2 = x1 - f(x1) * (x1 - x0) / (f(x1) - f(x0)) + iterations.append([x0, x1, f(x0), f(x1), abs(x1 - x0)]) + x0, x1 = x1, x2 + return x1, iterations + + +def newton_method(f, df, x0, tol): + iterations = [] + while True: + if df(x0) == 0: + print("Ошибка: Производная равна нулю, метод Ньютона не применим.") + return None, [] + x1 = x0 - f(x0) / df(x0) + iterations.append([x0, f(x0), df(x0), x1, abs(x1 - x0)]) + if abs(x1 - x0) < tol: + break + x0 = x1 + return x1, iterations + + +def simple_iteration_method(g, x0, tol): + iterations = [] + while True: + x1 = g(x0) + iterations.append([x0, x1, abs(x1 - x0)]) + if abs(x1 - x0) < tol: + break + x0 = x1 + return x1, iterations + + +def solve_nonlinear_equation(): + x = symbols('x') + functions = { + 1: sin(x) - x / 2, + 2: x ** 3 - 4 * x + 1, + 3: x ** 2 - 2, + } + + from_file = None + if input("Ввести данные из файла? (y/n): ").strip().lower() == 'y': + filename = input("Введите имя файла: ").strip() + from_file = open(filename, "r") + + print("Выберите уравнение:") + for k, v in functions.items(): + print(f"{k}: {v}") + choice = get_input("Введите номер уравнения: ", int, from_file) + if choice not in functions: + print("Некорректный выбор уравнения.") + return + + f_sym = functions[choice] + f = lambdify(x, f_sym, 'numpy') + df = lambdify(x, diff(f_sym, x), 'numpy') + + method = input("Выберите метод (bisection, secant, newton, iteration): ").strip().lower() + if method not in ["bisection", "secant", "newton", "iteration"]: + print("Некорректный метод.") + return + + tol = get_input("Введите точность: ", float, from_file) + + if method == "bisection": + a = get_input("Введите левую границу: ", float, from_file) + b = get_input("Введите правую границу: ", float, from_file) + root, iterations = bisection_method(f, a, b, tol) + else: + x0 = get_input("Введите начальное приближение: ", float, from_file) + if method == "secant": + x1 = get_input("Введите x1: ", float, from_file) + root, iterations = secant_method(f, x0, x1, tol) + elif method == "newton": + root, iterations = newton_method(f, df, x0, tol) + elif method == "iteration": + g = lambdify(x, x - f_sym, 'numpy') + root, iterations = simple_iteration_method(g, x0, tol) + a, b = root - 2, root + 2 + + if from_file: + from_file.close() + + if root is None: + print("Ошибка вычислений. Попробуйте снова с другим интервалом или методом.") + return + + function_value = f(root) + result = f"Найденный корень: {root}\nЗначение функции в корне: {function_value}\nЧисло итераций: {len(iterations)}\n" + print(result) + + save_to_file = input("Сохранить результат в файл? (y/n): ").strip().lower() + if save_to_file == 'y': + with open("result.txt", "w") as file: + file.write(result) + print("Результат сохранен в result.txt") + + plot_function(f, a, b, root) + + +def main(): + while True: + mode = input("Выберите режим (equation/system) или 'exit' для выхода: ").strip().lower() + if mode == "equation": + solve_nonlinear_equation() + elif mode == "system": + print("Функционал для систем еще не реализован.") + elif mode == "exit": + break + else: + print("Неверный выбор. Попробуйте снова.") + + +if __name__ == "__main__": + main() diff --git "a/\320\2403213/molodichenko_409163/lab2/\320\262\321\213\321\207\320\274\320\260\321\202 2.pdf" "b/\320\2403213/molodichenko_409163/lab2/\320\262\321\213\321\207\320\274\320\260\321\202 2.pdf" new file mode 100644 index 0000000..d9c0606 Binary files /dev/null and "b/\320\2403213/molodichenko_409163/lab2/\320\262\321\213\321\207\320\274\320\260\321\202 2.pdf" differ diff --git "a/\320\2403213/molodichenko_409163/lab3/lab3-2.py" "b/\320\2403213/molodichenko_409163/lab3/lab3-2.py" new file mode 100644 index 0000000..e1b8d99 --- /dev/null +++ "b/\320\2403213/molodichenko_409163/lab3/lab3-2.py" @@ -0,0 +1,250 @@ +import math + + +MAX_BREAKPOINTS = 10_000 + +def f1(x): + return x**2 + +def f2(x): + return math.sin(x) + +def f3(x): + return math.exp(x) + +def f4(x): + return 1 / x**2 + +def f5(x): + return 1 / x + +def f6(x): + return 1 / math.sqrt(x) + +def f7(x): + return -3*x**3 - 5*x**2 + 4*x - 2 + +def f8(x): + return 10 + +def f9(x): + return 1 / math.sqrt(2*x - x**2) + +functions = [f1, f2, f3, f4, f5, f6, f7, f8, f9] + +def rectangle_rule(func, a, b, n, mode="middle"): + h = (b - a) / n + result = 0 + + if mode == "left": + for i in range(n): + result += func(a + i * h) + + elif mode == "right": + for i in range(1, n + 1): + result += func(a + i * h) + + else: + for i in range(n): + result += func(a + (i + 0.5) * h) + + result *= h + return result + + +def trapezoid_rule(func, a, b, n): + h = (b - a) / n + result = (func(a) + func(b)) / 2 + + for i in range(1, n): + result += func(a + i * h) + + result *= h + return result + + +def simpson_rule(func, a, b, n): + h = (b - a) / n + result = func(a) + func(b) + + for i in range(1, n): + coef = 3 + (-1)**(i + 1) + result += coef * func(a + i * h) + + result *= h / 3 + return result + + +methods = { + "rectangle_left": lambda func, a, b, n: rectangle_rule(func, a, b, n, mode="left"), + "rectangle_right": lambda func, a, b, n: rectangle_rule(func, a, b, n, mode="right"), + "rectangle_middle": rectangle_rule, + "trapezoid": trapezoid_rule, + "simpson": simpson_rule +} + +def compute_integral(func, a, b, epsilon, method): + n = 4 + runge_coef = {"rectangle_left": 1, "rectangle_right": 1, "rectangle_middle": 3, "trapezoid": 3, "simpson": 15} + coef = runge_coef[method] + + result = methods[method](func, a, b, n) + error = math.inf + + while error > epsilon: + n *= 2 + new_result = methods[method](func, a, b, n) + error = abs(new_result - result) / coef + + result = new_result + + return result, n + + +def get_discontinuity_points(func, a, b, n): + breakpoints = [] + + try: + func(a) + except (ZeroDivisionError, OverflowError, ValueError): + breakpoints.append(a) + + try: + func(b) + except (ZeroDivisionError, OverflowError, ValueError): + breakpoints.append(b) + + try: + func((a + b) / 2) + except (ZeroDivisionError, OverflowError, ValueError): + breakpoints.append((a + b) / 2) + + h = (b - a) / n + for i in range(n): + point = a + i * h + try: + func(a + i * h) + except (ZeroDivisionError, OverflowError, ValueError): + breakpoints.append(point) + + if len(breakpoints) >= MAX_BREAKPOINTS: + return get_discontinuity_points(func, a, b, n // 10) + + return list(set(breakpoints)) + + +def try_to_compute(func, x): + try: + return func(x) + except Exception: + return None + + +if __name__ == "__main__": + while (True): + print("Выберите функцию:") + print("1. x^2") + print("2. sin(x)") + print("3. e^x") + print("4. 1/x^2") + print("5. 1/x") + print("6. 1/sqrt(x)") + print("7. -3x^3 - 5x^2 + 4x - 2") + print("8. 10") + print("9. 1 / sqrt(2x - x^2)") + + choosen_f = int(input("Ваш выбор: ")) - 1 + func = functions[choosen_f] + + if (choosen_f not in [0, 2, 3, 4, 5, 6, 7, 8]): + print("Пожалуйста, выберите корректный номер функции!\n") + continue + + while (True): + try: + a = float(input("Введите начальный предел интегрирования: ")) + b = float(input("Введите конечный предел интегрирования: ")) + + if (a >= b): + print(f'{a} >= {b}. Пожалуйста, введите a < b') + else: + break + except: + print("! Ошибка ввода: введите пределы интегрирования еще раз!\n") + + breakpoints = get_discontinuity_points(func, a, b, math.ceil(b - a) * 1_000) + + # Если разрыв: установить сходимость + if len(breakpoints) != 0: + print(f"! Обнаружен точка разрыва: функция имеет разрыв или не существует в точках {breakpoints}.") + + eps = 0.00001 + converges = True + for bp in breakpoints: + y1 = try_to_compute(func, bp - eps) + y2 = try_to_compute(func, bp + eps) + if y1 is not None and y2 is not None and abs(y1 - y2) > eps or (y1 == y2 and y1 is not None): + converges = False + break + + if not converges: + # расходящийся => выводить сообщение: «Интеграл не существует» + print('- Интеграл не существует: интеграл не сходится.') + else: + # сходящийся => реализовать в программе вычисление несобственных интегралов 2 рода + print('+ Интеграл сходится.') + epsilon = float(input("Введите требуемую точность вычислений: ")) + + for method in methods: + print(f"\n* Метод: {method}") + + if len(breakpoints) == 1: + if a in breakpoints: + a += eps + elif b in breakpoints: + b -= eps + else: + res = 0 + n = 0 + if not (try_to_compute(func, a) is None or try_to_compute(func, breakpoints[0] - eps) is None): + results = compute_integral(func, a, breakpoints[0] - eps, epsilon, method) + res += results[0] + n += results[1] + + if not (try_to_compute(func, b) is None or try_to_compute(func, breakpoints[0] + eps) is None): + results = compute_integral(func, breakpoints[0] + eps, b, epsilon, method) + res += results[0] + n += results[1] + + for bi in range(len(breakpoints) - 1): + b_cur = breakpoints[bi] + b_next = breakpoints[bi + 1] + + if not (try_to_compute(func, b_cur + eps) is None or try_to_compute(func, b_next - eps) is None): + results = compute_integral(func, b_cur + eps, b_next - eps, epsilon, method) + res += results[0] + n += results[1] + + print(f"Значение интеграла: {res}") + print(f"Число разбиений интервала интегрирования для достижения требуемой точности: n = {n}") + + if not breakpoints or a - eps in breakpoints or b + eps in breakpoints: + result, n = compute_integral(func, a, b, epsilon, method) + if result is not None and n is not None: + print(f"Значение интеграла: {result}") + print(f"Число разбиений интервала интегрирования для достижения требуемой точности: n = {n}") + else: + # Если нет разрыва: просто вычисляем + epsilon = float(input("Введите требуемую точность вычислений: ")) + + for method in methods: + print(f"\n* Метод: {method}") + result, n = compute_integral(func, a, b, epsilon, method) + + if result is not None and n is not None: + print(f"Значение интеграла: {result}") + print(f"Число разбиений интервала интегрирования для достижения требуемой точности: n = {n}") + + if (input('\nЕще раз? [y/n]: ') == 'n'): + print("Спасибо за использование программы!") + break \ No newline at end of file diff --git "a/\320\2403213/molodichenko_409163/lab3/lab3.1.py" "b/\320\2403213/molodichenko_409163/lab3/lab3.1.py" new file mode 100644 index 0000000..403108b --- /dev/null +++ "b/\320\2403213/molodichenko_409163/lab3/lab3.1.py" @@ -0,0 +1,39 @@ +from sympy import * + +x = symbols('x') + +f = -3*x**3 - 5*x**2 + 4*x - 2 + +a, b = -3, -1 +n = 10 +h = (b-a) / n + + +sum_midpoint = 0 +for i in range(n): + x_i = a + (i + 0.5) * h + sum_midpoint += f.subs(x, x_i) + +integral_midpoint = h * sum_midpoint + + +sum_trapezoid = 0 +for i in range(1, n): + x_i = a + i * h + sum_trapezoid += f.subs(x, x_i) + +integral_trapezoid = h / 2 * (f.subs(x, a) + 2*sum_trapezoid + f.subs(x, b)) + + +sum_simpson = f.subs(x, a) + f.subs(x, b) + +for i in range(1, n): + coef = 3 + (-1)**(i + 1) + sum_simpson += coef * f.subs(x, a + i * h) + +integral_simpson = h / 3 * sum_simpson + + +print(integral_midpoint) +print(integral_trapezoid) +print(integral_simpson) \ No newline at end of file diff --git "a/\320\2403213/molodichenko_409163/lab3/\320\273\320\260\320\2613.pdf" "b/\320\2403213/molodichenko_409163/lab3/\320\273\320\260\320\2613.pdf" new file mode 100644 index 0000000..06a31cb Binary files /dev/null and "b/\320\2403213/molodichenko_409163/lab3/\320\273\320\260\320\2613.pdf" differ diff --git "a/\320\2403213/molodichenko_409163/lab4/lab4.py" "b/\320\2403213/molodichenko_409163/lab4/lab4.py" new file mode 100644 index 0000000..8cc375d --- /dev/null +++ "b/\320\2403213/molodichenko_409163/lab4/lab4.py" @@ -0,0 +1,376 @@ +import numpy as np +import math +import matplotlib.pyplot as plt + + +# --------------------------------------------------------- +# Функции для чтения данных +# --------------------------------------------------------- + +def read_data_console(): + """ + Считывание данных из консоли. + Пользователь вводит количество точек n (8..12), + затем n пар (x_i, y_i). + """ + print("Чтение данных ИЗ КОНСОЛИ.") + print("Введите количество точек (8..12):") + n = int(input().strip()) + if not (8 <= n <= 12): + raise ValueError("Число точек должно быть в диапазоне [8..12].") + + x_vals = [] + y_vals = [] + print(f"Введите {n} пар (x_i, y_i), каждая в новой строке:") + for _ in range(n): + line = input().strip().split() + if len(line) < 2: + raise ValueError("Недостаточно значений в строке.") + x, y = float(line[0]), float(line[1]) + x_vals.append(x) + y_vals.append(y) + + return np.array(x_vals), np.array(y_vals) + + +def read_data_file(): + """ + Считывание данных из файла. + Формат файла (пример): + Первая строка: n (число точек) + Далее n строк, в каждой по два числа: x_i, y_i + """ + print("Чтение данных ИЗ ФАЙЛА.") + print("Введите путь к файлу (например, data.txt):") + filename = input().strip() + + with open(filename, 'r', encoding='utf-8') as f: + lines = f.read().strip().splitlines() + + if not lines: + raise ValueError("Пустой файл.") + + n = int(lines[0].strip()) + if not (8 <= n <= 12): + raise ValueError("Число точек должно быть в диапазоне [8..12].") + + if len(lines) < n + 1: + raise ValueError(f"В файле недостаточно строк. Ожидалось {n} пар данных.") + + x_vals, y_vals = [], [] + for i in range(n): + parts = lines[i + 1].split() + if len(parts) < 2: + raise ValueError(f"Недостаточно значений в строке {i + 2} файла.") + x, y = float(parts[0]), float(parts[1]) + x_vals.append(x) + y_vals.append(y) + + return np.array(x_vals), np.array(y_vals) + + +def choose_data_input(): + """ + Предлагает пользователю выбрать способ ввода данных: + 1) из консоли, + 2) из файла. + Возвращает (x_data, y_data). + """ + print("Выберите способ ввода данных:") + print(" [1] Консоль") + print(" [2] Файл") + choice = input("Ваш выбор: ").strip() + + if choice == '1': + return read_data_console() + elif choice == '2': + return read_data_file() + else: + raise ValueError("Некорректный выбор способа ввода данных.") + + +# --------------------------------------------------------- +# Модели аппроксимации (МНК). +# --------------------------------------------------------- +def fit_linear(x, y): + """ Линейная: f(x) = a + b*x """ + # polyfit вернет [b, a] + b, a = np.polyfit(x, y, deg=1) + return (a, b) + + +def linear_func(x, coeffs): + a, b = coeffs + return a + b * x + + +def fit_poly2(x, y): + """ Полином 2-й степени: f(x)= a + b*x + c*x^2 """ + c, b, a = np.polyfit(x, y, deg=2) + return (a, b, c) + + +def poly2_func(x, coeffs): + a, b, c = coeffs + return a + b * x + c * (x ** 2) + + +def fit_poly3(x, y): + """ Полином 3-й степени: f(x)= a + b*x + c*x^2 + d*x^3 """ + d, c, b, a = np.polyfit(x, y, deg=3) + return (a, b, c, d) + + +def poly3_func(x, coeffs): + a, b, c, d = coeffs + return a + b * x + c * (x ** 2) + d * (x ** 3) + + +def fit_exponential(x, y): + """ + Экспоненциальная: f(x) = A*exp(B*x) + Нужно y>0. + """ + if any(val <= 0 for val in y): + raise ValueError("Невозможно экспоненциальное приближение: y <= 0.") + ln_y = np.log(y) + B, lnA = np.polyfit(x, ln_y, deg=1) + A = math.exp(lnA) + return (A, B) + + +def exponential_func(x, coeffs): + A, B = coeffs + return A * np.exp(B * x) + + +def fit_logarithmic(x, y): + """ + Логарифмическая: f(x)= a + b*ln(x). + Нужно x>0. + """ + if any(val <= 0 for val in x): + raise ValueError("Невозможно логарифмическое приближение: x <= 0.") + ln_x = np.log(x) + b, a = np.polyfit(ln_x, y, deg=1) + return (a, b) + + +def logarithmic_func(x, coeffs): + a, b = coeffs + return a + b * np.log(x) + + +def fit_power(x, y): + """ + Степенная: f(x)= A*x^B. + Нужно x>0, y>0. + """ + if any(val <= 0 for val in x): + raise ValueError("Невозможно степенное приближение: x <= 0.") + if any(val <= 0 for val in y): + raise ValueError("Невозможно степенное приближение: y <= 0.") + ln_x = np.log(x) + ln_y = np.log(y) + B, lnA = np.polyfit(ln_x, ln_y, deg=1) + A = math.exp(lnA) + return (A, B) + + +def power_func(x, coeffs): + A, B = coeffs + return A * (x ** B) + + +# --------------------------------------------------------- +# Оценки (СКО, R^2, Пирсон). +# --------------------------------------------------------- +def sse(x, y, func, coeffs): + return np.sum((func(x, coeffs) - y) ** 2) + + +def rmse(x, y, func, coeffs): + n = len(x) + return math.sqrt(sse(x, y, func, coeffs) / n) + + +def determination_coefficient(x, y, func, coeffs): + ss_res = sse(x, y, func, coeffs) + y_mean = np.mean(y) + ss_tot = np.sum((y - y_mean) ** 2) + if ss_tot == 0: + return 0 + return 1 - (ss_res / ss_tot) + + +def pearson_correlation(x, y): + x_mean, y_mean = np.mean(x), np.mean(y) + num = np.sum((x - x_mean) * (y - y_mean)) + den = math.sqrt(np.sum((x - x_mean) ** 2) * np.sum((y - y_mean) ** 2)) + return num / den if den != 0 else 0 + + +def interpret_r2(r2): + if r2 < 0.3: + return "Очень слабая зависимость (R^2 < 0.3)." + elif r2 < 0.5: + return "Слабая зависимость (0.3 <= R^2 < 0.5)." + elif r2 < 0.7: + return "Зависимость средней силы (0.5 <= R^2 < 0.7)." + elif r2 < 0.9: + return "Достаточно сильная зависимость (0.7 <= R^2 < 0.9)." + else: + return "Очень сильная зависимость (R^2 >= 0.9)." + + +# --------------------------------------------------------- +# Набор рассматриваемых моделей +# --------------------------------------------------------- +MODELS = [ + ("Линейная", fit_linear, linear_func), + ("Полиномиальная 2", fit_poly2, poly2_func), + ("Полиномиальная 3", fit_poly3, poly3_func), + ("Экспоненциальная", fit_exponential, exponential_func), + ("Логарифмическая", fit_logarithmic, logarithmic_func), + ("Степенная", fit_power, power_func), +] + + +# --------------------------------------------------------- +# Рисование итогового графика +# --------------------------------------------------------- +def plot_results(x, y, results): + plt.figure(figsize=(8, 6)) + plt.scatter(x, y, c='black', label='Исходные точки') + + x_min, x_max = min(x), max(x) + dx = 0.05 * (x_max - x_min) if x_max > x_min else 1.0 + x_plot = np.linspace(x_min - dx, x_max + dx, 300) + + for (name, coeffs, func_obj, this_rmse, this_r2) in results: + # Лог/степень -> x>0 + if "Логарифмическая" in name or "Степенная" in name: + x_pos = x_plot[x_plot > 0] + if len(x_pos) == 0: + continue + y_plot = func_obj(x_pos, coeffs) + plt.plot(x_pos, y_plot, label=name) + else: + y_plot = func_obj(x_plot, coeffs) + plt.plot(x_plot, y_plot, label=name) + + plt.title("Сравнение аппроксимаций") + plt.xlabel("x") + plt.ylabel("y") + plt.grid(True) + plt.legend() + plt.show() + + +# --------------------------------------------------------- +# Вспомогательная функция для вывода текста и (опционально) записи в файл +# --------------------------------------------------------- +def print_to_console_and_file(text, file_obj=None, end="\n"): + """ + Выводит строку text в консоль (print) и дублирует её в файл file_obj, + если file_obj не None. + """ + print(text, end=end) + if file_obj is not None: + file_obj.write(text + end) + + +# --------------------------------------------------------- +# Основная программа +# --------------------------------------------------------- +def main(): + # 1) Читаем данные + try: + x_data, y_data = choose_data_input() + except Exception as e: + print(f"Ошибка при вводе данных: {e}") + return + + # 2) Обрабатываем все модели + results = [] # (model_name, coeffs, func, rmse_val, r2_val) + + for model_name, fit_f, func_f in MODELS: + try: + coeffs = fit_f(x_data, y_data) + curr_rmse = rmse(x_data, y_data, func_f, coeffs) + curr_r2 = determination_coefficient(x_data, y_data, func_f, coeffs) + results.append((model_name, coeffs, func_f, curr_rmse, curr_r2)) + except Exception as exc: + # Не удалось применить модель (напр., логарифм при x<=0) + print(f"[Предупреждение] Модель «{model_name}» не подходит: {exc}") + + if not results: + print("Не удалось построить ни одной аппроксимации.") + return + + # 2б) Спросим у пользователя, хочет ли он сохранить результаты в файл. + save_to_file = False + outfile = None + print("Хотите ли сохранить результаты в файл? (y/n)") + ans = input().strip().lower() + if ans == 'y': + print("Введите имя файла для сохранения (например, output.txt):") + out_filename = input().strip() + try: + outfile = open(out_filename, 'w', encoding='utf-8') + save_to_file = True + except Exception as e: + print(f"Не удалось открыть файл на запись: {e}") + + # 3) Вывод результатов в консоль (и файл, если нужно) + best_model, best_rmse, best_coeffs, best_func = None, float('inf'), None, None + + print_to_console_and_file("\nРезультаты аппроксимации:", outfile) + + for (model_name, coeffs, func_f, curr_rmse, curr_r2) in results: + print_to_console_and_file("", outfile) # пустая строка + print_to_console_and_file(f"Модель: {model_name}", outfile) + print_to_console_and_file(f" Коэффициенты: {coeffs}", outfile) + print_to_console_and_file(f" RMSE (СКО): {curr_rmse:.6f}", outfile) + print_to_console_and_file(f" R^2 : {curr_r2:.6f}", outfile) + print_to_console_and_file(f" -> {interpret_r2(curr_r2)}", outfile) + + # Линейная — Пирсон + if model_name == "Линейная": + r_xy = pearson_correlation(x_data, y_data) + print_to_console_and_file(f" Коэффициент корреляции Пирсона: r_xy = {r_xy:.6f}", outfile) + + # Минимальный RMSE -> лучшая модель + if curr_rmse < best_rmse: + best_rmse = curr_rmse + best_model = model_name + best_coeffs = coeffs + best_func = func_f + + print_to_console_and_file("", outfile) + print_to_console_and_file(f"Лучшая модель по критерию минимума RMSE: {best_model}", outfile) + + # 4) Остатки + print_to_console_and_file("", outfile) + print_to_console_and_file(f"Остатки eps_i = f(x_i) - y_i для лучшей модели:", outfile) + fvals = best_func(x_data, best_coeffs) + for i, (xx, yy, fv) in enumerate(zip(x_data, y_data, fvals), start=1): + eps = fv - yy + line = (f" Точка {i}: x={xx}, y={yy}, " + f"f(x)={fv:.5f}, eps={eps:.5f}") + print_to_console_and_file(line, outfile) + + # Закроем файл, если нужно + if outfile is not None: + outfile.close() + print("\nРезультаты также сохранены в файл:", out_filename) + + # 5) Построение единого графика + plot_results(x_data, y_data, results) + + +# --------------------------------------------------------- +# Запуск +# --------------------------------------------------------- +if __name__ == "__main__": + main() diff --git "a/\320\2403213/molodichenko_409163/lab4/lab4metop.py" "b/\320\2403213/molodichenko_409163/lab4/lab4metop.py" new file mode 100644 index 0000000..e5c1480 --- /dev/null +++ "b/\320\2403213/molodichenko_409163/lab4/lab4metop.py" @@ -0,0 +1,81 @@ +import numpy as np +from scipy.optimize import minimize_scalar + +# Целевая функция +f = lambda x: 6*x[0]**2 + x[1]**2 - x[0]*x[1] + 4*x[0] - 8*x[1] + 1 + +# Градиент функции +def grad_f(x): + df_dx1 = 12*x[0] - x[1] + 4 + df_dx2 = 2*x[1] - x[0] - 8 + return np.array([df_dx1, df_dx2]) + +# Округление до 4 значащих цифр +def round_significant(x, digits=4): + return np.array([float(f"{xi:.{digits}g}") for xi in x]) + +# Метод покоординатного спуска +def coordinate_descent(x0, eps=1e-4): + x = np.array(x0, dtype=float) + iterations = 0 + while True: + x_prev = x.copy() + iterations += 1 + + # Минимизация по x1 + f1 = lambda x1: f([x1, x[1]]) + res1 = minimize_scalar(f1) + x[0] = res1.x + + # Минимизация по x2 + f2 = lambda x2: f([x[0], x2]) + res2 = minimize_scalar(f2) + x[1] = res2.x + + if np.linalg.norm(x - x_prev) < eps: + break + + print(f"Coordinate Descent iterations: {iterations}") + return round_significant(x) + +# Метод градиентного спуска +def gradient_descent(x0, alpha=0.05, eps=1e-4): + x = np.array(x0, dtype=float) + iterations = 0 + while True: + x_prev = x.copy() + iterations += 1 + g = grad_f(x) + x = x - alpha * g + if np.linalg.norm(x - x_prev) < eps: + break + print(f"Gradient Descent iterations: {iterations}") + return round_significant(x) + +# Метод наискорейшего спуска +def steepest_descent(x0, eps=1e-4): + x = np.array(x0, dtype=float) + iterations = 0 + while True: + x_prev = x.copy() + iterations += 1 + g = grad_f(x) + direction = -g + + # Одномерная минимизация вдоль направления + phi = lambda alpha: f(x + alpha * direction) + res = minimize_scalar(phi) + alpha = res.x + + x = x + alpha * direction + if np.linalg.norm(x - x_prev) < eps: + break + print(f"Steepest Descent iterations: {iterations}") + return round_significant(x) + +# Тестирование +x0 = [2, 2] +print("Coordinate Descent result:", coordinate_descent(x0)) +print("Gradient Descent result:", gradient_descent(x0)) +print("Steepest Descent result:", steepest_descent(x0)) + diff --git "a/\320\2403213/molodichenko_409163/lab4/\320\273\320\260\320\2614.pdf" "b/\320\2403213/molodichenko_409163/lab4/\320\273\320\260\320\2614.pdf" new file mode 100644 index 0000000..832b3a0 Binary files /dev/null and "b/\320\2403213/molodichenko_409163/lab4/\320\273\320\260\320\2614.pdf" differ diff --git "a/\320\2403213/molodichenko_409163/lab5/main-5.py" "b/\320\2403213/molodichenko_409163/lab5/main-5.py" new file mode 100644 index 0000000..a72b5ac --- /dev/null +++ "b/\320\2403213/molodichenko_409163/lab5/main-5.py" @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +""" +ЛР-5 (Интерполяция функции) +Вариант 6 — универсальная программа: + • ввод данных тремя способами + • таблица конечных разностей + • методы: Лагранж, Ньютон (разд. и конечные Δ), Гаусс + • графики и элементарная валидация +""" + +import math, sys, json, pathlib +from typing import Callable, List, Tuple +import numpy as np +import matplotlib.pyplot as plt +def is_uniform(xs, rtol=1e-12, atol=1e-14): + diffs = np.diff(xs) + return np.allclose(diffs, diffs[0], rtol=rtol, atol=atol) +# ──────────────────────────────────── служебные функции ────────────── +def forward_differences(y: List[float]) -> List[List[float]]: + """Полный треугольник конечных разностей Δᵏyᵢ""" + table = [y] + while len(table[-1]) > 1: + prev = table[-1] + table.append([prev[i + 1] - prev[i] for i in range(len(prev) - 1)]) + return table + +def print_table(table: List[List[float]]) -> None: + w = max(len(table[0]), 7) + for k, row in enumerate(table): + print(f'Δ{k:>1} ', end='') + print(' '.join(f'{v:>10.6f}' for v in row).ljust(w * 12)) + print() + +# ─────────────────────────────── интерполяционные методы ───────────── +def lagrange(x: List[float], y: List[float], xp: float) -> float: + s = 0.0 + for i in range(len(x)): + li = 1.0 + for j in range(len(x)): + if i != j: + li *= (xp - x[j]) / (x[i] - x[j]) + s += y[i] * li + return s + +def newton_backward(x: List[float], y: List[float], xp: float) -> float: + h = x[1] - x[0] + u = (xp - x[-1]) / h + Δ = forward_differences(y) + res = y[-1] + term, fact = 1.0, 1 + for k in range(1, len(x)): + term *= (u + k - 1) + fact *= k + res += term * Δ[k][-1] / fact + return res + +def newton_forward(x: List[float], y: List[float], xp: float) -> float: + h = x[1] - x[0] + u = (xp - x[0]) / h + Δ = forward_differences(y) + res = y[0] + term, fact = 1.0, 1 + for k in range(1, len(x)): + term *= (u - (k - 1)) + fact *= k + res += term * Δ[k][0] / fact + return res + +def gauss_second_backward(x: List[float], y: List[float], xp: float) -> float: + """Формула Гаусса 2-я, 'назад' (центр — средняя точка)""" + n = len(x) + m = n // 2 # индекс центра + h = x[1] - x[0] + t = (xp - x[m]) / h + Δ = forward_differences(y) + + # удобные ссылки на нужные ∇-разности + def nabla(k: int, j: int) -> float: + """∇ᵏ y_{j} (j отсчитывается от x₀)""" + return Δ[k][j] + + res = y[m] + + res += t * nabla(1, m - 1) + res += t*(t + 1)/2 * nabla(2, m - 1) + res += t*(t + 1)*(t - 1)/6* nabla(3, m - 2) + res += t*(t + 1)*(t - 1)*(t - 2)/24 * nabla(4, m - 2) + res += t*(t + 1)*(t - 1)*(t - 2)*(t + 2)/120 * nabla(5, m - 3) + res += t*(t + 1)*(t - 1)*(t - 2)*(t + 2)*(t + 3)/720 * nabla(6, m - 3) + + return res + +# ──────────────────────────────── источник данных ──────────────────── +def source_keyboard() -> Tuple[List[float], List[float]]: + n = int(input("Сколько узлов? > ")) + x, y = [], [] + for i in range(n): + xi = float(input(f"x[{i}] = ")) + yi = float(input(f"y[{i}] = ")) + x.append(xi); y.append(yi) + return x, y + +def source_file(path: str) -> Tuple[List[float], List[float]]: + arr = np.loadtxt(path, delimiter=',') + return arr[:, 0].tolist(), arr[:, 1].tolist() + +def source_function(func: Callable[[float], float]) -> Tuple[List[float], List[float]]: + a = float(input("a = ")) + b = float(input("b = ")) + n = int(input("точек (≥2) = ")) + x = np.linspace(a, b, n) + y = [func(t) for t in x] + return x.tolist(), y + +# ────────────────────────────────── графика ────────────────────────── +def draw(x: List[float], y: List[float], + poly: Callable[[float], float], title: str = "") -> None: + xs = np.linspace(min(x), max(x), 400) + plt.figure() + plt.plot(xs, [poly(t) for t in xs], label='Полином', linewidth=1.2) + plt.scatter(x, y, marker='o', zorder=3, label='Узлы') + plt.title(title) + plt.grid() + plt.legend() + plt.show() + +# ─────────────────────────────── основная логика ───────────────────── +METHODS = { + 1: ("Лагранж", lagrange), + 2: ("Ньютон (разд.)", newton_forward), # для разн. h программа сама решит F/B + 3: ("Ньютон (Δ, назад)", newton_backward), +} + +def run() -> None: + print("===== Лабораторная работа 5. Выбор источника данных =====") + print("1 — Ввод с клавиатуры") + print("2 — Чтение CSV-файла (x,y)") + print("3 — Таблица сгенерирована по функции") + choice = input("> ") + + if choice == "1": + x, y = source_keyboard() + elif choice == "2": + fname = input("Имя файла > ") + x, y = source_file(fname) + elif choice == "3": + funcs = {"sin": math.sin, + "cos": math.cos, + "exp": math.exp} + print("Доступные функции:", *funcs) + fkey = input("> ") + x, y = source_function(funcs[fkey]) + else: + sys.exit("неизвестный выбор") + + if not is_uniform(x): + sys.exit("Для формул с Δ требуется равномерная сетка!") + + print("\n— Таблица конечных разностей —") + table = forward_differences(y) + print_table(table) + + xp = float(input("x*, где вычислять полином = ")) + + print("\nМетод значение") + for num, (name, fn) in METHODS.items(): + try: + fx = fn(x, y, xp) + print(f"{num:>2}. {name:<20} {fx:>12.6f}") + except Exception as e: + print(f"{num:>2}. {name:<20} ошибка: {e}") + + # пример графика с полиномом Ньютона (Δ, назад), + # если xp внутри диапазона + if min(x) <= xp <= max(x): + draw(x, y, lambda t: newton_backward(x, y, t), + f"Интерполяция (метод 3) — x*={xp}") + +if __name__ == "__main__": + run() diff --git "a/\320\2403213/molodichenko_409163/lab5/\320\273\320\260\320\2615.pdf" "b/\320\2403213/molodichenko_409163/lab5/\320\273\320\260\320\2615.pdf" new file mode 100644 index 0000000..0c0a9e9 Binary files /dev/null and "b/\320\2403213/molodichenko_409163/lab5/\320\273\320\260\320\2615.pdf" differ diff --git "a/\320\2403213/molodichenko_409163/lab6/vichmat6.py" "b/\320\2403213/molodichenko_409163/lab6/vichmat6.py" new file mode 100644 index 0000000..23deee8 --- /dev/null +++ "b/\320\2403213/molodichenko_409163/lab6/vichmat6.py" @@ -0,0 +1,120 @@ +import numpy as np +import matplotlib.pyplot as plt + +class ODESolver: + def __init__(self, f, exact=None): + self.f = f # function f(x,y) + self.exact = exact # exact solution y(x) + + def euler(self, x0, y0, xn, h): + n = int((xn - x0)/h) + xs = np.linspace(x0, x0 + n*h, n+1) + ys = np.zeros(n+1) + ys[0] = y0 + for i in range(n): + ys[i+1] = ys[i] + h * self.f(xs[i], ys[i]) + return xs, ys + + def rk4(self, x0, y0, xn, h): + n = int((xn - x0)/h) + xs = np.linspace(x0, x0 + n*h, n+1) + ys = np.zeros(n+1) + ys[0] = y0 + for i in range(n): + x, y = xs[i], ys[i] + k1 = self.f(x, y) + k2 = self.f(x + h/2, y + h*k1/2) + k3 = self.f(x + h/2, y + h*k2/2) + k4 = self.f(x + h, y + h*k3) + ys[i+1] = y + h*(k1 + 2*k2 + 2*k3 + k4)/6 + return xs, ys + + def adams_pc(self, x0, y0, xn, h): + # 4-step Adams-Bashforth predictor, Adams-Moulton corrector + xs_rk, ys_rk = self.rk4(x0, y0, x0 + 3*h, h) + xs = list(xs_rk) + ys = list(ys_rk) + n = int((xn - x0)/h) + for i in range(3, n): + x_vals = xs[i-3:i+1] + y_vals = ys[i-3:i+1] + f_vals = [self.f(x_vals[j], y_vals[j]) for j in range(4)] + # predictor (Adams-Bashforth) + y_pred = ys[i] + h*(55*f_vals[3] - 59*f_vals[2] + 37*f_vals[1] - 9*f_vals[0])/24 + x_next = xs[i] + h + # corrector (Adams-Moulton) + f_pred = self.f(x_next, y_pred) + y_corr = ys[i] + h*(9*f_pred + 19*f_vals[3] - 5*f_vals[2] + f_vals[1])/24 + xs.append(x_next) + ys.append(y_corr) + return np.array(xs), np.array(ys) + + def runge_error(self, method, p, *args): + # compute error estimate via Runge rule + xs1, ys1 = method(*args) + h = args[3] + args_half = (args[0], args[1], args[2], h/2) + xs2, ys2 = method(*args_half) + # align: ys2 at every 2nd step + ys2_sub = ys2[::2] + err = np.max(np.abs((ys2_sub - ys1)/(2**p - 1))) + return err + + +def select_problem(): + print("Выберите ОДУ из списка:") + print("1) y' = y, y(0) = 1, точное: y = exp(x)") + print("2) y' = x, y(0) = 0, точное: y = x^2/2") + print("3) y' = x*y, y(0) = 1, точное: y = exp(x^2/2)") + choice = int(input("Номер задачи: ")) + if choice == 1: + return lambda x,y: y, lambda x: np.exp(x), 0, 1 + if choice == 2: + return lambda x,y: x, lambda x: x**2/2, 0, 0 + if choice == 3: + return lambda x,y: x*y, lambda x: np.exp(x**2/2), 0, 1 + raise ValueError("Неправильный выбор") + +if __name__ == '__main__': + f, exact, x0, y0 = select_problem() + xn = float(input("Введите x_n (конец отрезка): ")) + h = float(input("Введите шаг h: ")) + eps = float(input("Введите точность ε для оценки (например, 1e-3): ")) + + solver = ODESolver(f, exact) + + # вычисления + xe, ye = solver.euler(x0, y0, xn, h) + xr, yr = solver.rk4(x0, y0, xn, h) + xa, ya = solver.adams_pc(x0, y0, xn, h) + + # оценки погрешности + err_euler = solver.runge_error(solver.euler, 1, x0, y0, xn, h) + err_rk4 = solver.runge_error(solver.rk4, 4, x0, y0, xn, h) + true_vals = exact(xr) + err_adams = np.max(np.abs(true_vals - ya)) + + # вывод таблиц + print("\nТаблица решений:") + print("i\tx\tEuler\tRK4\tAdams\tExact") + for i, x in enumerate(xe): + print(f"{i}\t{x:.4f}\t{ye[i]:.6f}\t{yr[i]:.6f}\t{ya[i]:.6f}\t{exact(x):.6f}") + + print(f"\nОценка погрешности Эйлера (Рунге): {err_euler:.2e}") + print(f"Оценка погрешности RK4 (Рунге): {err_rk4:.2e}") + print(f"Максимальная погрешность Адамса: {err_adams:.2e}") + + # график + xs = np.linspace(x0, xn, 200) + plt.plot(xs, exact(xs), label='Exact') + plt.plot(xe, ye, 'o-', label='Euler') + plt.plot(xr, yr, 's-', label='RK4') + plt.plot(xa, ya, 'd-', label='Adams') + plt.legend() + plt.xlabel('x') + plt.ylabel('y') + plt.title("Сравнение методов") + plt.grid(True) + plt.show() + + print("\nГотово. Проверьте, что шаг и точность дают приемлемый результат.") diff --git "a/\320\2403213/molodichenko_409163/lab6/\320\273\320\260\320\2616.pdf" "b/\320\2403213/molodichenko_409163/lab6/\320\273\320\260\320\2616.pdf" new file mode 100644 index 0000000..3b76b8a Binary files /dev/null and "b/\320\2403213/molodichenko_409163/lab6/\320\273\320\260\320\2616.pdf" differ