import os

from bs4 import BeautifulSoup
import pandas as pd
import re
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
from tqdm import tqdm
import random
from parser_app.logic.handlers.tools import wspex, wspex_space, get_proxy
from parser_app.logic.global_status import Global
from fake_useragent import UserAgent
import requests
import ssl

ssl._create_default_https_context = ssl._create_unverified_context

class OzonHandler():
    # def option_chrome(self, proxy):
        # chromeOptions = webdriver.ChromeOptions()
        # chromeOptions.add_argument('--proxy-server=%s' % proxy)
        # return chromeOptions

    def get_proxy(self):  # опционально, если понадобится прокси
        success = False
        while True:
            driver = webdriver.Chrome(executable_path=Global().path_chromedriver)
            driver.get("https://hidemyna.me/ru/proxy-list/?maxtime=300&ports=3128..")
            while True:
                # time.sleep(1)
                if "maxtime" in driver.page_source:
                    ip_list = re.findall(r'\d{2,3}[.]\d{2,3}[.]\d{2,3}[.]\d{2,3}', driver.page_source)
                    break
            driver.quit()

            for it in range(5):
                print('it =', it)
                proxy = random.choice(ip_list[1:]) + ":3128"
                success = False

                driver = webdriver.Chrome(executable_path=Global().path_chromedriver,
                                          chrome_options=Global().chrome_options)
                driver.get("https://ozon.ru")
                try:
                    WebDriverWait(driver, 10).until(
                        EC.presence_of_element_located((By.ID, "__nuxt"))
                    )
                    success = True
                    break
                finally:
                    driver.quit()
                if success == True:
                    break

            if success == True:
                break
            else:
                continue
        print('good proxy: {}'.format(proxy))
        driver.quit()
        return (proxy)

    def tnout(self, s):  # убрать \n и \t
        a = re.sub('\n', '', ' '.join(s.split()))
        a = re.sub('\t', '', ' '.join(a.split()))
        return a

    def extract_products(self, max_prod=200):

        path_sfb = os.path.join(Global().base_dir, 'description', 'urls.csv')
        sfb_df = pd.read_csv(path_sfb, sep=';', index_col='id')

        list_urls = sfb_df.fillna('')[sfb_df.fillna('')['URL'].str.contains('ozon')]['URL'].values

        res = pd.DataFrame(columns=['date', 'type', 'category_id', 'category_title',
                                    'site_title', 'price_new', 'price_old', 'site_unit',
                                    'site_link', 'site_code'])

        # proxy = self.get_proxy()
        # options = webdriver.ChromeOptions()
        # proxy = get_proxy('http://ozon.ru') # если понадобится прокси
        # options.add_argument('--headless')
        # options.add_argument('--disable-gpu')
        # options.add_argument('--proxy-server=%s' % proxy)

        driver = webdriver.Chrome(executable_path=Global().path_chromedriver,
                                  chrome_options=Global().chrome_options)  # , chrome_options=self.option_chrome(proxy))

        store = 'ozon'
        driver.implicitly_wait(30)

        id_n = -1

        for url in tqdm(list_urls[id_n + 1:]):
            flag = 0

            id_n += 1

            driver.get(url)
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight*0.01);")

            category_title = sfb_df[sfb_df.fillna('')['URL'].str.contains('ozon')]['cat_title'].iloc[id_n]
            print('\n{} ...'.format(category_title))
            offset = 0

            soup = BeautifulSoup(driver.page_source, 'lxml')
            problem_array = []

            i = 0

            page_n = 0
            # print(url)

            while True:

                tiles_list = soup.findAll('div', {'class': 'tile'})[offset:]  # контейнер для одного продукта
                try:
                    n = int(re.search('\d+', re.search('\d+ товар[а-я]*', soup.text)[0])[0])
                except:
                    try:
                        n = int(re.search('\d+', soup.find('div', {'class': 'search-title'}).text)[0])
                    except:
                        print("ACHTUNG! category {} has not been parsed".format(category_title))
                        continue
                # print('amount of items: ', n)

                for tile in tiles_list:
                    i += 1
                    price_dict = dict()
                    # print(tile)

                    try:
                        price_dict['price_old'] = tile.find('div', {'data-test-id': 'tile-discount'}).text
                        # print('price old:', price_dict['price_old'])
                        price_dict['price_old'] = int(re.search('\d+', wspex(price_dict['price_old']))[0])
                    except:
                        price_dict['price_old'] = ''

                    price_dict['site_unit'] = 'шт.'
                    price_dict['site_code'] = store
                    price_dict['category_id'] = int(
                        sfb_df.fillna('')[sfb_df.fillna('')['URL'].str.contains('ozon')].index[id_n])
                    # print('category_id: ',price_dict['category_id'])
                    price_dict['date'] = Global().date
                    price_dict['type'] = 'non-food'

                    try:
                        price_dict['site_title'] = self.tnout(tile.find('a', {'data-test-id': "tile-name"}).text)
                    except:
                        problem_array.append(url)
                        print('OOPS! url {} has not parsed site title'.format(url))
                        break
                    price_dict['category_title'] = category_title
                    price_dict['price_new'] = tile.find('span', {'class': 'total-price'}).text
                    price_dict['price_new'] = int(re.match('\d+', self.tnout(wspex(price_dict['price_new'])))[0])
                    if tile.find('a', {'class': 'full-cover-link'}) == None:
                        price_dict['site_link'] = ''
                        print("ACHTUNG! link has not parsed for site_title: {}".format(price_dict['site_title']))
                    else:
                        price_dict['site_link'] = 'https://www.ozon.ru' + tile.find('a',
                                                                                {'class': 'full-cover-link'}).get(
                            'href')
                    '''print('site_title[{}]: {}\nprice_new: {}\nprice_old: {}\n\n'.format(i,price_dict['site_title'],
                                                                                price_dict['price_new'],
                                                                                price_dict['price_old']))'''
                    res = res.append(price_dict, ignore_index=True)

                if i >= n or i >= max_prod or flag == 1:
                    print('   parsing has ended!')
                    break

                offset = offset + len(tiles_list)

                if offset % 280 == 0 and offset != 0:
                    page_n += 11
                    url = url + '&page={}'.format(str(page_n))
                    driver.get(url)
                    print('\n   loading url:{}'.format(url))
                    offset = 0
                    while True:
                        time.sleep(1)

                        soup = BeautifulSoup(driver.page_source, 'lxml')

                        if soup.findAll('div', {'class': 'tile'}) != []:
                            break
                else:

                    scheight = 0.9

                    while True:

                        driver.execute_script("window.scrollTo(0, document.body.scrollHeight*{});".format(scheight))

                        soup = BeautifulSoup(driver.page_source, 'lxml')

                        if soup.findAll('div', {'class': 'tile'})[offset:] != []:
                            print("  offset: {}".format(offset))
                            break
                        if scheight < 1:
                            scheight += 0.01
                        else:
                            print('WARNING! Scrolling has not been executed (we are here)')
                            flag = 1
                            break

                        print(scheight)
                        time.sleep(1)

        return res

    def extract_product_page(self):
        site_code = 'ozon'
        desc_df = Global().desc_df
        links_df = Global().links
        links_df = links_df[links_df['site_link'].str.contains(site_code)]

        if Global().max_links != None:
            links_df = links_df.iloc[:Global().max_links]
        category_ids = links_df.category_id.unique()
        res = pd.DataFrame(columns=['date', 'type', 'category_id', 'category_title',
                                    'site_title', 'price_new', 'price_old', 'site_unit',
                                    'site_link', 'site_code'])
        # options = webdriver.ChromeOptions()
        # proxies = get_proxy('https://www.ozon.ru/')
        # options.add_argument('--headless')
        # options.add_argument('--proxy-server=%s' % proxy)
        if Global().is_selenium_ozon is True:
            driver = webdriver.Chrome(executable_path=Global().path_chromedriver,
                                      chrome_options=Global().chrome_options)  #, chrome_options=self.option_chrome(proxy))
        ua = UserAgent()
        header = {'User-Agent': str(ua.chrome)}
        proxies = None

        h1_class = 'b4j'
        price_new_class_sale = 'b4u8 b4w0'
        price_new_class = 'b4u8'
        price_old_class = 'b4v2'
        for cat_id in tqdm(category_ids):  # испр
            url_list = links_df[links_df.category_id == cat_id].site_link.values
            category_title = desc_df.loc[cat_id, 'cat_title']
            print("{}... ".format(category_title))

            i = 0

            while i + 1 <= len(url_list):

                href_i = url_list[i]
                print(href_i)
                if Global().is_selenium_ozon is True:
                    driver.get(href_i)
                    soup = BeautifulSoup(driver.page_source, 'lxml')
                else:
                    try:
                        # time.sleep(3)
                        if proxies is not None:
                            r = requests.get(href_i, proxies=proxies, headers=header)  # CRITICAL
                        else:
                            r = requests.get(href_i, headers=header)
                    except:
                        while True:
                            print('im here!')
                            try:
                                proxies = get_proxy(href_i)
                                time.sleep(3)
                                r = requests.get(href_i, proxies=proxies, headers=header)
                                if r.status_code == 200:
                                    break
                            except:
                                continue
                    html = r.content
                    soup = BeautifulSoup(html, 'lxml')

                i += 1

                # print(soup)
                price_dict = dict()
                price_dict['date'] = Global().date
                price_dict['site_code'] = site_code
                price_dict['category_id'] = cat_id
                price_dict['category_title'] = category_title

                try:
                    if soup.find('h1', {'class': h1_class}) is not None:
                        price_dict['site_title'] = wspex_space(soup.find('h1', {'class': h1_class}).text)

                    print('site_title:', price_dict['site_title'])
                except:
                    print('except sitetitle not found')
                    if 'Такой страницы не существует' in soup.text:
                        print('Такой страницы не существует!')
                        continue
                    # i -= 1
                    if soup.find('li', {'class': 'links-item'}) is None:
                        while True:
                            proxies = get_proxy(href_i)
                            time.sleep(3)
                            r = requests.get(href_i, proxies=proxies, headers=header)
                            if r.status_code == 200:
                                break
                            else:
                                print('r.status_code:', r.status_code)
                    continue

                # div_new = soup.find('span', {'data-test-id': 'saleblock-first-price'})
                # print('soup:\n', soup)
                # if 'Товар закончился' in soup.text:
                # print('Товар закончился!')
                # continue

                div_new = soup.find('span', {'class': price_new_class_sale})

                if div_new is None:
                    div_new = soup.find('span', {'class': price_new_class})

                if div_new is None:
                    print('Товар закончился!\n')
                    continue

                if re.search('\d+', wspex(div_new.text)) is None:
                    print('Товар закончился!\n')
                    continue
                # print('din_new:\n', div_new)
                '''
                soup.find('span', {
                'class': 'price-number'})
                '''

                div_old = soup.find('span', {'class': price_old_class})

                if div_old is not None:
                    price_dict['price_old'] = int(re.search('\d+', wspex(div_old.text))[0])
                else:
                    price_dict['price_old'] = ''

                price_dict['price_new'] = int(re.search('\d+', wspex(div_new.text))[0])

                price_dict['site_unit'] = 'шт.'
                price_dict['site_link'] = href_i  # показывает название товара и ссылку на него
                price_dict['type'] = 'non-food'
                print('price_new: {}\nprice_old: {}\nunit: {}\n'.format(
                    price_dict['price_new'],
                    price_dict['price_old'],
                    price_dict['site_unit']))
                res = res.append(price_dict, ignore_index=True)

        print('OZON has successfully parsed')
        return res


from collections import defaultdict

def getHint(secret: str, guess: str):
    B, C = 0, 0
    sDic = defaultdict(int)
    gDic = defaultdict(int)

    for s, g in zip(secret, guess):
        if s == g:
            B += 1
        else:
            sDic[s] += 1
            gDic[g] += 1

    for i in gDic:
        if i in sDic:
            C += min(sDic[i], gDic[i])

    return [B, C]

