from .db_wrapper import db
from ..utils.consts import credentials
from ..utils.utils import (
    write_file,
    extract_value_from_a_query,
    extract_list_of_values_from_a_query,
    hash_password)
from ..utils.log import logger

#------------------------------------------------------------
#  QUERY - USERS  (customers)
#------------------------------------------------------------
def user_exist(user_id):
    print('user_exist()')
    command = "SELECT * FROM customers WHERE id = %s"
    user_exist = bool(db.execute_a_query(command, (user_id,)))
    return user_exist

#------------------------------------------------------------
def user_in_credentials_file(username):
    print('user_in_credentials_file()')
    admins = credentials["admins_username"]
    return username in admins

#------------------------------------------------------------
def is_admin(user_id):
    print('is_admin()')
    command = "SELECT is_admin FROM customers WHERE id = %s"
    user_is_admin = db.execute_a_query(command, (user_id,))
    user_exist = bool(user_is_admin)
    if user_exist:
        return extract_value_from_a_query(user_is_admin)
    else: return False

#------------------------------------------------------------
def get_all_available_by_user_id(user_id):
    print('get_all_available_by_user_id()')
    command = """ SELECT * FROM customers
        WHERE id = %s """
    user_with_id = db.execute_a_query(
        command, (user_id,))
    return user_with_id

#------------------------------------------------------------
def username_from_user_id(user_id):
    print('username_from_user_id()')
    command = "SELECT username FROM customers WHERE id = %s"
    user_name = db.execute_a_query(command, (user_id,))
    return extract_value_from_a_query(user_name)

#------------------------------------------------------------
#  QUERY - PHOTO
#------------------------------------------------------------
def extract_blob(photo_id):
    print('extract_blob()')
    command = "SELECT image_blob FROM photo WHERE id = %s"
    blob = bytes(
        extract_value_from_a_query(
        db.execute_a_query(command, (photo_id,)))
        )
    return blob

#------------------------------------------------------------
def save_photo_in_file(photo_id, file_path):
    print('save_photo_in_file()')
    blob = extract_blob(photo_id)
    write_file(blob, file_path)

#------------------------------------------------------------
#  QUERY - EFILE
#------------------------------------------------------------
def extract_efile_blob(efile_id):
    print('extract_efile_blob()')
    command = "SELECT efile_blob FROM efile WHERE id = %s"
    blob = bytes(
        extract_value_from_a_query(
        db.execute_a_query(command, (efile_id,)))
        )
    return blob

#------------------------------------------------------------
def save_efile_in_file(efile_id, file_path):
    print('save_efile_in_file()')
    blob = extract_blob(efile_id)
    write_file(blob, file_path)

#------------------------------------------------------------
#  QUERY - CATEGORY    (CREATORS)
#------------------------------------------------------------
def get_name_of_all_categories():
    print('get_name_of_all_categories()')
    command = "SELECT name FROM category"
    all_names_query = db.execute_a_query(command)
    names = extract_list_of_values_from_a_query(all_names_query)
    return names

#------------------------------------------------------------
def get_category_id_from_name(name):
    print('get_category_id_from_name()')
    command = "SELECT id FROM category WHERE name = %s"
    category_id = db.execute_a_query(command, (name,))
    return extract_value_from_a_query(category_id)

#------------------------------------------------------------
def get_category_id_from_creator_id(creator_id):
    print('get_category_id_from_creator_id()')
    command = "SELECT id FROM category WHERE creator_id = %s"
    category_id = db.execute_a_query(command, (creator_id,))
    return extract_value_from_a_query(category_id)

#------------------------------------------------------------
def get_all_descriptions_from_all_creators():
    print('get_all_descriptions_from_all_creators()')
    command = """ SELECT description FROM category
        WHERE id > %s """
    descriptions_from_creators = db.execute_a_query(
        command, (0,))
    return descriptions_from_creators

#------------------------------------------------------------
def get_description_from_creator_id(creator_id):
    print('get_description_from_creator_id()')
    command = """ SELECT description FROM category
        WHERE creator_id = %s """
    creator_description = db.execute_a_query(
        command, (creator_id,))
    return extract_value_from_a_query(creator_description)

#------------------------------------------------------------
def get_all_available_by_category_name(name):
    print('get_all_available_by_category_name()')
    category_id = get_category_id_from_name(name)
    return get_all_available_by_category_id(category_id)

#------------------------------------------------------------
#  QUERY - PRODUCTS
#------------------------------------------------------------
def get_quantity_purchased(product_id):
    print('get_quantity_purchased()')
    command = "SELECT total_sold FROM products WHERE id = %s"
    quantity_purchased = db.execute_a_query(command, (product_id,))
    return extract_value_from_a_query(quantity_purchased)

#------------------------------------------------------------
def get_quantity_in_stock(product_id):
    print('get_quantity_in_stock()')
    command = "SELECT in_stock FROM products WHERE id = %s"
    quantity_in_stock = db.execute_a_query(command, (product_id,))
    return extract_value_from_a_query(quantity_in_stock)

#------------------------------------------------------------
def get_efile_id_from_product_id(product_id):
    print('get_efile_id_from_product_id()')
    command = """ SELECT efile_id FROM products WHERE id = %s """
    efile_id_from_db = db.execute_a_query(
        command, (product_id,))
    return extract_value_from_a_query(efile_id_from_db)

#------------------------------------------------------------
def get_all_available_by_category_id(category_id):
    print('get_all_available_by_category_id()')
    command = """ SELECT * FROM products
        WHERE category_id = %s AND in_stock > 0"""
    products_with_category_id = db.execute_a_query(
        command, (category_id,))
    return products_with_category_id

#------------------------------------------------------------
#  QUERY - RECEIPTS
#------------------------------------------------------------

def customers_names_from_receipts_by_product_id(product_id):

    command = ("""
        SELECT buyer_id FROM receipts WHERE product_id = %s""")
    command_args = (product_id,)
    ids_query = db.execute_a_query(command,  command_args)
    return extract_list_of_values_from_a_query(ids_query)

##
# REMOVE RATINGS
#------------------------------------------------------------
def get_ratings_of_a_product(product_id):
    print('get_ratings_of_a_product()')
    command = """ SELECT rating FROM orders
        WHERE product_id = %s AND rating IS NOT NULL"""
    ratings_query = db.execute_a_query(command, (product_id,))
    return extract_list_of_values_from_a_query(ratings_query)

#------------------------------------------------------------
def count_occurrence_of_specified_rating(product_id, rating):
    print('count_occurrence_of_specified_rating()')
    all_ratings = get_ratings_of_a_product(product_id)
    return all_ratings.count(rating)

#------------------------------------------------------------
def search_products(string_to_search):
    print('search_products()')
    command = """SELECT * FROM products
        WHERE MATCH(name, description) AGAINST(%s)"""
    products_that_match = (
        db.execute_a_query(command, (string_to_search,)))
    return products_that_match


""" Write a python program to delete the age property of the user """

class person:
    def __init__(self):
        self.name="Sumit"
        self.age=20
        self.roll=17

p1=person()
print(p1.age)
del(p1.age)
print(p1.age)


import numpy as np
import scipy.constants as const
import math
from uncertainties import ufloat
import uncertainties.unumpy as unp
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

#Expeiment

U = np.array([0.15, 0.48, 0.7, 0.85, 0.95, 1.1, 1.2, 1.25, 1.3, 1.31, 1.4])
U1 = unp.uarray(U, 0.02*U)

I1 = np.array([88,69,56,47,40,36,32,29,27,24,23])
I = 0.001*I1

Ra = U/I
N_ex = Ra*I**2

plt.plot(Ra, N_ex, 'rx')
print(Ra)
print(N_ex)
#Theorie

U0 = 1.6
RI = 19
x = np.linspace(1, 61, 1000)

def f (U0,x,RI):
    return U0**2 * x /(RI+x)**2

plt.plot(x, f(U0,x,RI), 'b-')

plt.xlabel('Belastungswiderstand $R_{a}$ [Ω]')
plt.ylabel('Leistung $P$ [W]')
plt.legend(loc='best')
plt.show()


# Correlations sellingprice/time and housing info - Felicia
# This needs to be added in the wrapper.py file!

import pandas.io.sql as sqlio
import pandas as pd
import psycopg2
import mysql.connector

def correlation_housing_data_sellingprice_sellingtime():
    #start connection with database
    with open ('db_login.txt', 'r') as myfile:
        data = myfile.read()
    conn = psycopg2.connect(data)
    cur = conn.cursor()

    #Create dataframe to select columns of housing_data
    housinginfo_sellingpricetime_table = "SELECT sellingPrice, fullDescription, houseType, categoryObject, yearOfBuilding, garden, parcelSurface, numberRooms, numberBathrooms, energylabelClass, surface, sellingtime FROM funda;"
    housinginfo_sellingpricetime = sqlio.read_sql_query(housinginfo_sellingpricetime_table, conn)

    #Look for correlations between columns housing_data and sellingprice and sellingtime
    print(housinginfo_sellingpricetime.corr(method ='pearson'))

    ''''
    Conclusions with regard to sellingprice: 1)garden+sellingprice=-0,258484 2)parcelSurface+sellingprice=0.076516 3)numberrooms+sellingprice=0.100043
    4)numberbathrooms+sellingprice=0.069725 5)surface+sellingprice=0.580748 6)sellingtime+sellingprice=0.145279

    Conclusion with reagrd to sellingtime: 1)garden+sellingtime=0.145279 2)garden+sellingtime=-0.085790 3)parcelsurface+sellingtime=0.002927
    4)numberrooms+sellingtime= 0.136939 5)numberbathrooms+sellingtime=-0.073602 6)surface+sellingtime=0.153849
    '''

    return print('Analysis succesfully done')
correlation_housing_data_sellingprice_sellingtime()


import time,logging,traceback,unittest
from HTMLReport import ddt,addImage,no_retry
from common.parameter import ParameTestCase
from common.apiCenter import addHOld_ttl
from common.system_boss import addPfund,queryPfundCode,login_boss_api,getPower
from common.system_pmo import *
from common.tools import save_to_excel

from business.login_boss import login_boss
from page.appadmin.pFund import PagePfund

from testData.data import fundAcc
from config import bossAcc

