Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions solutions/sem02/lesson03/task1.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

return np.sqrt(((lhs[:, None, :] - rhs[None, :, :]) ** 2).sum(axis=2))
26 changes: 24 additions & 2 deletions solutions/sem02/lesson03/task2.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,33 @@ 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

r = np.sqrt(abscissa**2 + ordinates**2 + applicates**2)
azimuth = np.arctan2(ordinates, abscissa)

inclination = np.zeros_like(r)

mask = r != 0
inclination[mask] = np.arccos(applicates[mask] / r[mask])

return r, azimuth, inclination
17 changes: 16 additions & 1 deletion solutions/sem02/lesson03/task3.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,19 @@

def get_extremum_indices(
ordinates: np.ndarray,
) -> tuple[np.ndarray, np.ndarray]: ...
) -> tuple[np.ndarray, np.ndarray]:

if len(ordinates) < 3:
raise ValueError

left_compare = ordinates[1:-1] > ordinates[:-2]
right_compare = ordinates[1:-1] > ordinates[2:]

max = left_compare & right_compare

min = (~left_compare) & (~right_compare)

max_indices = np.where(max)[0] + 1
min_indices = np.where(min)[0] + 1

return min_indices, max_indices
54 changes: 50 additions & 4 deletions solutions/sem02/lesson04/task1.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,62 @@


def pad_image(image: np.ndarray, pad_size: int) -> np.ndarray:
# ваш код
return image

if pad_size < 1:
raise ValueError

if image.ndim == 2:

h, w = image.shape

padded = np.zeros((h + 2*pad_size, w + 2*pad_size), dtype=image.dtype)
padded[pad_size:pad_size+h, pad_size:pad_size+w] = image

elif image.ndim == 3:

h, w, c = image.shape

padded = np.zeros((h + 2*pad_size, w + 2*pad_size, c), dtype=image.dtype)
padded[pad_size:pad_size+h, pad_size:pad_size+w, :] = image

else:
raise ValueError

return padded


def blur_image(
image: np.ndarray,
kernel_size: int,
) -> np.ndarray:
# ваш код
return image

if kernel_size < 1 or kernel_size % 2 == 0:
raise ValueError

pad = kernel_size // 2
k = kernel_size

padded = pad_image(image.astype(np.float64), pad)
integral = np.cumsum(np.cumsum(padded, axis=0), axis=1)

if image.ndim == 2:
h, w = image.shape

sums = (integral[k:, k:] - integral[:-k, k:] -
integral[k:, :-k] + integral[:-k, :-k])

result = sums[:h, :w] / (k * k)

else:
h, w, c = image.shape
result = np.zeros((h, w, c), dtype=np.float64)

for ch in range(c):
sums = (integral[k:, k:, ch] - integral[:-k, k:, ch] -
integral[k:, :-k, ch] + integral[:-k, :-k, ch])
result[:, :, ch] = sums[:h, :w] / (k * k)

return np.clip(result, 0, 255).astype(np.uint8)


if __name__ == "__main__":
Expand Down
31 changes: 29 additions & 2 deletions solutions/sem02/lesson04/task2.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,33 @@ def get_dominant_color_info(
image: np.ndarray[np.uint8],
threshold: int = 5,
) -> tuple[np.uint8, float]:
# ваш код

if threshold < 1:
raise ValueError

pixels = image.flatten()
pixels.sort()

return 0, 0
current_group_start = 0
current_group_size = 1
best_group_start = 0
best_group_size = 1

for i in range(1, len(pixels)):
if pixels[i] - pixels[current_group_start] < threshold:
current_group_size += 1
else:
if current_group_size > best_group_size:
best_group_size = current_group_size
best_group_start = current_group_start
current_group_start = i
current_group_size = 1

if current_group_size > best_group_size:
best_group_size = current_group_size
best_group_start = current_group_start

total_pixels = len(pixels)
percentage = (best_group_size / total_pixels) * 100

return (pixels[best_group_start], percentage)
8 changes: 7 additions & 1 deletion solutions/sem02/lesson05/task1.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@ def can_satisfy_demand(
costs: np.ndarray,
resource_amounts: np.ndarray,
demand_expected: np.ndarray,
) -> bool: ...
) -> bool:
M, N = costs.shape

if len(resource_amounts) != M or len(demand_expected) != N:
raise ShapeMismatchError