n = int(input())
d = {str(i): 0 for i in range(1, 10)}
arr = []
for i in range(n):
    inputs = input().split()
    guess = inputs[0]
    bulls = int(inputs[1])
    cows = int(inputs[2])
    arr.append([guess, bulls, cows])
for i in range(10000):
    s = str(i)
    s = '0' * (4 - len(s)) + s
    k = 0
    for g, b, c in arr:
        bb, cc = getHint(s, g)
        if bb == b and cc == c:
            k += 1
    if k == len(arr):
        print(s)
        exit()


import numpy as np
import os
import datetime as dt

np.random.seed(1124)
root_dir = os.getcwd()
data_dir = root_dir + '/Data/'
outdata_dir = root_dir + '/Output/'
outplot_dir = root_dir + '/Plot/'

# Global parameters
# coins = ['gemini_BTC', 'gemini_ETH', 'BTC', 'ETH', 'LTC', 'XRP', 'BCH']

coins = ['gemini_BTC', 'gemini_ETH']
freqs = ['5min']
cvs = [3]
alphas = [0.9999]
sample_num = 288
tz_lag = 0
split_date = dt.date(2018, 1, 1)
rv_names = ['RV', 'Log_RV', 'Sqrt_RV']  # 3 forms of RV
# filter_jumps = ['AllJump', 'ConJump', 'NoJump']  #
filter_jumps = ['AllJump']
horizons = [1, 7, 30]
expect_excess_returns = [0.05, 0.08]

model_names = ['HAR',
               'HAR_RVJ', 'HAR_RVJs',
               'HAR_RVTJ', 'HAR_RVTJs',
               'HAR_CJ', 'HAR_CJs',
               'HAR_TCJ', 'HAR_TCJs',
               'HAR_Exp_RV_J', 'HAR_Exp_RV_Js',
               'HAR_Exp_RV_TJ', 'HAR_Exp_RV_TJs',
               'HAR_Exp_CJ', 'HAR_Exp_CJs',
               'HAR_Exp_TCJ', 'HAR_Exp_TCJs']

# Delete some of the regression results, optional
col_to_del = [
    'HAR_RVJ',
    'HAR_RVTJ',
    'HAR_CJ',
    'HAR_TCJ',
    'HAR_Exp_RV_J',
    'HAR_Exp_RV_TJ',
    'HAR_Exp_CJ',
    'HAR_Exp_TCJ',
]


import cv2
import numpy as np
import os
import time
import scipy.io as sio
import matplotlib.pyplot as plt
import math
import main_functions as main

def get_mini_batch(im_train, label_train, batch_size):
    # TO DO
    mini_batch_x = []
    mini_batch_y = []

    perm = np.random.permutation(im_train.shape[1])

    for i in range(0, len(perm), batch_size):
        batch_x = []
        batch_y = []
        for j in range(batch_size):
            if (i+j < len(perm)):
                batch_x.append(im_train[:, perm[i+j]])
                encoding = np.zeros(10)
                encoding[label_train[0, perm[i+j]]] = 1
                batch_y.append(encoding)

        mini_batch_x.append(np.asarray(batch_x))
        mini_batch_y.append(np.asarray(batch_y))

    return mini_batch_x, mini_batch_y

def fc(x, w, b):
    # TO DO
    y = np.matmul(w, x) + b
    return y

def fc_backward(dl_dy, x, w, b, y):
    # TO DO
    dl_dx = np.matmul(dl_dy, w)

    dl_dw = np.outer(dl_dy , x).reshape(w.shape)

    dl_db = dl_dy
    return dl_dx, dl_dw, dl_db

def loss_euclidean(y_tilde, y):
    # TO DO
    l = np.linalg.norm(y - y_tilde)**2

    dl_dy = ((y_tilde - y) * 2).T
    return l, dl_dy

def loss_cross_entropy_softmax(x, y):
    # TO DO

    xrel = x - x.max()
    y_tilde = np.exp(xrel) / np.sum(np.exp(xrel))

    l = - np.sum(y * np.log(y_tilde+1))

    dl_dy = (y_tilde - y).T
    return l, dl_dy

epsilon = 0.9

def relu(x):
    # TO DO
    y = np.where(x>0, x, x*epsilon)
    return y

def relu_backward(dl_dy, x, y):
    # TO DO
    dl_dx = np.where(dl_dy>0, dl_dy, dl_dy*epsilon)
    return dl_dx

def conv(x, w_conv, b_conv):
    # TO DO
    H, W, C1 = x.shape
    h, w, _, C2 = w_conv.shape

    h_pad = int(h/2)
    w_pad = int(w/2)
    x_padded = np.pad(x, ((h_pad, h_pad), (w_pad, w_pad), (0,0)))

    y = np.zeros((H, W, C2))

    for c in range(C2):
        for i in range(h_pad, x_padded.shape[0] - h_pad):
            for j in range(w_pad, x_padded.shape[1] - w_pad):
                inp = x_padded[(i - h_pad):(i + h_pad+1), (j - w_pad):(j + w_pad+1), :]
                convolved = np.sum(np.multiply(inp, w_conv[:,:,:,c])) + b_conv[c]
                y[i - h_pad, j - w_pad, c] = convolved

    return y

def conv_backward(dl_dy, x, w_conv, b_conv, y):
    # TO DO
    H, W, C1 = x.shape
    h, w, _, C2 = w_conv.shape

    dl_dw = np.zeros(w_conv.shape)
    dl_db = np.zeros(b_conv.shape)

    h_pad = int(h/2)
    w_pad = int(w/2)
    x_padded = np.pad(x, ((h_pad, h_pad), (w_pad, w_pad), (0,0)))

    for c2 in range(C2):
        L = dl_dy[:, :, c2]
        dl_db[c2] = np.sum(L)
        for c1 in range(C1):
            for i in range(h):
                for j in range(w):
                    X = x_padded[i: i + H, j:j + W, c1]
                    dl_dw[i, j, c1, c2] = np.sum(np.multiply(L, X))
    dl_db = dl_db.reshape((1,3))
    return dl_dw, dl_db

def pool2x2(x):
    # TO DO
    H, W, C = x.shape
    y = np.zeros((int(H/2), int(W/2), C))

    H = int(H/2) * 2
    W = int(W/2) * 2

    for c in range(C):
        pool = x[:,:,c]
        for h in range(0,H,2):
            for w in range(0,W,2):
                y[int(h/2), int(w/2), c] = np.amax(pool[h:h+2, w:w+2])
    return y

def pool2x2_backward(dl_dy, x, y):
    # TO DO
    H, W, C = x.shape
    dl_dx = np.zeros(x.shape)

    H = int(H/2) * 2
    W = int(W/2) * 2

    for c in range(C):
        pool = x[:,:,c]
        for h in range(0,H,2):
            for w in range(0,W,2):
                max_ind = np.argmax(pool[h:h+2, w:w+2])
                dl_dx[h+int(max_ind/2), w+max_ind%2, c] = dl_dy[int(h/2), int(w/2), c]
    return dl_dx

def flattening(x):
    # TO DO
    # y = x.reshape((np.size(x), 1))
    y = x.reshape(-1, order='F')
    y = y.reshape((y.shape[0], 1))
    return y

def flattening_backward(dl_dy, x, y):
    # TO DO
    dl_dx = dl_dy.reshape(x.shape, order='F')
    return dl_dx

def train_slp_linear(mini_batch_x, mini_batch_y):
    # TO DO
    # set rates
    gamma = 0.001
    lamda = 0.9

    m = 196
    n = 10

    # initialize weights with random noise
    w = np.random.rand(n, m)
    b = np.random.rand(n, 1)

    k = 0
    nIters = 2000
    loss = []

    for iIter in range(nIters):
        if (iIter + 1) % 1000 == 0:
            gamma = lamda * gamma

        dL_dw = np.zeros(w.shape)
        dL_db = np.zeros(n)
        mbl = 0

        batch_size = len(mini_batch_x[k])

        for j in range(batch_size):
            # label prediction
            x = mini_batch_x[k][j].reshape((m,1))
            y_tilde = fc(x, w, b);
            y = mini_batch_y[k][j].reshape((n,1))
            # loss computation
            l, dl_dy = loss_euclidean(y_tilde, y)
            mbl += np.abs(l)
            # gradient back-propagation
            dl_dx, dl_dw, dl_db = fc_backward(dl_dy, x, w, b, y)
            dL_dw = dL_dw + dl_dw
            dL_db = dL_db + dl_db

        k += 1
        if (k == len(mini_batch_x)):
            k = 0

        loss.append(mbl)
        w -= gamma * dL_dw
        b -= gamma * dL_db.reshape(b.shape)

    # plt.xlabel('iterations', fontsize=18)
    # plt.ylabel('training loss', fontsize=16)
    # plt.plot(loss)
    # plt.show()

    return w, b

def train_slp(mini_batch_x, mini_batch_y):
    # TO DO
    # set rates
    gamma = 0.01
    lamda = 0.9

    m = 196
    n = 10

    # initialize weights with random noise
    w = np.random.rand(n, m)
    b = np.random.rand(n, 1)

    k = 0
    nIters = 2000
    loss = []

    for iIter in range(nIters):
        if (iIter + 1) % 1000 == 0:
            gamma = lamda * gamma

        dL_dw = np.zeros(w.shape)
        dL_db = np.zeros(n)
        mbl = 0

        batch_size = len(mini_batch_x[k])

        for j in range(batch_size):
            # label prediction
            x = mini_batch_x[k][j].reshape((m,1))
            y_tilde = fc(x, w, b);
            y = mini_batch_y[k][j].reshape((n,1))
            # loss computation
            l, dl_dy = loss_cross_entropy_softmax(y_tilde, y)
            mbl += np.abs(l)
            # gradient back-propagation
            dl_dx, dl_dw, dl_db = fc_backward(dl_dy, x, w, b, y)
            dL_dw = dL_dw + dl_dw
            dL_db = dL_db + dl_db

        k += 1
        if (k == len(mini_batch_x)):
            k = 0

        loss.append(mbl)
        w -= gamma * dL_dw
        b -= gamma * dL_db.reshape(b.shape)

    # plt.xlabel('iterations', fontsize=18)
    # plt.ylabel('training loss', fontsize=16)
    # plt.plot(loss)
    # plt.show()

    return w, b

def train_mlp(mini_batch_x, mini_batch_y):
    # TO DO
    # set rates
    gamma = 0.01
    lamda = 0.9

    m = 196
    n = 10
    p = 30

    # initialize weights with random noise
    w1 = np.random.rand(p, m)
    b1 = np.random.rand(p, 1)
    w2 = np.random.rand(n, p)
    b2 = np.random.rand(n, 1)

    k = 0
    nIters = 20000
    loss = []

    for iIter in range(nIters):
        if (iIter + 1) % 500 == 0:
            gamma = lamda * gamma

        dL_dw1 = np.zeros(w1.shape)
        dL_db1 = np.zeros(p)
        dL_dw2 = np.zeros(w2.shape)
        dL_db2 = np.zeros(n)
        mbl = 0

        batch_size = len(mini_batch_x[k])

        for j in range(batch_size):
            # label prediction
            x = mini_batch_x[k][j].reshape((m,1))
            y = mini_batch_y[k][j].reshape((n,1))

            fc_1 = fc(x, w1, b1);
            # ReLU 1
            relu_1 = relu(fc_1)
            # FC 2
            fc_2 = fc(relu_1, w2, b2)
            # loss computation
            l, dl_dy = loss_cross_entropy_softmax(fc_2, y)
            mbl += np.abs(l)
            # gradient back-propagation
            dl_dx, dl_dw2, dl_db2 = fc_backward(dl_dy, relu_1, w2, b2, fc_2)

            relu_b = relu_backward(dl_dx, fc_1, relu_1)

            dl_dx, dl_dw1, dl_db1 = fc_backward(relu_b, x, w1, b1, fc_1)

            dL_dw1 = dL_dw1 + dl_dw1
            dL_db1 = dL_db1 + dl_db1
            dL_dw2 = dL_dw2 + dl_dw2
            dL_db2 = dL_db2 + dl_db2

        k += 1
        if (k == len(mini_batch_x)):
            k = 0

        loss.append(mbl)
        w1 -= gamma * dL_dw1
        b1 -= gamma * dL_db1.reshape(b1.shape)
        w2 -= gamma * dL_dw2
        b2 -= gamma * dL_db2.reshape(b2.shape)

    # plt.xlabel('iterations', fontsize=18)
    # plt.ylabel('training loss', fontsize=16)
    # plt.plot(loss)
    # plt.show()

    return w1, b1, w2, b2