# @unittest.skip('跳过')
@ddt.ddt
class TestPfund_uat(ParameTestCase):
	@classmethod
	def setUpClass(cls):
		logging.info(' ########## 私募基金下单测试开始 ########## ')
		cls.pagePfund=PagePfund(cls.driver)
		login_boss(cls.driver,bossAcc[cls.args.env],cls.args.env)
		cls.driver.set_window_size(1258,1329)
		login_boss_api(cls.args.env)

		cls.fundNameList=[]
		for curr in ['HKD','USD','CNY']:
			# for i in range(3):
			cls.fundNameList.append(addPfund(curr,cls.args.env))
			time.sleep(1)
		time.sleep(60)
		cls.pfundURL=f'http://{cls.args.env}-****.****.*****/frame/body/load?link_id=516'

	def setUp(self):
		pass

	# @unittest.skip('跳过')
	@no_retry
	def test_pFund_01(self):
		'''私募基金下单'''
		fail=0
		for pfundName in self.__class__.fundNameList:
			try:
				self.driver.get(self.__class__.pfundURL)
				time.sleep(3)
				self.driver.switch_to.frame('boss-frame')
				productCode=queryPfundCode(pfundName,self.args.env)
				logging.info(f' ========== 测试开始 pFund-01 私募基金申购 {productCode} ========== ')
				self.__class__.pagePfund.click_add()
				time.sleep(3)
				self.__class__.pagePfund.input_account(fundAcc[self.args.env])
				time.sleep(2)
				self.__class__.pagePfund.click_confirm()
				time.sleep(2)
				self.__class__.pagePfund.click_search()
				time.sleep(3)
				self.__class__.pagePfund.input_productCode(productCode)
				self.__class__.pagePfund.click_searchYes()
				time.sleep(3)
				self.__class__.pagePfund.click_result()
				time.sleep(3)
				minimum=self.__class__.pagePfund.get_minimum()
				power=getPower(fundAcc[self.args.env],productCode,types='pFundOrder',env=self.args.env)
				logging.info(f'申购前购买力: {power}')

				amount=self.__class__.pagePfund.input_buyAmount(minimum)
				self.__class__.pagePfund.losefocus()
				time.sleep(3)
				self.__class__.pagePfund.input_rate1()
				self.__class__.pagePfund.input_rate2()
				self.__class__.pagePfund.click_checkBox()
				self.__class__.pagePfund.select_custRatioRisk()
				self.__class__.pagePfund.input_middleSuggest()
				self.__class__.pagePfund.input_productMayRisk()
				self.__class__.pagePfund.myInput('录音编号 ',self.__class__.pagePfund.recordInfo,'recordInfo from AutoTest')
				self.__class__.pagePfund.myInput('见证职员名称 ',self.__class__.pagePfund.staffName,'AutoTest')

				self.__class__.pagePfund.click_submit()
				self.__class__.pagePfund.click_confirm2()
				# time.sleep(3)
				# self.__class__.pagePfund.click_confirm()
				time.sleep(1)
				if self.__class__.pagePfund.successFlag():
					logging.info('申购成功')
					addImage(self.driver.get_screenshot_as_base64(),f'{productCode} 申购成功')
					self.__class__.pagePfund.click_confirm3()
					time.sleep(3)
					power2=getPower(fundAcc[self.args.env],productCode,types='pFundOrder',env=self.args.env)
					logging.info(f'申购后购买力: {power2}')
					self.assertNotEqual(power,power2)

					mergerOrder(queryOrders(productCode))
					groupId=get_groupId(productCode,self.args.env)
					complete(groupId,self.args.env)
					status='Fail' if 'CNY' in productCode else 'Success'
					save_to_excel(groupId,productCode,pfundName,amount,side='BUY',status=status)
					pFund_upload()
					time.sleep(2)
					complete_confirm(groupId,self.args.env)

				else:
					fail=+1
					logging.info('申购失败')
					addImage(self.driver.get_screenshot_as_base64(),f'{productCode} 申购失败')
				logging.info(f' ========== 测试结束 pFund-01 私募基金申购 {productCode} ========== ')
			except:
				fail=+1
				logging.error(traceback.format_exc())
		self.assertFalse(fail)

	# @unittest.skip('跳过')
	@no_retry
	def test_pFund_02(self):
		'''私募基金赎回'''
		fail=0
		for pfundName in self.__class__.fundNameList:
			try:
				self.driver.get(self.__class__.pfundURL)
				# http://test-boss.cmbi.online/frame/body/load?link_id=534
				time.sleep(3)
				self.driver.switch_to.frame('boss-frame')
				productCode=queryPfundCode(pfundName,self.args.env)
				logging.info(f' ========== 测试开始 pFund-02 私募基金赎回 {productCode} ========== ')
				addHOld_ttl(fundAcc[self.args.env],productCode,'5000','FUND','D',self.args.env)
				self.__class__.pagePfund.click_add()
				time.sleep(3)
				self.__class__.pagePfund.input_account(fundAcc[self.args.env])
				time.sleep(2)
				self.__class__.pagePfund.click_confirm()
				time.sleep(2)

				self.__class__.pagePfund.click_redemption()
				self.__class__.pagePfund.click_search(1)
				time.sleep(3)
				self.__class__.pagePfund.input_productCode(productCode)
				self.__class__.pagePfund.click_searchYes()
				time.sleep(3)
				self.__class__.pagePfund.click_result()
				time.sleep(3)
				amount=self.__class__.pagePfund.input_units()
				self.__class__.pagePfund.input_redemptionFeeRate()
				# self.__class__.pagePfund.input_remRecordInfo()
				self.__class__.pagePfund.click_checkBox()
				self.__class__.pagePfund.click_remSubmit()
				self.__class__.pagePfund.click_confirm2()

				time.sleep(1)
				if self.__class__.pagePfund.successFlag():
					addImage(self.driver.get_screenshot_as_base64(),f'{productCode} 赎回成功')
					self.__class__.pagePfund.click_confirm3()
					time.sleep(3)

					mergerOrder(queryOrders(productCode,'SELL'))
					groupId=get_groupId(productCode,self.args.env)
					complete(groupId,self.args.env)
					status='Fail' if 'CNY' in productCode else 'Success'
					save_to_excel(groupId,productCode,pfundName,amount,side='SELL',status=status)
					pFund_upload()
					time.sleep(2)
					complete_confirm(groupId,self.args.env)

				else:
					fail+=1
					addImage(self.driver.get_screenshot_as_base64(),f'{productCode} 赎回失败')
				logging.info(f' ========== 测试结束 pFund-02 私募基金赎回 {productCode} ========== ')
			except:
				fail+=1
				logging.error(traceback.format_exc())
		self.assertFalse(fail)

	def tearDown(self):
		pass

	@classmethod
	def tearDownClass(cls):
		logging.info(' ########## 私募基金下单测试结束 ########## ')

if __name__=='__main__':
	unittest.main()


#!/usr/bin/python3

# AoC 2021 Problem 4a and 4b Solution

from io import IncrementalNewlineDecoder
from os import lseek
#from posix import XATTR_SIZEMAX

fname = "input7.txt"

dbg = False
# dbg = True
if dbg: fname = "testinp7.txt"

def ans7():
    l = open(fname).readline()
    w = l.split(',')
    xs = []
    sum = max = 0
    min = 10**20
    for e in w:
        x = int(e)
        xs.append(x)
        sum += x
        if (min > x):
            min = x
        if (max < x):
            max = x

    avg = sum / len(w)
    ravg = round(avg)
    print("Sum: {0} avg: {1} ravg: {2} min: {3} max: {4}".format(sum, avg, ravg, min, max))
    minstepsa = minposa = minstepsb = minposb = 10**20
    for pos in range(min,max+1):
        fuelstepsa = fuelstepsb = 0
        for x in xs:
            fuelstepsa += abs(x - pos)
            fuelstepsb += abs(x-pos) * (abs(x-pos) + 1) / 2
        if (fuelstepsa < minstepsa):
            minstepsa = fuelstepsa
            minposa = pos
            print ("New minstepsa: {0} at minposa: {1}".format(minstepsa, minposa))
        if (fuelstepsb < minstepsb):
            minstepsb = fuelstepsb
            minposb = pos
            print ("New minstepsb: {0} at minposb: {1}".format(minstepsb, minposb))
    return [minstepsa, minstepsb]

def main():
    res = ans7()
    print("Resa: {0}".format(res[0]))
    print("Resb: {0}".format(res[1]))

main()


from mchy.common.com_types import ComType, ExecCoreTypes, ExecType, InertCoreTypes, InertType
from tests.common_tests.helpers import BOOL, INT, FLOAT, STR

import pytest

@pytest.mark.parametrize("left_type, right_type, expectation", [
    (InertType(INT), InertType(INT), True),
    (InertType(INT), InertType(BOOL), False),
    (InertType(INT), InertType(INT, const=True), False),
    (InertType(INT, const=True), InertType(INT), False),
    (InertType(INT), InertType(INT, nullable=True), False),
    (InertType(INT, nullable=True), InertType(INT), False),
    (ExecType(ExecCoreTypes.WORLD, False), ExecType(ExecCoreTypes.WORLD, False), True),
    (ExecType(ExecCoreTypes.ENTITY, False), ExecType(ExecCoreTypes.WORLD, False), False),
    (ExecType(ExecCoreTypes.ENTITY, False), ExecType(ExecCoreTypes.ENTITY, False), True),
    (ExecType(ExecCoreTypes.ENTITY, True), ExecType(ExecCoreTypes.ENTITY, False), False),
])
def test_node_eq(left_type: ComType, right_type: ComType, expectation: bool):
    assert (left_type == right_type) == expectation

def test_null_nullable():
    assert (InertType(InertCoreTypes.NULL).nullable is False), "Null is nullable (The distinction is important for cmd optimizers)"


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import yfinance as yf

tickers = [ 'PETZ3.SA', 'VIVA3.SA','VIIA3.SA','AZUL4.SA']
carteira = pd.DataFrame()
for i in tickers:
  carteira[i] = yf.download(i, period='1y')['Adj Close']

retorno = carteira.pct_change()

num_acoes = len(tickers)
num_carteiras = 10
Rf = 0

lista_retornos = []
lista_volatilidade = []
lista_pesos = []
lista_sharpe_ratio = []

for carteira in range(num_carteiras):
  #gerando pesos aleartorios para as ações
  peso = np.random.random(num_acoes)
  peso = np.round((peso / np.sum(peso)), 3)
  lista_pesos.append(peso)
  #calculo de retorno esperado
  retorno_esperado = np.sum(retorno.mean() * peso) * 264
  lista_retornos.append(retorno_esperado)
  #calculo risco
  Matrix_cov = retorno.cov() * 264
  variancia = np.dot(peso.T,
                     np.dot(Matrix_cov, peso))
  desvio_padrao = np.sqrt(variancia)
  lista_volatilidade.append(desvio_padrao)

  #calculo Sharpe ratio
  sharpe_ratio = (retorno_esperado - Rf) / desvio_padrao
  lista_sharpe_ratio.append(sharpe_ratio)

lista_retornos = np.array(lista_retornos)
lista_volatilidade = np.array(lista_volatilidade)
lista_sharpe_ratio = np.array(lista_sharpe_ratio)

metricas = [lista_retornos, lista_volatilidade, lista_sharpe_ratio]
portifolios_df = pd.DataFrame(metricas).T
for contar,acao in enumerate(tickers):
  portifolios_df[acao+' Peso'] = [Peso[contar] for Peso in lista_pesos]
portifolios_df.columns = ['Retorno', 'Risco', 'Sharpe'] + [acao+' Peso' for acao in tickers]

min_Risco = portifolios_df.iloc[portifolios_df['Risco'].astype(float).idxmin()]
max_Retorno = portifolios_df.iloc[portifolios_df['Retorno'].astype(float).idxmax()]
max_Sharpe = portifolios_df.iloc[portifolios_df['Sharpe'].astype(float).idxmax()]

portifolios_df.to_csv("10portifolios_4smallcaps.csv")

print(portifolios_df)
print('')
print('Minimo risco')
print(min_Risco)
print('')
print('Maximo Retorno')
print(max_Retorno)
print('')
print('Max Sharpe')
print(max_Sharpe)
print('')

#grafico

plt.figure(figsize = (10,5))
plt.scatter(lista_volatilidade, lista_retornos,
            c = lista_retornos / lista_volatilidade)
plt.title('Otimização de Portifólio', fontsize = 26)
plt.xlabel('Volatilidade', fontsize = 20)
plt.ylabel('Retorno', fontsize = 20)
plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.colorbar(label = 'Sharpe Ratio')
plt.show()


from django import forms
from django.forms import widgets

from items.models import Item

sizes = (
    ('S', 'S'),
    ('M', 'M'),
    ('L', 'L'),
    ('XL', 'XL')
)
PAYMENT_CHOICES = (
    ('IB', 'Internet Banking'),
    ('C', 'COD')
)
class OrderItemForm(forms.Form):
    item_size = forms.ChoiceField(choices=sizes, widget=forms.RadioSelect(attrs={'require':True}))
    # quantity = forms.DecimalField(min_value=1, max_value=100, max_digits=4,widget=forms.NumberInput(attrs={'class': 'text-black',
    #                                                                 }),)


# Grocery List (19 items)
grocery_list = ['Bananas', 'Clementines', 'Baguette', 'Oat Milk', 'Olive Oil', 'Coffee Beans',
                'Chocolate Bar', 'Brocolli', 'Eggplant', 'Chickpeas', 'Lentils', 'Tomatoes',
                'Pasta', 'Rice', 'Yogurt', 'Blueberries', 'Onions', 'Garlic', 'Truffles']

# City Price
city_price = [6.49, 4.99, 4.39, 4.29, 11.99, 17.99,
              3.49, 3.99, 1.10, 1.99, 2.99, 4.68,
              1.59, 8.99, 3.49, 6.99, 2.99, 1.98, 14.99]

# Country Price
country_price = [4.49, 4.12, 3.42, 6.99, 7.99, 14.99,
                2.99, 2.49, 0.99, 1.49, 2.49, 1.99,
                1.59, 6.99, 3.89, 4.99, 1.69, 1.87, 11.49]

city=0
country=0

#No need for such complicated methods
# for each in range(len(city_price)):
#    difference = (city_price[each]-country_price[each])/country_price[each]
#    print(grocery_list[each], " city: ", city_price[each], " country: ", country_price[each], " percent: ", difference)
#    percent.append(difference)
#    total = total + difference
# print(total/len(city_price))

for each in range(len(city_price)):
    city = city + city_price[each]
    country = country + country_price[each]

percent = (city - country) / country
print(round(percent,4))

#or according to another source
city2=(sum(city_price))
country2=(sum(country_price))
difference=(city2-country2)/country2
print(difference)


#!python
"""advent of code 2022 day 8 part 2"""
trees = [list(map(int, line)) for line in open("input.txt").read().splitlines()]
length = len(trees)

