#include <iostream>
#include <vector>
#include <thread>
#include <chrono>
#include <mutex>
#include <cstdlib>
#include <ctime>

using namespace std;

mutex print_mutex;

void multiply_part(const vector<vector<float>>& A, 
                   const vector<vector<float>>& B_T,
                   vector<vector<float>>& C,
                   int start_row, int end_row,
                   int thread_id) {
    int n = A.size();
    
    for (int i = start_row; i < end_row; i++) {
        for (int k = 0; k < n; k++) {
            float aik = A[i][k];
            if (aik != 0.0f) {
                for (int j = 0; j < n; j++) {
                    C[i][j] += aik * B_T[k][j];
                }
            }
        }
    }
    
    lock_guard<mutex> lock(print_mutex);
    cout << "Поток " << thread_id << " завершил строки " << start_row << "-" << end_row << endl;
}

int main() {
    const int SIZE = 64;       // 64x64 (маленький, для онлайн-компилятора)
    const int THREADS = 4;     // 4 потока
    
    cout << "Создание матриц " << SIZE << "x" << SIZE << "..." << endl;
    
    // Создаём матрицы
    vector<vector<float>> A(SIZE, vector<float>(SIZE));
    vector<vector<float>> B(SIZE, vector<float>(SIZE));
    vector<vector<float>> C(SIZE, vector<float>(SIZE, 0.0f));
    
    // Заполняем случайными числами
    srand(123);
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            A[i][j] = (float)(rand() % 100) / 100.0f;
            B[i][j] = (float)(rand() % 100) / 100.0f;
        }
    }
    
    // Транспонируем B для лучшей производительности
    cout << "Транспонирование матрицы B..." << endl;
    vector<vector<float>> B_T(SIZE, vector<float>(SIZE));
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            B_T[j][i] = B[i][j];
        }
    }
    
    // Запускаем потоки
    cout << "Запуск " << THREADS << " потоков..." << endl;
    vector<thread> threads;
    int rows_per_thread = SIZE / THREADS;
    
    for (int t = 0; t < THREADS; t++) {
        int start_row = t * rows_per_thread;
        int end_row = (t == THREADS - 1) ? SIZE : (t + 1) * rows_per_thread;
        
        threads.push_back(thread(multiply_part, ref(A), ref(B_T), ref(C), 
                                 start_row, end_row, t));
    }
    
    // Ждём завершения всех потоков
    for (auto& th : threads) {
        th.join();
    }
    
    // Выводим результат
    cout << "\nРезультат умножения:" << endl;
    cout << "C[0][0] = " << C[0][0] << endl;
    cout << "C[0][1] = " << C[0][1] << endl;
    cout << "C[1][0] = " << C[1][0] << endl;
    cout << "C[63][63] = " << C[SIZE-1][SIZE-1] << endl;
    
    cout << "\nГотово!" << endl;
    
    return 0;
}