def train_cnn(mini_batch_x, mini_batch_y):
    # TO DO
    # set rates
    gamma = 0.01
    lamda = 0.9

    m = 196
    n = 10
    p = 30

    # initialize weights with random noise
    w_conv = np.random.rand(3,3,1,3)
    b_conv = np.random.rand(3)
    w_fc = np.random.rand(10, 147)
    b_fc = np.random.rand(10, 1)

    k = 0
    nIters = 10000
    loss = []

    for iIter in range(nIters):
        if (iIter + 1) % 500 == 0:
            gamma = lamda * gamma
        print(iIter)
        dL_dw_conv = np.zeros(w_conv.shape)
        dL_db_conv = np.zeros(3)
        dL_dw_fc = np.zeros(w_fc.shape)
        dL_db_fc = np.zeros(10)
        mbl = 0

        batch_size = len(mini_batch_x[k])

        for j in range(batch_size):
            # label prediction
            x = mini_batch_x[k][j].reshape((14,14,1), order='F')
            y = mini_batch_y[k][j].reshape((n,1))

            conv_1 = conv(x, w_conv, b_conv)
            # print(conv_1.shape)
            # ReLU 1
            relu_1 = relu(conv_1)
            # print(relu_1.shape)
            # FC 2
            pool_1 = pool2x2(relu_1)
            # print(pool_1.shape)
            flatten_1 = flattening(pool_1)
            # print(flatten_1.shape)
            fc_1 = fc(flatten_1, w_fc, b_fc)
            # print(fc_1.shape)
            # loss computation
            l, dl_dy = loss_cross_entropy_softmax(fc_1, y)
            mbl += np.abs(l)
            # print(dl_dy.shape)
            # gradient back-propagation
            dl_dx, dl_dw_fc, dl_db_fc = fc_backward(dl_dy, flatten_1, w_fc, b_fc, fc_1)
            # print(dl_dx.shape)
            flatten_b = flattening_backward(dl_dx, pool_1, flatten_1)

            pool_b = pool2x2_backward(flatten_b, relu_1, pool_1)

            relu_b = relu_backward(pool_b, conv_1, relu_1)

            dl_dw_conv, dl_db_conv = conv_backward(relu_b, x, w_conv, b_conv, conv_1)

            dL_dw_conv = dL_dw_conv + dl_dw_conv
            # dL_db_conv = dL_db_conv + dl_db_conv
            dL_dw_fc = dL_dw_fc + dl_dw_fc
            dL_db_fc = dL_db_fc + dl_db_fc

        k += 1
        if (k == len(mini_batch_x)):
            k = 0

        loss.append(mbl)
        w_conv -= gamma * dL_dw_conv
        # b_conv -= gamma * dL_db_conv.reshape(b_conv.shape)
        w_fc -= gamma * dL_dw_fc
        b_fc -= gamma * dL_db_fc.reshape(b_fc.shape)

    # plt.xlabel('iterations', fontsize=18)
    # plt.ylabel('training loss', fontsize=16)
    # plt.plot(loss)
    # plt.show()
    return w_conv, b_conv, w_fc, b_fc

if __name__ == '__main__':
    # main.main_slp_linear()
    # main.main_slp()
    # main.main_mlp()
    main.main_cnn()

    mnist_train = sio.loadmat('./mnist_train.mat')
    mnist_test = sio.loadmat('./mnist_test.mat')
    im_train, label_train = mnist_train['im_train'], mnist_train['label_train']
    im_test, label_test = mnist_test['im_test'], mnist_test['label_test']
    batch_size = 32
    im_train, im_test = im_train / 255.0, im_test / 255.0
    mini_batch_x, mini_batch_y = get_mini_batch(im_train, label_train, batch_size)


# Name:Pritam Shrestha
# FileName:Non_derivable_itemsets
# Date:06/17/2020
# Course: DSC550-Data Mining
# Professor/Instructor:Brant Abeln
# Description:Non Derivable Itemsest
# Due Date:06/21/20
# Assignment No:2

# In[17]:

import pandas as pd
from itertools import combinations
import traceback                                                      # GV change for traceback.print_exc()

# creating function to pass arguments
def calculate_combinations(itemset, num_combinations):
    # creating list
    list_of_combination = []
    # loop through itemset
    for comb in combinations(itemset, num_combinations):
        # appending in empty list
        list_of_combination.append(comb)
    return list_of_combination

# function to calculate the bound value
def calc_value(st, itemset, dictionary, n):
    # build subsets based on combinations
    value = 0.0
    for num in range(n - 1, 0, -1):
        # build list of combinations
        subsets = calculate_combinations(itemset, num)
        # looping through combinations list
        for comb in subsets:
            # get all items in combination based on items in itemset
            ck = all(item in comb for item in st)
            # increment value by i
            if ck or st == ():
                i = int(dictionary[comb]) * pow(-1.0, (n + 1) - num)
                value += i
    # if combination set is empty, update dictionary values
    if st == ():
        empty = 0
        for dict_value in dictionary.values():
            empty += int(dict_value)
        value += empty * pow(-1.0, (n + 1))

    # returning value
    return value

# function to obtain upper and lower bounds
def evaluate_bounds(itemset, dictionary):
    # set variables to obtain and determin upper and lower bound per itemset
    upper_bounds = []
    lower_bounds = []
    lower_bound = 0
    upper_bound = 0
    n = len(itemset)

    # loop through itemset and break down the combinations into subsets
    for index in range(len(itemset)):
        subsets = calculate_combinations(itemset, index)
        # checking odd or even
        boolean_Odd = (n - len(subsets[0])) % 2
        for comb in subsets:
            # if the length is odd, update upper bound list
            if boolean_Odd:
                upper_bounds.append(calc_value(comb, itemset, dictionary, n))
            # if length is even, update lower bound list
            else:
                lower_bounds.append(calc_value(comb, itemset, dictionary, n))

    # if the maximum number in the lower bound list is less than zero, set lower bound to zero
    if max(lower_bounds) < 0:
        lower_bound = 0
    # if maxium number is 0 or greater, set lower bound to that number
    else:
        lower_bound = max(lower_bounds)

    # set upper bound to the minumum number within the upper bound list
    upper_bound = min(upper_bounds)

    # applying condition for upper and lower bound
    if lower_bound == upper_bound:
        bound = 'This Itemset is derivable'
    else:
        bound = 'This Itemset is non-derivable'

    # returning valuse using format function
    return '{}: [{}, {}] {}'.format(itemset, lower_bound, upper_bound, bound)

# main function for exercise three
def main():
    # reading data as dataframe
    itemset_df = pd.read_csv('itemsets.txt', header=None)
    ndi_df = pd.read_csv('ndi.txt', header=None)

    # converting itemsets to dictionary
    itemset_dict = {}
    for i, itemset_support in enumerate(itemset_df[0]):
        set_support_list = []
        # splitting
        for val in itemset_support.split(' '):
            # passing hypen condition
            if val == '-':
                continue
            else:
                set_support_list.append(val)
        itemset_dict[tuple(set_support_list[:-1])] = set_support_list[-1]
        # processing ndi datasets
    ndi_dict = {}
    # iterating over ndi
    for i, itemset in enumerate(ndi_df[0]):
        ndi_dict[i] = itemset.split(' ')
    for itemset in ndi_dict.values():
        # printing values
        print(evaluate_bounds(itemset, itemset_dict))

if __name__ == '__main__':
    # calling function inside try blck to catch the eror
    try:
        main()
    except Exception as exception:
        print('exception')
        traceback.print_exc()
        print('An exception of type {0} occurred.  Arguments:\n{1!r}'.format(type(exception).__name__, exception.args));
    finally:
        print("finally block is executed whether exception is handled or not!!")


def is_prime(n):
    if n <= 1:
        return False
    if n == 2:
        return True

    for i in range(3, int(n ** 0.5) + 1):
        if n % i == 0:
            return False

    return True

diagonals = 0
primes = 0
l = 1
top_right = top_left = bot_left = 1

for _ in range(100000):
    diagonals += 4

    top_right += (l * 4) - 2
    if is_prime(top_right):
        primes += 1

    top_left += l * 4
    if is_prime(top_left):
        primes += 1

    bot_left += (l * 4) + 2
    if is_prime(bot_left):
        primes += 1

    #print(top_right, top_left, bot_left, primes, diagonals)
    if primes / diagonals < 0.1:
        break

    l += 2
    #bot_right diagonal is always a perfect square, so never prime, and thus no need to calculate it
    #but it would be (l * 4) + 4

print(l)


from random import shuffle

import numpy as np
import scanpy.api as sc
import tensorflow as tf
from data_reader import data_reader

# =============================== downloading training and validation files ====================================
train_path = "../data/train_pbmc.h5ad"
valid_path = "../data/valid_pbmc.h5ad"

import os

print(os.getcwd())
data = sc.read(train_path)

validation = sc.read(valid_path)
# =============================== data gathering ====================================
# training cells
t_in = ['CD8T', 'NK', 'B', 'Dendritic', 'FCGR3A+Mono', 'CD14+Mono']
# heldout cells
t_out = ['CD4T']
dr = data_reader(data, validation, {"ctrl": "control", "stim": "stimulated"}, t_in, t_out)
train_real = dr.train_real_adata
train_real_stim = train_real[train_real.obs["condition"] == "stimulated"]
train_real_ctrl = train_real[train_real.obs["condition"] == "control"]
train_real_stim = train_real_stim.X
ind_list = [i for i in range(train_real_stim.shape[0])]
shuffle(ind_list)
train_real_stim = train_real_stim[ind_list, :]
gex_size = train_real_stim.shape[1]
train_real_ctrl = train_real_ctrl.X
ind_list = [i for i in range(train_real_ctrl.shape[0])]
shuffle(ind_list)
train_real_ctrl = train_real_ctrl[ind_list, :]
eq = min(len(train_real_ctrl), len(train_real_stim))
stim_ind = np.random.choice(range(len(train_real_stim)), size=eq, replace=False)
ctrl_ind = np.random.choice(range(len(train_real_ctrl)), size=eq, replace=False)
##selecting equal size for both stimulated and control cells
train_real_ctrl = train_real_ctrl[ctrl_ind, :]
train_real_stim = train_real_stim[stim_ind, :]
# =============================== parameters ====================================
model_to_use = "../models/STGAN/stgan"
os.makedirs(model_to_use, exist_ok=True)
X_dim = gex_size
z_dim = 100
h_dim = 200
batch_size = 512
inflate_to_size = 100
lambda_l2 = .8
arch = {"noise_input_size": z_dim, "inflate_to_size": inflate_to_size,
        "epochs": 0, "bsize": batch_size, "disc_internal_size ": h_dim, "#disc_train": 1}
X_stim = tf.placeholder(tf.float32, shape=[None, X_dim], name="data_stim")
X_ctrl = tf.placeholder(tf.float32, shape=[None, X_dim], name="data_ctrl")
time_step = tf.placeholder(tf.int32)
size = tf.placeholder(tf.int32)
learning_rate = 0.001
initializer = tf.truncated_normal_initializer(stddev=0.02)
is_training = tf.placeholder(tf.bool)
dr_rate = .5
const = 5