answer = 0
for x in range(1, length-1):
    for y in range(1, length-1):
        score = [x, length-1-x, y, length-1-y]

        for n in range(x-1, -1, -1): # looking up
            if trees[x][y] <= trees[n][y]:
                score[0] = x-n
                break

        for n in range(x+1, length): # looking down
            if trees[x][y] <= trees[n][y]:
                score[1] = n-x
                break

        for n in range(y-1, -1, -1): # looking left
            if trees[x][y] <= trees[x][n]:
                score[2] = y-n
                break

        for n in range(y+1, length): # looking right
            if trees[x][y] <= trees[x][n]:
                score[3] = n-y
                break

        answer = max(answer, score[0] * score[1] * score[2] * score[3])

print("part 2:", answer)


import sys

def read_original_annotation_file(annotation_file):
    with open(annotation_file, "r") as f:
        nb_frames = int(f.readline().strip().split()[-1])

        boxes_by_frame = [[] for i in range(nb_frames)]
        frame_id = -1
        for line in f:
            if line[:6] == "#frame":
                frame_id += 1
            else:
                x1, y1, side = tuple(map(int, line.split()[1:4]))
                x2, y2 = x1 + side, y1 + side
                interacting = (line.split()[4] != "no_interaction")

                box_info = [(x1, y1, x2, y2), interacting]
                boxes_by_frame[frame_id].append(box_info)

    return boxes_by_frame

if __name__ == "__main__":
    annotation_file = sys.argv[1]
    boxes_by_frame = read_original_annotation_file(annotation_file)


import os
import ast
import torch
from model_dispatcher import MODEL_DISPATCHER
from dataset import TestDataset
from torch import nn
import pandas as pd
from tqdm import tqdm

DEVICE = 'cuda'

IMAGE_HEIGHT = int(os.environ.get("IMAGE_HEIGHT"))
IMAGE_WIDTH = int(os.environ.get("IMAGE_WIDTH"))

TEST_BATCH_SIZE = int(os.environ.get("TEST_BATCH_SIZE"))

MODEL_MEAN = ast.literal_eval(os.environ.get("MODEL_MEAN"))
MODEL_STD = ast.literal_eval(os.environ.get("MODEL_STD"))

BASE_MODEL = os.environ.get("BASE_MODEL")

def predict_to_numpy(predict):
    return torch.nn.functional.softmax(predict, dim=1).data.cpu().numpy().argmax(axis=1)

def get_prediction( data_loader, models):
    predictions = []
    total_model = float(len(models))

    with torch.no_grad():
        for bi, d in tqdm(enumerate(data_loader), total=int(len(data_loader))):
            image = d["image"]
            img_id = d["image_id"]
            image = image.to(DEVICE, dtype = torch.float)

            preds = torch.zeros(image.shape[0], 4, dtype = torch.float).to(DEVICE)

            for i in range(len(models)):
                p = models[i](image)
                preds += p/float(len(models))

            preds = predict_to_numpy(preds)

            for ii, imid in enumerate(img_id):
                predictions.append((f"{imid}", preds[ii]))

    return predictions

def get_models():
    models =[]
    i =0
    for j in [0,1,2,3,4,5,6]:
        models.append(MODEL_DISPATCHER[BASE_MODEL](pretrained=False))
        models[i].load_state_dict(torch.load(f'../save_model/{BASE_MODEL}_folds({j},).bin'))
        models[i].to(DEVICE)
        models[i].eval()
        i+=1
    return models

def save_submission(predictions):
    inverse_map={0:'Food',1:'Attire',2:'Decorationandsignage',3:'misc'}

    sub = pd.DataFrame(predictions, columns = ["Image", "label"])
    sub['Class']=sub['label'].map(inverse_map)
    sub = sub[['Image', 'Class']]
    sub.to_csv("../save_submission/submission.csv", index = False)
    print(sub.head(5))

def main():

    models = get_models()

    test_dataset  = TestDataset(
        img_height = IMAGE_HEIGHT,
        img_width = IMAGE_WIDTH,
        mean = MODEL_MEAN,
        std = MODEL_STD
    )

    test_loader = torch.utils.data.DataLoader(
        dataset = test_dataset,
        batch_size = TEST_BATCH_SIZE,
        shuffle = False,
        num_workers = 4
    )

    predictions = get_prediction(test_loader, models)

    save_submission(predictions)

if __name__ == "__main__":
    main()


# To funkcijo prijazno podarjam vsem, ki bodo programirali v eni vrstici. :)
# Kako jo uporabiti, je v navodilih. Kdor je ne potrebuje, naj jo ignorira.
def vsa_polja(s, v):
    """
    Generiraj vse koordinate (x, y) za polje s podano širino in višino
    Args:
        s (int): širina
        v (int): višina

    Returns:
        generator parov polj
    """

    return ((x, y) for x in range(s) for y in range(v))

########################
# Za oceno 6

def sosedov(x, y, mine):
    return sum([1 for x1, y1 in vsa_polja(3, 3) if((x-(x1-1),y-(y1-1)) in mine and (x-(x1-1),y-(y1-1)) != (x,y))])

def najvec_sosedov(mine, s, v):
    return [(x1,y1) for x1,y1 in vsa_polja(s,v) if(max([sosedov(x,y,mine) for x,y in vsa_polja(s,v)]) == sosedov(x1,y1,mine))][0]

def brez_sosedov(mine, s, v):
    return {(x,y) for x, y in vsa_polja(s, v) if sosedov(x,y,mine) == 0}

def po_sosedih(mine, s, v):
    return ({ key:set({(x,y) for x,y in vsa_polja(s,v) if sosedov(x,y,mine) == key}) for key in range(0,9)})

########################
# Za oceno 7

def dolzina_poti(pot):
    return sum([abs((pot[i][0] - pot[i - 1][0]) + (pot[i][1] - pot[i - 1][1])) for i in range(1, len(pot))])

def varen_premik(x0, y0, x1, y1, mine):
    return (all([False for (x,y) in[(x,y) for x in range(min(x1,x0),max(x1,x0)+1) for y in range(min(y1,y0),max(y1,y0)+1)] if (x,y) in mine]))

def varna_pot(pot, mine):
    return all([False for i in range(1,len(pot)) if (not varen_premik(pot[i-1][0],pot[i-1][1],pot[i][0],pot[i][1],mine))]+[False for x,y in pot if (not varen_premik(x,y,x,y,mine))])

########################
# Za oceno 8

def polje_v_mine(polje):
    k = set()
    polje = polje.strip()
    polje = polje.split(" ")
    v = len(polje)
    s = len(polje[0])
    for x in range(v):
        for y in range(s):
            if polje[x][y] == "X":
                k.add((y,x))
    return (k,s,v)

########################
# Za oceno 9
#
# Vse funkcije za oceno 6 in 7 morajo biti napisane v eni vrstici.

########################
# Za oceno 10

def preberi_pot(ukazi):
    obr = 0
    x = 0
    y = 0
    r = [(x,y)]
    ukazi = ukazi.split('\n')
    for i in ukazi:
        if i == "LEVO":
            if obr == 0:
                obr = 270
            else:
                obr -= 90
        elif i == "DESNO":
            if obr == 270:
                obr = 0
            else:
                obr += 90
        elif i.isnumeric():
            i = int(i)
            if obr == 0:
                y += i
                r.append((abs(x), abs(y)))
            if obr == 90:
                x += i
                r.append((abs(x), abs(y)))
            if obr == 180:
                y -= i
                r.append((abs(x), abs(y)))
            if obr == 270:
                x -= i
                r.append((abs(x),abs(y)))
    return r

def zapisi_pot(pot):
    uk = ""
    pre = 0
    for i in range(1, len(pot)):
        x = pot[i - 1][0]
        y = pot[i - 1][1]
        x1 = pot[i][0]
        y1 = pot[i][1]
        if (y < y1):
            uk += str(y1-y)
            uk += "\n"
        if (y > y1):
            uk += "LEVO\nLEVO\n"
            uk += str(y - y1)
            uk += "\n"
            uk += "LEVO\nLEVO\n"
        if (x < x1):
            uk += "DESNO\n"
            uk += str(x1 - x)
            uk += "\n"
            uk += "DESNO\nDESNO\nDESNO\n"
        if (x > x1):
            uk += "LEVO\n"
            uk += str(x - x1)
            uk += "\n"
            uk += "LEVO\nLEVO\nLEVO\n"
    return uk

import unittest

"""
...X....
.X....X.
.XX.....
......X.
"""
mine1 = {(3, 0), (1, 1), (6, 1), (1, 2), (2, 2), (6, 3)}
s1, v1 = 8, 4

"""
........
........
........
"""
mine2 = set()
s2, v2 = 8, 3

"""
...X...X.X....X.
"""
mine3 = {(3, 0), (7, 0), (9, 0), (14, 0)}
s3, v3 = 16, 1

"""
X
"""
mine4 = {(0, 0)}
s4, v4 = 1, 1

"""
X
.
.
X
.
X
.
"""
mine5 = {(0, 0), (0, 3), (0, 5)}
s5, v5 = 1, 7

class Test06(unittest.TestCase):
    def test_01_sosedov(self):
        self.assertEqual(sosedov(2, 1, mine1), 4)
        self.assertEqual(sosedov(0, 3, mine1), 1)
        self.assertEqual(sosedov(4, 3, mine1), 0)
        self.assertEqual(sosedov(4, 2, mine1), 0)
        self.assertEqual(sosedov(0, 0, mine1), 1)
        self.assertEqual(sosedov(7, 0, mine1), 1)
        self.assertEqual(sosedov(3, 0, mine1), 0)

        self.assertEqual(sosedov(2, 2, mine2), 0)
        self.assertEqual(sosedov(0, 0, mine2), 0)
        self.assertEqual(sosedov(0, 0, mine2), 0)

        self.assertEqual(sosedov(0, 0, mine3), 0)
        self.assertEqual(sosedov(2, 0, mine3), 1)
        self.assertEqual(sosedov(3, 0, mine3), 0)
        self.assertEqual(sosedov(8, 0, mine3), 2)

        self.assertEqual(sosedov(0, 0, mine4), 0)

        self.assertEqual(sosedov(0, 0, mine5), 0)
        self.assertEqual(sosedov(0, 1, mine5), 1)
        self.assertEqual(sosedov(0, 2, mine5), 1)
        self.assertEqual(sosedov(0, 3, mine5), 0)
        self.assertEqual(sosedov(0, 4, mine5), 2)
        self.assertEqual(sosedov(0, 5, mine5), 0)
        self.assertEqual(sosedov(0, 6, mine5), 1)

    def test_02_najvec_sosedov(self):
        self.assertEqual(najvec_sosedov(mine1, s1, v1), (2, 1))
        x, y = najvec_sosedov(mine2, s2, v2)
        self.assertTrue(0 <= x < s2)
        self.assertTrue(0 <= y < v2)
        self.assertEqual(najvec_sosedov(mine3, s3, v3), (8, 0))
        self.assertEqual(najvec_sosedov(mine4, s4, v4), (0, 0))
        self.assertEqual(najvec_sosedov(mine5, s5, v5), (0, 4))

    def test_03_brez_sosedov(self):
        self.assertEqual(brez_sosedov(mine1, s1, v1),
                         {(3, 0), (4, 2), (6, 1), (6, 3), (4, 3)})
        self.assertEqual(brez_sosedov(mine2, s2, v2),
                         {(x, y) for x in range(s2) for y in range(v2)})
        self.assertEqual(brez_sosedov(mine3, s3, v3),
                         {(x, 0) for x in (0, 1, 3, 5, 7, 9, 11, 12, 14)})
        self.assertEqual(brez_sosedov(mine4, s4, v4), {(0, 0)})
        self.assertEqual(brez_sosedov(mine5, s5, v5),
                         {(0, 0), (0, 3), (0, 5)})

    def test_04_po_sosedih(self):
        self.assertEqual(po_sosedih(mine1, s1, v1),
                         {0: {(3, 0), (4, 2), (6, 1), (6, 3), (4, 3)},
                          1: {(7, 3), (3, 2), (0, 0), (7, 0), (3, 3), (7, 1),
                              (4, 0), (6, 0), (5, 0), (5, 3), (5, 1), (1, 0),
                              (4, 1), (0, 3)},
                          2: {(0, 1), (1, 2), (1, 3), (0, 2), (3, 1), (2, 0),
                              (6, 2), (2, 3), (2, 2), (5, 2), (1, 1), (7, 2)},
                          3: set(),
                          4: {(2, 1)},
                          5: set(),
                          6: set(),
                          7: set(),
                          8: set()}
                         )

        prazen = dict.fromkeys(range(9), set())
        prazen[0] = {(x, y) for x in range(s2) for y in range(v2)}
        self.assertEqual(po_sosedih(mine2, s2, v2), prazen)

        s = dict.fromkeys(range(9), set())
        s.update({0: {(9, 0), (0, 0), (7, 0), (12, 0), (3, 0), (11, 0),
                      (14, 0), (5, 0), (1, 0)},
                  1: {(15, 0), (6, 0), (2, 0), (10, 0), (13, 0), (4, 0)},
                  2: {(8, 0)}})
        self.assertEqual(po_sosedih(mine3, s3, v3), s)

        s = dict.fromkeys(range(9), set())
        s.update({0: {(9, 0), (0, 0), (7, 0), (12, 0), (3, 0), (11, 0),
                      (14, 0), (5, 0), (1, 0)},
                  1: {(15, 0), (6, 0), (2, 0), (10, 0), (13, 0), (4, 0)},
                  2: {(8, 0)}})
        self.assertEqual(po_sosedih(mine3, s3, v3), s)

        s = dict.fromkeys(range(9), set())
        s[0] = {(0, 0)}
        self.assertEqual(po_sosedih(mine4, s4, v4), s)

        s = dict.fromkeys(range(9), set())
        s.update({0: {(0, 3), (0, 0), (0, 5)},
                  1: {(0, 1), (0, 6), (0, 2)},
                  2: {(0, 4)}})
        self.assertEqual(po_sosedih(mine5, s5, v5), s)

