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
31 changes: 31 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Run Tests

on:
[ push, pull_request ]

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Check out code
uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.8'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Install mypy
run: |
python -m pip install mypy
- name: Run mypy
run: |
mypy .
- name: Run tests
run: |
python ./scripts/run_tests.py
2 changes: 2 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[mypy]
exclude = venv/
73 changes: 73 additions & 0 deletions project/matrix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from typing import List


class Matrix:
"""
Класс для работы с матрицами, включая сложение, умножение и транспонирование.
"""

def __init__(self, data: List[List[float]]):
"""
Инициализирует матрицу.

:param data: Двумерный список чисел, представляющий матрицу.
"""
self.data: List[List[float]] = data
self.rows: int = len(data)
self.cols: int = len(data[0]) if data else 0

def __str__(self) -> str:
"""
Возвращает строковое представление матрицы.

:return: Строка, представляющая матрицу.
"""
return "\n".join(["\t".join(map(str, row)) for row in self.data])

def add(self, other: "Matrix") -> "Matrix":
"""
Складывает две матрицы.

:param other: Вторая матрица для сложения.
:return: Новая матрица, представляющая сумму.
:raises ValueError: Если матрицы имеют разные размеры.
"""
if self.rows != other.rows or self.cols != other.cols:
raise ValueError("Matrices must have the same dimensions for addition.")

result = [
[self.data[i][j] + other.data[i][j] for j in range(self.cols)]
for i in range(self.rows)
]
return Matrix(result)

def multiply(self, other: "Matrix") -> "Matrix":
"""
Умножает две матрицы.

:param other: Вторая матрица для умножения.
:return: Новая матрица, представляющая произведение.
:raises ValueError: Если число столбцов первой матрицы не равно числу строк второй матрицы.
"""
if self.cols != other.rows:
raise ValueError(
"Number of columns in the first matrix must equal the number of rows in the second matrix."
)

result = [
[
sum(self.data[i][k] * other.data[k][j] for k in range(self.cols))
for j in range(other.cols)
]
for i in range(self.rows)
]
return Matrix(result)

def transpose(self) -> "Matrix":
"""
Транспонирует матрицу, меняя строки и столбцы местами.

:return: Новая транспонированная матрица.
"""
result = [[self.data[j][i] for j in range(self.rows)] for i in range(self.cols)]
return Matrix(result)
64 changes: 64 additions & 0 deletions project/vectors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import math
from typing import List


class Vector:
"""
Класс для работы с векторами в многомерном пространстве.
"""

def __init__(self, components: List[float]):
"""
Инициализирует вектор с заданными компонентами.

:param components: Список чисел, представляющих компоненты вектора.
"""
self.components: List[float] = components

def __str__(self) -> str:
"""
Возвращает строковое представление вектора.

:return: Строка, представляющая вектор.
"""
return f"Vector({self.components})"

def length(self) -> float:
"""
Вычисляет длину (модуль) вектора.

:return: Длина вектора.
"""
return math.sqrt(sum(x**2 for x in self.components))

def dot_product(self, other: "Vector") -> float:
"""
Вычисляет скалярное произведение с другим вектором.

:param other: Второй вектор.
:return: Скалярное произведение векторов.
:raises ValueError: Если векторы имеют разные размеры.
"""
if len(self.components) != len(other.components):
raise ValueError("Vectors must have the same dimension for dot product")
return sum(x * y for x, y in zip(self.components, other.components))

def angle_between(self, other: "Vector") -> float:
"""
Вычисляет угол между двумя векторами в радианах.

:param other: Второй вектор.
:return: Угол в радианах.
:raises ValueError: Если хотя бы один из векторов имеет нулевую длину.
"""
dot_prod = self.dot_product(other)
length_self = self.length()
length_other = other.length()

if length_self == 0 or length_other == 0:
raise ValueError("Cannot compute angle with zero-length vector")

cos_theta = dot_prod / (length_self * length_other)
# Ограничиваем значение cos_theta из-за возможных ошибок округления
cos_theta = max(-1.0, min(1.0, cos_theta))
return math.acos(cos_theta)
18 changes: 0 additions & 18 deletions tests/test_basic.py

This file was deleted.

41 changes: 41 additions & 0 deletions tests/test_matrix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import pytest
from project.matrix import Matrix


def test_matrix_addition():
A = Matrix([[1, 2], [3, 4]])
B = Matrix([[5, 6], [7, 8]])
expected = Matrix([[6, 8], [10, 12]])
assert A.add(B).data == expected.data


def test_matrix_addition_dimension_mismatch():
A = Matrix([[1, 2, 3], [4, 5, 6]])
B = Matrix([[7, 8], [9, 10]])
with pytest.raises(
ValueError, match="Matrices must have the same dimensions for addition."
):
A.add(B)


def test_matrix_multiplication():
A = Matrix([[1, 2], [3, 4]])
B = Matrix([[2, 0], [1, 2]])
expected = Matrix([[4, 4], [10, 8]])
assert A.multiply(B).data == expected.data


def test_matrix_multiplication_dimension_mismatch():
A = Matrix([[1, 2], [3, 4]])
B = Matrix([[5, 6, 7]])
with pytest.raises(
ValueError,
match="Number of columns in the first matrix must equal the number of rows in the second matrix.",
):
A.multiply(B)


def test_matrix_transpose():
A = Matrix([[1, 2, 3], [4, 5, 6]])
expected = Matrix([[1, 4], [2, 5], [3, 6]])
assert A.transpose().data == expected.data
38 changes: 38 additions & 0 deletions tests/test_vectors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pytest
import math
from project.vectors import Vector


def test_vector_length():
v = Vector([3, 4])
assert v.length() == 5


def test_dot_product():
v1 = Vector([1, 2, 3])
v2 = Vector([4, -5, 6])
assert v1.dot_product(v2) == 12


def test_angle_between():
v1 = Vector([1, 0])
v2 = Vector([0, 1])
assert math.isclose(v1.angle_between(v2), math.pi / 2, rel_tol=1e-6)


def test_dot_product_dimension_mismatch():
v1 = Vector([1, 2, 3])
v2 = Vector([4, 5])
with pytest.raises(
ValueError, match="Vectors must have the same dimension for dot product"
):
v1.dot_product(v2)


def test_angle_with_zero_length_vector():
v1 = Vector([0, 0, 0])
v2 = Vector([1, 2, 3])
with pytest.raises(
ValueError, match="Cannot compute angle with zero-length vector"
):
v1.angle_between(v2)