package ru.kuznec;

import mpi.MPI;

public class MatrixMinBelowMainDiagonal {
    public static void main(String[] args) {
        MPI.Init(args);

        int rank = MPI.COMM_WORLD.Rank();
        int size = MPI.COMM_WORLD.Size();

        int n = 4;
        double[] matrix = new double[n * n];

        if (rank == 0) {
            double[][] m = {
                    {1, 2, 3, 4},
                    {5, 6, 7, 8},
                    {9, 10, 11, 12},
                    {13, 14, 15, 16}
            };

            for (int i = 0; i < n; i++) {
                System.arraycopy(m[i], 0, matrix, i * n, n);
            }
        }

        System.nanoTime();

        int[] dim = new int[]{n};
        MPI.COMM_WORLD.Bcast(dim, 0, 1, MPI.INT, 0);
        n = dim[0];

        MPI.COMM_WORLD.Bcast(matrix, 0, n * n, MPI.DOUBLE, 0);

        int rowsPerProc = n / size;
        int extra = n % size;
        int startRow, endRow;
        if (rank < extra) {
            startRow = rank * (rowsPerProc + 1);
            endRow = startRow + rowsPerProc;
        } else {
            startRow = rank * rowsPerProc + extra;
            endRow = startRow + rowsPerProc - 1;
        }

        double localMin = Double.MAX_VALUE;
        for (int i = startRow; i <= endRow; i++) {
            for (int j = 0; j < i; j++) {
                double value = matrix[i * n + j];
                if (value < localMin) {
                    localMin = value;
                }
            }
        }

        double[] sendBuf = new double[]{ localMin };
        double[] globalMin = new double[1];
        MPI.COMM_WORLD.Reduce(sendBuf, 0, globalMin, 0, 1, MPI.DOUBLE, MPI.MIN, 0);

        if (rank == 0) {
            if (globalMin[0] == Double.MAX_VALUE) {
                System.out.println("Элементы ниже главной диагонали отсутствуют.");
            } else {
                System.out.println("Минимальный элемент ниже главной диагонали: " + globalMin[0]);
            }
        }

        MPI.Finalize();
    }
}
