import java.util.concurrent.*;
import java.util.Random;
import java.util.List;
import java.util.ArrayList;

public class MatrixMultiplicationBenchmark {

  // Обычное умножение матриц
  public static int[][] multiplyMatrices(int[][] A, int[][] B) {
    int n = A.length;
    int[][] C = new int[n][n];

    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
        for (int k = 0; k < n; k++) {
          C[i][j] += A[i][k] * B[k][j];
        }
      }
    }

    return C;
  }

  // Параллельное умножение матриц
  public static int[][] multiplyMatricesParallel(int[][] A, int[][] B, int numThreads)
      throws InterruptedException, ExecutionException {
    int n = A.length;
    int[][] C = new int[n][n];

    ExecutorService executor = Executors.newFixedThreadPool(numThreads);
    List<Future<?>> futures = new ArrayList<>();

    for (int i = 0; i < n; i++) {
      final int row = i;
      futures.add(executor.submit(() -> {
        for (int j = 0; j < n; j++) {
          for (int k = 0; k < n; k++) {
            C[row][j] += A[row][k] * B[k][j];
          }
        }
      }));
    }

    // Ожидание завершения всех задач
    for (Future<?> future : futures) {
      future.get();
    }

    executor.shutdown();

    return C;
  }

  // Генерация случайной матрицы
  public static int[][] generateRandomMatrix(int size) {
    Random random = new Random();
    int[][] matrix = new int[size][size];
    for (int i = 0; i < size; i++) {
      for (int j = 0; j < size; j++) {
        matrix[i][j] = random.nextInt(10); // случайные числа от 0 до 9
      }
    }
    return matrix;
  }

  // Бенчмарк методов умножения матриц
  public static void benchmarkMatrixMultiplication(int size) throws InterruptedException, ExecutionException {
    int[][] A = generateRandomMatrix(size);
    int[][] B = generateRandomMatrix(size);

    System.out.println("Матрица " + size + "x" + size);

    // Обычное умножение
    long start = System.nanoTime();
    multiplyMatrices(A, B);
    long end = System.nanoTime();
    System.out.println("Время обычного: " + (end - start) / 1_000_000 + " ms");

    // Параллельное умножение
    int numThreads = Runtime.getRuntime().availableProcessors();
    start = System.nanoTime();
    multiplyMatricesParallel(A, B, numThreads);
    end = System.nanoTime();
    System.out.println("Время параллельного: " + (end - start) / 1_000_000 + " ms");

    System.out.println();
  }

  public static void main(String[] args) throws InterruptedException, ExecutionException {
    int[] sizes = { 100, 300, 500 };

    for (int size : sizes) {
      benchmarkMatrixMultiplication(size);
    }
  }
}