### helper function

def predict(ctrl):
    pred = sess.run(gen_stim_fake, feed_dict={X_ctrl: ctrl, is_training: False})
    return pred

def low_embed(all):
    pred = sess.run(disc_c, feed_dict={X_ctrl: all, is_training: False})
    return pred

def low_embed_stim(all):
    pred = sess.run(disc_s, feed_dict={X_stim: all, is_training: False})
    return pred

# network

def discriminator_stimulated(tensor, reuse=False, ):
    with tf.variable_scope("discriminator_s", reuse=reuse):
        h = tf.layers.dense(inputs=tensor, units=700, kernel_initializer=initializer, use_bias=False)
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(h, dr_rate, training=is_training)
        h = tf.layers.dense(inputs=h, units=100, kernel_initializer=initializer, use_bias=False, )
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        disc = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(disc, dr_rate, training=is_training)

        h = tf.layers.dense(inputs=h, units=1, kernel_initializer=initializer, use_bias=False)
        h = tf.nn.sigmoid(h)

        return h, disc

def discriminator_control(tensor, reuse=False, ):
    with tf.variable_scope("discriminator_b", reuse=reuse):
        h = tf.layers.dense(inputs=tensor, units=700, kernel_initializer=initializer, use_bias=False)
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(h, dr_rate, training=is_training)

        h = tf.layers.dense(inputs=h, units=100, kernel_initializer=initializer, use_bias=False, )
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        disc = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(disc, dr_rate, training=is_training)

        h = tf.layers.dense(inputs=h, units=1, kernel_initializer=initializer, use_bias=False)
        h = tf.nn.sigmoid(h)
        return h, disc

def generator_stim_ctrl(image, reuse=False):
    with tf.variable_scope("generator_sb", reuse=reuse):
        h = tf.layers.dense(inputs=image, units=700, kernel_initializer=initializer, use_bias=False)
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(h, dr_rate, training=is_training)

        h = tf.layers.dense(inputs=h, units=100, kernel_initializer=initializer, use_bias=False)
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(h, dr_rate, training=is_training)

        h = tf.layers.dense(inputs=h, units=50, kernel_initializer=initializer, use_bias=False, )
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(h, dr_rate, training=is_training)

        h = tf.layers.dense(inputs=h, units=100, kernel_initializer=initializer, use_bias=False)
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(h, dr_rate, training=is_training)

        h = tf.layers.dense(inputs=h, units=700, kernel_initializer=initializer, use_bias=False)
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(h, dr_rate, training=is_training)

        h = tf.layers.dense(inputs=h, units=X_dim, kernel_initializer=initializer, use_bias=False, )
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.relu(h)
        return h

def generator_ctrl_stim(image, reuse=False, ):
    with tf.variable_scope("generator_bs", reuse=reuse):
        h = tf.layers.dense(inputs=image, units=700, kernel_initializer=initializer, use_bias=False)
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(h, dr_rate, training=is_training)

        h = tf.layers.dense(inputs=h, units=100, kernel_initializer=initializer, use_bias=False)
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(h, dr_rate, training=is_training)

        h = tf.layers.dense(inputs=h, units=50, kernel_initializer=initializer, use_bias=False, )
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(h, dr_rate, training=is_training)

        h = tf.layers.dense(inputs=h, units=100, kernel_initializer=initializer, use_bias=False)
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(h, dr_rate, training=is_training)

        h = tf.layers.dense(inputs=h, units=700, kernel_initializer=initializer, use_bias=False)
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.leaky_relu(h)
        h = tf.layers.dropout(h, dr_rate, training=is_training)

        h = tf.layers.dense(inputs=h, units=X_dim, kernel_initializer=initializer, use_bias=False, )
        h = tf.layers.batch_normalization(h, axis=1, training=is_training)
        h = tf.nn.relu(h)

        return h

# generator and discriminator

gen_stim_fake = generator_ctrl_stim(X_ctrl)
gen_ctrl_fake = generator_stim_ctrl(X_stim)

recon_ctrl = generator_stim_ctrl(gen_stim_fake, reuse=True)
recon_stim = generator_ctrl_stim(gen_ctrl_fake, reuse=True)

disc_ctrl_fake, _ = discriminator_control(gen_ctrl_fake)
disc_stim_fake, _ = discriminator_stimulated(gen_stim_fake)

disc_ctrl_real, disc_c = discriminator_control(X_ctrl, reuse=True)
disc_stim_real, disc_s = discriminator_stimulated(X_stim, reuse=True)

# computing loss

const_loss_s = tf.reduce_sum(tf.losses.mean_squared_error(recon_ctrl, X_ctrl))
const_loss_b = tf.reduce_sum(tf.losses.mean_squared_error(recon_stim, X_stim))

gen_ctrl_loss = tf.reduce_sum(tf.square(disc_ctrl_fake - 1)) / 2
gen_stim_loss = tf.reduce_sum(tf.square(disc_stim_fake - 1)) / 2

disc_ctrl_loss = tf.reduce_sum(tf.square(disc_ctrl_real - 1) + tf.square(disc_ctrl_fake)) / 2
disc_stim_loss = tf.reduce_sum(tf.square(disc_stim_real - 1) + tf.square(disc_stim_fake)) / 2

gen_loss = const * (const_loss_s + const_loss_b) + gen_ctrl_loss + gen_stim_loss
disc_loss = disc_ctrl_loss + disc_stim_loss

# applying gradients

gen_sb_variables = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope="generator_sb")
gen_bs_variables = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope="generator_bs")
dis_s_variables = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope="discriminator_s")
dis_b_variables = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope="discriminator_b")
with tf.control_dependencies(tf.get_collection(tf.GraphKeys.UPDATE_OPS)):
    update_D = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(disc_loss,
                                                                            var_list=dis_s_variables + dis_b_variables,
                                                                            )
    update_G = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(gen_loss,
                                                                            var_list=gen_sb_variables + gen_bs_variables)
global_step = tf.Variable(0, name='global_step', trainable=False, dtype=tf.int32)
sess = tf.InteractiveSession()
saver = tf.train.Saver(max_to_keep=1)
init = tf.global_variables_initializer().run()

def train(n_epochs, initial_run=True):
    if initial_run:
        print("Initial run")
        print("Training started")
        assign_step_zero = tf.assign(global_step, 0)
        init_step = sess.run(assign_step_zero)
    if not initial_run:
        saver.restore(sess, model_to_use)
        current_step = sess.run(global_step)
    for it in range(n_epochs):
        increment_global_step_op = tf.assign(global_step, global_step + 1)
        step = sess.run(increment_global_step_op)
        current_step = sess.run(global_step)
        batch_ind1 = np.random.choice(range(len(train_real_stim)), size=eq, replace=False)
        mb_ctrl = train_real_ctrl[batch_ind1, :]
        mb_stim = train_real_stim[batch_ind1, :]
        for gen_it in range(2):
            _, g_loss, d_loss = sess.run([update_G, gen_loss, disc_loss],
                                         feed_dict={X_ctrl: mb_ctrl, X_stim: mb_stim, is_training: True})
        _, g_loss, d_loss = sess.run([update_G, gen_loss, disc_loss],
                                     feed_dict={X_ctrl: mb_ctrl, X_stim: mb_stim, is_training: True})
        print(f"Iteration {it}: {g_loss + d_loss}")
        _ = sess.run(update_D, feed_dict={X_ctrl: mb_ctrl, X_stim: mb_stim, is_training: True})
    save_path = saver.save(sess, model_to_use)
    print("Model saved in file: %s" % save_path)
    print(f"Training finished")

def restore():
    saver.restore(sess, model_to_use)

if __name__ == "__main__":
    import sys
    path_to_save = "../results/Figures/Supplemental Figure 4/"
    sc.settings.figdir = path_to_save
    sc.settings.writedir = "../data"
    print(sys.argv[1])
    if sys.argv[1] == "train":
        train(1000, initial_run=True)
    else:
        restore()
    print("model has been trained/restored!")
    adata_list = dr.extractor(data, "CD4T")
    ctrl_CD4T = adata_list[1]
    if sys.argv[1] == "train":
        predicted_cells = predict(ctrl_CD4T.X.A)
        all_Data = sc.AnnData(np.concatenate([adata_list[1].X.A, adata_list[2].X.A, predicted_cells]))
        all_Data.obs["condition"] = ["ctrl"] * len(adata_list[1].X.A) + ["real_stim"] * len(adata_list[2].X.A) + \
                                    ["pred_stim"] * len(predicted_cells)
        all_Data.var_names = adata_list[3].var_names
        all_Data.write("../data/reconstructed/CGAN/cgan_cd4t.h5ad")
    if sys.argv[1] == "latent":
        low_dim = low_embed_stim(train_real.X)
        dt = sc.AnnData(low_dim)
        sc.pp.neighbors(dt)
        sc.tl.umap(dt)
        dt.obs["cell_type"] = train_real.obs["cell_type"]
        dt.obs["condition"] = train_real.obs["condition"]
        sc.pl.umap(dt, color=["cell_type"], show=False, frameon=False
                   , save="_latent_cell_type.png")

        sc.pl.umap(dt, color=["condition"], show=False, frameon=False
                   , save="_latent_condition.png", palette=["#96a1a3", "#A4E804"])

        os.rename(src=os.path.join(path_to_save, "umap_latent_cell_type.png"),
                  dst=os.path.join(path_to_save, f"SupplFig4b_style_transfer_celltype.png"))

        os.rename(src=os.path.join(path_to_save, "umap_latent_condition.png"),
                  dst=os.path.join(path_to_save, f"SupplFig4b_style_transfer_condition.png"))


import sys
_module = sys.modules[__name__]
del sys
display_samples = _module
download_mnist = _module
convert = _module
main = _module
example = _module
main = _module
rpc_parameter_server = _module
main = _module
main = _module
main = _module
rnn = _module
download_saved_models = _module
neural_style = _module
neural_style = _module
transformer_net = _module
utils = _module
vgg = _module
main = _module
main = _module
main = _module
train = _module
main = _module
actor_critic = _module
reinforce = _module
model = _module
train = _module
util = _module
data = _module
dataset = _module
main = _module
model = _module
super_resolve = _module
generate_sine_wave = _module
train = _module
main = _module
data = _module
generate = _module
main = _module
model = _module

from _paritybench_helpers import _mock_config, patch_functional
from unittest.mock import mock_open, MagicMock
from torch.autograd import Function
from torch.nn import Module
import abc, collections, copy, enum, functools, inspect, itertools, logging, math, matplotlib, numbers, numpy, pandas, queue, random, re, scipy, sklearn, string, tensorflow, time, torch, torchaudio, torchtext, torchvision, types, typing, uuid, warnings
import numpy as np
from torch import Tensor
patch_functional()
open = mock_open()
yaml = logging = sys = argparse = MagicMock()
ArgumentParser = argparse.ArgumentParser
_global_config = args = argv = cfg = config = params = _mock_config()
argparse.ArgumentParser.return_value.parse_args.return_value = _global_config
yaml.load.return_value = _global_config
sys.argv = _global_config
__version__ = '1.0.0'
xrange = range
wraps = functools.wraps

import matplotlib.pyplot as plt

import torch

from torchvision import models

import random

import torch.nn as nn

import torch.nn.parallel

import torch.backends.cudnn as cudnn

import torch.optim as optim

import torch.utils.data

import torchvision.datasets as dset

import torchvision.transforms as transforms

import torchvision.utils as vutils

import torch.distributed as dist

from torch.nn.parallel import DistributedDataParallel as DDP

import torch.multiprocessing as mp

import time

import torch.distributed.autograd as dist_autograd

import torch.distributed.rpc as rpc