class Test07(unittest.TestCase):
    def test_01_dolzina_poti(self):
        self.assertEqual(dolzina_poti([(7, 2), (7, 5)]), 3)
        self.assertEqual(dolzina_poti([(7, 5), (7, 2)]), 3)
        self.assertEqual(dolzina_poti([(7, 5), (4, 5)]), 3)
        self.assertEqual(dolzina_poti([(1, 5), (4, 5)]), 3)
        self.assertEqual(
            dolzina_poti([(0, 0), (0, 3), (4, 3), (4, 2), (7, 2), (7, 3)]),
            3 + 4 + 1 + 3 + 1)
        self.assertEqual(
            dolzina_poti([(0, 3), (4, 3), (4, 2), (7, 2), (7, 3)]),
            4 + 1 + 3 + 1)
        self.assertEqual(
            dolzina_poti([(0, 0), (0, 1), (3, 1)]),
            1 + 3)
        self.assertEqual(dolzina_poti([(5, 3)]), 0)
        self.assertEqual(dolzina_poti([]), 0)

    """
    ...X....
    .X....X.
    .XX.....
    ......X.
    """
    def test_02_varen_premik(self):
        self.assertTrue(varen_premik(3, 1, 3, 3, mine1))
        self.assertTrue(varen_premik(3, 3, 3, 1, mine1))
        self.assertTrue(varen_premik(4, 0, 7, 0, mine1))
        self.assertTrue(varen_premik(7, 0, 4, 0, mine1))
        self.assertTrue(varen_premik(2, 1, 5, 1, mine1))
        self.assertTrue(varen_premik(5, 1, 2, 1, mine1))

        self.assertFalse(varen_premik(2, 1, 6, 1, mine1))
        self.assertFalse(varen_premik(6, 1, 2, 1, mine1))
        self.assertFalse(varen_premik(1, 1, 5, 1, mine1))
        self.assertFalse(varen_premik(5, 1, 1, 1, mine1))
        self.assertFalse(varen_premik(0, 1, 4, 1, mine1))
        self.assertFalse(varen_premik(4, 1, 0, 1, mine1))

        self.assertFalse(varen_premik(2, 1, 2, 3, mine1))
        self.assertFalse(varen_premik(2, 3, 2, 1, mine1))
        self.assertFalse(varen_premik(2, 1, 2, 2, mine1))
        self.assertFalse(varen_premik(2, 2, 2, 1, mine1))
        self.assertFalse(varen_premik(2, 2, 2, 0, mine1))
        self.assertFalse(varen_premik(2, 0, 2, 2, mine1))

        self.assertFalse(varen_premik(1, 1, 1, 1, mine1))

    """
    ...X....
    .X....X.
    .XX.....
    ......X.
    """
    def test_03_varna_pot(self):
        self.assertTrue(varna_pot([(0, 0), (0, 3), (4, 3), (4, 2), (7, 2), (7, 3)], mine1))
        self.assertTrue(varna_pot([(0, 3), (4, 3), (4, 2), (7, 2), (7, 3)], mine1))
        self.assertTrue(varna_pot([(2, 1)], mine1))
        self.assertTrue(varna_pot([], mine1))

        self.assertFalse(varna_pot([(0, 0), (0, 1), (3, 1)], mine1))
        self.assertFalse(varna_pot([(0, 0), (1, 0), (1, 3)], mine1))
        self.assertFalse(varna_pot([(0, 0), (1, 0), (0, 0), (1, 0), (1, 3), (3, 3)], mine1))
        self.assertFalse(varna_pot([(1, 1)], mine1))

class Test08(unittest.TestCase):
    def test_01_polje_v_mine(self):
        # Če si sledi več nizov, med katerimi ni ničesar, jih Python zlepi
        # ".X. "   "..X" je isto kot ".X. ...".
        self.assertEqual(polje_v_mine("...X.... "
                                      ".X....X. "
                                      ".XX..... "
                                      "......X."), (mine1, s1, v1))
        self.assertEqual(polje_v_mine("........ "
                                      "........ "
                                      "........"), (mine2, s2, v2))
        self.assertEqual(polje_v_mine("...X...X.X....X."), (mine3, s3, v3))
        self.assertEqual(polje_v_mine("X"), (mine4, s4, v4))
        self.assertEqual(polje_v_mine("X "
                                      ". "
                                      ". "
                                      "X "
                                      ". "
                                      "X "
                                      ". "), (mine5, s5, v5))

class Test10(unittest.TestCase):
    def test_01_preberi_pot(self):
        self.assertEqual(
            preberi_pot(
"""DESNO
DESNO
3
LEVO
4
LEVO
1
DESNO
3
DESNO
1"""), [(0, 0), (0, 3), (4, 3), (4, 2), (7, 2), (7, 3)])

        self.assertEqual(
            preberi_pot(
"""DESNO
LEVO
DESNO
DESNO
DESNO
DESNO
DESNO
3"""), [(0, 0), (3, 0)])

        self.assertEqual(
            preberi_pot(
"""LEVO
DESNO
LEVO
LEVO
LEVO
LEVO
DESNO
3"""), [(0, 0), (3, 0)])

        self.assertEqual(
            preberi_pot(
"""LEVO
DESNO
LEVO
LEVO
LEVO
LEVO
DESNO
3"""), [(0, 0), (3, 0)])

        self.assertEqual(
            preberi_pot(
"""DESNO
3
DESNO
3
DESNO
3
DESNO
3"""), [(0, 0), (3, 0), (3, 3), (0, 3), (0, 0)])

        self.assertEqual(
            preberi_pot(
"""DESNO
1
DESNO
DESNO
1
LEVO
LEVO
1
DESNO
3
LEVO
2
DESNO
DESNO"""), [(0, 0), (1, 0), (0, 0), (1, 0), (1, 3), (3, 3)])

    def test_02_zapisi_pot(self):
        pot = [(0, 0), (3, 0)]
        self.assertEqual(preberi_pot(zapisi_pot(pot)), pot)

        pot = [(0, 0), (3, 0), (3, 3)]
        self.assertEqual(preberi_pot(zapisi_pot(pot)), pot)

        pot = [(0, 0), (3, 0), (3, 3), (3, 5), (5, 5), (5, 1), (4, 1), (6, 1), (6, 8), (6, 3)]
        self.assertEqual(preberi_pot(zapisi_pot(pot)), pot)

        pot = [(0, 0), (0, 3), (4, 3), (4, 2), (7, 2), (7, 3)]
        self.assertEqual(preberi_pot(zapisi_pot(pot)), pot)

if __name__ == "__main__":
    unittest.main()


"""
Question:
        Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.

        Example 1:

        Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
        Output: 6
        Explanation: The above elevation map (black section) is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped.
        Example 2:

        Input: height = [4,2,0,3,2,5]
        Output: 9

        Constraints:

        n == height.length
        1 <= n <= 2 * 104
        0 <= height[i] <= 105

"""

"""
Method 1:
Time Complexity: O(n)
Space Complexity: O(1)
"""
class Solution:
    def trap(self, height: list[int]) -> int:
        res = 0
        length = len(height)
        left_prev = height[0]
        right_prev = height[length - 1]
        i = 1
        j = length - 2
        while i <= j:
            if left_prev < right_prev:
                if left_prev <= height[i]:
                    left_prev = height[i]
                else:
                    res += left_prev - height[i]
                i += 1
            else:
                if right_prev <= height[j]:
                    right_prev = height[j]
                else:
                    res += right_prev - height[j]
                j -= 1

        return res


# 5688. 세제곱근을 찾아라 D3
for tc in range(1, int(input()) + 1):
    n = int(input())
    answer = 0
    answer = n ** (1/3)
    ans = round(answer)
    if ans ** 3 == n:
        answer = ans
    else:
        answer = -1
    print(f'#{tc} {answer}')


# Write a program that displays the following table (1 kilogram = 2.2 pounds):

# Kilograms Pounds
# 1         2.2
# 2         4.4
# 3         6.6
# ...
# 9         19.8
# 10        22.0

def kilotopounds(n,end):
  print("Kilograms" + "\t" + "Pounds")
  for i in range(n,end):
    print(str(i) + "\t\t" + str("{0:.1f}".format(i*2.2)))

kilotopounds(1,11)


from django.urls import path
from . import views

app_name = "ruta_apps"

urlpatterns = [

    path(
        'add-cargue-recepcion/',
        views.RecepcioCreateView.as_view(),
        name = 'cargue-recepcion'
    ),

    path(
        'listar-planillas/<full_name>/',
        views.ListEmpleadosPdf.as_view(),
        name = 'impresion',
    ),

    path(
        'lista/planillas/asignar/',
        views.AsignarCreateView.as_view(),
        name='asignar',
    ),

     path(
        'lista/planillas/generar/',
        views.AsignarListview.as_view(),
        name='planillas',
    ),

    path(
        'generar/destino/',
        views.DestinoCreate.as_view(),
        name='destino'
    ),

    path(
        'generar/descargue/',
        views.DescargueCreateView.as_view(),
        name='destino-descargue'
    ),

    # path(
    #     'generar/historial/',
    #     views.HistorialListview.as_view(),
    #     name='historial'
    # ),
    path('<int:rr>/results/', views.detail, name='results'),

    path(
        'inf/destino/ciudad/',
        views.InformeRutaCiudadListView.as_view(),
        name='informe-destino',
    ),

    path(
        'update/recepcion/view/<int:pk>/',
        views.CorreccionRecepcion.as_view(),
        name='update-recepcion',
    ),

    path(
        'lista/recepcion/',
        views.RecepcionListView.as_view(),
        name='lista-recepcion',
    ),
    # path('about/', TemplateView.as_view(template_name="ruta/    prueba.html")),

    ]


# Long-short trading strategy with FTSE 100 ETF (ISF.L) using Keltner Channels (K-Band)
# Part 2 (adding stop loss)

### Loading libraries
import yfinance as yf
import ta
import pandas as pd
from datetime import date, timedelta, datetime

### Importing data
ticker = 'ISF.L'
# ticker = 'NVDA' #NVDA not performing as well, with a negative 36.67% cumulative return
start_date = '2019-01-01'
end_date = '2019-12-31'

date_fmt = '%Y-%m-%d'

start_date_buffer = datetime.strptime(start_date, date_fmt) - timedelta(days = 365)
start_date_buffer = start_date_buffer.strftime(date_fmt)
start_date_buffer

### downloading data with yahoo finance
df = yf.download(ticker, start = start_date, end = end_date)
df.head()

### Keltner Channel calculation
k_band = ta.volatility.KeltnerChannel(df.High, df.Low, df.Close, 10, 10)

df['K_BAND_UB'] = k_band.keltner_channel_hband().round(4)
df['K_BAND_LB'] = k_band.keltner_channel_lband().round(4)

