diff --git a/deprecated_tests/sem01/tests/test_lesson04_tasks.py b/deprecated_tests/sem01/tests/test_lesson04_tasks.py index 4110bdcc..54087b11 100644 --- a/deprecated_tests/sem01/tests/test_lesson04_tasks.py +++ b/deprecated_tests/sem01/tests/test_lesson04_tasks.py @@ -1,6 +1,7 @@ -import pytest import random +import pytest + from solutions.sem01.lesson04.task1 import is_arithmetic_progression from solutions.sem01.lesson04.task2 import merge_intervals from solutions.sem01.lesson04.task3 import find_single_number @@ -8,6 +9,7 @@ from solutions.sem01.lesson04.task5 import find_row_with_most_ones from solutions.sem01.lesson04.task6 import count_cycles + @pytest.mark.parametrize("lst, expected", [ pytest.param([], True, id="empty_list"), pytest.param([5], True, id="single_element"), diff --git a/deprecated_tests/sem01/tests/test_lesson05_tasks.py b/deprecated_tests/sem01/tests/test_lesson05_tasks.py index 72ad6bc8..5c9de778 100644 --- a/deprecated_tests/sem01/tests/test_lesson05_tasks.py +++ b/deprecated_tests/sem01/tests/test_lesson05_tasks.py @@ -1,4 +1,4 @@ -import pytest +import pytest from solutions.sem01.lesson05.task1 import is_palindrome from solutions.sem01.lesson05.task2 import are_anagrams @@ -7,6 +7,7 @@ from solutions.sem01.lesson05.task5 import reg_validator from solutions.sem01.lesson05.task6 import simplify_path + @pytest.mark.parametrize("s, expected", [ pytest.param("", True, id="empty_string"), pytest.param("a", True, id="single_char"), diff --git a/deprecated_tests/sem01/tests/test_lesson06_tasks.py b/deprecated_tests/sem01/tests/test_lesson06_tasks.py index 707d6609..4d69961b 100644 --- a/deprecated_tests/sem01/tests/test_lesson06_tasks.py +++ b/deprecated_tests/sem01/tests/test_lesson06_tasks.py @@ -1,4 +1,4 @@ -import pytest +import pytest from solutions.sem01.lesson06.task1 import int_to_roman from solutions.sem01.lesson06.task2 import get_len_of_longest_substring @@ -88,6 +88,7 @@ def test_is_there_any_good_subarray(nums, k, expected): import pytest + @pytest.mark.parametrize("text, expected", [ pytest.param("", 0, id="empty_string"), pytest.param(" ", 0, id="only_spaces"), diff --git a/deprecated_tests/sem01/tests/test_lesson08_tasks.py b/deprecated_tests/sem01/tests/test_lesson08_tasks.py index 962ba4bd..cf0bcbc9 100644 --- a/deprecated_tests/sem01/tests/test_lesson08_tasks.py +++ b/deprecated_tests/sem01/tests/test_lesson08_tasks.py @@ -1,10 +1,10 @@ -import pytest import math import time from solutions.sem01.lesson08.task1 import make_averager from solutions.sem01.lesson08.task2 import collect_statistic + def test_make_averager(): get_avg = make_averager(2) diff --git a/deprecated_tests/sem01/tests/test_lesson11_tasks.py b/deprecated_tests/sem01/tests/test_lesson11_tasks.py index d0cd02ef..e7d7b067 100644 --- a/deprecated_tests/sem01/tests/test_lesson11_tasks.py +++ b/deprecated_tests/sem01/tests/test_lesson11_tasks.py @@ -1,9 +1,8 @@ -import pytest - import math import sys from io import StringIO +import pytest from solutions.sem01.lesson11.task1 import Vector2D diff --git a/deprecated_tests/sem01/tests_hw/test_hw1_tasks.py b/deprecated_tests/sem01/tests_hw/test_hw1_tasks.py index 0ecf8a10..5bc36c6f 100644 --- a/deprecated_tests/sem01/tests_hw/test_hw1_tasks.py +++ b/deprecated_tests/sem01/tests_hw/test_hw1_tasks.py @@ -1,15 +1,12 @@ -import pytest import uuid -from unittest.mock import MagicMock, patch, Mock +from unittest.mock import MagicMock, Mock, patch + +import pytest -from homeworks.sem01.hw1.aggregate_segmentation import aggregate_segmentation, ALLOWED_TYPES +from homeworks.sem01.hw1.aggregate_segmentation import ALLOWED_TYPES, aggregate_segmentation from homeworks.sem01.hw1.backoff import backoff from homeworks.sem01.hw1.cache import lru_cache from homeworks.sem01.hw1.convert_exception import convert_exceptions_to_api_compitable_ones -from .hw1_test_data.cache_test_data import ( - TESTCASE_DATA, - TESTCASE_IDS, -) NAME_BACKOFF_MODULE = "homeworks.hw1.backoff" # название модуля с backoff diff --git a/homeworks/sem01/hw1/backoff.py b/homeworks/sem01/hw1/backoff.py index 696ffa73..a3373a98 100644 --- a/homeworks/sem01/hw1/backoff.py +++ b/homeworks/sem01/hw1/backoff.py @@ -1,5 +1,3 @@ -from random import uniform -from time import sleep from typing import ( Callable, ParamSpec, diff --git a/solutions/sem01/lesson02/task3.py b/solutions/sem01/lesson02/task3.py index ee2a84ec..e997f805 100644 --- a/solutions/sem01/lesson02/task3.py +++ b/solutions/sem01/lesson02/task3.py @@ -1,4 +1,4 @@ def get_amount_of_ways_to_climb(stair_amount: int) -> int: - step_prev, step_curr = 1, 1 + _step_prev, step_curr = 1, 1 # ваш код return step_curr diff --git a/solutions/sem01/lesson03/task1.py b/solutions/sem01/lesson03/task1.py index f1d8fe26..7b048e65 100644 --- a/solutions/sem01/lesson03/task1.py +++ b/solutions/sem01/lesson03/task1.py @@ -1,3 +1,3 @@ def flip_bits_in_range(num: int, left_bit: int, right_bit: int) -> int: # ваш код - return num \ No newline at end of file + return num diff --git a/solutions/sem01/lesson03/task2.py b/solutions/sem01/lesson03/task2.py index a3a738c2..5cf2b631 100644 --- a/solutions/sem01/lesson03/task2.py +++ b/solutions/sem01/lesson03/task2.py @@ -1,3 +1,3 @@ def get_cube_root(n: float, eps: float) -> float: # ваш код - return n \ No newline at end of file + return n diff --git a/solutions/sem01/lesson04/task1.py b/solutions/sem01/lesson04/task1.py index 47384423..0135e399 100644 --- a/solutions/sem01/lesson04/task1.py +++ b/solutions/sem01/lesson04/task1.py @@ -1,3 +1,3 @@ def is_arithmetic_progression(lst: list[list[int]]) -> bool: # ваш код - return False \ No newline at end of file + return False diff --git a/solutions/sem01/lesson04/task2.py b/solutions/sem01/lesson04/task2.py index 4591d0a3..5d6f8ee8 100644 --- a/solutions/sem01/lesson04/task2.py +++ b/solutions/sem01/lesson04/task2.py @@ -1,3 +1,3 @@ def merge_intervals(intervals: list[list[int, int]]) -> list[list[int, int]]: # ваш код - return [[0,0]] \ No newline at end of file + return [[0, 0]] diff --git a/solutions/sem01/lesson04/task4.py b/solutions/sem01/lesson04/task4.py index b21bc5a3..2664384d 100644 --- a/solutions/sem01/lesson04/task4.py +++ b/solutions/sem01/lesson04/task4.py @@ -1,3 +1,3 @@ def move_zeros_to_end(nums: list[int]) -> list[int]: # ваш код - return 0 \ No newline at end of file + return 0 diff --git a/solutions/sem01/lesson04/task5.py b/solutions/sem01/lesson04/task5.py index 02d7742b..ec6932ee 100644 --- a/solutions/sem01/lesson04/task5.py +++ b/solutions/sem01/lesson04/task5.py @@ -1,3 +1,3 @@ def find_row_with_most_ones(matrix: list[list[int]]) -> int: # ваш код - return 0 \ No newline at end of file + return 0 diff --git a/solutions/sem01/lesson04/task6.py b/solutions/sem01/lesson04/task6.py index 16df27ca..d16e77dd 100644 --- a/solutions/sem01/lesson04/task6.py +++ b/solutions/sem01/lesson04/task6.py @@ -1,3 +1,3 @@ -def count_cycles(arr: list[int]) -> int: +def count_cycles(arr: list[int]) -> int: # ваш код - return 0 \ No newline at end of file + return 0 diff --git a/solutions/sem01/lesson05/task1.py b/solutions/sem01/lesson05/task1.py index 9a17211e..fdf3b548 100644 --- a/solutions/sem01/lesson05/task1.py +++ b/solutions/sem01/lesson05/task1.py @@ -1,3 +1,3 @@ def is_palindrome(text: str) -> bool: # ваш код - return False \ No newline at end of file + return False diff --git a/solutions/sem01/lesson05/task2.py b/solutions/sem01/lesson05/task2.py index 36750380..c70b4029 100644 --- a/solutions/sem01/lesson05/task2.py +++ b/solutions/sem01/lesson05/task2.py @@ -1,3 +1,3 @@ def are_anagrams(word1: str, word2: str) -> bool: # ваш код - return False \ No newline at end of file + return False diff --git a/solutions/sem01/lesson05/task4.py b/solutions/sem01/lesson05/task4.py index 4c4e9086..7c2c26f1 100644 --- a/solutions/sem01/lesson05/task4.py +++ b/solutions/sem01/lesson05/task4.py @@ -1,3 +1,3 @@ def unzip(compress_text: str) -> str: # ваш код - return compress_text \ No newline at end of file + return compress_text diff --git a/solutions/sem01/lesson05/task5.py b/solutions/sem01/lesson05/task5.py index 076c5bb6..da9e6d08 100644 --- a/solutions/sem01/lesson05/task5.py +++ b/solutions/sem01/lesson05/task5.py @@ -1,3 +1,3 @@ -def reg_validator(reg_expr: str, text: str) -> bool: +def reg_validator(reg_expr: str, text: str) -> bool: # ваш код - return False \ No newline at end of file + return False diff --git a/solutions/sem01/lesson05/task6.py b/solutions/sem01/lesson05/task6.py index 1b914ada..63207797 100644 --- a/solutions/sem01/lesson05/task6.py +++ b/solutions/sem01/lesson05/task6.py @@ -1,3 +1,3 @@ def simplify_path(path: str) -> str: # ваш код - return path \ No newline at end of file + return path diff --git a/solutions/sem01/lesson06/task1.py b/solutions/sem01/lesson06/task1.py index 2d1e30e9..353cb361 100644 --- a/solutions/sem01/lesson06/task1.py +++ b/solutions/sem01/lesson06/task1.py @@ -1,3 +1,3 @@ def int_to_roman(num: int) -> str: # ваш код - return "" \ No newline at end of file + return "" diff --git a/solutions/sem01/lesson06/task2.py b/solutions/sem01/lesson06/task2.py index f535b5a0..f1034e24 100644 --- a/solutions/sem01/lesson06/task2.py +++ b/solutions/sem01/lesson06/task2.py @@ -1,3 +1,3 @@ def get_len_of_longest_substring(text: str) -> int: # ваш код - return 0 \ No newline at end of file + return 0 diff --git a/solutions/sem01/lesson06/task3.py b/solutions/sem01/lesson06/task3.py index 7449a1e7..b160d615 100644 --- a/solutions/sem01/lesson06/task3.py +++ b/solutions/sem01/lesson06/task3.py @@ -2,6 +2,5 @@ def is_there_any_good_subarray( nums: list[int], k: int, ) -> bool: - # ваш код return False diff --git a/solutions/sem01/lesson06/task4.py b/solutions/sem01/lesson06/task4.py index 5b75a110..95a7098e 100644 --- a/solutions/sem01/lesson06/task4.py +++ b/solutions/sem01/lesson06/task4.py @@ -1,3 +1,3 @@ def count_unique_words(text: str) -> int: # ваш код - return 0 \ No newline at end of file + return 0 diff --git a/solutions/sem01/lesson08/task1.py b/solutions/sem01/lesson08/task1.py index 4390f6c8..7fa724ef 100644 --- a/solutions/sem01/lesson08/task1.py +++ b/solutions/sem01/lesson08/task1.py @@ -1,5 +1,6 @@ from typing import Callable + def make_averager(accumulation_period: int) -> Callable[[float], float]: # ваш код - pass \ No newline at end of file + pass diff --git a/solutions/sem01/lesson08/task2.py b/solutions/sem01/lesson08/task2.py index 6e4af870..cc2ae430 100644 --- a/solutions/sem01/lesson08/task2.py +++ b/solutions/sem01/lesson08/task2.py @@ -2,9 +2,7 @@ T = TypeVar("T") -def collect_statistic( - statistics: dict[str, list[float, int]] -) -> Callable[[T], T]: - + +def collect_statistic(statistics: dict[str, list[float, int]]) -> Callable[[T], T]: # ваш код - pass \ No newline at end of file + pass diff --git a/solutions/sem01/lesson12/task3.py b/solutions/sem01/lesson12/task3.py index 64c112cc..58b0986e 100644 --- a/solutions/sem01/lesson12/task3.py +++ b/solutions/sem01/lesson12/task3.py @@ -1,6 +1,3 @@ -import sys - - class FileOut: def __init__( self, diff --git a/solutions/sem02/lesson03/task1.py b/solutions/sem02/lesson03/task1.py index 2c3fc0b5..322706c5 100644 --- a/solutions/sem02/lesson03/task1.py +++ b/solutions/sem02/lesson03/task1.py @@ -5,16 +5,20 @@ class ShapeMismatchError(Exception): pass -def sum_arrays_vectorized( - lhs: np.ndarray, - rhs: np.ndarray, -) -> np.ndarray: ... +def sum_arrays_vectorized(lhs: np.ndarray, rhs: np.ndarray) -> np.ndarray: + if len(lhs) != len(rhs): + raise ShapeMismatchError + return np.add(lhs, rhs) -def compute_poly_vectorized(abscissa: np.ndarray) -> np.ndarray: ... +def compute_poly_vectorized(abscissa: np.ndarray) -> np.ndarray: + return 3 * (abscissa**2) + 2 * abscissa + 1 -def get_mutual_l2_distances_vectorized( - lhs: np.ndarray, - rhs: np.ndarray, -) -> np.ndarray: ... +def get_mutual_l2_distances_vectorized(lhs: np.ndarray, rhs: np.ndarray) -> np.ndarray: + if lhs.shape[1] != rhs.shape[1]: + raise ShapeMismatchError + + cube = lhs[:, np.newaxis, :] - rhs[np.newaxis, :, :] + distances = np.sqrt(np.sum(cube**2, axis=2)) + return distances diff --git a/solutions/sem02/lesson03/task2.py b/solutions/sem02/lesson03/task2.py index fc823c1d..962daa33 100644 --- a/solutions/sem02/lesson03/task2.py +++ b/solutions/sem02/lesson03/task2.py @@ -9,11 +9,28 @@ def convert_from_sphere( distances: np.ndarray, azimuth: np.ndarray, inclination: np.ndarray, -) -> tuple[np.ndarray, np.ndarray, np.ndarray]: ... +) -> tuple[np.ndarray, np.ndarray, np.ndarray]: + if not (distances.shape == azimuth.shape == inclination.shape): + raise ShapeMismatchError + + x = distances * np.sin(inclination) * np.cos(azimuth) + y = distances * np.sin(inclination) * np.sin(azimuth) + z = distances * np.cos(inclination) + + return x, y, z def convert_to_sphere( abscissa: np.ndarray, ordinates: np.ndarray, applicates: np.ndarray, -) -> tuple[np.ndarray, np.ndarray, np.ndarray]: ... +) -> tuple[np.ndarray, np.ndarray, np.ndarray]: + if not (abscissa.shape == ordinates.shape == applicates.shape): + raise ShapeMismatchError + + rad = np.sqrt(abscissa**2 + ordinates**2 + applicates**2) + azim = np.arctan2(ordinates, abscissa) + inc = np.arccos(applicates / rad) + inc = np.where(rad == 0, 0.0, inc) + + return rad, azim, inc diff --git a/solutions/sem02/lesson03/task3.py b/solutions/sem02/lesson03/task3.py index 477acd0c..0b0d7ca2 100644 --- a/solutions/sem02/lesson03/task3.py +++ b/solutions/sem02/lesson03/task3.py @@ -3,4 +3,17 @@ def get_extremum_indices( ordinates: np.ndarray, -) -> tuple[np.ndarray, np.ndarray]: ... +) -> tuple[np.ndarray, np.ndarray]: + if ordinates.ndim > 1 or len(ordinates) < 3: + raise ValueError + + left = ordinates[:-2] + center = ordinates[1:-1] + right = ordinates[2:] + + max = (left < center) & (center > right) + min = (left > center) & (center < right) + + index = np.arange(1, len(ordinates) - 1) + + return index[min], index[max] diff --git a/solutions/sem02/lesson04/task1.py b/solutions/sem02/lesson04/task1.py index 1b5526c1..094eff52 100644 --- a/solutions/sem02/lesson04/task1.py +++ b/solutions/sem02/lesson04/task1.py @@ -1,17 +1,42 @@ import numpy as np +from matplotlib import image def pad_image(image: np.ndarray, pad_size: int) -> np.ndarray: - # ваш код - return image + H, W = image.shape[:2] + + if pad_size < 1: + raise ValueError + + if image.ndim == 2: + zer = np.zeros((H + 2 * pad_size, W + 2 * pad_size), dtype=image.dtype) + zer[pad_size : pad_size + H, pad_size : pad_size + W] = image + else: + zer = np.zeros((H + 2 * pad_size, W + 2 * pad_size, image.shape[2]), dtype=image.dtype) + zer[pad_size : pad_size + H, pad_size : pad_size + W, :] = image + + return zer def blur_image( image: np.ndarray, kernel_size: int, ) -> np.ndarray: - # ваш код - return image + if kernel_size <= 0 or kernel_size % 2 == 0: + raise ValueError + + if kernel_size == 1: + return image.copy() + + padded_image = pad_image(image, kernel_size // 2) + res = np.zeros(image.shape, dtype=float) + + for i in range(kernel_size): + for j in range(kernel_size): + res += padded_image[i : i + image.shape[0], j : j + image.shape[1]] + + res /= kernel_size**2 + return res.astype(np.uint8) if __name__ == "__main__": diff --git a/solutions/sem02/lesson04/task2.py b/solutions/sem02/lesson04/task2.py index be9a2288..8ff165d6 100644 --- a/solutions/sem02/lesson04/task2.py +++ b/solutions/sem02/lesson04/task2.py @@ -5,6 +5,17 @@ def get_dominant_color_info( image: np.ndarray[np.uint8], threshold: int = 5, ) -> tuple[np.uint8, float]: - # ваш код + if threshold < 1: + raise ValueError("threshold must be positive") - return 0, 0 + img = image.astype(np.int64) + uniq, counts = np.unique(img, return_counts=True) + delta = uniq[:, np.newaxis] - uniq + res = np.abs(delta) < threshold + result = np.sum(res * counts, axis=1) + index = np.argmax(result) + + color = uniq[index] + percentage = result[index] / image.size + + return np.uint8(color), float(percentage) diff --git a/solutions/sem02/lesson05/task1.py b/solutions/sem02/lesson05/task1.py index e9c7c3c5..31a4d435 100644 --- a/solutions/sem02/lesson05/task1.py +++ b/solutions/sem02/lesson05/task1.py @@ -9,4 +9,13 @@ def can_satisfy_demand( costs: np.ndarray, resource_amounts: np.ndarray, demand_expected: np.ndarray, -) -> bool: ... +) -> bool: + if costs.shape[0] != len(resource_amounts): + raise ShapeMismatchError() + if costs.shape[1] != len(demand_expected): + raise ShapeMismatchError() + + matrix = costs @ demand_expected + answer = (matrix <= resource_amounts).all() + + return answer diff --git a/solutions/sem02/lesson05/task2.py b/solutions/sem02/lesson05/task2.py index be1fb9d2..09b7b49f 100644 --- a/solutions/sem02/lesson05/task2.py +++ b/solutions/sem02/lesson05/task2.py @@ -8,4 +8,19 @@ class ShapeMismatchError(Exception): def get_projections_components( matrix: np.ndarray, vector: np.ndarray, -) -> tuple[np.ndarray | None, np.ndarray | None]: ... +) -> tuple[np.ndarray | None, np.ndarray | None]: + if matrix.shape[0] != matrix.shape[1]: + raise ShapeMismatchError() + if matrix.shape[1] != vector.shape[0]: + raise ShapeMismatchError() + + if abs(np.linalg.det(matrix)) < 1e-10: + return (None, None) + + dot = matrix @ vector + norms_sq = np.sum(matrix * matrix, axis=1) + coeffs = dot / norms_sq + pr = coeffs[:, np.newaxis] * matrix + ort = vector - pr + + return pr, ort diff --git a/solutions/sem02/lesson05/task3.py b/solutions/sem02/lesson05/task3.py index 0c66906c..1a66c954 100644 --- a/solutions/sem02/lesson05/task3.py +++ b/solutions/sem02/lesson05/task3.py @@ -9,4 +9,25 @@ def adaptive_filter( Vs: np.ndarray, Vj: np.ndarray, diag_A: np.ndarray, -) -> np.ndarray: ... +) -> np.ndarray: + M, N = Vs.shape + M2, K = Vj.shape + + if M != M2: + raise ShapeMismatchError() + if diag_A.shape[0] != K: + raise ShapeMismatchError() + + Vj_H = Vj.conj().T + A = np.diag(diag_A) + + inner = np.eye(K) + Vj_H @ Vj @ A # K K + inner_inv = np.linalg.inv(inner) + + temp = Vj_H @ Vs # K N + temp = inner_inv @ temp # K N + temp = Vj @ temp # M N + + y = Vs - temp + + return y diff --git a/solutions/sem02/lesson07/task1.py b/solutions/sem02/lesson07/task1.py index 3a505d89..0ca7081c 100644 --- a/solutions/sem02/lesson07/task1.py +++ b/solutions/sem02/lesson07/task1.py @@ -13,8 +13,87 @@ def visualize_diagrams( ordinates: np.ndarray, diagram_type: Any, ) -> None: - # ваш код - pass + if abscissa.shape != ordinates.shape: + raise ShapeMismatchError() + + figure = plt.figure(figsize=(8, 8)) + grid = plt.GridSpec(4, 4, wspace=space, hspace=space) + + axis_scatter = figure.add_subplot(grid[:-1, 1:]) + axis_hist_vert = figure.add_subplot( + grid[:-1, 0], + sharey=axis_scatter, + ) + axis_hist_hor = figure.add_subplot( + grid[-1, 1:], + sharex=axis_scatter, + ) + + axis_scatter.scatter(abscissa, ordinates, color="mediumpurple", alpha=0.7) + + if diagram_type == "box": + axis_hist_hor.boxplot( + abscissa, + vert=False, + patch_artist=True, + boxprops=dict(facecolor="mediumpurple", alpha=0.7), + medianprops=dict(color="black", linewidth=0.5), + ) + axis_hist_vert.boxplot( + ordinates, + vert=True, + patch_artist=True, + boxprops=dict(facecolor="mediumpurple", alpha=0.7), + medianprops=dict(color="black", linewidth=0.5), + ) + + axis_hist_hor.set_yticks([]) + axis_hist_vert.set_xticks([]) + + elif diagram_type == "hist": + axis_hist_hor.hist( + abscissa, + bins=50, + color="mediumpurple", + density=True, + alpha=0.7, + ) + axis_hist_vert.hist( + ordinates, + bins=50, + color="mediumpurple", + orientation="horizontal", + density=True, + alpha=0.7, + ) + + elif diagram_type == "violin": + vils = [None, None] + vils[0] = axis_hist_hor.violinplot(abscissa, vert=False) + vils[1] = axis_hist_vert.violinplot(ordinates, vert=True) + + for i in vils: + for body in i["bodies"]: + body.set_facecolor("red") + body.set_edgecolor("brown") + + for part in i: + if part == "bodies": + continue + + i[part].set_edgecolor("darkred") + i[part].set_linewidth(0.5) + + axis_hist_hor.set_yticks([]) + axis_hist_vert.set_xticks([]) + + else: + raise ValueError("Unknown diagram type") + + axis_hist_hor.invert_yaxis() + axis_hist_vert.invert_xaxis() + + plt.show() if __name__ == "__main__": diff --git a/solutions/sem02/lesson07/task2.py b/solutions/sem02/lesson07/task2.py index decd607e..c7a81880 100644 --- a/solutions/sem02/lesson07/task2.py +++ b/solutions/sem02/lesson07/task2.py @@ -1 +1,49 @@ -# ваш код (используйте функции или классы для решения данной задачи) +import json + +import matplotlib.pyplot as plt +import numpy as np + +with open("data/medic_data.json", "r") as f: + data_prew = json.load(f) + +data1 = np.array(data_prew["before"]) +labels, counts1 = np.unique(data1, return_counts=True) + +data2 = np.array(data_prew["after"]) +_, counts2 = np.unique(data2, return_counts=True) + +abscissa = np.arange(len(labels)) +width = 0.35 + +figure, axis = plt.subplots(figsize=(12, 7)) + +bl = axis.bar( + abscissa - width / 1.9, + counts1, + width=width, + label="Before", + color="cornflowerblue", + edgecolor="black", + alpha=0.7, +) +br = axis.bar( + abscissa + width / 1.9, + counts2, + width=width, + label="After", + color="mediumpurple", + edgecolor="black", + alpha=0.7, +) + +axis.set_title("Mitral disease stages", fontsize=16, fontweight="bold", color="dimgray") +axis.set_ylabel("amount of people", fontsize=12, fontweight="bold", color="dimgray") +axis.set_xticks(abscissa) +axis.set_xticklabels(labels, fontsize=10, fontweight="bold", color="dimgray") +axis.legend() + +axis.bar_label(bl, padding=3) +axis.bar_label(br, padding=3) + +plt.savefig("my_analysis.png", dpi=300, bbox_inches="tight") +plt.show() diff --git a/solutions/sem02/lesson08/task1.py b/solutions/sem02/lesson08/task1.py index 89f88572..659f066a 100644 --- a/solutions/sem02/lesson08/task1.py +++ b/solutions/sem02/lesson08/task1.py @@ -2,33 +2,97 @@ import matplotlib.pyplot as plt import numpy as np - from IPython.display import HTML from matplotlib.animation import FuncAnimation +def update_frame( + frame_id: int, + *, + line: plt.Line2D, + abscissa: np.ndarray, + axis: plt.Axes, + func, + animation_step, +) -> tuple[plt.Line2D]: + shift = frame_id * animation_step + ordinate = func(abscissa + shift) + line.set_data(abscissa + shift, ordinate) + axis.set_xlim(abscissa.min() + shift, abscissa.max() + shift) + + return line, axis + + +def function( + modulation, + fc, +): + def wrapper(abscissa: np.ndarray): + ordinate = modulation(abscissa) * np.sin(2 * np.pi * fc * abscissa) + + return ordinate + + return wrapper + + +def modulation_wraper(_): + return 1 + + def create_modulation_animation( - modulation, - fc, - num_frames, - plot_duration, - time_step=0.001, + modulation, + fc, + num_frames, + plot_duration, + time_step=0.001, animation_step=0.01, - save_path="" + save_path="", ) -> FuncAnimation: - # ваш код - return FuncAnimation() + if not modulation: + modulation = modulation_wraper + + num_points = int(plot_duration / time_step) + abscissa = np.linspace(0, plot_duration, num_points) + + figure, axis = plt.subplots(figsize=(16, 9)) + axis: plt.Axes + func = function(modulation, fc) + ordinate = func(abscissa) + + axis.set_xlim(abscissa.min(), abscissa.max()) + line, *_ = axis.plot(abscissa, ordinate, c="royalblue") + + animation = FuncAnimation( + figure, + partial( + update_frame, + line=line, + abscissa=abscissa, + axis=axis, + func=func, + animation_step=animation_step, + ), + frames=num_frames, + interval=animation_step * 1000, + blit=False, + ) + + if save_path: + animation.save(save_path, writer="pillow", fps=1 // animation_step) + + return animation if __name__ == "__main__": + def modulation_function(t): - return np.cos(t * 6) + return np.cos(t * 6) - num_frames = 100 - plot_duration = np.pi / 2 - time_step = 0.001 - animation_step = np.pi / 200 - fc = 50 + num_frames = 100 + plot_duration = np.pi / 2 + time_step = 0.001 + animation_step = np.pi / 200 + fc = 50 save_path_with_modulation = "modulated_signal.gif" animation = create_modulation_animation( @@ -38,6 +102,7 @@ def modulation_function(t): plot_duration=plot_duration, time_step=time_step, animation_step=animation_step, - save_path=save_path_with_modulation + save_path=save_path_with_modulation, ) - HTML(animation.to_jshtml()) \ No newline at end of file + HTML(animation.to_jshtml()) + plt.show() diff --git a/solutions/sem02/lesson08/task2.py b/solutions/sem02/lesson08/task2.py index b677c070..9c66ce57 100644 --- a/solutions/sem02/lesson08/task2.py +++ b/solutions/sem02/lesson08/task2.py @@ -1,34 +1,149 @@ +from collections import deque from functools import partial import matplotlib.pyplot as plt import numpy as np - from IPython.display import HTML from matplotlib.animation import FuncAnimation +from matplotlib.colors import BoundaryNorm, ListedColormap + +my_cmap = ListedColormap(["white", "black", "blue", "green"]) +boundaries = [0, 0.5, 1.5, 3, 5] +norm = BoundaryNorm(boundaries, my_cmap.N) + + +class Wave_Animation: + def __init__( + self, + maze: np.ndarray, + axis: plt.Axes, + start: tuple[int, int, int], + end: tuple[int, int, int], + ): + self.maze = maze.copy() + self.fontsize = 50 / max(maze.shape) + self.way = np.zeros_like(maze, dtype=int) + self.way[start[0], start[1]] = 1 + self.axis = axis + self.img = axis.imshow(maze, cmap=my_cmap, norm=norm, origin="upper", zorder=1) + self.start = start + self.end = end + self.queue = deque([start]) + self.text_grid = np.empty(maze.shape, dtype=object) + for i in range(maze.shape[0]): + for j in range(maze.shape[1]): + self.text_grid[i, j] = self.axis.text( + j, i, "", ha="center", va="center", color="white", fontsize=8 + ) + + t = self.text_grid[start[0], start[1]] + t.set_text("0") + t.set_color("white") + t.set_fontsize(self.fontsize) + + axis.tick_params(axis="both", which="major", labelsize=self.fontsize) + axis.set_xticks(range(maze.shape[1])) + axis.set_yticks(range(maze.shape[0])) + + axis.set_xticks(np.arange(-0.5, maze.shape[1], 1), minor=True) + axis.set_yticks(np.arange(-0.5, maze.shape[0], 1), minor=True) + + axis.grid(which="minor", color="black", linewidth=0.1, zorder=10) + axis.grid(which="major", visible=False) + + if maze.shape[0] > 40: + self.show_text = False + self.axis.grid(False) + else: + self.show_text = True + + def __call__(self, frame_id: int): + number = len(self.queue) + + if not self.queue: + return None + + for _ in range(number): + y, x, dist = self.queue.popleft() + + for neighbor in self._get_neighbors((y, x)): + self.way[neighbor] = 1 + + if self.show_text: + t = self.text_grid[neighbor] + t.set_text(str(dist + 1)) + t.set_fontsize(self.fontsize) + + self.maze[neighbor] = 2 + if neighbor == self.end: + if self.show_text: + t.set_color("red") + t.set_fontsize(self.fontsize) + self.axis.set_title(f"Path found with length {dist + 1}") + self.maze[neighbor] = 4 + self.queue.append((*neighbor, dist + 1)) + + self.img.set_data(self.maze) + + return [self.img] + + def _get_neighbors(self, coordinate: tuple[int, int]) -> list[tuple[int, int]]: + neighbors = [] + directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] + for dx, dy in directions: + new_y, new_x = coordinate[0] + dx, coordinate[1] + dy + if ( + 0 <= new_x < self.maze.shape[1] + and 0 <= new_y < self.maze.shape[0] + and self.way[new_y, new_x] == 0 + and self.maze[new_y, new_x] == 1 + ): + neighbors.append((new_y, new_x)) + return neighbors def animate_wave_algorithm( - maze: np.ndarray, - start: tuple[int, int], - end: tuple[int, int], - save_path: str = "" -) -> FuncAnimation: - # ваш код - return FuncAnimation() + maze: np.ndarray, start: tuple[int, int], end: tuple[int, int], save_path: str = "" +) -> FuncAnimation: + figure, axis = plt.subplots(figsize=(8, 8)) + axis: plt.Axes + + axis.set_title("Wave Algorithm Animation") + + wave_animation = Wave_Animation(maze, axis, (*start, 0), end) + + animation = FuncAnimation( + figure, + partial(wave_animation), + frames=1000, + interval=50, + repeat=False, + blit=False, + ) + + plt.show() + + if save_path: + animation.save(save_path, writer="pillow", fps=15, savefig_kwargs={"loop": 0}) + + return animation + if __name__ == "__main__": # Пример 1 - maze = np.array([ - [0, 0, 0, 0, 0, 0, 0], - [0, 1, 1, 1, 1, 1, 0], - [1, 1, 0, 1, 0, 1, 0], - [0, 0, 1, 1, 0, 1, 0], - [0, 0, 0, 0, 0, 1, 0], - [1, 1, 1, 1, 1, 1, 0], - [0, 0, 0, 0, 0, 0, 0], - ]) + maze = np.array( + [ + [0, 0, 0, 0, 0, 0, 0], + [0, 1, 1, 1, 1, 1, 0], + [1, 1, 0, 1, 0, 1, 0], + [0, 0, 1, 1, 0, 1, 0], + [0, 0, 0, 0, 0, 1, 0], + [1, 1, 1, 1, 1, 1, 0], + [0, 0, 0, 0, 0, 0, 0], + ] + ) start = (2, 0) end = (5, 0) @@ -36,18 +151,16 @@ def animate_wave_algorithm( animation = animate_wave_algorithm(maze, start, end, save_path) HTML(animation.to_jshtml()) - + # Пример 2 - + maze_path = "./data/maze.npy" loaded_maze = np.load(maze_path) # можете поменять, если захотите запустить из других точек - start = (2, 0) - end = (5, 0) + start = (2, 3) + end = (70, 3) loaded_save_path = "loaded_labyrinth.gif" loaded_animation = animate_wave_algorithm(loaded_maze, start, end, loaded_save_path) HTML(loaded_animation.to_jshtml()) - - \ No newline at end of file