import torch.nn.functional as F

from torch import optim

from torch.distributed.optim import DistributedOptimizer

from torchvision import datasets

from torchvision import transforms

from functools import wraps

from torch.distributed.rpc import RRef

from torchvision.models.resnet import Bottleneck

import numpy as np

from itertools import count

from torch.distributed.rpc import rpc_sync

from torch.distributed.rpc import rpc_async

from torch.distributed.rpc import remote

from torch.distributions import Categorical

import re

from torch.optim import Adam

from torch.utils.data import DataLoader

import torch.onnx

from collections import namedtuple

import warnings

import torch.optim

import torch.utils.data.distributed

import torchvision.datasets as datasets

import torchvision.models as models

from torch.optim.lr_scheduler import StepLR

import torch.optim as O

from torchtext import data

from torchtext import datasets

import torch.utils.data as data

from math import log10

import torch.nn.init as init

from torchvision.transforms import ToTensor

import matplotlib

from torch import nn

from torch.nn import functional as F

from torchvision.utils import save_image

import math

parser = argparse.ArgumentParser(description='PyTorch Wikitext-2 RNN/LSTM/GRU/Transformer Language Model')

opt = parser.parse_args()

class Generator(nn.Module):

    def __init__(self, ngpu):
        super(Generator, self).__init__()
        self.ngpu = ngpu
        self.main = nn.Sequential(nn.ConvTranspose2d(nz, ngf * 8, 4, 1, 0, bias=False), nn.BatchNorm2d(ngf * 8), nn.ReLU(True), nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf * 4), nn.ReLU(True), nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf * 2), nn.ReLU(True), nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf), nn.ReLU(True), nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False), nn.Tanh())

    def forward(self, input):
        if input.is_cuda and self.ngpu > 1:
            output = nn.parallel.data_parallel(self.main, input, range(self.ngpu))
        else:
            output = self.main(input)
        return output

class Discriminator(nn.Module):

    def __init__(self, ngpu):
        super(Discriminator, self).__init__()
        self.ngpu = ngpu
        self.main = nn.Sequential(nn.Conv2d(nc, ndf, 4, 2, 1, bias=False), nn.LeakyReLU(0.2, inplace=True), nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False), nn.BatchNorm2d(ndf * 2), nn.LeakyReLU(0.2, inplace=True), nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False), nn.BatchNorm2d(ndf * 4), nn.LeakyReLU(0.2, inplace=True), nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False), nn.BatchNorm2d(ndf * 8), nn.LeakyReLU(0.2, inplace=True), nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False), nn.Sigmoid())

    def forward(self, input):
        if input.is_cuda and self.ngpu > 1:
            output = nn.parallel.data_parallel(self.main, input, range(self.ngpu))
        else:
            output = self.main(input)
        return output.view(-1, 1).squeeze(1)

class ToyModel(nn.Module):

    def __init__(self):
        super(ToyModel, self).__init__()
        self.net1 = nn.Linear(10, 10)
        self.relu = nn.ReLU()
        self.net2 = nn.Linear(10, 5)

    def forward(self, x):
        return self.net2(self.relu(self.net1(x)))

class ToyMpModel(nn.Module):

    def __init__(self, dev0, dev1):
        super(ToyMpModel, self).__init__()
        self.dev0 = dev0
        self.dev1 = dev1
        self.net1 = torch.nn.Linear(10, 10)
        self.relu = torch.nn.ReLU()
        self.net2 = torch.nn.Linear(10, 5)

    def forward(self, x):
        x = x
        x = self.relu(self.net1(x))
        x = x
        return self.net2(x)

class Net(nn.Module):

    def __init__(self, upscale_factor):
        super(Net, self).__init__()
        self.relu = nn.ReLU()
        self.conv1 = nn.Conv2d(1, 64, (5, 5), (1, 1), (2, 2))
        self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
        self.conv3 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
        self.conv4 = nn.Conv2d(32, upscale_factor ** 2, (3, 3), (1, 1), (1, 1))
        self.pixel_shuffle = nn.PixelShuffle(upscale_factor)
        self._initialize_weights()

    def forward(self, x):
        x = self.relu(self.conv1(x))
        x = self.relu(self.conv2(x))
        x = self.relu(self.conv3(x))
        x = self.pixel_shuffle(self.conv4(x))
        return x

    def _initialize_weights(self):
        init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv4.weight)

class ParameterServer(nn.Module):

    def __init__(self, num_gpus=0):
        super().__init__()
        model = Net(num_gpus=num_gpus)
        self.model = model
        self.input_device = torch.device('cuda:0' if torch.cuda.is_available() and num_gpus > 0 else 'cpu')

    def forward(self, inp):
        inp = inp
        out = self.model(inp)
        out = out
        return out

    def get_dist_gradients(self, cid):
        grads = dist_autograd.get_gradients(cid)
        cpu_grads = {}
        for k, v in grads.items():
            k_cpu, v_cpu = k, v
            cpu_grads[k_cpu] = v_cpu
        return cpu_grads

    def get_param_rrefs(self):
        param_rrefs = [rpc.RRef(param) for param in self.model.parameters()]
        return param_rrefs

def get_parameter_server(num_gpus=0):
    global param_server
    with global_lock:
        if not param_server:
            param_server = ParameterServer(num_gpus=num_gpus)
        return param_server

def call_method(method, rref, *args, **kwargs):
    return method(rref.local_value(), *args, **kwargs)

def remote_method(method, rref, *args, **kwargs):
    args = [method, rref] + list(args)
    return rpc.rpc_sync(rref.owner(), call_method, args=args, kwargs=kwargs)

class TrainerNet(nn.Module):

    def __init__(self, num_gpus=0):
        super().__init__()
        self.num_gpus = num_gpus
        self.param_server_rref = rpc.remote('parameter_server', get_parameter_server, args=(num_gpus,))

    def get_global_param_rrefs(self):
        remote_params = remote_method(ParameterServer.get_param_rrefs, self.param_server_rref)
        return remote_params

    def forward(self, x):
        model_output = remote_method(ParameterServer.forward, self.param_server_rref, x)
        return model_output

def conv1x1(in_planes, out_planes, stride=1):
    """1x1 convolution"""
    return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)

class ResNetBase(nn.Module):

    def __init__(self, block, inplanes, num_classes=1000, groups=1, width_per_group=64, norm_layer=None):
        super(ResNetBase, self).__init__()
        self._lock = threading.Lock()
        self._block = block
        self._norm_layer = nn.BatchNorm2d
        self.inplanes = inplanes
        self.dilation = 1
        self.groups = groups
        self.base_width = width_per_group

    def _make_layer(self, planes, blocks, stride=1):
        norm_layer = self._norm_layer
        downsample = None
        previous_dilation = self.dilation
        if stride != 1 or self.inplanes != planes * self._block.expansion:
            downsample = nn.Sequential(conv1x1(self.inplanes, planes * self._block.expansion, stride), norm_layer(planes * self._block.expansion))
        layers = []
        layers.append(self._block(self.inplanes, planes, stride, downsample, self.groups, self.base_width, previous_dilation, norm_layer))
        self.inplanes = planes * self._block.expansion
        for _ in range(1, blocks):
            layers.append(self._block(self.inplanes, planes, groups=self.groups, base_width=self.base_width, dilation=self.dilation, norm_layer=norm_layer))
        return nn.Sequential(*layers)

num_classes = 1000

class ResNetPart1(ResNetBase):
    """
    The first part of ResNet.
    """

    def __init__(self, device, *args, **kwargs):
        super(ResNetPart1, self).__init__(Bottleneck, 64, *args, num_classes=num_classes, **kwargs)
        self.device = device
        self.seq = nn.Sequential(nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3, bias=False), self._norm_layer(self.inplanes), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=3, stride=2, padding=1), self._make_layer(64, 3), self._make_layer(128, 4, stride=2))
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.ones_(m.weight)
                nn.init.zeros_(m.bias)

    def forward(self, x_rref):
        x = x_rref.to_here()
        with self._lock:
            out = self.seq(x)
        return out.cpu()

class ResNetPart2(ResNetBase):
    """
    The second part of ResNet.
    """

    def __init__(self, device, *args, **kwargs):
        super(ResNetPart2, self).__init__(Bottleneck, 512, *args, num_classes=num_classes, **kwargs)
        self.device = device
        self.seq = nn.Sequential(self._make_layer(256, 6, stride=2), self._make_layer(512, 3, stride=2), nn.AdaptiveAvgPool2d((1, 1)))
        self.fc = nn.Linear(512 * self._block.expansion, num_classes)

    def forward(self, x_rref):
        x = x_rref.to_here()
        with self._lock:
            out = self.fc(torch.flatten(self.seq(x), 1))
        return out.cpu()

def _call_method(method, rref, *args, **kwargs):
    """
    a helper function to call a method on the given RRef
    """
    return method(rref.local_value(), *args, **kwargs)

def _async_on_rref(method, rref, *args, **kwargs):
    """
    a helper function to run method on the owner of rref and fetch back the
    result using RPC
    """
    return rpc.rpc_async(rref.owner(), _call_method, args=[method, rref] + list(args), kwargs=kwargs)

def _parameter_rrefs(module):
    """
    Create one RRef for each parameter in the given local module, and return a
    list of RRefs.
    """
    param_rrefs = []
    for param in module.parameters():
        param_rrefs.append(RRef(param))
    return param_rrefs

def _remote_on_rref(method, rref, *args, **kwargs):
    """
    a helper function to run method on the owner of rref and return an RRef
    of the result.
    """
    return rpc.remote(rref.owner(), _call_method, args=[method, rref] + list(args), kwargs=kwargs)

class DistResNet50(nn.Module):
    """
    Assemble two parts as an nn.Module and define pipelining logic
    """

    def __init__(self, split_size, workers, *args, **kwargs):
        super(DistResNet50, self).__init__()
        self.split_size = split_size
        self.p1_rref = rpc.remote(workers[0], ResNetPart1, args=('cuda:0',) + args, kwargs=kwargs)
        self.p2_rref = rpc.remote(workers[1], ResNetPart2, args=('cuda:1',) + args, kwargs=kwargs)

    def forward(self, xs):
        out_futures = []
        for x in iter(xs.split(self.split_size, dim=0)):
            x_rref = RRef(x)
            y_rref = _remote_on_rref(ResNetPart1.forward, self.p1_rref, x_rref)
            z_fut = _async_on_rref(ResNetPart2.forward, self.p2_rref, y_rref)
            out_futures.append(z_fut)
        outs = [fut.wait() for fut in out_futures]
        out = torch.cat(outs)
        return out

    def parameter_rrefs(self):
        remote_params = []
        remote_params.extend(_remote_on_rref(_parameter_rrefs, self.p1_rref).to_here())
        remote_params.extend(_remote_on_rref(_parameter_rrefs, self.p2_rref).to_here())
        return remote_params

class Policy(nn.Module):

    def __init__(self):
        super(Policy, self).__init__()
        self.affine1 = nn.Linear(4, 128)
        self.dropout = nn.Dropout(p=0.6)
        self.affine2 = nn.Linear(128, 2)
        self.saved_log_probs = []
        self.rewards = []

    def forward(self, x):
        x = self.affine1(x)
        x = self.dropout(x)
        x = F.relu(x)
        action_scores = self.affine2(x)
        return F.softmax(action_scores, dim=1)

class EmbeddingTable(nn.Module):
    """
    Encoding layers of the RNNModel
    """

    def __init__(self, ntoken, ninp, dropout):
        super(EmbeddingTable, self).__init__()
        self.drop = nn.Dropout(dropout)
        self.encoder = nn.Embedding(ntoken, ninp)
        nn.init.uniform_(self.encoder.weight, -0.1, 0.1)

    def forward(self, input):
        return self.drop(self.encoder(input)).cpu()

