from mpi4py import MPI
import pandas as pd
import numpy as np
import pprint

# Р¤СѓРЅРєС†РёСЏ РґР»СЏ СЌС‚Р°РїР° Map вЂ” РїРѕРґСЃС‡РёС‚С‹РІР°РµС‚ РєРѕР»РёС‡РµСЃС‚РІРѕ РІС…РѕР¶РґРµРЅРёР№ С‡РёСЃРµР»
def compute_frequencies(data_segment):
    frequency_dict = {}
    for number in data_segment:
        if number in frequency_dict:
            frequency_dict[number] += 1
        else:
            frequency_dict[number] = 1
    return frequency_dict

# Р¤СѓРЅРєС†РёСЏ РґР»СЏ СЌС‚Р°РїР° Reduce вЂ” РѕР±СЉРµРґРёРЅСЏРµС‚ СЂРµР·СѓР»СЊС‚Р°С‚С‹ РёР· СЂР°Р·РЅС‹С… РїСЂРѕС†РµСЃСЃРѕРІ
def aggregate_counts(main_counts, incoming_counts):
    for key, value in incoming_counts.items():
        if key in main_counts:
            main_counts[key] += value
        else:
            main_counts[key] = value
    return main_counts

# РРЅРёС†РёР°Р»РёР·Р°С†РёСЏ MPI
comm = MPI.COMM_WORLD
process_rank = comm.Get_rank()  # РџРѕР»СѓС‡РµРЅРёРµ РёРґРµРЅС‚РёС„РёРєР°С‚РѕСЂР° РїСЂРѕС†РµСЃСЃР°
process_size = comm.Get_size()  # РџРѕР»СѓС‡РµРЅРёРµ РѕР±С‰РµРіРѕ РєРѕР»РёС‡РµСЃС‚РІР° РїСЂРѕС†РµСЃСЃРѕРІ

# РџСѓС‚СЊ Рє С„Р°Р№Р»Сѓ СЃ РґР°РЅРЅС‹РјРё
input_file = "random_numbers.csv"

# РЎРёРЅС…СЂРѕРЅРёР·Р°С†РёСЏ РІСЃРµС… РїСЂРѕС†РµСЃСЃРѕРІ РїРµСЂРµРґ РЅР°С‡Р°Р»РѕРј РёР·РјРµСЂРµРЅРёСЏ РІСЂРµРјРµРЅРё
comm.Barrier()
if process_rank == 0:
    start_time = MPI.Wtime()  # РќР°С‡Р°Р»Рѕ РѕС‚СЃС‡С‘С‚Р° РІСЂРµРјРµРЅРё С‚РѕР»СЊРєРѕ РЅР° РіР»Р°РІРЅРѕРј РїСЂРѕС†РµСЃСЃРµ

# Р“Р»Р°РІРЅС‹Р№ РїСЂРѕС†РµСЃСЃ РѕС‚РІРµС‡Р°РµС‚ Р·Р° СЂР°СЃРїСЂРµРґРµР»РµРЅРёРµ РґР°РЅРЅС‹С… Рё СЃР±РѕСЂ СЂРµР·СѓР»СЊС‚Р°С‚РѕРІ
if process_rank == 0:
    # Р§С‚РµРЅРёРµ РґР°РЅРЅС‹С… РёР· CSV С„Р°Р№Р»Р° Р±РµР· Р·Р°РіРѕР»РѕРІРєР°
    data_frame = pd.read_csv(input_file, header=None)
    all_numbers = data_frame[0].tolist()

    # Р Р°Р·РґРµР»РµРЅРёРµ РґР°РЅРЅС‹С… РЅР° С‡Р°СЃС‚Рё РґР»СЏ СЂР°Р±РѕС‡РёС… РїСЂРѕС†РµСЃСЃРѕРІ
    data_chunks = np.array_split(all_numbers, process_size - 1)
    total_numbers = len(all_numbers)

    # РћС‚РїСЂР°РІРєР° РєР°Р¶РґРѕР№ С‡Р°СЃС‚Рё РґР°РЅРЅС‹С… СЃРѕРѕС‚РІРµС‚СЃС‚РІСѓСЋС‰РµРјСѓ СЂР°Р±РѕС‡РµРјСѓ РїСЂРѕС†РµСЃСЃСѓ
    for dest in range(1, process_size):
        if dest - 1 < len(data_chunks):
            current_chunk = data_chunks[dest - 1].tolist()
        else:
            current_chunk = []
        comm.send(current_chunk, dest=dest)
        print(f"Sent data packet to process {dest}")

    # РРЅРёС†РёР°Р»РёР·Р°С†РёСЏ СЃР»РѕРІР°СЂСЏ РґР»СЏ С…СЂР°РЅРµРЅРёСЏ РёС‚РѕРіРѕРІС‹С… РїРѕРґСЃС‡С‘С‚РѕРІ
    final_frequency = {}

    # РџРѕР»СѓС‡РµРЅРёРµ Рё РѕР±СЉРµРґРёРЅРµРЅРёРµ С‡Р°СЃС‚РёС‡РЅС‹С… СЂРµР·СѓР»СЊС‚Р°С‚РѕРІ РѕС‚ СЂР°Р±РѕС‡РёС… РїСЂРѕС†РµСЃСЃРѕРІ
    for source in range(1, process_size):
        partial_result = comm.recv(source=source)
        final_frequency = aggregate_counts(final_frequency, partial_result)
        print(f"Received data from process {source}")

    # Р’С‹РІРѕРґ РёС‚РѕРіРѕРІС‹С… СЂРµР·СѓР»СЊС‚Р°С‚РѕРІ РїРѕРґСЃС‡С‘С‚Р°
    print("\nFrequency of each number:")
    pprint.pprint(final_frequency)

    # Р¤РёР»СЊС‚СЂР°С†РёСЏ СѓРЅРёРєР°Р»СЊРЅС‹С… С‡РёСЃРµР» (РІСЃС‚СЂРµС‡Р°СЋС‚СЃСЏ С‚РѕР»СЊРєРѕ РѕРґРёРЅ СЂР°Р·)
    unique_entries = {num: cnt for num, cnt in final_frequency.items() if cnt == 1}
    print("\nUnique numbers:")
    print(", ".join(map(str, unique_entries)))

    # Р—Р°РІРµСЂС€РµРЅРёРµ РёР·РјРµСЂРµРЅРёСЏ РІСЂРµРјРµРЅРё
    end_time = MPI.Wtime()
    total_time = end_time - start_time
    print(f"\nTotal execution time: {total_time:.6f} seconds")