return bool(np.all(costs @ demand_expected <= resource_amounts))
20 changes: 19 additions & 1 deletion solutions/sem02/lesson05/task2.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,22 @@ 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

n = matrix.shape[0]
if len(vector) != n:
raise ShapeMismatchError

if abs(np.linalg.det(matrix)) < 1e-10:
return None, None

coeffs = np.linalg.solve(matrix.T, vector)

projections = np.array([coeffs[i] * matrix[i] for i in range(n)])

total_projection = np.sum(projections, axis=0)
components = vector - total_projection

return projections, components
23 changes: 22 additions & 1 deletion solutions/sem02/lesson05/task3.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 or len(diag_A) != K:
raise ShapeMismatchError

Vj_H = Vj.conj().T

A = np.diag(diag_A.astype(complex))

I_K = np.eye(K, dtype=complex)
matrix_to_invert = I_K + Vj_H @ Vj @ A

inv_matrix = np.linalg.inv(matrix_to_invert)

I_M = np.eye(M, dtype=complex)
R_inv = I_M - Vj @ inv_matrix @ Vj_H

y = R_inv @ Vs

return y
83 changes: 81 additions & 2 deletions solutions/sem02/lesson07/task1.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,87 @@ def visualize_diagrams(
ordinates: np.ndarray,
diagram_type: Any,
) -> None:
# ваш код
pass

if len(abscissa) != len(ordinates):
raise ShapeMismatchError(
f"Длины массивов должны совпадать: abscissa={len(abscissa)}, ordinates={len(ordinates)}"
)

# проверка допустимости diagram_type
valid_types = ["hist", "violin", "box"]
if diagram_type not in valid_types:
raise ValueError(
f"diagram_type должен быть одним из: {valid_types}, получено '{diagram_type}'"
)

# Создаем фигуру с сеткой 2x2
plt.figure(figsize=(10, 10))

# Основная диаграмма рассеяния (нижний левый)
scatter_ax = plt.subplot(2, 2, 3)
scatter_ax.scatter(
abscissa, ordinates, alpha=0.6, s=20, c="steelblue", edgecolors="white", linewidth=0.5
)
scatter_ax.set_xlabel("X")
scatter_ax.set_ylabel("Y")
scatter_ax.set_title("Диаграмма рассеяния")
scatter_ax.grid(True, alpha=0.3)

# Распределение по оси X (верхний левый)
x_ax = plt.subplot(2, 2, 1)

if diagram_type == "hist":
x_ax.hist(abscissa, bins=30, color="steelblue", alpha=0.7, edgecolor="white")
x_ax.set_title("Распределение по X (гистограмма)")

elif diagram_type == "violin":
x_ax.violinplot(abscissa, positions=[0], showmeans=True, showmedians=True)
x_ax.set_title("Распределение по X (скрипичная диаграмма)")

elif diagram_type == "box":
x_ax.boxplot(abscissa, vert=True, positions=[0])
x_ax.set_title("Распределение по X (ящик с усами)")

x_ax.set_xlabel("X")
x_ax.set_ylabel("Плотность")
x_ax.grid(True, alpha=0.3)

# Распределение по оси Y (нижний правый)
y_ax = plt.subplot(2, 2, 4)

if diagram_type == "hist":
y_ax.hist(
ordinates,
bins=30,
color="lightcoral",
alpha=0.7,
edgecolor="white",
orientation="horizontal",
)
y_ax.set_title("Распределение по Y (гистограмма)")

elif diagram_type == "violin":
y_ax.violinplot(ordinates, positions=[0], vert=False, showmeans=True, showmedians=True)
y_ax.set_title("Распределение по Y (скрипичная диаграмма)")

elif diagram_type == "box":
y_ax.boxplot(ordinates, vert=False, positions=[0])
y_ax.set_title("Распределение по Y (ящик с усами)")

y_ax.set_xlabel("Плотность")
y_ax.set_ylabel("Y")
y_ax.grid(True, alpha=0.3)

# Убираем пустой угол (верхний правый)
plt.subplot(2, 2, 2).axis("off")

# Общий заголовок
plt.suptitle(
f"Визуализация данных\nТип распределения: {diagram_type}", fontsize=14, fontweight="bold"
)

# Автоматическая подгонка
plt.tight_layout()


if __name__ == "__main__":
Expand Down
Loading
Loading