### Developing a trading strategy
'''
Our Strategy will be as follows:
Enter Long when close cross below the K-Band lower bound
Enter Short when close cross above the K-Band upper bound
Exit Position when there’s an opposite signal
'''
df['CLOSE_PREV'] = df.Close.shift(1)
df['LONG'] = (df.Close <= df.K_BAND_LB) & (df.CLOSE_PREV > df.K_BAND_LB)
df['EXIT_LONG'] = (df.Close >= df.K_BAND_UB) & (df.CLOSE_PREV < df.K_BAND_UB)

df['SHORT'] = (df.Close >= df.K_BAND_UB) & (df.CLOSE_PREV < df.K_BAND_UB)
df['EXIT_SHORT'] = (df.Close <= df.K_BAND_LB) & (df.CLOSE_PREV > df.K_BAND_LB)

'''
In real-world, when we see the trading signals, we will only be able to trade the next day, so the
trades will happen the day after, i.e. we need to shift the signals by one day.
'''
df.LONG = df.LONG.shift(1)
df.EXIT_LONG = df.EXIT_LONG.shift(1)
df.SHORT = df.SHORT.shift(1)
df.EXIT_SHORT = df.EXIT_SHORT.shift(1)

df[['LONG', 'EXIT_LONG', 'SHORT', 'EXIT_SHORT']].dropna().head()

### Simulating trading in the year 2019

bt_df = df[(df.index >= start_date) & (df.index <= end_date)]

'''
We want to set up three things:
Initial Context: Start account balance, PnL (Profit and Loss) and positions.
Temporary Variables: the last signal indicating how to compute PnL, last price computing PnL and counter recording the days of trade.
Data to Analyze the Strategy: Trade dates, side, days, PnL, return and cumulative PnL.
'''

balance = 1000000
pnl = 0
position = 0

stop_loss_lvl = -2  # adding stop loss level

last_signal = 'hold'
last_price = 0
c = 0

trade_date_start = []
trade_date_end = []
trade_days = []
trade_side = []
trade_pnl = []
trade_ret = []

cum_value = []

'''
Within the loop, we will:
Exit Position if there’s a signal to exit.
Enter Position if there’s a signal to enter
Compute daily PnL, count trade days and record it
'''
'''
When we exit a trade, we need to do three things.
1) Compute the PnL of the trade and cash balance
2) Record trade stats such as the end date, days of trading and PnL
3) Reset the Temporary Variables such as trading day counter, position and last signal

The way to compute the PnL under either situation is the same. We also assume that we will use the Open price for trading
(we will have the signal one day before). Notice, we used the Temporary Variables “last_price”, which we will record when entering the previous position.

The way to calculate the cash position will be different. For a long position, we sell the shares and take in the cash. We use the
position and Open price to compute the market value and add that into the balance.

For a short position, we borrowed the shares and sold when entering the position, so we need to buy the shares back when exiting. In this case,
we just need to update the balance with PnL.
'''

for index, row in bt_df.iterrows():

    # check and close any positions
    if row.EXIT_LONG and last_signal == 'long':
        trade_date_end.append(row.name)  # row.name and index correspond to the same thing
        trade_days.append(c)

        pnl = (row.Open - last_price) * position
        trade_pnl.append(pnl)
        trade_ret.append((row.Open / last_price - 1) * 100)

        balance = balance + row.Open * position  # on the long side, we add to the balance price at which we exit the trade (row.Open) * position

        position = 0
        last_signal = 'hold'
        c = 0

    elif row.EXIT_SHORT and last_signal == 'short':
        trade_date_end.append(row.name)
        trade_days.append(c)

        pnl = (row.Open - last_price) * position
        trade_pnl.append(pnl)
        trade_ret.append((last_price / row.Open - 1) * 100)

        balance = balance + pnl  # on the short side, since we borrowed shares, we only add pnl amount

        position = 0
        last_signal = 'hold'
        c = 0

    if row.LONG and last_signal != 'long':
        last_signal = 'long'
        last_price = row.Open
        trade_date_start.append(row.name)
        trade_side.append('long')

        position = int(balance / row.Open)
        cost = position * row.Open
        balance = balance - cost  # on the long side, when we open a trade, we compute the possible number of share we can buy and compute the cost to deduct from the current balance
        c = 0

    elif row.SHORT and last_signal != 'short':
        last_signal = 'short'
        last_price = row.Open
        trade_date_start.append(row.name)
        trade_side.append('short')

        position = int(balance / row.Open) * -1   # on the short side, we don't reduce our balance when we open the trade since we borrow shares. We just need to compute the number of shares we could borrow (we assume we can only borrow up to the cash balance we have)
        c = 0

    # checking stop loss for the long position - new part of the code (part 2)
    if last_signal == 'long' and c > 0 and (row.Low / last_price - 1) * 100 <= stop_loss_lvl:  # to trigger a stop loss from a long trade, 3 conditions need to be met: we are in a long position, we held position for at least 1 day, and daily low is lower than our stop loss level
        # recording the trade
        c = c+1
        trade_date_end.append(row.name)
        trade_days.append(c)

        stop_loss_price = last_price + round(last_price * (stop_loss_lvl / 100), 4)  # computing stop loss price

        # updating balance
        pnl = (stop_loss_price - last_price) * position
        trade_pnl.append(pnl)
        trade_ret.append((stop_loss_price / last_price -1) * 100)

        balance = balance + stop_loss_price * position

        # resetting temp variables
        position = 0
        last_signal = 'hold'
        c = 0
    # checking stop loss for the short position - new part of the code (part 2)
    elif last_signal == 'short' and c > 0 and (last_price / row.High - 1) * 100 <= stop_loss_lvl:  # to trigger a stop loss from a short trade, 3 conditions need to be met: we are in a short position, we held position for at least 1 day, and daily high is higher than our stop loss level
        # recording the trade
        c = c+1
        trade_date_end.append(row.name)
        trade_days.append(c)

        stop_loss_price = last_price - round(last_price * (stop_loss_lvl / 100), 4)  # computing stop loss price

        # updating balance
        pnl = (stop_loss_price - last_price) * position
        trade_pnl.append(pnl)
        trade_ret.append((last_price / stop_loss_price -1) * 100)

        balance = balance + pnl

        # resetting temp variables
        position = 0
        last_signal = 'hold'
        c = 0

    # compute market value and count days for any possible position
    '''
    There are three possible situations:
        1) We are not in any position, nothing changes. Market value will be the cash balance we have.
        2) If we are in a long position, we then increase the day count by one and compute the market value.
           We use the position times the Close price plus the existing cash balance.
        3) If we are in a short position. we will increase the day count by one too. To compute the market value,
           we will calculate the PnL (difference of the Close price and last trading price times the positions).
           It will then increase or decrease the existing balance accordingly.
    '''
    if last_signal == 'hold':
        market_value = balance
    elif last_signal == 'long':
        c = c + 1
        market_value = position * row.Close + balance
    else:
        c = c + 1
        market_value = (row.Close - last_price) * position + balance

    cum_value.append(market_value)

### Backtest results
'''
We'd like to see 2 things:
1) Comparing with buy and hold strategy (i.e. do nothing), is our strategy getting us much more returns?
2) Is our strategy feasible? Will we have too many trades (i.e. increasing the trading cost)? Is the outperformance coming
   from one or two single trades (i.e. quality of the signal)?
'''
cum_ret_df = pd.DataFrame(cum_value, index = bt_df.index, columns = ['CUM_RET'])
cum_ret_df['CUM_RET'] = (cum_ret_df.CUM_RET / 1000000 - 1) * 100
cum_ret_df['BUY_HOLD'] = (bt_df.Close / bt_df.Open.iloc[0] - 1) * 100
cum_ret_df['ZERO'] = 0
cum_ret_df.plot(figsize = (15, 5))

cum_ret_df.iloc[[-1]].round(2)
'''
We can see in 2019, our K-Band trading strategy worked well for ISF.L, which is ETF for the FTSE 100 index. However, by adding stop loss,
our performance declined from 41% to 39.5%.
This is not surprising, because -2% stop loss level is too sensitive. In reality, with the stock market, the level should be higher. We could
try longer periods or higher level for experiments, which we will cover in the future.
From the chart we can see the trading strategy we have is not too volatile.
'''

### Pulling all stats into one table
size = min(len(trade_date_start), len(trade_date_end))

trade_dict = { 'START': trade_date_start[:size], 'END': trade_date_end[:size],
              'SIDE': trade_side[:size], 'DAYS': trade_days[:size],
              'PNL': trade_pnl[:size], 'RET': trade_ret[:size]
              }

trade_df = pd.DataFrame(trade_dict)
trade_df.head()

### Computing stats
num_trades = trade_df.groupby('SIDE').count()[['START']]
num_trades_win = trade_df[trade_df.PNL > 0].groupby('SIDE').count()[['START']]

avg_days = trade_df.groupby('SIDE').mean()[['DAYS']]

avg_ret = trade_df.groupby('SIDE').mean()[['RET']]
avg_ret_win = trade_df[trade_df.PNL > 0].groupby('SIDE').mean()[['RET']]
avg_ret_loss = trade_df[trade_df.PNL < 0].groupby('SIDE').mean()[['RET']]

std_ret = trade_df.groupby('SIDE').std()[['RET']]

detail_df = pd.concat([num_trades, num_trades_win, avg_days, avg_ret, avg_ret_win, avg_ret_loss, std_ret], axis = 1, sort = False)

detail_df.columns = ['NUM_TRADES', 'NUM_TRADES_WIN', 'AVG_DAYS', 'AVG_RET', 'AVG_RET_WIN', 'AVG_RET_LOSS', 'STD_RET']

detail_df.round(2)

### Adding maximum drawdown (new part of the code in part 2)
mv_df = pd.DataFrame(cum_value, index = bt_df.index, columns = ['MV'])
mv_df.head()

# calculating rolling maximum value
days = len(mv_df)

roll_max = mv_df.MV.rolling(window = days, min_periods  = 1).max()
drawdown_val = mv_df.MV - roll_max
drawdown_pct = (mv_df.MV / roll_max - 1) * 100

print('Max Drawdown Value:', round(drawdown_val.min(), 0))
print('Max Drawdown %', round(drawdown_pct.min(), 2))
'''
With our strategy, the maximum drawdown is -3.95%, which is good considering the general volatility of the stock market.

We could use it to analyze the strategy without stop loss too and we will find without stop loss, our maximum drawdown will be over -4%,
which means it’s riskier. But using less than 1% risk to get 2% more performance may be a good trade-off.
'''

Keltner Channel Trading Strategy2 (adding stop loss).py


from gensim.models import word2vec
import numpy as np
import argparse
import networkx as nx
from node2vec import Node2Vec

from util.helper import ensure_dir
from util.setting import log

class Node2vec:
    def __init__(self, args:argparse.Namespace, inter_data) -> None:
        self.nx_G = self.read_graph(inter_data)
        self.walk_length = args.walk_length
        self.num_walks = args.num_walks

        self.type_dim = args.type_dim
        self.window = args.word2vec_window
        self.min_count = args.word2vec_count
        self.worker = args.word2vec_worker
        self.model = None
        self.embedding = None

    def read_graph(self, inter_data):
        '''
        Reads the input network in networkx.
        '''
        G = nx.Graph()
        G.add_edges_from(inter_data)

        for edge in G.edges():
            G[edge[0]][edge[1]]['weight'] = 1

        return G

    def init_embedding(self, e2t_list:list, typetoken_seq:list):
        """"""
        log.info('Initing type/token embeddings with node2vec')
        node2vec = Node2Vec(self.nx_G,
            dimensions=self.type_dim, walk_length=self.walk_length,
            num_walks=self.num_walks, workers=self.worker, seed=2022)

        model = node2vec.fit(window=self.window, min_count=self.min_count, batch_words=4)

        init_embedding = np.zeros(shape=(len(e2t_list), 2*self.type_dim), dtype=np.float32)

        # Embedding: entity = type || token
        for idx, typetoken in enumerate(e2t_list):
            if typetoken[1] != -1:
                init_embedding[idx] = np.append(model.wv[typetoken[0]], model.wv[typetoken[1]])
            else:
                init_embedding[idx] = np.append(model.wv[typetoken[0]], np.zeros(self.type_dim))

        self.embedding = init_embedding
        self.model = model

    def store_embedding(self, pretrain_path:str):
        """"""
        embedding_save_dir = '%s/node2vec/%s_%s_%s/' % \
            (pretrain_path, self.type_dim, self.window, self.min_count)
        ensure_dir(embedding_save_dir)

        embedding_path = embedding_save_dir + 'node2vec.embedding'

        with open (embedding_path, 'wb') as f:
            np.save(f, self.embedding)

        log.info("save node2vec embeddings in %s" % embedding_path)

    def load_embedding(self, pretrain_path:str):
        """"""
        embedding_path = '%s/node2vec/%s_%s_%s/node2vec.embedding' % \
            (pretrain_path, self.type_dim, self.window, self.min_count)

        with open(embedding_path, 'rb') as f:
            self.embedding = np.load(embedding_path)

        log.info("load node2vec embeddings in %s" % embedding_path)