# Р Р°Р±РѕС‡РёРµ РїСЂРѕС†РµСЃСЃС‹ РІС‹РїРѕР»РЅСЏСЋС‚ СЌС‚Р°Рї Map
else:
    # РџСЂРёС‘Рј РґР°РЅРЅС‹С… РѕС‚ РіР»Р°РІРЅРѕРіРѕ РїСЂРѕС†РµСЃСЃР°
    received_segment = comm.recv(source=0)

    # РџРѕРґСЃС‡С‘С‚ РІС…РѕР¶РґРµРЅРёР№ С‡РёСЃРµР» РІ РїРѕР»СѓС‡РµРЅРЅРѕР№ С‡Р°СЃС‚Рё РґР°РЅРЅС‹С…
    local_frequency = compute_frequencies(received_segment)

    # РћС‚РїСЂР°РІРєР° СЂРµР·СѓР»СЊС‚Р°С‚РѕРІ РїРѕРґСЃС‡С‘С‚Р° РѕР±СЂР°С‚РЅРѕ РіР»Р°РІРЅРѕРјСѓ РїСЂРѕС†РµСЃСЃСѓ
    comm.send(local_frequency, dest=0)

    print(f"Process {process_rank} has completed counting and sent the results.")

# Р—Р°РІРµСЂС€РµРЅРёРµ СЂР°Р±РѕС‚С‹ СЃ MPI
MPI.Finalize()


Traceback (most recent call last):
  File "C:\Users\ivanm\PycharmProjects\pythonProject8\main.py", line 1, in <module>
    from mpi4py import MPI
  File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1140, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1080, in _find_spec
  File "C:\Users\ivanm\PycharmProjects\pythonProject8\venv\Lib\site-packages\mpi4py\_mpiabi.py", line 246, in find_spec
    mpiabi_suffix = _get_mpiabi_suffix(fullname)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ivanm\PycharmProjects\pythonProject8\venv\Lib\site-packages\mpi4py\_mpiabi.py", line 228, in _get_mpiabi_suffix
    version, family = _get_mpiabi()
                      ^^^^^^^^^^^^^
  File "C:\Users\ivanm\PycharmProjects\pythonProject8\venv\Lib\site-packages\mpi4py\_mpiabi.py", line 209, in _get_mpiabi
    version, family = _get_mpiabi_from_libmpi(libmpi)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ivanm\PycharmProjects\pythonProject8\venv\Lib\site-packages\mpi4py\_mpiabi.py", line 153, in _get_mpiabi_from_libmpi
    lib = _dlopen_libmpi(libmpi)
          ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ivanm\PycharmProjects\pythonProject8\venv\Lib\site-packages\mpi4py\_mpiabi.py", line 144, in _dlopen_libmpi
    raise RuntimeError("\n".join(errors))
RuntimeError: cannot load MPI library
Could not find module 'C:\Users\ivanm\PycharmProjects\pythonProject8\venv\DLLs' (or one of its dependencies). Try using the full path with constructor syntax.
Could not find module 'C:\Users\ivanm\PycharmProjects\pythonProject8\venv\Library\bin' (or one of its dependencies). Try using the full path with constructor syntax.
Could not find module 'impi.dll' (or one of its dependencies). Try using the full path with constructor syntax.
Could not find module 'msmpi.dll' (or one of its dependencies). Try using the full path with constructor syntax.