# Модуль `additional_funcs`

Этот модуль содержит набор функций для работы с числовыми данными, включая генерацию массивов с возмущениями, интерполяцию, манипуляции с матрицами и вычисление косинусного сходства.

## Функции

### 1. `generate_perturbed_array`

**Описание:**

Генерирует массив значений с равномерным шагом и добавляет к каждому элементу случайное возмущение из заданного диапазона.

**Параметры:**

- `start` (float или int): Начальное значение массива (включительно).
- `stop` (float или int): Конечное значение массива (исключительно).
- `step` (float или int): Шаг между соседними значениями.
- `perturbation_range` (float, по умолчанию 0.1): Диапазон случайных возмущений (значения отклоняются на величину из интервала `[-perturbation_range, perturbation_range]`).
- `dtype` (data-type, по умолчанию float): Тип данных элементов массива (например, `float`, `int`).

**Возвращаемое значение:**

`numpy.ndarray`: Массив с равномерным шагом и добавленными случайными возмущениями.

**Пример:**

```python
import numpy as np
from matplobblib.nm.additional_funcs import generate_perturbed_array

# Генерация массива от 0 до 1 с шагом 0.2 и возмущением ±0.05
result = generate_perturbed_array(0, 1, 0.2, perturbation_range=0.05)
print(result)
# Возможный вывод: [0.023 0.241 0.478 0.689 0.854] (значения могут отличаться из-за случайности)
```

**Теоретическая справка:**

Функция использует `numpy.arange` для создания базового массива с равномерным шагом. Затем к каждому элементу добавляется случайное значение, сгенерированное с помощью `numpy.random.uniform`.  Равномерное распределение означает, что каждое значение в диапазоне `[-perturbation_range, perturbation_range]` имеет одинаковую вероятность быть выбранным.  Это может быть полезно для моделирования небольших случайных отклонений в данных или для тестирования устойчивости алгоритмов к шуму.

**Ссылки:**

- NumPy Documentation — numpy.random.uniform
- NumPy Documentation — numpy.arange

### 2. `quadratic_interpolate`

**Описание:**

Восстанавливает пропуски (NaN значения) в одномерном массиве, используя квадратичную интерполяцию на основе трех ближайших валидных точек.

**Параметры:**

- `series` (pandas.Series или array-like): Входной массив с пропусками.  Предполагается, что данные равномерно распределены по индексу.
- `just_gaps` (bool, по умолчанию False): Если `True`, возвращает только восстановленные пропуски в виде `pandas.Series`, где индекс соответствует позициям пропусков.  Если `False`, возвращает массив с заполненными пропусками.
- `dtype` (numpy.dtype, по умолчанию np.float64): Тип данных для результата.

**Возвращаемое значение:**

`pandas.Series` или `numpy.ndarray`: Массив с восстановленными пропусками.  Если `just_gaps=True`, возвращается `pandas.Series` с восстановленными значениями только для пропущенных позиций.

**Пример:**

```python
import pandas as pd
import numpy as np
from matplobblib.nm.additional_funcs import quadratic_interpolate

# Пример с пропуском в середине
data = pd.Series([1.0, 2.0, np.nan, 4.0, 5.0])
result = quadratic_interpolate(data)
print(result)
# Ожидаемый вывод:
# 0    1.0
# 1    2.0
# 2    3.0
# 3    4.0
# 4    5.0
# dtype: float64
```

**Теоретическая справка:**

Функция использует квадратичную интерполяцию, которая является частным случаем полиномиальной интерполяции Лагранжа.  Интерполяция Лагранжа строит многочлен, который проходит через заданный набор точек.  В случае квадратичной интерполяции используются три точки, и строится многочлен второй степени (парабола).  Для каждой пропущенной точки функция находит три ближайшие валидные точки (сначала слева, затем справа, при необходимости дополняя слева) и использует их для построения интерполяционного многочлена.  Значение многочлена в позиции пропуска используется для его восстановления.