class Decoder(nn.Module):
    """
    Decoding layers of the RNNModel
    """

    def __init__(self, ntoken, nhid, dropout):
        super(Decoder, self).__init__()
        self.drop = nn.Dropout(dropout)
        self.decoder = nn.Linear(nhid, ntoken)
        nn.init.zeros_(self.decoder.bias)
        nn.init.uniform_(self.decoder.weight, -0.1, 0.1)

    def forward(self, output):
        return self.decoder(self.drop(output))

class RNNModel(nn.Module):
    """Container module with an encoder, a recurrent module, and a decoder."""

    def __init__(self, rnn_type, ntoken, ninp, nhid, nlayers, dropout=0.5, tie_weights=False):
        super(RNNModel, self).__init__()
        self.ntoken = ntoken
        self.drop = nn.Dropout(dropout)
        self.encoder = nn.Embedding(ntoken, ninp)
        if rnn_type in ['LSTM', 'GRU']:
            self.rnn = getattr(nn, rnn_type)(ninp, nhid, nlayers, dropout=dropout)
        else:
            try:
                nonlinearity = {'RNN_TANH': 'tanh', 'RNN_RELU': 'relu'}[rnn_type]
            except KeyError:
                raise ValueError("""An invalid option for `--model` was supplied,
                                 options are ['LSTM', 'GRU', 'RNN_TANH' or 'RNN_RELU']""")
            self.rnn = nn.RNN(ninp, nhid, nlayers, nonlinearity=nonlinearity, dropout=dropout)
        self.decoder = nn.Linear(nhid, ntoken)
        if tie_weights:
            if nhid != ninp:
                raise ValueError('When using the tied flag, nhid must be equal to emsize')
            self.decoder.weight = self.encoder.weight
        self.init_weights()
        self.rnn_type = rnn_type
        self.nhid = nhid
        self.nlayers = nlayers

    def init_weights(self):
        initrange = 0.1
        nn.init.uniform_(self.encoder.weight, -initrange, initrange)
        nn.init.zeros_(self.decoder.weight)
        nn.init.uniform_(self.decoder.weight, -initrange, initrange)

    def forward(self, input, hidden):
        emb = self.drop(self.encoder(input))
        output, hidden = self.rnn(emb, hidden)
        output = self.drop(output)
        decoded = self.decoder(output)
        decoded = decoded.view(-1, self.ntoken)
        return F.log_softmax(decoded, dim=1), hidden

    def init_hidden(self, bsz):
        weight = next(self.parameters())
        if self.rnn_type == 'LSTM':
            return weight.new_zeros(self.nlayers, bsz, self.nhid), weight.new_zeros(self.nlayers, bsz, self.nhid)
        else:
            return weight.new_zeros(self.nlayers, bsz, self.nhid)

class ConvLayer(torch.nn.Module):

    def __init__(self, in_channels, out_channels, kernel_size, stride):
        super(ConvLayer, self).__init__()
        reflection_padding = kernel_size // 2
        self.reflection_pad = torch.nn.ReflectionPad2d(reflection_padding)
        self.conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride)

    def forward(self, x):
        out = self.reflection_pad(x)
        out = self.conv2d(out)
        return out

class ResidualBlock(torch.nn.Module):
    """ResidualBlock
    introduced in: https://arxiv.org/abs/1512.03385
    recommended architecture: http://torch.ch/blog/2016/02/04/resnets.html
    """

    def __init__(self, channels):
        super(ResidualBlock, self).__init__()
        self.conv1 = ConvLayer(channels, channels, kernel_size=3, stride=1)
        self.in1 = torch.nn.InstanceNorm2d(channels, affine=True)
        self.conv2 = ConvLayer(channels, channels, kernel_size=3, stride=1)
        self.in2 = torch.nn.InstanceNorm2d(channels, affine=True)
        self.relu = torch.nn.ReLU()

    def forward(self, x):
        residual = x
        out = self.relu(self.in1(self.conv1(x)))
        out = self.in2(self.conv2(out))
        out = out + residual
        return out

class UpsampleConvLayer(torch.nn.Module):
    """UpsampleConvLayer
    Upsamples the input and then does a convolution. This method gives better results
    compared to ConvTranspose2d.
    ref: http://distill.pub/2016/deconv-checkerboard/
    """

    def __init__(self, in_channels, out_channels, kernel_size, stride, upsample=None):
        super(UpsampleConvLayer, self).__init__()
        self.upsample = upsample
        reflection_padding = kernel_size // 2
        self.reflection_pad = torch.nn.ReflectionPad2d(reflection_padding)
        self.conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride)

    def forward(self, x):
        x_in = x
        if self.upsample:
            x_in = torch.nn.functional.interpolate(x_in, mode='nearest', scale_factor=self.upsample)
        out = self.reflection_pad(x_in)
        out = self.conv2d(out)
        return out

class TransformerNet(torch.nn.Module):

    def __init__(self):
        super(TransformerNet, self).__init__()
        self.conv1 = ConvLayer(3, 32, kernel_size=9, stride=1)
        self.in1 = torch.nn.InstanceNorm2d(32, affine=True)
        self.conv2 = ConvLayer(32, 64, kernel_size=3, stride=2)
        self.in2 = torch.nn.InstanceNorm2d(64, affine=True)
        self.conv3 = ConvLayer(64, 128, kernel_size=3, stride=2)
        self.in3 = torch.nn.InstanceNorm2d(128, affine=True)
        self.res1 = ResidualBlock(128)
        self.res2 = ResidualBlock(128)
        self.res3 = ResidualBlock(128)
        self.res4 = ResidualBlock(128)
        self.res5 = ResidualBlock(128)
        self.deconv1 = UpsampleConvLayer(128, 64, kernel_size=3, stride=1, upsample=2)
        self.in4 = torch.nn.InstanceNorm2d(64, affine=True)
        self.deconv2 = UpsampleConvLayer(64, 32, kernel_size=3, stride=1, upsample=2)
        self.in5 = torch.nn.InstanceNorm2d(32, affine=True)
        self.deconv3 = ConvLayer(32, 3, kernel_size=9, stride=1)
        self.relu = torch.nn.ReLU()

    def forward(self, X):
        y = self.relu(self.in1(self.conv1(X)))
        y = self.relu(self.in2(self.conv2(y)))
        y = self.relu(self.in3(self.conv3(y)))
        y = self.res1(y)
        y = self.res2(y)
        y = self.res3(y)
        y = self.res4(y)
        y = self.res5(y)
        y = self.relu(self.in4(self.deconv1(y)))
        y = self.relu(self.in5(self.deconv2(y)))
        y = self.deconv3(y)
        return y

class Vgg16(torch.nn.Module):

    def __init__(self, requires_grad=False):
        super(Vgg16, self).__init__()
        vgg_pretrained_features = models.vgg16(pretrained=True).features
        self.slice1 = torch.nn.Sequential()
        self.slice2 = torch.nn.Sequential()
        self.slice3 = torch.nn.Sequential()
        self.slice4 = torch.nn.Sequential()
        for x in range(4):
            self.slice1.add_module(str(x), vgg_pretrained_features[x])
        for x in range(4, 9):
            self.slice2.add_module(str(x), vgg_pretrained_features[x])
        for x in range(9, 16):
            self.slice3.add_module(str(x), vgg_pretrained_features[x])
        for x in range(16, 23):
            self.slice4.add_module(str(x), vgg_pretrained_features[x])
        if not requires_grad:
            for param in self.parameters():
                param.requires_grad = False

    def forward(self, X):
        h = self.slice1(X)
        h_relu1_2 = h
        h = self.slice2(h)
        h_relu2_2 = h
        h = self.slice3(h)
        h_relu3_3 = h
        h = self.slice4(h)
        h_relu4_3 = h
        vgg_outputs = namedtuple('VggOutputs', ['relu1_2', 'relu2_2', 'relu3_3', 'relu4_3'])
        out = vgg_outputs(h_relu1_2, h_relu2_2, h_relu3_3, h_relu4_3)
        return out

class Bottle(nn.Module):

    def forward(self, input):
        if len(input.size()) <= 2:
            return super(Bottle, self).forward(input)
        size = input.size()[:2]
        out = super(Bottle, self).forward(input.view(size[0] * size[1], -1))
        return out.view(size[0], size[1], -1)

class Linear(Bottle, nn.Linear):
    pass

class Encoder(nn.Module):

    def __init__(self, config):
        super(Encoder, self).__init__()
        self.config = config
        input_size = config.d_proj if config.projection else config.d_embed
        dropout = 0 if config.n_layers == 1 else config.dp_ratio
        self.rnn = nn.LSTM(input_size=input_size, hidden_size=config.d_hidden, num_layers=config.n_layers, dropout=dropout, bidirectional=config.birnn)

    def forward(self, inputs):
        batch_size = inputs.size()[1]
        state_shape = self.config.n_cells, batch_size, self.config.d_hidden
        h0 = c0 = inputs.new_zeros(state_shape)
        outputs, (ht, ct) = self.rnn(inputs, (h0, c0))
        return ht[-1] if not self.config.birnn else ht[-2:].transpose(0, 1).contiguous().view(batch_size, -1)

class SNLIClassifier(nn.Module):

    def __init__(self, config):
        super(SNLIClassifier, self).__init__()
        self.config = config
        self.embed = nn.Embedding(config.n_embed, config.d_embed)
        self.projection = Linear(config.d_embed, config.d_proj)
        self.encoder = Encoder(config)
        self.dropout = nn.Dropout(p=config.dp_ratio)
        self.relu = nn.ReLU()
        seq_in_size = 2 * config.d_hidden
        if self.config.birnn:
            seq_in_size *= 2
        lin_config = [seq_in_size] * 2
        self.out = nn.Sequential(Linear(*lin_config), self.relu, self.dropout, Linear(*lin_config), self.relu, self.dropout, Linear(*lin_config), self.relu, self.dropout, Linear(seq_in_size, config.d_out))

    def forward(self, batch):
        prem_embed = self.embed(batch.premise)
        hypo_embed = self.embed(batch.hypothesis)
        if self.config.fix_emb:
            prem_embed = prem_embed.detach()
            hypo_embed = hypo_embed.detach()
        if self.config.projection:
            prem_embed = self.relu(self.projection(prem_embed))
            hypo_embed = self.relu(self.projection(hypo_embed))
        premise = self.encoder(prem_embed)
        hypothesis = self.encoder(hypo_embed)
        scores = self.out(torch.cat([premise, hypothesis], 1))
        return scores

class Sequence(nn.Module):

    def __init__(self):
        super(Sequence, self).__init__()
        self.lstm1 = nn.LSTMCell(1, 51)
        self.lstm2 = nn.LSTMCell(51, 51)
        self.linear = nn.Linear(51, 1)

    def forward(self, input, future=0):
        outputs = []
        h_t = torch.zeros(input.size(0), 51, dtype=torch.double)
        c_t = torch.zeros(input.size(0), 51, dtype=torch.double)
        h_t2 = torch.zeros(input.size(0), 51, dtype=torch.double)
        c_t2 = torch.zeros(input.size(0), 51, dtype=torch.double)
        for i, input_t in enumerate(input.chunk(input.size(1), dim=1)):
            h_t, c_t = self.lstm1(input_t, (h_t, c_t))
            h_t2, c_t2 = self.lstm2(h_t, (h_t2, c_t2))
            output = self.linear(h_t2)
            outputs += [output]
        for i in range(future):
            h_t, c_t = self.lstm1(output, (h_t, c_t))
            h_t2, c_t2 = self.lstm2(h_t, (h_t2, c_t2))
            output = self.linear(h_t2)
            outputs += [output]
        outputs = torch.stack(outputs, 1).squeeze(2)
        return outputs