# -*- coding: utf-8 -*-
import os
from sklearn.metrics import confusion_matrix, precision_score
import numpy as np

class result_summary():
    def __init__(self, pred, true, score = None, score_th = None, labels = None):
        self.pred = pred
        self.true = true
        self.labels = labels
        if labels is None:
            self.Get_labels()

        self.score = score
        self.score_th = score_th
        if not (self.score is None or self.score_th is None):
            self.Pred_score_filter()
        self.confusion_mat = self.Get_Confusion_matrix()

    def Get_labels(self):
        true_label = np.ndarray.tolist(self.true)
        self.labels = list(set(true_label))
        return self.labels

    def Pred_score_filter(self):
        filter_index = self.score < self.score_th
        self.pred[filter_index] = 0
        self.score[filter_index] = 0.0

    def Gwt_diag(self):
        return np.diag(self.Get_Confusion_matrix())

    # def Get_FP(self):
    def Get_Confusion_matrix(self):
        return confusion_matrix(self.true, self.pred, self.labels)

    def Get_TP(self):
        tp_list = np.diag(self.confusion_mat)
        tp_dict = {}
        for index_i, label_i in enumerate(self.labels):
            tp_dict[label_i] = tp_list[index_i]
        return tp_dict

    def Get_FP(self):
        fp_list = np.sum(self.confusion_mat, 0) - np.diag(self.confusion_mat)
        fp_dict = {}
        for index_i, label_i in enumerate(self.labels):
            fp_dict[label_i] = fp_list[index_i]
        return fp_dict

    def Get_FN(self):
        fn_list = np.sum(self.confusion_mat, 1) - np.diag(self.confusion_mat)
        fn_dict = {}
        for index_i, label_i in enumerate(self.labels):
            fn_dict[label_i] = fn_list[index_i]
        return fn_dict

    def Get_Accuracy(self):
        All_num = np.sum(self.confusion_mat)
        Ture_num = np.sum(np.diag(self.confusion_mat))
        return 1.0*Ture_num/np.maximum(All_num, np.finfo(np.float64).eps)

    def Get_Recall(self):
        tp_list = np.diag(self.confusion_mat)
        recall_list = 1.0*tp_list/np.maximum(np.sum(self.confusion_mat, 1), np.finfo(np.float64).eps)
        recall_dict = {}
        for index_i, label_i in enumerate(self.labels):
            recall_dict[label_i] = recall_list[index_i]
        return recall_dict

    def Get_Precision(self):
        # precision_list = precision_score(self.true, self.pred, labels=self.labels, average=None)

        tp_list = np.diag(self.confusion_mat)
        precision_list = 1.0*tp_list/np.maximum(np.sum(self.confusion_mat, 0), np.finfo(np.float64).eps)
        precision_dict = {}
        for index_i, label_i in enumerate(self.labels):
            precision_dict[label_i] = precision_list[index_i]
        return precision_dict

    def Get_AP(self):
        if self.score is None:
            return None
        pred_dict = {}
        sorted_ind = np.argsort(-self.score)
        sort_pred = self.pred[sorted_ind]
        sort_true = self.true[sorted_ind]
        for label_i in self.labels:
            pred_dict[label_i] = []
        for index_i, pred_i in enumerate(sort_pred):
            if pred_i == sort_true[index_i]:
                pred_dict[pred_i].append(1.0)
            else:
                pred_dict[pred_i].append(0.0)

        pred_total_num = np.sum(self.confusion_mat, 0)
        true_total_num = np.sum(self.confusion_mat, 1)

        AP_dict = {}
        for i, label_i in enumerate(self.labels):
            pred_num_i = pred_total_num[i]
            true_num_i = true_total_num[i]

            tp_i = np.array(pred_dict[label_i])
            tp_i = np.cumsum(tp_i)

            recall_i = tp_i/np.maximum(true_num_i, np.finfo(np.float64).eps)
            precision_i = tp_i/np.maximum(pred_num_i, np.finfo(np.float64).eps)
            AP_dict[label_i] = self.voc_ap(recall_i, precision_i)
        return AP_dict

    def voc_ap(self, rec, prec):
        # correct AP calculation
        # first append sentinel values at the end
        mrec = np.concatenate(([0.], rec, [1.]))
        mpre = np.concatenate(([0.], prec, [0.]))

        # compute the precision envelope
        for i in range(mpre.size - 1, 0, -1):
            mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])

        # to calculate area under PR curve, look for points
        # where X axis (recall) changes value
        i = np.where(mrec[1:] != mrec[:-1])[0]

        # and sum (\Delta recall) * prec
        ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
        return ap


from utils.consts import *

class ScaledDotProduct(Module):

    def __init__(self, args: DataParams):
        super().__init__()

        self.args = args

        self.drop = nn.Dropout(args.dr)

    def forward(self, q: Tensor, k: Tensor, v: Tensor, mask: Tensor = null) -> Tensor:
        attn = (q @ k.transpose(-2, -1)) / torch.tensor([self.args.sd], device=self.args.device).sqrt()
        if mask != null: attn += mask
        attn = F.softmax(attn, dim=-1)

        cross = self.drop(attn @ v).permute(0, 2, 1, 3)
        cross = cross.reshape(cross.shape[0], cross.shape[1], self.args.dims)
        return cross

"""
Linear "Attention" Mechanism
Time Complexity: O(TD)
"""

class HydraAttention(Module):

    def __init__(self, args: DataParams):
        super().__init__()

        self.nheads = args.dims

        self.to_qkv = nn.Linear(args.dims, 3 * args.dims)
        self.proj = nn.Linear(args.dims, args.dims)

        self.drop = nn.Dropout(args.dr)

    def forward(self, x: Tensor, mask: Tensor = null) -> Tensor:
        b, s, d = x.shape

        q, k, v = self.to_qkv(x).view(b, s, self.nheads, 3).permute(0, 2, 1, 3).chunk(3, dim=-1)

        q = q / q.norm(dim=-1, keepdim=true)
        k = k / k.norm(dim=-1, keepdim=true)

        aggregated = (k * v).sum(dim=-2, keepdims=true)
        gated = self.drop(q * aggregated)

        gated = gated.permute(0, 2, 1, 3).view(b, s, d)

        return self.proj(gated)

class MultiHeadAttention(Module):

    def __init__(self, args: DataParams):
        super().__init__()

        self.args = args

        self.base = ScaledDotProduct(args)

        self.to_qkv = nn.Linear(args.dims, 3 * args.dims)
        self.proj = nn.Linear(args.dims, args.dims)

        # self.proj.weight.data.uniform_(-.1, .1)
        # self.to_qkv.weight.data.uniform_(-.1, .1)

        # nn.init.normal_(self.to_qkv.weight, mean=0., std=np.sqrt(2 / (args.dims + args.dims)))

    def forward(self, x: Tensor, mask: Tensor = null) -> Tensor:

        if not self.args.bf: x = x.transpose(0, 1)

        b, s, d = x.shape

        q, k, v = self.to_qkv(x).view(b, s, self.args.h, 3 * self.args.sd).permute(0, 2, 1, 3).chunk(3, -1)

        attn = self.base(q, k, v, mask)

        if not self.args.bf: attn = attn.transpose(0, 1)

        return self.proj(attn)

class CrossAttention(Module):

    def __init__(self, args: DataParams):
        super().__init__()

        self.args = args

        self.base = ScaledDotProduct(args)

        self.to_qk = nn.Linear(args.dims, 2 * args.dims)
        self.to_v = nn.Linear(args.dims, args.dims)

        self.proj = nn.Linear(args.dims, args.dims)

    def forward(self, x: Tensor, ctx: Tensor, mask: Tensor = null) -> Tensor:

        if not self.args.bf: x = x.transpose(0, 1)

        b, s, d = x.shape

        q, k = self.to_qk(ctx).view(b, s, self.args.h, 2 * self.args.sd).permute(0, 2, 1, 3).chunk(2, -1)
        v = self.to_v(x).view(b, s, self.args.h, self.args.sd).permute(0, 2, 1, 3)

        attn = self.base(q, k, v, mask)

        if not self.args.bf: attn = attn.transpose(0, 1)

        return self.proj(attn)

class FFN(Module):

    def __init__(self, args: DataParams):
        super().__init__()

        self.proj = nn.Linear(args.dims, args.scale * args.dims)
        self.proj_back = nn.Linear(args.scale * args.dims, args.dims)

        self.drop = nn.Dropout(args.dr)

        self.nl = args.nl
        self.proj.weight.data.uniform_(-.1, .1)

    def forward(self, x: Tensor) -> Tensor:
        return self.drop(self.proj_back(self.nl(self.proj(x))))

class PositionalEncoding(Module):

    def __init__(self, args: DataParams):
        super().__init__()

        self.args = args

        pos = torch.arange(0, args.max_toks).unsqueeze(1).to(args.device)
        vals = torch.exp(torch.arange(0, args.dims, 2) / args.dims * -np.log(1e4)).to(args.device)

        self.encodes = torch.zeros(args.max_toks, 1, args.dims).to(args.device)  # (seq, batch, dims)
        self.encodes[:, 0, 0::2] = (pos * vals).sin()
        self.encodes[:, 0, 1::2] = (pos * vals).cos()

        self.drop = nn.Dropout(args.dr)

    def forward(self, x: Tensor) -> Tensor:
        s, b, c = x.shape
        return self.drop(x + self.encodes[:s])

def main(x: Tensor, mask: Tensor = null) -> Tensor:
    proj = nn.Linear(x.shape[-1], model_args.dims)
    pos_enc = PositionalEncoding(model_args)
    mha = MultiHeadAttention(model_args)
    return mha(pos_enc(proj(x)), mask)

if __name__ == "__main__":

    tnsr = torch.randn(3, 10, 200)
    hydra = HydraAttention(model_args)


# define the function first
def dipole_moment_integrand(phi, theta, mu, l1, m1, l2, m2 ):
    mu_operator=mu*(np.sin(theta)*np.cos(phi) + np.sin(theta)*np.sin(phi) + np.cos(theta))
    Y_lm_1 = sph_harm(m1, l1, phi, theta)
    Y_lm_2 = sph_harm(m2, l2, phi, theta)
    dV=np.sin(theta)
    integrand=np.conjugate(Y_lm_1)*mu_operator*Y_lm_2*dV
    return integrand
# starting variables
mu=0.425
# example of how to compute the expectation for the dipole moment Y_0^0
dipole_m_00,_ = nquad(dipole_moment_integrand, [[0,2.0*np.pi],[0,np.pi]], args=[mu,0,0,0,0])
print("The dipole moment for Y^0_0 is: ",dipole_m_00)
# compute the expectation for the dipole moment Y_1^1
dipole_m_11,_ = nquad(dipole_moment_integrand, [[0,2.0*np.pi],[0,np.pi]], args=[mu,1,1,1,1])
print("The dipole moment for Y^1_1 is: ",dipole_m_11)

10.Molecular Rotations/Dipole moment of rotational wavefunctions.py


"""This file produces results for when the Global Model uses all data in the train set for
fitting the Global Model"""
from sklearn.ensemble import GradientBoostingRegressor, RandomForestRegressor
from sklearn.linear_model import (
    LinearRegression,
    HuberRegressor,
)
from xgboost import XGBRegressor
from lightgbm import LGBMRegressor
from main import run_LESST, performance_LESST
from data_prep import to_array
from preprocessing import read_m4test_series, read_m4_series
import numpy as np
import pickle

np.seed = 1

# models to consider
models = {
    "xgb": XGBRegressor(tree_method="gpu_hist"),
    "lgbm": LGBMRegressor(),
    "rf": RandomForestRegressor(
        bootstrap=True, max_depth=80, max_features=6, n_estimators=100
    ),
    "ols": LinearRegression(),
    "huber": HuberRegressor(),
    "gradient": GradientBoostingRegressor(),
}

datasets = [
    "Yearly",
    "Quarterly",
    "Monthly",
    "Weekly",
    "Daily",
    "Hourly",
]
frequencys = [1, 4, 12, 52, 7, 24]
n_clusters = [100, 3, 3, 30, 30, 100]
deseasons = [False, True]