**Ссылки:**

- Quadratic spline interpolation - OneCompiler
- Quadratic Interpolation - LinkedIn
- Quadratic Interpolation | GeeksforGeeks
- sidartchy/Quadratic-Biquadratic-Spline-Interpolation - GitHub
- Interpolation (scipy.interpolate) — SciPy Manual
- Lagrange interpolation in Python - Stack Overflow
- Lagrange Interpolation with Python - RareSkills
- Lagrange Polynomial Interpolation - Python Numerical Methods
- Python Program for Lagrange Interpolation Method - Codesansar

### 3. `next_power_of_two`

**Описание:**

Вычисляет ближайшую степень двойки, не меньшую заданного числа.

**Параметры:**

- `n` (int): Входное число (должно быть целым и неотрицательным).

**Возвращаемое значение:**

`int`: Наименьшая степень двойки, которая больше или равна `n`.

**Пример:**

```python
from matplobblib.nm.additional_funcs import next_power_of_two

print(next_power_of_two(5))  # Вывод: 8
print(next_power_of_two(8))  # Вывод: 8
print(next_power_of_two(0))  # Вывод: 1
```

**Теоретическая справка:**

Функция использует битовую арифметику для эффективного вычисления следующей степени двойки.  Длина битового представления числа `n-1` определяет показатель степени `k`, для которого `2^k` будет ближайшей степенью двойки, не меньшей `n`.  Например, если `n = 5`, то `n - 1 = 4`, битовое представление `4` равно `100`, длина этого представления равна 3, следовательно, следующая степень двойки равна `2^3 = 8`.  Этот метод значительно быстрее, чем итеративное умножение или использование логарифмов, особенно для больших чисел.

**Ссылки:**

- CUDA练手小项目——Parallel Prefix Sum (Scan) - 知乎专栏
- C++ next_power_of_two函數代碼示例- 純淨天空
- 深入探讨Linux环境下C语言编程中的向上取整算法实现与应用 (пример условный, замените на реальную ссылку)

### 4. `pad_matrix`

**Описание:**

Дополняет матрицу нулями до заданного размера, создавая квадратную матрицу.

**Параметры:**

- `A` (`numpy.ndarray`): Исходная матрица для дополнения.
- `size` (int): Желаемый размер выходной квадратной матрицы.

**Возвращаемое значение:**

`numpy.ndarray`: Квадратная матрица размера `(size x size)`, заполненная нулями, с исходной матрицей `A` в верхнем левом углу.

**Пример:**

```python
import numpy as np
from matplobblib.nm.additional_funcs import pad_matrix

A = np.array([[1, 2], [3, 4]])
padded = pad_matrix(A, 3)
print(padded)
# Вывод:
# [[1. 2. 0.]
#  [3. 4. 0.]
#  [0. 0. 0.]]
```

**Теоретическая справка:**

Функция создает новую матрицу нулей заданного размера и копирует в нее элементы исходной матрицы.  Если исходная матрица меньше заданного размера, оставшиеся элементы заполняются нулями.  Если исходная матрица больше заданного размера, возвращается только верхний левый угол матрицы размером `(size x size)`.  Это полезно для выравнивания матриц перед операциями, требующими одинаковых размеров, например, перед выполнением преобразований Фурье или других операций линейной алгебры.

**Ссылки:**

- numpy.zeros — NumPy Documentation
- numpy.ndarray — NumPy Documentation
- Array creation routines — NumPy Manual
- numpy.reshape — NumPy Documentation

### 5. `parallel_max_offdiag`

**Описание:**

Находит максимальный по модулю внедиагональный элемент симметричной матрицы и его индексы, используя параллельные вычисления.

**Параметры:**

- `A` (`numpy.ndarray`): Квадратная симметричная матрица.
- `n` (int): Размерность матрицы (количество строк/столбцов).

**Возвращаемое значение:**

