# Лабораторная работа №2
Разработка параллельного приложения с использованием MPI (Message Passing Interface) на языке Java.

## Вариант задания
Определить минимальный элемент матрицы. 

---

## Как запустить лабораторную работу
1. **Установить Java** на каждом контейнере (например, OpenJDK 8+ или 17).
2. **Установить библиотеку MPI** для Java. Используется MPJ Express:
   - Скачайте MPJ Express на все контейнеры.
   - Добавьте переменные окружения в `~/.bashrc`:
     ```bash
     export MPJ_HOME=~/mpj
     export PATH=$PATH:$MPJ_HOME/bin
     export CLASSPATH=.:$MPJ_HOME/lib/mpj.jar
     ```
3. **Настройте SSH без пароля** между контейнерами, чтобы mpjrun или mpjdaemon могли подключаться друг к другу.
4. **Отредактируйте** файл `machines`, вписав IP-адреса контейнеров (по одному в каждой строке):
   ```
   192.168.4.104
   192.168.4.105
   ```
5. **Скомпилируйте код** на контейнере, откуда будете запускать:
   ```bash
   javac -cp $MPJ_HOME/lib/mpj.jar:. MPIMinimumMatrix.java
   ```
6. **Скопируйте** файл `MPIMinimumMatrix.class` на остальные контейнеры в ту же директорию, чтобы все узлы имели доступ к коду.
7. **Запустите демонов** (в кластере) на всех контейнерах:
   ```bash
   mpjdaemon -boot 192.168.4.104 192.168.4.105
   ```

8. **Запустите программу**:
   ```bash
   ./mpjrun.sh -np 2 -dev niodev -machinesfile ~/machines -cp . MPIMinimumMatrix
   ```
   Здесь:
   - `-np 2` означает число процессов (должно совпадать с числом контейнеров или быть меньше/больше — тогда распределение строк меняется).
   - `-dev niodev` включает сетевой (кластерный) режим.
   - `-machinesfile ./machines` — указывает IP контейнеров.

---

## Какие технологии использовались
- **Java** (JDK 8 или выше) для написания кода.
- **MPJ Express** (v0_44) для реализации MPI-функций (`MPI.Init`, `MPI.COMM_WORLD.Scatter`, `MPI.COMM_WORLD.Reduce` и т.д.).

---

## Что делает программа
1. Процесс с рангом 0 (**rank=0**) генерирует квадратную матрицу размера `SIZE x SIZE` (по умолчанию 3000 x 3000) в двумерном массиве `matrix2D`.
2. Преобразует матрицу в одномерный массив `flatMatrix`.
3. **Scatter**: Делит `flatMatrix` на фрагменты по строкам и рассылает их другим процессам (включая себя).
4. Каждый узел получает часть строк, ищет минимум в своих элементах.
5. **Reduce**: Узлы передают локальный минимум процессу 0, который находит глобальный минимум и выводит результат.
6. Замеряет и выводит **время выполнения** (в миллисекундах).

---

## Пример тестов
Вычисление минимального элемента для матрицы `3000 x 3000`.

### Распределение
- Узел `rank=0` получает первые 1500 строки.
- Узел `rank=1` получает последние 1500 строки.

### Локальный поиск минимума
- На `rank=0`: минимум = 1
- На `rank=1`: минимум = 0

### Глобальный минимум
- `Reduce(MIN)` = 0

### Вывод
```
Starting process <0> on <CT104>
Starting process <1> on <second-container>
[Container 1] Matrix generated. Sending data to container 2...
[Container 0] Received matrix size: 1500x3000
[Container 1] Received matrix size: 1500x3000
[Container 0] Local minimum: 1
[Container 1] Local minimum: 0
[Container 1] All minimums received. Global minimum: 0
[Container 1] Time last: 3895 ms
Stopping Process <0> on <CT104>
Stopping Process <1> on <second-container>
```

## Проблемы, с которыми столкнулись
- **SSH-пароли**: Без настройки SSH-ключей mpjrun/daemon будет «виснуть», ожидая пароль.
- **Разные подсети**: Если контейнеры в разных сетях (192.168.4.x и 192.168.5.x), нужно либо объединить их в одну сеть, либо настроить маршруты.
- **Переменная окружения `MPJ_HOME`** не видна при запуске неинтерактивной SSH-сессии. Решение: прописать `MPJ_HOME` и `PATH` в `/etc/environment`.

---

## Вывод
Используя MPI (MPJ Express) и несколько контейнеров, удалось распараллелить задачу поиска минимума по строкам матрицы. Каждый контейнер обрабатывает свой блок данных, а затем результат собирается через операцию `Reduce`. Подход хорошо масштабируется и демонстрирует, как распределённые процессы могут совместно решать одну задачу.

