import pyperclip


def help():
    """Выводит справку о всех доступных методах."""
    help_message = "Справка по методам:\n"
    methods_info = {
        "mlp": "1. Модель перцептрона. Проблема линейно неразделимых множеств и ее решение. Логика построения многослойных ИНС. Линейные слои (Linear Layers) в PyTorch.",
    }
    for method, description in methods_info.items():
        help_message += f"- {method}: {description}\n"
    pyperclip.copy(help_message)


def mlp(idx: int = 0):
    """1. Модель перцептрона. Проблема линейно неразделимых множеств и ее решение. Логика построения многослойных ИНС. Линейные слои (Linear Layers) в PyTorch."""
    if idx == 0:
        code = """
### 1. Модель перцептрона
Перцептрон — это одна из первых моделей искусственных нейронных сетей. Его основная идея заключается в следующем:
1. **Функция активации**: вычисляется взвешенная сумма входов и добавляется смещение (bias). Применяется нелинейная функция активации, например, ступенчатая функция (sign).
2. **Обучение**: используется алгоритм коррекции ошибок, обновляя веса в зависимости от ошибки на каждом шаге.

#### Формула:
\[
y = f\left(\sum_{i=1}^n w_i x_i + b\right)
\]
где \(w_i\) — веса, \(x_i\) — входы, \(b\) — смещение, а \(f\) — функция активации.

---

### 2. Проблема линейно неразделимых множеств
Перцептрон справляется только с **линейно разделимыми данными**. Например, он не может решить задачу XOR, так как классы нельзя разделить прямой линией в двумерном пространстве. Это ключевое ограничение классического перцептрона.

#### Решение проблемы:
- Добавление **скрытых слоев** с нелинейными функциями активации (например, ReLU, sigmoid). Это позволяет модели представлять более сложные зависимости между входами и выходами.
- Многослойные нейронные сети (MLP) обучаются с использованием **обратного распространения ошибки (backpropagation)**.

---

### 3. Логика построения многослойных ИНС
Многослойный перцептрон (MLP) состоит из:
1. **Входного слоя**: принимает данные.
2. **Скрытых слоев**: выполняют вычисления и преобразования для обучения нелинейным зависимостям.
3. **Выходного слоя**: возвращает результат классификации или регрессии.

Каждый слой преобразует входы в выходы с помощью линейного преобразования и нелинейной функции активации:
\[
y = f(Wx + b)
\]

---

### 4. Линейные слои (Linear Layers) в PyTorch
В PyTorch линейный слой реализуется с помощью класса `torch.nn.Linear`. Он выполняет операцию \(y = Wx + b\).
"""
    else:
        code = """
import torch
import torch.nn as nn
import torch.optim as optim

# Создаем модель
class SimplePerceptron(nn.Module):
    def __init__(self, input_size, output_size):
        super(SimplePerceptron, self).__init__()
        self.linear = nn.Linear(input_size, output_size)  # Линейный слой
    
    def forward(self, x):
        return self.linear(x)  # Линейное преобразование

# Создаем данные
X = torch.tensor([[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]])  # XOR данные
y = torch.tensor([0, 1, 1, 0])  # Метки классов

# Параметры модели
input_size = 2
output_size = 1

# Инициализация модели
model = SimplePerceptron(input_size, output_size)

# Определяем функцию потерь и оптимизатор
criterion = nn.BCEWithLogitsLoss()  # Для бинарной классификации
optimizer = optim.SGD(model.parameters(), lr=0.1)

# Обучение
epochs = 1000
for epoch in range(epochs):
    # Прямой проход
    outputs = model(X)
    loss = criterion(outputs.squeeze(), y.float())
    
    # Обратное распространение
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}')
"""
    pyperclip.copy(code)
