import math


def model(AD,ZA):
    # ZA: mDR -0, mDW -1, mdR -2,mdW -3,mPW- 4, mPR -5,mN1- 6, mN2 -7, t -8, точность- 9
    # количество узлов Map (NM) и Reduce (NR), общее число узлов (N)
    # K - макс. число узлов, подключённых к коммутатору
    # NM=3; NR=1; N=3; K=50; K1=min(N,K)
    NM=AD["NM"]; NR=AD["NR"]; N=AD["N"]; K=50; K1=min(N,K)
    # размер блока и split в Мбайтах
    VB=128; VS=128
    # размер кучи Map и Reduce (VKM,VKR),  в Мбайтах
    VKM=200; VKR=200
    # параметры L, R
    # L=2; R=2
    L = AD["L"]; R =AD["R"]
    # kr - число групп по R задач Reduce, выполняемых последовательно,s - общее число задач Reduce
    # kr=1; s= NR*kr*R
    kr=1; s= AD["s"]
    # тау (сек)
    #t=1.0E-6 # старое - 1.6E-8
    t=ZA[8]
    # число измерений (n) и одна таблица внешних ключей+число значений (столбцов) фактов (1+m)
    n=3; m=1+1
    # интенсивности чтения (R), записи (W) с локального диска (d) или HDFS (D) - Мбайтов/с
    # mPDC - скорость разархивации Мбайтов/с
    # mDR=50; mDW=24; mdR=50; mdW=50; mPDC=300
    mDR=ZA[0]; mDW=ZA[1]; mdR=ZA[2]; mdW=ZA[3]; mPDC=300
    # производительности порта (PW и PR) и сети (N1-коммутатора и N2-кольца)- Мбайтов/с
    # mPW=1024/8; mN1=10; mN2=10; mPR=1024/8
    mPW=ZA[4]; mN1=ZA[6]; mN2=ZA[7]; mPR=ZA[5]
    # QM - число отсортированных записей, сохранённых одним Map в одном промежуточном файле
    QM=100*0.8*0.05/(16/1024**2) # размер буфера*порог заполнения*доля под метаданные/объём на одну запись
    # количество файлов для сортировки слиянием на фазе Reduce
    u=100
    # время распространения задач Map и Reduce (сек)
    TNZ=14
    # исходные данные измерений и фактов
    """V:  объём всей табл,Q: число зап во всей табл,
    dr: длина записи, ds: длина полей за Select, dsw: длина полей за Select и where
    CR: коэфф. сжатия, Г: число атр. и лог. операций, P: вероятность,
    следующие поля м.б. использованы потом:
    gr: число атрибутов в Group by и во всех ф-ях агрегации,
    op: число операций в ф-ях агригтрования на одну запись в группе,
    I: произведение мощностей атрибутов, участвующих в группировании,
    dagr: длина атрибутов группы и всех агрегатов - результирующая запись"""
    tab=[{"V":0.0,"Q":36.0,"dr":10.0/1024**2,"ds":0.0/1024**2,"dsw":(10.0)/1024**2,"CR":1.0,"Г":4.0,"P":0.67,
    "gr":0,"op":0,"I":0,"dagr":0},
    {"V":0.0,"Q":200.0,"dr":10.0/1024**2,"ds": 0.0/1024**2,"dsw": (10.0)/1024**2, "CR": 1.0, "Г": 4.0, "P":0.9,
    "gr":0,"op":0,"I":0,"dagr":0},
    {"V":0.0,"Q":8500.0,"dr":10.0/1024**2,"ds": 0.0/1024**2,"dsw": (10.0)/1024**2, "CR": 1.0, "Г": 4.0, "P":0.8,
    "gr":0,"op":0,"I":0,"dagr":0},
    {"V":0.0,"Q":AD["Q"],"dr":(65.4-ZA[9])/1024**2,"ds":(39.4-0.65*ZA[10])/0.35/1024**2,"dsw": (53.55)/1024**2, "CR": 1.0, "Г": 0.0, "P":0.0,
    "gr":0,"op":0,"I":0,"dagr":0},
    {"V":0.0,"Q":AD["Q"],"dr":ZA[9]/1024**2,"ds": ZA[10]/1024**2,"dsw": (11.85)/1024**2, "CR": 1.0, "Г": 0.0, "P":1,
    "gr":0,"op":0,"I":0,"dagr":0}]
    # для табл. вн ключей и факта -"dr":53.55/1024**2, "dr":11.85/1024**2    "ds": (66.5)/1024**2, "ds": (24.8)/1024**2
    PP=1; Sds=tab[n]["ds"]
    for x in tab[0:n]:
        PP*=x["P"]    # произведение вероятностей
        Sds+=x["ds"]  # сумма значений ds
    tab[n]["P"]=PP    # сохранить в tab для таблицы внешних ключей
    tab[n]["ds"]=Sds   # сохранить в tab для таблицы внешних ключей
    # ------------------------------------------------------------
    # VP -0.7·0.66·VКR - порог копирования в буфер задачи Reduce в Мбайт,
    VP=0.7*0.66*VKR
    # Программа вычисления времени тиражирования
    def Ttir(N,NM,V12,mN1,mN2):
        return ((N-1)*V12*NM)/min(mN1,mN2)
    # Программа вычисления V или Q (в узле)
    def VQ(listV, i=0, nx=n):
        return sum([x[0]*x[1]*x[2] for x in listV[i:nx]])
    # Программа вычисления TRWdD
    def TRWdD(V,mRWdD,LR=L):
        return V/mRWdD/LR
    # Программа вычисления TP
    def TP(listTP,tp=t,i=0, nx=n,LR=L):
        return sum([x[0]*x[1] for x in listTP[i:nx]])*tp/LR
    # программа вычисления PxQ
    def PQ(listPQ, nx=n):
        return sum([x[0]*x[1] for x in listPQ[0:nx]])
    # Время выполнения фазы Shuffle
    def TNSH(V2,G2,nsplit): # nsplit=V1/VS - число split
        return max([
    #   V2/NM/mdR, # чтение выходных данных экземпляров Map узла, 0 - если из кучи
        V2*(1-1/N)/NM/mPW, # пересылка данных узла в выходной порт коммутатора
        V2*(K1-1)*K1*(N-1)/N/N/N/mN1, # передача в пределах коммутатора
        V2*(N-K1)*(N-1)/N/N/mN2, # передача по кольцу
        V2 *(1-1/N)/NR/mPR, # приём данных всеми экз Reduce узла из вх. порта коммут
        t*6.5*kr*(G2/s)*math.log(math.ceil(min(VP,V2/s)/(V2/nsplit/s)),2),#сортировка-объединение
        V2/NR/mdW # сохранение файлов на диске
        ])

    # ------------------ЗАДАНИЕ 1-------------------------------------
    # вычисление nsplit - число split, x["V"] - объём упакованных таблиц
    nsplit=0
    for x in tab[n:n+m]:
        y=x["Q"]*x["dr"]/x["CR"]
        x["V"]=y # сохранить объём всей таблицы
        nsplit+=math.ceil(y/VS)  # накпливать общее число split
    NM_SAVE=NM # сохранить NM
    NM=min(NM,math.ceil(nsplit/L)) # новый NM: NM не может быть больше nsplit/L
    #________________________________________________
    #=======
    T11= TNZ # время распространения функций Map и Reduce
    # ФАЗА MAP
    #________________________________________________ Шаг 1 Задания 1
    # время чтения упакованных таблиц измерений с диска
    T1D1=0 # время чтения таблиц измерений с диска
    for x in tab[0:n]:
        x["V"]=x["Q"]*x["dr"]/x["CR"]
        T1D1+=TRWdD(x["V"],mDR,1)
    # распаковка и фильтрация записей таблиц измерений в процессоре
    T2P1=0
    for x in tab[0:n]:
        if x["CR"]>1:
            list1 = [[x["Q"],x["dsw"]/x["CR"]]]
            T2P1+=TP(list1,1/mPDC,0,1,1) # распаковка
    list1 = [[x["Q"],x["Г"]]for x in tab[0:n]]
    T3P1=TP(list1,t,0,n,1) # фильтрация
    #________________________________________________ Шаг 2 Задания 1
    # время чтения упакованных таблиц фактов с диска
    T1D=0 # время чтения таблиц фактов с диска
    for x in tab[n:n+m]:
        T1D+=TRWdD(x["V"]/NM,mDR)
    # распаковка и фильтрация записей таблиц фактов в процессоре
    T2P=0
    for x in tab[n:n+m]:
        if x["CR"]>1:
            list1 = [[x["Q"]/NM,x["dsw"]/x["CR"]]]
            T2P+=TP(list1,1/mPDC,0,1,L) # распаковка
    list1 = [[x["Q"]/NM,x["Г"]]for x in tab[n:n+m]]
    T3P=TP(list1,t,0,m,L) # фильтрация
    #------------------------------------------------
    # Сортировка ключей в  буфере и их последующая запись на диск
    list1=[[x["Q"]/NM,x["P"],1]for x in tab[n:n+m]]
    Q12=VQ(list1,0,m) # число записей, помещаемых в выходной поток на узел Map
    split1=math.ceil(nsplit/NM)       # число split на узел
    r12=math.ceil(Q12/split1/QM) # количество файлов  на split
    Gsort12=6.5*Q12*math.log(math.ceil(Q12/split1/r12/s),2)
    list1=[[1,Gsort12]]
    T4P=TP(list1,t,0,1) # время сортировки
    list1=[[x["Q"]/NM,x["P"],x["ds"]]for x in tab[n:n+m]]
    V12=VQ(list1,0,m)   # объем данных в выходном потоке на узел Map
    T5d=TRWdD(V12,mdW) # время записи на локальный диск
    #========
    T12=T1D1+T2P1+T3P1+max(T1D+T2P+T3P,T4P+T5d) # время 2-го шага Задания 1
    #________________________________________________ Шаг 3 Задания 1 (выполняется, если r12>1)
    #========
    T13=0
    # Чтение записей и сортировка слиянием
    if r12>1 :
        Gmerge13= 2.5*(r12-1)+4
        T6d=TRWdD(V12,mdR) # время чтения с локального диска
        list1=[[Q12,Gmerge13]]
        T7P=TP(list1,t,0,1) # время сортировки слиянием в ОП
        T8d=TRWdD(V12,mdW) # время записи на локальный диск
        #========
        T13=max(T6d+T7P,T8d) # время 3-го шага Задания 1
    # ВРЕМЯ ВЫПОЛНЕНИЯ ЗАДАНИЯ 1
    T1MAP=T12+T13
    #===========
    T1=T11+T1MAP

    # ------------------ЗАДАНИЕ 2------------------------------------
    # вычисление времени тиражирования
    Tt = Ttir(N,NM,V12,mN1,mN2)
    # вычисление nsplit - число split, x["V"] - объём упакованных таблиц
    nsplit = 0
    for x in tab[n:n + m]:
        y = x["Q"] * x["dr"] / x["CR"]
        x["V"] = y  # сохранить объём всей таблицы
        nsplit += math.ceil(y / VS)  # накпливать общее число split
    NM_SAVE = NM  # сохранить NM
    NM = min(NM, math.ceil(nsplit / L))  # новый NM: NM не может быть больше nsplit/L
    # ________________________________________________
    # =======
    T21 = TNZ  # время распространения функций Map и Reduce
    # ФАЗА MAP
    # ________________________________________________ Шаг 1 Задания 1
    # время чтения упакованных таблиц измерений с диска
    T1D1 = 0  # время чтения таблиц измерений с диска
    for x in tab[0:n]:
        x["V"] = x["Q"] * x["dr"] / x["CR"]
        T1D1 += TRWdD(x["V"], mDR, 1)
    # распаковка и фильтрация записей таблиц измерений в процессоре
    T2P1 = 0
    for x in tab[0:n]:
        if x["CR"] > 1:
            list1 = [[x["Q"], x["dsw"] / x["CR"]]]
            T2P1 += TP(list1, 1 / mPDC, 0, 1, 1)  # распаковка
    list1 = [[x["Q"], x["Г"]] for x in tab[0:n]]
    T3P1 = TP(list1, t, 0, n, 1)  # фильтрация
    # ________________________________________________ Шаг 2 Задания 1
    # время чтения упакованных таблиц фактов с диска
    T1D = 0  # время чтения таблиц фактов с диска
    for x in tab[n:n + m]:
        T1D += TRWdD(x["V"] / NM, mDR)
    # распаковка и фильтрация записей таблиц фактов в процессоре
    T2P = 0
    for x in tab[n:n + m]:
        if x["CR"] > 1:
            list1 = [[x["Q"] / NM, x["dsw"] / x["CR"]]]
            T2P += TP(list1, 1 / mPDC, 0, 1, L)  # распаковка
    list1 = [[x["Q"] / NM, x["Г"]] for x in tab[n:n + m]]
    T3P = TP(list1, t, 0, m, L)  # фильтрация
    # ------------------------------------------------
    # Сортировка ключей в  буфере и их последующая запись на диск
    list1 = [[x["Q"] / NM, x["P"], 1] for x in tab[n:n + m]]
    Q12 = VQ(list1, 0, m)  # число записей, помещаемых в выходной поток на узел Map
    split1 = math.ceil(nsplit / NM)  # число split на узел
    r12 = math.ceil(Q12 / split1 / QM)  # количество файлов  на split
    Gsort12 = 6.5 * Q12 * math.log(math.ceil(Q12 / split1 / r12 / s), 2)
    list1 = [[1, Gsort12]]
    T4P = TP(list1, t, 0, 1)  # время сортировки
    list1 = [[x["Q"] / NM, x["P"], x["ds"]] for x in tab[n:n + m]]
    V12 = VQ(list1, 0, m)  # объем данных в выходном потоке на узел Map
    T5d = TRWdD(V12, mdW)  # время записи на локальный диск
    # ========
    T22 = T1D1 + T2P1 + T3P1 + max(T1D + T2P + T3P, T4P + T5d)  # время 2-го шага Задания 1
    # ________________________________________________ Шаг 3 Задания 1 (выполняется, если r12>1)
    # ========
    T23 = 0
    # Чтение записей и сортировка слиянием
    if r12 > 1:
        Gmerge13 = 2.5 * (r12 - 1) + 4
        T6d = TRWdD(V12, mdR)  # время чтения с локального диска
        list1 = [[Q12, Gmerge13]]
        T7P = TP(list1, t, 0, 1)  # время сортировки слиянием в ОП
        T8d = TRWdD(V12, mdW)  # время записи на локальный диск
        # ========
        T23 = max(T6d + T7P, T8d)  # время 3-го шага Задания 1
    # ФАЗА SHUFFLE
    # ________________________________________________ Шаг 4 Задания 1
    # =======
    T24 = TNSH(V12 * NM, Q12 * NM, nsplit)  # время 4-го шага Задания 1
    # ФАЗА REDUCE
    # ________________________________________________ Шаг 5 Задания 1
    V15 = V12 * NM / NR  # объём аписей на узел с Reduce
    Q15 = Q12 * NM / NR  # число записей на узел с Reduce
    #   T9d=TRWdD(V15,mdR,R) # время чтения с локального диска
    T9d = 0.0  # если читается из кучи
    q15 = math.ceil(V12 * NM / s / VP)  # число файлов для слияния экземпляром Reduce
    r15 = math.ceil(q15 / u)
    T10P = 0
    T11d = 0
    if q15 > 1:
        Gmerge15 = 2.5 * (min(q15, u) - 1) + 4
        list1 = [[Q15, Gmerge15]]
        T10P = TP(list1, t, 0, 1, R)  # время сортировки слиянием в ОП
        if r15 > 1:
            T11d = TRWdD(V15, mdW, R)  # время записи на локальный диск
    # =========
    T25 = max(T9d + T10P, T11d)  # время 5-го шага Задания 1
    # ________________________________________________ Шаг 6 Задания 1
    T12d = 0
    T13P = 0
    if r15 > 1:
        T12d = TRWdD(V15, mdR, R)  # время чтения с локального диска
        Gmerge16 = 2.5 * (r15 - 1) + 4
        list1 = [[Q15, Gmerge16]]
        T13P = TP(list1, t, 0, 1, R)  # время сортировки слиянием в ОП
    # обработка групп функцией Reduce
    PP1 = 1
    for x in tab[n:n + m]:
        PP1 *= x["P"]  # произведение вероятностей
    Q16 = PP1 * tab[n]["Q"] / NM  # Число-групп записей, помещаемых в выходной файл на один Map
    # вычисление средней длины записи l16
    l16 = 8 / 1024 ** 2
    for x in tab[n:n + m]:
        l16 += x["ds"]
    # вычисление объёма файла на узел Мбайт
    V16 = Q16 * l16
    T14d = TRWdD(V16, mDW, R)  # время записи в файл HDFS (Ф1)
    # ==========
    T26 = max(T12d + T13P, T14d)  # время 6-го шага Задания 1
    # ВРЕМЯ ВЫПОЛНЕНИЯ ЗАДАНИЯ 1
    T2MAP = T22 + T23
    T2SHUFFLE = T24
    T2REDUCE = T25 + T26
    # ===========
    if L < nsplit / NM:
        rb = L / (nsplit / NM)  # учитывает пересечение map и shuffle
    else:
        rb = 1
    T2 = T21 + T2MAP * rb + T2SHUFFLE + T2REDUCE
    # ===========
    Titog = T1 + Tt + T2
    AD["ТМРАБ"] = Titog
    return 0