diff --git a/.gitignore b/.gitignore index cececc15..9b686918 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ venv __pycache__ .pytest_cache .ruff_check +.vscode +all_conditions/ # Python Files *solved.ipynb diff --git a/Mitral disease stages.png b/Mitral disease stages.png new file mode 100644 index 00000000..c432e565 Binary files /dev/null and b/Mitral disease stages.png differ diff --git a/homeworks/sem01/hw1/aggregate_segmentation.py b/homeworks/sem01/hw1/aggregate_segmentation.py index 1cdc176a..29d8d16b 100644 --- a/homeworks/sem01/hw1/aggregate_segmentation.py +++ b/homeworks/sem01/hw1/aggregate_segmentation.py @@ -1,4 +1,4 @@ -ALLOWED_TYPES = { +'''ALLOWED_TYPES = { "spotter_word", "voice_human", "voice_bot", @@ -26,3 +26,4 @@ def aggregate_segmentation( # ваш код return {}, [] +''' \ No newline at end of file diff --git a/homeworks/sem01/hw1/backoff.py b/homeworks/sem01/hw1/backoff.py index 696ffa73..e12b4587 100644 --- a/homeworks/sem01/hw1/backoff.py +++ b/homeworks/sem01/hw1/backoff.py @@ -1,4 +1,4 @@ -from random import uniform +'''from random import uniform from time import sleep from typing import ( Callable, @@ -36,3 +36,4 @@ def backoff( # ваш код pass +''' \ No newline at end of file diff --git a/homeworks/sem01/hw1/cache.py b/homeworks/sem01/hw1/cache.py index 9eb1d5d2..c5abfebf 100644 --- a/homeworks/sem01/hw1/cache.py +++ b/homeworks/sem01/hw1/cache.py @@ -1,4 +1,4 @@ -from typing import ( +'''from typing import ( Callable, ParamSpec, TypeVar, @@ -25,3 +25,4 @@ def lru_cache(capacity: int) -> Callable[[Callable[P, R]], Callable[P, R]]: """ # ваш код pass +''' \ No newline at end of file diff --git a/homeworks/sem01/hw1/convert_exception.py b/homeworks/sem01/hw1/convert_exception.py index fe5c770f..2b100c1f 100644 --- a/homeworks/sem01/hw1/convert_exception.py +++ b/homeworks/sem01/hw1/convert_exception.py @@ -1,4 +1,4 @@ -from typing import ( +'''from typing import ( Callable, ParamSpec, TypeVar, @@ -26,3 +26,4 @@ def convert_exceptions_to_api_compitable_ones( # ваш код pass +''' \ No newline at end of file diff --git a/labyrinth.gif b/labyrinth.gif new file mode 100644 index 00000000..03451ec4 Binary files /dev/null and b/labyrinth.gif differ diff --git a/loaded_labyrinth.gif b/loaded_labyrinth.gif new file mode 100644 index 00000000..48f5ccd9 Binary files /dev/null and b/loaded_labyrinth.gif differ diff --git a/modulated_signal.gif b/modulated_signal.gif new file mode 100644 index 00000000..d6afbf02 Binary files /dev/null and b/modulated_signal.gif differ diff --git a/requirements-ci.txt b/requirements-ci.txt index 581b008d..b9227d4b 100644 --- a/requirements-ci.txt +++ b/requirements-ci.txt @@ -1,6 +1,8 @@ +ipython==9.10.1 matplotlib==3.8.0 numpy==1.26.1 pandas==2.2.2 +pillow==11.1.0 pytest==8.4.2 pytest-cov==7.0.0 diff --git a/solutions/sem01/lesson02/task1.py b/solutions/sem01/lesson02/task1.py index c782dcd8..540d982e 100644 --- a/solutions/sem01/lesson02/task1.py +++ b/solutions/sem01/lesson02/task1.py @@ -1,4 +1,5 @@ -def get_factorial(num: int) -> int: +'''def get_factorial(num: int) -> int: factorial = 1 # ваш код return factorial +''' \ No newline at end of file diff --git a/solutions/sem01/lesson02/task2.py b/solutions/sem01/lesson02/task2.py index b91420c5..ddbe6c33 100644 --- a/solutions/sem01/lesson02/task2.py +++ b/solutions/sem01/lesson02/task2.py @@ -1,4 +1,5 @@ -def get_doubled_factorial(num: int) -> int: +'''def get_doubled_factorial(num: int) -> int: factorial = 1 # ваш код return factorial +''' \ No newline at end of file diff --git a/solutions/sem01/lesson02/task3.py b/solutions/sem01/lesson02/task3.py index ee2a84ec..1bc933fc 100644 --- a/solutions/sem01/lesson02/task3.py +++ b/solutions/sem01/lesson02/task3.py @@ -1,4 +1,5 @@ -def get_amount_of_ways_to_climb(stair_amount: int) -> int: +'''def get_amount_of_ways_to_climb(stair_amount: int) -> int: step_prev, step_curr = 1, 1 # ваш код return step_curr +''' \ No newline at end of file diff --git a/solutions/sem01/lesson02/task4.py b/solutions/sem01/lesson02/task4.py index 45ff4bb4..328220b8 100644 --- a/solutions/sem01/lesson02/task4.py +++ b/solutions/sem01/lesson02/task4.py @@ -1,4 +1,5 @@ -def get_multiplications_amount(num: int) -> int: +'''def get_multiplications_amount(num: int) -> int: multiplications_amount = 0 # ваш код return multiplications_amount +''' \ No newline at end of file diff --git a/solutions/sem01/lesson02/task5.py b/solutions/sem01/lesson02/task5.py index 8fb9a048..18aabcc5 100644 --- a/solutions/sem01/lesson02/task5.py +++ b/solutions/sem01/lesson02/task5.py @@ -1,3 +1,4 @@ -def get_gcd(num1: int, num2: int) -> int: +'''def get_gcd(num1: int, num2: int) -> int: # ваш код return num1 +''' \ No newline at end of file diff --git a/solutions/sem01/lesson02/task6.py b/solutions/sem01/lesson02/task6.py index bec4b6cd..d542eb90 100644 --- a/solutions/sem01/lesson02/task6.py +++ b/solutions/sem01/lesson02/task6.py @@ -1,4 +1,5 @@ -def get_sum_of_prime_divisors(num: int) -> int: +'''def get_sum_of_prime_divisors(num: int) -> int: sum_of_divisors = 0 # ваш код return sum_of_divisors +''' \ No newline at end of file diff --git a/solutions/sem01/lesson02/task7.py b/solutions/sem01/lesson02/task7.py index 4b2d73be..0459fcf9 100644 --- a/solutions/sem01/lesson02/task7.py +++ b/solutions/sem01/lesson02/task7.py @@ -1,5 +1,6 @@ -def is_palindrome(num: int) -> bool: +'''def is_palindrome(num: int) -> bool: num_reversed = 0 num_origin = num # ваш код return num_origin == num_reversed +''' \ No newline at end of file diff --git a/solutions/sem01/lesson03/task1.py b/solutions/sem01/lesson03/task1.py index f1d8fe26..825d8f1b 100644 --- a/solutions/sem01/lesson03/task1.py +++ b/solutions/sem01/lesson03/task1.py @@ -1,3 +1,4 @@ -def flip_bits_in_range(num: int, left_bit: int, right_bit: int) -> int: +'''def flip_bits_in_range(num: int, left_bit: int, right_bit: int) -> int: # ваш код - return num \ No newline at end of file + return num +''' \ No newline at end of file diff --git a/solutions/sem01/lesson03/task2.py b/solutions/sem01/lesson03/task2.py index a3a738c2..c276a1f8 100644 --- a/solutions/sem01/lesson03/task2.py +++ b/solutions/sem01/lesson03/task2.py @@ -1,3 +1,4 @@ -def get_cube_root(n: float, eps: float) -> float: +'''def get_cube_root(n: float, eps: float) -> float: # ваш код - return n \ No newline at end of file + return n +''' \ No newline at end of file diff --git a/solutions/sem01/lesson03/task3.py b/solutions/sem01/lesson03/task3.py index 5e91a6ac..ea278d0f 100644 --- a/solutions/sem01/lesson03/task3.py +++ b/solutions/sem01/lesson03/task3.py @@ -1,3 +1,4 @@ -def get_nth_digit(num: int) -> int: +'''def get_nth_digit(num: int) -> int: # ваш код return 0 +''' \ No newline at end of file diff --git a/solutions/sem01/lesson04/task1.py b/solutions/sem01/lesson04/task1.py index 47384423..ad75edcc 100644 --- a/solutions/sem01/lesson04/task1.py +++ b/solutions/sem01/lesson04/task1.py @@ -1,3 +1,4 @@ -def is_arithmetic_progression(lst: list[list[int]]) -> bool: +'''def is_arithmetic_progression(lst: list[list[int]]) -> bool: # ваш код - return False \ No newline at end of file + return False +''' \ No newline at end of file diff --git a/solutions/sem01/lesson04/task2.py b/solutions/sem01/lesson04/task2.py index 4591d0a3..bd94b4ef 100644 --- a/solutions/sem01/lesson04/task2.py +++ b/solutions/sem01/lesson04/task2.py @@ -1,3 +1,4 @@ -def merge_intervals(intervals: list[list[int, int]]) -> list[list[int, int]]: +'''def merge_intervals(intervals: list[list[int, int]]) -> list[list[int, int]]: # ваш код - return [[0,0]] \ No newline at end of file + return [[0,0]] +''' \ No newline at end of file diff --git a/solutions/sem01/lesson04/task3.py b/solutions/sem01/lesson04/task3.py index 7253f6cb..472a15a8 100644 --- a/solutions/sem01/lesson04/task3.py +++ b/solutions/sem01/lesson04/task3.py @@ -1,3 +1,4 @@ -def find_single_number(nums: list[int]) -> int: +'''def find_single_number(nums: list[int]) -> int: # ваш код return 0 +''' \ No newline at end of file diff --git a/solutions/sem01/lesson04/task4.py b/solutions/sem01/lesson04/task4.py index b21bc5a3..85b93ef3 100644 --- a/solutions/sem01/lesson04/task4.py +++ b/solutions/sem01/lesson04/task4.py @@ -1,3 +1,4 @@ -def move_zeros_to_end(nums: list[int]) -> list[int]: +'''def move_zeros_to_end(nums: list[int]) -> list[int]: # ваш код - return 0 \ No newline at end of file + return 0 +''' \ No newline at end of file diff --git a/solutions/sem01/lesson04/task5.py b/solutions/sem01/lesson04/task5.py index 02d7742b..64daaa9f 100644 --- a/solutions/sem01/lesson04/task5.py +++ b/solutions/sem01/lesson04/task5.py @@ -1,3 +1,4 @@ -def find_row_with_most_ones(matrix: list[list[int]]) -> int: +'''def find_row_with_most_ones(matrix: list[list[int]]) -> int: # ваш код - return 0 \ No newline at end of file + return 0 +''' \ No newline at end of file diff --git a/solutions/sem01/lesson04/task6.py b/solutions/sem01/lesson04/task6.py index 16df27ca..d93015f6 100644 --- a/solutions/sem01/lesson04/task6.py +++ b/solutions/sem01/lesson04/task6.py @@ -1,3 +1,4 @@ -def count_cycles(arr: list[int]) -> int: +'''def count_cycles(arr: list[int]) -> int: # ваш код - return 0 \ No newline at end of file + return 0 +''' \ No newline at end of file diff --git a/solutions/sem01/lesson05/task1.py b/solutions/sem01/lesson05/task1.py index 9a17211e..eb93169e 100644 --- a/solutions/sem01/lesson05/task1.py +++ b/solutions/sem01/lesson05/task1.py @@ -1,3 +1,4 @@ -def is_palindrome(text: str) -> bool: +'''def is_palindrome(text: str) -> bool: # ваш код - return False \ No newline at end of file + return False +''' \ No newline at end of file diff --git a/solutions/sem01/lesson05/task2.py b/solutions/sem01/lesson05/task2.py index 36750380..2de270c6 100644 --- a/solutions/sem01/lesson05/task2.py +++ b/solutions/sem01/lesson05/task2.py @@ -1,3 +1,4 @@ -def are_anagrams(word1: str, word2: str) -> bool: +'''def are_anagrams(word1: str, word2: str) -> bool: # ваш код - return False \ No newline at end of file + return False +''' \ No newline at end of file diff --git a/solutions/sem01/lesson05/task3.py b/solutions/sem01/lesson05/task3.py index e368e2f4..6303885b 100644 --- a/solutions/sem01/lesson05/task3.py +++ b/solutions/sem01/lesson05/task3.py @@ -1,3 +1,4 @@ -def is_punctuation(text: str) -> bool: +'''def is_punctuation(text: str) -> bool: # ваш код return False +''' \ No newline at end of file diff --git a/solutions/sem01/lesson05/task4.py b/solutions/sem01/lesson05/task4.py index 4c4e9086..1678e931 100644 --- a/solutions/sem01/lesson05/task4.py +++ b/solutions/sem01/lesson05/task4.py @@ -1,3 +1,4 @@ -def unzip(compress_text: str) -> str: +'''def unzip(compress_text: str) -> str: # ваш код - return compress_text \ No newline at end of file + return compress_text +''' \ No newline at end of file diff --git a/solutions/sem01/lesson05/task5.py b/solutions/sem01/lesson05/task5.py index 076c5bb6..e345d555 100644 --- a/solutions/sem01/lesson05/task5.py +++ b/solutions/sem01/lesson05/task5.py @@ -1,3 +1,4 @@ -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 +''' \ No newline at end of file diff --git a/solutions/sem01/lesson05/task6.py b/solutions/sem01/lesson05/task6.py index 1b914ada..0461c047 100644 --- a/solutions/sem01/lesson05/task6.py +++ b/solutions/sem01/lesson05/task6.py @@ -1,3 +1,4 @@ -def simplify_path(path: str) -> str: +'''def simplify_path(path: str) -> str: # ваш код - return path \ No newline at end of file + return path +''' \ No newline at end of file diff --git a/solutions/sem01/lesson06/task1.py b/solutions/sem01/lesson06/task1.py index 2d1e30e9..f5a328a8 100644 --- a/solutions/sem01/lesson06/task1.py +++ b/solutions/sem01/lesson06/task1.py @@ -1,3 +1,4 @@ -def int_to_roman(num: int) -> str: +'''def int_to_roman(num: int) -> str: # ваш код - return "" \ No newline at end of file + return "" +''' \ No newline at end of file diff --git a/solutions/sem01/lesson06/task2.py b/solutions/sem01/lesson06/task2.py index f535b5a0..e6162ae2 100644 --- a/solutions/sem01/lesson06/task2.py +++ b/solutions/sem01/lesson06/task2.py @@ -1,3 +1,4 @@ -def get_len_of_longest_substring(text: str) -> int: +'''def get_len_of_longest_substring(text: str) -> int: # ваш код - return 0 \ No newline at end of file + return 0 +''' \ No newline at end of file diff --git a/solutions/sem01/lesson06/task3.py b/solutions/sem01/lesson06/task3.py index 7449a1e7..ffe634d3 100644 --- a/solutions/sem01/lesson06/task3.py +++ b/solutions/sem01/lesson06/task3.py @@ -1,7 +1,8 @@ -def is_there_any_good_subarray( +'''def is_there_any_good_subarray( nums: list[int], k: int, ) -> bool: # ваш код return False +''' \ No newline at end of file diff --git a/solutions/sem01/lesson06/task4.py b/solutions/sem01/lesson06/task4.py index 5b75a110..11915f4f 100644 --- a/solutions/sem01/lesson06/task4.py +++ b/solutions/sem01/lesson06/task4.py @@ -1,3 +1,4 @@ -def count_unique_words(text: str) -> int: +'''def count_unique_words(text: str) -> int: # ваш код - return 0 \ No newline at end of file + return 0 +''' \ No newline at end of file diff --git a/solutions/sem01/lesson08/task1.py b/solutions/sem01/lesson08/task1.py index 4390f6c8..e2153a2c 100644 --- a/solutions/sem01/lesson08/task1.py +++ b/solutions/sem01/lesson08/task1.py @@ -1,5 +1,6 @@ -from typing import Callable +'''from typing import Callable def make_averager(accumulation_period: int) -> Callable[[float], float]: # ваш код - pass \ No newline at end of file + pass +''' \ No newline at end of file diff --git a/solutions/sem01/lesson08/task2.py b/solutions/sem01/lesson08/task2.py index 6e4af870..53adb731 100644 --- a/solutions/sem01/lesson08/task2.py +++ b/solutions/sem01/lesson08/task2.py @@ -1,4 +1,4 @@ -from typing import Callable, TypeVar +'''from typing import Callable, TypeVar T = TypeVar("T") @@ -7,4 +7,5 @@ def collect_statistic( ) -> Callable[[T], T]: # ваш код - pass \ No newline at end of file + pass +''' \ No newline at end of file diff --git a/solutions/sem01/lesson11/task1.py b/solutions/sem01/lesson11/task1.py index 6a15f31f..39e8bae6 100644 --- a/solutions/sem01/lesson11/task1.py +++ b/solutions/sem01/lesson11/task1.py @@ -1,4 +1,4 @@ -class Vector2D: +'''class Vector2D: def conj(self) -> "Vector2D": # ваш код return Vector2D() @@ -8,3 +8,4 @@ def get_angle(self, other: "Vector2D") -> float: return 0 # ваш код +''' \ No newline at end of file diff --git a/solutions/sem01/lesson12/task1.py b/solutions/sem01/lesson12/task1.py index d1bb828c..498176fc 100644 --- a/solutions/sem01/lesson12/task1.py +++ b/solutions/sem01/lesson12/task1.py @@ -1,6 +1,7 @@ -from typing import Any, Generator, Iterable +'''from typing import Any, Generator, Iterable def chunked(iterable: Iterable, size: int) -> Generator[tuple[Any], None, None]: # ваш код ... +''' \ No newline at end of file diff --git a/solutions/sem01/lesson12/task2.py b/solutions/sem01/lesson12/task2.py index 3ad802ee..058e23b5 100644 --- a/solutions/sem01/lesson12/task2.py +++ b/solutions/sem01/lesson12/task2.py @@ -1,6 +1,7 @@ -from typing import Any, Generator, Iterable +'''from typing import Any, Generator, Iterable def circle(iterable: Iterable) -> Generator[Any, None, None]: # ваш код ... +''' \ No newline at end of file diff --git a/solutions/sem01/lesson12/task3.py b/solutions/sem01/lesson12/task3.py index 64c112cc..fb9ec3fa 100644 --- a/solutions/sem01/lesson12/task3.py +++ b/solutions/sem01/lesson12/task3.py @@ -1,4 +1,4 @@ -import sys +'''#import sys class FileOut: @@ -10,3 +10,4 @@ def __init__( ... # ваш код +''' \ No newline at end of file diff --git a/solutions/sem02/lesson03/task1.py b/solutions/sem02/lesson03/task1.py index 2c3fc0b5..fb8063af 100644 --- a/solutions/sem02/lesson03/task1.py +++ b/solutions/sem02/lesson03/task1.py @@ -8,13 +8,23 @@ class ShapeMismatchError(Exception): def sum_arrays_vectorized( lhs: np.ndarray, rhs: np.ndarray, -) -> np.ndarray: ... +) -> np.ndarray: + if lhs.shape != rhs.shape: + raise ShapeMismatchError + return 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: ... +) -> np.ndarray: + if lhs.shape[1] != rhs.shape[1]: + raise ShapeMismatchError + differences = lhs[:, np.newaxis] - rhs + distances = np.sqrt(np.sum(differences**2, axis=2)) + + return distances diff --git a/solutions/sem02/lesson03/task2.py b/solutions/sem02/lesson03/task2.py index fc823c1d..0e7a99e7 100644 --- a/solutions/sem02/lesson03/task2.py +++ b/solutions/sem02/lesson03/task2.py @@ -9,11 +9,31 @@ 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 + + abscissa = distances * np.sin(inclination) * np.cos(azimuth) + ordinates = distances * np.sin(inclination) * np.sin(azimuth) + applicates = distances * np.cos(inclination) + + return (abscissa, ordinates, applicates) 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 + + distances = np.sqrt(abscissa**2 + ordinates**2 + applicates**2) + inclination = np.arctan2(np.sqrt(abscissa**2 + ordinates**2), applicates) + azimuth = np.arctan2(ordinates, abscissa) + + zero_mask = distances == 0 + azimuth[zero_mask] = 0 + inclination[zero_mask] = 0 + + return (distances, azimuth, inclination) diff --git a/solutions/sem02/lesson03/task3.py b/solutions/sem02/lesson03/task3.py index 477acd0c..9d3bb7b1 100644 --- a/solutions/sem02/lesson03/task3.py +++ b/solutions/sem02/lesson03/task3.py @@ -3,4 +3,16 @@ def get_extremum_indices( ordinates: np.ndarray, -) -> tuple[np.ndarray, np.ndarray]: ... +) -> tuple[np.ndarray, np.ndarray]: + if ordinates.shape[0] < 3: + raise ValueError + + indices = np.arange(1, ordinates.shape[0] - 1) + prev = ordinates[indices - 1] + curr = ordinates[indices] + next = ordinates[indices + 1] + + min_mask = (curr < prev) & (curr < next) + max_mask = (curr > prev) & (curr > next) + + return (indices[min_mask], indices[max_mask]) diff --git a/solutions/sem02/lesson04/task1.py b/solutions/sem02/lesson04/task1.py index 1b5526c1..615b11be 100644 --- a/solutions/sem02/lesson04/task1.py +++ b/solutions/sem02/lesson04/task1.py @@ -2,16 +2,49 @@ def pad_image(image: np.ndarray, pad_size: int) -> np.ndarray: - # ваш код - return image + if pad_size < 1: + raise ValueError + + if image.ndim == 2: + height, width = image.shape + + padded_image = np.zeros((height + 2 * pad_size, width + 2 * pad_size), dtype=np.uint8) + padded_image[pad_size:-pad_size, pad_size:-pad_size] = image + else: + height, width, depth = image.shape + + padded_image = np.zeros( + (height + 2 * pad_size, width + 2 * pad_size, depth), dtype=np.uint8 + ) + padded_image[pad_size : pad_size + height, pad_size : pad_size + width, :] = image + + return padded_image def blur_image( image: np.ndarray, kernel_size: int, ) -> np.ndarray: - # ваш код - return image + if kernel_size < 1 or kernel_size % 2 == 0: + raise ValueError + + if kernel_size == 1: + return image + + pad_size = kernel_size // 2 + image = pad_image(image, pad_size) / kernel_size**2 + + np.cumsum(image, axis=0, out=image) + vert = np.zeros(image.shape) + vert[kernel_size:, :] = image[:-kernel_size, :] + image -= vert + + np.cumsum(image, axis=1, out=image) + horiz = np.zeros(image.shape) + horiz[:, kernel_size:] = image[:, :-kernel_size] + image -= horiz + + return np.array(image[pad_size * 2 : :, pad_size * 2 : :], dtype=np.uint8) if __name__ == "__main__": diff --git a/solutions/sem02/lesson04/task2.py b/solutions/sem02/lesson04/task2.py index be9a2288..ee79ddff 100644 --- a/solutions/sem02/lesson04/task2.py +++ b/solutions/sem02/lesson04/task2.py @@ -5,6 +5,23 @@ 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 + unique_colors, unique_colors_cnt = np.unique(image, return_counts=True) + array_count_colors = np.zeros(256) + array_count_colors[unique_colors] = unique_colors_cnt + + dominant_color = -1 + dominant_group_size = 0 + + for color in unique_colors: + left_limit = max(0, int(color) - threshold + 1) + right_limit = min(256, int(color) + threshold - 1) + + curr_group_size = np.sum(array_count_colors[left_limit : right_limit + 1]) + if curr_group_size > dominant_group_size: + dominant_group_size = curr_group_size + dominant_color = color + + return dominant_color, float(dominant_group_size / image.size * 100) diff --git a/solutions/sem02/lesson05/task1.py b/solutions/sem02/lesson05/task1.py index e9c7c3c5..8c91a02f 100644 --- a/solutions/sem02/lesson05/task1.py +++ b/solutions/sem02/lesson05/task1.py @@ -9,4 +9,9 @@ def can_satisfy_demand( costs: np.ndarray, resource_amounts: np.ndarray, demand_expected: np.ndarray, -) -> bool: ... +) -> bool: + if costs.shape[0] != resource_amounts.size or costs.shape[1] != demand_expected.size: + raise ShapeMismatchError + + costs_all_products = costs * demand_expected[np.newaxis, ...] + return np.all(np.sum(costs_all_products, axis=1) <= resource_amounts) diff --git a/solutions/sem02/lesson05/task2.py b/solutions/sem02/lesson05/task2.py index be1fb9d2..77253a6a 100644 --- a/solutions/sem02/lesson05/task2.py +++ b/solutions/sem02/lesson05/task2.py @@ -8,4 +8,18 @@ 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] or vector.size != matrix.shape[1]: + raise ShapeMismatchError + + if np.linalg.det(matrix) == 0: + return (None, None) + + scalar_matr_vect = np.sum(matrix * vector, axis=1) + matr_squared = np.sum(matrix * matrix, axis=1) + + coef = (scalar_matr_vect / matr_squared).reshape(-1, 1) + ort_projections = coef * matrix + + ort_components = vector - ort_projections + return (ort_projections, ort_components) diff --git a/solutions/sem02/lesson05/task3.py b/solutions/sem02/lesson05/task3.py index 0c66906c..ffdf5f50 100644 --- a/solutions/sem02/lesson05/task3.py +++ b/solutions/sem02/lesson05/task3.py @@ -9,4 +9,17 @@ def adaptive_filter( Vs: np.ndarray, Vj: np.ndarray, diag_A: np.ndarray, -) -> np.ndarray: ... +) -> np.ndarray: + if np.ndim(Vs) != 2 or np.ndim(Vj) != 2 or np.ndim(diag_A) != 1: + raise ShapeMismatchError + + if Vs.shape[0] != Vj.shape[0] or Vj.shape[1] != diag_A.size: + raise ShapeMismatchError + + A = np.diag(diag_A) + E = np.eye(diag_A.size) + VjH = np.conj(Vj).T + R_1 = np.linalg.inv(E + VjH @ Vj @ A) + result = Vs - Vj @ R_1 @ (VjH @ Vs) + + return result diff --git a/solutions/sem02/lesson07/task1.py b/solutions/sem02/lesson07/task1.py index 3a505d89..7c2b4826 100644 --- a/solutions/sem02/lesson07/task1.py +++ b/solutions/sem02/lesson07/task1.py @@ -8,13 +8,104 @@ class ShapeMismatchError(Exception): pass -def visualize_diagrams( - abscissa: np.ndarray, - ordinates: np.ndarray, - diagram_type: Any, -) -> None: - # ваш код - pass +class DiagramVisualizer: + def __init__(self, abscissa: np.ndarray, ordinates: np.ndarray, space: float = 0.2) -> None: + self._abscissa = abscissa + self._ordinates = ordinates + self._space = space + self._validate() + + def _validate(self) -> None: + if self._abscissa.shape != self._ordinates.shape: + raise ShapeMismatchError + + def _setup_figure_grid_axes(self): + figure = plt.figure(figsize=(8, 8)) + grid = plt.GridSpec(4, 4, wspace=self._space, hspace=self._space) + + axis_scatter = figure.add_subplot(grid[:-1, 1:]) + axis_horis = figure.add_subplot(grid[-1, 1:], sharex=axis_scatter) + axis_vert = figure.add_subplot(grid[:-1, 0], sharey=axis_scatter) + + axis_horis.set_xlabel("Horizontal", fontsize=14, c="dimgray") + axis_vert.set_ylabel("Vertical", fontsize=14, c="dimgray") + + return axis_scatter, axis_horis, axis_vert + + def _setup_scatter(self, axis_scatter: plt.Axes) -> None: + axis_scatter.scatter(self._abscissa, self._ordinates, color="mediumseagreen", alpha=0.3) + axis_scatter.set_title("Distribution", fontsize=17, fontweight="bold", c="dimgray") + + def visualize(self, diagram_type: Any) -> None: + if diagram_type not in ["hist", "violin", "box"]: + raise ValueError + + axis_scatter, axis_horis, axis_vert = self._setup_figure_grid_axes() + self._setup_scatter(axis_scatter) + + if diagram_type == "hist": + histogram_plot(self._abscissa, axis_horis, is_horis=True) + histogram_plot(self._ordinates, axis_vert, is_horis=False) + elif diagram_type == "violin": + violin_plot(self._abscissa, axis_horis, is_horis=True) + violin_plot(self._ordinates, axis_vert, is_horis=False) + else: + box_plot(self._abscissa, axis_horis, is_horis=True) + box_plot(self._ordinates, axis_vert, is_horis=False) + + +def histogram_plot(data: np.ndarray, axis: plt.Axes, is_horis: bool) -> None: + axis.hist( + data, + bins=50, + color="mediumseagreen", + orientation="vertical" if is_horis else "horizontal", + density=True, + alpha=0.4, + ) + + if is_horis: + axis.invert_yaxis() + else: + axis.invert_xaxis() + + +def violin_plot(data: np.ndarray, axis: plt.Axes, is_horis: bool) -> None: + violin_parts = axis.violinplot(data, vert=False if is_horis else True, showmedians=True) + + for body in violin_parts["bodies"]: + body.set_facecolor("mediumseagreen") + body.set_edgecolor("green") + + for part in violin_parts: + if part == "bodies": + continue + violin_parts[part].set_edgecolor("mediumseagreen") + + if is_horis: + axis.set_yticks([]) + else: + axis.set_xticks([]) + + +def box_plot(data: np.ndarray, axis: plt.Axes, is_horis: bool) -> None: + axis.boxplot( + data, + vert=False if is_horis else True, + patch_artist=True, + boxprops=dict(facecolor="mediumseagreen", alpha=0.6), + medianprops=dict(color="k"), + ) + + if is_horis: + axis.set_yticks([]) + else: + axis.set_xticks([]) + + +def visualize_diagrams(abscissa: np.ndarray, ordinates: np.ndarray, diagram_type: Any) -> None: + visualizer = DiagramVisualizer(abscissa, ordinates, space) + visualizer.visualize(diagram_type) if __name__ == "__main__": diff --git a/solutions/sem02/lesson07/task2.py b/solutions/sem02/lesson07/task2.py index decd607e..abee2dff 100644 --- a/solutions/sem02/lesson07/task2.py +++ b/solutions/sem02/lesson07/task2.py @@ -1 +1,67 @@ -# ваш код (используйте функции или классы для решения данной задачи) +import json + +import matplotlib.pyplot as plt +import numpy as np + + +def read_from_file(filename: str) -> tuple[list[str], list[str]]: + with open(filename, "r") as file: + data = json.load(file) + + return data["before"], data["after"] + + +def get_counts_in_groups(before: list[str], after: list[str]) -> tuple[np.ndarray, np.ndarray]: + count_before = np.unique(np.array(before), return_counts=True)[1] + count_after = np.unique(after, return_counts=True)[1] + + return count_before, count_after + + +def set_labels_and_ticks(axis: plt.Axes) -> None: + axis.set_title("Mitral disease stages", fontsize=17, fontweight="bold", c="dimgray") + axis.set_xlabel("Group", fontsize=14, fontweight="bold", c="dimgray") + axis.set_ylabel("Amount of people", fontsize=14, fontweight="bold", c="dimgray") + + labels = np.array(["I", "II", "III", "IV"]) + axis.set_xticks(np.arange(labels.size), labels=labels, fontweight="bold") + axis.tick_params(axis="x", labelsize=14, labelcolor="dimgray") + + +def show_plots_and_legend( + axis: plt.Axes, count_before: np.ndarray, count_after: np.ndarray +) -> None: + shift = 0.2 + + bar_before = axis.bar( + np.arange(count_before.size) - shift, + count_before, + width=0.4, + color="moccasin", + edgecolor="orange", + ) + bar_after = axis.bar( + np.arange(count_after.size) + shift, + count_after, + width=0.4, + color="orange", + edgecolor="chocolate", + ) + axis.legend((bar_before, bar_after), ["before", "after"]) + + +def visualize(count_before: np.ndarray, count_after: np.ndarray) -> None: + figure, axis = plt.subplots(figsize=(9, 9)) + axis: plt.Axes + + set_labels_and_ticks(axis) + show_plots_and_legend(axis, count_before, count_after) + plt.show() + + figure.savefig("Mitral disease stages.png", bbox_inches="tight") + + +if __name__ == "__main__": + data = read_from_file("data/medic_data.json") + counts = get_counts_in_groups(*data) + visualize(*counts) diff --git a/solutions/sem02/lesson08/task1.py b/solutions/sem02/lesson08/task1.py index 89f88572..a91a911e 100644 --- a/solutions/sem02/lesson08/task1.py +++ b/solutions/sem02/lesson08/task1.py @@ -1,34 +1,79 @@ from functools import partial +from typing import Callable, Optional import matplotlib.pyplot as plt import numpy as np - from IPython.display import HTML from matplotlib.animation import FuncAnimation +plt.style.use("seaborn-v0_8") + + +def modulated_signal(t: np.ndarray, modulation: Optional[Callable], fc: float) -> np.ndarray: + M = modulation if modulation is not None else lambda t: 1 + return M(t) * np.sin(2 * np.pi * fc * t) + + +def update_frame(frame_id: int, axis: plt.Axes, t_base: np.ndarray, step: float, signal: Callable): + t_current = t_base + step * frame_id + + line = axis.get_lines()[0] + line.set_xdata(t_current) + line.set_ydata(signal(t_current)) + + axis.set_xlim(t_current.min(), t_current.max()) + return axis.get_lines() + + +def setup_figure(plot_duration: float, time_step: float, signal: Callable): + figure, axis = plt.subplots(figsize=(9, 6)) + t = np.linspace(0, plot_duration, int(plot_duration / time_step)) + axis.plot(t, signal(t), c="royalblue", label="Сигнал") + axis.set_title("Анимация модулированного сигнала", fontsize=17, pad=20) + axis.set_xlabel("Время (с)", fontsize=13, labelpad=7) + axis.set_ylabel("Амплитуда", fontsize=13, labelpad=7) + axis.set_ylim(-2, 2) + plt.legend() + return figure, axis, t + def create_modulation_animation( - modulation, - fc, - num_frames, - plot_duration, - time_step=0.001, - animation_step=0.01, - save_path="" + modulation: Optional[Callable], + fc: float, + num_frames: int, + plot_duration: float, + time_step: float = 0.001, + animation_step: float = 0.01, + save_path: str = "", ) -> FuncAnimation: - # ваш код - return FuncAnimation() + signal = partial(modulated_signal, modulation=modulation, fc=fc) + + figure, axis, t_base = setup_figure(plot_duration, time_step, signal) + + animation = FuncAnimation( + figure, + lambda frame: update_frame(frame, axis, t_base, animation_step, signal), + frames=num_frames, + interval=1000 * animation_step, + blit=True, + ) + + if save_path: + animation.save(save_path, writer="pillow", fps=30) + + 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 +83,6 @@ 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()) diff --git a/solutions/sem02/lesson08/task2.py b/solutions/sem02/lesson08/task2.py index b677c070..dbfad741 100644 --- a/solutions/sem02/lesson08/task2.py +++ b/solutions/sem02/lesson08/task2.py @@ -1,34 +1,128 @@ -from functools import partial +from typing import Tuple import matplotlib.pyplot as plt import numpy as np - from IPython.display import HTML from matplotlib.animation import FuncAnimation +def is_cell_not_in_walk_place(visited_cells: np.ndarray, x: int, y: int) -> bool: + return ( + not (0 <= x < visited_cells.shape[0] and 0 <= y < visited_cells.shape[1]) + or visited_cells[x, y] != -1 + ) + + +def mark_cells(visited_cells: np.ndarray, start_x: int, start_y: int) -> None: + if is_cell_not_in_walk_place(visited_cells, start_x, start_y): + print("Начальная точка находится за пределами дорожки, по которой можно ходить") + return + + step = 0 + cells = [(start_x, start_y, step)] + curr = 0 + + while curr < len(cells): + curr_x, curr_y, step = cells[curr] + curr += 1 + + if is_cell_not_in_walk_place(visited_cells, curr_x, curr_y): + continue + + visited_cells[curr_x, curr_y] = step + + cells.append((curr_x + 1, curr_y, step + 1)) + cells.append((curr_x - 1, curr_y, step + 1)) + cells.append((curr_x, curr_y + 1, step + 1)) + cells.append((curr_x, curr_y - 1, step + 1)) + + +def image_maze(axis: plt.Axes, maze: np.ndarray) -> None: + x_size, y_size = maze.shape[1], maze.shape[0] + axis.set_title("Волновой алгоритм", fontsize=17, fontweight="bold") + + axis.set_xticks(np.arange(0, x_size, max(1, x_size // 10))) + axis.set_yticks(np.arange(0, y_size, max(1, y_size // 10))) + + axis.set_xticks(np.arange(-0.5, x_size, 1), minor=True) + axis.set_yticks(np.arange(-0.5, y_size, 1), minor=True) + + axis.tick_params(axis="both", which="major", labelsize=12, width=3) + + axis.grid(True, which="minor", linewidth=2, color="black") + axis.grid(False, which="major") + + axis.set_xlim(-0.5, x_size - 0.5) + axis.set_ylim(y_size - 0.5, -0.5) + + way_mask = maze != 0 + way = np.zeros((maze.shape[0], maze.shape[1], 4)) + way[way_mask] = [0, 0, 0, 1] # черный цвет + + image_edge = [-0.5, x_size - 0.5, y_size - 0.5, -0.5] + axis.imshow(way, extent=image_edge, origin="upper") 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: + visited_cells = -1 * maze.astype(np.int32) + + mark_cells(visited_cells, *start) + + if visited_cells[end] == -1: + print("Пути до выхода не существует") + + figure, axis = plt.subplots(figsize=(10, 10)) + + marker_size = 350 / max(*maze.shape) + x_points = np.array([]) + y_points = np.array([]) + wave, *_ = axis.plot(x_points, y_points, "o", ms=marker_size) + end_point, *_ = axis.plot([], [], "o", ms=marker_size, c="orange") + + image_maze(axis, maze) + + def update(frame_id: int): + nonlocal x_points, y_points + if frame_id == 0: + x_points = np.append(x_points, start[1]) + y_points = np.append(y_points, start[0]) + else: + mask_cells = visited_cells == frame_id + cells = np.nonzero(mask_cells) + + x_points = np.append(x_points, cells[1]) + y_points = np.append(y_points, cells[0]) + + if frame_id == visited_cells[*end]: + end_point.set_data([end[1]], [end[0]]) + else: + end_point.set_data([], []) + + wave.set_data(x_points, y_points) + return wave, end_point + + animation = FuncAnimation(figure, update, frames=np.max(visited_cells) + 1, interval=200) + + if save_path: + animation.save(save_path, writer="pillow", fps=3) + 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 +130,16 @@ def animate_wave_algorithm( animation = animate_wave_algorithm(maze, start, end, save_path) HTML(animation.to_jshtml()) - + # Пример 2 - - maze_path = "./data/maze.npy" + + maze_path = "solutions\sem02\lesson08\data\maze.npy" loaded_maze = np.load(maze_path) # можете поменять, если захотите запустить из других точек - start = (2, 0) - end = (5, 0) + start = (3, 6) + end = (98, 33) 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