Кортеж: `(global_max, global_i, global_j)`, где `global_max` - максимальное значение абсолютной величины внедиагонального элемента, `global_i` и `global_j` - индексы этого элемента.

**Пример:**

```python
import numpy as np
from matplobblib.nm.additional_funcs import parallel_max_offdiag

A = np.array([[1, 3, 2],
              [3, 4, 5],
              [2, 5, 6]])
max_val, i, j = parallel_max_offdiag(A, 3)
print(f"Максимальный внедиагональный элемент: {max_val} на позиции ({i}, {j})")
# Вывод: Максимальный внедиагональный элемент: 5.0 на позиции (1, 2)
```

**Теоретическая справка:**

Функция использует параллельные вычисления (с помощью библиотеки `numba`) для ускорения поиска максимального внедиагонального элемента.  Она предполагает, что матрица симметрична, поэтому рассматриваются только элементы выше главной диагонали.  Алгоритм разделяет матрицу на строки и обрабатывает каждую строку параллельно, находя локальный максимум в каждой строке.  Затем выполняется редукция для нахождения глобального максимума среди локальных максимумов.  Использование `fastmath=True` может повысить производительность, но может повлиять на точность вычислений.  Этот алгоритм часто используется в методах диагонализации матриц, таких как метод Якоби.

**Ссылки:**

- Numba documentation
- Parallel computing with Numba
- Golub, G. H., & Van Loan, C. F. (2013). *Matrix computations*. Johns Hopkins University Press.

### 6. `nearest_cosine_neighbors`

**Описание:**

Находит для каждого столбца тестовой матрицы наиболее похожий столбец в эталонной матрице на основе косинусного сходства.

**Параметры:**

- `W_test` (`numpy.ndarray`): Матрица тестовых векторов (размерность `(r, m)`, где `r` - размерность признаков, `m` - количество тестовых векторов).
- `W` (`numpy.ndarray`): Матрица эталонных векторов (размерность `(r, n)`, где `n` - количество эталонных векторов).

**Возвращаемое значение:**

`numpy.ndarray`: Массив индексов формы `(m,)`, где каждый элемент - индекс наиболее похожего эталонного вектора для соответствующего тестового вектора.

**Пример:**

```python
import numpy as np
from matplobblib.nm.additional_funcs import nearest_cosine_neighbors

W_test = np.array([[1, 0], [0, 1]], dtype=np.float64)
W = np.array([[1, 0], [0, 1]], dtype=np.float64)
print(nearest_cosine_neighbors(W_test, W))
# Вывод: [0 1]
```

**Теоретическая справка:**

Косинусное сходство измеряет угол между двумя векторами.  Оно определяется как косинус угла между ними и вычисляется по формуле:

```
cos(θ) = (a · b) / (||a|| ||b||)
```

где `a · b` - скалярное произведение векторов `a` и `b`, а `||a||` и `||b||` - их евклидовы нормы (длины).  Косинусное сходство принимает значения от -1 (полностью противоположные направления) до 1 (одинаковое направление), при этом 0 означает ортогональность векторов.

Функция сначала нормализует все столбцы эталонной матрицы `W` до единичной длины.  Затем для каждого столбца тестовой матрицы `W_test` вычисляется косинусное сходство со всеми нормализованными столбцами `W` с помощью скалярного произведения.  Индекс столбца `W` с максимальным сходством возвращается как наиболее похожий сосед.  Нулевые векторы в `W_test` обрабатываются отдельно: для них возвращается индекс 0.  Предварительная нормализация эталонных векторов и использование матричного умножения для вычисления сходств повышают эффективность алгоритма.

**Ссылки:**

- "Cosine similarity: what is it and how does it enable effective ……"
- "kNNTutorial/kNN-Cosine.ipynb at master - GitHub" (пример условный, замените на реальную ссылку)
- "1.6. Nearest Neighbors - Scikit-learn"