localmodels = [
    models["huber"],
    models["huber"],
    models["huber"],
    models["huber"],
    models["huber"],
    models["huber"],
]
globalmodels = [
    models["huber"],
    models["huber"],
    models["huber"],
    models["rf"],
    models["huber"],
    models["huber"],
]
lesst_owas = {}
lesst_smapes = {}
lesst_rmses = {}
lesst_mases = {}
for dataset, frequency, n_cluster, deseason, localmodel, globalmodel in zip(
    datasets, frequencys, n_clusters, deseasons, localmodels, globalmodels
):
    test = read_m4test_series(dataset)
    train = read_m4_series(dataset)
    res_train = to_array(train)
    res_test = to_array(test)
    horizon = test.shape[1]
    predictions, less = run_LESST(
        dataset,
        train,
        n_cluster,
        horizon,
        frequency,
        localmodel,
        globalmodel,
        deseason,
        rolling=True,
    )
    del less
    lesst_owa, lesst_smape, lesst_mase, lesst_rmse = performance_LESST(
        predictions,
        dataset,
        res_train,
        res_test,
        horizon,
        frequency,
    )
    lesst_owas.update({f"{dataset}": lesst_owa})
    lesst_smapes.update({f"{dataset}": lesst_smape})
    lesst_mases.update({f"{dataset}": lesst_mase})
    lesst_rmses.update({f"{dataset}": lesst_rmse})
    with open(
        f"E:/documents/work/thesis/rolling_{dataset}.pkl",
        "wb",
    ) as handle:
        pickle.dump(
            {
                "owa": lesst_owas,
                "smape": lesst_smapes,
                "mase": lesst_mases,
                "rmse": lesst_rmses,
            },
            handle,
            protocol=pickle.HIGHEST_PROTOCOL,
        )
    print("=====================================================")
    print(f"{dataset} is DONE")
    print("=====================================================")


"""
todo @ Elie
"""
import logging

import numpy as np

from bipv.bipv_panel import BipvPanel

import csv
from libraries_addons.solar_panels.pv_efficiency_functions import get_efficiency_loss_function_from_string

user_logger = logging.getLogger("user")
dev_logger = logging.getLogger("dev")

def load_panels_on_sensor_grid(sensor_grid, pv_technology_object, yearly_solar_radiation_values,
                               minimum_ratio_energy_harvested_on_primary_energy, performance_ratio):
    """
    Take a sensor grid and create a list of panels that correspond to each face of the mesh of the sensor grid
    The panels are initialized as switched on
    :param sensor_grid: sensor_grid of the face, roof, facades... we want to load the panels on
    :param pv_technology_object: PVPanelTechnology object
    :param yearly_solar_radiation_values: list of floats: list of the yearly cumulative solar radiation got by the solar
    radiation simulation in Wh/panel/year
    :param minimum_ratio_energy_harvested_on_primary_energy: float: minimum ratio between the energy harvested during the panel's
    lifetime and the energy necessary to produce, transport and recycle it. Default=1.2
    :param performance_ratio: float: performance ratio of the PV, Default=0.75
    :return panels
    """
    mesh = sensor_grid.mesh
    face_areas = mesh.face_areas
    panels = []

    efficiency_loss_function = get_efficiency_loss_function_from_string(pv_technology_object.efficiency_function)
    initial_efficiency = pv_technology_object.initial_efficiency
    area = pv_technology_object.panel_area
    weibull_lifetime = pv_technology_object.weibull_law_failure_parameters["lifetime"]

    for face in mesh.faces:
        energy_harvested = sum([efficiency_loss_function(initial_efficiency, i) * yearly_solar_radiation_values[
            mesh.faces.index(face)] * area * performance_ratio / 1000 for i in range(weibull_lifetime)])
        primary_energy = \
            pv_technology_object.primary_energy_manufacturing + pv_technology_object.primary_energy_recycling + \
            pv_technology_object.primary_energy_transport

        if face_areas[mesh.faces.index(face)] < pv_technology_object.panel_area:
            user_logger.warning("The area of the mesh's faces is not big enough to contain the PV panels. "
                                "Make a mesh with bigger faces")
            dev_logger.warning("The area of the mesh's faces is not big enough to contain the PV panels. "
                               "Make a mesh with bigger faces")
        elif (energy_harvested / primary_energy) <= minimum_ratio_energy_harvested_on_primary_energy:
            user_logger.warning("If a panel is put here, it won't produce enough energy to be profitable")
            dev_logger.warning("If a panel is put here, it won't produce enough energy to be profitable")
        else:
            panel_of_face = BipvPanel(mesh.faces.index(face), pv_technology_object)
            panel_of_face.initialize_or_replace_panel()
            panels.append(panel_of_face)
    return panels

def loop_over_the_years_for_solar_panels(pv_panel_obj_list, yearly_solar_radiation_values, performance_ratio,
                                         study_duration_in_years, replacement_scenario="yearly", **kwargs):
    """
    Loop over every year of the study duration to get the energy harvested, the energy used and the dmfa waste harvested
    every year
    :param pv_panel_obj_list: list of panel objects
    :param yearly_solar_radiation_values: list of floats: list of the yearly cumulative solar radiation got by the solar
    radiation simulation in Wh/panel/year
    :param study_duration_in_years: int: duration of the study in years, Default=1.2
    :param performance_ratio: float: performance ratio of the PV, Default=0.75
    :param replacement_scenario: string: replacement scenario chosen
    :return energy_production_per_year_list: list of floats in kWh/year
    :return nb_of_panels_installed_list: list of int: list of the number of panels installed each year
    :return nb_of_failed_panels_list: list of int: list of the number of panels failing each year
    """
    energy_production_per_year_list = []
    nb_of_panels_installed_list = []
    nb_of_failed_panels_list = []

    for year in range(study_duration_in_years):
        # initialize
        energy_harvested = 0.
        nb_of_new_panels = 0
        nb_of_failed_panels = 0
        # Initialize panels for year 0
        if year == 0:
            for panel_obj in pv_panel_obj_list:
                panel_obj.initialize_or_replace_panel()
                nb_of_new_panels += 1

        # Replace according to replacement "scenario" \(- -)/
        if replacement_scenario == "yearly":
            # the code inside each statement
            for panel_obj in pv_panel_obj_list:
                if not panel_obj.is_panel_working():
                    panel_obj.initialize_or_replace_panel()
                    nb_of_new_panels += 1
        elif replacement_scenario == "every_X_years":
            replacement_year = kwargs["replacement_year"]
            if year != 0 and year % replacement_year == 0:
                for panel_obj in pv_panel_obj_list:
                    if not panel_obj.is_panel_working():
                        panel_obj.initialize_or_replace_panel()
                        nb_of_new_panels += 1

        # Increment of 1 year
        for panel_obj in pv_panel_obj_list:
            index_panel = pv_panel_obj_list.index(panel_obj)
            energy_harvested_panel, panel_failed = panel_obj.pass_year(yearly_solar_radiation_values[index_panel],
                                                                       performance_ratio)
            energy_harvested += energy_harvested_panel
            if panel_failed:
                nb_of_failed_panels += 1

        energy_production_per_year_list.append(energy_harvested)
        nb_of_panels_installed_list.append(nb_of_new_panels)
        nb_of_failed_panels_list.append(nb_of_failed_panels)

    return energy_production_per_year_list, nb_of_panels_installed_list, nb_of_failed_panels_list

def write_to_csv_arr(header, arr, file_path):
    """
    write a list of int to a csv file
    :param header: list of str
    :param arr: list of lists of integers
    :param file_path: path to where the file should be written
    """
    with open(file_path, 'w') as f:
        writer = csv.writer(f, lineterminator='\n')
        writer.writerow(header)
        writer.writerows(arr)

def beginning_end_of_life_lca_results_in_lists(energy_production_per_year_list, nb_of_panels_installed_list,
                                               nb_of_failed_panels_list, pv_tech):
    """
    Take the results from function loop_over_the_years_for_solar_panels and use the pv_tech info to transform it to data
    :param energy_production_per_year_list: list of floats: describes the energy production each year
    :param nb_of_panels_installed_list: list of integers: describes how many panels are installed each year
    :param nb_of_failed_panels_list: list of integers: describes how many panels fail each year
    :param pv_tech: PVPanelTechnology object
    :return energy_production_per_year_list: list of floats
    :return lca_cradle_to_installation_primary_energy_list: list of floats: describes how much energy was used to manufacture the panels installed for
    each year
    :return lca_cradle_to_installation_carbon_list: list of floats: describes how much carbon was released to manufacture the panels installed,
    for each year
    :return dmfa_waste_list: list of floats: describes the dmfa waste caused by the failed panels, for each year
    :return lca_recycling_primary_energy_list: list of float: describes how much energy was used to recycle the panels having failed
    """
    # todo: add comments
    panel_energy_cradle_to_installation = pv_tech.primary_energy_manufacturing + pv_tech.primary_energy_transport
    panel_carbon_cradle_to_installation = pv_tech.carbon_manufacturing + pv_tech.carbon_transport
    panel_waste = pv_tech.weight
    panel_primary_energy_recycling = pv_tech.primary_energy_recycling
    panel_carbon_recycling = pv_tech.carbon_recycling

    cradle_to_installation_primary_energy_list = [i * panel_energy_cradle_to_installation for i in
                                                   nb_of_panels_installed_list]
    cradle_to_installation_carbon_list = [i * panel_carbon_cradle_to_installation for i in
                                           nb_of_panels_installed_list]
    dmfa_waste_list = [i * panel_waste for i in nb_of_failed_panels_list]
    lca_recycling_primary_energy_list = [i * panel_primary_energy_recycling for i in nb_of_panels_installed_list]
    lca_recycling_carbon_list = [i * panel_carbon_recycling for i in nb_of_panels_installed_list]

    return energy_production_per_year_list, cradle_to_installation_primary_energy_list, cradle_to_installation_carbon_list, \
        dmfa_waste_list, lca_recycling_primary_energy_list, lca_recycling_carbon_list

def results_from_lists_to_dict(energy_production_per_year_list, cradle_to_installation_primary_energy_list,
                               cradle_to_installation_carbon_list, dmfa_waste_list, lca_recycling_primary_energy_list,
                               lca_recycling_carbon_list):
    """
    Transform those results into a dictionary
    :param energy_production_per_year_list: list of floats describes the energy production each year
    :param cradle_to_installation_primary_energy_list: list of floats: describes how much energy was used to manufacture the panels
    installed for each year
    :param cradle_to_installation_carbon_list: list of floats: describes how much carbon was released to manufacture the panels
    installed for each year
    :param dmfa_waste_list: list of floats: describes the dmfa waste caused by the failed panels, for each year
    :param lca_recycling_primary_energy_list: list of floats: describes how much energy is used to recycle the panels
    :return results_dict: dictionary containing all the data
    """
    # todo: add comments
    results_dict = {}
    energy_harvested_dict = {"list": energy_production_per_year_list, "total": sum(energy_production_per_year_list)}
    lca_cradle_to_installation_primary_energy_dict = {"list": cradle_to_installation_primary_energy_list,
                                                       "total": sum(cradle_to_installation_primary_energy_list)}
    lca_cradle_to_installation_carbon_dict = {"list": cradle_to_installation_carbon_list,
                                               "total": sum(cradle_to_installation_carbon_list)}
    dmfa_waste_dict = {"list": dmfa_waste_list, "total": sum(dmfa_waste_list)}
    lca_recycling_primary_energy_dict = {"list": lca_recycling_primary_energy_list,
                                         "total": sum(lca_recycling_primary_energy_list)}
    lca_recycling_carbon_dict = {"list": lca_recycling_carbon_list, "total": sum(lca_recycling_carbon_list)}

    results_dict["energy_harvested"] = energy_harvested_dict
    results_dict["lca_cradle_to_installation_primary_energy"] = lca_cradle_to_installation_primary_energy_dict
    results_dict["lca_cradle_to_installation_carbon"] = lca_cradle_to_installation_carbon_dict
    results_dict["dmfa_waste"] = dmfa_waste_dict
    results_dict["lca_recycling_primary_energy"] = lca_recycling_primary_energy_dict
    results_dict["lca_recycling_carbon"] = lca_recycling_carbon_dict

    return results_dict

def get_cumul_values(list1):
    list_cumul = [sum(list1[0:i]) for i in range(1, len(list1) + 1)]
    return list_cumul

def add_elements_of_two_lists(list1, list2):
    if not list1:
        return list2
    elif not list2:
        return list1
    else:
        added_list = [sum(i) for i in zip(list1, list2)]
        return added_list

