#include <iostream>
#include <vector>
#include <random>
#include <chrono>

// usage: g++ -Ofast inner_product.cpp && ./a.out

std::vector<std::vector<float>> generate_random_float_vectors(size_t numVectors, size_t vectorSize) {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<float> dist(0.0f, 1.0f);

    std::vector<std::vector<float>> vectors(numVectors, std::vector<float>(vectorSize));
    for (size_t i = 0; i < numVectors; ++i) {
        for (size_t j = 0; j < vectorSize; ++j) {
            vectors[i][j] = dist(gen);
        }
    }

    return vectors;
}

float inner_product(const std::vector<float>& x, const std::vector<float>& y) {
    // Check if the input vectors have the same size
    if (x.size() != y.size()) {
        std::cerr << "Error: Input vectors must have the same size!" << std::endl;
        return -1.0f;  // Error code
    }

    float result = 0.0f;
    for (size_t i = 0; i < x.size(); ++i) {
        // Multiply and accumulate
        result += x[i] * y[i];
    }

    return result;
}

int main() {
    // Example usage with 10000-dimensional random float vectors
    size_t vectorSize = 512;
    size_t numVectors = 10000;

    std::vector<std::vector<float>> x = generate_random_float_vectors(numVectors, vectorSize);
    std::vector<std::vector<float>> y = generate_random_float_vectors(numVectors, vectorSize);

    // Measure the execution time of the inner_product function for each vector pair
    std::vector<std::vector<float>> results(numVectors, std::vector<float>(numVectors));
    auto start = std::chrono::high_resolution_clock::now();
    for (size_t i = 0; i < numVectors; ++i) {
        for (size_t j = 0; j < numVectors; ++j) {
            results[i][j] = inner_product(x[i], y[j]);
        }
    }
    auto end = std::chrono::high_resolution_clock::now();

    // // Print some example results
    // size_t numResultsToPrint = 5;
    // for (size_t i = 0; i < numResultsToPrint; ++i) {
    //     for (size_t j = 0; j < numResultsToPrint; ++j) {
    //         std::cout << "Inner product (x[" << i << "], y[" << j << "]): " << results[i][j] << std::endl;
    //     }
    // }

    // Calculate and print the execution time
    std::chrono::duration<double> duration = end - start;
    std::cout << "Execution time: " << duration.count() << " seconds" << std::endl;

    return 0;
}