class VAE(nn.Module):

    def __init__(self):
        super(VAE, self).__init__()
        self.fc1 = nn.Linear(784, 400)
        self.fc21 = nn.Linear(400, 20)
        self.fc22 = nn.Linear(400, 20)
        self.fc3 = nn.Linear(20, 400)
        self.fc4 = nn.Linear(400, 784)

    def encode(self, x):
        h1 = F.relu(self.fc1(x))
        return self.fc21(h1), self.fc22(h1)

    def reparameterize(self, mu, logvar):
        std = torch.exp(0.5 * logvar)
        eps = torch.randn_like(std)
        return mu + eps * std

    def decode(self, z):
        h3 = F.relu(self.fc3(z))
        return torch.sigmoid(self.fc4(h3))

    def forward(self, x):
        mu, logvar = self.encode(x.view(-1, 784))
        z = self.reparameterize(mu, logvar)
        return self.decode(z), mu, logvar

class PositionalEncoding(nn.Module):
    """Inject some information about the relative or absolute position of the tokens
        in the sequence. The positional encodings have the same dimension as
        the embeddings, so that the two can be summed. Here, we use sine and cosine
        functions of different frequencies.
    .. math::
        \\text{PosEncoder}(pos, 2i) = sin(pos/10000^(2i/d_model))
        \\text{PosEncoder}(pos, 2i+1) = cos(pos/10000^(2i/d_model))
        \\text{where pos is the word position and i is the embed idx)
    Args:
        d_model: the embed dim (required).
        dropout: the dropout value (default=0.1).
        max_len: the max. length of the incoming sequence (default=5000).
    Examples:
        >>> pos_encoder = PositionalEncoding(d_model)
    """

    def __init__(self, d_model, dropout=0.1, max_len=5000):
        super(PositionalEncoding, self).__init__()
        self.dropout = nn.Dropout(p=dropout)
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0).transpose(0, 1)
        self.register_buffer('pe', pe)

    def forward(self, x):
        """Inputs of forward function
        Args:
            x: the sequence fed to the positional encoder model (required).
        Shape:
            x: [sequence length, batch size, embed dim]
            output: [sequence length, batch size, embed dim]
        Examples:
            >>> output = pos_encoder(x)
        """
        x = x + self.pe[:x.size(0), :]
        return self.dropout(x)

class TransformerModel(nn.Module):
    """Container module with an encoder, a recurrent or transformer module, and a decoder."""

    def __init__(self, ntoken, ninp, nhead, nhid, nlayers, dropout=0.5):
        super(TransformerModel, self).__init__()
        try:
            from torch.nn import TransformerEncoder
            from torch.nn import TransformerEncoderLayer
        except:
            raise ImportError('TransformerEncoder module does not exist in PyTorch 1.1 or lower.')
        self.model_type = 'Transformer'
        self.src_mask = None
        self.pos_encoder = PositionalEncoding(ninp, dropout)
        encoder_layers = TransformerEncoderLayer(ninp, nhead, nhid, dropout)
        self.transformer_encoder = TransformerEncoder(encoder_layers, nlayers)
        self.encoder = nn.Embedding(ntoken, ninp)
        self.ninp = ninp
        self.decoder = nn.Linear(ninp, ntoken)
        self.init_weights()

    def _generate_square_subsequent_mask(self, sz):
        mask = (torch.triu(torch.ones(sz, sz)) == 1).transpose(0, 1)
        mask = mask.float().masked_fill(mask == 0, float('-inf')).masked_fill(mask == 1, float(0.0))
        return mask

    def init_weights(self):
        initrange = 0.1
        nn.init.uniform_(self.encoder.weight, -initrange, initrange)
        nn.init.zeros_(self.decoder)
        nn.init.uniform_(self.decoder.weight, -initrange, initrange)

    def forward(self, src, has_mask=True):
        if has_mask:
            device = src.device
            if self.src_mask is None or self.src_mask.size(0) != len(src):
                mask = self._generate_square_subsequent_mask(len(src))
                self.src_mask = mask
        else:
            self.src_mask = None
        src = self.encoder(src) * math.sqrt(self.ninp)
        src = self.pos_encoder(src)
        output = self.transformer_encoder(src, self.src_mask)
        output = self.decoder(output)
        return F.log_softmax(output, dim=-1)

import torch
from torch.nn import MSELoss, ReLU
from _paritybench_helpers import _mock_config, _mock_layer, _paritybench_base, _fails_compile

TESTCASES = [
    # (nn.Module, init_args, forward_args, jit_compiles)
    (ConvLayer,
     lambda: ([], {'in_channels': 4, 'out_channels': 4, 'kernel_size': 4, 'stride': 1}),
     lambda: ([torch.rand([4, 4, 4, 4])], {}),
     True),
    (Decoder,
     lambda: ([], {'ntoken': 4, 'nhid': 4, 'dropout': 0.5}),
     lambda: ([torch.rand([4, 4, 4, 4])], {}),
     True),
    (EmbeddingTable,
     lambda: ([], {'ntoken': 4, 'ninp': 4, 'dropout': 0.5}),
     lambda: ([torch.ones([4], dtype=torch.int64)], {}),
     True),
    (Linear,
     lambda: ([], {'in_features': 4, 'out_features': 4}),
     lambda: ([torch.rand([4, 4])], {}),
     False),
    (Net,
     lambda: ([], {'upscale_factor': 4}),
     lambda: ([torch.rand([4, 1, 64, 64])], {}),
     True),
    (Policy,
     lambda: ([], {}),
     lambda: ([torch.rand([4, 4, 4, 4])], {}),
     True),
    (PositionalEncoding,
     lambda: ([], {'d_model': 4}),
     lambda: ([torch.rand([4, 4, 4, 4])], {}),
     True),
    (ResidualBlock,
     lambda: ([], {'channels': 4}),
     lambda: ([torch.rand([4, 4, 4, 4])], {}),
     True),
    (TransformerNet,
     lambda: ([], {}),
     lambda: ([torch.rand([4, 3, 64, 64])], {}),
     False),
    (UpsampleConvLayer,
     lambda: ([], {'in_channels': 4, 'out_channels': 4, 'kernel_size': 4, 'stride': 1}),
     lambda: ([torch.rand([4, 4, 4, 4])], {}),
     False),
    (VAE,
     lambda: ([], {}),
     lambda: ([torch.rand([4, 784])], {}),
     True),
    (Vgg16,
     lambda: ([], {}),
     lambda: ([torch.rand([4, 3, 64, 64])], {}),
     False),
]

class Test_pytorch_examples(_paritybench_base):
    def test_000(self):
        self._check(*TESTCASES[0])

    def test_001(self):
        self._check(*TESTCASES[1])

    def test_002(self):
        self._check(*TESTCASES[2])

    def test_003(self):
        self._check(*TESTCASES[3])

    def test_004(self):
        self._check(*TESTCASES[4])

    def test_005(self):
        self._check(*TESTCASES[5])

    def test_006(self):
        self._check(*TESTCASES[6])

    def test_007(self):
        self._check(*TESTCASES[7])

    def test_008(self):
        self._check(*TESTCASES[8])

    def test_009(self):
        self._check(*TESTCASES[9])

    def test_010(self):
        self._check(*TESTCASES[10])

    def test_011(self):
        self._check(*TESTCASES[11])


import errno
import itertools
import math
import os
import platform
import signal
import subprocess
import sys

def to_bytes(str):
    # Encode to UTF-8 to get binary data.
    return str.encode('utf-8')

def to_string(bytes):
    if isinstance(bytes, str):
        return bytes
    return to_bytes(bytes)

def convert_string(bytes):
    try:
        return to_string(bytes.decode('utf-8'))
    except UnicodeError:
        return str(bytes)

def detectCPUs():
    """
    Detects the number of CPUs on a system. Cribbed from pp.
    """
    # Linux, Unix and MacOS:
    if hasattr(os, "sysconf"):
        if "SC_NPROCESSORS_ONLN" in os.sysconf_names:
            # Linux & Unix:
            ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
            if isinstance(ncpus, int) and ncpus > 0:
                return ncpus
        else: # OSX:
            return int(capture(['sysctl', '-n', 'hw.ncpu']))
    # Windows:
    if "NUMBER_OF_PROCESSORS" in os.environ:
        ncpus = int(os.environ["NUMBER_OF_PROCESSORS"])
        if ncpus > 0:
            return ncpus
    return 1 # Default

def mkdir_p(path):
    """mkdir_p(path) - Make the "path" directory, if it does not exist; this
    will also make directories for any missing parent directories."""
    if not path or os.path.exists(path):
        return

    parent = os.path.dirname(path)
    if parent != path:
        mkdir_p(parent)

    try:
        os.mkdir(path)
    except OSError:
        e = sys.exc_info()[1]
        # Ignore EEXIST, which may occur during a race condition.
        if e.errno != errno.EEXIST:
            raise

def capture(args, env=None):
    """capture(command) - Run the given command (or argv list) in a shell and
    return the standard output."""
    p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                         env=env)
    out,_ = p.communicate()
    return convert_string(out)

def which(command, paths = None):
    """which(command, [paths]) - Look up the given command in the paths string
    (or the PATH environment variable, if unspecified)."""

    if paths is None:
        paths = os.environ.get('PATH','')

    # Check for absolute match first.
    if os.path.isfile(command):
        return command

    # Would be nice if Python had a lib function for this.
    if not paths:
        paths = os.defpath

    # Get suffixes to search.
    # On Cygwin, 'PATHEXT' may exist but it should not be used.
    if os.pathsep == ';':
        pathext = os.environ.get('PATHEXT', '').split(';')
    else:
        pathext = ['']

    # Search the paths...
    for path in paths.split(os.pathsep):
        for ext in pathext:
            p = os.path.join(path, command + ext)
            if os.path.exists(p):
                return p

    return None

def checkToolsPath(dir, tools):
    for tool in tools:
        if not os.path.exists(os.path.join(dir, tool)):
            return False;
    return True;

def whichTools(tools, paths):
    for path in paths.split(os.pathsep):
        if checkToolsPath(path, tools):
            return path
    return None

def printHistogram(items, title = 'Items'):
    items.sort(key = lambda item: item[1])

    maxValue = max([v for _,v in items])

    # Select first "nice" bar height that produces more than 10 bars.
    power = int(math.ceil(math.log(maxValue, 10)))
    for inc in itertools.cycle((5, 2, 2.5, 1)):
        barH = inc * 10**power
        N = int(math.ceil(maxValue / barH))
        if N > 10:
            break
        elif inc == 1:
            power -= 1

    histo = [set() for i in range(N)]
    for name,v in items:
        bin = min(int(N * v/maxValue), N-1)
        histo[bin].add(name)

    barW = 40
    hr = '-' * (barW + 34)
    print('\nSlowest %s:' % title)
    print(hr)
    for name,value in items[-20:]:
        print('%.2fs: %s' % (value, name))
    print('\n%s Times:' % title)
    print(hr)
    pDigits = int(math.ceil(math.log(maxValue, 10)))
    pfDigits = max(0, 3-pDigits)
    if pfDigits:
        pDigits += pfDigits + 1
    cDigits = int(math.ceil(math.log(len(items), 10)))
    print("[%s] :: [%s] :: [%s]" % ('Range'.center((pDigits+1)*2 + 3),
                                    'Percentage'.center(barW),
                                    'Count'.center(cDigits*2 + 1)))
    print(hr)
    for i,row in enumerate(histo):
        pct = float(len(row)) / len(items)
        w = int(barW * pct)
        print("[%*.*fs,%*.*fs) :: [%s%s] :: [%*d/%*d]" % (
            pDigits, pfDigits, i*barH, pDigits, pfDigits, (i+1)*barH,
            '*'*w, ' '*(barW-w), cDigits, len(row), cDigits, len(items)))

