diff --git a/solutions/sem02/lesson04/task1.py b/solutions/sem02/lesson04/task1.py index 1b5526c1f..2e754fc80 100644 --- a/solutions/sem02/lesson04/task1.py +++ b/solutions/sem02/lesson04/task1.py @@ -2,16 +2,85 @@ def pad_image(image: np.ndarray, pad_size: int) -> np.ndarray: - # ваш код - return image + if pad_size < 1: + raise ValueError + + shape = image.shape + shape = list(shape) + + if len(shape) == 2: + for i in range(len(shape)): + shape[i] += 2 * pad_size + else: + shape[0] += 2 * pad_size + shape[1] += 2 * pad_size + + border_array = np.ones(shape, dtype=image.dtype) + + if len(shape) == 2: + border_array[:pad_size, :] = 0 + border_array[-pad_size:, :] = 0 + border_array[:, :pad_size] = 0 + border_array[:, -pad_size:] = 0 + else: + border_array[:pad_size, :, :] = 0 + border_array[-pad_size:, :, :] = 0 + border_array[:, :pad_size, :] = 0 + border_array[:, -pad_size:, :] = 0 + + idx = border_array != 0 + border_array[idx] = image.reshape(-1) + + return border_array def blur_image( image: np.ndarray, kernel_size: int, ) -> np.ndarray: - # ваш код - return image + if kernel_size < 1 or kernel_size % 2 == 0: + raise ValueError + + border = kernel_size // 2 + if border == 0: + return image.astype(np.uint8) + + if image.ndim == 3: + first, second, third = image.shape + out = np.zeros((first, second, third), dtype=np.uint8) + for i in range(third): + out[:, :, i] = blur_image(image[:, :, i], kernel_size) + return out + + first, second = image.shape + image_new = pad_image(image, border) + new_first, new_second = image_new.shape + + flat = image_new.flatten() + + centers = [] + for i in range(border, border + first): + for j in range(border, border + second): + centers.append(i * new_second + j) + centers = np.array(centers) + + remotes = [] + for i in range(-border, border + 1): + for j in range(-border, border + 1): + remotes.append(i * new_second + j) + remotes = np.array(remotes) + + n_idx = centers[:, None] + remotes[None, :] + n_vals = flat[n_idx] + means = n_vals.mean(axis=1) + + blur_flat = flat.astype(float) + blur_flat[centers] = means + + blur_new = blur_flat.reshape(new_first, new_second) + final_image = blur_new[border : border + first, border : border + second] + + return np.round(final_image).astype(np.uint8) if __name__ == "__main__": diff --git a/solutions/sem02/lesson04/task2.py b/solutions/sem02/lesson04/task2.py index be9a2288f..254169d48 100644 --- a/solutions/sem02/lesson04/task2.py +++ b/solutions/sem02/lesson04/task2.py @@ -2,9 +2,39 @@ def get_dominant_color_info( - image: np.ndarray[np.uint8], + image: np.ndarray, threshold: int = 5, ) -> tuple[np.uint8, float]: - # ваш код + if threshold < 1: + raise ValueError('threshold must be positive') - return 0, 0 + first, second = image.shape + total = first * second + if total == 0: + return (np.uint8(0), 0.0) + + num = [0] * 256 + for i in range(first): + for j in range(second): + num[image[i, j]] += 1 + + palette = [i for i in range(256) if num[i] > 0] + if not palette: + return (np.uint8(0), 0.0) + if len(palette) == 1: + return (np.uint8(palette[0]), 100.0) + + biggest_sum = -1 + most_frequent_col = 0 + for c in palette: + low = max(0, c - threshold + 1) + high = min(255, c + threshold - 1) + s = 0 + for k in range(low, high + 1): + s += num[k] + if s > biggest_sum: + biggest_sum = s + most_frequent_col = c + + percentage = (biggest_sum / total) * 100.0 + return (np.uint8(most_frequent_col), percentage) diff --git a/solutions/sem02/lesson05/task1.py b/solutions/sem02/lesson05/task1.py index e9c7c3c56..be0d2a113 100644 --- a/solutions/sem02/lesson05/task1.py +++ b/solutions/sem02/lesson05/task1.py @@ -9,4 +9,17 @@ def can_satisfy_demand( costs: np.ndarray, resource_amounts: np.ndarray, demand_expected: np.ndarray, -) -> bool: ... +) -> bool: + + first, second = costs.shape + if demand_expected.size != second or resource_amounts.size != first: + raise ShapeMismatchError + + costs_required = costs * demand_expected + resource_required = np.sum(costs_required, axis = 1) + result = resource_amounts - resource_required + + if np.all(result >= 0): + return True + + return False \ No newline at end of file diff --git a/solutions/sem02/lesson05/task2.py b/solutions/sem02/lesson05/task2.py index be1fb9d2b..058931b8a 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]: + first, second = matrix.shape + + if first != second or second != vector.size: + raise ShapeMismatchError + + if np.linalg.det(matrix) == 0: + return (None, None) + + vectors_from_matrix_sq_lens = np.sum(matrix**2, axis = 1) + col_temp = np.sum(matrix*vector, axis = 1) + col_temp = col_temp / vectors_from_matrix_sq_lens + elem_1 = col_temp[:, np.newaxis] * matrix + + return (elem_1, vector - elem_1) diff --git a/solutions/sem02/lesson05/task3.py b/solutions/sem02/lesson05/task3.py index 0c66906cb..57267262b 100644 --- a/solutions/sem02/lesson05/task3.py +++ b/solutions/sem02/lesson05/task3.py @@ -9,4 +9,20 @@ def adaptive_filter( Vs: np.ndarray, Vj: np.ndarray, diag_A: np.ndarray, -) -> np.ndarray: ... +) -> np.ndarray: + + if Vj.shape[1] != diag_A.size or Vs.shape[0] != Vj.shape[0]: + raise ShapeMismatchError + A = np.zeros((diag_A.size, diag_A.size), dtype=diag_A.dtype) + A[np.arange(diag_A.size), np.arange(diag_A.size)] = diag_A + Vj_H = np.transpose(Vj.conj()) + result_interm = Vj_H@Vj@A + M0 = result_interm.shape[0] + x1 = np.linalg.inv((np.eye(M0)+result_interm)) + x2 = Vj_H@Vs + x3 = Vj@x1 + result = Vs - x3@x2 + # Так как 2 последних теста постоянно падали, пришлось выражение ниже + # на отдельные кусочки поменьше разбить + # result = Vs - Vj@(np.linalg.inv((np.eye(M0)+result_interm)))@Vj_H@Vs + return result \ No newline at end of file diff --git a/solutions/sem02/lesson07/task1.py b/solutions/sem02/lesson07/task1.py index 3a505d89b..b79ee2ef2 100644 --- a/solutions/sem02/lesson07/task1.py +++ b/solutions/sem02/lesson07/task1.py @@ -13,7 +13,93 @@ def visualize_diagrams( ordinates: np.ndarray, diagram_type: Any, ) -> None: - # ваш код + if abscissa.shape != ordinates.shape: + raise ShapeMismatchError + + valid_types = ("hist", "violin", "box") + if diagram_type not in valid_types: + raise ValueError + + picture = plt.figure(figsize=(12, 12)) + grid = plt.GridSpec(4, 4, wspace=space, hspace=space) + + main = picture.add_subplot(grid[:-1, 1:]) + left = picture.add_subplot(grid[:-1, 0], sharey=main) + low = picture.add_subplot(grid[-1, 1:], sharex=main) + + main.scatter(abscissa, ordinates, color="m", alpha=0.7) + + if diagram_type == "hist": + + low.hist( + abscissa, + bins=75, + color="m", + density=True + ) + + left.hist( + ordinates, + bins=75, + color="m", + density=True, + orientation="horizontal", + ) + + low.invert_yaxis() + left.invert_xaxis() + + elif diagram_type == "violin": + v_left = left.violinplot( + ordinates, + vert=False, + showmedians=True + ) + + for body in v_left["bodies"]: + body.set_facecolor("m") + body.set_edgecolor("m") + + for part in v_left: + if part != "bodies": + v_left[part].set_edgecolor("m") + + v_low = low.violinplot( + abscissa, + vert=True, + showmedians=True + ) + + for body in v_low["bodies"]: + body.set_facecolor("m") + body.set_edgecolor("m") + + for part in v_low: + if part != "bodies": + v_low[part].set_edgecolor("m") + + low.invert_yaxis() + left.invert_xaxis() + + else: + + left.boxplot(ordinates, vert=False, patch_artist=True, + boxprops=dict(facecolor="m", alpha=0.7), + medianprops=dict(color="darkmagenta"), + whiskerprops=dict(color="m"), + capprops=dict(color="m"), + flierprops=dict(marker="o", markerfacecolor="m", markeredgecolor="m")) + + low.boxplot(abscissa, vert=True, patch_artist=True, + boxprops=dict(facecolor="m", alpha=0.7), + medianprops=dict(color="darkmagenta"), + whiskerprops=dict(color="m"), + capprops=dict(color="m"), + flierprops=dict(marker="o", markerfacecolor="m", markeredgecolor="m")) + + low.invert_yaxis() + left.invert_xaxis() + pass diff --git a/solutions/sem02/lesson08/task1.py b/solutions/sem02/lesson08/task1.py index 89f88572f..fecc41186 100644 --- a/solutions/sem02/lesson08/task1.py +++ b/solutions/sem02/lesson08/task1.py @@ -8,27 +8,67 @@ def create_modulation_animation( - modulation, - fc, - num_frames, - plot_duration, - time_step=0.001, - animation_step=0.01, - save_path="" + modulation, # Функция модуляции + fc, # Частота несущего сигнала + num_frames, # Количество кадров, которые будут сохранены в анимацию + plot_duration, # длительность интервала времени до зацикливания + time_step=0.001, # Промежуток времени между соседними вычисленными точками сигнала + animation_step=0.01, # время, которое прибавляется к оси за кадр + save_path="", ) -> FuncAnimation: - # ваш код - return FuncAnimation() + figure, axis = plt.subplots(figsize=(16, 9)) + axis.set_xlabel("Время (с)", fontsize=20) + axis.set_ylabel("Амплитуда", fontsize=20) + axis.text( + 0.98, + 0.98, + "Модулированный сигнал", + transform=axis.transAxes, + ha="right", + va="top", + fontsize=14, + bbox=dict(facecolor="white", alpha=0.5, edgecolor="black"), + ) + x_values = np.arange(0, plot_duration, time_step) + if modulation is None: + modulation_multiplier = 1.0 + else: + modulation_multiplier = modulation(x_values) + y_values_start = modulation_multiplier * np.sin(2 * np.pi * fc * x_values) + (line_start,) = axis.plot(x_values, y_values_start, lw=1, c="purple") + + axis.set_xlim(x_values.min(), x_values.max()) + axis.set_ylim(-1.5, 1.5) + + def update_frame(frame_id: int): + t = x_values + animation_step * frame_id + if modulation is None: + modulation_multiplier = 1.0 + else: + modulation_multiplier = modulation(t) + y_values_new = modulation_multiplier * np.sin(2 * np.pi * fc * t) + line_start.set_data(t, y_values_new) + axis.set_xlim(t.min(), t.max()) + return line_start, axis + + anim = FuncAnimation(figure, update_frame, frames=num_frames, interval=50, blit=False) + + if save_path: + anim.save(save_path, writer="pillow") + + return anim 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 +78,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 b677c0702..352ea982d 100644 --- a/solutions/sem02/lesson08/task2.py +++ b/solutions/sem02/lesson08/task2.py @@ -5,30 +5,91 @@ from IPython.display import HTML from matplotlib.animation import FuncAnimation +from matplotlib.colors import ListedColormap # !!! +# Пусть путь всегда существует +def animate_wave_algorithm( + maze: np.ndarray, start: tuple[int, int], end: tuple[int, int], save_path: str = "" +) -> FuncAnimation: + starting_maze = maze.copy() + def make_visual(p_ways): + visual = np.where(starting_maze == 0, 0, 1) + visual[p_ways >= 0] = 2 + return visual + + p_ways = np.full_like(maze, -1) + coordinates = [start] + steps = [(0, 1), (1, 0), (-1, 0), (0, -1)] + head = 0 + p_ways[start] = 0 + + frames = [make_visual(p_ways)] + current_dist = 0 + + while head < len(coordinates): + dist = p_ways[coordinates[head]] + if dist > current_dist: + frames.append(make_visual(p_ways)) + current_dist = dist + + maze[coordinates[head]] = 7 + for i in range(len(steps)): + shift_up_down = coordinates[head][0] + steps[i][0] + shift_left_right = coordinates[head][1] + steps[i][1] + if ((0 <= shift_left_right < maze.shape[1]) == False) or ( + (0 <= shift_up_down < maze.shape[0]) == False + ): + continue + if maze[shift_up_down, shift_left_right] == 1: + coordinates.append((shift_up_down, shift_left_right)) + p_ways[shift_up_down, shift_left_right] = p_ways[coordinates[head]] + 1 + head += 1 + + figure, axes = plt.subplots(figsize=(12, 12)) + cmap = ListedColormap(["green", "brown", "blue"]) + image = axes.imshow( + frames[0], + cmap=cmap, + ) + axes.set_xticks(np.arange(starting_maze.shape[1])) + axes.set_yticks(np.arange(starting_maze.shape[0])) + axes.set_xticklabels(np.arange(starting_maze.shape[1])) + axes.set_yticklabels(np.arange(starting_maze.shape[0])) + + axes.set_xticks(np.arange(-0.5, starting_maze.shape[1], 1), minor=True) + axes.set_yticks(np.arange(-0.5, starting_maze.shape[0], 1), minor=True) + + axes.grid(which="minor", color="black", linestyle="-", linewidth=2) + axes.grid(which="major", visible=False) + + axes.set_title("Волновой алгоритм", fontsize=16) + + def update(frame_id): + image.set_data(frames[frame_id]) + return [image] + + anim = FuncAnimation(figure, update, frames=len(frames), interval=100, blit=True, repeat=False) + + if save_path: + anim.save(save_path, writer="pillow") + + return anim -def animate_wave_algorithm( - maze: np.ndarray, - start: tuple[int, int], - end: tuple[int, int], - save_path: str = "" -) -> FuncAnimation: - # ваш код - return FuncAnimation() 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,10 +97,8 @@ 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 = "./data/maze.npy" loaded_maze = np.load(maze_path) # можете поменять, если захотите запустить из других точек @@ -48,6 +107,4 @@ def animate_wave_algorithm( 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 + HTML(loaded_animation.to_jshtml()) """