def transform_to_linear_function(x, y):
    """
    Transforms data into a linear function using linear regression.

    Arguments:
    x, y -- Arrays representing the x and y values of the data.

    Returns:
    slope -- Slope of the linear function.
    intercept -- Intercept of the linear function.
    """
    # Convert x and y to NumPy arrays
    x = np.array(x)
    y = np.array(y)

    # Calculate the slope and intercept
    mean_x = np.mean(x)
    mean_y = np.mean(y)
    slope = np.sum((x - mean_x) * (y - mean_y)) / np.sum((x - mean_x) ** 2)
    intercept = mean_y - slope * mean_x

    return slope, intercept

def generate_step_function(x_values, y_values):
    """
    Generates a step function from a set of x and y values.

    Arguments:
    x_values -- Array of x-values.
    y_values -- Array of y-values.

    Returns:
    step_function -- A function that represents the step function.
    """

    def step_function(x):
        # Find the index of the largest x-value that is less than or equal to the input x
        idx = np.searchsorted(x_values, x, side='right') - 1

        # Return the corresponding y-value
        return y_values[idx]

    return step_function

def find_intersection_functions(func1, func2, x_start, x_end, tol=1e-3, max_iter=500):
    """
    Finds the intersection of two functions using the bisection method.

    Arguments:
    func1, func2 -- Functions to find the intersection of.
    x_start, x_end -- Range of x-values to search for the intersection.
    tol -- Tolerance for the intersection value (default: 1e-6).
    max_iter -- Maximum number of iterations (default: 100).

    Returns:
    x_intersection -- Approximated x-value of the intersection.
    y_intersection -- Approximated y-value of the intersection.
    """
    x_left = x_start
    x_right = x_end

    for _ in range(max_iter):
        x_mid = (x_left + x_right) / 2
        y_mid1 = func1(x_mid)
        y_mid2 = func2(x_mid)

        if abs(y_mid1 - y_mid2) < tol:
            return x_mid, y_mid1

        if y_mid1 > y_mid2:
            x_right = x_mid
        else:
            x_left = x_mid

    # If no intersection is found within the maximum iterations
    dev_logger.warning("Intersection not found within the specified range and maximum iterations.")
    return None


# Definition for singly-linked list.
class ListNode(object):

    def __init__(self, x):
        self.val = x
        self.next = None

class Solution(object):

    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if head is None:
            return None
        elif head.next is None:
            return head
        else:
            result = head.next
            count = 1
            current = head
            temp = head
            pprev = head
            while current is not None:
                if count % 2 == 0:
                    temp.next = current.next
                    current.next = temp
                    if count > 3:
                        pprev.next = current
                        pprev = temp
                else:
                    temp = current
                current = temp.next
                count += 1
            return result

if __name__ == '__main__':
    head, node2, node3, node4, node5, node6 = ListNode(
        1), ListNode(2), ListNode(3), ListNode(4), ListNode(5), ListNode(6)
    head.next = node2
    node2.next = node3
    node3.next = node4
    node4.next = node5
    node5.next = node6
    solution = Solution()
    result = solution.swapPairs(head)
    print('=========================')
    while result is not None:
        print(result.val)
        result = result.next


import json
from pathlib import Path
from typing import Dict

import click
import cv2
import numpy as np
from tqdm import tqdm

def detect_orange(img):
    height, width, channels = img.shape
    if width < height:
        img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
    scaled_img = cv2.resize(img, (0, 0), fx=0.2, fy=0.2)
    gaussian_img = cv2.GaussianBlur(scaled_img, (9, 9), 0)
    hsv = cv2.cvtColor(gaussian_img, cv2.COLOR_BGR2HSV)
    w = np.array([12, 193, 180])
    s = np.array([18, 249, 235])
    kernel = np.ones((33, 33), np.uint8)
    mask = cv2.inRange(hsv, w, s)
    ker_mask = cv2.dilate(mask, kernel, iterations=1)
    ker_mask = cv2.morphologyEx(ker_mask, cv2.MORPH_CLOSE, kernel)
    ker_mask = cv2.morphologyEx(ker_mask, cv2.MORPH_OPEN, kernel)
    res = cv2.bitwise_and(gaussian_img, gaussian_img, mask=ker_mask)
    res = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
    ret, thresh = cv2.threshold(res, 0, 255, cv2.THRESH_BINARY)
    # cv2.imshow('image', thresh)
    # cv2.waitKey()
    contours, hierarchy = cv2.findContours(image=thresh, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_NONE)
    contours_number = []
    for contour in contours:
        if cv2.contourArea(contour) > 6000:
            contours_number.append(contour)
    return(len(contours_number))

def detect_banana(img):
    height, width, channels = img.shape
    if width < height:
        img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
    scaled_img = cv2.resize(img, (0, 0), fx=0.2, fy=0.2)
    gaussian_img = cv2.GaussianBlur(scaled_img, (5, 5), 0)
    hsv = cv2.cvtColor(gaussian_img, cv2.COLOR_BGR2HSV)
    w = np.array([20, 93, 116])
    s = np.array([36, 230, 240])
    kernel = np.ones((11, 11), np.uint8)
    mask = cv2.inRange(hsv, w, s)
    ker_mask = cv2.dilate(mask, kernel, iterations=1)
    ker_mask = cv2.morphologyEx(ker_mask, cv2.MORPH_CLOSE, kernel)
    ker_mask = cv2.morphologyEx(ker_mask, cv2.MORPH_OPEN, kernel)
    res = cv2.bitwise_and(gaussian_img, gaussian_img, mask=ker_mask)
    res = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
    ret, thresh = cv2.threshold(res, 0, 255, cv2.THRESH_BINARY)
    # cv2.imshow('image', thresh)
    # cv2.waitKey()
    contours, hierarchy = cv2.findContours(image=thresh, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_NONE)
    contours_number = []
    for contour in contours:
        if cv2.contourArea(contour) > 7000:
            contours_number.append(contour)
    return(len(contours_number))

def detect_apple(img):
    height, width, channels = img.shape
    if width < height:
        img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)

    scaled_img = cv2.resize(img, (0, 0), fx=0.2, fy=0.2)
    gaussian_img = cv2.GaussianBlur(scaled_img, (5, 5), 0)
    hsv = cv2.cvtColor(gaussian_img, cv2.COLOR_BGR2HSV)

    w1 = np.array([0, 33, 29])
    s1 = np.array([3, 194, 188])
    kernel1 = np.ones((21, 21), np.uint8)
    mask1 = cv2.inRange(hsv, w1, s1)
    ker_mask1 = cv2.dilate(mask1, kernel1, iterations=1)
    ker_mask1 = cv2.morphologyEx(ker_mask1, cv2.MORPH_CLOSE, kernel1)
    ker_mask1 = cv2.morphologyEx(ker_mask1, cv2.MORPH_OPEN, kernel1)
    w2 = np.array([3, 100, 44])
    s2 = np.array([17, 219, 160])
    kernel2 = np.ones((13, 13), np.uint8)
    mask2 = cv2.inRange(hsv, w2, s2)
    ker_mask2 = cv2.dilate(mask2, kernel2, iterations=1)
    ker_mask2 = cv2.morphologyEx(ker_mask2, cv2.MORPH_CLOSE, kernel2)
    ker_mask2 = cv2.morphologyEx(ker_mask2, cv2.MORPH_OPEN, kernel2)
    ker_mask = ker_mask1 + ker_mask2
    res = cv2.bitwise_and(gaussian_img, gaussian_img, mask=ker_mask)
    res = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
    ret, thresh = cv2.threshold(res, 0, 255, cv2.THRESH_BINARY)
    # cv2.imshow('image', thresh)
    # cv2.waitKey()
    contours, hierarchy = cv2.findContours(image=thresh, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_NONE)
    contours_number = []
    for contour in contours:
        if cv2.contourArea(contour) > 6000:
            contours_number.append(contour)
    return(len(contours_number))

def detect_fruits(img_path: str) -> Dict[str, int]:
    """Fruit detection function, to implement.

    Parameters
    ----------
    img_path : str
        Path to processed image.

    Returns
    -------
    Dict[str, int]
        Dictionary with quantity of each fruit.
    """
    img = cv2.imread(img_path, cv2.IMREAD_COLOR)

    #TODO: Implement detection method.

    apple = 0
    banana = 0
    orange = 0

    apple = detect_apple(img)
    banana = detect_banana(img)
    orange = detect_orange(img)

    return {'apple': apple, 'banana': banana, 'orange': orange}

@click.command()
@click.option('-p', '--data_path', help='Path to data directory', type=click.Path(exists=True, file_okay=False,
                                                                                path_type=Path), required=True)
@click.option('-o', '--output_file_path', help='Path to output file', type=click.Path(dir_okay=False, path_type=Path),
              required=True)
def main(data_path: Path, output_file_path: Path):
    img_list = data_path.glob('*.jpg')

    results = {}
    for img_path in tqdm(sorted(img_list)):
        fruits = detect_fruits(str(img_path))
        results[img_path.name] = fruits

    with open(output_file_path, 'w') as ofp:
        json.dump(results, ofp)

if __name__ == '__main__':
    main()


from gc import callbacks
from tqdm import tqdm

import sys
import os
import inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir)

from commons.utils import FileSaver
from commons import saveModel
import numpy as np

def train(agent,
agent_type,
env,
actorCriticCheck=False,
batch_size=0,
episodes=50000,
print_every=10,
file_name=None,
callback=None,
timesteps=100000,
print_bool=False,
save_to_file_bool=True,
info_file_path='./'):
    """
    This function trains a specific agent and regulates the workflow of the overall application:
    agent: the agent object employed in the task.
    agent_type: string used to discriminate between agents' different implementations.
    env: specific environment object retrived by makeEnvironment.
    actorCriticCheck: bool to discriminate between A2C and REINFORCE. Fundamental since A2C policy updates are performed in batches.
    batch_size: int used to indicate the batch chunk size for A2C policy updates.
    episodes: number of training episodes.
    print_every: number of episodes to skip before printing to episode's return to standard output.
    file_name: if save_to_file_bool==True then saves the information in the file specified here via utils.FileSaver() object.
    callback: specific callback given to TRPO and PPO agents.
    timesteps: number of training timesteps for PPO and TRPO.
    print_bool: bool used to indicate wheather to print or not episode's return to standard output.
    save_to_file_bool: bool used to indicate if the current training process informations should be saved or not.
    info_file_path: file path for utils.FileSaver() object instantiation.
    """
    if agent_type.lower() == 'reinforce' or agent_type.lower() == 'actorcritic':
        if save_to_file_bool:
            files = [
                f'{file_name}_reward_file.txt',
                f'{file_name}_action_file.txt'
                ]
            fs_reward = FileSaver(file_name=files[0], path=info_file_path)
            fs_action = FileSaver(file_name=files[1], path=info_file_path)

            fs_reward.write_header("EpisodeID,Return\n")
            fs_action.write_header("EpisodeID,ActionMeasure\n")

        episodes_counter = 0
        timestep_counter = 0
        for episode in tqdm(range(episodes)):
            episode_return = 0
            episodes_counter += 1
            batch_counter = 0
            done = False
            train_reward = 0
            state = env.reset()

            timestep_per_episode = 0
            episode_actions = np.array([])
            while not done:
                batch_counter += 1
                timestep_counter += 1
                timestep_per_episode += 1

                action, action_probabilities = agent.get_action(state)

                episode_actions = np.append(episode_actions, action)

                previous_state = state

                state, reward, done, info = env.step(action.detach().cpu().numpy())
                agent.store_outcome(previous_state, state, action_probabilities, reward, done)

                train_reward += reward
                episode_return += reward

                if actorCriticCheck and batch_counter == batch_size:
                    agent.update_policy()
                    agent.clear_history()
                    batch_counter = 0
                    continue

            if actorCriticCheck:
                agent.clear_history()

            if not actorCriticCheck:
                agent.update_policy()

            if save_to_file_bool:
                action_derivative = np.diff(episode_actions.reshape(3, -1))
                action_measure = np.abs(action_derivative).max(axis = 0) - np.abs(action_derivative).min(axis = 0)
                action_measure = action_measure.max() - action_measure.min()

                fs_reward.append_content(f"{episodes_counter},{episode_return}\n")
                fs_action.append_content(f"{episodes_counter},{action_measure}\n")

            if print_bool:
                if (episode+1)%print_every == 0:
                    print('Training episode:', episode)
                    print('Episode return:', train_reward)

    elif agent_type == 'ppo' or agent_type == 'trpo':
        agent.learn(total_timesteps=timesteps, callback=callback)
        saveModel.save_model(agent=agent, agent_type=agent_type, folder_path=info_file_path)