# Close extra file handles on UNIX (on Windows this cannot be done while
# also redirecting input).
kUseCloseFDs = not (platform.system() == 'Windows')
def executeCommand(command, cwd=None, env=None):
    p = subprocess.Popen(command, cwd=cwd,
                         stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         env=env, close_fds=kUseCloseFDs)
    out,err = p.communicate()
    exitCode = p.wait()

    # Detect Ctrl-C in subprocess.
    if exitCode == -signal.SIGINT:
        raise KeyboardInterrupt

    # Ensure the resulting output is always of string type.
    out = convert_string(out)
    err = convert_string(err)

    return out, err, exitCode

def usePlatformSdkOnDarwin(config, lit_config):
    # On Darwin, support relocatable SDKs by providing Clang with a
    # default system root path.
    if 'darwin' in config.target_triple:
        try:
            cmd = subprocess.Popen(['xcrun', '--show-sdk-path'],
                                   stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            out, err = cmd.communicate()
            out = out.strip()
            res = cmd.wait()
        except OSError:
            res = -1
        if res == 0 and out:
            sdk_path = out
            lit_config.note('using SDKROOT: %r' % sdk_path)
            config.environment['SDKROOT'] = sdk_path


import copy
from typing import Any, Optional

import yaml

from config import Config
from transform import manager
from utils import utils, logger
from utils.utils import CachedProperty as cached_property

class Builder(object):
    """
    The base class for building components.

    Args:
        config (Config): A Config class.
        comp_list (list, optional): A list of component classes. Default: None
    """

    def __init__(self, config: Config, comp_list: Optional[list]=None):
        super().__init__()
        self.config = config
        self.comp_list = comp_list

    def build_component(self, cfg):
        """
        Create Python object, such as model, loss, dataset, etc.
        """
        cfg = copy.deepcopy(cfg)
        if 'type' not in cfg:
            raise RuntimeError(
                "It is not possible to create a component object from {}, as 'type' is not specified.".
                format(cfg))

        class_type = cfg.pop('type')
        com_class = self.load_component_class(class_type)

        params = {}
        for key, val in cfg.items():
            if self.is_meta_type(val):
                params[key] = self.build_component(val)
            elif isinstance(val, list):
                params[key] = [
                    self.build_component(item)
                    if self.is_meta_type(item) else item for item in val
                ]
            else:
                params[key] = val

        try:
            obj = self.build_component_impl(com_class, **params)
        except Exception as e:
            if hasattr(com_class, '__name__'):
                com_name = com_class.__name__
            else:
                com_name = ''
            raise RuntimeError(
                f"Tried to create a {com_name} object, but the operation has failed. "
                "Please double check the arguments used to create the object.\n"
                f"The error message is: \n{str(e)}")

        return obj

    def build_component_impl(self, component_class, *args, **kwargs):
        return component_class(*args, **kwargs)

    def load_component_class(self, class_type):
        for com in self.comp_list:
            if class_type in com.components_dict:
                return com[class_type]
        raise RuntimeError("The specified component ({}) was not found.".format(
            class_type))

    @classmethod
    def is_meta_type(cls, obj):
        # TODO: should we define a protocol (see https://peps.python.org/pep-0544/#defining-a-protocol)
        # to make it more pythonic?
        return isinstance(obj, dict) and 'type' in obj

    @classmethod
    def show_msg(cls, name, cfg):
        msg = 'Use the following config to build {}\n'.format(name)
        msg += str(yaml.dump({name: cfg}, Dumper=utils.NoAliasDumper))
        logger.info(msg[0:-1])

class SegBuilder(Builder):
    """
    This class is responsible for building components for semantic segmentation.
    """

    def __init__(self, config, comp_list=None):
        if comp_list is None:
            comp_list = [
                manager.TRANSFORMS
            ]
        super().__init__(config, comp_list)

    @cached_property
    def val_dataset_class(self) -> Any:
        dataset_cfg = self.config.val_dataset_cfg
        assert dataset_cfg != {}, \
            'No val_dataset specified in the configuration file.'
        dataset_type = dataset_cfg.get('type')
        return self.load_component_class(dataset_type)

    @cached_property
    def val_transforms(self) -> list:
        dataset_cfg = self.config.val_dataset_cfg
        assert dataset_cfg != {}, \
            'No val_dataset specified in the configuration file.'
        transforms = []
        for item in dataset_cfg.get('transforms', []):
            transforms.append(self.build_component(item))
        return transforms

if __name__=='__main__':
    config = Config(r'D:\objectdetection\other\config1\test.yml')
    builder = SegBuilder(config)
    transforms = builder.val_transforms
    print(transforms)


import tensorflow as tf
from tensorflow.keras.layers import Dense, Input
from tensorflow.keras import Model
from tensorflow.keras.optimizers import Adam

HIDDEN1_UNITS = 400
HIDDEN2_UNITS = 400

def create_actor_network(state_size, action_size):
	"""Creates an actor network.

	Args:
		state_size: (int) size of the input.
		action_size: (int) size of the action.
	Returns:
		model: an instance of tf.keras.Model.
		state_input: a tf.placeholder for the batched state.
	"""
	input_layer = Input(shape=(state_size,))
	layer = Dense(HIDDEN1_UNITS, activation='relu')(input_layer)
	layer = Dense(HIDDEN2_UNITS, activation='relu')(layer)
	output_layer = Dense(action_size, activation='tanh')(layer)
	model = Model(inputs=input_layer, outputs=output_layer)

	return model, input_layer

class ActorNetwork(object):
	def __init__(self, sess, state_size, action_size, batch_size,
				 tau, learning_rate):
		"""Initialize the ActorNetwork.
		This class internally stores both the actor and the target actor nets.
		It also handles training the actor and updating the target net.

		Args:
			sess: A Tensorflow session to use.
			state_size: (int) size of the input.
			action_size: (int) size of the action.
			batch_size: (int) the number of elements in each batch.
			tau: (float) the target net update rate.
			learning_rate: (float) learning rate for the critic.
		"""
		self.sess = sess
		self.batch_size = batch_size
		self.tau = tau
		self.learning_rate = learning_rate
		self.action_size = action_size

		self.model, self.state = create_actor_network(state_size, action_size)
		self.target_model, self.target_state  = create_actor_network(state_size, action_size)

		self.action_gradient = tf.placeholder(tf.float32, [None, action_size])
		self.params_grad = tf.gradients(self.model.output, self.model.trainable_weights, -self.action_gradient)
		grads = zip(self.params_grad, self.model.trainable_weights)

		self.optimizer = tf.train.AdamOptimizer(learning_rate).apply_gradients(grads)
		self.sess.run(tf.initialize_all_variables())

	def train(self, states, action_grads):
		"""Updates the actor by applying dQ(s, a) / da.

		Args:
			states: a batched numpy array storing the state.
			actions: a batched numpy array storing the actions.
			action_grads: a batched numpy array storing the
				gradients dQ(s, a) / da.
		"""
		self.sess.run(self.optimizer, feed_dict={self.state: states,
												 self.action_gradient: action_grads})

	def update_target(self):
		"""Updates the target net using an update rate of tau."""
		actor_weights = self.model.get_weights()
		actor_target_weights = self.target_model.get_weights()
		for i in range(len(actor_weights)):
			actor_target_weights[i] = self.tau * actor_weights[i] + (1 - self.tau) * actor_target_weights[i]
		self.target_model.set_weights(actor_target_weights)


import traceback
import sys
import os
import string
import datetime
import locale
import platform

from dateutil import rrule

_locale_radix = locale.localeconv()['decimal_point']

class MyException(Exception):
    def __init__(self, message):
        self.message = message
    def __str__(self):
        return self.message

def dbg_except():
    """Функция для отладки операторов try-except"""
    print(sys.exc_info())
    print(" ".join(traceback.format_exception(*sys.exc_info())))

def printf(*args):
    """ аналог print но возвращает строку"""
    return ''.join(map(str, args))

def play_sound(sound_file):
    """Plays the audio file that is at the fully qualified path `sound_file`"""
    system = platform.system()
    if system == "Windows":
        import winsound
        winsound.PlaySound(sound_file,
                           winsound.SND_FILENAME | winsound.SND_ASYNC)
    elif system == "Darwin":  # macOS
        from AppKit import NSSound
        from Foundation import NSURL
        cwd = os.getcwd()
        url = NSURL.URLWithString_("file://" + sound_file)
        NSSound.alloc().initWithContentsOfURL_byReference_(url, True).play()
    else:  # Linux
        import subprocess
        command = ["aplay", sound_file]
        subprocess.Popen(
            command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
            bufsize=0, universal_newlines=True)

def string_to_float(value):
    '''
    Универсальное преобразование, меняем и . и , в системный десятичный разделитель. Но разделителей разряда быть не должно

    '''

    value = value.replace(".", _locale_radix)
    value = value.replace(",", _locale_radix)
    return float(value)

def string_to_float_old(value):
    '''
    Преобразуем флоат из строки NTR в float так как у меня , а в англоинтерфейсе используется.

    '''

    if _locale_radix != ',':
        value = value.replace(",", _locale_radix)
    return float(value)

def weeks_between(start_date, end_date):
    """ количестве недель между датами"""
    weeks = rrule.rrule(rrule.WEEKLY, dtstart=start_date, until=end_date)
    return weeks.count()

def compare_balls(balls1,balls2):
    """ сравним два массива c шарами на количество совпадений
    balls1 и balls1 одномерные массивы шаров тиража,например [3,15,36,44] и [2,33,12,11]!
    """
    coins=0
    for ball1 in balls1:
        for ball2 in balls2:
            if ball1==ball2:coins+= 1

    return coins

    pass #compare_balls

def openurl(url):
    try:
        if sys.platform=='win32':
            os.startfile(url)
        elif sys.platform=='darwin':
            subprocess.Popen(['open', url])
        else:
            subprocess.Popen(['xdg-open', url])
    except OSError:
            print ('Пожалуйста, откройте адрес в браузере: '+url)

def compare_balls_detail(balls1,balls2, by_position=False):
    """ сравним два массива c шарами на количество совпадений и отображение самих совпадений
    balls1 и balls1 одномерные массивы шаров тиража,например [3,15,36,44] и [2,33,12,11]!
    Если задано by_position - то по позициям
    Возвращаем кортеж {число совпадений,какие номера совпали}
    """
    if by_position:
        return __compare_balls_detail_pos(balls1,balls2)

    coins=0
    detail=''
    for ball1 in balls1:
        for ball2 in balls2:
            if ball1==ball2:
                coins+= 1
                detail+=str(ball1)+' '

    return (coins,detail)

    pass #compare_balls_detail

def __compare_balls_detail_pos(balls1,balls2):
    """ сравним два массива c шарами на количество совпадений и отображение самих совпадений ПО ПОЗИЦИЯМ
    balls1 и balls1 одномерные массивы шаров тиража,например [0,1,1,2] и [0,0,1,1]!
    Возвращаем кортеж {число совпадений,какие номера совпали}
    """
    coins=0
    detail=''
    min_len=min(len(balls1), len(balls2))
    for i in range(min_len):
        if balls1[i]==balls2[i]:
            coins+= 1
            detail+=str(balls1[i])+' '

    return (coins,detail)

    pass #compare_balls_detail_pos

def compare_draws(balls_array1,balls_array2, by_position=False):
    """ сравним два массива c шарами на количество совпадений
    balls_array1 и balls_array2 двумерные массивы шаров тиража, а не отдельный тираж!
    """
    coins=[]
    if by_position:
        for balls1 in balls_array1:
            len1=len(balls1)
            for balls2 in balls_array2:
                len2=len(balls2)
                min_len=min(len1, len2)
                one_coin=0
                for i in range(min_len):
                    if balls1[i]==balls2[i]:one_coin+= 1

                coins.append(one_coin)
    else:
        for balls1 in balls_array1:
            for balls2 in balls_array2:
                one_coin=0
                for ball1 in balls1:
                    for ball2 in balls2:
                        if ball1==ball2:one_coin+= 1

                coins.append(one_coin)
    return coins

    pass #compare_draws